示例#1
0
文件: usn.c 项目: benegon/openldap
/* Read the old USN from the underlying DB. This code is
 * stolen from the syncprov overlay.
 */
static int
usn_db_open(
	BackendDB *be,
	ConfigReply *cr)
{
	slap_overinst   *on = (slap_overinst *) be->bd_info;
	usn_info_t *ui = (usn_info_t *)on->on_bi.bi_private;

	Connection conn = { 0 };
	OperationBuffer opbuf;
	Operation *op;
	Entry *e = NULL;
	Attribute *a;
	int rc;
	void *thrctx = NULL;

	thrctx = ldap_pvt_thread_pool_context();
	connection_fake_init( &conn, &opbuf, thrctx );
	op = &opbuf.ob_op;
	op->o_bd = be;
	op->o_dn = be->be_rootdn;
	op->o_ndn = be->be_rootndn;

	rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL,
		slap_schema.si_ad_contextCSN, 0, &e, on );

	if ( e ) {
		a = attr_find( e->e_attrs, ad_usnChanged );
		if ( a ) {
			ui->ui_current = atoi( a->a_vals[0].bv_val );
		}
		overlay_entry_release_ov( op, e, 0, on );
	}
	return 0;
}
示例#2
0
static int
pguid_op_rename( Operation *op, SlapReply *rs )
{
	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;

	Entry *e = NULL;
	Attribute *a;
	int rc;

	if ( op->orr_nnewSup == NULL ) {
		return SLAP_CB_CONTINUE;
	}

	rc = overlay_entry_get_ov( op, op->orr_nnewSup, NULL, slap_schema.si_ad_entryUUID, 0, &e, on );
	if ( rc != LDAP_SUCCESS || e == NULL ) {
		Debug( LDAP_DEBUG_ANY, "%s: pguid_op_rename: unable to get newSuperior entry DN=\"%s\" (%d)\n",
			op->o_log_prefix, op->orr_newSup->bv_val, rc );
		return SLAP_CB_CONTINUE;
	}

	a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
	if ( a == NULL ) {
		Debug( LDAP_DEBUG_ANY, "%s: pguid_op_rename: unable to find entryUUID of newSuperior entry DN=\"%s\" (%d)\n",
			op->o_log_prefix, op->orr_newSup->bv_val, rc );
		
	} else {
		Modifications *mod;

		assert( a->a_numvals == 1 );

		mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
		mod->sml_flags = SLAP_MOD_INTERNAL;
		mod->sml_op = LDAP_MOD_REPLACE;
		mod->sml_desc = ad_parentUUID;
		mod->sml_type = ad_parentUUID->ad_cname;
		mod->sml_values = ch_malloc( sizeof( struct berval ) * 2 );
		mod->sml_nvalues = NULL;
		mod->sml_numvals = 1;

		ber_dupbv( &mod->sml_values[0], &a->a_vals[0] );
		BER_BVZERO( &mod->sml_values[1] );

		mod->sml_next = op->orr_modlist;
		op->orr_modlist = mod;
	}

	if ( e != NULL ) {
		(void)overlay_entry_release_ov( op, e, 0, on );
	}

	return SLAP_CB_CONTINUE;
}
示例#3
0
static int translucent_compare(Operation *op, SlapReply *rs) {
	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
	translucent_info *ov = on->on_bi.bi_private;
	AttributeAssertion *ava = op->orc_ava;
	Entry *e = NULL;
	BackendDB *db;
	int rc;

	Debug(LDAP_DEBUG_TRACE, "==> translucent_compare: <%s> %s:%s\n",
		op->o_req_dn.bv_val, ava->aa_desc->ad_cname.bv_val, ava->aa_value.bv_val);

/*
** if the local backend has an entry for this attribute:
**	CONTINUE and let it do the compare;
**
*/
	rc = overlay_entry_get_ov(op, &op->o_req_ndn, NULL, ava->aa_desc, 0, &e, on);
	if(rc == LDAP_SUCCESS && e) {
		overlay_entry_release_ov(op, e, 0, on);
		return(SLAP_CB_CONTINUE);
	}

	if(ov->defer_db_open) {
		send_ldap_error(op, rs, LDAP_UNAVAILABLE,
			"remote DB not available");
		return(rs->sr_err);
	}
/*
** call compare() in the captive backend;
** return the result;
**
*/
	db = op->o_bd;
	op->o_bd = &ov->db;
	ov->db.be_acl = op->o_bd->be_acl;
	rc = ov->db.bd_info->bi_op_compare(op, rs);
	op->o_bd = db;

	return(rc);
}
示例#4
0
static int
deref_response( Operation *op, SlapReply *rs )
{
	int rc = SLAP_CB_CONTINUE;

	if ( rs->sr_type == REP_SEARCH ) {
		BerElementBuffer berbuf;
		BerElement *ber = (BerElement *) &berbuf;
		deref_cb_t *dc = (deref_cb_t *)op->o_callback->sc_private;
		DerefSpec *ds;
		DerefRes *dr, *drhead = NULL, **drp = &drhead;
		struct berval bv = BER_BVNULL;
		int nDerefRes = 0, nDerefVals = 0, nAttrs = 0, nVals = 0;
		struct berval ctrlval;
		LDAPControl *ctrl, *ctrlsp[2];
		AccessControlState acl_state = ACL_STATE_INIT;
		static char dummy = '\0';
		Entry *ebase;
		int i;

		rc = overlay_entry_get_ov( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &ebase, dc->dc_on );
		if ( rc != LDAP_SUCCESS || ebase == NULL ) {
			return SLAP_CB_CONTINUE;
		}

		for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) {
			Attribute *a = attr_find( ebase->e_attrs, ds->ds_derefAttr );

			if ( a != NULL ) {
				DerefVal *dv;
				BerVarray *bva;

				if ( !access_allowed( op, rs->sr_entry, a->a_desc,
						NULL, ACL_READ, &acl_state ) )
				{
					continue;
				}

				dr = op->o_tmpcalloc( 1,
					sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ),
					op->o_tmpmemctx );
				dr->dr_spec = *ds;
				dv = dr->dr_vals = (DerefVal *)&dr[ 1 ];
				bva = (BerVarray *)&dv[ a->a_numvals + 1 ];

				bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len;
				nAttrs++;
				nDerefRes++;

				for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
					Entry *e = NULL;

					dv[ i ].dv_attrVals = bva;
					bva += ds->ds_nattrs;


					if ( !access_allowed( op, rs->sr_entry, a->a_desc,
							&a->a_nvals[ i ], ACL_READ, &acl_state ) )
					{
						dv[ i ].dv_derefSpecVal.bv_val = &dummy;
						continue;
					}

					ber_dupbv_x( &dv[ i ].dv_derefSpecVal, &a->a_vals[ i ], op->o_tmpmemctx );
					bv.bv_len += dv[ i ].dv_derefSpecVal.bv_len;
					nVals++;
					nDerefVals++;

					rc = overlay_entry_get_ov( op, &a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on );
					if ( rc == LDAP_SUCCESS && e != NULL ) {
						int j;

						if ( access_allowed( op, e, slap_schema.si_ad_entry,
							NULL, ACL_READ, NULL ) )
						{
							for ( j = 0; j < ds->ds_nattrs; j++ ) {
								Attribute *aa;

								if ( !access_allowed( op, e, ds->ds_attributes[ j ], NULL,
									ACL_READ, &acl_state ) )
								{
									continue;
								}

								aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] );
								if ( aa != NULL ) {
									unsigned k, h, last = aa->a_numvals;

									ber_bvarray_dup_x( &dv[ i ].dv_attrVals[ j ],
										aa->a_vals, op->o_tmpmemctx );

									bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len;

									for ( k = 0, h = 0; k < aa->a_numvals; k++ ) {
										if ( !access_allowed( op, e,
											aa->a_desc,
											&aa->a_nvals[ k ],
											ACL_READ, &acl_state ) )
										{
											op->o_tmpfree( dv[ i ].dv_attrVals[ j ][ h ].bv_val,
												op->o_tmpmemctx );
											dv[ i ].dv_attrVals[ j ][ h ] = dv[ i ].dv_attrVals[ j ][ --last ];
											BER_BVZERO( &dv[ i ].dv_attrVals[ j ][ last ] );
											continue;
										}
										bv.bv_len += dv[ i ].dv_attrVals[ j ][ h ].bv_len;
										nVals++;
										h++;
									}
									nAttrs++;
								}
							}
						}

						overlay_entry_release_ov( op, e, 0, dc->dc_on );
					}
				}

				*drp = dr;
				drp = &dr->dr_next;
			}
		}
		overlay_entry_release_ov( op, ebase, 0, dc->dc_on );

		if ( drhead == NULL ) {
			return SLAP_CB_CONTINUE;
		}

		/* cook the control value */
		bv.bv_len += nVals * sizeof(struct berval)
			+ nAttrs * sizeof(struct berval)
			+ nDerefVals * sizeof(DerefVal)
			+ nDerefRes * sizeof(DerefRes);
		bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );

		ber_init2( ber, &bv, LBER_USE_DER );
		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );

		rc = ber_printf( ber, "{" /*}*/ );
		for ( dr = drhead; dr != NULL; dr = dr->dr_next ) {
			for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) {
				int j, first = 1;

				if ( dr->dr_vals[ i ].dv_derefSpecVal.bv_val == &dummy ) {
					continue;
				}

				rc = ber_printf( ber, "{OO" /*}*/,
					&dr->dr_spec.ds_derefAttr->ad_cname,
					&dr->dr_vals[ i ].dv_derefSpecVal );
				op->o_tmpfree( dr->dr_vals[ i ].dv_derefSpecVal.bv_val, op->o_tmpmemctx );
				for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) {
					if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) {
						if ( first ) {
							rc = ber_printf( ber, "t{" /*}*/,
								(LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) );
							first = 0;
						}
						rc = ber_printf( ber, "{O[W]}",
							&dr->dr_spec.ds_attributes[ j ]->ad_cname,
							dr->dr_vals[ i ].dv_attrVals[ j ] );
						op->o_tmpfree( dr->dr_vals[ i ].dv_attrVals[ j ],
							op->o_tmpmemctx );
					}
				}
				if ( !first ) {
					rc = ber_printf( ber, /*{{*/ "}N}" );
				} else {
					rc = ber_printf( ber, /*{*/ "}" );
				}
			}
		}
		rc = ber_printf( ber, /*{*/ "}" );
		if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
			if ( op->o_deref == SLAP_CONTROL_CRITICAL ) {
				rc = LDAP_CONSTRAINT_VIOLATION;

			} else {
				rc = SLAP_CB_CONTINUE;
			}
			goto cleanup;
		}

		ctrl = op->o_tmpcalloc( 1,
			sizeof( LDAPControl ) + ctrlval.bv_len + 1,
			op->o_tmpmemctx );
		ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ];
		ctrl->ldctl_oid = LDAP_CONTROL_X_DEREF;
		ctrl->ldctl_iscritical = 0;
		ctrl->ldctl_value.bv_len = ctrlval.bv_len;
		memcpy( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len );
		ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0';

		ber_free_buf( ber );

		ctrlsp[0] = ctrl;
		ctrlsp[1] = NULL;
		slap_add_ctrls( op, rs, ctrlsp );

		rc = SLAP_CB_CONTINUE;

