idattr_check_isuser ( Operation *op, Entry *user, AttributeDescription *searchAttr, idattr_t *id) { int rc = LDAP_INSUFFICIENT_ACCESS; Attribute *theAttr = NULL; if (id->idattr_type == SELFWRITE_TYPE || id->idattr_type == OWNER_TYPE || id->idattr_type == USERS_TYPE) { if ((op->o_conn->c_authz.c_sai_krb5_auth_data_provisioned && (id->idattr_type == OWNER_TYPE || id->idattr_type == USERS_TYPE)) || (user != NULL)) { rc = LDAP_SUCCESS; } else { rc = LDAP_INSUFFICIENT_ACCESS; } } else if (op->o_conn->c_authz.c_sai_krb5_auth_data_provisioned) { if (ber_bvcmp(&op->o_conn->c_authz.c_sai_krb5_pac_id , &id->idattr_pat) == 0) { rc = LDAP_SUCCESS; } else { rc = LDAP_INSUFFICIENT_ACCESS; } } else { theAttr = attr_find( user->e_attrs, searchAttr); if ( !theAttr || !BER_BVISNULL( &theAttr->a_nvals[ 1 ] ) ) { rc = LDAP_NO_SUCH_ATTRIBUTE; } else { // check user match rc = value_find_ex( searchAttr, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, theAttr->a_nvals, &(id->idattr_pat), op->o_tmpmemctx ); Debug( LDAP_DEBUG_ACL, "#####idattr_check_isuser <Find By ID> value_find_ex [%d]#####\n", rc, 0, 0); #ifdef PAC_PROXY_USERS if (rc != LDAP_SUCCESS) { theAttr = attr_find( user->e_attrs, idattr_memberships); if ( !theAttr || !BER_BVISNULL( &theAttr->a_nvals[ 1 ] ) ) { rc = LDAP_NO_SUCH_ATTRIBUTE; } else { rc = value_find_ex( idattr_memberships, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, theAttr->a_nvals, &(id->idattr_pat), op->o_tmpmemctx ); Debug( LDAP_DEBUG_ACL, "#####idattr_check_isuser <Find By GROUP ID> value_find_ex [%d]#####\n", rc, 0, 0); } } #endif } } return rc; }
idattr_check_applyto ( Operation *op, Entry *target, AttributeDescription *searchAttr, idattr_t *id) { int rc = LDAP_INSUFFICIENT_ACCESS; int entry_rc = LDAP_NO_SUCH_OBJECT; Entry *theEntry = NULL; // is target a member of APPLYTO group // retrieve and cache dn of APPLYTO group if (BER_BVISNULL(&id->idattr_applyto_dn)) { idattr_id_to_dn (op,searchAttr, &(id->idattr_applyto_uuid), &(id->idattr_applyto_dn)); Debug( LDAP_DEBUG_ACL, "idattr_dynacl_mask: len[%d] idattr_applyto_dn[%s] \n", id->idattr_applyto_dn.bv_len, id->idattr_applyto_dn.bv_val, 0 ); } if (!BER_BVISNULL(&id->idattr_applyto_dn)) { entry_rc = be_entry_get_rw( op, &target->e_nname, NULL , idattr_uuid, 0, &theEntry ); if (entry_rc == LDAP_SUCCESS && theEntry) { Attribute *uuidAttr = NULL; u_int32_t isMember = 0; uuidAttr = attr_find( theEntry->e_attrs, idattr_uuid); if (uuidAttr) { entry_rc = value_find_ex( idattr_uuid, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, uuidAttr->a_nvals, &(id->idattr_applyto_uuid), op->o_tmpmemctx ); if (entry_rc == LDAP_SUCCESS) { // TARGET == APPLYTO_TARGET rc = LDAP_SUCCESS; } else { // TARGET == MEMBEROF(APPLYTO) idattr_is_member ( op, &(id->idattr_applyto_dn), idattr_memberships, uuidAttr->a_nvals , &isMember); // flat list if (isMember) { rc = LDAP_SUCCESS; } } } } } exitonerror: if (theEntry) be_entry_release_r(op, theEntry); return rc; }
/* return 0 IFF op_dn is a value in group_at (member) attribute * of entry with gr_dn AND that entry has an objectClass * value of group_oc (groupOfNames) */ int ldap_back_group( Backend *be, Connection *conn, Operation *op, Entry *target, struct berval *gr_ndn, struct berval *op_ndn, ObjectClass *group_oc, AttributeDescription* group_at ) { struct ldapinfo *li = (struct ldapinfo *) be->be_private; int rc = 1; Attribute *attr; LDAPMessage *result; char *gattr[2]; char *filter = NULL, *ptr; LDAP *ld; struct berval mop_ndn = { 0, NULL }, mgr_ndn = { 0, NULL }; AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; struct berval group_oc_name = {0, NULL}; struct berval group_at_name = group_at->ad_cname; if( group_oc->soc_names && group_oc->soc_names[0] ) { group_oc_name.bv_val = group_oc->soc_names[0]; } else { group_oc_name.bv_val = group_oc->soc_oid; } if (group_oc_name.bv_val) group_oc_name.bv_len = strlen(group_oc_name.bv_val); if (target != NULL && dn_match( &target->e_nname, gr_ndn ) ) { /* we already have a copy of the entry */ /* attribute and objectclass mapping has already been done */ /* * first we need to check if the objectClass attribute * has been retieved; otherwise we need to repeat the search */ attr = attr_find( target->e_attrs, ad_objectClass ); if ( attr != NULL ) { /* * Now we can check for the group objectClass value */ if( !is_entry_objectclass( target, group_oc, 0 ) ) { return(1); } /* * This part has been reworked: the group attr compare * fails only if the attribute is PRESENT but the value * is NOT PRESENT; if the attribute is NOT PRESENT, the * search must be repeated as well. * This may happen if a search for an entry has already * been performed (target is not null) but the group * attribute has not been required */ if ((attr = attr_find(target->e_attrs, group_at)) != NULL) { if( value_find_ex( group_at, SLAP_MR_VALUE_NORMALIZED_MATCH, attr->a_vals, op_ndn ) != LDAP_SUCCESS ) return(1); return(0); } /* else: repeat the search */ } /* else: repeat the search */ } /* else: do the search */ /* * Rewrite the op ndn if needed */ #ifdef ENABLE_REWRITE switch ( rewrite_session( li->rwinfo, "bindDn", op_ndn->bv_val, conn, &mop_ndn.bv_val ) ) { case REWRITE_REGEXEC_OK: if ( mop_ndn.bv_val == NULL ) { mop_ndn = *op_ndn; } #ifdef NEW_LOGGING LDAP_LOG( BACK_LDAP, DETAIL1, "[rw] bindDn (op ndn in group): \"%s\" -> \"%s\"\n", op_ndn->bv_val, mop_ndn.bv_val, 0 ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "rw> bindDn (op ndn in group): \"%s\" -> \"%s\"\n%s", op_ndn->bv_val, mop_ndn.bv_val, "" ); #endif /* !NEW_LOGGING */ break; case REWRITE_REGEXEC_UNWILLING: case REWRITE_REGEXEC_ERR: goto cleanup; } /* * Rewrite the gr ndn if needed */ switch ( rewrite_session( li->rwinfo, "searchBase", gr_ndn->bv_val, conn, &mgr_ndn.bv_val ) ) { case REWRITE_REGEXEC_OK: if ( mgr_ndn.bv_val == NULL ) { mgr_ndn = *gr_ndn; } #ifdef NEW_LOGGING LDAP_LOG( BACK_LDAP, DETAIL1, "[rw] searchBase (gr ndn in group): \"%s\" -> \"%s\"\n%s", gr_ndn->bv_val, mgr_ndn.bv_val, "" ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "rw> searchBase (gr ndn in group):" " \"%s\" -> \"%s\"\n%s", gr_ndn->bv_val, mgr_ndn.bv_val, "" ); #endif /* !NEW_LOGGING */ break; case REWRITE_REGEXEC_UNWILLING: case REWRITE_REGEXEC_ERR: goto cleanup; } #else /* !ENABLE_REWRITE */ ldap_back_dn_massage( li, op_ndn, &mop_ndn, 1, 1 ); if ( mop_ndn.bv_val == NULL ) { goto cleanup; } ldap_back_dn_massage( li, gr_ndn, &mgr_ndn, 1, 1 ); if ( mgr_ndn.bv_val == NULL ) { goto cleanup; } #endif /* !ENABLE_REWRITE */ ldap_back_map(&li->oc_map, &group_oc_name, &group_oc_name, BACKLDAP_MAP); if (group_oc_name.bv_val == NULL || group_oc_name.bv_val[0] == '\0') goto cleanup; ldap_back_map(&li->at_map, &group_at_name, &group_at_name, BACKLDAP_MAP); if (group_at_name.bv_val == NULL || group_at_name.bv_val[0] == '\0') goto cleanup; filter = ch_malloc(sizeof("(&(objectclass=)(=))") + group_oc_name.bv_len + group_at_name.bv_len + mop_ndn.bv_len + 1); if (filter == NULL) goto cleanup; if (ldap_initialize(&ld, li->url) != LDAP_SUCCESS) { goto cleanup; } if (ldap_bind_s(ld, li->binddn, li->bindpw, LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) { goto cleanup; } ptr = lutil_strcopy(filter, "(&(objectclass="); ptr = lutil_strcopy(ptr, group_oc_name.bv_val); ptr = lutil_strcopy(ptr, ")("); ptr = lutil_strcopy(ptr, group_at_name.bv_val); ptr = lutil_strcopy(ptr, "="); ptr = lutil_strcopy(ptr, mop_ndn.bv_val); strcpy(ptr, "))"); gattr[0] = "objectclass"; gattr[1] = NULL; if (ldap_search_ext_s(ld, mgr_ndn.bv_val, LDAP_SCOPE_BASE, filter, gattr, 0, NULL, NULL, LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result) == LDAP_SUCCESS) { if (ldap_first_entry(ld, result) != NULL) rc = 0; ldap_msgfree(result); } cleanup:; if ( ld != NULL ) { ldap_unbind(ld); } ch_free(filter); if ( mop_ndn.bv_val != op_ndn->bv_val ) { free( mop_ndn.bv_val ); } if ( mgr_ndn.bv_val != gr_ndn->bv_val ) { free( mgr_ndn.bv_val ); } return(rc); }
int fe_op_compare( Operation *op, SlapReply *rs ) { Entry *entry = NULL; AttributeAssertion *ava = op->orc_ava; BackendDB *bd = op->o_bd; if( strcasecmp( op->o_req_ndn.bv_val, LDAP_ROOT_DSE ) == 0 ) { if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } rs->sr_err = root_dse_info( op->o_conn, &entry, &rs->sr_text ); if( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); rs->sr_err = 0; goto cleanup; } rs->sr_err = schema_info( &entry, &rs->sr_text ); if( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); rs->sr_err = 0; goto cleanup; } } if( entry ) { rs->sr_err = slap_compare_entry( op, entry, ava ); entry_free( entry ); send_ldap_result( op, rs ); if( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) { rs->sr_err = LDAP_SUCCESS; } goto cleanup; } /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ op->o_bd = select_backend( &op->o_req_ndn, 0 ); if ( op->o_bd == NULL ) { rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); rs->sr_err = LDAP_REFERRAL; if (!rs->sr_ref) rs->sr_ref = default_referral; op->o_bd = bd; send_ldap_result( op, rs ); if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref ); rs->sr_err = 0; goto cleanup; } /* check restrictions */ if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } /* check for referrals */ if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { goto cleanup; } if ( SLAP_SHADOW(op->o_bd) && get_dontUseCopy(op) ) { /* don't use shadow copy */ send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "copy not used" ); } else if ( ava->aa_desc == slap_schema.si_ad_entryDN ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "entryDN compare not supported" ); } else if ( ava->aa_desc == slap_schema.si_ad_subschemaSubentry ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "subschemaSubentry compare not supported" ); #ifndef SLAP_COMPARE_IN_FRONTEND } else if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates && op->o_bd->be_has_subordinates ) { int rc, hasSubordinates = LDAP_SUCCESS; rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &entry ); if ( rc == 0 && entry ) { if ( ! access_allowed( op, entry, ava->aa_desc, &ava->aa_value, ACL_COMPARE, NULL ) ) { rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; } else { rc = rs->sr_err = op->o_bd->be_has_subordinates( op, entry, &hasSubordinates ); be_entry_release_r( op, entry ); } } if ( rc == 0 ) { int asserted; asserted = bvmatch( &ava->aa_value, &slap_true_bv ) ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE; if ( hasSubordinates == asserted ) { rs->sr_err = LDAP_COMPARE_TRUE; } else { rs->sr_err = LDAP_COMPARE_FALSE; } } else { /* return error only if "disclose" * is granted on the object */ if ( backend_access( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } } send_ldap_result( op, rs ); if ( rc == 0 ) { rs->sr_err = LDAP_SUCCESS; } } else if ( op->o_bd->be_compare ) { rs->sr_err = op->o_bd->be_compare( op, rs ); #endif /* ! SLAP_COMPARE_IN_FRONTEND */ } else { rs->sr_err = SLAP_CB_CONTINUE; } if ( rs->sr_err == SLAP_CB_CONTINUE ) { /* do our best to compare that AVA * * NOTE: this code is used only * if SLAP_COMPARE_IN_FRONTEND * is #define'd (it's not by default) * or if op->o_bd->be_compare is NULL. * * FIXME: one potential issue is that * if SLAP_COMPARE_IN_FRONTEND overlays * are not executed for compare. */ BerVarray vals = NULL; int rc = LDAP_OTHER; rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, ava->aa_desc, &vals, ACL_COMPARE ); switch ( rs->sr_err ) { default: /* return error only if "disclose" * is granted on the object */ if ( backend_access( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } break; case LDAP_SUCCESS: if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, vals, &ava->aa_value, op->o_tmpmemctx ) == 0 ) { rs->sr_err = LDAP_COMPARE_TRUE; break; } else { rs->sr_err = LDAP_COMPARE_FALSE; } rc = LDAP_SUCCESS; break; } send_ldap_result( op, rs ); if ( rc == 0 ) { rs->sr_err = LDAP_SUCCESS; } if ( vals ) { ber_bvarray_free_x( vals, op->o_tmpmemctx ); } } cleanup:; op->o_bd = bd; return rs->sr_err; }
idattr_check_isowner ( Operation *op, Entry *user, Entry *target, AttributeDescription *searchAttr, idattr_t *id) { int rc = LDAP_INSUFFICIENT_ACCESS; int entry_rc = LDAP_INSUFFICIENT_ACCESS; Entry *targetEntry = NULL; Entry *requestEntry = NULL; Attribute *ownerIDAttr = NULL; if (op->o_conn->c_authz.c_sai_krb5_auth_data_provisioned) { entry_rc = be_entry_get_rw( op, &target->e_nname, NULL, idattr_owneruuid, 0, &targetEntry ); // check target for owner if (entry_rc == LDAP_SUCCESS && targetEntry != NULL) { Attribute *theOwnerIDAttr = NULL; theOwnerIDAttr = attr_find( targetEntry->e_attrs, idattr_owneruuid); if (theOwnerIDAttr && ber_bvcmp(&op->o_conn->c_authz.c_sai_krb5_pac_id , &theOwnerIDAttr->a_nvals[0]) == 0) { rc = LDAP_SUCCESS; Debug(LDAP_DEBUG_ACL, "idattr_check_isowner by request[%s] - PROXYUSER BY TARGET\n", op->o_req_ndn.bv_val, 0, 0); } else { rc = LDAP_INSUFFICIENT_ACCESS; } } // check entry for owner if ((rc != LDAP_SUCCESS) && !BER_BVISNULL(&op->o_req_ndn)) { entry_rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, idattr_owneruuid, 0, &requestEntry ); if (entry_rc == LDAP_SUCCESS && requestEntry != NULL) { Attribute *theOwnerIDAttr = NULL; theOwnerIDAttr = attr_find( requestEntry->e_attrs, idattr_owneruuid); if (theOwnerIDAttr == NULL) { rc = LDAP_INSUFFICIENT_ACCESS; goto exitonerror; } if (ber_bvcmp(&op->o_conn->c_authz.c_sai_krb5_pac_id , &theOwnerIDAttr->a_nvals[0]) == 0) { rc = LDAP_SUCCESS; Debug(LDAP_DEBUG_ACL, "idattr_check_isowner by request[%s] - PROXYUSER BY ENTRY\n", op->o_req_ndn.bv_val, 0, 0); } } } } else { if (user == NULL) { rc = LDAP_INSUFFICIENT_ACCESS; goto exitonerror; } ownerIDAttr = attr_find( user->e_attrs, searchAttr); if (ownerIDAttr == NULL) { rc = LDAP_INSUFFICIENT_ACCESS; goto exitonerror; } entry_rc = be_entry_get_rw( op, &target->e_nname, NULL, idattr_owneruuid, 0, &targetEntry ); if (entry_rc == LDAP_SUCCESS && targetEntry != NULL) { Attribute *theAttr = NULL; theAttr = attr_find( targetEntry->e_attrs, idattr_owneruuid); if (theAttr) { entry_rc = value_find_ex( idattr_owneruuid, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, theAttr->a_nvals, ownerIDAttr->a_nvals, op->o_tmpmemctx ); if (entry_rc == LDAP_SUCCESS) { rc = LDAP_SUCCESS; Debug(LDAP_DEBUG_ACL, "idattr_check_isowner by target[%s]\n", target->e_nname.bv_val, 0, 0); } // check group membership if applicable if (rc != LDAP_SUCCESS) { u_int32_t isMember = 0; if (BER_BVISNULL(&id->idattr_owner_dn)) { idattr_id_to_dn (op,searchAttr, theAttr->a_nvals, &id->idattr_owner_dn); } if (!BER_BVISNULL(&id->idattr_owner_dn) && strstr(id->idattr_owner_dn.bv_val, group_subtree) != NULL) { Debug( LDAP_DEBUG_ACL, "idattr_check_isowner: len[%d] idattr_owner_dn[%s] \n", id->idattr_owner_dn.bv_len, id->idattr_owner_dn.bv_val, 0 ); idattr_is_member ( op, &id->idattr_owner_dn, idattr_memberships, ownerIDAttr->a_nvals , &isMember); if (isMember) { Debug( LDAP_DEBUG_ACL, "idattr_check_isowner: user is member of Group (from target)\n", 0, 0, 0 ); rc = LDAP_SUCCESS; } } } } } // check op->o_req_ndn // target: cn=record,dc=com // request_dn: cn=myrecord,cn=record,dc=com // access to the parent (target) is required prior to requesting right access to the child (request_dn) // lookahead at the child to check for ownership if ((rc != LDAP_SUCCESS) && !BER_BVISNULL(&op->o_req_ndn)) { entry_rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, idattr_owneruuid, 0, &requestEntry ); if (entry_rc == LDAP_SUCCESS && requestEntry != NULL) { Attribute *theAttr = NULL; theAttr = attr_find( requestEntry->e_attrs, idattr_owneruuid); if (theAttr) { entry_rc = value_find_ex( idattr_owneruuid, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, theAttr->a_nvals, ownerIDAttr->a_nvals, op->o_tmpmemctx ); if (entry_rc == LDAP_SUCCESS) { rc = LDAP_SUCCESS; Debug(LDAP_DEBUG_ACL, "idattr_check_isowner by request[%s]\n", op->o_req_ndn.bv_val, 0, 0); } // check group membership if applicable u_int32_t isMember = 0; if (BER_BVISNULL(&id->idattr_owner_dn)) { idattr_id_to_dn (op,searchAttr, theAttr->a_nvals, &id->idattr_owner_dn); } if (!BER_BVISNULL(&id->idattr_owner_dn) && strstr(id->idattr_owner_dn.bv_val, group_subtree) != NULL) { Debug( LDAP_DEBUG_ACL, "idattr_check_isowner: len[%d] id->idattr_owner_dn[%s] \n", id->idattr_owner_dn.bv_len, id->idattr_owner_dn.bv_val, 0 ); idattr_is_member ( op, &id->idattr_owner_dn, idattr_memberships, ownerIDAttr->a_nvals , &isMember); if (isMember) { Debug( LDAP_DEBUG_ACL, "idattr_check_isowner: user is member of Group (by parent)\n", 0, 0, 0 ); rc = LDAP_SUCCESS; } } } } } } exitonerror: if (targetEntry) be_entry_release_r(op, targetEntry); if (requestEntry) be_entry_release_r(op, requestEntry); return rc; }
static int pg_dynacl_mask( void *priv, Operation *op, Entry *target, AttributeDescription *desc, struct berval *val, int nmatch, regmatch_t *matches, slap_access_t *grant, slap_access_t *deny ) { pg_t *pg = (pg_t *)priv; Entry *group = NULL, *user = NULL; int rc; Backend *be = op->o_bd, *group_be = NULL, *user_be = NULL; struct berval group_ndn; ACL_INVALIDATE( *deny ); /* get user */ if ( target && dn_match( &target->e_nname, &op->o_ndn ) ) { user = target; rc = LDAP_SUCCESS; } else { user_be = op->o_bd = select_backend( &op->o_ndn, 0 ); if ( op->o_bd == NULL ) { op->o_bd = be; return 0; } rc = be_entry_get_rw( op, &op->o_ndn, pg_posixAccount, pg_uidNumber, 0, &user ); } if ( rc != LDAP_SUCCESS || user == NULL ) { op->o_bd = be; return 0; } /* get target */ if ( pg->pg_style == ACL_STYLE_EXPAND ) { char buf[ 1024 ]; struct berval bv; AclRegexMatches amatches = { 0 }; amatches.dn_count = nmatch; AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) ); bv.bv_len = sizeof( buf ) - 1; bv.bv_val = buf; if ( acl_string_expand( &bv, &pg->pg_pat, &target->e_nname, NULL, &amatches ) ) { goto cleanup; } if ( dnNormalize( 0, NULL, NULL, &bv, &group_ndn, op->o_tmpmemctx ) != LDAP_SUCCESS ) { /* did not expand to a valid dn */ goto cleanup; } } else { group_ndn = pg->pg_pat; } if ( target && dn_match( &target->e_nname, &group_ndn ) ) { group = target; rc = LDAP_SUCCESS; } else { group_be = op->o_bd = select_backend( &group_ndn, 0 ); if ( op->o_bd == NULL ) { goto cleanup; } rc = be_entry_get_rw( op, &group_ndn, pg_posixGroup, pg_memberUid, 0, &group ); } if ( group_ndn.bv_val != pg->pg_pat.bv_val ) { op->o_tmpfree( group_ndn.bv_val, op->o_tmpmemctx ); } if ( rc == LDAP_SUCCESS && group != NULL ) { Attribute *a_uid, *a_member; a_uid = attr_find( user->e_attrs, pg_uidNumber ); if ( !a_uid || !BER_BVISNULL( &a_uid->a_nvals[ 1 ] ) ) { rc = LDAP_NO_SUCH_ATTRIBUTE; } else { a_member = attr_find( group->e_attrs, pg_memberUid ); if ( !a_member ) { rc = LDAP_NO_SUCH_ATTRIBUTE; } else { rc = value_find_ex( pg_memberUid, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, a_member->a_nvals, &a_uid->a_nvals[ 0 ], op->o_tmpmemctx ); } } } else { rc = LDAP_NO_SUCH_OBJECT; } if ( rc == LDAP_SUCCESS ) { ACL_LVL_ASSIGN_WRITE( *grant ); } cleanup:; if ( group != NULL && group != target ) { op->o_bd = group_be; be_entry_release_r( op, group ); op->o_bd = be; } if ( user != NULL && user != target ) { op->o_bd = user_be; be_entry_release_r( op, user ); op->o_bd = be; } return 0; }
static int autogroup_response( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; autogroup_def_t *agd = agi->agi_def; autogroup_entry_t *age = agi->agi_entry; autogroup_filter_t *agf; BerValue new_dn, new_ndn, pdn; Entry *e, *group; Attribute *a; int is_olddn, is_newdn, dn_equal; if ( op->o_tag == LDAP_REQ_MODRDN ) { if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op )) { Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val, 0, 0); ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); if ( op->oq_modrdn.rs_newSup ) { pdn = *op->oq_modrdn.rs_newSup; } else { dnParent( &op->o_req_dn, &pdn ); } build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx ); if ( op->oq_modrdn.rs_nnewSup ) { pdn = *op->oq_modrdn.rs_nnewSup; } else { dnParent( &op->o_req_ndn, &pdn ); } build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val, 0, 0); dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn ); if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) != LDAP_SUCCESS || e == NULL ) { Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val, 0, 0); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass ); if ( a == NULL ) { Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val, 0, 0); overlay_entry_release_ov( op, e, 0, on ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */ for ( ; agd; agd = agd->agd_next ) { if ( value_find_ex( slap_schema.si_ad_objectClass, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, a->a_nvals, &agd->agd_oc->soc_cname, op->o_tmpmemctx ) == 0 ) { for ( age = agi->agi_entry ; age ; age = age->age_next ) { int match = 1; dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn ); if ( match == 0 ) { Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val, 0, 0); ber_dupbv( &age->age_dn, &new_dn ); ber_dupbv( &age->age_ndn, &new_ndn ); op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); overlay_entry_release_ov( op, e, 0, on ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } } } } overlay_entry_release_ov( op, e, 0, on ); /* For each group: 1. check if the orginal entry's DN is in the group. 2. chceck if the any of the group filter's base DN is a suffix of the new DN If 1 and 2 are both false, we do nothing. If 1 and 2 is true, we remove the old DN from the group, and add the new DN. If 1 is false, and 2 is true, we check the entry against the group's filters, and add it's DN to the group. If 1 is true, and 2 is false, we delete the entry's DN from the group. */ for ( age = agi->agi_entry ; age ; age = age->age_next ) { is_olddn = 0; is_newdn = 0; ldap_pvt_thread_mutex_lock( &age->age_mutex ); if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) != LDAP_SUCCESS || group == NULL ) { Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val, 0, 0); op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); ldap_pvt_thread_mutex_unlock( &age->age_mutex ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } a = attrs_find( group->e_attrs, age->age_def->agd_member_ad ); if ( a != NULL ) { if ( value_find_ex( age->age_def->agd_member_ad, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 ) { is_olddn = 1; } } overlay_entry_release_ov( op, group, 0, on ); for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) { is_newdn = 1; break; } } if ( is_olddn == 1 && is_newdn == 0 ) { autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age ); } else if ( is_olddn == 0 && is_newdn == 1 ) { for ( agf = age->age_filter; agf; agf = agf->agf_next ) { if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) { autogroup_add_member_to_group( op, &new_dn, &new_ndn, age ); break; } } } else if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) { autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age ); autogroup_add_member_to_group( op, &new_dn, &new_ndn, age ); } ldap_pvt_thread_mutex_unlock( &age->age_mutex ); } op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); } } if ( op->o_tag == LDAP_REQ_MODIFY ) { if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !get_manageDSAit( op ) ) { Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val, 0, 0); ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != LDAP_SUCCESS || e == NULL ) { Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass ); if ( a == NULL ) { Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0); overlay_entry_release_ov( op, e, 0, on ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } /* If we modify a group's memberURL, we have to delete all of it's members, and add them anew, because we cannot tell from which memberURL a member was added. */ for ( ; agd; agd = agd->agd_next ) { if ( value_find_ex( slap_schema.si_ad_objectClass, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, a->a_nvals, &agd->agd_oc->soc_cname, op->o_tmpmemctx ) == 0 ) { Modifications *m; int match = 1; m = op->orm_modlist; for ( ; age ; age = age->age_next ) { ldap_pvt_thread_mutex_lock( &age->age_mutex ); dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn ); if ( match == 0 ) { for ( ; m ; m = m->sml_next ) { if ( m->sml_desc == age->age_def->agd_member_url_ad ) { autogroup_def_t *group_agd = age->age_def; Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n", op->o_req_dn.bv_val, 0, 0); overlay_entry_release_ov( op, e, 0, on ); autogroup_delete_member_from_group( op, NULL, NULL, age ); autogroup_delete_group( agi, age ); autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } } ldap_pvt_thread_mutex_unlock( &age->age_mutex ); break; } ldap_pvt_thread_mutex_unlock( &age->age_mutex ); } overlay_entry_release_ov( op, e, 0, on ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } } overlay_entry_release_ov( op, e, 0, on ); /* When modifing any of the attributes of an entry, we must check if the entry is in any of our groups, and if the modified entry maches any of the filters of that group. If the entry exists in a group, but the modified attributes do not match any of the group's filters, we delete the entry from that group. If the entry doesn't exist in a group, but matches a filter, we add it to that group. */ for ( age = agi->agi_entry ; age ; age = age->age_next ) { is_olddn = 0; is_newdn = 0; ldap_pvt_thread_mutex_lock( &age->age_mutex ); if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) != LDAP_SUCCESS || group == NULL ) { Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", age->age_dn.bv_val, 0, 0); ldap_pvt_thread_mutex_unlock( &age->age_mutex ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } a = attrs_find( group->e_attrs, age->age_def->agd_member_ad ); if ( a != NULL ) { if ( value_find_ex( age->age_def->agd_member_ad, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, a->a_nvals, &op->o_req_ndn, op->o_tmpmemctx ) == 0 ) { is_olddn = 1; } } overlay_entry_release_ov( op, group, 0, on ); for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) { if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { if ( test_filter( op, e, agf->agf_filter ) == LDAP_COMPARE_TRUE ) { is_newdn = 1; break; } } } if ( is_olddn == 1 && is_newdn == 0 ) { autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age ); } else if ( is_olddn == 0 && is_newdn == 1 ) { autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age ); } ldap_pvt_thread_mutex_unlock( &age->age_mutex ); } ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); } } return SLAP_CB_CONTINUE; }
/* ** When modifing a group, we must deny any modifications to the member attribute, ** because the group would be inconsistent. */ static int autogroup_modify_entry( Operation *op, SlapReply *rs) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; autogroup_info_t *agi = (autogroup_info_t *)on->on_bi.bi_private; autogroup_def_t *agd = agi->agi_def; autogroup_entry_t *age = agi->agi_entry; Entry *e; Attribute *a; if ( get_manageDSAit( op ) ) { return SLAP_CB_CONTINUE; } Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val, 0, 0); ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) != LDAP_SUCCESS || e == NULL ) { Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val, 0, 0); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass ); if ( a == NULL ) { Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val, 0, 0); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } for ( ; agd; agd = agd->agd_next ) { if ( value_find_ex( slap_schema.si_ad_objectClass, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, a->a_nvals, &agd->agd_oc->soc_cname, op->o_tmpmemctx ) == 0 ) { Modifications *m; int match = 1; m = op->orm_modlist; for ( ; age ; age = age->age_next ) { dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn ); if ( match == 0 ) { for ( ; m ; m = m->sml_next ) { if ( m->sml_desc == age->age_def->agd_member_ad ) { overlay_entry_release_ov( op, e, 0, on ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val, 0, 0); send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute"); return LDAP_CONSTRAINT_VIOLATION; } } break; } } overlay_entry_release_ov( op, e, 0, on ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } } overlay_entry_release_ov( op, e, 0, on ); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; }
static int rdnval_rdn2vals( Operation *op, SlapReply *rs, struct berval *dn, struct berval *ndn, BerVarray *valsp, BerVarray *nvalsp, int *numvalsp ) { LDAPRDN rdn = NULL, nrdn = NULL; int nAVA, i; assert( *valsp == NULL ); assert( *nvalsp == NULL ); *numvalsp = 0; if ( ldap_bv2rdn_x( dn, &rdn, (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) { Debug( LDAP_DEBUG_TRACE, "%s rdnval: can't figure out " "type(s)/value(s) of rdn DN=\"%s\"\n", op->o_log_prefix, dn->bv_val, 0 ); rs->sr_err = LDAP_INVALID_DN_SYNTAX; rs->sr_text = "unknown type(s) used in RDN"; goto done; } if ( ldap_bv2rdn_x( ndn, &nrdn, (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) { Debug( LDAP_DEBUG_TRACE, "%s rdnval: can't figure out " "type(s)/value(s) of normalized rdn DN=\"%s\"\n", op->o_log_prefix, ndn->bv_val, 0 ); rs->sr_err = LDAP_INVALID_DN_SYNTAX; rs->sr_text = "unknown type(s) used in RDN"; goto done; } for ( nAVA = 0; rdn[ nAVA ]; nAVA++ ) /* count'em */ ; /* NOTE: we assume rdn and nrdn contain the same AVAs! */ *valsp = SLAP_CALLOC( sizeof( struct berval ), nAVA + 1 ); *nvalsp = SLAP_CALLOC( sizeof( struct berval ), nAVA + 1 ); /* Add new attribute values to the entry */ for ( i = 0; rdn[ i ]; i++ ) { AttributeDescription *desc = NULL; rs->sr_err = slap_bv2ad( &rdn[ i ]->la_attr, &desc, &rs->sr_text ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "%s rdnval: %s: %s\n", op->o_log_prefix, rs->sr_text, rdn[ i ]->la_attr.bv_val ); goto done; } if ( !rdnval_is_valid( desc, &rdn[ i ]->la_value ) ) { Debug( LDAP_DEBUG_TRACE, "%s rdnval: syntax of naming attribute '%s' " "not compatible with directoryString", op->o_log_prefix, rdn[ i ]->la_attr.bv_val, 0 ); continue; } if ( value_find_ex( desc, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, *nvalsp, &nrdn[ i ]->la_value, op->o_tmpmemctx ) == LDAP_NO_SUCH_ATTRIBUTE ) { ber_dupbv( &(*valsp)[ *numvalsp ], &rdn[ i ]->la_value ); ber_dupbv( &(*nvalsp)[ *numvalsp ], &nrdn[ i ]->la_value ); (*numvalsp)++; } } if ( rdnval_unique_check( op, *valsp ) != LDAP_SUCCESS ) { rs->sr_err = LDAP_CONSTRAINT_VIOLATION; rs->sr_text = "rdnValue not unique within siblings"; goto done; } done:; if ( rdn != NULL ) { ldap_rdnfree_x( rdn, op->o_tmpmemctx ); } if ( nrdn != NULL ) { ldap_rdnfree_x( nrdn, op->o_tmpmemctx ); } if ( rs->sr_err != LDAP_SUCCESS ) { if ( *valsp != NULL ) { ber_bvarray_free( *valsp ); ber_bvarray_free( *nvalsp ); *valsp = NULL; *nvalsp = NULL; *numvalsp = 0; } } return rs->sr_err; }