/* ** When adding a group, we first strip any existing members, ** and add all which match the filters ourselfs. */ static int autogroup_add_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; autogroup_filter_t *agf; int rc = 0; Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n", op->ora_e->e_name.bv_val, 0, 0); ldap_pvt_thread_mutex_lock( &agi->agi_mutex ); /* Check if it's a group. */ for ( ; agd ; agd = agd->agd_next ) { if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) { Modification mod; const char *text = NULL; char textbuf[1024]; mod.sm_op = LDAP_MOD_DELETE; mod.sm_desc = agd->agd_member_ad; mod.sm_type = agd->agd_member_ad->ad_cname; mod.sm_values = NULL; mod.sm_nvalues = NULL; /* We don't want any member attributes added by the user. */ modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) ); autogroup_add_group( op, agi, agd, op->ora_e, NULL, 1 , 0); ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; } } for ( ; age ; age = age->age_next ) { ldap_pvt_thread_mutex_lock( &age->age_mutex ); /* Check if any of the filters are the suffix to the entry DN. If yes, we can test that filter against the entry. */ for ( agf = age->age_filter; agf ; agf = agf->agf_next ) { if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) { rc = test_filter( op, op->ora_e, agf->agf_filter ); if ( rc == LDAP_COMPARE_TRUE ) { autogroup_add_member_to_group( op, &op->ora_e->e_name, &op->ora_e->e_nname, age ); break; } } } ldap_pvt_thread_mutex_unlock( &age->age_mutex ); } ldap_pvt_thread_mutex_unlock( &agi->agi_mutex ); return SLAP_CB_CONTINUE; }
static int retcode_entry_response( Operation *op, SlapReply *rs, BackendInfo *bi, Entry *e ) { Attribute *a; int err; char *next; int disconnect = 0; if ( get_manageDSAit( op ) ) { return SLAP_CB_CONTINUE; } if ( !is_entry_objectclass_or_sub( e, oc_errAbsObject ) ) { return SLAP_CB_CONTINUE; } /* operation */ a = attr_find( e->e_attrs, ad_errOp ); if ( a != NULL ) { int i, gotit = 0; struct berval bv = BER_BVNULL; (void)retcode_op2str( op->o_tag, &bv ); if ( BER_BVISNULL( &bv ) ) { return SLAP_CB_CONTINUE; } for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { if ( bvmatch( &a->a_nvals[ i ], &bv ) ) { gotit = 1; break; } } if ( !gotit ) { return SLAP_CB_CONTINUE; } } /* disconnect */ a = attr_find( e->e_attrs, ad_errDisconnect ); if ( a != NULL ) { if ( bvmatch( &a->a_nvals[ 0 ], &slap_true_bv ) ) { return rs->sr_err = SLAPD_DISCONNECT; } disconnect = 1; } /* error code */ a = attr_find( e->e_attrs, ad_errCode ); if ( a == NULL ) { return SLAP_CB_CONTINUE; } err = strtol( a->a_nvals[ 0 ].bv_val, &next, 0 ); if ( next == a->a_nvals[ 0 ].bv_val || next[ 0 ] != '\0' ) { return SLAP_CB_CONTINUE; } rs->sr_err = err; /* sleep time */ a = attr_find( e->e_attrs, ad_errSleepTime ); if ( a != NULL && a->a_nvals[ 0 ].bv_val[ 0 ] != '-' ) { int sleepTime; if ( lutil_atoi( &sleepTime, a->a_nvals[ 0 ].bv_val ) == 0 ) { retcode_sleep( sleepTime ); } } if ( rs->sr_err != LDAP_SUCCESS && !LDAP_API_ERROR( rs->sr_err )) { BackendDB db = *op->o_bd, *o_bd = op->o_bd; void *o_callback = op->o_callback; /* message text */ a = attr_find( e->e_attrs, ad_errText ); if ( a != NULL ) { rs->sr_text = a->a_vals[ 0 ].bv_val; } /* matched DN */ a = attr_find( e->e_attrs, ad_errMatchedDN ); if ( a != NULL ) { rs->sr_matched = a->a_vals[ 0 ].bv_val; } if ( bi == NULL ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; bi = on->on_info->oi_orig; } db.bd_info = bi; op->o_bd = &db; op->o_callback = NULL; /* referral */ if ( rs->sr_err == LDAP_REFERRAL ) { BerVarray refs = default_referral; a = attr_find( e->e_attrs, slap_schema.si_ad_ref ); if ( a != NULL ) { refs = a->a_vals; } rs->sr_ref = referral_rewrite( refs, NULL, &op->o_req_dn, op->oq_search.rs_scope ); send_search_reference( op, rs ); ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } else { a = attr_find( e->e_attrs, ad_errUnsolicitedOID ); if ( a != NULL ) { struct berval oid = BER_BVNULL, data = BER_BVNULL; ber_int_t msgid = op->o_msgid; /* RFC 4511 unsolicited response */ op->o_msgid = 0; oid = a->a_nvals[ 0 ]; a = attr_find( e->e_attrs, ad_errUnsolicitedData ); if ( a != NULL ) { data = a->a_nvals[ 0 ]; } if ( strcmp( oid.bv_val, "0" ) == 0 ) { send_ldap_result( op, rs ); } else { ber_tag_t tag = op->o_tag; op->o_tag = LDAP_REQ_EXTENDED; rs->sr_rspoid = oid.bv_val; if ( !BER_BVISNULL( &data ) ) { rs->sr_rspdata = &data; } send_ldap_extended( op, rs ); rs->sr_rspoid = NULL; rs->sr_rspdata = NULL; op->o_tag = tag; } op->o_msgid = msgid; } else { send_ldap_result( op, rs ); } } rs->sr_text = NULL; rs->sr_matched = NULL; op->o_bd = o_bd; op->o_callback = o_callback; } if ( rs->sr_err != LDAP_SUCCESS ) { if ( disconnect ) { return rs->sr_err = SLAPD_DISCONNECT; } op->o_abandon = 1; return rs->sr_err; } 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; 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 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; }
static int cloak_search_response_cb( Operation *op, SlapReply *rs ) { slap_callback *sc; cloak_info_t *ci; Entry *e = NULL; Entry *me = NULL; assert( op && op->o_callback && rs ); if ( rs->sr_type != REP_SEARCH || !rs->sr_entry ) { return ( SLAP_CB_CONTINUE ); } sc = op->o_callback; e = rs->sr_entry; /* * First perform a quick scan for an attribute to cloak */ for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { Attribute *a; if ( ci->ci_oc != NULL && !is_entry_objectclass_or_sub( e, ci->ci_oc ) ) continue; for ( a = e->e_attrs; a; a = a->a_next ) if ( a->a_desc == ci->ci_ad ) break; if ( a != NULL ) break; } /* * Nothing found to cloak */ if ( ci == NULL ) return ( SLAP_CB_CONTINUE ); /* * We are now committed to cloak an attribute. */ rs_entry2modifiable( op, rs, (slap_overinst *) op->o_bd->bd_info ); me = rs->sr_entry; for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { Attribute *a; Attribute *pa; for ( pa = NULL, a = me->e_attrs; a; pa = a, a = a->a_next ) { if ( a->a_desc != ci->ci_ad ) continue; Debug( LDAP_DEBUG_TRACE, "cloak_search_response_cb: cloak %s\n", a->a_desc->ad_cname.bv_val, 0, 0 ); if ( pa != NULL ) pa->a_next = a->a_next; else me->e_attrs = a->a_next; attr_clean( a ); } } 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; }
static int cloak_search_cb( Operation *op, SlapReply *rs ) { slap_callback *sc; cloak_info_t *ci; Entry *e = NULL; Entry *me = NULL; assert( op && op->o_callback && rs ); if ( rs->sr_type != REP_SEARCH || !rs->sr_entry ) { slap_freeself_cb( op, rs ); return ( SLAP_CB_CONTINUE ); } sc = op->o_callback; e = rs->sr_entry; /* * First perform a quick scan for an attribute to cloak */ for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { Attribute *a; if ( ci->ci_oc != NULL && !is_entry_objectclass_or_sub( e, ci->ci_oc ) ) continue; for ( a = e->e_attrs; a; a = a->a_next ) if ( a->a_desc == ci->ci_ad ) break; if ( a != NULL ) break; } /* * Nothing found to cloak */ if ( ci == NULL ) return ( SLAP_CB_CONTINUE ); /* * We are now committed to cloak an attribute. */ if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) me = e; else me = entry_dup( e ); for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) { Attribute *a; Attribute *pa; for ( pa = NULL, a = me->e_attrs; a; pa = a, a = a->a_next ) { if ( a->a_desc != ci->ci_ad ) continue; Debug( LDAP_DEBUG_TRACE, "cloak_search_cb: cloak %s\n", a->a_desc->ad_cname.bv_val, 0, 0 ); if ( pa != NULL ) pa->a_next = a->a_next; else me->e_attrs = a->a_next; attr_clean( a ); } } if ( me != e ) { if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) entry_free( e ); rs->sr_entry = me; rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; } return ( SLAP_CB_CONTINUE ); }