cleanup:;
		/* release all */
		for ( ; drhead != NULL; ) {
			DerefRes *drnext = drhead->dr_next;
			op->o_tmpfree( drhead, op->o_tmpmemctx );
			drhead = drnext;
		}

	} else if ( rs->sr_type == REP_RESULT ) {
		rc = deref_cleanup( op, rs );
	}

	return rc;
}
示例#5
0
static int
autoca_db_open(
	BackendDB *be,
	ConfigReply *cr
)
{
	slap_overinst *on = (slap_overinst *)be->bd_info;
	autoca_info *ai = on->on_bi.bi_private;

	Connection conn = { 0 };
	OperationBuffer opbuf;
	Operation *op;
	void *thrctx;
	Entry *e;
	Attribute *a;
	int rc;

	if (slapMode & SLAP_TOOL_MODE)
		return 0;

	if ( ! *aca_attr2[0].ad ) {
		int i, code;
		const char *text;

		for ( i=0; aca_attr2[i].at; i++ ) {
			code = slap_str2ad( aca_attr2[i].at, aca_attr2[i].ad, &text );
			if ( code ) return code;
		}

		/* Schema may not be loaded, ignore if missing */
		slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );

		for ( i=0; aca_ocs[i].ot; i++ ) {
			code = register_oc( aca_ocs[i].ot, aca_ocs[i].oc, 0 );
			if ( code ) return code;
		}
	}

	thrctx = ldap_pvt_thread_pool_context();
	connection_fake_init2( &conn, &opbuf, thrctx, 0 );
	op = &opbuf.ob_op;
	op->o_bd = be;
	op->o_dn = be->be_rootdn;
	op->o_ndn = be->be_rootndn;
	rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL, 
		NULL, 0, &e, on );

	if ( e ) {
		int gotoc = 0, gotat = 0;
		if ( is_entry_objectclass( e, oc_caObj, 0 )) {
			gotoc = 1;
			a = attr_find( e->e_attrs, ad_caPkey );
			if ( a ) {
				const unsigned char *pp;
				pp = (unsigned char *)a->a_vals[0].bv_val;
				ai->ai_pkey = d2i_AutoPrivateKey( NULL, &pp, a->a_vals[0].bv_len );
				if ( ai->ai_pkey )
				{
					a = attr_find( e->e_attrs, ad_caCert );
					if ( a )
					{
						pp = (unsigned char *)a->a_vals[0].bv_val;
						ai->ai_cert = d2i_X509( NULL, &pp, a->a_vals[0].bv_len );
						/* If TLS wasn't configured yet, set this as our CA */
						if ( !slap_tls_ctx )
							autoca_setca( a->a_vals );
					}
				}
				gotat = 1;
			}
		}
		overlay_entry_release_ov( op, e, 0, on );
		/* generate attrs, store... */
		if ( !gotat ) {
			genargs args;
			saveargs arg2;

			args.issuer_cert = NULL;
			args.issuer_pkey = NULL;
			args.subjectDN = &be->be_suffix[0];
			args.cert_exts = CAexts;
			args.more_exts = NULL;
			args.keybits = ai->ai_cakeybits;
			args.days = ai->ai_cadays;

			rc = autoca_gencert( op, &args );
			if ( rc )
				return -1;

			ai->ai_cert = args.newcert;
			ai->ai_pkey = args.newpkey;

			arg2.dn = be->be_suffix;
			arg2.ndn = be->be_nsuffix;
			arg2.isca = 1;
			if ( !gotoc )
				arg2.oc = oc_caObj;
			else
				arg2.oc = NULL;
			arg2.on = on;
			arg2.dercert = &args.dercert;
			arg2.derpkey = &args.derpkey;

			autoca_savecert( op, &arg2 );

			/* If TLS wasn't configured yet, set this as our CA */
			if ( !slap_tls_ctx )
				autoca_setca( &args.dercert );

			op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
			op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
		}
	}

	return 0;
}
示例#6
0
static int
dynlist_compare( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
	dynlist_info_t	*dli = (dynlist_info_t *)on->on_bi.bi_private;
	Operation o = *op;
	Entry *e = NULL;
	dynlist_map_t *dlm;
	BackendDB *be;

	for ( ; dli != NULL; dli = dli->dli_next ) {
		for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next )
			if ( op->oq_compare.rs_ava->aa_desc == dlm->dlm_member_ad )
				break;

		if ( dlm ) {
			/* This compare is for one of the attributes we're
			 * interested in. We'll use slapd's existing dyngroup
			 * evaluator to get the answer we want.
			 */
			BerVarray id = NULL, authz = NULL;

			o.o_do_not_cache = 1;

			if ( ad_dgIdentity && backend_attribute( &o, NULL, &o.o_req_ndn,
				ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS )
			{
				/* if not rootdn and dgAuthz is present,
				 * check if user can be authorized as dgIdentity */
				if ( ad_dgAuthz && !BER_BVISEMPTY( id ) && !be_isroot( op )
					&& backend_attribute( &o, NULL, &o.o_req_ndn,
						ad_dgAuthz, &authz, ACL_READ ) == LDAP_SUCCESS )
				{
					
					rs->sr_err = slap_sasl_matches( op, authz,
						&o.o_ndn, &o.o_ndn );
					ber_bvarray_free_x( authz, op->o_tmpmemctx );
					if ( rs->sr_err != LDAP_SUCCESS ) {
						goto done;
					}
				}

				o.o_dn = *id;
				o.o_ndn = *id;
				o.o_groups = NULL; /* authz changed, invalidate cached groups */
			}

			rs->sr_err = backend_group( &o, NULL, &o.o_req_ndn,
				&o.oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad );
			switch ( rs->sr_err ) {
			case LDAP_SUCCESS:
				rs->sr_err = LDAP_COMPARE_TRUE;
				break;

			case LDAP_NO_SUCH_OBJECT:
				/* NOTE: backend_group() returns noSuchObject
				 * if op_ndn does not exist; however, since
				 * dynamic list expansion means that the
				 * member attribute is virtually present, the
				 * non-existence of the asserted value implies
				 * the assertion is FALSE rather than
				 * UNDEFINED */
				rs->sr_err = LDAP_COMPARE_FALSE;
				break;
			}

done:;
			if ( id ) ber_bvarray_free_x( id, o.o_tmpmemctx );

			return SLAP_CB_CONTINUE;
		}
	}

	be = select_backend( &o.o_req_ndn, 1 );
	if ( !be || !be->be_search ) {
		return SLAP_CB_CONTINUE;
	}

	if ( overlay_entry_get_ov( &o, &o.o_req_ndn, NULL, NULL, 0, &e, on ) !=
		LDAP_SUCCESS || e == NULL )
	{
		return SLAP_CB_CONTINUE;
	}

	/* check for dynlist objectClass; done if not found */
	dli = (dynlist_info_t *)on->on_bi.bi_private;
	while ( dli != NULL && !is_entry_objectclass_or_sub( e, dli->dli_oc ) ) {
		dli = dli->dli_next;
	}
	if ( dli == NULL ) {
		goto release;
	}

	if ( ad_dgIdentity ) {
		Attribute *id = attrs_find( e->e_attrs, ad_dgIdentity );
		if ( id ) {
			Attribute *authz;

			/* if not rootdn and dgAuthz is present,
			 * check if user can be authorized as dgIdentity */
			if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op )
				&& ( authz = attrs_find( e->e_attrs, ad_dgAuthz ) ) )
			{
				if ( slap_sasl_matches( op, authz->a_nvals,
					&o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS )
				{
					goto release;
				}
			}

			o.o_dn = id->a_vals[0];
			o.o_ndn = id->a_nvals[0];
			o.o_groups = NULL;
		}
	}

	/* generate dynamic list with dynlist_response() and compare */
	{
		SlapReply	r = { REP_SEARCH };
		dynlist_cc_t	dc = { { 0, dynlist_sc_compare_entry, 0, 0 }, 0 };
		AttributeName	an[2];

		dc.dc_ava = op->orc_ava;
		dc.dc_res = &rs->sr_err;
		o.o_callback = (slap_callback *) &dc;

		o.o_tag = LDAP_REQ_SEARCH;
		o.ors_limit = NULL;
		o.ors_tlimit = SLAP_NO_LIMIT;
		o.ors_slimit = SLAP_NO_LIMIT;

		o.ors_filterstr = *slap_filterstr_objectClass_pres;
		o.ors_filter = (Filter *) slap_filter_objectClass_pres;

		o.ors_scope = LDAP_SCOPE_BASE;
		o.ors_deref = LDAP_DEREF_NEVER;
		an[0].an_name = op->orc_ava->aa_desc->ad_cname;
		an[0].an_desc = op->orc_ava->aa_desc;
		BER_BVZERO( &an[1].an_name );
		o.ors_attrs = an;
		o.ors_attrsonly = 0;

		o.o_acl_priv = ACL_COMPARE;

		o.o_bd = be;
		(void)be->be_search( &o, &r );

		if ( o.o_dn.bv_val != op->o_dn.bv_val ) {
			slap_op_groups_free( &o );
		}
	}

