diff -ur openldap-2.3.11/servers/slapd/acl.c openldap-2.3.11-mod-clean/servers/slapd/acl.c --- openldap-2.3.11/servers/slapd/acl.c 2005-09-27 17:30:30.000000000 -0700 +++ openldap-2.3.11-mod-clean/servers/slapd/acl.c 2005-10-17 21:15:53.507227000 -0700 @@ -885,6 +885,50 @@ Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] matched\n", *count, 0, 0 ); } + else if ( a->acl_c_dn_rels[0] != 0 ) + { + int i = 0, dn_rels_match = 0; + slap_acl_rels_t acl_rels; + + if (!op->o_conn->c_ndn.bv_len) + continue; + + while ( acl_rels = a->acl_c_dn_rels[i++] ) + { + struct berval eparent = { 0, NULL }; + struct berval cparent = { 0, NULL }; + + Debug( LDAP_DEBUG_ACL, "=> binddn_rel: [%d] %d\n", + *count, acl_rels, 0 ); + if ( acl_rels == ACL_RELS_CHILDREN ) + { + dnParent( &e->e_nname, &eparent ); + if ( eparent.bv_len && dn_match( &op->o_conn->c_ndn, &eparent ) ) + dn_rels_match = 1; + } + else if ( acl_rels == ACL_RELS_SELF ) + { + if ( dn_match( &op->o_conn->c_ndn, &e->e_nname ) ) + dn_rels_match = 1; + } + else if ( acl_rels == ACL_RELS_PEERS ) + { + dnParent( &e->e_nname, &eparent ); + dnParent( &op->o_conn->c_ndn, &cparent ); + if ( eparent.bv_len && cparent.bv_len && dn_match( &cparent, &eparent ) ) + dn_rels_match = 1; + } + + if (dn_rels_match) + { + Debug( LDAP_DEBUG_ACL, "=> acl_get: [%d] matched\n", + *count, 0, 0 ); + break; + } + } + if (!dn_rels_match) + continue; + } if ( a->acl_attrs && !ad_inlist( desc, a->acl_attrs ) ) { matches[0].rm_so = matches[0].rm_eo = -1; diff -ur openldap-2.3.11/servers/slapd/aclparse.c openldap-2.3.11-mod-clean/servers/slapd/aclparse.c --- openldap-2.3.11/servers/slapd/aclparse.c 2005-09-27 17:30:30.000000000 -0700 +++ openldap-2.3.11-mod-clean/servers/slapd/aclparse.c 2005-10-17 20:59:06.294347000 -0700 @@ -341,6 +341,7 @@ acl_usage(); } a = (AccessControl *) ch_calloc( 1, sizeof(AccessControl) ); + a->acl_c_dn_rels[0] = 0; for ( ++i; i < argc; i++ ) { if ( strcasecmp( argv[i], "by" ) == 0 ) { i--; @@ -357,6 +358,20 @@ fname, lineno, 0 ); acl_usage(); } + if( a->acl_c_dn_rels[0] != 0 ) { + fprintf( stderr, + "%s: line %d: and binddn_rel=" + " already specified in to clause.\n", + fname, lineno ); + acl_usage(); + } + if( a->acl_c_dn_rels[0] != 0 ) { + fprintf( stderr, + "%s: line %d: cannot specify both dn= and binddn_rel=" + " in to clause.\n", + fname, lineno ); + acl_usage(); + } ber_str2bv( "*", STRLENOF( "*" ), 1, &a->acl_dn_pat ); continue; @@ -444,6 +459,58 @@ continue; } + if ( strncasecmp( left, "binddn_rel", 10 ) == 0 ) { + char **rlist, **r; + int rc = 0; + + /* binddn_rel= and dn= are mutually exclusive */ + if( a->acl_dn_pat.bv_len ) { + fprintf( stderr, + "%s: line %d: cannot specify both dn= and binddn_rel=" + " in to clause.\n", + fname, lineno ); + acl_usage(); + } + if( a->acl_c_dn_rels[0] != 0 ) { + fprintf( stderr, + "%s: line %d: binddn_rels list" + " already specified in to clause.\n", + fname, lineno ); + acl_usage(); + } + r = ldap_str2charray( right, "," ); + + for ( rlist = r; *rlist != NULL && rc < 10; rlist++) + { + if ( strcasecmp( *rlist, "children" ) == 0 ) + { + a->acl_c_dn_rels[rc++] = ACL_RELS_CHILDREN; + } + else if ( strcasecmp( *rlist, "self" ) == 0 ) + { + a->acl_c_dn_rels[rc++] = ACL_RELS_SELF; + } + else if ( strcasecmp( *rlist, "peers" ) == 0 ) + { + a->acl_c_dn_rels[rc++] = ACL_RELS_PEERS; + } + else + { + fprintf( stderr, + "%s: line %d: invalid value for binddn_rel [%s].\n", + fname, lineno, *rlist ); + acl_usage(); + } + } + + a->acl_c_dn_rels[rc] = 0; + + ldap_charray_free( r ); + + continue; + } + + if ( strcasecmp( left, "filter" ) == 0 ) { if ( (a->acl_filter = str2filter( right )) == NULL ) { Debug( LDAP_DEBUG_ANY, @@ -2239,9 +2306,11 @@ "[ by [ ] ]+ \n"; char *what = - " ::= * | [dn[.]=] [filter=] [attrs=]\n" + " ::= * | [dn[.]= | binddn_rels=] [filter=] [attrs=]\n" " ::= [val[/matchingRule][.]=] | , \n" - " ::= | entry | children\n"; + " ::= | entry | children\n" + " ::= | , \n" + " ::= peers | self | children\n"; char *who = " ::= [ * | anonymous | users | self | dn[.]= ]\n" @@ -2771,6 +2840,38 @@ ptr = lutil_strcopy( ptr, "\"\n" ); } + if ( a->acl_c_dn_rels[0] != 0 ) { + int i = 0, first = 1; + char *v; + slap_acl_rels_t acl_rels; + to++; + fprintf( stderr, " binddn_rels=" ); + while ( acl_rels = a->acl_c_dn_rels[i++] ) + { + if ( ! first ) { + fprintf( stderr, "," ); + } + switch (acl_rels) + { + case ACL_RELS_CHILDREN: + v = "children"; + break; + case ACL_RELS_PEERS: + v = "peers"; + break; + case ACL_RELS_SELF: + v = "self"; + break; + default: + v = "UNKNOWN"; + break; + } + fprintf( stderr, v ); + first = 0; + } + fprintf( stderr, "\n" ); + } + if ( a->acl_filter != NULL ) { struct berval bv = BER_BVNULL; diff -ur openldap-2.3.11/servers/slapd/slap.h openldap-2.3.11-mod-clean/servers/slapd/slap.h --- openldap-2.3.11/servers/slapd/slap.h 2005-10-12 14:33:52.000000000 -0700 +++ openldap-2.3.11-mod-clean/servers/slapd/slap.h 2005-10-17 20:52:37.353475000 -0700 @@ -1251,6 +1251,12 @@ ACL_STYLE_PATH } slap_style_t; +typedef enum slap_acl_rels_e { + ACL_RELS_CHILDREN = 1, + ACL_RELS_SELF, + ACL_RELS_PEERS +} slap_acl_rels_t; + typedef struct slap_authz_info { ber_tag_t sai_method; /* LDAP_AUTH_* from */ struct berval sai_mech; /* SASL Mechanism */ @@ -1461,6 +1467,7 @@ slap_style_t acl_dn_style; regex_t acl_dn_re; struct berval acl_dn_pat; + slap_acl_rels_t acl_c_dn_rels[10]; AttributeName *acl_attrs; MatchingRule *acl_attrval_mr; slap_style_t acl_attrval_style;