예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
/* 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);
}
예제 #4
0
파일: compare.c 프로젝트: Joywar/openldap
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;
}
예제 #5
0
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;
}
예제 #6
0
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;
}
예제 #7
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;
}
예제 #8
0
/*
** 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;
}
예제 #9
0
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;
}