factor ACI code out of slapd; now it can only use dynacl layer

This commit is contained in:
Pierangelo Masarati 2006-01-06 17:12:35 +00:00
parent f0ae7d7a1b
commit a54ca7a6ce
9 changed files with 95 additions and 324 deletions

View File

@ -263,7 +263,8 @@ dnl SLAPD OPTIONS
AC_ARG_ENABLE(xxslapdoptions,[
SLAPD (Standalone LDAP Daemon) Options:])
OL_ARG_ENABLE(slapd,[ --enable-slapd enable building slapd], yes)dnl
OL_ARG_ENABLE(aci,[ --enable-aci enable per-object ACIs (experimental)], no)dnl
OL_ARG_ENABLE(dynacl,[ --enable-dynacl enable run-time loadable ACL support (experimental)], no)dnl
OL_ARG_ENABLE(aci,[ --enable-aci enable per-object ACIs (experimental)], no, [no yes mod])dnl
OL_ARG_ENABLE(cleartext,[ --enable-cleartext enable cleartext passwords], yes)dnl
OL_ARG_ENABLE(crypt,[ --enable-crypt enable crypt(3) passwords], no)dnl
OL_ARG_ENABLE(lmpasswd,[ --enable-lmpasswd enable LAN Manager passwords], no)dnl
@ -463,6 +464,7 @@ if test $ol_enable_slapd = no ; then
ol_enable_modules=no
ol_enable_multimaster=no
ol_enable_rlookups=no
ol_enable_dynacl=no
ol_enable_aci=no
ol_enable_wrappers=no
@ -2697,11 +2699,25 @@ if test "$ol_enable_rlookups" != no ; then
AC_DEFINE(SLAPD_RLOOKUPS,1,[define to support reverse lookups])
fi
if test "$ol_enable_aci" != no ; then
AC_DEFINE(SLAPD_ACI_ENABLED,1,[define to support per-object ACIs])
WITH_ACI_ENABLED=yes
if test $ol_enable_dynacl = no ; then
ol_enable_dynacl=yes
AC_MSG_WARN([ACIs need dynacl])
fi
if test "$ol_enable_aci" = mod ; then
MFLAG=SLAPD_MOD_DYNAMIC
dnl remove this after moving servers/slapd/aci.c in contrib/slapd-modules/acl
AC_MSG_ERROR([ACI build as dynamic module not supported (yet)])
else
MFLAG=SLAPD_MOD_STATIC
fi
WITH_ACI_ENABLED=$ol_enable_aci
AC_DEFINE_UNQUOTED(SLAPD_ACI_ENABLED,$MFLAG,[define to support per-object ACIs])
else
WITH_ACI_ENABLED=no
fi
if test "$ol_enable_dynacl" != no ; then
AC_DEFINE(SLAP_DYNACL,1,[define to support run-time loadable ACL])
fi
if test "$ol_link_modules" != no ; then
AC_DEFINE(SLAPD_MODULES,1,[define to support modules])

View File

@ -254,8 +254,7 @@ It can have the forms
tls_ssf=<n>
sasl_ssf=<n>
aci[=<attrname>]
dynacl/name[/<options>][.<dynstyle>][=<pattern>]
dynacl/<name>[/<options>][.<dynstyle>][=<pattern>]
.fi
.LP
with
@ -270,6 +269,7 @@ with
<domainstyle>={exact|regex|sub(tree)}
<setstyle>={exact|regex}
<modifier>={expand}
<name>=aci <pattern>=<attrname>]
.fi
.LP
They may be specified in combination.
@ -620,19 +620,6 @@ The statement
is undocumented yet.
.LP
The statement
.B aci[=<attrname>]
means that the access control is determined by the values in the
.B attrname
of the entry itself.
The optional
.B <attrname>
indicates what attributeType holds the ACI information in the entry.
By default, the
.B OpenLDAPaci
operational attribute is used.
ACIs are experimental; they must be enabled at compile time.
.LP
The statement
.B dynacl/<name>[/<options>][.<dynstyle>][=<pattern>]
means that access checking is delegated to the admin-defined method
indicated by
@ -647,12 +634,19 @@ and
.B <pattern>
are optional, and are directly passed to the registered parsing routine.
Dynacl is experimental; it must be enabled at compile time.
If dynacl and ACIs are both enabled, ACIs are cast into the dynacl scheme,
where
.B <name>=aci
and, optionally,
.BR <patten>=<attrname> .
However, the original ACI syntax is preserved for backward compatibility.
.LP
The statement
.B dynacl/aci[=<attrname>]
means that the access control is determined by the values in the
.B attrname
of the entry itself.
The optional
.B <attrname>
indicates what attributeType holds the ACI information in the entry.
By default, the
.B OpenLDAPaci
operational attribute is used.
ACIs are experimental; they must be enabled at compile time.
.LP
The statements
.BR ssf=<n> ,

