/* 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; }
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; }
/* Obey and clear rs->sr_flags & REP_ENTRY_MASK. Clear sr_entry if freed. */ void rs_flush_entry( Operation *op, SlapReply *rs, slap_overinst *on ) { rs_assert_ok( rs ); if ( (rs->sr_flags & REP_ENTRY_MUSTFLUSH) && rs->sr_entry != NULL ) { if ( !(rs->sr_flags & REP_ENTRY_MUSTRELEASE) ) { entry_free( rs->sr_entry ); } else if ( on != NULL ) { overlay_entry_release_ov( op, rs->sr_entry, 0, on ); } else { be_entry_release_rw( op, rs->sr_entry, 0 ); } rs->sr_entry = NULL; } rs->sr_flags &= ~REP_ENTRY_MASK; }
/* Set rs->sr_entry after obyeing and clearing sr_flags & REP_ENTRY_MASK. */ void rs_replace_entry( Operation *op, SlapReply *rs, slap_overinst *on, Entry *e ) { slap_mask_t e_flags = rs->sr_flags & REP_ENTRY_MUSTFLUSH; if ( e_flags && rs->sr_entry != NULL ) { RS_ASSERT( e_flags != REP_ENTRY_MUSTFLUSH ); if ( !(e_flags & REP_ENTRY_MUSTRELEASE) ) { entry_free( rs->sr_entry ); } else if ( on != NULL ) { overlay_entry_release_ov( op, rs->sr_entry, 0, on ); } else { be_entry_release_rw( op, rs->sr_entry, 0 ); } } rs->sr_flags &= ~REP_ENTRY_MASK; rs->sr_entry = e; }
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); }
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; }
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; }
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; }
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; }
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; }
/* ** 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; }
/* ** 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; }
/** * 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; } }
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; }
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; }
static int valsort_response( Operation *op, SlapReply *rs ) { slap_overinst *on; valsort_info *vi; Attribute *a; /* If this is not a search response, or it is a syncrepl response, * or the valsort control wants raw results, pass thru unmodified. */ if ( rs->sr_type != REP_SEARCH || ( _SCM(op->o_sync) > SLAP_CONTROL_IGNORED ) || ( op->o_ctrlflag[valsort_cid] & SLAP_CONTROL_DATA0)) return SLAP_CB_CONTINUE; on = (slap_overinst *) op->o_bd->bd_info; vi = on->on_bi.bi_private; /* And we must have something configured */ if ( !vi ) return SLAP_CB_CONTINUE; /* Find a rule whose baseDN matches this entry */ for (; vi; vi = vi->vi_next ) { int i, n; if ( !dnIsSuffix( &rs->sr_entry->e_nname, &vi->vi_dn )) continue; /* Find attr that this rule affects */ a = attr_find( rs->sr_entry->e_attrs, vi->vi_ad ); if ( !a ) continue; if (( rs->sr_flags & ( REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED ) ) != ( REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED ) ) { Entry *e; e = entry_dup( rs->sr_entry ); if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) { overlay_entry_release_ov( op, rs->sr_entry, 0, on ); rs->sr_flags &= ~REP_ENTRY_MUSTRELEASE; } else if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) { entry_free( rs->sr_entry ); } rs->sr_entry = e; rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED; a = attr_find( rs->sr_entry->e_attrs, vi->vi_ad ); } n = a->a_numvals; if ( vi->vi_sort & VALSORT_WEIGHTED ) { int j, gotnvals; long *index = op->o_tmpalloc( n * sizeof(long), op->o_tmpmemctx ); gotnvals = (a->a_vals != a->a_nvals ); for (i=0; i<n; i++) { char *ptr = ber_bvchr( &a->a_nvals[i], '{' ); char *end = NULL; if ( !ptr ) { Debug(LDAP_DEBUG_TRACE, "weights missing from attr %s " "in entry %s\n", vi->vi_ad->ad_cname.bv_val, rs->sr_entry->e_name.bv_val, 0 ); break; } index[i] = strtol( ptr+1, &end, 0 ); if ( *end != '}' ) { Debug(LDAP_DEBUG_TRACE, "weights misformatted " "in entry %s\n", rs->sr_entry->e_name.bv_val, 0, 0 ); break; } /* Strip out weights */ ptr = a->a_nvals[i].bv_val; end++; for (;*end;) *ptr++ = *end++; *ptr = '\0'; a->a_nvals[i].bv_len = ptr - a->a_nvals[i].bv_val; if ( a->a_vals != a->a_nvals ) { ptr = a->a_vals[i].bv_val; end = ber_bvchr( &a->a_vals[i], '}' ); assert( end != NULL ); end++; for (;*end;) *ptr++ = *end++; *ptr = '\0'; a->a_vals[i].bv_len = ptr - a->a_vals[i].bv_val; } } /* An attr was missing weights here, ignore it */ if ( i<n ) { op->o_tmpfree( index, op->o_tmpmemctx ); continue; } /* Insertion sort */ for ( i=1; i<n; i++) { long idx = index[i]; struct berval tmp = a->a_vals[i], ntmp; if ( gotnvals ) ntmp = a->a_nvals[i]; j = i; while (( j>0 ) && (index[j-1] > idx )) { index[j] = index[j-1]; a->a_vals[j] = a->a_vals[j-1]; if ( gotnvals ) a->a_nvals[j] = a->a_nvals[j-1]; j--; } index[j] = idx; a->a_vals[j] = tmp; if ( gotnvals ) a->a_nvals[j] = ntmp; } /* Check for secondary sort */ if ( vi->vi_sort ^ VALSORT_WEIGHTED ) { for ( i=0; i<n;) { for (j=i+1; j<n; j++) { if (index[i] != index[j]) break; } if( j-i > 1 ) do_sort( op, a, i, j-i, vi->vi_sort ); i = j; } } op->o_tmpfree( index, op->o_tmpmemctx ); } else { do_sort( op, a, 0, n, vi->vi_sort ); } } return SLAP_CB_CONTINUE; }
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; }
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; }