release:;
	if ( e != NULL ) {
		overlay_entry_release_ov( &o, e, 0, on );
	}

	return SLAP_CB_CONTINUE;
}
示例#7
0
static int translucent_search_cb(Operation *op, SlapReply *rs) {
	trans_ctx *tc;
	BackendDB *db;
	slap_overinst *on;
	translucent_info *ov;
	Entry *le, *re;
	Attribute *a, *ax, *an, *as = NULL;
	int rc;
	int test_f = 0;

	tc = op->o_callback->sc_private;

	/* Don't let the op complete while we're gathering data */
	if ( rs->sr_type == REP_RESULT && ( tc->step & USE_LIST ))
		return 0;

	if(rs->sr_type != REP_SEARCH || !rs->sr_entry)
		return(SLAP_CB_CONTINUE);

	Debug(LDAP_DEBUG_TRACE, "==> translucent_search_cb: %s\n",
		rs->sr_entry->e_name.bv_val, 0, 0);

	op->ors_slimit = tc->slimit + ( tc->slimit > 0 ? 1 : 0 );
	if ( op->ors_attrs == slap_anlist_all_attributes ) {
		op->ors_attrs = tc->attrs;
		rs->sr_attrs = tc->attrs;
		rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs );
	}

	on = tc->on;
	ov = on->on_bi.bi_private;

	db = op->o_bd;
	re = NULL;

	/* If we have local, get remote */
	if ( tc->step & LCL_SIDE ) {
		le = rs->sr_entry;
		/* If entry is already on list, use it */
		if ( tc->step & USE_LIST ) {
			re = tavl_delete( &tc->list, le, entry_dn_cmp );
			if ( re ) {
				rs_flush_entry( op, rs, on );
				rc = test_filter( op, re, tc->orig );
				if ( rc == LDAP_COMPARE_TRUE ) {
					rs->sr_flags |= REP_ENTRY_MUSTBEFREED;
					rs->sr_entry = re;

					if ( tc->slimit >= 0 && rs->sr_nentries >= tc->slimit ) {
						return LDAP_SIZELIMIT_EXCEEDED;
					}

					return SLAP_CB_CONTINUE;
				} else {
					entry_free( re );
					rs->sr_entry = NULL;
					return 0;
				}
			}
		}
		op->o_bd = &ov->db;
		rc = be_entry_get_rw( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &re );
		if ( rc == LDAP_SUCCESS && re ) {
			Entry *tmp = entry_dup( re );
			be_entry_release_r( op, re );
			re = tmp;
			test_f = 1;
		}
	} else {
	/* Else we have remote, get local */
		op->o_bd = tc->db;
		le = NULL;
		rc = overlay_entry_get_ov(op, &rs->sr_entry->e_nname, NULL, NULL, 0, &le, on);
		if ( rc == LDAP_SUCCESS && le ) {
			re = entry_dup( rs->sr_entry );
			rs_flush_entry( op, rs, on );
		} else {
			le = NULL;
		}
	}