View File

@ -1326,7 +1326,7 @@ default, readonly is off.
.B bindmethod=simple|sasl [binddn=<simple DN>] [credentials=<simple password>]
.B [saslmech=<SASL mech>] [secprops=<properties>] [realm=<realm>]
.B [authcId=<authentication ID>] [authzId=<authorization ID>]
.B [attr[!]=<attr list>]
.B [attrs[!]=<attr list>]
.RS
Specify a replication site for this database. Refer to the "OpenLDAP
Administrator's Guide" for detailed information on setting up a replicated
@ -1370,7 +1370,7 @@ will use Kerberos, a kerberos instance should be given in
An
.B attr list
can be given after the
.B attr
.B attrs
keyword to allow the selective replication of the listed attributes only;
if the optional
.B !
@ -1860,7 +1860,7 @@ pidfile LOCALSTATEDIR/slapd.pid
# option ";x-hidden" can be searched for/compared,
# but are not shown. See \fBslapd.access\fP(5).
attributeoptions x-hidden lang-
access to attr=name;x-hidden by * =cs
access to attrs=name;x-hidden by * =cs
# Protect passwords. See \fBslapd.access\fP(5).
access to attrs=userPassword by * auth

View File

@ -40,7 +40,14 @@
#include "lber_pvt.h"
#include "lutil.h"
#define ACI_BUF_SIZE 1024 /* use most appropriate size */
/* use most appropriate size */
#define ACI_BUF_SIZE 1024
/* move to "stable" when no longer experimental */
#define SLAPD_ACI_SYNTAX "1.3.6.1.4.1.4203.666.2.1"
/* change this to "OpenLDAPset" */
#define SLAPD_ACI_SET_ATTR "template"
enum {
ACI_BV_ENTRY,
@ -111,10 +118,7 @@ static const struct berval aci_bv[] = {
BER_BVNULL
};
#ifdef SLAP_DYNACL
static
#endif /* SLAP_DYNACL */
AttributeDescription *slap_ad_aci;
static AttributeDescription *slap_ad_aci;
static int
OpenLDAPaciValidate(
@ -390,7 +394,7 @@ done:
return rc;
}
int
static int
aci_mask(
Operation *op,
Entry *e,
@ -640,7 +644,7 @@ aci_mask(
return 0;
}
int
static int
aci_init( void )
{
/* OpenLDAP eXperimental Syntax */
@ -727,7 +731,6 @@ aci_init( void )
return rc;
}
#ifdef SLAP_DYNACL
static int
dynacl_aci_parse(
const char *fname,
@ -970,7 +973,6 @@ dynacl_aci_init( void )
return rc;
}
#endif /* SLAP_DYNACL */
/* ACI syntax validation */
@ -1694,7 +1696,7 @@ OpenLDAPaciNormalize(
int
init_module( int argc, char *argv[] )
{
return slap_dynacl_register();
return dynacl_aci_init();
}
#endif /* SLAPD_ACI_ENABLED == SLAPD_MOD_DYNAMIC */

View File

@ -373,17 +373,15 @@ access_allowed_mask(
if ( state ) {
if ( state->as_vd_ad == desc ) {
if ( state->as_recorded ) {
if ( ( state->as_recorded & ACL_STATE_RECORDED_NV ) &&
val == NULL )
{
return state->as_result;
if ( ( state->as_recorded & ACL_STATE_RECORDED_NV ) &&
val == NULL )
{
return state->as_result;
} else if ( ( state->as_recorded & ACL_STATE_RECORDED_VD ) &&
val != NULL && state->as_vd_acl == NULL )
{
return state->as_result;
}
} else if ( ( state->as_recorded & ACL_STATE_RECORDED_VD ) &&
val != NULL && state->as_vd_acl == NULL )
{
return state->as_result;
}
st_same_attr = 1;
} else {
@ -520,24 +518,22 @@ access_allowed_mask(
if ( state ) {
if ( state->as_vd_ad == desc ) {
if ( state->as_recorded ) {
if ( ( state->as_recorded & ACL_STATE_RECORDED_NV ) &&
val == NULL )
{
return state->as_result;
if ( ( state->as_recorded & ACL_STATE_RECORDED_NV ) &&
val == NULL )
{
return state->as_result;
} else if ( ( state->as_recorded & ACL_STATE_RECORDED_VD ) &&
val != NULL && state->as_vd_acl == NULL )
{
return state->as_result;
}
} else if ( ( state->as_recorded & ACL_STATE_RECORDED_VD ) &&
val != NULL && state->as_vd_acl == NULL )
{
return state->as_result;
}
st_same_attr = 1;
} else {
*state = state_init;
}
state->as_vd_ad=desc;
state->as_vd_ad = desc;
}
Debug( LDAP_DEBUG_ACL,
@ -740,7 +736,7 @@ done:
return ret;
}
#endif /* SLAP_OVERLAY_ACCESS */
#endif /* !SLAP_OVERLAY_ACCESS */
/*
* slap_acl_get - return the acl applicable to entry e, attribute
@ -2008,169 +2004,7 @@ slap_acl_mask(
}
} else
#else /* !SLAP_DYNACL */
/* NOTE: this entire block can be eliminated when SLAP_DYNACL
* moves outside of LDAP_DEVEL */
#ifdef SLAPD_ACI_ENABLED
if ( b->a_aci_at != NULL ) {
Attribute *at;
slap_access_t grant, deny, tgrant, tdeny;
struct berval parent_ndn;
BerVarray bvals = NULL;
int ret, stop;
#ifdef LDAP_DEBUG
char accessmaskbuf1[ACCESSMASK_MAXLEN];
#endif /* DEBUG */
Debug( LDAP_DEBUG_ACL, " <= check a_aci_at: %s\n",
b->a_aci_at->ad_cname.bv_val, 0, 0 );
/* this case works different from the others above.
* since aci's themselves give permissions, we need
* to first check b->a_access_mask, the ACL's access level.
*/
if ( BER_BVISEMPTY( &e->e_nname ) ) {
/* no ACIs in the root DSE */
continue;
}
/* first check if the right being requested
* is allowed by the ACL clause.
*/
if ( ! ACL_GRANT( b->a_access_mask, *mask ) ) {
continue;
}
/* start out with nothing granted, nothing denied */
ACL_INIT(tgrant);
ACL_INIT(tdeny);
/* get the aci attribute */
at = attr_find( e->e_attrs, b->a_aci_at );
if ( at != NULL ) {
#if 0
/* FIXME: this breaks acl caching;
* see also ACL_RECORD_VALUE_STATE below */
ACL_RECORD_VALUE_STATE;
#endif
/* the aci is an multi-valued attribute. The
* rights are determined by OR'ing the individual
* rights given by the acis.
*/
for ( i = 0; !BER_BVISNULL( &at->a_nvals[i] ); i++ ) {
if ( aci_mask( op,
e, desc, val,
&at->a_nvals[i],
nmatch, matches,
&grant, &deny, SLAP_ACI_SCOPE_ENTRY ) != 0 )
{
tgrant |= grant;
tdeny |= deny;
}
}
Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
accessmask2str(tgrant, accessmaskbuf, 1),
accessmask2str(tdeny, accessmaskbuf1, 1), 0);
}
/* If the entry level aci didn't contain anything valid for the
* current operation, climb up the tree and evaluate the
* acis with scope set to subtree
*/
if ( (tgrant == ACL_PRIV_NONE) && (tdeny == ACL_PRIV_NONE) ) {
dnParent( &e->e_nname, &parent_ndn );
while ( !BER_BVISEMPTY( &parent_ndn ) ) {
Debug(LDAP_DEBUG_ACL, "checking ACI of %s\n", parent_ndn.bv_val, 0, 0);
ret = backend_attribute(op, NULL, &parent_ndn, b->a_aci_at, &bvals, ACL_AUTH);
switch(ret){
case LDAP_SUCCESS :
stop = 0;
if (!bvals){
break;
}
for ( i = 0; !BER_BVISNULL( &bvals[i] ); i++ ) {
#if 0
/* FIXME: this breaks acl caching;
* see also ACL_RECORD_VALUE_STATE above */
ACL_RECORD_VALUE_STATE;
#endif
if ( aci_mask( op, e, desc, val, &bvals[i],
nmatch, matches,
&grant, &deny, SLAP_ACI_SCOPE_CHILDREN ) != 0 )
{
tgrant |= grant;
tdeny |= deny;
/* evaluation stops as soon as either a "deny" or a
* "grant" directive matches.
*/
if( (tgrant != ACL_PRIV_NONE) || (tdeny != ACL_PRIV_NONE) ){
stop = 1;
}
}
Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
accessmask2str(tgrant, accessmaskbuf, 1),
accessmask2str(tdeny, accessmaskbuf1, 1), 0);
}
break;
case LDAP_NO_SUCH_ATTRIBUTE:
/* just go on if the aci-Attribute is not present in
* the current entry
*/
Debug(LDAP_DEBUG_ACL, "no such attribute\n", 0, 0, 0);
stop = 0;
break;
case LDAP_NO_SUCH_OBJECT:
/* We have reached the base object */
Debug(LDAP_DEBUG_ACL, "no such object\n", 0, 0, 0);
stop = 1;
break;
default:
stop = 1;
break;
}
if (stop){
break;
}
dnParent( &parent_ndn, &parent_ndn );
}
}
/* remove anything that the ACL clause does not allow */
tgrant &= b->a_access_mask & ACL_PRIV_MASK;
tdeny &= ACL_PRIV_MASK;
/* see if we have anything to contribute */
if( ACL_IS_INVALID(tgrant) && ACL_IS_INVALID(tdeny) ) {
continue;
}
/* this could be improved by changing slap_acl_mask so that it can deal with
* by clauses that return grant/deny pairs. Right now, it does either
* additive or subtractive rights, but not both at the same time. So,
* we need to combine the grant/deny pair into a single rights mask in
* a smart way: if either grant or deny is "empty", then we use the
* opposite as is, otherwise we remove any denied rights from the grant
* rights mask and construct an additive mask.
*/
if (ACL_IS_INVALID(tdeny)) {
modmask = tgrant | ACL_PRIV_ADDITIVE;
} else if (ACL_IS_INVALID(tgrant)) {
modmask = tdeny | ACL_PRIV_SUBSTRACTIVE;
} else {
modmask = (tgrant & ~tdeny) | ACL_PRIV_ADDITIVE;
}
} else
#endif /* SLAPD_ACI_ENABLED */
#endif /* !SLAP_DYNACL */
#endif /* SLAP_DYNACL */
{
modmask = b->a_access_mask;
}
@ -2781,13 +2615,12 @@ slap_dynacl_get( const char *name )
* statically built-in dynamic ACL initialization
*/
static int (*acl_init_func[])( void ) = {
#ifdef SLAPD_ACI_ENABLED
#ifdef SLAP_DYNACL
/* TODO: remove when ACI will only be dynamic */
#if SLAPD_ACI_ENABLED == SLAPD_MOD_STATIC
dynacl_aci_init,
#else /* !SLAP_DYNACL */
aci_init,
#endif /* !SLAP_DYNACL */
#endif /* SLAPD_ACI_ENABLED */
#endif /* SLAP_DYNACL */
NULL
};

View File

@ -1622,11 +1622,18 @@ parse_acl(
{
char *name = NULL,
*opts = NULL;
#if 1 /* tolerate legacy "aci" <who> */
if ( strcasecmp( left, "aci" ) == 0 ) {
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
"undocumented deprecated \"aci\" directive "
"is superseded by \"dynacl/aci\".\n",
fname, lineno, 0 );
name = "aci";
} else if ( strncasecmp( left, "dynacl/", STRLENOF( "dynacl/" ) ) == 0 ) {
} else
#endif /* tolerate legacy "aci" <who> */
if ( strncasecmp( left, "dynacl/", STRLENOF( "dynacl/" ) ) == 0 ) {
name = &left[ STRLENOF( "dynacl/" ) ];
opts = strchr( name, '/' );
if ( opts ) {
@ -1646,61 +1653,7 @@ parse_acl(
continue;
}
}
#else /* ! SLAP_DYNACL */
#ifdef SLAPD_ACI_ENABLED
if ( strcasecmp( left, "aci" ) == 0 ) {
if (sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE) {
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
"inappropriate style \"%s\" in by clause.\n",
fname, lineno, style );
return acl_usage();
}
if( b->a_aci_at != NULL ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: ACI attribute already specified.\n",
fname, lineno, 0 );
return acl_usage();
}
if ( right != NULL && *right != '\0' ) {
rc = slap_str2ad( right, &b->a_aci_at, &text );
if( rc != LDAP_SUCCESS ) {
char buf[ SLAP_TEXT_BUFLEN ];
snprintf( buf, sizeof( buf ),
"aci \"%s\": %s.",
right, text );
Debug( LDAP_DEBUG_ANY,
"%s: line %d: %s\n",
fname, lineno, buf );
return acl_usage();
}
} else {
b->a_aci_at = slap_ad_aci;
}
if( !is_at_syntax( b->a_aci_at->ad_type,
SLAPD_ACI_SYNTAX) )
{
char buf[ SLAP_TEXT_BUFLEN ];
snprintf( buf, sizeof( buf ),
"ACI \"%s\": inappropriate syntax: %s.",
right,
b->a_aci_at->ad_type->sat_syntax_oid );
Debug( LDAP_DEBUG_ANY, "%s: line %d: %s\n",
fname, lineno, buf );
return acl_usage();
}
continue;
}
#endif /* SLAPD_ACI_ENABLED */
#endif /* ! SLAP_DYNACL */
#endif /* SLAP_DYNACL */
if ( strcasecmp( left, "ssf" ) == 0 ) {
if ( sty != ACL_STYLE_REGEX && sty != ACL_STYLE_BASE ) {
@ -2282,11 +2235,7 @@ acl_usage( void )
"\t[domain[.<domainstyle>]=<domain>] [sockurl[.<style>]=<url>]\n"
#ifdef SLAP_DYNACL
"\t[dynacl/<name>[/<options>][.<dynstyle>][=<pattern>]]\n"
#else /* ! SLAP_DYNACL */
#ifdef SLAPD_ACI_ENABLED
"\t[aci[=<attrname>]]\n"
#endif /* SLAPD_ACI_ENABLED */
#endif /* ! SLAP_DYNACL */
#endif /* SLAP_DYNACL */
"\t[ssf=<n>] [transport_ssf=<n>] [tls_ssf=<n>] [sasl_ssf=<n>]\n"
"<style> ::= exact | regex | base(Object)\n"
"<dnstyle> ::= base(Object) | one(level) | sub(tree) | children | "
@ -2731,13 +2680,6 @@ access2text( Access *b, char *ptr )
}
}
}
#else /* ! SLAP_DYNACL */
#ifdef SLAPD_ACI_ENABLED
if ( b->a_aci_at != NULL ) {
ptr = lutil_strcopy( ptr, " aci=" );
ptr = lutil_strcopy( ptr, b->a_aci_at->ad_cname.bv_val );
}
#endif
#endif /* SLAP_DYNACL */
/* Security Strength Factors */

View File

@ -34,24 +34,11 @@ LDAP_BEGIN_DECL
/*
* aci.c
*/
#ifdef SLAPD_ACI_ENABLED
LDAP_SLAPD_F (int) aci_mask LDAP_P((
Operation *op, Entry *e,
AttributeDescription *desc,
struct berval *val,
struct berval *aci,
int nmatch,
regmatch_t *matches,
slap_access_t *grant,
slap_access_t *deny,
slap_aci_scope_t scope));
#ifdef SLAP_DYNACL
#ifdef SLAPD_ACI_ENABLED
LDAP_SLAPD_F (int) dynacl_aci_init LDAP_P(( void ));
#else /* !SLAP_DYNACL */
LDAP_SLAPD_F (int) aci_init LDAP_P(( void ));
LDAP_SLAPD_V (AttributeDescription *) slap_ad_aci;
#endif /* !SLAP_DYNACL */
#endif /* SLAPD_ACI_ENABLED */
#endif /* SLAP_DYNACL */
/*
* acl.c

View File

@ -67,7 +67,6 @@ LDAP_BEGIN_DECL
#define SLAP_ACL_HONOR_DISCLOSE /* partially implemented */
#define SLAP_ACL_HONOR_MANAGE /* not yet implemented */
#define SLAP_DYNACL
#define SLAP_OVERLAY_ACCESS
#define LDAP_COMP_MATCH
#define LDAP_DYNAMIC_OBJECTS
@ -211,13 +210,6 @@ LDAP_BEGIN_DECL
#define SLAPD_ROLE_ATTR "roleOccupant"
#define SLAPD_ROLE_CLASS "organizationalRole"
#ifdef SLAPD_ACI_ENABLED
#define SLAPD_ACI_SYNTAX "1.3.6.1.4.1.4203.666.2.1"
#endif /* SLAPD_ACI_ENABLED */
/* change this to "OpenLDAPset" */
#define SLAPD_ACI_SET_ATTR "template"
#define SLAPD_TOP_OID "2.5.6.0"
LDAP_SLAPD_V (int) slap_debug;
@ -1480,12 +1472,15 @@ typedef struct slap_acl {
struct slap_acl *acl_next;
} AccessControl;
typedef enum {
ACL_STATE_NOT_RECORDED = 0x0,
ACL_STATE_RECORDED_VD = 0x1,
ACL_STATE_RECORDED_NV = 0x2,
ACL_STATE_RECORDED = ( ACL_STATE_RECORDED_VD | ACL_STATE_RECORDED_NV )
} slap_acl_state_t;
typedef struct slap_acl_state {
unsigned as_recorded;
#define ACL_STATE_NOT_RECORDED 0x0
#define ACL_STATE_RECORDED_VD 0x1
#define ACL_STATE_RECORDED_NV 0x2
#define ACL_STATE_RECORDED 0x3
slap_acl_state_t as_recorded;
/* Access state */
AccessControl *as_vd_acl;

View File

@ -28,6 +28,8 @@ argsfile @TESTDIR@/slapd.1.args
#mod#moduleload back_@BACKEND@.la
#monitormod#modulepath ../servers/slapd/back-monitor/
#monitormod#moduleload back_monitor.la
#acimod#modulepath ../servers/slapd/
#acimod#moduleload aci.la
#######################################################################
# database definitions
@ -51,7 +53,7 @@ rootpw secret
#ldbm#index cn,sn,uid pres,eq,sub
access to dn.subtree="dc=example,dc=com"
by aci write
by dynacl/aci write
#monitor#database monitor