- a = attr_find( rs->sr_entry->e_attrs, desc );
- if ( a != NULL ) {
- int i;
-
- for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ )
- ;
-
- bvalsp = a->a_nvals;
- }
- }
- }
-
- if ( bvals ) {
- p->bvals = slap_set_join( p->cookie, p->bvals,
- ( '|' | SLAP_SET_RREF ), bvalsp );
- }
-
- } else {
- assert( rs->sr_type == REP_RESULT );
- }
-
- return 0;
-}
-
-BerVarray
-aci_set_gather( SetCookie *cookie, struct berval *name, AttributeDescription *desc )
-{
- AciSetCookie *cp = (AciSetCookie *)cookie;
- int rc = 0;
- LDAPURLDesc *ludp = NULL;
- Operation op2 = { 0 };
- SlapReply rs = {REP_RESULT};
- AttributeName anlist[ 2 ], *anlistp = NULL;
- int nattrs = 0;
- slap_callback cb = { NULL, aci_set_cb_gather, NULL, NULL };
- aci_set_gather_t p = { 0 };
- const char *text = NULL;
- static struct berval defaultFilter_bv = BER_BVC( "(objectClass=*)" );
-
- /* this routine needs to return the bervals instead of
- * plain strings, since syntax is not known. It should
- * also return the syntax or some "comparison cookie".
- */
- if ( strncasecmp( name->bv_val, "ldap:///", STRLENOF( "ldap:///" ) ) != 0 ) {
- return aci_set_gather2( cookie, name, desc );
- }
-
- rc = ldap_url_parse( name->bv_val, &ludp );
- if ( rc != LDAP_URL_SUCCESS ) {
- rc = LDAP_PROTOCOL_ERROR;
- goto url_done;
- }
-
- if ( ( ludp->lud_host && ludp->lud_host[0] ) || ludp->lud_exts )
- {
- /* host part must be empty */
- /* extensions parts must be empty */
- rc = LDAP_PROTOCOL_ERROR;
- goto url_done;
- }
-
- /* Grab the searchbase and see if an appropriate database can be found */
- ber_str2bv( ludp->lud_dn, 0, 0, &op2.o_req_dn );
- rc = dnNormalize( 0, NULL, NULL, &op2.o_req_dn,
- &op2.o_req_ndn, cp->op->o_tmpmemctx );
- BER_BVZERO( &op2.o_req_dn );
- if ( rc != LDAP_SUCCESS ) {
- goto url_done;
- }
-
- op2.o_bd = select_backend( &op2.o_req_ndn, 0, 1 );
- if ( ( op2.o_bd == NULL ) || ( op2.o_bd->be_search == NULL ) ) {
- rc = LDAP_NO_SUCH_OBJECT;
- goto url_done;
- }
-
- /* Grab the filter */
- if ( ludp->lud_filter ) {
- ber_str2bv_x( ludp->lud_filter, 0, 0, &op2.ors_filterstr,
- cp->op->o_tmpmemctx );
-
- } else {
- op2.ors_filterstr = defaultFilter_bv;
- }
-
- op2.ors_filter = str2filter_x( cp->op, op2.ors_filterstr.bv_val );
- if ( op2.ors_filter == NULL ) {
- rc = LDAP_PROTOCOL_ERROR;
- goto url_done;
- }
-
- /* Grab the scope */
- op2.ors_scope = ludp->lud_scope;
-
- /* Grap the attributes */
- if ( ludp->lud_attrs ) {
- for ( ; ludp->lud_attrs[ nattrs ]; nattrs++ )
- ;
-
- anlistp = slap_sl_malloc( sizeof( AttributeName ) * ( nattrs + 2 ),
- cp->op->o_tmpmemctx );
-
- for ( ; ludp->lud_attrs[ nattrs ]; nattrs++ ) {
- ber_str2bv( ludp->lud_attrs[ nattrs ], 0, 0, &anlistp[ nattrs ].an_name );
- anlistp[ nattrs ].an_desc = NULL;
- rc = slap_bv2ad( &anlistp[ nattrs ].an_name,
- &anlistp[ nattrs ].an_desc, &text );
- if ( rc != LDAP_SUCCESS ) {
- goto url_done;
- }
- }
-
- } else {
- anlistp = anlist;
- }
-
- anlistp[ nattrs ].an_name = desc->ad_cname;
- anlistp[ nattrs ].an_desc = desc;
-
- BER_BVZERO( &anlistp[ nattrs + 1 ].an_name );
-
- p.cookie = cookie;
-
- op2.o_tag = LDAP_REQ_SEARCH;
- op2.o_protocol = LDAP_VERSION3;
- op2.o_ndn = op2.o_bd->be_rootndn;
- op2.o_callback = &cb;
- op2.o_time = slap_get_time();
- op2.o_do_not_cache = 1;
- op2.o_is_auth_check = 0;
- op2.o_threadctx = cp->op->o_threadctx;
- op2.o_tmpmemctx = cp->op->o_tmpmemctx;
- op2.o_tmpmfuncs = cp->op->o_tmpmfuncs;
-#ifdef LDAP_SLAPI
- op2.o_pb = cp->op->o_pb;
-#endif
- op2.o_conn = cp->op->o_conn;
- op2.o_connid = cp->op->o_connid;
- ber_dupbv_x( &op2.o_req_dn, &op2.o_req_ndn, cp->op->o_tmpmemctx );
- op2.ors_slimit = SLAP_NO_LIMIT;
- op2.ors_tlimit = SLAP_NO_LIMIT;
- op2.ors_attrs = anlistp;
- op2.ors_attrsonly = 0;
-
- cb.sc_private = &p;
-
- rc = op2.o_bd->be_search( &op2, &rs );
- if ( rc != 0 ) {
- goto url_done;
- }
-
-url_done:;
- if ( op2.ors_filter ) {
- filter_free_x( cp->op, op2.ors_filter );
- }
- if ( !BER_BVISNULL( &op2.o_req_ndn ) ) {
- slap_sl_free( op2.o_req_ndn.bv_val, cp->op->o_tmpmemctx );
- }
- if ( !BER_BVISNULL( &op2.o_req_dn ) ) {
- slap_sl_free( op2.o_req_dn.bv_val, cp->op->o_tmpmemctx );
- }
- if ( ludp ) {
- ldap_free_urldesc( ludp );
- }
- if ( anlistp && anlistp != anlist ) {
- slap_sl_free( anlistp, cp->op->o_tmpmemctx );
- }
-
- return p.bvals;
-}
-
-BerVarray
-aci_set_gather2( SetCookie *cookie, struct berval *name, AttributeDescription *desc )
-{
- AciSetCookie *cp = (AciSetCookie *)cookie;
- BerVarray bvals = NULL;
- struct berval ndn;
- int rc = 0;
-
- /* this routine needs to return the bervals instead of
- * plain strings, since syntax is not known. It should
- * also return the syntax or some "comparison cookie".
- */
- rc = dnNormalize( 0, NULL, NULL, name, &ndn, cp->op->o_tmpmemctx );
- if ( rc == LDAP_SUCCESS ) {
- if ( desc == slap_schema.si_ad_entryDN ) {
- bvals = (BerVarray)slap_sl_malloc( sizeof( BerValue ) * 2,
- cp->op->o_tmpmemctx );
- bvals[ 0 ] = ndn;
- BER_BVZERO( &bvals[ 1 ] );
- BER_BVZERO( &ndn );
-
- } else {
- backend_attribute( cp->op,
- cp->e, &ndn, desc, &bvals, ACL_NONE );
- }
-
- if ( !BER_BVISNULL( &ndn ) ) {
- slap_sl_free( ndn.bv_val, cp->op->o_tmpmemctx );
- }
- }
-
- return bvals;
-}
-
-static int
-aci_match_set (
- struct berval *subj,
- Operation *op,
- Entry *e,
- int setref
-)
-{
- struct berval set = BER_BVNULL;
- int rc = 0;
- AciSetCookie cookie;
-
- if (setref == 0) {
- ber_dupbv_x( &set, subj, op->o_tmpmemctx );
- } else {
- struct berval subjdn, ndn = BER_BVNULL;
- struct berval setat;
- BerVarray bvals;
- const char *text;
- AttributeDescription *desc = NULL;
-
- /* format of string is "entry/setAttrName" */
- if ( aci_get_part( subj, 0, '/', &subjdn ) < 0 ) {
- return(0);
- }
-
- if ( aci_get_part( subj, 1, '/', &setat ) < 0 ) {
- setat = aci_bv_set_attr;
- }
-
- /*
- * NOTE: dnNormalize honors the ber_len field
- * as the length of the dn to be normalized
- */
- if ( slap_bv2ad( &setat, &desc, &text ) == LDAP_SUCCESS ) {
- if ( dnNormalize( 0, NULL, NULL, &subjdn, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS )
- {
- backend_attribute( op, e, &ndn, desc, &bvals, ACL_NONE );
- if ( bvals != NULL && !BER_BVISNULL( &bvals[0] ) ) {
- int i;
-
- set = bvals[0];
- BER_BVZERO( &bvals[0] );
- for ( i = 1; !BER_BVISNULL( &bvals[i] ); i++ )
- /* count */ ;
- bvals[0].bv_val = bvals[i-1].bv_val;
- BER_BVZERO( &bvals[i-1] );
- }
- ber_bvarray_free_x( bvals, op->o_tmpmemctx );
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
- }
- }
- }
-
- if ( !BER_BVISNULL( &set ) ) {
- cookie.op = op;
- cookie.e = e;
- rc = ( slap_set_filter( aci_set_gather, (SetCookie *)&cookie, &set,
- &op->o_ndn, &e->e_nname, NULL ) > 0 );
- slap_sl_free( set.bv_val, op->o_tmpmemctx );
- }
-
- return(rc);
-}
-
-#ifdef SLAPD_ACI_ENABLED
-static int
-aci_list_map_rights(
- struct berval *list )
-{
- struct berval bv;
- slap_access_t mask;
- int i;
-
- ACL_INIT(mask);
- for (i = 0; aci_get_part(list, i, ',', &bv) >= 0; i++) {
- if (bv.bv_len <= 0)
- continue;
- switch (*bv.bv_val) {
- case 'c':
- ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
- break;
- case 's':
- /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
- * the right 's' to mean "set", but in the examples states
- * that the right 's' means "search". The latter definition
- * is used here.
- */
- ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
- break;
- case 'r':
- ACL_PRIV_SET(mask, ACL_PRIV_READ);
- break;
- case 'w':
- ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
- break;
- case 'x':
- /* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not
- * define any equivalent to the AUTH right, so I've just used
- * 'x' for now.
- */
- ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
- break;
- default:
- break;
- }
-
- }
- return(mask);
-}
-
-static int
-aci_list_has_attr(
- struct berval *list,
- const struct berval *attr,
- struct berval *val )
-{
- struct berval bv, left, right;
- int i;
-
- for (i = 0; aci_get_part(list, i, ',', &bv) >= 0; i++) {
- if (aci_get_part(&bv, 0, '=', &left) < 0
- || aci_get_part(&bv, 1, '=', &right) < 0)
- {
- if (ber_bvstrcasecmp(attr, &bv) == 0)
- return(1);
- } else if (val == NULL) {
- if (ber_bvstrcasecmp(attr, &left) == 0)
- return(1);
- } else {
- if (ber_bvstrcasecmp(attr, &left) == 0) {
- /* this is experimental code that implements a
- * simple (prefix) match of the attribute value.
- * the ACI draft does not provide for aci's that
- * apply to specific values, but it would be
- * nice to have. If the <attr> part of an aci's
- * rights list is of the form <attr>=<value>,
- * that means the aci applies only to attrs with
- * the given value. Furthermore, if the attr is
- * of the form <attr>=<value>*, then <value> is
- * treated as a prefix, and the aci applies to
- * any value with that prefix.
- *
- * Ideally, this would allow r.e. matches.
- */
- if (aci_get_part(&right, 0, '*', &left) < 0
- || right.bv_len <= left.bv_len)
- {
- if (ber_bvstrcasecmp(val, &right) == 0)
- return(1);
- } else if (val->bv_len >= left.bv_len) {
- if (strncasecmp( val->bv_val, left.bv_val, left.bv_len ) == 0)
- return(1);
- }
- }
- }
- }
- return(0);
-}
-
-static slap_access_t
-aci_list_get_attr_rights(
- struct berval *list,
- const struct berval *attr,
- struct berval *val )
-{
- struct berval bv;
- slap_access_t mask;
- int i;
-
- /* loop through each rights/attr pair, skip first part (action) */
- ACL_INIT(mask);
- for (i = 1; aci_get_part(list, i + 1, ';', &bv) >= 0; i += 2) {
- if (aci_list_has_attr(&bv, attr, val) == 0)
- continue;
- if (aci_get_part(list, i, ';', &bv) < 0)
- continue;
- mask |= aci_list_map_rights(&bv);
- }
- return(mask);
-}
-
-static int
-aci_list_get_rights(
- struct berval *list,
- const struct berval *attr,
- struct berval *val,
- slap_access_t *grant,
- slap_access_t *deny )
-{
- struct berval perm, actn;
- slap_access_t *mask;
- int i, found;
-
- if (attr == NULL || attr->bv_len == 0
- || ber_bvstrcasecmp( attr, &aci_bv_entry ) == 0) {
- attr = &aci_bv_br_entry;
- }
-
- found = 0;
- ACL_INIT(*grant);
- ACL_INIT(*deny);
- /* loop through each permissions clause */
- for (i = 0; aci_get_part(list, i, '$', &perm) >= 0; i++) {
- if (aci_get_part(&perm, 0, ';', &actn) < 0)
- continue;
- if (ber_bvstrcasecmp( &aci_bv_grant, &actn ) == 0) {
- mask = grant;
- } else if (ber_bvstrcasecmp( &aci_bv_deny, &actn ) == 0) {
- mask = deny;
- } else {
- continue;
- }
-
- found = 1;
- *mask |= aci_list_get_attr_rights(&perm, attr, val);
- *mask |= aci_list_get_attr_rights(&perm, &aci_bv_br_all, NULL);
- }
- return(found);
-}
-
-static int
-aci_group_member (
- struct berval *subj,
- struct berval *defgrpoc,
- struct berval *defgrpat,
- Operation *op,
- Entry *e,
- int nmatch,
- regmatch_t *matches
-)
-{
- struct berval subjdn;
- struct berval grpoc;
- struct berval grpat;
- ObjectClass *grp_oc = NULL;
- AttributeDescription *grp_ad = NULL;
- const char *text;
- int rc;
-
- /* format of string is "group/objectClassValue/groupAttrName" */
- if (aci_get_part(subj, 0, '/', &subjdn) < 0) {
- return(0);
- }
-
- if (aci_get_part(subj, 1, '/', &grpoc) < 0) {
- grpoc = *defgrpoc;
- }
-
- if (aci_get_part(subj, 2, '/', &grpat) < 0) {
- grpat = *defgrpat;
- }
-
- rc = slap_bv2ad( &grpat, &grp_ad, &text );
- if( rc != LDAP_SUCCESS ) {
- rc = 0;
- goto done;
- }
- rc = 0;
-
- grp_oc = oc_bvfind( &grpoc );
-
- if (grp_oc != NULL && grp_ad != NULL ) {
- char buf[ACL_BUF_SIZE];
- struct berval bv, ndn;
- bv.bv_len = sizeof( buf ) - 1;
- bv.bv_val = (char *)&buf;
- if ( string_expand(&bv, &subjdn,
- e->e_ndn, nmatch, matches) )
- {
- rc = LDAP_OTHER;
- goto done;
- }
- if ( dnNormalize( 0, NULL, NULL, &bv, &ndn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
- rc = ( backend_group( op, e, &ndn, &op->o_ndn,
- grp_oc, grp_ad ) == 0 );
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
- }
- }
-
-done:
- return(rc);
-}
-
-static int
-aci_mask(
- 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 asserted_scope
-)
-{
- struct berval bv, scope, perms, type, sdn;
- int rc;
-
-
- assert( !BER_BVISNULL( &desc->ad_cname ) );
-
- /* parse an aci of the form:
- oid # scope # action;rights;attr;rights;attr
- $ action;rights;attr;rights;attr # type # subject
-
- [NOTE: the following comment is very outdated,
- as the draft version it refers to (Ando, 2004-11-20)].
-
- See draft-ietf-ldapext-aci-model-04.txt section 9.1 for
- a full description of the format for this attribute.
- Differences: "this" in the draft is "self" here, and
- "self" and "public" is in the position of type.
-
- <scope> = {entry|children|subtree}
- <type> = {public|users|access-id|subtree|onelevel|children|
- self|dnattr|group|role|set|set-ref}
-
- This routine now supports scope={ENTRY,CHILDREN}
- with the semantics:
- - ENTRY applies to "entry" and "subtree";
- - CHILDREN aplies to "children" and "subtree"
- */
-
- /* check that the aci has all 5 components */
- if ( aci_get_part( aci, 4, '#', NULL ) < 0 ) {
- return 0;
- }
-
- /* check that the aci family is supported */
- if ( aci_get_part( aci, 0, '#', &bv ) < 0 ) {
- return 0;
- }
-
- /* check that the scope matches */
- if ( aci_get_part( aci, 1, '#', &scope ) < 0 ) {
- return 0;
- }
-
- /* note: scope can be either ENTRY or CHILDREN;
- * they respectively match "entry" and "children" in bv
- * both match "subtree" */
- switch ( asserted_scope ) {
- case SLAP_ACI_SCOPE_ENTRY:
- if ( ber_bvstrcasecmp( &scope, &aci_bv_entry ) != 0
- && ber_bvstrcasecmp( &scope, &aci_bv_subtree ) != 0 )
- {
- return 0;
- }
- break;
-
- case SLAP_ACI_SCOPE_CHILDREN:
- if ( ber_bvstrcasecmp( &scope, &aci_bv_children ) != 0
- && ber_bvstrcasecmp( &scope, &aci_bv_subtree ) != 0 )
- {
- return 0;
- }
- break;
-
- default:
- return 0;
- }
-
- /* get the list of permissions clauses, bail if empty */
- if ( aci_get_part( aci, 2, '#', &perms ) <= 0 ) {
- return 0;
- }
-
- /* check if any permissions allow desired access */
- if ( aci_list_get_rights( &perms, &desc->ad_cname, val, grant, deny ) == 0 ) {
- return 0;
- }
-
- /* see if we have a DN match */
- if ( aci_get_part( aci, 3, '#', &type ) < 0 ) {
- return 0;
- }
-
- /* see if we have a public (i.e. anonymous) access */
- if ( ber_bvstrcasecmp( &aci_bv_public, &type ) == 0 ) {
- return 1;
- }
-
- /* otherwise require an identity */
- if ( BER_BVISNULL( &op->o_ndn ) || BER_BVISEMPTY( &op->o_ndn ) ) {
- return 0;
- }
-
- /* see if we have a users access */
- if ( ber_bvstrcasecmp( &aci_bv_users, &type ) == 0 ) {
- return 1;
- }
-
- /* NOTE: this may fail if a DN contains a valid '#' (unescaped);
- * just grab all the berval up to its end (ITS#3303).
- * NOTE: the problem could be solved by providing the DN with
- * the embedded '#' encoded as hexpairs: "cn=Foo#Bar" would
- * become "cn=Foo\23Bar" and be safely used by aci_mask(). */
-#if 0
- if ( aci_get_part( aci, 4, '#', &sdn ) < 0 ) {
- return 0;
- }
-#endif
- sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
- sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );
-
- if ( ber_bvstrcasecmp( &aci_bv_access_id, &type ) == 0 ) {
- struct berval ndn;
-
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- if ( dn_match( &op->o_ndn, &ndn ) ) {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
-
- return rc;
-
- } else if ( ber_bvstrcasecmp( &aci_bv_subtree, &type ) == 0 ) {
- struct berval ndn;
-
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- if ( dnIsSuffix( &op->o_ndn, &ndn ) ) {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
-
- return rc;
-
- } else if ( ber_bvstrcasecmp( &aci_bv_onelevel, &type ) == 0 ) {
- struct berval ndn, pndn;
-
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- dnParent( &ndn, &pndn );
-
- if ( dn_match( &op->o_ndn, &pndn ) ) {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
-
- return rc;
-
- } else if ( ber_bvstrcasecmp( &aci_bv_children, &type ) == 0 ) {
- struct berval ndn;
-
- rc = dnNormalize( 0, NULL, NULL, &sdn, &ndn, op->o_tmpmemctx );
- if ( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- if ( !dn_match( &op->o_ndn, &ndn )
- && dnIsSuffix( &op->o_ndn, &ndn ) )
- {
- rc = 1;
- }
- slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
-
- return rc;
-
- } else if ( ber_bvstrcasecmp( &aci_bv_self, &type ) == 0 ) {
- if ( dn_match( &op->o_ndn, &e->e_nname ) ) {
- return 1;
- }
-
- } else if ( ber_bvstrcasecmp( &aci_bv_dnattr, &type ) == 0 ) {
- Attribute *at;
- AttributeDescription *ad = NULL;
- const char *text;
-
- rc = slap_bv2ad( &sdn, &ad, &text );
-
- if( rc != LDAP_SUCCESS ) {
- return 0;
- }
-
- rc = 0;
-
- for ( at = attrs_find( e->e_attrs, ad );
- at != NULL;
- at = attrs_find( at->a_next, ad ) )
- {
- if ( value_find_ex( ad,
- SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
- SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
- at->a_nvals,
- &op->o_ndn, op->o_tmpmemctx ) == 0 )
- {
- rc = 1;
- break;
- }
- }
-
- return rc;