/*
** if we got remote and local entry:
**	foreach local attr:
**		foreach remote attr:
**			if match, remote attr with local attr;
**			if new local, add to list;
**	append new local attrs to remote;
**
*/

	if ( re && le ) {
		for(ax = le->e_attrs; ax; ax = ax->a_next) {
			for(a = re->e_attrs; a; a = a->a_next) {
				if(a->a_desc == ax->a_desc) {
					test_f = 1;
					if(a->a_vals != a->a_nvals)
						ber_bvarray_free(a->a_nvals);
					ber_bvarray_free(a->a_vals);
					ber_bvarray_dup_x( &a->a_vals, ax->a_vals, NULL );
					if ( ax->a_vals == ax->a_nvals ) {
						a->a_nvals = a->a_vals;
					} else {
						ber_bvarray_dup_x( &a->a_nvals, ax->a_nvals, NULL );
					}
					break;
				}
			}
			if(a) continue;
			an = attr_dup(ax);
			an->a_next = as;
			as = an;
		}
		/* Dispose of local entry */
		if ( tc->step & LCL_SIDE ) {
			rs_flush_entry(op, rs, on);
		} else {
			overlay_entry_release_ov(op, le, 0, on);
		}

		/* literally append, so locals are always last */
		if(as) {
			if(re->e_attrs) {
				for(ax = re->e_attrs; ax->a_next; ax = ax->a_next);
				ax->a_next = as;
			} else {
				re->e_attrs = as;
			}
		}
		/* If both filters, save entry for later */
		if ( tc->step == (USE_LIST|RMT_SIDE) ) {
			tavl_insert( &tc->list, re, entry_dn_cmp, avl_dup_error );
			rs->sr_entry = NULL;
			rc = 0;
		} else {
		/* send it now */
			rs->sr_entry = re;
			rs->sr_flags |= REP_ENTRY_MUSTBEFREED;
			if ( test_f ) {
				rc = test_filter( op, rs->sr_entry, tc->orig );
				if ( rc == LDAP_COMPARE_TRUE ) {
					rc = SLAP_CB_CONTINUE;
				} else {
					rc = 0;
				}
			} else {
				rc = SLAP_CB_CONTINUE;
			}
		}
	} else if ( le ) {
	/* Only a local entry: remote was deleted
	 * Ought to delete the local too...
	 */
	 	rc = 0;
	} else if ( tc->step & USE_LIST ) {
	/* Only a remote entry, but both filters:
	 * Test the complete filter
	 */
		rc = test_filter( op, rs->sr_entry, tc->orig );
		if ( rc == LDAP_COMPARE_TRUE ) {
			rc = SLAP_CB_CONTINUE;
		} else {
			rc = 0;
		}
	} else {
	/* Only a remote entry, only remote filter:
	 * just pass thru
	 */
		rc = SLAP_CB_CONTINUE;
	}

	op->o_bd = db;

	if ( rc == SLAP_CB_CONTINUE && tc->slimit >= 0 && rs->sr_nentries >= tc->slimit ) {
		return LDAP_SIZELIMIT_EXCEEDED;
	}

	return rc;
}
示例#8
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;
}
示例#9
0
static int
autogroup_delete_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_entry_t	*age = agi->agi_entry,
				*age_prev, *age_next;
	autogroup_filter_t	*agf;
	Entry			*e;
	int			matched_group = 0, rc = 0;

	Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_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_delete_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;
	}

	/* Check if the entry to be deleted is one of our groups. */
	for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
		ldap_pvt_thread_mutex_lock( &age->age_mutex );
		age_next = age->age_next;

		if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
			int match = 1;

			matched_group = 1;

			dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );

			if ( match == 0 ) {
				autogroup_delete_group( agi, age );
				break;
			}
		}

		ldap_pvt_thread_mutex_unlock( &age->age_mutex );			
	}

	if ( matched_group == 1 ) {
		overlay_entry_release_ov( op, e, 0, on );
		ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );		
		return SLAP_CB_CONTINUE;
	}

	/* Check if the entry matches any of the groups.
	   If yes, we can delete the entry from that group. */

	for ( age = agi->agi_entry ; age ; age = age->age_next ) {
		ldap_pvt_thread_mutex_lock( &age->age_mutex );		

		for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
			if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
				rc = test_filter( op, e, agf->agf_filter );
				if ( rc == LDAP_COMPARE_TRUE ) {
				autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
					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;
}
示例#10
0
/* 
** Adds a group to the internal list from the passed entry.
** scan specifies whether to add all maching members to the group.
** modify specifies whether to modify the given group entry (when modify == 0),
**	or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
** agi	- pointer to the groups and the attribute definitions
** agd - the attribute definition of the added group
** e	- the entry representing the group, can be NULL if the ndn is specified, and modify == 1
** ndn	- the DN of the group, can be NULL if we give a non-NULL e
*/
static int
autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
{
	autogroup_entry_t	**agep = &agi->agi_entry;
	autogroup_filter_t	*agf, *agf_prev = NULL;
	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
	LDAPURLDesc		*lud = NULL;
	Attribute		*a;
	BerValue		*bv, dn;
	int			rc = 0, match = 1, null_entry = 0;

	if ( e == NULL ) {
		if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
			LDAP_SUCCESS || e == NULL ) {
			Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val, 0, 0);
			return 1;
		}

		null_entry = 1;
	}

	Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
		e->e_name.bv_val, 0, 0);

	if ( agi->agi_entry != NULL ) {
		for ( ; *agep ; agep = &(*agep)->age_next ) {
			dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
			if ( match == 0 ) {
				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val,0,0);
				return 1;
			}
			/* goto last */;
		}
	}


	*agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
	ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
	(*agep)->age_def = agd;
	(*agep)->age_filter = NULL;

	ber_dupbv( &(*agep)->age_dn, &e->e_name );
	ber_dupbv( &(*agep)->age_ndn, &e->e_nname );

	a = attrs_find( e->e_attrs, agd->agd_member_url_ad );

	if ( null_entry == 1 ) {
		a = attrs_dup( a );
		overlay_entry_release_ov( op, e, 0, on );
	}

	if( a == NULL ) {
		Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n", 0,0,0);
	} else {
		for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {

			agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );

			if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val,0,0);
				/* FIXME: error? */
				ch_free( agf ); 
				continue;
			}

			agf->agf_scope = lud->lud_scope;

			if ( lud->lud_dn == NULL ) {
				BER_BVSTR( &dn, "" );
			} else {
				ber_str2bv( lud->lud_dn, 0, 0, &dn );
			}

			rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
			if ( rc != LDAP_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val,0,0);
				/* FIXME: error? */
				goto cleanup;
			}

			if ( lud->lud_filter != NULL ) {
				ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
				agf->agf_filter = str2filter( lud->lud_filter );
			}			

			agf->agf_next = NULL;


			if( (*agep)->age_filter == NULL ) {
				(*agep)->age_filter = agf;
			}

			if( agf_prev != NULL ) {
				agf_prev->agf_next = agf;
			}

			agf_prev = agf;

			if ( scan == 1 ){
				autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
			}

			Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
				agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val, 0);

			ldap_free_urldesc( lud );

			continue;


cleanup:;

			ldap_free_urldesc( lud );				
			ch_free( agf ); 
		}
	}

	if ( null_entry == 1 ) {
		attrs_free( a );
	}
	return rc;
}
示例#11
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;
}
示例#12
0
/**
 *  The meat of the overlay.  Search for the record, determine changes, take
 *  action or fall through.
 */
static int addpartial_add( Operation *op, SlapReply *rs)
{
    Operation nop = *op;
    Entry *toAdd = NULL;
    Entry *found = NULL;
    slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
    int rc;

    toAdd = op->oq_add.rs_e;

    Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
          addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0);

    /* if the user doesn't have access, fall through to the normal ADD */
    if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
                       NULL, ACL_WRITE, NULL))
    {
        return SLAP_CB_CONTINUE;
    }

    rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on);

    if(rc != LDAP_SUCCESS)
    {
        Debug(LDAP_DEBUG_TRACE,
              "%s: no entry found, falling through to normal add\n",
              addpartial.on_bi.bi_type, 0, 0);
        return SLAP_CB_CONTINUE;
    }
    else
    { 
        Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type,
              0,0);

        if(found)
        {
            Attribute *attr = NULL;
            Attribute *at = NULL;
            int ret;
            Modifications *mods = NULL;
            Modifications **modtail = &mods;
            Modifications *mod = NULL;

            Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
                  addpartial.on_bi.bi_type,0,0);

           /* determine if the changes are in the found entry */ 
            for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
            {
                if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;

                at = attr_find(found->e_attrs, attr->a_desc);
                if(!at)
                {
                    Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
                          addpartial.on_bi.bi_type,
                          attr->a_desc->ad_cname.bv_val,0);
                    mod = (Modifications *) ch_malloc(sizeof(
                                                            Modifications));
                    mod->sml_flags = 0;
                    mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
                    mod->sml_op &= LDAP_MOD_OP;
                    mod->sml_next = NULL;
                    mod->sml_desc = attr->a_desc;
                    mod->sml_type = attr->a_desc->ad_cname;
                    mod->sml_values = attr->a_vals;
                    mod->sml_nvalues = attr->a_nvals;
                    mod->sml_numvals = attr->a_numvals;
                    *modtail = mod;
                    modtail = &mod->sml_next;
                }
                else
                {
                    MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
                    struct berval *bv;
                    const char *text;
                    int acount , bcount;
                    Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
                          addpartial.on_bi.bi_type,
                          attr->a_desc->ad_cname.bv_val,0);

                    for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL; 
                        bv++, acount++)
                    {
                        /* count num values for attr */
                    }
                    for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL; 
                        bv++, bcount++)
                    {
                        /* count num values for attr */
                    }
                    if(acount != bcount)
                    {
                        Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
                              addpartial.on_bi.bi_type,
                              "replace all",0);
                        mod = (Modifications *) ch_malloc(sizeof(
                                                                Modifications));
                        mod->sml_flags = 0;
                        mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
                        mod->sml_op &= LDAP_MOD_OP;
                        mod->sml_next = NULL;
                        mod->sml_desc = attr->a_desc;
                        mod->sml_type = attr->a_desc->ad_cname;
                        mod->sml_values = attr->a_vals;
                        mod->sml_nvalues = attr->a_nvals;
                        mod->sml_numvals = attr->a_numvals;
                        *modtail = mod;
                        modtail = &mod->sml_next;
                        continue;
                    }
                    
                    for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
                    {
                        struct berval *v;
                        ret = -1;
                        
                        for(v = at->a_vals; v->bv_val != NULL; v++)
                        {
                            int r;
                            if(mr && ((r = value_match(&ret, attr->a_desc, mr,
                                           SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
                                           bv, v, &text)) == 0))
                            {
                                if(ret == 0)
                                    break;
                            }
                            else
                            {
                                Debug(LDAP_DEBUG_TRACE,
                                      "%s: \tvalue DNE, r: %d \n",
                                      addpartial.on_bi.bi_type,
                                      r,0);
                                ret = strcmp(bv->bv_val, v->bv_val);
                                if(ret == 0)
                                    break;
                            }
                        }

                        if(ret == 0)
                        {
                            Debug(LDAP_DEBUG_TRACE,
                                  "%s: \tvalue %s exists, ret: %d\n",
                                  addpartial.on_bi.bi_type, bv->bv_val, ret);
                        }
                        else
                        {
                            Debug(LDAP_DEBUG_TRACE,
                                  "%s: \tvalue %s DNE, ret: %d\n",
                                  addpartial.on_bi.bi_type, bv->bv_val, ret);
                            mod = (Modifications *) ch_malloc(sizeof(
                                                                Modifications));
                            mod->sml_flags = 0;
                            mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
                            mod->sml_op &= LDAP_MOD_OP;
                            mod->sml_next = NULL;
                            mod->sml_desc = attr->a_desc;
                            mod->sml_type = attr->a_desc->ad_cname;
                            mod->sml_values = attr->a_vals;
                            mod->sml_nvalues = attr->a_nvals;
                            mod->sml_numvals = attr->a_numvals;
                            *modtail = mod;
                            modtail = &mod->sml_next;
                            break;
                        }
                    }
                }
            }

            /* determine if any attributes were deleted */
            for(attr = found->e_attrs; attr; attr = attr->a_next)
            {
                if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;

                at = NULL;
                at = attr_find(toAdd->e_attrs, attr->a_desc);
                if(!at)
                {
                    Debug(LDAP_DEBUG_TRACE,
                          "%s: Attribute %s not found in new entry!!!\n",
                          addpartial.on_bi.bi_type,
                          attr->a_desc->ad_cname.bv_val, 0);
                    mod = (Modifications *) ch_malloc(sizeof(
                                                        Modifications));
                    mod->sml_flags = 0;
                    mod->sml_op = LDAP_MOD_REPLACE;
                    mod->sml_next = NULL;
                    mod->sml_desc = attr->a_desc;
                    mod->sml_type = attr->a_desc->ad_cname;
                    mod->sml_values = NULL;
                    mod->sml_nvalues = NULL;
                    mod->sml_numvals = 0;
                    *modtail = mod;
                    modtail = &mod->sml_next;
                }
                else
                {
                    Debug(LDAP_DEBUG_TRACE,
                          "%s: Attribute %s found in new entry\n",
                          addpartial.on_bi.bi_type,
                          at->a_desc->ad_cname.bv_val, 0);
                }
            }

            overlay_entry_release_ov(&nop, found, 0, on);

            if(mods)
            {
                Modifications *m = NULL;
                Modifications *toDel;
                int modcount;
                slap_callback nullcb = { NULL, collect_error_msg_cb, 
                                         NULL, NULL };

                Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
                      addpartial.on_bi.bi_type, 0, 0);

                nop.o_tag = LDAP_REQ_MODIFY;
                nop.orm_modlist = mods;
                nop.orm_no_opattrs = 0;
                nop.o_callback = &nullcb;
                nop.o_bd->bd_info = (BackendInfo *) on->on_info;

                for(m = mods, modcount = 0; m; m = m->sml_next, 
                    modcount++)
                {
                    /* count number of mods */
                }

                Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
                      addpartial.on_bi.bi_type, modcount, 0);

                if(nop.o_bd->be_modify)
                {
                    SlapReply nrs = { REP_RESULT };
                    rc = (nop.o_bd->be_modify)(&nop, &nrs);
                }

                if(rc == LDAP_SUCCESS)
                {
                    Debug(LDAP_DEBUG_TRACE,
                          "%s: modify successful\n",
                          addpartial.on_bi.bi_type, 0, 0);
                }
                else
                {
                    Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
                          addpartial.on_bi.bi_type, rc, 0);
                    rs->sr_err = rc;
                    if(nullcb.sc_private)
                    {
                        rs->sr_text = nullcb.sc_private;
                    }
                }

                Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
                      addpartial.on_bi.bi_type, 0, 0);

                for(toDel = mods; toDel; toDel = mods)
                {
                    mods = mods->sml_next;
                    ch_free(toDel);
                }
            }
            else
            {
                Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
                      addpartial.on_bi.bi_type, 0, 0);
            }
        }
        else
        {
            Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
                  addpartial.on_bi.bi_type, 0, 0);
        }

        op->o_callback = NULL;
        send_ldap_result( op, rs );
        ch_free((void *)rs->sr_text);
        rs->sr_text = NULL;

        return LDAP_SUCCESS;
    }
}
示例#13
0
static int
pguid_op_add( Operation *op, SlapReply *rs )
{
	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;

	struct berval pdn, pndn;
	Entry *e = NULL;
	Attribute *a;
	int rc;

	/* don't care about suffix entry */
	if ( dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[0] ) ) {
		return SLAP_CB_CONTINUE;
	}

	dnParent( &op->o_req_dn, &pdn );
	dnParent( &op->o_req_ndn, &pndn );

	rc = overlay_entry_get_ov( op, &pndn, NULL, slap_schema.si_ad_entryUUID, 0, &e, on );
	if ( rc != LDAP_SUCCESS || e == NULL ) {
		Debug( LDAP_DEBUG_ANY, "%s: pguid_op_add: unable to get parent entry DN=\"%s\" (%d)\n",
			op->o_log_prefix, pdn.bv_val, rc );
		return SLAP_CB_CONTINUE;
	}

	a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
	if ( a == NULL ) {
		Debug( LDAP_DEBUG_ANY, "%s: pguid_op_add: unable to find entryUUID of parent entry DN=\"%s\" (%d)\n",
			op->o_log_prefix, pdn.bv_val, rc );
		
	} else {
		assert( a->a_numvals == 1 );

		if ( op->ora_e != NULL ) {
			attr_merge_one( op->ora_e, ad_parentUUID, &a->a_vals[0], a->a_nvals == a->a_vals ? NULL : &a->a_nvals[0] );
		
		} else {
			Modifications *ml;
			Modifications *mod;

			assert( op->ora_modlist != NULL );

			for ( ml = op->ora_modlist; ml != NULL; ml = ml->sml_next ) {
				if ( ml->sml_mod.sm_desc == slap_schema.si_ad_entryUUID ) {
					break;
				}
			}

			if ( ml == NULL ) {
				ml = op->ora_modlist;
			}

			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
			mod->sml_flags = SLAP_MOD_INTERNAL;
			mod->sml_op = LDAP_MOD_ADD;
			mod->sml_desc = ad_parentUUID;
			mod->sml_type = ad_parentUUID->ad_cname;
			mod->sml_values = ch_malloc( sizeof( struct berval ) * 2 );
			mod->sml_nvalues = NULL;
			mod->sml_numvals = 1;

			ber_dupbv( &mod->sml_values[0], &a->a_vals[0] );
			BER_BVZERO( &mod->sml_values[1] );

			mod->sml_next = ml->sml_next;
			ml->sml_next = mod;
		}
	}

	if ( e != NULL ) {
		(void)overlay_entry_release_ov( op, e, 0, on );
	}

	return SLAP_CB_CONTINUE;
}
示例#14
0
static int
pguid_repair_cb( Operation *op, SlapReply *rs )
{
	int rc;
	pguid_repair_cb_t *pcb = op->o_callback->sc_private;
	Entry *e = NULL;
	Attribute *a;
	struct berval pdn, pndn;

	switch ( rs->sr_type ) {
	case REP_SEARCH:
		break;

	case REP_SEARCHREF:
	case REP_RESULT:
		return rs->sr_err;

	default:
		assert( 0 );
	}

	assert( rs->sr_entry != NULL );

	dnParent( &rs->sr_entry->e_name, &pdn );
	dnParent( &rs->sr_entry->e_nname, &pndn );

	rc = overlay_entry_get_ov( op, &pndn, NULL, slap_schema.si_ad_entryUUID, 0, &e, pcb->on );
	if ( rc != LDAP_SUCCESS || e == NULL ) {
		Debug( LDAP_DEBUG_ANY, "%s: pguid_repair_cb: unable to get parent entry DN=\"%s\" (%d)\n",
			op->o_log_prefix, pdn.bv_val, rc );
		return 0;
	}

	a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID );
	if ( a == NULL ) {
		Debug( LDAP_DEBUG_ANY, "%s: pguid_repair_cb: unable to find entryUUID of parent entry DN=\"%s\" (%d)\n",
			op->o_log_prefix, pdn.bv_val, rc );
		
	} else {
		ber_len_t len;
		pguid_mod_t *mod;

		assert( a->a_numvals == 1 );

		len = sizeof( pguid_mod_t ) + rs->sr_entry->e_nname.bv_len + 1 + a->a_vals[0].bv_len + 1;
		mod = op->o_tmpalloc( len, op->o_tmpmemctx );
		mod->ndn.bv_len = rs->sr_entry->e_nname.bv_len;
		mod->ndn.bv_val = (char *)&mod[1];
		mod->pguid.bv_len = a->a_vals[0].bv_len;
		mod->pguid.bv_val = (char *)&mod->ndn.bv_val[mod->ndn.bv_len + 1];
		lutil_strncopy( mod->ndn.bv_val, rs->sr_entry->e_nname.bv_val, rs->sr_entry->e_nname.bv_len );
		lutil_strncopy( mod->pguid.bv_val, a->a_vals[0].bv_val, a->a_vals[0].bv_len );

		mod->next = pcb->mods;
		pcb->mods = mod;

		Debug( LDAP_DEBUG_TRACE, "%s: pguid_repair_cb: scheduling entry DN=\"%s\" for repair\n",
			op->o_log_prefix, rs->sr_entry->e_name.bv_val, 0 );
	}

	if ( e != NULL ) {
		(void)overlay_entry_release_ov( op, e, 0, pcb->on );
	}

	return 0;
}
示例#15
0
static int
dynlist_compare( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
	dynlist_info_t	*dli = (dynlist_info_t *)on->on_bi.bi_private;
	Operation o = *op;
	Entry *e = NULL;
	dynlist_map_t *dlm;

	for ( ; dli != NULL; dli = dli->dli_next ) {
		for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next )
			if ( op->oq_compare.rs_ava->aa_desc == dlm->dlm_member_ad )
				break;

		if ( dli->dli_dlm && dlm ) {
			/* This compare is for one of the attributes we're
			 * interested in. We'll use slapd's existing dyngroup
			 * evaluator to get the answer we want.
			 */
			BerVarray id = NULL, authz = NULL;

			o.o_do_not_cache = 1;

			if ( ad_dgIdentity && backend_attribute( &o, NULL, &o.o_req_ndn,
				ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS )
			{
				/* if not rootdn and dgAuthz is present,
				 * check if user can be authorized as dgIdentity */
				if ( ad_dgAuthz && !BER_BVISEMPTY( id ) && !be_isroot( op )
					&& backend_attribute( &o, NULL, &o.o_req_ndn,
						ad_dgAuthz, &authz, ACL_READ ) == LDAP_SUCCESS )
				{
					
					rs->sr_err = slap_sasl_matches( op, authz,
						&o.o_ndn, &o.o_ndn );
					ber_bvarray_free_x( authz, op->o_tmpmemctx );
					if ( rs->sr_err != LDAP_SUCCESS ) {
						goto done;
					}
				}

				o.o_dn = *id;
				o.o_ndn = *id;
				o.o_groups = NULL; /* authz changed, invalidate cached groups */
			}

			rs->sr_err = backend_group( &o, NULL, &o.o_req_ndn,
				&o.oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad );
			switch ( rs->sr_err ) {
			case LDAP_SUCCESS:
				rs->sr_err = LDAP_COMPARE_TRUE;
				break;

			case LDAP_NO_SUCH_OBJECT:
				/* NOTE: backend_group() returns noSuchObject
				 * if op_ndn does not exist; however, since
				 * dynamic list expansion means that the
				 * member attribute is virtually present, the
				 * non-existence of the asserted value implies
				 * the assertion is FALSE rather than
				 * UNDEFINED */
				rs->sr_err = LDAP_COMPARE_FALSE;
				break;
			}

done:;
			if ( id ) ber_bvarray_free_x( id, o.o_tmpmemctx );

			return SLAP_CB_CONTINUE;
		}
	}

	if ( overlay_entry_get_ov( &o, &o.o_req_ndn, NULL, NULL, 0, &e, on ) !=
		LDAP_SUCCESS || e == NULL )
	{
		return SLAP_CB_CONTINUE;
	}

	if ( ad_dgIdentity ) {
		Attribute *id = attrs_find( e->e_attrs, ad_dgIdentity );
		if ( id ) {
			Attribute *authz;

			/* if not rootdn and dgAuthz is present,
			 * check if user can be authorized as dgIdentity */
			if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op )
				&& ( authz = attrs_find( e->e_attrs, ad_dgAuthz ) ) )
			{
				if ( slap_sasl_matches( op, authz->a_nvals,
					&o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS )
				{
					goto release;
				}
			}

			o.o_dn = id->a_vals[0];
			o.o_ndn = id->a_nvals[0];
			o.o_groups = NULL;
		}
	}

	dli = (dynlist_info_t *)on->on_bi.bi_private;
	for ( ; dli != NULL && rs->sr_err != LDAP_COMPARE_TRUE; dli = dli->dli_next ) {
		Attribute	*a;
		slap_callback	cb;
		SlapReply	r = { REP_SEARCH };
		AttributeName	an[2];
		int		rc;
		dynlist_sc_t	dlc = { 0 };

		if ( !is_entry_objectclass_or_sub( e, dli->dli_oc ))
			continue;

		/* if the entry has the right objectClass, generate
		 * the dynamic list and compare */
		dlc.dlc_dli = dli;
		cb.sc_private = &dlc;
		cb.sc_response = dynlist_sc_save_entry;
		cb.sc_cleanup = NULL;
		cb.sc_next = NULL;
		o.o_callback = &cb;

		o.o_tag = LDAP_REQ_SEARCH;
		o.ors_limit = NULL;
		o.ors_tlimit = SLAP_NO_LIMIT;
		o.ors_slimit = SLAP_NO_LIMIT;

		o.o_bd = select_backend( &o.o_req_ndn, 1 );
		if ( !o.o_bd || !o.o_bd->be_search ) {
			goto release;
		}

		o.ors_filterstr = *slap_filterstr_objectClass_pres;
		o.ors_filter = (Filter *) slap_filter_objectClass_pres;

		o.ors_scope = LDAP_SCOPE_BASE;
		o.ors_deref = LDAP_DEREF_NEVER;
		an[0].an_name = op->orc_ava->aa_desc->ad_cname;
		an[0].an_desc = op->orc_ava->aa_desc;
		BER_BVZERO( &an[1].an_name );
		o.ors_attrs = an;
		o.ors_attrsonly = 0;

		o.o_acl_priv = ACL_COMPARE;

		rc = o.o_bd->be_search( &o, &r );

		if ( o.o_dn.bv_val != op->o_dn.bv_val ) {
			slap_op_groups_free( &o );
		}

		if ( rc != 0 ) {
			goto release;
		}

		if ( dlc.dlc_e != NULL ) {
			r.sr_entry = dlc.dlc_e;
		}

		if ( r.sr_err != LDAP_SUCCESS || r.sr_entry == NULL ) {
			/* error? */
			goto release;
		}

		for ( a = attrs_find( r.sr_entry->e_attrs, op->orc_ava->aa_desc );
			a != NULL;
			a = attrs_find( a->a_next, op->orc_ava->aa_desc ) )
		{
			/* if we're here, we got a match... */
			rs->sr_err = LDAP_COMPARE_FALSE;

			if ( attr_valfind( a,
				SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
					SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
				&op->orc_ava->aa_value, NULL, op->o_tmpmemctx ) == 0 )
			{
				rs->sr_err = LDAP_COMPARE_TRUE;
				break;
			}
		}

		if ( r.sr_flags & REP_ENTRY_MUSTBEFREED ) {
			entry_free( r.sr_entry );
		}
	}

release:;
	if ( e != NULL ) {
		overlay_entry_release_ov( &o, e, 0, on );
	}

	return SLAP_CB_CONTINUE;
}