static int monitor_subsys_conn_update( Operation *op, SlapReply *rs, Entry *e ) { monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private; long n = -1; static struct berval total_bv = BER_BVC( "cn=total" ), current_bv = BER_BVC( "cn=current" ); struct berval rdn; assert( mi != NULL ); assert( e != NULL ); dnRdn( &e->e_nname, &rdn ); if ( dn_match( &rdn, &total_bv ) ) { n = connections_nextid(); } else if ( dn_match( &rdn, ¤t_bv ) ) { Connection *c; ber_socket_t connindex; for ( n = 0, c = connection_first( &connindex ); c != NULL; n++, c = connection_next( c, &connindex ) ) { /* No Op */ ; } connection_done( c ); } if ( n != -1 ) { Attribute *a; char buf[LDAP_PVT_INTTYPE_CHARS(long)]; ber_len_t len; a = attr_find( e->e_attrs, mi->mi_ad_monitorCounter ); if ( a == NULL ) { return( -1 ); } snprintf( buf, sizeof( buf ), "%ld", n ); len = strlen( buf ); if ( len > a->a_vals[ 0 ].bv_len ) { a->a_vals[ 0 ].bv_val = ber_memrealloc( a->a_vals[ 0 ].bv_val, len + 1 ); } a->a_vals[ 0 ].bv_len = len; memcpy( a->a_vals[ 0 ].bv_val, buf, len + 1 ); /* FIXME: touch modifyTimestamp? */ }
static int collect_response( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; collect_info *ci = on->on_bi.bi_private; /* If we've been configured and the current response is * a search entry */ if ( ci && rs->sr_type == REP_SEARCH ) { int rc; op->o_bd->bd_info = (BackendInfo *)on->on_info; for (; ci; ci=ci->ci_next ) { int idx=0; /* Is this entry an ancestor of this collectinfo ? */ if (!dnIsSuffix(&rs->sr_entry->e_nname, &ci->ci_dn)) { /* collectinfo does not match */ continue; } /* Is this entry the same as the template DN ? */ if ( dn_match(&rs->sr_entry->e_nname, &ci->ci_dn)) { /* dont apply change to parent */ continue; } /* The current entry may live in a cache, so * don't modify it directly. Make a copy and * work with that instead. */ rs_entry2modifiable( op, rs, on ); /* Loop for each attribute in this collectinfo */ for(idx=0; idx<ci->ci_ad_num; idx++) { BerVarray vals = NULL; /* Extract the values of the desired attribute from * the ancestor entry */ rc = backend_attribute( op, NULL, &ci->ci_dn, ci->ci_ad[idx], &vals, ACL_READ ); /* If there are any values, merge them into the * current search result */ if ( vals ) { attr_merge( rs->sr_entry, ci->ci_ad[idx], vals, NULL ); ber_bvarray_free_x( vals, op->o_tmpmemctx ); } } } } /* Default is to just fall through to the normal processing */ return SLAP_CB_CONTINUE; }
static int rdnval_op_rename( Operation *op, SlapReply *rs ) { Modifications *ml, **mlp; int numvals = 0; BerVarray vals = NULL, nvals = NULL; struct berval old; int rc; dnRdn( &op->o_req_dn, &old ); if ( dn_match( &old, &op->orr_newrdn ) ) { dnRdn( &op->o_req_ndn, &old ); if ( dn_match( &old, &op->orr_nnewrdn ) ) { return SLAP_CB_CONTINUE; } } rc = rdnval_rdn2vals( op, rs, &op->orr_newrdn, &op->orr_nnewrdn, &vals, &nvals, &numvals ); if ( rc != LDAP_SUCCESS ) { send_ldap_result( op, rs ); } ml = SLAP_CALLOC( sizeof( Modifications ), 1 ); ml->sml_values = vals; ml->sml_nvalues = nvals; ml->sml_numvals = numvals; ml->sml_op = LDAP_MOD_REPLACE; ml->sml_flags = SLAP_MOD_INTERNAL; ml->sml_desc = ad_rdnValue; ml->sml_type = ad_rdnValue->ad_cname; for ( mlp = &op->orr_modlist; *mlp != NULL; mlp = &(*mlp)->sml_next ) /* goto tail */ ; *mlp = ml; return SLAP_CB_CONTINUE; }
static int sasl_sc_smatch( BackendDB *be, Connection *conn, Operation *o, Entry *e, AttributeName *an, int ao, LDAPControl **c) { smatch_info *sm = o->o_callback->sc_private; if (dn_match(sm->dn, &e->e_nname)) { sm->match = 1; return -1; /* short-circuit the search */ } return 1; }
static int usn_operational( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; usn_info_t *ui = (usn_info_t *)on->on_bi.bi_private; if ( rs->sr_entry && dn_match( &rs->sr_entry->e_nname, op->o_bd->be_nsuffix )) { if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( ad_usnChanged, rs->sr_attrs )) { Attribute *a, **ap = NULL; char intbuf[64]; struct berval bv; int my_usn; for ( a=rs->sr_entry->e_attrs; a; a=a->a_next ) { if ( a->a_desc == ad_usnChanged ) break; } if ( !a ) { for ( ap = &rs->sr_operational_attrs; *ap; ap=&(*ap)->a_next ); a = attr_alloc( ad_usnChanged ); *ap = a; } if ( !ap ) { if ( rs_entry2modifiable( op,rs, on )) { a = attr_find( rs->sr_entry->e_attrs, ad_usnChanged ); } ber_bvarray_free( a->a_vals ); a->a_vals = NULL; a->a_numvals = 0; } ldap_pvt_thread_mutex_lock( &ui->ui_mutex ); my_usn = ui->ui_current; ldap_pvt_thread_mutex_unlock( &ui->ui_mutex ); bv.bv_len = snprintf( intbuf, sizeof(intbuf), "%d", my_usn ); bv.bv_val = intbuf; attr_valadd( a, &bv, NULL, 1 ); } } return SLAP_CB_CONTINUE; }
static int collect_modify( Operation *op, SlapReply *rs) { slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; collect_info *ci = on->on_bi.bi_private; Modifications *ml; char errMsg[100]; int idx; for ( ml = op->orm_modlist; ml != NULL; ml = ml->sml_next) { for (; ci; ci=ci->ci_next ) { /* Is this entry an ancestor of this collectinfo ? */ if (!dnIsSuffix(&op->o_req_ndn, &ci->ci_dn)) { /* this collectinfo does not match */ continue; } /* Is this entry the same as the template DN ? */ if ( dn_match(&op->o_req_ndn, &ci->ci_dn)) { /* all changes in this ci are allowed */ continue; } /* check for collect attributes - disallow modify if present */ for(idx=0; idx<ci->ci_ad_num; idx++) { if (ml->sml_desc == ci->ci_ad[idx]) { rs->sr_err = LDAP_UNWILLING_TO_PERFORM; snprintf( errMsg, sizeof( errMsg ), "cannot change virtual attribute '%s'", ci->ci_ad[idx]->ad_cname.bv_val); rs->sr_text = errMsg; send_ldap_result( op, rs ); return rs->sr_err; } } } } return SLAP_CB_CONTINUE; }
int meta_back_bind( Operation *op, SlapReply *rs ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metaconn_t *mc = NULL; int rc = LDAP_OTHER, i, gotit = 0, isroot = 0; SlapReply *candidates; rs->sr_err = LDAP_SUCCESS; Debug( LDAP_DEBUG_ARGS, "%s meta_back_bind: dn=\"%s\".\n", op->o_log_prefix, op->o_req_dn.bv_val ); /* the test on the bind method should be superfluous */ switch ( be_rootdn_bind( op, rs ) ) { case LDAP_SUCCESS: if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) { /* frontend will return success */ return rs->sr_err; } isroot = 1; /* fallthru */ case SLAP_CB_CONTINUE: break; default: /* be_rootdn_bind() sent result */ return rs->sr_err; } /* we need meta_back_getconn() not send result even on error, * because we want to intercept the error and make it * invalidCredentials */ mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND ); if ( !mc ) { if ( LogTest( LDAP_DEBUG_ANY ) ) { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "meta_back_bind: no target " "for dn \"%s\" (%d%s%s).", op->o_req_dn.bv_val, rs->sr_err, rs->sr_text ? ". " : "", rs->sr_text ? rs->sr_text : "" ); Debug( LDAP_DEBUG_ANY, "%s %s\n", op->o_log_prefix, buf ); } /* FIXME: there might be cases where we don't want * to map the error onto invalidCredentials */ switch ( rs->sr_err ) { case LDAP_NO_SUCH_OBJECT: case LDAP_UNWILLING_TO_PERFORM: rs->sr_err = LDAP_INVALID_CREDENTIALS; rs->sr_text = NULL; break; } send_ldap_result( op, rs ); return rs->sr_err; } candidates = meta_back_candidates_get( op ); /* * Each target is scanned ... */ mc->mc_authz_target = META_BOUND_NONE; for ( i = 0; i < mi->mi_ntargets; i++ ) { metatarget_t *mt = mi->mi_targets[ i ]; int lerr; /* * Skip non-candidates */ if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { continue; } if ( gotit == 0 ) { /* set rc to LDAP_SUCCESS only if at least * one candidate has been tried */ rc = LDAP_SUCCESS; gotit = 1; } else if ( !isroot ) { /* * A bind operation is expected to have * ONE CANDIDATE ONLY! */ Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind: more than one" " candidate selected...\n", op->o_log_prefix ); } if ( isroot ) { if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE || BER_BVISNULL( &mt->mt_idassert_authcDN ) ) { metasingleconn_t *msc = &mc->mc_conns[ i ]; /* skip the target if no pseudorootdn is provided */ if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { ch_free( msc->msc_bound_ndn.bv_val ); BER_BVZERO( &msc->msc_bound_ndn ); } if ( !BER_BVISNULL( &msc->msc_cred ) ) { /* destroy sensitive data */ memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); ch_free( msc->msc_cred.bv_val ); BER_BVZERO( &msc->msc_cred ); } continue; } (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND, 1 ); lerr = rs->sr_err; } else { lerr = meta_back_single_bind( op, rs, mc, i ); } if ( lerr != LDAP_SUCCESS ) { rc = rs->sr_err = lerr; /* FIXME: in some cases (e.g. unavailable) * do not assume it's not candidate; rather * mark this as an error to be eventually * reported to client */ META_CANDIDATE_CLEAR( &candidates[ i ] ); break; } } /* must re-insert if local DN changed as result of bind */ if ( rc == LDAP_SUCCESS ) { if ( isroot ) { mc->mc_authz_target = META_BOUND_ALL; } if ( !LDAP_BACK_PCONN_ISPRIV( mc ) && !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) { int lerr; /* wait for all other ops to release the connection */ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); assert( mc->mc_refcnt == 1 ); #if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi, ">>> meta_back_bind" ); #endif /* META_BACK_PRINT_CONNTREE */ /* delete all cached connections with the current connection */ if ( LDAP_BACK_SINGLECONN( mi ) ) { metaconn_t *tmpmc; while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL ) { assert( !LDAP_BACK_PCONN_ISPRIV( mc ) ); Debug( LDAP_DEBUG_TRACE, "=>meta_back_bind: destroying conn %lu (refcnt=%u)\n", mc->mc_conn->c_connid, mc->mc_refcnt ); if ( tmpmc->mc_refcnt != 0 ) { /* taint it */ LDAP_BACK_CONN_TAINTED_SET( tmpmc ); } else { /* * Needs a test because the handler may be corrupted, * and calling ldap_unbind on a corrupted header results * in a segmentation fault */ meta_back_conn_free( tmpmc ); } } } ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn ); lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conndn_cmp, meta_back_conndn_dup ); #if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi, "<<< meta_back_bind" ); #endif /* META_BACK_PRINT_CONNTREE */ if ( lerr == 0 ) { #if 0 /* NOTE: a connection cannot be privileged * and be in the avl tree at the same time */ if ( isroot ) { LDAP_BACK_CONN_ISPRIV_SET( mc ); LDAP_BACK_PCONN_SET( mc, op ); } #endif LDAP_BACK_CONN_CACHED_SET( mc ); } else { LDAP_BACK_CONN_CACHED_CLEAR( mc ); } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } } if ( mc != NULL ) { meta_back_release_conn( mi, mc ); } /* * rc is LDAP_SUCCESS if at least one bind succeeded, * err is the last error that occurred during a bind; * if at least (and at most?) one bind succeeds, fine. */ if ( rc != LDAP_SUCCESS ) { /* * deal with bind failure ... */ /* * no target was found within the naming context, * so bind must fail with invalid credentials */ if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) { rs->sr_err = LDAP_INVALID_CREDENTIALS; } else { rs->sr_err = slap_map_api2result( rs ); } send_ldap_result( op, rs ); return rs->sr_err; } return LDAP_SUCCESS; }
static int slapi_over_acl_group( Operation *op, Entry *target, struct berval *gr_ndn, struct berval *op_ndn, ObjectClass *group_oc, AttributeDescription *group_at ) { Slapi_Entry *e; int rc; Slapi_PBlock *pb; BackendDB *be = op->o_bd; GroupAssertion *g; SlapReply rs = { REP_RESULT }; op->o_bd = select_backend( gr_ndn, 0 ); for ( g = op->o_groups; g; g = g->ga_next ) { if ( g->ga_be != op->o_bd || g->ga_oc != group_oc || g->ga_at != group_at || g->ga_len != gr_ndn->bv_len ) { continue; } if ( strcmp( g->ga_ndn, gr_ndn->bv_val ) == 0 ) { break; } } if ( g != NULL ) { rc = g->ga_res; goto done; } if ( target != NULL && dn_match( &target->e_nname, gr_ndn ) ) { e = target; rc = 0; } else { rc = be_entry_get_rw( op, gr_ndn, group_oc, group_at, 0, &e ); } if ( e != NULL ) { int internal_op; slap_callback cb; internal_op = slapi_op_internal_p( op, &rs, &cb ); cb.sc_response = NULL; cb.sc_cleanup = NULL; pb = SLAPI_OPERATION_PBLOCK( op ); slapi_pblock_set( pb, SLAPI_X_GROUP_ENTRY, (void *)e ); slapi_pblock_set( pb, SLAPI_X_GROUP_OPERATION_DN, (void *)op_ndn->bv_val ); slapi_pblock_set( pb, SLAPI_X_GROUP_ATTRIBUTE, (void *)group_at->ad_cname.bv_val ); slapi_pblock_set( pb, SLAPI_X_GROUP_TARGET_ENTRY, (void *)target ); rc = slapi_over_call_plugins( pb, SLAPI_X_PLUGIN_PRE_GROUP_FN ); if ( rc >= 0 ) /* 1 means no plugins called */ rc = SLAP_CB_CONTINUE; else rc = pb->pb_rs->sr_err; slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ENTRY ); slapi_pblock_delete_param( pb, SLAPI_X_GROUP_OPERATION_DN ); slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ATTRIBUTE ); slapi_pblock_delete_param( pb, SLAPI_X_GROUP_TARGET_ENTRY ); if ( !internal_op ) slapi_pblock_destroy( pb ); if ( e != target ) { be_entry_release_r( op, e ); } op->o_callback = cb.sc_next; } else { rc = LDAP_NO_SUCH_OBJECT; /* return SLAP_CB_CONTINUE for correctness? */ } if ( op->o_tag != LDAP_REQ_BIND && !op->o_do_not_cache && rc != SLAP_CB_CONTINUE ) { g = op->o_tmpalloc( sizeof( GroupAssertion ) + gr_ndn->bv_len, op->o_tmpmemctx ); g->ga_be = op->o_bd; g->ga_oc = group_oc; g->ga_at = group_at; g->ga_res = rc; g->ga_len = gr_ndn->bv_len; strcpy( g->ga_ndn, gr_ndn->bv_val ); g->ga_next = op->o_groups; op->o_groups = g; } /* * XXX don't call POST_GROUP_FN, I have no idea what the point of * that plugin function was anyway */ done: op->o_bd = be; return rc; }
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 aci_mask( Operation *op, Entry *e, AttributeDescription *desc, struct berval *val, struct berval *aci, int nmatch, regmatch_t *matches, slap_access_t *grant, slap_access_t *deny, slap_aci_scope_t asserted_scope ) { struct berval bv, scope, perms, type, opts, sdn; int rc; ACL_INIT( *grant ); ACL_INIT( *deny ); assert( !BER_BVISNULL( &desc->ad_cname ) ); /* parse an aci of the form: oid # scope # action;rights;attr;rights;attr $ action;rights;attr;rights;attr # type # subject [NOTE: the following comment is very outdated, as the draft version it refers to (Ando, 2004-11-20)]. See draft-ietf-ldapext-aci-model-04.txt section 9.1 for a full description of the format for this attribute. Differences: "this" in the draft is "self" here, and "self" and "public" is in the position of type. <scope> = {entry|children|subtree} <type> = {public|users|access-id|subtree|onelevel|children| self|dnattr|group|role|set|set-ref} This routine now supports scope={ENTRY,CHILDREN} with the semantics: - ENTRY applies to "entry" and "subtree"; - CHILDREN applies to "children" and "subtree" */ /* check that the aci has all 5 components */ if ( acl_get_part( aci, 4, '#', NULL ) < 0 ) { return 0; } /* check that the aci family is supported */ /* FIXME: the OID is ignored? */ if ( acl_get_part( aci, 0, '#', &bv ) < 0 ) { return 0; } /* check that the scope matches */ if ( acl_get_part( aci, 1, '#', &scope ) < 0 ) { return 0; } /* note: scope can be either ENTRY or CHILDREN; * they respectively match "entry" and "children" in bv * both match "subtree" */ switch ( asserted_scope ) { case SLAP_ACI_SCOPE_ENTRY: if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_ENTRY ] ) != 0 && ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 ) { return 0; } break; case SLAP_ACI_SCOPE_CHILDREN: if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_CHILDREN ] ) != 0 && ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 ) { return 0; } break; case SLAP_ACI_SCOPE_SUBTREE: /* TODO: add assertion? */ return 0; } /* get the list of permissions clauses, bail if empty */ if ( acl_get_part( aci, 2, '#', &perms ) <= 0 ) { LDAP_BUG(); return 0; } /* check if any permissions allow desired access */ if ( aci_list_get_rights( &perms, &desc->ad_cname, val, grant, deny ) == 0 ) { return 0; } /* see if we have a DN match */ if ( acl_get_part( aci, 3, '#', &type ) < 0 ) { LDAP_BUG(); return 0; } /* see if we have a public (i.e. anonymous) access */ if ( ber_bvcmp( &aci_bv[ ACI_BV_PUBLIC ], &type ) == 0 ) { return 1; } /* otherwise require an identity */ if ( BER_BVISNULL( &op->o_ndn ) || BER_BVISEMPTY( &op->o_ndn ) ) { return 0; } /* see if we have a users access */ if ( ber_bvcmp( &aci_bv[ ACI_BV_USERS ], &type ) == 0 ) { return 1; } /* NOTE: this may fail if a DN contains a valid '#' (unescaped); * just grab all the berval up to its end (ITS#3303). * NOTE: the problem could be solved by providing the DN with * the embedded '#' encoded as hexpairs: "cn=Foo#Bar" would * become "cn=Foo\23Bar" and be safely used by aci_mask(). */ #if 0 if ( acl_get_part( aci, 4, '#', &sdn ) < 0 ) { return 0; } #endif sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" ); sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val ); /* get the type options, if any */ if ( acl_get_part( &type, 1, '/', &opts ) > 0 ) { opts.bv_len = type.bv_len - ( opts.bv_val - type.bv_val ); type.bv_len = opts.bv_val - type.bv_val - 1; } else { BER_BVZERO( &opts ); } if ( ber_bvcmp( &aci_bv[ ACI_BV_ACCESS_ID ], &type ) == 0 ) { return dn_match( &op->o_ndn, &sdn ); } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SUBTREE ], &type ) == 0 ) { return dnIsSuffix( &op->o_ndn, &sdn ); } else if ( ber_bvcmp( &aci_bv[ ACI_BV_ONELEVEL ], &type ) == 0 ) { struct berval pdn; dnParent( &sdn, &pdn ); return dn_match( &op->o_ndn, &pdn ); } else if ( ber_bvcmp( &aci_bv[ ACI_BV_CHILDREN ], &type ) == 0 ) { return ( !dn_match( &op->o_ndn, &sdn ) && dnIsSuffix( &op->o_ndn, &sdn ) ); } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SELF ], &type ) == 0 ) { return dn_match( &op->o_ndn, &e->e_nname ); } else if ( ber_bvcmp( &aci_bv[ ACI_BV_DNATTR ], &type ) == 0 ) { Attribute *at; AttributeDescription *ad = NULL; const char *text; rc = slap_bv2ad( &sdn, &ad, &text ); assert( rc == LDAP_SUCCESS ); rc = 0; for ( at = attrs_find( e->e_attrs, ad ); at != NULL; at = attrs_find( at->a_next, ad ) ) { if ( attr_valfind( at, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, &op->o_ndn, NULL, op->o_tmpmemctx ) == 0 ) { rc = 1; break; } } return rc; } else if ( ber_bvcmp( &aci_bv[ ACI_BV_GROUP ], &type ) == 0 ) { struct berval oc, at; if ( BER_BVISNULL( &opts ) ) { oc = aci_bv[ ACI_BV_GROUP_CLASS ]; at = aci_bv[ ACI_BV_GROUP_ATTR ]; } else { if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) { LDAP_BUG(); } if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) { at = aci_bv[ ACI_BV_GROUP_ATTR ]; } } if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) ) { return 1; } } else if ( ber_bvcmp( &aci_bv[ ACI_BV_ROLE ], &type ) == 0 ) { struct berval oc, at; if ( BER_BVISNULL( &opts ) ) { oc = aci_bv[ ACI_BV_ROLE_CLASS ]; at = aci_bv[ ACI_BV_ROLE_ATTR ]; } else { if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) { LDAP_BUG(); } if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) { at = aci_bv[ ACI_BV_ROLE_ATTR ]; } } if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) ) { return 1; } } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET ], &type ) == 0 ) { if ( acl_match_set( &sdn, op, e, NULL ) ) { return 1; } } else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET_REF ], &type ) == 0 ) { if ( acl_match_set( &sdn, op, e, (struct berval *)&aci_bv[ ACI_BV_SET_ATTR ] ) ) { return 1; } } else { /* it passed normalization! */ LDAP_BUG(); } return 0; }
/* * This routine generates the DN appropriate to return in * an LDAP referral. */ static char * referral_dn_muck( const char * refDN, struct berval * baseDN, struct berval * targetDN ) { int rc; struct berval bvin; struct berval nrefDN = BER_BVNULL; struct berval nbaseDN = BER_BVNULL; struct berval ntargetDN = BER_BVNULL; if( !baseDN ) { /* no base, return target */ return targetDN ? ch_strdup( targetDN->bv_val ) : NULL; } if( refDN ) { bvin.bv_val = (char *)refDN; bvin.bv_len = strlen( refDN ); rc = dnPretty( NULL, &bvin, &nrefDN, NULL ); if( rc != LDAP_SUCCESS ) { /* Invalid refDN */ return NULL; } } if( !targetDN ) { /* continuation reference * if refDN present return refDN * else return baseDN */ return nrefDN.bv_len ? nrefDN.bv_val : ch_strdup( baseDN->bv_val ); } rc = dnPretty( NULL, targetDN, &ntargetDN, NULL ); if( rc != LDAP_SUCCESS ) { /* Invalid targetDN */ ch_free( nrefDN.bv_val ); return NULL; } if( nrefDN.bv_len ) { rc = dnPretty( NULL, baseDN, &nbaseDN, NULL ); if( rc != LDAP_SUCCESS ) { /* Invalid baseDN */ ch_free( nrefDN.bv_val ); ch_free( ntargetDN.bv_val ); return NULL; } if( dn_match( &nbaseDN, &nrefDN ) ) { ch_free( nrefDN.bv_val ); ch_free( nbaseDN.bv_val ); return ntargetDN.bv_val; } { struct berval muck; if( ntargetDN.bv_len < nbaseDN.bv_len ) { ch_free( nrefDN.bv_val ); ch_free( nbaseDN.bv_val ); return ntargetDN.bv_val; } rc = strcasecmp( &ntargetDN.bv_val[ntargetDN.bv_len-nbaseDN.bv_len], nbaseDN.bv_val ); if( rc ) { /* target not subordinate to base */ ch_free( nrefDN.bv_val ); ch_free( nbaseDN.bv_val ); return ntargetDN.bv_val; } muck.bv_len = ntargetDN.bv_len + nrefDN.bv_len - nbaseDN.bv_len; muck.bv_val = ch_malloc( muck.bv_len + 1 ); strncpy( muck.bv_val, ntargetDN.bv_val, ntargetDN.bv_len-nbaseDN.bv_len ); strcpy( &muck.bv_val[ntargetDN.bv_len-nbaseDN.bv_len], nrefDN.bv_val ); ch_free( nrefDN.bv_val ); ch_free( nbaseDN.bv_val ); ch_free( ntargetDN.bv_val ); return muck.bv_val; } } ch_free( nrefDN.bv_val ); return ntargetDN.bv_val; }
static int retcode_op_func( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; retcode_t *rd = (retcode_t *)on->on_bi.bi_private; retcode_item_t *rdi; struct berval nrdn, npdn; slap_callback *cb = NULL; /* sleep as required */ retcode_sleep( rd->rd_sleep ); if ( !dnIsSuffix( &op->o_req_ndn, &rd->rd_npdn ) ) { if ( RETCODE_INDIR( rd ) ) { switch ( op->o_tag ) { case LDAP_REQ_ADD: return retcode_op_add( op, rs ); case LDAP_REQ_BIND: /* skip if rootdn */ /* FIXME: better give the db a chance? */ if ( be_isroot_pw( op ) ) { return LDAP_SUCCESS; } return retcode_op_internal( op, rs ); case LDAP_REQ_SEARCH: if ( op->ors_scope == LDAP_SCOPE_BASE ) { rs->sr_err = retcode_op_internal( op, rs ); switch ( rs->sr_err ) { case SLAP_CB_CONTINUE: if ( rs->sr_nentries == 0 ) { break; } rs->sr_err = LDAP_SUCCESS; /* fallthru */ default: send_ldap_result( op, rs ); break; } return rs->sr_err; } break; case LDAP_REQ_MODIFY: case LDAP_REQ_DELETE: case LDAP_REQ_MODRDN: case LDAP_REQ_COMPARE: return retcode_op_internal( op, rs ); } } return SLAP_CB_CONTINUE; } if ( op->o_tag == LDAP_REQ_SEARCH && op->ors_scope != LDAP_SCOPE_BASE && op->o_req_ndn.bv_len == rd->rd_npdn.bv_len ) { return retcode_send_onelevel( op, rs ); } dnParent( &op->o_req_ndn, &npdn ); if ( npdn.bv_len != rd->rd_npdn.bv_len ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_matched = rd->rd_pdn.bv_val; send_ldap_result( op, rs ); rs->sr_matched = NULL; return rs->sr_err; } dnRdn( &op->o_req_ndn, &nrdn ); for ( rdi = rd->rd_item; rdi != NULL; rdi = rdi->rdi_next ) { struct berval rdi_nrdn; dnRdn( &rdi->rdi_ndn, &rdi_nrdn ); if ( dn_match( &nrdn, &rdi_nrdn ) ) { break; } } if ( rdi != NULL && rdi->rdi_mask != SN_DG_OP_ALL ) { retcode_op_e o_tag = SN_DG_OP_NONE; switch ( op->o_tag ) { case LDAP_REQ_ADD: o_tag = SN_DG_OP_ADD; break; case LDAP_REQ_BIND: o_tag = SN_DG_OP_BIND; break; case LDAP_REQ_COMPARE: o_tag = SN_DG_OP_COMPARE; break; case LDAP_REQ_DELETE: o_tag = SN_DG_OP_DELETE; break; case LDAP_REQ_MODIFY: o_tag = SN_DG_OP_MODIFY; break; case LDAP_REQ_MODRDN: o_tag = SN_DG_OP_RENAME; break; case LDAP_REQ_SEARCH: o_tag = SN_DG_OP_SEARCH; break; case LDAP_REQ_EXTENDED: o_tag = SN_DG_EXTENDED; break; default: /* Should not happen */ break; } if ( !( o_tag & rdi->rdi_mask ) ) { return SLAP_CB_CONTINUE; } } if ( rdi == NULL ) { rs->sr_matched = rd->rd_pdn.bv_val; rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = "retcode not found"; } else { if ( rdi->rdi_flags & RDI_PRE_DISCONNECT ) { return rs->sr_err = SLAPD_DISCONNECT; } rs->sr_err = rdi->rdi_err; rs->sr_text = rdi->rdi_text.bv_val; rs->sr_matched = rdi->rdi_matched.bv_val; /* FIXME: we only honor the rdi_ref field in case rdi_err * is LDAP_REFERRAL otherwise send_ldap_result() bails out */ if ( rs->sr_err == LDAP_REFERRAL ) { BerVarray ref; if ( rdi->rdi_ref != NULL ) { ref = rdi->rdi_ref; } else { ref = default_referral; } if ( ref != NULL ) { rs->sr_ref = referral_rewrite( ref, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); } else { rs->sr_err = LDAP_OTHER; rs->sr_text = "bad referral object"; } } retcode_sleep( rdi->rdi_sleeptime ); } switch ( op->o_tag ) { case LDAP_REQ_EXTENDED: if ( rdi == NULL ) { break; } cb = ( slap_callback * )ch_malloc( sizeof( slap_callback ) ); memset( cb, 0, sizeof( slap_callback ) ); cb->sc_cleanup = retcode_cleanup_cb; op->o_callback = cb; break; default: if ( rdi && !BER_BVISNULL( &rdi->rdi_unsolicited_oid ) ) { ber_int_t msgid = op->o_msgid; /* RFC 4511 unsolicited response */ op->o_msgid = 0; if ( strcmp( rdi->rdi_unsolicited_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 = rdi->rdi_unsolicited_oid.bv_val; if ( !BER_BVISNULL( &rdi->rdi_unsolicited_data ) ) { rs->sr_rspdata = &rdi->rdi_unsolicited_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 ); } if ( rs->sr_ref != NULL ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } rs->sr_matched = NULL; rs->sr_text = NULL; if ( rdi && rdi->rdi_flags & RDI_POST_DISCONNECT ) { return rs->sr_err = SLAPD_DISCONNECT; } break; } return rs->sr_err; }
int mdb_add(Operation *op, SlapReply *rs ) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; struct berval pdn; Entry *p = NULL, *oe = op->ora_e; char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; AttributeDescription *children = slap_schema.si_ad_children; AttributeDescription *entry = slap_schema.si_ad_entry; MDB_txn *txn = NULL; MDB_cursor *mc = NULL; MDB_cursor *mcd; ID eid, pid = 0; mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo; int subentry; int numads = mdb->mi_numads; int success; LDAPControl **postread_ctrl = NULL; LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; int num_ctrls = 0; #ifdef LDAP_X_TXN int settle = 0; #endif Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(mdb_add) ": %s\n", op->ora_e->e_name.bv_val, 0, 0); #ifdef LDAP_X_TXN if( op->o_txnSpec ) { /* acquire connection lock */ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) { rs->sr_text = "invalid transaction identifier"; rs->sr_err = LDAP_X_TXN_ID_INVALID; goto txnReturn; } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) { settle=1; goto txnReturn; } if( op->o_conn->c_txn_backend == NULL ) { op->o_conn->c_txn_backend = op->o_bd; } else if( op->o_conn->c_txn_backend != op->o_bd ) { rs->sr_text = "transaction cannot span multiple database contexts"; rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS; goto txnReturn; } /* insert operation into transaction */ rs->sr_text = "transaction specified"; rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY; txnReturn: /* release connection lock */ ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); if( !settle ) { send_ldap_result( op, rs ); return rs->sr_err; } } #endif ctrls[num_ctrls] = 0; /* check entry's schema */ rs->sr_err = entry_schema_check( op, op->ora_e, NULL, get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": entry failed schema check: " "%s (%d)\n", rs->sr_text, rs->sr_err, 0 ); goto return_results; } /* begin transaction */ rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi ); rs->sr_text = NULL; if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": txn_begin failed: %s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } txn = moi->moi_txn; /* add opattrs to shadow as well, only missing attrs will actually * be added; helps compatibility with older OL versions */ rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": entry failed op attrs add: " "%s (%d)\n", rs->sr_text, rs->sr_err, 0 ); goto return_results; } if ( get_assert( op ) && ( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE )) { rs->sr_err = LDAP_ASSERTION_FAILED; goto return_results; } subentry = is_entry_subentry( op->ora_e ); /* * Get the parent dn and see if the corresponding entry exists. */ if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) { pdn = slap_empty_bv; } else { dnParent( &op->ora_e->e_nname, &pdn ); } rs->sr_err = mdb_cursor_open( txn, mdb->mi_dn2id, &mcd ); if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": mdb_cursor_open failed (%d)\n", rs->sr_err, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } /* get entry or parent */ rs->sr_err = mdb_dn2entry( op, txn, mcd, &op->ora_e->e_nname, &p, NULL, 1 ); switch( rs->sr_err ) { case 0: rs->sr_err = LDAP_ALREADY_EXISTS; mdb_entry_return( op, p ); p = NULL; goto return_results; case MDB_NOTFOUND: break; case LDAP_BUSY: rs->sr_text = "ldap server busy"; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } if ( !p ) p = (Entry *)&slap_entry_root; if ( !bvmatch( &pdn, &p->e_nname ) ) { rs->sr_matched = ber_strdup_x( p->e_name.bv_val, op->o_tmpmemctx ); if ( p != (Entry *)&slap_entry_root && is_entry_referral( p )) { BerVarray ref = get_entry_referrals( op, p ); rs->sr_ref = referral_rewrite( ref, &p->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); ber_bvarray_free( ref ); } else { rs->sr_ref = NULL; } if ( p != (Entry *)&slap_entry_root ) mdb_entry_return( op, p ); p = NULL; Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": parent " "does not exist\n", 0, 0, 0 ); rs->sr_err = LDAP_REFERRAL; rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; goto return_results; } rs->sr_err = access_allowed( op, p, children, NULL, ACL_WADD, NULL ); if ( ! rs->sr_err ) { if ( p != (Entry *)&slap_entry_root ) mdb_entry_return( op, p ); p = NULL; Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": no write access to parent\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to parent"; goto return_results;; } if ( p != (Entry *)&slap_entry_root ) { if ( is_entry_subentry( p ) ) { mdb_entry_return( op, p ); p = NULL; /* parent is a subentry, don't allow add */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": parent is subentry\n", 0, 0, 0 ); rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; rs->sr_text = "parent is a subentry"; goto return_results;; } if ( is_entry_alias( p ) ) { mdb_entry_return( op, p ); p = NULL; /* parent is an alias, don't allow add */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": parent is alias\n", 0, 0, 0 ); rs->sr_err = LDAP_ALIAS_PROBLEM; rs->sr_text = "parent is an alias"; goto return_results;; } if ( is_entry_referral( p ) ) { BerVarray ref = get_entry_referrals( op, p ); /* parent is a referral, don't allow add */ rs->sr_matched = ber_strdup_x( p->e_name.bv_val, op->o_tmpmemctx ); rs->sr_ref = referral_rewrite( ref, &p->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); ber_bvarray_free( ref ); mdb_entry_return( op, p ); p = NULL; Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": parent is referral\n", 0, 0, 0 ); rs->sr_err = LDAP_REFERRAL; rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; goto return_results; } } if ( subentry ) { /* FIXME: */ /* parent must be an administrative point of the required kind */ } /* free parent */ if ( p != (Entry *)&slap_entry_root ) { pid = p->e_id; if ( p->e_nname.bv_len ) { struct berval ppdn; /* ITS#5326: use parent's DN if differs from provided one */ dnParent( &op->ora_e->e_name, &ppdn ); if ( !dn_match( &p->e_name, &ppdn ) ) { struct berval rdn; struct berval newdn; dnRdn( &op->ora_e->e_name, &rdn ); build_new_dn( &newdn, &p->e_name, &rdn, NULL ); if ( op->ora_e->e_name.bv_val != op->o_req_dn.bv_val ) ber_memfree( op->ora_e->e_name.bv_val ); op->ora_e->e_name = newdn; /* FIXME: should check whether * dnNormalize(newdn) == e->e_nname ... */ } } mdb_entry_return( op, p ); } p = NULL; rs->sr_err = access_allowed( op, op->ora_e, entry, NULL, ACL_WADD, NULL ); if ( ! rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": no write access to entry\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to entry"; goto return_results;; } /* * Check ACL for attribute write access */ if (!acl_check_modlist(op, oe, op->ora_modlist)) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": no write access to attribute\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to attribute"; goto return_results;; } rs->sr_err = mdb_cursor_open( txn, mdb->mi_id2entry, &mc ); if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": mdb_cursor_open failed (%d)\n", rs->sr_err, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } rs->sr_err = mdb_next_id( op->o_bd, mc, &eid ); if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": next_id failed (%d)\n", rs->sr_err, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } op->ora_e->e_id = eid; /* dn2id index */ rs->sr_err = mdb_dn2id_add( op, mcd, mcd, pid, 1, 1, op->ora_e ); mdb_cursor_close( mcd ); if ( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": dn2id_add failed: %s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 ); switch( rs->sr_err ) { case MDB_KEYEXIST: rs->sr_err = LDAP_ALREADY_EXISTS; break; default: rs->sr_err = LDAP_OTHER; } goto return_results; } /* attribute indexes */ rs->sr_err = mdb_index_entry_add( op, txn, op->ora_e ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": index_entry_add failed\n", 0, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "index generation failed"; goto return_results; } /* id2entry index */ rs->sr_err = mdb_id2entry_add( op, txn, mc, op->ora_e ); if ( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": id2entry_add failed\n", 0, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "entry store failed"; goto return_results; } /* post-read */ if( op->o_postread ) { if( postread_ctrl == NULL ) { postread_ctrl = &ctrls[num_ctrls++]; ctrls[num_ctrls] = NULL; } if ( slap_read_controls( op, rs, op->ora_e, &slap_post_read_bv, postread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(mdb_add) ": post-read " "failed!\n", 0, 0, 0 ); if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ goto return_results; } } } if ( moi == &opinfo ) { LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next ); opinfo.moi_oe.oe_key = NULL; if ( op->o_noop ) { mdb->mi_numads = numads; mdb_txn_abort( txn ); rs->sr_err = LDAP_X_NO_OPERATION; txn = NULL; goto return_results; } rs->sr_err = mdb_txn_commit( txn ); txn = NULL; if ( rs->sr_err != 0 ) { mdb->mi_numads = numads; rs->sr_text = "txn_commit failed"; Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_add) ": %s : %s (%d)\n", rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err ); rs->sr_err = LDAP_OTHER; goto return_results; } } Debug(LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_add) ": added%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no-op)" : "", op->ora_e->e_id, op->ora_e->e_dn ); rs->sr_text = NULL; if( num_ctrls ) rs->sr_ctrls = ctrls; return_results: success = rs->sr_err; send_ldap_result( op, rs ); if( moi == &opinfo ) { if( txn != NULL ) { mdb->mi_numads = numads; mdb_txn_abort( txn ); } if ( opinfo.moi_oe.oe_key ) { LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next ); } } else { moi->moi_ref--; } if( success == LDAP_SUCCESS ) { #if 0 if ( mdb->bi_txn_cp_kbyte ) { TXN_CHECKPOINT( mdb->bi_dbenv, mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 ); } #endif } slap_graduate_commit_csn( op ); if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); } return rs->sr_err; }
static int monitor_subsys_time_update( Operation *op, SlapReply *rs, Entry *e ) { monitor_info_t *mi = ( monitor_info_t * )op->o_bd->be_private; static struct berval bv_current = BER_BVC( "cn=current" ), bv_uptime = BER_BVC( "cn=uptime" ); struct berval rdn; assert( mi != NULL ); assert( e != NULL ); dnRdn( &e->e_nname, &rdn ); if ( dn_match( &rdn, &bv_current ) ) { struct tm tm; char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; Attribute *a; ber_len_t len; time_t currtime; currtime = slap_get_time(); ldap_pvt_gmtime( &currtime, &tm ); lutil_gentime( tmbuf, sizeof( tmbuf ), &tm ); len = strlen( tmbuf ); a = attr_find( e->e_attrs, mi->mi_ad_monitorTimestamp ); if ( a == NULL ) { return rs->sr_err = LDAP_OTHER; } assert( len == a->a_vals[ 0 ].bv_len ); AC_MEMCPY( a->a_vals[ 0 ].bv_val, tmbuf, len ); /* FIXME: touch modifyTimestamp? */ } else if ( dn_match( &rdn, &bv_uptime ) ) { Attribute *a; double diff; char buf[ BACKMONITOR_BUFSIZE ]; struct berval bv; a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo ); if ( a == NULL ) { return rs->sr_err = LDAP_OTHER; } diff = difftime( slap_get_time(), starttime ); bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", (unsigned long) diff ); bv.bv_val = buf; ber_bvreplace( &a->a_vals[ 0 ], &bv ); if ( a->a_nvals != a->a_vals ) { ber_bvreplace( &a->a_nvals[ 0 ], &bv ); } /* FIXME: touch modifyTimestamp? */ } return SLAP_CB_CONTINUE; }
int slap_sasl_authorized( Connection *conn, struct berval *authcDN, struct berval *authzDN ) { int rc = LDAP_INAPPROPRIATE_AUTH; /* User binding as anonymous */ if ( authzDN == NULL ) { rc = LDAP_SUCCESS; goto DONE; } #ifdef NEW_LOGGING LDAP_LOG( TRANSPORT, ENTRY, "slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val, 0 ); #else Debug( LDAP_DEBUG_TRACE, "==>slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val, 0 ); #endif /* If person is authorizing to self, succeed */ if ( dn_match( authcDN, authzDN ) ) { rc = LDAP_SUCCESS; goto DONE; } /* Allow the manager to authorize as any DN. */ if( conn->c_authz_backend && be_isroot( conn->c_authz_backend, authcDN )) { rc = LDAP_SUCCESS; goto DONE; } /* Check source rules */ if( authz_policy & SASL_AUTHZ_TO ) { rc = slap_sasl_check_authz( conn, authcDN, authzDN, slap_schema.si_ad_saslAuthzTo, authcDN ); if( rc == LDAP_SUCCESS ) { goto DONE; } } /* Check destination rules */ if( authz_policy & SASL_AUTHZ_FROM ) { rc = slap_sasl_check_authz( conn, authzDN, authcDN, slap_schema.si_ad_saslAuthzFrom, authcDN ); if( rc == LDAP_SUCCESS ) { goto DONE; } } rc = LDAP_INAPPROPRIATE_AUTH; DONE: #ifdef NEW_LOGGING LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 ); #else Debug( LDAP_DEBUG_TRACE, "<== slap_sasl_authorized: return %d\n", rc, 0, 0 ); #endif return( rc ); }
static int pg_dynacl_mask( void *priv, Operation *op, Entry *target, AttributeDescription *desc, struct berval *val, int nmatch, regmatch_t *matches, slap_access_t *grant, slap_access_t *deny ) { pg_t *pg = (pg_t *)priv; Entry *group = NULL, *user = NULL; int rc; Backend *be = op->o_bd, *group_be = NULL, *user_be = NULL; struct berval group_ndn; ACL_INVALIDATE( *deny ); /* get user */ if ( target && dn_match( &target->e_nname, &op->o_ndn ) ) { user = target; rc = LDAP_SUCCESS; } else { user_be = op->o_bd = select_backend( &op->o_ndn, 0 ); if ( op->o_bd == NULL ) { op->o_bd = be; return 0; } rc = be_entry_get_rw( op, &op->o_ndn, pg_posixAccount, pg_uidNumber, 0, &user ); } if ( rc != LDAP_SUCCESS || user == NULL ) { op->o_bd = be; return 0; } /* get target */ if ( pg->pg_style == ACL_STYLE_EXPAND ) { char buf[ 1024 ]; struct berval bv; AclRegexMatches amatches = { 0 }; amatches.dn_count = nmatch; AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) ); bv.bv_len = sizeof( buf ) - 1; bv.bv_val = buf; if ( acl_string_expand( &bv, &pg->pg_pat, &target->e_nname, NULL, &amatches ) ) { goto cleanup; } if ( dnNormalize( 0, NULL, NULL, &bv, &group_ndn, op->o_tmpmemctx ) != LDAP_SUCCESS ) { /* did not expand to a valid dn */ goto cleanup; } } else { group_ndn = pg->pg_pat; } if ( target && dn_match( &target->e_nname, &group_ndn ) ) { group = target; rc = LDAP_SUCCESS; } else { group_be = op->o_bd = select_backend( &group_ndn, 0 ); if ( op->o_bd == NULL ) { goto cleanup; } rc = be_entry_get_rw( op, &group_ndn, pg_posixGroup, pg_memberUid, 0, &group ); } if ( group_ndn.bv_val != pg->pg_pat.bv_val ) { op->o_tmpfree( group_ndn.bv_val, op->o_tmpmemctx ); } if ( rc == LDAP_SUCCESS && group != NULL ) { Attribute *a_uid, *a_member; a_uid = attr_find( user->e_attrs, pg_uidNumber ); if ( !a_uid || !BER_BVISNULL( &a_uid->a_nvals[ 1 ] ) ) { rc = LDAP_NO_SUCH_ATTRIBUTE; } else { a_member = attr_find( group->e_attrs, pg_memberUid ); if ( !a_member ) { rc = LDAP_NO_SUCH_ATTRIBUTE; } else { rc = value_find_ex( pg_memberUid, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, a_member->a_nvals, &a_uid->a_nvals[ 0 ], op->o_tmpmemctx ); } } } else { rc = LDAP_NO_SUCH_OBJECT; } if ( rc == LDAP_SUCCESS ) { ACL_LVL_ASSIGN_WRITE( *grant ); } cleanup:; if ( group != NULL && group != target ) { op->o_bd = group_be; be_entry_release_r( op, group ); op->o_bd = be; } if ( user != NULL && user != target ) { op->o_bd = user_be; be_entry_release_r( op, user ); op->o_bd = be; } return 0; }
static int autoca_op_response( Operation *op, SlapReply *rs ) { slap_overinst *on = op->o_callback->sc_private; autoca_info *ai = on->on_bi.bi_private; Attribute *a; int isusr = 0; if (rs->sr_type != REP_SEARCH) return SLAP_CB_CONTINUE; /* If root or self */ if ( !be_isroot( op ) && !dn_match( &rs->sr_entry->e_nname, &op->o_ndn )) return SLAP_CB_CONTINUE; isusr = is_entry_objectclass( rs->sr_entry, ai->ai_usrclass, SLAP_OCF_CHECK_SUP ); if ( !isusr ) { if (!is_entry_objectclass( rs->sr_entry, ai->ai_srvclass, SLAP_OCF_CHECK_SUP )) return SLAP_CB_CONTINUE; } a = attr_find( rs->sr_entry->e_attrs, ad_usrPkey ); if ( !a ) { Operation op2; genargs args; saveargs arg2; myext extras[2]; int rc; args.issuer_cert = ai->ai_cert; args.issuer_pkey = ai->ai_pkey; args.subjectDN = &rs->sr_entry->e_name; args.more_exts = NULL; if ( isusr ) { args.cert_exts = usrExts; args.keybits = ai->ai_usrkeybits; args.days = ai->ai_usrdays; a = attr_find( rs->sr_entry->e_attrs, ad_mail ); if ( a ) { extras[0].name = "subjectAltName"; extras[1].name = NULL; extras[0].value = op->o_tmpalloc( sizeof("email:") + a->a_vals[0].bv_len, op->o_tmpmemctx ); sprintf(extras[0].value, "email:%s", a->a_vals[0].bv_val); args.more_exts = extras; } } else { args.cert_exts = srvExts; args.keybits = ai->ai_srvkeybits; args.days = ai->ai_srvdays; if ( ad_ipaddr && (a = attr_find( rs->sr_entry->e_attrs, ad_ipaddr ))) { extras[0].name = "subjectAltName"; extras[1].name = NULL; extras[0].value = op->o_tmpalloc( sizeof("IP:") + a->a_vals[0].bv_len, op->o_tmpmemctx ); sprintf(extras[0].value, "IP:%s", a->a_vals[0].bv_val); args.more_exts = extras; } } rc = autoca_gencert( op, &args ); if ( rc ) return SLAP_CB_CONTINUE; X509_free( args.newcert ); EVP_PKEY_free( args.newpkey ); if ( is_entry_objectclass( rs->sr_entry, oc_usrObj, 0 )) arg2.oc = NULL; else arg2.oc = oc_usrObj; if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE )) { Entry *e = entry_dup( rs->sr_entry ); rs_replace_entry( op, rs, on, e ); rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; } arg2.dercert = &args.dercert; arg2.derpkey = &args.derpkey; arg2.on = on; arg2.dn = &rs->sr_entry->e_name; arg2.ndn = &rs->sr_entry->e_nname; arg2.isca = 0; op2 = *op; rc = autoca_savecert( &op2, &arg2 ); if ( !rc ) { /* If this is our cert DN, configure it */ if ( dn_match( &rs->sr_entry->e_nname, &ai->ai_localndn )) autoca_setlocal( &op2, &args.dercert, &args.derpkey ); attr_merge_one( rs->sr_entry, ad_usrCert, &args.dercert, NULL ); attr_merge_one( rs->sr_entry, ad_usrPkey, &args.derpkey, NULL ); } op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx ); op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx ); } return SLAP_CB_CONTINUE; }
int backsql_modrdn( Operation *op, SlapReply *rs ) { backsql_info *bi = (backsql_info*)op->o_bd->be_private; SQLHDBC dbh = SQL_NULL_HDBC; SQLHSTMT sth = SQL_NULL_HSTMT; RETCODE rc; backsql_entryID e_id = BACKSQL_ENTRYID_INIT, n_id = BACKSQL_ENTRYID_INIT; backsql_srch_info bsi = { 0 }; backsql_oc_map_rec *oc = NULL; struct berval pdn = BER_BVNULL, pndn = BER_BVNULL, *new_pdn = NULL, *new_npdn = NULL, new_dn = BER_BVNULL, new_ndn = BER_BVNULL, realnew_dn = BER_BVNULL; Entry r = { 0 }, p = { 0 }, n = { 0 }, *e = NULL; int manageDSAit = get_manageDSAit( op ); struct berval *newSuperior = op->oq_modrdn.rs_newSup; Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry \"%s\", " "newrdn=\"%s\", newSuperior=\"%s\"\n", op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val, newSuperior ? newSuperior->bv_val : "(NULL)" ); rs->sr_err = backsql_get_db_conn( op, &dbh ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "could not get connection handle - exiting\n" ); rs->sr_text = ( rs->sr_err == LDAP_OTHER ) ? "SQL-backend error" : NULL; e = NULL; goto done; } bsi.bsi_e = &r; rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_all_attributes, ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) ); switch ( rs->sr_err ) { case LDAP_SUCCESS: break; case LDAP_REFERRAL: if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) { rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; rs->sr_matched = NULL; if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } break; } e = &r; /* fallthru */ default: Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " "could not retrieve modrdnDN ID - no such entry\n" ); if ( !BER_BVISNULL( &r.e_nname ) ) { /* FIXME: should always be true! */ e = &r; } else { e = NULL; } goto done; } Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=" BACKSQL_IDFMT "\n", BACKSQL_IDARG(e_id.eid_id) ); if ( get_assert( op ) && ( test_filter( op, &r, get_assertion( op ) ) != LDAP_COMPARE_TRUE ) ) { rs->sr_err = LDAP_ASSERTION_FAILED; e = &r; goto done; } if ( backsql_has_children( op, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "entry \"%s\" has children\n", op->o_req_dn.bv_val ); rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; rs->sr_text = "subtree rename not supported"; e = &r; goto done; } /* * Check for entry access to target */ if ( !access_allowed( op, &r, slap_schema.si_ad_entry, NULL, ACL_WRITE, NULL ) ) { Debug( LDAP_DEBUG_TRACE, " no access to entry\n" ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto done; } dnParent( &op->o_req_dn, &pdn ); dnParent( &op->o_req_ndn, &pndn ); /* * namingContext "" is not supported */ if ( BER_BVISEMPTY( &pdn ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "parent is \"\" - aborting\n" ); rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "not allowed within namingContext"; e = NULL; goto done; } /* * Check for children access to parent */ bsi.bsi_e = &p; e_id = bsi.bsi_base_id; memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); rs->sr_err = backsql_init_search( &bsi, &pndn, LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_all_attributes, BACKSQL_ISF_GET_ENTRY ); Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): old parent entry id is " BACKSQL_IDFMT "\n", BACKSQL_IDARG(bsi.bsi_base_id.eid_id) ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " "could not retrieve renameDN ID - no such entry\n" ); e = &p; goto done; } if ( !access_allowed( op, &p, slap_schema.si_ad_children, NULL, newSuperior ? ACL_WDEL : ACL_WRITE, NULL ) ) { Debug( LDAP_DEBUG_TRACE, " no access to parent\n" ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto done; } if ( newSuperior ) { (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); /* * namingContext "" is not supported */ if ( BER_BVISEMPTY( newSuperior ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "newSuperior is \"\" - aborting\n" ); rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "not allowed within namingContext"; e = NULL; goto done; } new_pdn = newSuperior; new_npdn = op->oq_modrdn.rs_nnewSup; /* * Check for children access to new parent */ bsi.bsi_e = &n; rs->sr_err = backsql_init_search( &bsi, new_npdn, LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_all_attributes, ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " "could not retrieve renameDN ID - no such entry\n" ); e = &n; goto done; } n_id = bsi.bsi_base_id; Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new parent entry id=" BACKSQL_IDFMT "\n", BACKSQL_IDARG(n_id.eid_id) ); if ( !access_allowed( op, &n, slap_schema.si_ad_children, NULL, ACL_WADD, NULL ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "no access to new parent \"%s\"\n", new_pdn->bv_val ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; e = &n; goto done; } } else { n_id = bsi.bsi_base_id; new_pdn = &pdn; new_npdn = &pndn; } memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); if ( newSuperior && dn_match( &pndn, new_npdn ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "newSuperior is equal to old parent - ignored\n" ); newSuperior = NULL; } if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "newSuperior is equal to entry being moved " "- aborting\n" ); rs->sr_err = LDAP_OTHER; rs->sr_text = "newSuperior is equal to old DN"; e = &r; goto done; } build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn, op->o_tmpmemctx ); build_new_dn( &new_ndn, new_npdn, &op->oq_modrdn.rs_nnewrdn, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n", new_dn.bv_val ); realnew_dn = new_dn; if ( backsql_api_dn2odbc( op, rs, &realnew_dn ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): " "backsql_api_dn2odbc(\"%s\") failed\n", op->o_req_dn.bv_val, realnew_dn.bv_val ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; e = NULL; goto done; } Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "executing renentry_stmt\n" ); rc = backsql_Prepare( dbh, &sth, bi->sql_renentry_stmt, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "error preparing renentry_stmt\n" ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; e = NULL; goto done; } rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realnew_dn ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "error binding DN parameter for objectClass %s\n", oc->bom_oc->soc_cname.bv_val ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; e = NULL; goto done; } rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT, &n_id.eid_id ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "error binding parent ID parameter for objectClass %s\n", oc->bom_oc->soc_cname.bv_val ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; e = NULL; goto done; } rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &e_id.eid_keyval ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "error binding entry ID parameter for objectClass %s\n", oc->bom_oc->soc_cname.bv_val ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; e = NULL; goto done; } rc = backsql_BindParamID( sth, 4, SQL_PARAM_INPUT, &e_id.eid_id ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "error binding ID parameter for objectClass %s\n", oc->bom_oc->soc_cname.bv_val ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; e = NULL; goto done; } rc = SQLExecute( sth ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "could not rename ldap_entries record\n" ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; e = NULL; goto done; } SQLFreeStmt( sth, SQL_DROP ); assert( op->orr_modlist != NULL ); slap_mods_opattrs( op, &op->orr_modlist, 1 ); assert( e_id.eid_oc != NULL ); oc = e_id.eid_oc; rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, op->orr_modlist ); slap_graduate_commit_csn( op ); if ( rs->sr_err != LDAP_SUCCESS ) { e = &r; goto done; } if ( BACKSQL_CHECK_SCHEMA( bi ) ) { char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; backsql_entry_clean( op, &r ); (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); bsi.bsi_e = &r; rs->sr_err = backsql_init_search( &bsi, &new_ndn, LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_all_attributes, ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); switch ( rs->sr_err ) { case LDAP_SUCCESS: break; case LDAP_REFERRAL: if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && dn_match( &new_ndn, &bsi.bsi_e->e_nname ) ) { rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; rs->sr_matched = NULL; if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } break; } e = &r; /* fallthru */ default: Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " "could not retrieve modrdnDN ID - no such entry\n" ); if ( !BER_BVISNULL( &r.e_nname ) ) { /* FIXME: should always be true! */ e = &r; } else { e = NULL; } goto done; } e_id = bsi.bsi_base_id; rs->sr_err = entry_schema_check( op, &r, NULL, 0, 0, NULL, &rs->sr_text, textbuf, sizeof( textbuf ) ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): " "entry failed schema check -- aborting\n", r.e_name.bv_val ); e = NULL; goto done; } } done:; if ( e != NULL ) { if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = NULL; rs->sr_matched = NULL; if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } } } /* * Commit only if all operations succeed */ if ( sth != SQL_NULL_HSTMT ) { SQLUSMALLINT CompletionType = SQL_ROLLBACK; if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { CompletionType = SQL_COMMIT; } SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); } if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { rs->sr_err = LDAP_X_NO_OPERATION; } send_ldap_result( op, rs ); slap_graduate_commit_csn( op ); if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) { ch_free( realnew_dn.bv_val ); } if ( !BER_BVISNULL( &new_dn ) ) { slap_sl_free( new_dn.bv_val, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &new_ndn ) ) { slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &e_id.eid_ndn ) ) { (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &n_id.eid_ndn ) ) { (void)backsql_free_entryID( &n_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &r.e_nname ) ) { backsql_entry_clean( op, &r ); } if ( !BER_BVISNULL( &p.e_nname ) ) { backsql_entry_clean( op, &p ); } if ( !BER_BVISNULL( &n.e_nname ) ) { backsql_entry_clean( op, &n ); } if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n" ); return rs->sr_err; }
int backsql_modify( Operation *op, SlapReply *rs ) { backsql_info *bi = (backsql_info*)op->o_bd->be_private; SQLHDBC dbh = SQL_NULL_HDBC; backsql_oc_map_rec *oc = NULL; backsql_srch_info bsi = { 0 }; Entry m = { 0 }, *e = NULL; int manageDSAit = get_manageDSAit( op ); SQLUSMALLINT CompletionType = SQL_ROLLBACK; /* * FIXME: in case part of the operation cannot be performed * (missing mapping, SQL write fails or so) the entire operation * should be rolled-back */ Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): modifying entry \"%s\"\n", op->o_req_ndn.bv_val, 0, 0 ); rs->sr_err = backsql_get_db_conn( op, &dbh ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modify(): " "could not get connection handle - exiting\n", 0, 0, 0 ); /* * FIXME: we don't want to send back * excessively detailed messages */ rs->sr_text = ( rs->sr_err == LDAP_OTHER ) ? "SQL-backend error" : NULL; goto done; } bsi.bsi_e = &m; rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_all_attributes, ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) ); switch ( rs->sr_err ) { case LDAP_SUCCESS: break; case LDAP_REFERRAL: if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) { rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; rs->sr_matched = NULL; if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } break; } e = &m; /* fallthru */ default: Debug( LDAP_DEBUG_TRACE, "backsql_modify(): " "could not retrieve modifyDN ID - no such entry\n", 0, 0, 0 ); if ( !BER_BVISNULL( &m.e_nname ) ) { /* FIXME: should always be true! */ e = &m; } else { e = NULL; } goto done; } #ifdef BACKSQL_ARBITRARY_KEY Debug( LDAP_DEBUG_TRACE, " backsql_modify(): " "modifying entry \"%s\" (id=%s)\n", bsi.bsi_base_id.eid_dn.bv_val, bsi.bsi_base_id.eid_id.bv_val, 0 ); #else /* ! BACKSQL_ARBITRARY_KEY */ Debug( LDAP_DEBUG_TRACE, " backsql_modify(): " "modifying entry \"%s\" (id=%ld)\n", bsi.bsi_base_id.eid_dn.bv_val, bsi.bsi_base_id.eid_id, 0 ); #endif /* ! BACKSQL_ARBITRARY_KEY */ if ( get_assert( op ) && ( test_filter( op, &m, get_assertion( op ) ) != LDAP_COMPARE_TRUE )) { rs->sr_err = LDAP_ASSERTION_FAILED; e = &m; goto done; } slap_mods_opattrs( op, &op->orm_modlist, 1 ); assert( bsi.bsi_base_id.eid_oc != NULL ); oc = bsi.bsi_base_id.eid_oc; if ( !acl_check_modlist( op, &m, op->orm_modlist ) ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; e = &m; goto done; } rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &bsi.bsi_base_id, op->orm_modlist ); if ( rs->sr_err != LDAP_SUCCESS ) { e = &m; goto do_transact; } if ( BACKSQL_CHECK_SCHEMA( bi ) ) { char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; backsql_entry_clean( op, &m ); bsi.bsi_e = &m; rs->sr_err = backsql_id2entry( &bsi, &bsi.bsi_base_id ); if ( rs->sr_err != LDAP_SUCCESS ) { e = &m; goto do_transact; } rs->sr_err = entry_schema_check( op, &m, NULL, 0, 0, NULL, &rs->sr_text, textbuf, sizeof( textbuf ) ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modify(\"%s\"): " "entry failed schema check -- aborting\n", m.e_name.bv_val, 0, 0 ); e = NULL; goto do_transact; } } do_transact:; /* * Commit only if all operations succeed */ if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { assert( e == NULL ); CompletionType = SQL_COMMIT; } SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); done:; if ( e != NULL ) { if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = NULL; rs->sr_matched = NULL; if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } } } if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { rs->sr_err = LDAP_X_NO_OPERATION; } send_ldap_result( op, rs ); slap_graduate_commit_csn( op ); if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &m.e_nname ) ) { backsql_entry_clean( op, &m ); } if ( bsi.bsi_attrs != NULL ) { op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx ); } if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 ); return rs->sr_err; }
/* * meta_back_single_dobind */ int meta_back_single_dobind( Operation *op, SlapReply *rs, metaconn_t **mcp, int candidate, ldap_back_send_t sendok, int nretries, int dolock ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; metaconn_t *mc = *mcp; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; int msgid; assert( !LDAP_BACK_CONN_ISBOUND( msc ) ); /* NOTE: this obsoletes pseudorootdn */ if ( op->o_conn != NULL && !op->o_do_not_cache && ( BER_BVISNULL( &msc->msc_bound_ndn ) || BER_BVISEMPTY( &msc->msc_bound_ndn ) || ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) || ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) { (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok, dolock ); } else { char *binddn = ""; struct berval cred = BER_BVC( "" ); /* use credentials if available */ if ( !BER_BVISNULL( &msc->msc_bound_ndn ) && !BER_BVISNULL( &msc->msc_cred ) ) { binddn = msc->msc_bound_ndn.bv_val; cred = msc->msc_cred; } /* FIXME: should we check if at least some of the op->o_ctrls * can/should be passed? */ if(!dolock) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } for (;;) { rs->sr_err = ldap_sasl_bind( msc->msc_ld, binddn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid ); if ( rs->sr_err != LDAP_X_CONNECTING ) { break; } ldap_pvt_thread_yield(); } if(!dolock) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); } rs->sr_err = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock ); /* if bind succeeded, but anonymous, clear msc_bound_ndn */ if ( rs->sr_err != LDAP_SUCCESS || binddn[0] == '\0' ) { if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { ber_memfree( msc->msc_bound_ndn.bv_val ); BER_BVZERO( &msc->msc_bound_ndn ); } if ( !BER_BVISNULL( &msc->msc_cred ) ) { memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); ber_memfree( msc->msc_cred.bv_val ); BER_BVZERO( &msc->msc_cred ); } } } if ( rs->sr_err != LDAP_SUCCESS ) { if ( dolock ) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); } LDAP_BACK_CONN_BINDING_CLEAR( msc ); if ( META_BACK_ONERR_STOP( mi ) ) { LDAP_BACK_CONN_TAINTED_SET( mc ); meta_back_release_conn_lock( mi, mc, 0 ); *mcp = NULL; } if ( dolock ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } } if ( META_BACK_TGT_QUARANTINE( mt ) ) { meta_back_quarantine( op, rs, candidate ); } return rs->sr_err; }
static int limits_get( Operation *op, struct slap_limits_set **limit ) { static struct berval empty_dn = BER_BVC( "" ); struct slap_limits **lm; struct berval *ndns[2]; assert( op != NULL ); assert( limit != NULL ); ndns[0] = &op->o_ndn; ndns[1] = &op->o_req_ndn; Debug( LDAP_DEBUG_TRACE, "==> limits_get: %s self=\"%s\" this=\"%s\"\n", op->o_log_prefix, BER_BVISNULL( ndns[0] ) ? "[anonymous]" : ndns[0]->bv_val, BER_BVISNULL( ndns[1] ) ? "" : ndns[1]->bv_val ); /* * default values */ *limit = &op->o_bd->be_def_limit; if ( op->o_bd->be_limits == NULL ) { return( 0 ); } for ( lm = op->o_bd->be_limits; lm[0] != NULL; lm++ ) { unsigned style = lm[0]->lm_flags & SLAP_LIMITS_MASK; unsigned type = lm[0]->lm_flags & SLAP_LIMITS_TYPE_MASK; unsigned isthis = type == SLAP_LIMITS_TYPE_THIS; struct berval *ndn = ndns[isthis]; if ( style == SLAP_LIMITS_ANY ) goto found_any; if ( BER_BVISEMPTY( ndn ) ) { if ( style == SLAP_LIMITS_ANONYMOUS ) goto found_nodn; if ( !isthis ) continue; ndn = &empty_dn; } switch ( style ) { case SLAP_LIMITS_EXACT: if ( type == SLAP_LIMITS_TYPE_GROUP ) { int rc = backend_group( op, NULL, &lm[0]->lm_pat, ndn, lm[0]->lm_group_oc, lm[0]->lm_group_ad ); if ( rc == 0 ) { goto found_group; } } else { if ( dn_match( &lm[0]->lm_pat, ndn ) ) { goto found_dn; } } break; case SLAP_LIMITS_ONE: case SLAP_LIMITS_SUBTREE: case SLAP_LIMITS_CHILDREN: { ber_len_t d; /* ndn shorter than lm_pat */ if ( ndn->bv_len < lm[0]->lm_pat.bv_len ) { break; } d = ndn->bv_len - lm[0]->lm_pat.bv_len; if ( d == 0 ) { /* allow exact match for SUBTREE only */ if ( style != SLAP_LIMITS_SUBTREE ) { break; } } else { /* check for unescaped rdn separator */ if ( !DN_SEPARATOR( ndn->bv_val[d - 1] ) ) { break; } } /* check that ndn ends with lm_pat */ if ( strcmp( lm[0]->lm_pat.bv_val, &ndn->bv_val[d] ) != 0 ) { break; } /* in case of ONE, require exactly one rdn below lm_pat */ if ( style == SLAP_LIMITS_ONE ) { if ( dn_rdnlen( NULL, ndn ) != d - 1 ) { break; } } goto found_dn; } case SLAP_LIMITS_REGEX: if ( regexec( &lm[0]->lm_regex, ndn->bv_val, 0, NULL, 0 ) == 0 ) { goto found_dn; } break; case SLAP_LIMITS_ANONYMOUS: break; case SLAP_LIMITS_USERS: found_nodn: Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=%s match=%s\n", dn_source[isthis], limits2str( style ), 0 ); found_any: *limit = &lm[0]->lm_limits; return( 0 ); found_dn: Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=%s match=%s dn=\"%s\"\n", dn_source[isthis], limits2str( style ), lm[0]->lm_pat.bv_val ); *limit = &lm[0]->lm_limits; return( 0 ); found_group: Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=GROUP match=EXACT " "dn=\"%s\" oc=\"%s\" ad=\"%s\"\n", lm[0]->lm_pat.bv_val, lm[0]->lm_group_oc->soc_cname.bv_val, lm[0]->lm_group_ad->ad_cname.bv_val ); *limit = &lm[0]->lm_limits; return( 0 ); default: assert( 0 ); /* unreachable */ return( -1 ); } } return( 0 ); }
int ndb_back_modrdn( Operation *op, SlapReply *rs ) { struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private; AttributeDescription *children = slap_schema.si_ad_children; AttributeDescription *entry = slap_schema.si_ad_entry; struct berval new_dn = BER_BVNULL, new_ndn = BER_BVNULL; Entry e = {0}; Entry e2 = {0}; char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; struct berval *np_dn = NULL; /* newSuperior dn */ struct berval *np_ndn = NULL; /* newSuperior ndn */ int manageDSAit = get_manageDSAit( op ); int num_retries = 0; NdbArgs NA, NA2; NdbRdns rdns, rdn2; struct berval matched; LDAPControl **preread_ctrl = NULL; LDAPControl **postread_ctrl = NULL; LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; int num_ctrls = 0; int rc; Debug( LDAP_DEBUG_ARGS, "==>" LDAP_XSTRING(ndb_back_modrdn) "(%s,%s,%s)\n", op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val, op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" ); ctrls[num_ctrls] = NULL; slap_mods_opattrs( op, &op->orr_modlist, 1 ); e.e_name = op->o_req_dn; e.e_nname = op->o_req_ndn; /* Get our NDB handle */ rs->sr_err = ndb_thread_handle( op, &NA.ndb ); rdns.nr_num = 0; NA.rdns = &rdns; NA.e = &e; NA2.ndb = NA.ndb; NA2.e = &e2; NA2.rdns = &rdn2; if( 0 ) { retry: /* transaction retry */ NA.txn->close(); NA.txn = NULL; if ( e.e_attrs ) { attrs_free( e.e_attrs ); e.e_attrs = NULL; } Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(ndb_back_modrdn) ": retrying...\n", 0, 0, 0 ); if ( op->o_abandon ) { rs->sr_err = SLAPD_ABANDON; goto return_results; } if ( NA2.ocs ) { ber_bvarray_free_x( NA2.ocs, op->o_tmpmemctx ); } if ( NA.ocs ) { ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx ); } ndb_trans_backoff( ++num_retries ); } NA.ocs = NULL; NA2.ocs = NULL; /* begin transaction */ NA.txn = NA.ndb->startTransaction(); rs->sr_text = NULL; if( !NA.txn ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": startTransaction failed: %s (%d)\n", NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } NA2.txn = NA.txn; /* get entry */ rs->sr_err = ndb_entry_get_info( op, &NA, 1, &matched ); switch( rs->sr_err ) { case 0: break; case LDAP_NO_SUCH_OBJECT: Debug( LDAP_DEBUG_ARGS, "<=- ndb_back_modrdn: no such object %s\n", op->o_req_dn.bv_val, 0, 0 ); rs->sr_matched = matched.bv_val; if ( NA.ocs ) ndb_check_referral( op, rs, &NA ); goto return_results; #if 0 case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; #endif case LDAP_BUSY: rs->sr_text = "ldap server busy"; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } /* acquire and lock entry */ rs->sr_err = ndb_entry_get_data( op, &NA, 1 ); if ( rs->sr_err ) goto return_results; if ( !manageDSAit && is_entry_glue( &e )) { rs->sr_err = LDAP_NO_SUCH_OBJECT; goto return_results; } if ( get_assert( op ) && ( test_filter( op, &e, (Filter *)get_assertion( op )) != LDAP_COMPARE_TRUE )) { rs->sr_err = LDAP_ASSERTION_FAILED; goto return_results; } /* check write on old entry */ rs->sr_err = access_allowed( op, &e, entry, NULL, ACL_WRITE, NULL ); if ( ! rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0, 0, 0 ); rs->sr_text = "no write access to old entry"; rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto return_results; } /* Can't do it if we have kids */ rs->sr_err = ndb_has_children( &NA, &rc ); if ( rs->sr_err ) { Debug(LDAP_DEBUG_ARGS, "<=- " LDAP_XSTRING(ndb_back_modrdn) ": has_children failed: %s (%d)\n", NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } if ( rc == LDAP_COMPARE_TRUE ) { Debug(LDAP_DEBUG_ARGS, "<=- " LDAP_XSTRING(ndb_back_modrdn) ": non-leaf %s\n", op->o_req_dn.bv_val, 0, 0); rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; rs->sr_text = "subtree rename not supported"; goto return_results; } if (!manageDSAit && is_entry_referral( &e ) ) { /* entry is a referral, don't allow modrdn */ rs->sr_ref = get_entry_referrals( op, &e ); Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": entry %s is referral\n", e.e_dn, 0, 0 ); rs->sr_err = LDAP_REFERRAL, rs->sr_matched = op->o_req_dn.bv_val; rs->sr_flags = REP_REF_MUSTBEFREED; goto return_results; } if ( be_issuffix( op->o_bd, &e.e_nname ) ) { /* There can only be one suffix entry */ rs->sr_err = LDAP_NAMING_VIOLATION; rs->sr_text = "cannot rename suffix entry"; goto return_results; } else { dnParent( &e.e_nname, &e2.e_nname ); dnParent( &e.e_name, &e2.e_name ); } /* check parent for "children" acl */ rs->sr_err = access_allowed( op, &e2, children, NULL, op->oq_modrdn.rs_newSup == NULL ? ACL_WRITE : ACL_WDEL, NULL ); if ( ! rs->sr_err ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 ); rs->sr_text = "no write access to old parent's children"; goto return_results; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": wr to children " "of entry %s OK\n", e2.e_name.bv_val, 0, 0 ); if ( op->oq_modrdn.rs_newSup != NULL ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": new parent \"%s\" requested...\n", op->oq_modrdn.rs_newSup->bv_val, 0, 0 ); /* newSuperior == oldParent? */ if( dn_match( &e2.e_nname, op->oq_modrdn.rs_nnewSup ) ) { Debug( LDAP_DEBUG_TRACE, "bdb_back_modrdn: " "new parent \"%s\" same as the old parent \"%s\"\n", op->oq_modrdn.rs_newSup->bv_val, e2.e_name.bv_val, 0 ); op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */ } } if ( op->oq_modrdn.rs_newSup != NULL ) { if ( op->oq_modrdn.rs_newSup->bv_len ) { rdn2.nr_num = 0; np_dn = op->oq_modrdn.rs_newSup; np_ndn = op->oq_modrdn.rs_nnewSup; /* newSuperior == oldParent? - checked above */ /* newSuperior == entry being moved?, if so ==> ERROR */ if ( dnIsSuffix( np_ndn, &e.e_nname )) { rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = "new superior not found"; goto return_results; } /* Get Entry with dn=newSuperior. Does newSuperior exist? */ e2.e_name = *np_dn; e2.e_nname = *np_ndn; rs->sr_err = ndb_entry_get_info( op, &NA2, 1, NULL ); switch( rs->sr_err ) { case 0: break; case LDAP_NO_SUCH_OBJECT: Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": newSup(ndn=%s) not here!\n", np_ndn->bv_val, 0, 0); rs->sr_text = "new superior not found"; goto return_results; #if 0 case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; #endif case LDAP_BUSY: rs->sr_text = "ldap server busy"; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } if ( NA2.ocs ) { Attribute a; int i; for ( i=0; !BER_BVISNULL( &NA2.ocs[i] ); i++); a.a_numvals = i; a.a_desc = slap_schema.si_ad_objectClass; a.a_vals = NA2.ocs; a.a_nvals = NA2.ocs; a.a_next = NULL; e2.e_attrs = &a; if ( is_entry_alias( &e2 )) { /* parent is an alias, don't allow move */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": entry is alias\n", 0, 0, 0 ); rs->sr_text = "new superior is an alias"; rs->sr_err = LDAP_ALIAS_PROBLEM; goto return_results; } if ( is_entry_referral( &e2 ) ) { /* parent is a referral, don't allow move */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": entry is referral\n", 0, 0, 0 ); rs->sr_text = "new superior is a referral"; rs->sr_err = LDAP_OTHER; goto return_results; } } } /* check newSuperior for "children" acl */ rs->sr_err = access_allowed( op, &e2, children, NULL, ACL_WADD, NULL ); if( ! rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": no wr to newSup children\n", 0, 0, 0 ); rs->sr_text = "no write access to new superior's children"; rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto return_results; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": wr to new parent OK id=%ld\n", (long) e2.e_id, 0, 0 ); } /* Build target dn and make sure target entry doesn't exist already. */ if (!new_dn.bv_val) { build_new_dn( &new_dn, &e2.e_name, &op->oq_modrdn.rs_newrdn, NULL ); } if (!new_ndn.bv_val) { build_new_dn( &new_ndn, &e2.e_nname, &op->oq_modrdn.rs_nnewrdn, NULL ); } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": new ndn=%s\n", new_ndn.bv_val, 0, 0 ); /* Allow rename to same DN */ if ( !bvmatch ( &new_ndn, &e.e_nname )) { rdn2.nr_num = 0; e2.e_name = new_dn; e2.e_nname = new_ndn; NA2.ocs = &matched; rs->sr_err = ndb_entry_get_info( op, &NA2, 1, NULL ); NA2.ocs = NULL; switch( rs->sr_err ) { #if 0 case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; #endif case LDAP_NO_SUCH_OBJECT: break; case 0: rs->sr_err = LDAP_ALREADY_EXISTS; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } } assert( op->orr_modlist != NULL ); if( op->o_preread ) { if( preread_ctrl == NULL ) { preread_ctrl = &ctrls[num_ctrls++]; ctrls[num_ctrls] = NULL; } if( slap_read_controls( op, rs, &e, &slap_pre_read_bv, preread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(ndb_back_modrdn) ": pre-read failed!\n", 0, 0, 0 ); if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ goto return_results; } } } /* delete old DN */ rs->sr_err = ndb_entry_del_info( op->o_bd, &NA ); if ( rs->sr_err != 0 ) { Debug(LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(ndb_back_modrdn) ": dn2id del failed: %s (%d)\n", NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 ); #if 0 switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } #endif rs->sr_err = LDAP_OTHER; rs->sr_text = "DN index delete fail"; goto return_results; } /* copy entry fields */ e2.e_attrs = e.e_attrs; e2.e_id = e.e_id; /* add new DN */ rs->sr_err = ndb_entry_put_info( op->o_bd, &NA2, 0 ); if ( rs->sr_err != 0 ) { Debug(LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(ndb_back_modrdn) ": dn2id add failed: %s (%d)\n", NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 ); #if 0 switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } #endif rs->sr_err = LDAP_OTHER; rs->sr_text = "DN index add failed"; goto return_results; } /* modify entry */ rs->sr_err = ndb_modify_internal( op, &NA2, &rs->sr_text, textbuf, textlen ); if( rs->sr_err != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(ndb_back_modrdn) ": modify failed: %s (%d)\n", NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 ); #if 0 switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } #endif goto return_results; } e.e_attrs = e2.e_attrs; if( op->o_postread ) { if( postread_ctrl == NULL ) { postread_ctrl = &ctrls[num_ctrls++]; ctrls[num_ctrls] = NULL; } if( slap_read_controls( op, rs, &e2, &slap_post_read_bv, postread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(ndb_back_modrdn) ": post-read failed!\n", 0, 0, 0 ); if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ goto return_results; } } } if( op->o_noop ) { if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback, NdbOperation::AbortOnError, 1 )) != 0 ) { rs->sr_text = "txn_abort (no-op) failed"; } else { rs->sr_err = LDAP_X_NO_OPERATION; } } else { if (( rs->sr_err=NA.txn->execute( NdbTransaction::Commit, NdbOperation::AbortOnError, 1 )) != 0 ) { rs->sr_text = "txn_commit failed"; } else { rs->sr_err = LDAP_SUCCESS; } } if( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": txn_%s failed: %s (%d)\n", op->o_noop ? "abort (no-op)" : "commit", NA.txn->getNdbError().message, NA.txn->getNdbError().code ); rs->sr_err = LDAP_OTHER; goto return_results; } NA.txn->close(); NA.txn = NULL; Debug(LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": rdn modified%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no-op)" : "", e.e_id, op->o_req_dn.bv_val ); rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; if( num_ctrls ) rs->sr_ctrls = ctrls; return_results: if ( NA2.ocs ) { ber_bvarray_free_x( NA2.ocs, op->o_tmpmemctx ); NA2.ocs = NULL; } if ( NA.ocs ) { ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx ); NA.ocs = NULL; } if ( e.e_attrs ) { attrs_free( e.e_attrs ); e.e_attrs = NULL; } if( NA.txn != NULL ) { NA.txn->execute( Rollback ); NA.txn->close(); } send_ldap_result( op, rs ); slap_graduate_commit_csn( op ); if( new_dn.bv_val != NULL ) free( new_dn.bv_val ); if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val ); if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) { slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); slap_sl_free( *preread_ctrl, op->o_tmpmemctx ); } if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); } rs->sr_text = NULL; return rs->sr_err; }
/* return 0 IFF op_dn is a value in group_at (member) attribute * of entry with gr_dn AND that entry has an objectClass * value of group_oc (groupOfNames) */ int ldap_back_group( Backend *be, Connection *conn, Operation *op, Entry *target, struct berval *gr_ndn, struct berval *op_ndn, ObjectClass *group_oc, AttributeDescription* group_at ) { struct ldapinfo *li = (struct ldapinfo *) be->be_private; int rc = 1; Attribute *attr; LDAPMessage *result; char *gattr[2]; char *filter = NULL, *ptr; LDAP *ld; struct berval mop_ndn = { 0, NULL }, mgr_ndn = { 0, NULL }; AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; struct berval group_oc_name = {0, NULL}; struct berval group_at_name = group_at->ad_cname; if( group_oc->soc_names && group_oc->soc_names[0] ) { group_oc_name.bv_val = group_oc->soc_names[0]; } else { group_oc_name.bv_val = group_oc->soc_oid; } if (group_oc_name.bv_val) group_oc_name.bv_len = strlen(group_oc_name.bv_val); if (target != NULL && dn_match( &target->e_nname, gr_ndn ) ) { /* we already have a copy of the entry */ /* attribute and objectclass mapping has already been done */ /* * first we need to check if the objectClass attribute * has been retieved; otherwise we need to repeat the search */ attr = attr_find( target->e_attrs, ad_objectClass ); if ( attr != NULL ) { /* * Now we can check for the group objectClass value */ if( !is_entry_objectclass( target, group_oc, 0 ) ) { return(1); } /* * This part has been reworked: the group attr compare * fails only if the attribute is PRESENT but the value * is NOT PRESENT; if the attribute is NOT PRESENT, the * search must be repeated as well. * This may happen if a search for an entry has already * been performed (target is not null) but the group * attribute has not been required */ if ((attr = attr_find(target->e_attrs, group_at)) != NULL) { if( value_find_ex( group_at, SLAP_MR_VALUE_NORMALIZED_MATCH, attr->a_vals, op_ndn ) != LDAP_SUCCESS ) return(1); return(0); } /* else: repeat the search */ } /* else: repeat the search */ } /* else: do the search */ /* * Rewrite the op ndn if needed */ #ifdef ENABLE_REWRITE switch ( rewrite_session( li->rwinfo, "bindDn", op_ndn->bv_val, conn, &mop_ndn.bv_val ) ) { case REWRITE_REGEXEC_OK: if ( mop_ndn.bv_val == NULL ) { mop_ndn = *op_ndn; } #ifdef NEW_LOGGING LDAP_LOG( BACK_LDAP, DETAIL1, "[rw] bindDn (op ndn in group): \"%s\" -> \"%s\"\n", op_ndn->bv_val, mop_ndn.bv_val, 0 ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "rw> bindDn (op ndn in group): \"%s\" -> \"%s\"\n%s", op_ndn->bv_val, mop_ndn.bv_val, "" ); #endif /* !NEW_LOGGING */ break; case REWRITE_REGEXEC_UNWILLING: case REWRITE_REGEXEC_ERR: goto cleanup; } /* * Rewrite the gr ndn if needed */ switch ( rewrite_session( li->rwinfo, "searchBase", gr_ndn->bv_val, conn, &mgr_ndn.bv_val ) ) { case REWRITE_REGEXEC_OK: if ( mgr_ndn.bv_val == NULL ) { mgr_ndn = *gr_ndn; } #ifdef NEW_LOGGING LDAP_LOG( BACK_LDAP, DETAIL1, "[rw] searchBase (gr ndn in group): \"%s\" -> \"%s\"\n%s", gr_ndn->bv_val, mgr_ndn.bv_val, "" ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_ARGS, "rw> searchBase (gr ndn in group):" " \"%s\" -> \"%s\"\n%s", gr_ndn->bv_val, mgr_ndn.bv_val, "" ); #endif /* !NEW_LOGGING */ break; case REWRITE_REGEXEC_UNWILLING: case REWRITE_REGEXEC_ERR: goto cleanup; } #else /* !ENABLE_REWRITE */ ldap_back_dn_massage( li, op_ndn, &mop_ndn, 1, 1 ); if ( mop_ndn.bv_val == NULL ) { goto cleanup; } ldap_back_dn_massage( li, gr_ndn, &mgr_ndn, 1, 1 ); if ( mgr_ndn.bv_val == NULL ) { goto cleanup; } #endif /* !ENABLE_REWRITE */ ldap_back_map(&li->oc_map, &group_oc_name, &group_oc_name, BACKLDAP_MAP); if (group_oc_name.bv_val == NULL || group_oc_name.bv_val[0] == '\0') goto cleanup; ldap_back_map(&li->at_map, &group_at_name, &group_at_name, BACKLDAP_MAP); if (group_at_name.bv_val == NULL || group_at_name.bv_val[0] == '\0') goto cleanup; filter = ch_malloc(sizeof("(&(objectclass=)(=))") + group_oc_name.bv_len + group_at_name.bv_len + mop_ndn.bv_len + 1); if (filter == NULL) goto cleanup; if (ldap_initialize(&ld, li->url) != LDAP_SUCCESS) { goto cleanup; } if (ldap_bind_s(ld, li->binddn, li->bindpw, LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) { goto cleanup; } ptr = lutil_strcopy(filter, "(&(objectclass="); ptr = lutil_strcopy(ptr, group_oc_name.bv_val); ptr = lutil_strcopy(ptr, ")("); ptr = lutil_strcopy(ptr, group_at_name.bv_val); ptr = lutil_strcopy(ptr, "="); ptr = lutil_strcopy(ptr, mop_ndn.bv_val); strcpy(ptr, "))"); gattr[0] = "objectclass"; gattr[1] = NULL; if (ldap_search_ext_s(ld, mgr_ndn.bv_val, LDAP_SCOPE_BASE, filter, gattr, 0, NULL, NULL, LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result) == LDAP_SUCCESS) { if (ldap_first_entry(ld, result) != NULL) rc = 0; ldap_msgfree(result); } cleanup:; if ( ld != NULL ) { ldap_unbind(ld); } ch_free(filter); if ( mop_ndn.bv_val != op_ndn->bv_val ) { free( mop_ndn.bv_val ); } if ( mgr_ndn.bv_val != gr_ndn->bv_val ) { free( mgr_ndn.bv_val ); } return(rc); }
static int auditlog_response(Operation *op, SlapReply *rs) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; auditlog_data *ad = on->on_bi.bi_private; FILE *f; Attribute *a; Modifications *m; struct berval *b, *who = NULL, peername; char *what, *whatm, *suffix; time_t stamp; int i; if ( rs->sr_err != LDAP_SUCCESS ) return SLAP_CB_CONTINUE; if ( !ad->ad_logfile ) return SLAP_CB_CONTINUE; /* ** add or modify: use modifiersName if present ** */ switch(op->o_tag) { case LDAP_REQ_MODRDN: what = "modrdn"; break; case LDAP_REQ_DELETE: what = "delete"; break; case LDAP_REQ_ADD: what = "add"; for(a = op->ora_e->e_attrs; a; a = a->a_next) if( a->a_desc == slap_schema.si_ad_modifiersName ) { who = &a->a_vals[0]; break; } break; case LDAP_REQ_MODIFY: what = "modify"; for(m = op->orm_modlist; m; m = m->sml_next) if( m->sml_desc == slap_schema.si_ad_modifiersName && ( m->sml_op == LDAP_MOD_ADD || m->sml_op == LDAP_MOD_REPLACE )) { who = &m->sml_values[0]; break; } break; default: return SLAP_CB_CONTINUE; } suffix = op->o_bd->be_suffix[0].bv_len ? op->o_bd->be_suffix[0].bv_val : "global"; /* ** note: this means requestor's dn when modifiersName is null */ if ( !who ) who = &op->o_dn; peername = op->o_conn->c_peer_name; ldap_pvt_thread_mutex_lock(&ad->ad_mutex); if((f = fopen(ad->ad_logfile, "a")) == NULL) { ldap_pvt_thread_mutex_unlock(&ad->ad_mutex); return SLAP_CB_CONTINUE; } stamp = slap_get_time(); fprintf(f, "# %s %ld %s%s%s %s conn=%ld\n", what, (long)stamp, suffix, who ? " " : "", who ? who->bv_val : "", peername.bv_val ? peername.bv_val: "", op->o_conn->c_connid); if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) && (!who || !dn_match( who, &op->o_conn->c_dn ))) fprintf(f, "# realdn: %s\n", op->o_conn->c_dn.bv_val ); fprintf(f, "dn: %s\nchangetype: %s\n", op->o_req_dn.bv_val, what); switch(op->o_tag) { case LDAP_REQ_ADD: for(a = op->ora_e->e_attrs; a; a = a->a_next) if((b = a->a_vals) != NULL) for(i = 0; b[i].bv_val; i++) fprint_ldif(f, a->a_desc->ad_cname.bv_val, b[i].bv_val, b[i].bv_len); break; case LDAP_REQ_MODIFY: for(m = op->orm_modlist; m; m = m->sml_next) { switch(m->sml_op & LDAP_MOD_OP) { case LDAP_MOD_ADD: whatm = "add"; break; case LDAP_MOD_REPLACE: whatm = "replace"; break; case LDAP_MOD_DELETE: whatm = "delete"; break; case LDAP_MOD_INCREMENT: whatm = "increment"; break; default: fprintf(f, "# MOD_TYPE_UNKNOWN:%02x\n", m->sml_op & LDAP_MOD_OP); continue; } fprintf(f, "%s: %s\n", whatm, m->sml_desc->ad_cname.bv_val); if((b = m->sml_values) != NULL) for(i = 0; b[i].bv_val; i++) fprint_ldif(f, m->sml_desc->ad_cname.bv_val, b[i].bv_val, b[i].bv_len); fprintf(f, "-\n"); } break; case LDAP_REQ_MODRDN: fprintf(f, "newrdn: %s\ndeleteoldrdn: %s\n", op->orr_newrdn.bv_val, op->orr_deleteoldrdn ? "1" : "0"); if(op->orr_newSup) fprintf(f, "newsuperior: %s\n", op->orr_newSup->bv_val); break; case LDAP_REQ_DELETE: /* nothing else needed */ break; } fprintf(f, "# end %s %ld\n\n", what, (long)stamp); fclose(f); ldap_pvt_thread_mutex_unlock(&ad->ad_mutex); return SLAP_CB_CONTINUE; }
int backsql_delete( Operation *op, SlapReply *rs ) { SQLHDBC dbh = SQL_NULL_HDBC; SQLHSTMT sth = SQL_NULL_HSTMT; backsql_oc_map_rec *oc = NULL; backsql_srch_info bsi = { 0 }; backsql_entryID e_id = { 0 }; Entry d = { 0 }, p = { 0 }, *e = NULL; struct berval pdn = BER_BVNULL; int manageDSAit = get_manageDSAit( op ); Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n", op->o_req_ndn.bv_val, 0, 0 ); rs->sr_err = backsql_get_db_conn( op, &dbh ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "could not get connection handle - exiting\n", 0, 0, 0 ); rs->sr_text = ( rs->sr_err == LDAP_OTHER ) ? "SQL-backend error" : NULL; e = NULL; goto done; } /* * Get the entry */ bsi.bsi_e = &d; rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) ); switch ( rs->sr_err ) { case LDAP_SUCCESS: break; case LDAP_REFERRAL: if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) { rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; rs->sr_matched = NULL; if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } break; } e = &d; /* fallthru */ default: Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " "could not retrieve deleteDN ID - no such entry\n", 0, 0, 0 ); if ( !BER_BVISNULL( &d.e_nname ) ) { /* FIXME: should always be true! */ e = &d; } else { e = NULL; } goto done; } if ( get_assert( op ) && ( test_filter( op, &d, get_assertion( op ) ) != LDAP_COMPARE_TRUE ) ) { rs->sr_err = LDAP_ASSERTION_FAILED; e = &d; goto done; } if ( !access_allowed( op, &d, slap_schema.si_ad_entry, NULL, ACL_WDEL, NULL ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "no write access to entry\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; e = &d; goto done; } rs->sr_err = backsql_has_children( op, dbh, &op->o_req_ndn ); switch ( rs->sr_err ) { case LDAP_COMPARE_FALSE: rs->sr_err = LDAP_SUCCESS; break; case LDAP_COMPARE_TRUE: #ifdef SLAP_CONTROL_X_TREE_DELETE if ( get_treeDelete( op ) ) { rs->sr_err = LDAP_SUCCESS; break; } #endif /* SLAP_CONTROL_X_TREE_DELETE */ Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "entry \"%s\" has children\n", op->o_req_dn.bv_val, 0, 0 ); rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; rs->sr_text = "subordinate objects must be deleted first"; /* fallthru */ default: e = &d; goto done; } assert( bsi.bsi_base_id.eid_oc != NULL ); oc = bsi.bsi_base_id.eid_oc; if ( oc->bom_delete_proc == NULL ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "delete procedure is not defined " "for this objectclass - aborting\n", 0, 0, 0 ); rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "operation not permitted within namingContext"; e = NULL; goto done; } /* * Get the parent */ e_id = bsi.bsi_base_id; memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) { dnParent( &op->o_req_ndn, &pdn ); bsi.bsi_e = &p; rs->sr_err = backsql_init_search( &bsi, &pdn, LDAP_SCOPE_BASE, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, BACKSQL_ISF_GET_ENTRY ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " "could not retrieve deleteDN ID " "- no such entry\n", 0, 0, 0 ); e = &p; goto done; } (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); /* check parent for "children" acl */ if ( !access_allowed( op, &p, slap_schema.si_ad_children, NULL, ACL_WDEL, NULL ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "no write access to parent\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; e = &p; goto done; } } e = &d; #ifdef SLAP_CONTROL_X_TREE_DELETE if ( get_treeDelete( op ) ) { backsql_tree_delete( op, rs, dbh, &sth ); if ( rs->sr_err == LDAP_OTHER || rs->sr_err == LDAP_SUCCESS ) { e = NULL; } } else #endif /* SLAP_CONTROL_X_TREE_DELETE */ { backsql_delete_int( op, rs, dbh, &sth, &e_id, &e ); } /* * Commit only if all operations succeed */ if ( sth != SQL_NULL_HSTMT ) { SQLUSMALLINT CompletionType = SQL_ROLLBACK; if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { assert( e == NULL ); CompletionType = SQL_COMMIT; } SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); } done:; if ( e != NULL ) { if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = NULL; rs->sr_matched = NULL; if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } } } if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { rs->sr_err = LDAP_X_NO_OPERATION; } send_ldap_result( op, rs ); Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 ); if ( !BER_BVISNULL( &e_id.eid_ndn ) ) { (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); } if ( !BER_BVISNULL( &d.e_nname ) ) { backsql_entry_clean( op, &d ); } if ( !BER_BVISNULL( &p.e_nname ) ) { backsql_entry_clean( op, &p ); } if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } return rs->sr_err; }
static int monitor_subsys_rww_update( Operation *op, SlapReply *rs, Entry *e ) { monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private; Connection *c; int connindex; long nconns, nwritewaiters, nreadwaiters; int i; struct berval nrdn; Attribute *a; char buf[LDAP_PVT_INTTYPE_CHARS(long)]; long num = 0; ber_len_t len; assert( mi != NULL ); assert( e != NULL ); dnRdn( &e->e_nname, &nrdn ); for ( i = 0; !BER_BVISNULL( &monitor_rww[ i ].nrdn ); i++ ) { if ( dn_match( &nrdn, &monitor_rww[ i ].nrdn ) ) { break; } } if ( i == MONITOR_RWW_LAST ) { return SLAP_CB_CONTINUE; } nconns = nwritewaiters = nreadwaiters = 0; for ( c = connection_first( &connindex ); c != NULL; c = connection_next( c, &connindex ), nconns++ ) { if ( c->c_writewaiter ) { nwritewaiters++; } /* FIXME: ?!? */ if ( c->c_currentber != NULL ) { nreadwaiters++; } } connection_done(c); switch ( i ) { case MONITOR_RWW_READ: num = nreadwaiters; break; case MONITOR_RWW_WRITE: num = nwritewaiters; break; default: assert( 0 ); } snprintf( buf, sizeof( buf ), "%ld", num ); a = attr_find( e->e_attrs, mi->mi_ad_monitorCounter ); assert( a != NULL ); len = strlen( buf ); if ( len > a->a_vals[ 0 ].bv_len ) { a->a_vals[ 0 ].bv_val = ber_memrealloc( a->a_vals[ 0 ].bv_val, len + 1 ); if ( BER_BVISNULL( &a->a_vals[ 0 ] ) ) { BER_BVZERO( &a->a_vals[ 0 ] ); return SLAP_CB_CONTINUE; } } AC_MEMCPY( a->a_vals[ 0 ].bv_val, buf, len + 1 ); a->a_vals[ 0 ].bv_len = len; /* FIXME: touch modifyTimestamp? */ return SLAP_CB_CONTINUE; }
int bdb_add(Operation *op, SlapReply *rs ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; struct berval pdn; Entry *p = NULL, *oe = op->ora_e; EntryInfo *ei; char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; AttributeDescription *children = slap_schema.si_ad_children; AttributeDescription *entry = slap_schema.si_ad_entry; DB_TXN *ltid = NULL, *lt2; ID eid = NOID; struct bdb_op_info opinfo = {{{ 0 }}}; int subentry; DB_LOCK lock; int num_retries = 0; int success; LDAPControl **postread_ctrl = NULL; LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; int num_ctrls = 0; #ifdef LDAP_X_TXN int settle = 0; #endif Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(bdb_add) ": %s\n", op->ora_e->e_name.bv_val, 0, 0); #ifdef LDAP_X_TXN if( op->o_txnSpec ) { /* acquire connection lock */ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) { rs->sr_text = "invalid transaction identifier"; rs->sr_err = LDAP_X_TXN_ID_INVALID; goto txnReturn; } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) { settle=1; goto txnReturn; } if( op->o_conn->c_txn_backend == NULL ) { op->o_conn->c_txn_backend = op->o_bd; } else if( op->o_conn->c_txn_backend != op->o_bd ) { rs->sr_text = "transaction cannot span multiple database contexts"; rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS; goto txnReturn; } /* insert operation into transaction */ rs->sr_text = "transaction specified"; rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY; txnReturn: /* release connection lock */ ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); if( !settle ) { send_ldap_result( op, rs ); return rs->sr_err; } } #endif ctrls[num_ctrls] = 0; /* check entry's schema */ rs->sr_err = entry_schema_check( op, op->ora_e, NULL, get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": entry failed schema check: " "%s (%d)\n", rs->sr_text, rs->sr_err, 0 ); goto return_results; } /* add opattrs to shadow as well, only missing attrs will actually * be added; helps compatibility with older OL versions */ rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": entry failed op attrs add: " "%s (%d)\n", rs->sr_text, rs->sr_err, 0 ); goto return_results; } if ( get_assert( op ) && ( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE )) { rs->sr_err = LDAP_ASSERTION_FAILED; goto return_results; } subentry = is_entry_subentry( op->ora_e ); if( 0 ) { retry: /* transaction retry */ if( p ) { /* free parent and reader lock */ if ( p != (Entry *)&slap_entry_root ) { bdb_unlocked_cache_return_entry_r( bdb, p ); } p = NULL; } rs->sr_err = TXN_ABORT( ltid ); ltid = NULL; LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next ); opinfo.boi_oe.oe_key = NULL; op->o_do_not_cache = opinfo.boi_acl_cache; if( rs->sr_err != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } if ( op->o_abandon ) { rs->sr_err = SLAPD_ABANDON; goto return_results; } bdb_trans_backoff( ++num_retries ); } /* begin transaction */ rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, bdb->bi_db_opflags ); rs->sr_text = NULL; if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": txn_begin failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": txn1 id: %x\n", ltid->id(ltid), 0, 0 ); opinfo.boi_oe.oe_key = bdb; opinfo.boi_txn = ltid; opinfo.boi_err = 0; opinfo.boi_acl_cache = op->o_do_not_cache; LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next ); /* * Get the parent dn and see if the corresponding entry exists. */ if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) { pdn = slap_empty_bv; } else { dnParent( &op->ora_e->e_nname, &pdn ); } /* get entry or parent */ rs->sr_err = bdb_dn2entry( op, ltid, &op->ora_e->e_nname, &ei, 1, &lock ); switch( rs->sr_err ) { case 0: rs->sr_err = LDAP_ALREADY_EXISTS; goto return_results; case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case LDAP_BUSY: rs->sr_text = "ldap server busy"; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } p = ei->bei_e; if ( !p ) p = (Entry *)&slap_entry_root; if ( !bvmatch( &pdn, &p->e_nname ) ) { rs->sr_matched = ber_strdup_x( p->e_name.bv_val, op->o_tmpmemctx ); rs->sr_ref = is_entry_referral( p ) ? get_entry_referrals( op, p ) : NULL; if ( p != (Entry *)&slap_entry_root ) bdb_unlocked_cache_return_entry_r( bdb, p ); p = NULL; Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": parent " "does not exist\n", 0, 0, 0 ); rs->sr_err = LDAP_REFERRAL; rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; goto return_results; } rs->sr_err = access_allowed( op, p, children, NULL, ACL_WADD, NULL ); if ( ! rs->sr_err ) { switch( opinfo.boi_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } if ( p != (Entry *)&slap_entry_root ) bdb_unlocked_cache_return_entry_r( bdb, p ); p = NULL; Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": no write access to parent\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to parent"; goto return_results;; } if ( p != (Entry *)&slap_entry_root ) { if ( is_entry_subentry( p ) ) { bdb_unlocked_cache_return_entry_r( bdb, p ); p = NULL; /* parent is a subentry, don't allow add */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": parent is subentry\n", 0, 0, 0 ); rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; rs->sr_text = "parent is a subentry"; goto return_results;; } if ( is_entry_alias( p ) ) { bdb_unlocked_cache_return_entry_r( bdb, p ); p = NULL; /* parent is an alias, don't allow add */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": parent is alias\n", 0, 0, 0 ); rs->sr_err = LDAP_ALIAS_PROBLEM; rs->sr_text = "parent is an alias"; goto return_results;; } if ( is_entry_referral( p ) ) { /* parent is a referral, don't allow add */ rs->sr_matched = ber_strdup_x( p->e_name.bv_val, op->o_tmpmemctx ); rs->sr_ref = get_entry_referrals( op, p ); bdb_unlocked_cache_return_entry_r( bdb, p ); p = NULL; Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": parent is referral\n", 0, 0, 0 ); rs->sr_err = LDAP_REFERRAL; rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; goto return_results; } } if ( subentry ) { /* FIXME: */ /* parent must be an administrative point of the required kind */ } /* free parent and reader lock */ if ( p != (Entry *)&slap_entry_root ) { if ( p->e_nname.bv_len ) { struct berval ppdn; /* ITS#5326: use parent's DN if differs from provided one */ dnParent( &op->ora_e->e_name, &ppdn ); if ( !dn_match( &p->e_name, &ppdn ) ) { struct berval rdn; struct berval newdn; dnRdn( &op->ora_e->e_name, &rdn ); build_new_dn( &newdn, &p->e_name, &rdn, NULL ); if ( op->ora_e->e_name.bv_val != op->o_req_dn.bv_val ) ber_memfree( op->ora_e->e_name.bv_val ); op->ora_e->e_name = newdn; /* FIXME: should check whether * dnNormalize(newdn) == e->e_nname ... */ } } bdb_unlocked_cache_return_entry_r( bdb, p ); } p = NULL; rs->sr_err = access_allowed( op, op->ora_e, entry, NULL, ACL_WADD, NULL ); if ( ! rs->sr_err ) { switch( opinfo.boi_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": no write access to entry\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to entry"; goto return_results;; } /* * Check ACL for attribute write access */ if (!acl_check_modlist(op, oe, op->ora_modlist)) { switch( opinfo.boi_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": no write access to attribute\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to attribute"; goto return_results;; } if ( eid == NOID ) { rs->sr_err = bdb_next_id( op->o_bd, &eid ); if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": next_id failed (%d)\n", rs->sr_err, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } op->ora_e->e_id = eid; } /* nested transaction */ rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, <2, bdb->bi_db_opflags ); rs->sr_text = NULL; if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": txn_begin(2) failed: " "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": txn2 id: %x\n", lt2->id(lt2), 0, 0 ); /* dn2id index */ rs->sr_err = bdb_dn2id_add( op, lt2, ei, op->ora_e ); if ( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": dn2id_add failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case DB_KEYEXIST: rs->sr_err = LDAP_ALREADY_EXISTS; break; default: rs->sr_err = LDAP_OTHER; } goto return_results; } /* attribute indexes */ rs->sr_err = bdb_index_entry_add( op, lt2, op->ora_e ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": index_entry_add failed\n", 0, 0, 0 ); switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; default: rs->sr_err = LDAP_OTHER; } rs->sr_text = "index generation failed"; goto return_results; } /* id2entry index */ rs->sr_err = bdb_id2entry_add( op->o_bd, lt2, op->ora_e ); if ( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": id2entry_add failed\n", 0, 0, 0 ); switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; default: rs->sr_err = LDAP_OTHER; } rs->sr_text = "entry store failed"; goto return_results; } if ( TXN_COMMIT( lt2, 0 ) != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "txn_commit(2) failed"; goto return_results; } /* post-read */ if( op->o_postread ) { if( postread_ctrl == NULL ) { postread_ctrl = &ctrls[num_ctrls++]; ctrls[num_ctrls] = NULL; } if ( slap_read_controls( op, rs, op->ora_e, &slap_post_read_bv, postread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(bdb_add) ": post-read " "failed!\n", 0, 0, 0 ); if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ goto return_results; } } } if ( op->o_noop ) { if (( rs->sr_err=TXN_ABORT( ltid )) != 0 ) { rs->sr_text = "txn_abort (no-op) failed"; } else { rs->sr_err = LDAP_X_NO_OPERATION; ltid = NULL; goto return_results; } } else { struct berval nrdn; /* pick the RDN if not suffix; otherwise pick the entire DN */ if (pdn.bv_len) { nrdn.bv_val = op->ora_e->e_nname.bv_val; nrdn.bv_len = pdn.bv_val - op->ora_e->e_nname.bv_val - 1; } else { nrdn = op->ora_e->e_nname; } bdb_cache_add( bdb, ei, op->ora_e, &nrdn, ltid, &lock ); if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) { rs->sr_text = "txn_commit failed"; } else { rs->sr_err = LDAP_SUCCESS; } } ltid = NULL; LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next ); opinfo.boi_oe.oe_key = NULL; if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": %s : %s (%d)\n", rs->sr_text, db_strerror(rs->sr_err), rs->sr_err ); rs->sr_err = LDAP_OTHER; goto return_results; } Debug(LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": added%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no-op)" : "", op->ora_e->e_id, op->ora_e->e_dn ); rs->sr_text = NULL; if( num_ctrls ) rs->sr_ctrls = ctrls; return_results: success = rs->sr_err; send_ldap_result( op, rs ); if( ltid != NULL ) { TXN_ABORT( ltid ); } if ( opinfo.boi_oe.oe_key ) { LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next ); } if( success == LDAP_SUCCESS ) { /* We own the entry now, and it can be purged at will * Check to make sure it's the same entry we entered with. * Possibly a callback may have mucked with it, although * in general callbacks should treat the entry as read-only. */ bdb_cache_deref( oe->e_private ); if ( op->ora_e == oe ) op->ora_e = NULL; if ( bdb->bi_txn_cp_kbyte ) { TXN_CHECKPOINT( bdb->bi_dbenv, bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 ); } } slap_graduate_commit_csn( op ); if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); } return rs->sr_err; }
/* * NOTE: the dn must be normalized */ int backsql_dn2id( Operation *op, SlapReply *rs, SQLHDBC dbh, struct berval *ndn, backsql_entryID *id, int matched, int muck ) { backsql_info *bi = op->o_bd->be_private; SQLHSTMT sth = SQL_NULL_HSTMT; BACKSQL_ROW_NTS row = { 0 }; RETCODE rc; int res; struct berval realndn = BER_BVNULL; /* TimesTen */ char upperdn[ BACKSQL_MAX_DN_LEN + 1 ]; struct berval tbbDN; int i, j; /* * NOTE: id can be NULL; in this case, the function * simply checks whether the DN can be successfully * turned into an ID, returning LDAP_SUCCESS for * positive cases, or the most appropriate error */ Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(\"%s\")%s%s\n", ndn->bv_val, id == NULL ? " (no ID expected)" : "", matched ? " matched expected" : "" ); if ( id ) { /* NOTE: trap inconsistencies */ assert( BER_BVISNULL( &id->eid_ndn ) ); } if ( ndn->bv_len > BACKSQL_MAX_DN_LEN ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): DN length=%ld " "exceeds max DN length %d:\n", ndn->bv_val, ndn->bv_len, BACKSQL_MAX_DN_LEN ); return LDAP_OTHER; } /* return baseObject if available and matches */ /* FIXME: if ndn is already mucked, we cannot check this */ if ( bi->sql_baseObject != NULL && dn_match( ndn, &bi->sql_baseObject->e_nname ) ) { if ( id != NULL ) { #ifdef BACKSQL_ARBITRARY_KEY ber_dupbv_x( &id->eid_id, &backsql_baseObject_bv, op->o_tmpmemctx ); ber_dupbv_x( &id->eid_keyval, &backsql_baseObject_bv, op->o_tmpmemctx ); #else /* ! BACKSQL_ARBITRARY_KEY */ id->eid_id = BACKSQL_BASEOBJECT_ID; id->eid_keyval = BACKSQL_BASEOBJECT_KEYVAL; #endif /* ! BACKSQL_ARBITRARY_KEY */ id->eid_oc_id = BACKSQL_BASEOBJECT_OC; ber_dupbv_x( &id->eid_ndn, &bi->sql_baseObject->e_nname, op->o_tmpmemctx ); ber_dupbv_x( &id->eid_dn, &bi->sql_baseObject->e_name, op->o_tmpmemctx ); id->eid_next = NULL; } return LDAP_SUCCESS; } /* begin TimesTen */ Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): id_query \"%s\"\n", ndn->bv_val, bi->sql_id_query, 0 ); assert( bi->sql_id_query != NULL ); rc = backsql_Prepare( dbh, &sth, bi->sql_id_query, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error preparing SQL:\n %s", ndn->bv_val, bi->sql_id_query, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); res = LDAP_OTHER; goto done; } realndn = *ndn; if ( muck ) { if ( backsql_api_dn2odbc( op, rs, &realndn ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "backsql_api_dn2odbc(\"%s\") failed\n", ndn->bv_val, realndn.bv_val, 0 ); res = LDAP_OTHER; goto done; } } if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) { /* * Prepare an upper cased, byte reversed version * that can be searched using indexes */ for ( i = 0, j = realndn.bv_len - 1; realndn.bv_val[ i ]; i++, j--) { upperdn[ i ] = realndn.bv_val[ j ]; } upperdn[ i ] = '\0'; ldap_pvt_str2upper( upperdn ); Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "upperdn=\"%s\"\n", ndn->bv_val, upperdn, 0 ); ber_str2bv( upperdn, 0, 0, &tbbDN ); } else { if ( BACKSQL_USE_REVERSE_DN( bi ) ) { AC_MEMCPY( upperdn, realndn.bv_val, realndn.bv_len + 1 ); ldap_pvt_str2upper( upperdn ); Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "upperdn=\"%s\"\n", ndn->bv_val, upperdn, 0 ); ber_str2bv( upperdn, 0, 0, &tbbDN ); } else { tbbDN = realndn; } } rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &tbbDN ); if ( rc != SQL_SUCCESS) { /* end TimesTen */ Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error binding dn=\"%s\" parameter:\n", ndn->bv_val, tbbDN.bv_val, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); res = LDAP_OTHER; goto done; } rc = SQLExecute( sth ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "error executing query (\"%s\", \"%s\"):\n", ndn->bv_val, bi->sql_id_query, tbbDN.bv_val ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); res = LDAP_OTHER; goto done; } backsql_BindRowAsStrings_x( sth, &row, op->o_tmpmemctx ); rc = SQLFetch( sth ); if ( BACKSQL_SUCCESS( rc ) ) { char buf[ SLAP_TEXT_BUFLEN ]; #ifdef LDAP_DEBUG snprintf( buf, sizeof(buf), "id=%s keyval=%s oc_id=%s dn=%s", row.cols[ 0 ], row.cols[ 1 ], row.cols[ 2 ], row.cols[ 3 ] ); Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): %s\n", ndn->bv_val, buf, 0 ); #endif /* LDAP_DEBUG */ res = LDAP_SUCCESS; if ( id != NULL ) { struct berval dn; id->eid_next = NULL; #ifdef BACKSQL_ARBITRARY_KEY ber_str2bv_x( row.cols[ 0 ], 0, 1, &id->eid_id, op->o_tmpmemctx ); ber_str2bv_x( row.cols[ 1 ], 0, 1, &id->eid_keyval, op->o_tmpmemctx ); #else /* ! BACKSQL_ARBITRARY_KEY */ if ( lutil_atoulx( &id->eid_id, row.cols[ 0 ], 0 ) != 0 ) { res = LDAP_OTHER; goto done; } if ( lutil_atoulx( &id->eid_keyval, row.cols[ 1 ], 0 ) != 0 ) { res = LDAP_OTHER; goto done; } #endif /* ! BACKSQL_ARBITRARY_KEY */ if ( lutil_atoulx( &id->eid_oc_id, row.cols[ 2 ], 0 ) != 0 ) { res = LDAP_OTHER; goto done; } ber_str2bv( row.cols[ 3 ], 0, 0, &dn ); if ( backsql_api_odbc2dn( op, rs, &dn ) ) { res = LDAP_OTHER; goto done; } res = dnPrettyNormal( NULL, &dn, &id->eid_dn, &id->eid_ndn, op->o_tmpmemctx ); if ( res != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): " "dnPrettyNormal failed (%d: %s)\n", realndn.bv_val, res, ldap_err2string( res ) ); /* cleanup... */ (void)backsql_free_entryID( id, 0, op->o_tmpmemctx ); } if ( dn.bv_val != row.cols[ 3 ] ) { free( dn.bv_val ); } } } else { res = LDAP_NO_SUCH_OBJECT; if ( matched ) { struct berval pdn = *ndn; /* * Look for matched */ rs->sr_matched = NULL; while ( !be_issuffix( op->o_bd, &pdn ) ) { char *matchedDN = NULL; dnParent( &pdn, &pdn ); /* * Empty DN ("") defaults to LDAP_SUCCESS */ rs->sr_err = backsql_dn2id( op, rs, dbh, &pdn, id, 0, 1 ); switch ( rs->sr_err ) { case LDAP_NO_SUCH_OBJECT: /* try another one */ break; case LDAP_SUCCESS: matchedDN = pdn.bv_val; /* fail over to next case */ default: rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_matched = matchedDN; goto done; } } } } done:; backsql_FreeRow_x( &row, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<==backsql_dn2id(\"%s\"): err=%d\n", ndn->bv_val, res, 0 ); if ( sth != SQL_NULL_HSTMT ) { SQLFreeStmt( sth, SQL_DROP ); } if ( !BER_BVISNULL( &realndn ) && realndn.bv_val != ndn->bv_val ) { ch_free( realndn.bv_val ); } return res; }
int dnssrv_back_search( Operation *op, SlapReply *rs ) { int i; int rc; char *domain = NULL; char *hostlist = NULL; char **hosts = NULL; char *refdn; struct berval nrefdn = BER_BVNULL; BerVarray urls = NULL; int manageDSAit; rs->sr_ref = NULL; if ( BER_BVISEMPTY( &op->o_req_ndn ) ) { /* FIXME: need some means to determine whether the database * is a glue instance; if we got here with empty DN, then * we passed this same test in dnssrv_back_referrals() */ if ( !SLAP_GLUE_INSTANCE( op->o_bd ) ) { rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "DNS SRV operation upon null (empty) DN disallowed"; } else { rs->sr_err = LDAP_SUCCESS; } goto done; } manageDSAit = get_manageDSAit( op ); /* * FIXME: we may return a referral if manageDSAit is not set */ if ( !manageDSAit ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "manageDSAit must be set" ); goto done; } if( ldap_dn2domain( op->o_req_dn.bv_val, &domain ) || domain == NULL ) { rs->sr_err = LDAP_REFERRAL; rs->sr_ref = default_referral; send_ldap_result( op, rs ); rs->sr_ref = NULL; goto done; } Debug( LDAP_DEBUG_TRACE, "DNSSRV: dn=\"%s\" -> domain=\"%s\"\n", op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", domain ); if( ( rc = ldap_domain2hostlist( domain, &hostlist ) ) ) { Debug( LDAP_DEBUG_TRACE, "DNSSRV: domain2hostlist returned %d\n", rc ); send_ldap_error( op, rs, LDAP_NO_SUCH_OBJECT, "no DNS SRV RR available for DN" ); goto done; } hosts = ldap_str2charray( hostlist, " " ); if( hosts == NULL ) { Debug( LDAP_DEBUG_TRACE, "DNSSRV: str2charray error\n" ); send_ldap_error( op, rs, LDAP_OTHER, "problem processing DNS SRV records for DN" ); goto done; } for( i=0; hosts[i] != NULL; i++) { struct berval url; url.bv_len = STRLENOF( "ldap://" ) + strlen(hosts[i]); url.bv_val = ch_malloc( url.bv_len + 1 ); strcpy( url.bv_val, "ldap://" ); strcpy( &url.bv_val[STRLENOF( "ldap://" )], hosts[i] ); if( ber_bvarray_add( &urls, &url ) < 0 ) { free( url.bv_val ); send_ldap_error( op, rs, LDAP_OTHER, "problem processing DNS SRV records for DN" ); goto done; } } Debug( LDAP_DEBUG_STATS, "%s DNSSRV p=%d dn=\"%s\" url=\"%s\"\n", op->o_log_prefix, op->o_protocol, op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", urls[0].bv_val ); Debug( LDAP_DEBUG_TRACE, "DNSSRV: ManageDSAit scope=%d dn=\"%s\" -> url=\"%s\"\n", op->oq_search.rs_scope, op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", urls[0].bv_val ); rc = ldap_domain2dn(domain, &refdn); if( rc != LDAP_SUCCESS ) { send_ldap_error( op, rs, LDAP_OTHER, "DNS SRV problem processing manageDSAit control" ); goto done; } else { struct berval bv; bv.bv_val = refdn; bv.bv_len = strlen( refdn ); rc = dnNormalize( 0, NULL, NULL, &bv, &nrefdn, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { send_ldap_error( op, rs, LDAP_OTHER, "DNS SRV problem processing manageDSAit control" ); goto done; } } if( !dn_match( &nrefdn, &op->o_req_ndn ) ) { /* requested dn is subordinate */ Debug( LDAP_DEBUG_TRACE, "DNSSRV: dn=\"%s\" subordinate to refdn=\"%s\"\n", op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", refdn == NULL ? "" : refdn ); rs->sr_matched = refdn; rs->sr_err = LDAP_NO_SUCH_OBJECT; send_ldap_result( op, rs ); rs->sr_matched = NULL; } else if ( op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL ) { send_ldap_error( op, rs, LDAP_SUCCESS, NULL ); } else { Entry e = { 0 }; AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; AttributeDescription *ad_ref = slap_schema.si_ad_ref; e.e_name.bv_val = ch_strdup( op->o_req_dn.bv_val ); e.e_name.bv_len = op->o_req_dn.bv_len; e.e_nname.bv_val = ch_strdup( op->o_req_ndn.bv_val ); e.e_nname.bv_len = op->o_req_ndn.bv_len; e.e_attrs = NULL; e.e_private = NULL; attr_merge_one( &e, ad_objectClass, &slap_schema.si_oc_referral->soc_cname, NULL ); attr_merge_one( &e, ad_objectClass, &slap_schema.si_oc_extensibleObject->soc_cname, NULL ); if ( ad_dc ) { char *p; struct berval bv; bv.bv_val = domain; p = strchr( bv.bv_val, '.' ); if ( p == bv.bv_val ) { bv.bv_len = 1; } else if ( p != NULL ) { bv.bv_len = p - bv.bv_val; } else { bv.bv_len = strlen( bv.bv_val ); } attr_merge_normalize_one( &e, ad_dc, &bv, NULL ); } if ( ad_associatedDomain ) { struct berval bv; ber_str2bv( domain, 0, 0, &bv ); attr_merge_normalize_one( &e, ad_associatedDomain, &bv, NULL ); } attr_merge_normalize_one( &e, ad_ref, urls, NULL ); rc = test_filter( op, &e, op->oq_search.rs_filter ); if( rc == LDAP_COMPARE_TRUE ) { rs->sr_entry = &e; rs->sr_attrs = op->oq_search.rs_attrs; rs->sr_flags = REP_ENTRY_MODIFIABLE; send_search_entry( op, rs ); rs->sr_entry = NULL; rs->sr_attrs = NULL; rs->sr_flags = 0; } entry_clean( &e ); rs->sr_err = LDAP_SUCCESS; send_ldap_result( op, rs ); } free( refdn ); if ( nrefdn.bv_val ) free( nrefdn.bv_val ); done: if( domain != NULL ) ch_free( domain ); if( hostlist != NULL ) ch_free( hostlist ); if( hosts != NULL ) ldap_charray_free( hosts ); if( urls != NULL ) ber_bvarray_free( urls ); return 0; }
int bdb_modrdn( Operation *op, SlapReply *rs ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; AttributeDescription *children = slap_schema.si_ad_children; AttributeDescription *entry = slap_schema.si_ad_entry; struct berval p_dn, p_ndn; struct berval new_dn = {0, NULL}, new_ndn = {0, NULL}; Entry *e = NULL; Entry *p = NULL; EntryInfo *ei = NULL, *eip = NULL, *nei = NULL, *neip = NULL; /* LDAP v2 supporting correct attribute handling. */ char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; DB_TXN *ltid = NULL, *lt2; struct bdb_op_info opinfo = {{{ 0 }}}; Entry dummy = {0}; Entry *np = NULL; /* newSuperior Entry */ struct berval *np_dn = NULL; /* newSuperior dn */ struct berval *np_ndn = NULL; /* newSuperior ndn */ struct berval *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */ int manageDSAit = get_manageDSAit( op ); DB_LOCK lock, plock, nplock; int num_retries = 0; LDAPControl **preread_ctrl = NULL; LDAPControl **postread_ctrl = NULL; LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; int num_ctrls = 0; int rc; int parent_is_glue = 0; int parent_is_leaf = 0; #ifdef LDAP_X_TXN int settle = 0; #endif Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(bdb_modrdn) "(%s,%s,%s)\n", op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val, op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" ); #ifdef LDAP_X_TXN if( op->o_txnSpec ) { /* acquire connection lock */ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) { rs->sr_text = "invalid transaction identifier"; rs->sr_err = LDAP_X_TXN_ID_INVALID; goto txnReturn; } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) { settle=1; goto txnReturn; } if( op->o_conn->c_txn_backend == NULL ) { op->o_conn->c_txn_backend = op->o_bd; } else if( op->o_conn->c_txn_backend != op->o_bd ) { rs->sr_text = "transaction cannot span multiple database contexts"; rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS; goto txnReturn; } /* insert operation into transaction */ rs->sr_text = "transaction specified"; rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY; txnReturn: /* release connection lock */ ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); if( !settle ) { send_ldap_result( op, rs ); return rs->sr_err; } } #endif ctrls[num_ctrls] = NULL; slap_mods_opattrs( op, &op->orr_modlist, 1 ); if( 0 ) { retry: /* transaction retry */ if ( dummy.e_attrs ) { attrs_free( dummy.e_attrs ); dummy.e_attrs = NULL; } if (e != NULL) { bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); e = NULL; } if (p != NULL) { bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p); p = NULL; } if (np != NULL) { bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np); np = NULL; } Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(bdb_modrdn) ": retrying...\n", 0, 0, 0 ); rs->sr_err = TXN_ABORT( ltid ); ltid = NULL; LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next ); opinfo.boi_oe.oe_key = NULL; op->o_do_not_cache = opinfo.boi_acl_cache; if( rs->sr_err != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } if ( op->o_abandon ) { rs->sr_err = SLAPD_ABANDON; goto return_results; } parent_is_glue = 0; parent_is_leaf = 0; bdb_trans_backoff( ++num_retries ); } /* begin transaction */ rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, bdb->bi_db_opflags ); rs->sr_text = NULL; if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": txn_begin failed: " "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": txn1 id: %x\n", ltid->id(ltid), 0, 0 ); opinfo.boi_oe.oe_key = bdb; opinfo.boi_txn = ltid; opinfo.boi_err = 0; opinfo.boi_acl_cache = op->o_do_not_cache; LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next ); /* get entry */ rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1, &lock ); switch( rs->sr_err ) { case 0: case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case LDAP_BUSY: rs->sr_text = "ldap server busy"; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } e = ei->bei_e; /* FIXME: dn2entry() should return non-glue entry */ if (( rs->sr_err == DB_NOTFOUND ) || ( !manageDSAit && e && is_entry_glue( e ))) { if( e != NULL ) { rs->sr_matched = ch_strdup( e->e_dn ); rs->sr_ref = is_entry_referral( e ) ? get_entry_referrals( op, e ) : NULL; bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, e); e = NULL; } else { rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); } rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); ber_bvarray_free( rs->sr_ref ); free( (char *)rs->sr_matched ); rs->sr_ref = NULL; rs->sr_matched = NULL; goto done; } if ( get_assert( op ) && ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE )) { rs->sr_err = LDAP_ASSERTION_FAILED; goto return_results; } /* check write on old entry */ rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL ); if ( ! rs->sr_err ) { switch( opinfo.boi_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0, 0, 0 ); rs->sr_text = "no write access to old entry"; rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto return_results; } #ifndef BDB_HIER rs->sr_err = bdb_cache_children( op, ltid, e ); if ( rs->sr_err != DB_NOTFOUND ) { switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case 0: Debug(LDAP_DEBUG_ARGS, "<=- " LDAP_XSTRING(bdb_modrdn) ": non-leaf %s\n", op->o_req_dn.bv_val, 0, 0); rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; rs->sr_text = "subtree rename not supported"; break; default: Debug(LDAP_DEBUG_ARGS, "<=- " LDAP_XSTRING(bdb_modrdn) ": has_children failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; } goto return_results; } ei->bei_state |= CACHE_ENTRY_NO_KIDS; #endif if (!manageDSAit && is_entry_referral( e ) ) { /* parent is a referral, don't allow add */ rs->sr_ref = get_entry_referrals( op, e ); Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": entry %s is referral\n", e->e_dn, 0, 0 ); rs->sr_err = LDAP_REFERRAL, rs->sr_matched = e->e_name.bv_val; send_ldap_result( op, rs ); ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; rs->sr_matched = NULL; goto done; } if ( be_issuffix( op->o_bd, &e->e_nname ) ) { #ifdef BDB_MULTIPLE_SUFFIXES /* Allow renaming one suffix entry to another */ p_ndn = slap_empty_bv; #else /* There can only be one suffix entry */ rs->sr_err = LDAP_NAMING_VIOLATION; rs->sr_text = "cannot rename suffix entry"; goto return_results; #endif } else { dnParent( &e->e_nname, &p_ndn ); } np_ndn = &p_ndn; eip = ei->bei_parent; if ( eip && eip->bei_id ) { /* Make sure parent entry exist and we can write its * children. */ rs->sr_err = bdb_cache_find_id( op, ltid, eip->bei_id, &eip, 0, &plock ); switch( rs->sr_err ) { case 0: case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case LDAP_BUSY: rs->sr_text = "ldap server busy"; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } p = eip->bei_e; if( p == NULL) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": parent does not exist\n", 0, 0, 0); rs->sr_err = LDAP_OTHER; rs->sr_text = "old entry's parent does not exist"; goto return_results; } } else { p = (Entry *)&slap_entry_root; } /* check parent for "children" acl */ rs->sr_err = access_allowed( op, p, children, NULL, op->oq_modrdn.rs_newSup == NULL ? ACL_WRITE : ACL_WDEL, NULL ); if ( !p_ndn.bv_len ) p = NULL; if ( ! rs->sr_err ) { switch( opinfo.boi_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } rs->sr_err = LDAP_INSUFFICIENT_ACCESS; Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 ); rs->sr_text = "no write access to old parent's children"; goto return_results; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": wr to children " "of entry %s OK\n", p_ndn.bv_val, 0, 0 ); if ( p_ndn.bv_val == slap_empty_bv.bv_val ) { p_dn = slap_empty_bv; } else { dnParent( &e->e_name, &p_dn ); } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": parent dn=%s\n", p_dn.bv_val, 0, 0 ); new_parent_dn = &p_dn; /* New Parent unless newSuperior given */ if ( op->oq_modrdn.rs_newSup != NULL ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": new parent \"%s\" requested...\n", op->oq_modrdn.rs_newSup->bv_val, 0, 0 ); /* newSuperior == oldParent? */ if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) { Debug( LDAP_DEBUG_TRACE, "bdb_back_modrdn: " "new parent \"%s\" same as the old parent \"%s\"\n", op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 ); op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */ } } /* There's a BDB_MULTIPLE_SUFFIXES case here that this code doesn't * support. E.g., two suffixes dc=foo,dc=com and dc=bar,dc=net. * We do not allow modDN * dc=foo,dc=com * newrdn dc=bar * newsup dc=net * and we probably should. But since MULTIPLE_SUFFIXES is deprecated * I'm ignoring this problem for now. */ if ( op->oq_modrdn.rs_newSup != NULL ) { if ( op->oq_modrdn.rs_newSup->bv_len ) { np_dn = op->oq_modrdn.rs_newSup; np_ndn = op->oq_modrdn.rs_nnewSup; /* newSuperior == oldParent? - checked above */ /* newSuperior == entry being moved?, if so ==> ERROR */ if ( dnIsSuffix( np_ndn, &e->e_nname )) { rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = "new superior not found"; goto return_results; } /* Get Entry with dn=newSuperior. Does newSuperior exist? */ rs->sr_err = bdb_dn2entry( op, ltid, np_ndn, &neip, 0, &nplock ); switch( rs->sr_err ) { case 0: np = neip->bei_e; case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case LDAP_BUSY: rs->sr_text = "ldap server busy"; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } if( np == NULL) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": newSup(ndn=%s) not here!\n", np_ndn->bv_val, 0, 0); rs->sr_text = "new superior not found"; rs->sr_err = LDAP_NO_SUCH_OBJECT; goto return_results; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": wr to new parent OK np=%p, id=%ld\n", (void *) np, (long) np->e_id, 0 ); /* check newSuperior for "children" acl */ rs->sr_err = access_allowed( op, np, children, NULL, ACL_WADD, NULL ); if( ! rs->sr_err ) { switch( opinfo.boi_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": no wr to newSup children\n", 0, 0, 0 ); rs->sr_text = "no write access to new superior's children"; rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto return_results; } if ( is_entry_alias( np ) ) { /* parent is an alias, don't allow add */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": entry is alias\n", 0, 0, 0 ); rs->sr_text = "new superior is an alias"; rs->sr_err = LDAP_ALIAS_PROBLEM; goto return_results; } if ( is_entry_referral( np ) ) { /* parent is a referral, don't allow add */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": entry is referral\n", 0, 0, 0 ); rs->sr_text = "new superior is a referral"; rs->sr_err = LDAP_OTHER; goto return_results; } } else { np_dn = NULL; /* no parent, modrdn entry directly under root */ if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv ) || be_isupdate( op ) ) { np = (Entry *)&slap_entry_root; /* check parent for "children" acl */ rs->sr_err = access_allowed( op, np, children, NULL, ACL_WADD, NULL ); np = NULL; if ( ! rs->sr_err ) { switch( opinfo.boi_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } rs->sr_err = LDAP_INSUFFICIENT_ACCESS; Debug( LDAP_DEBUG_TRACE, "no access to new superior\n", 0, 0, 0 ); rs->sr_text = "no write access to new superior's children"; goto return_results; } } } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": wr to new parent's children OK\n", 0, 0, 0 ); new_parent_dn = np_dn; } /* Build target dn and make sure target entry doesn't exist already. */ if (!new_dn.bv_val) { build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, NULL ); } if (!new_ndn.bv_val) { struct berval bv = {0, NULL}; dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx ); ber_dupbv( &new_ndn, &bv ); /* FIXME: why not call dnNormalize() w/o ctx? */ op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": new ndn=%s\n", new_ndn.bv_val, 0, 0 ); /* Shortcut the search */ nei = neip ? neip : eip; rs->sr_err = bdb_cache_find_ndn ( op, ltid, &new_ndn, &nei ); if ( nei ) bdb_cache_entryinfo_unlock( nei ); switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case DB_NOTFOUND: break; case 0: /* Allow rename to same DN */ if ( nei == ei ) break; rs->sr_err = LDAP_ALREADY_EXISTS; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } assert( op->orr_modlist != NULL ); if( op->o_preread ) { if( preread_ctrl == NULL ) { preread_ctrl = &ctrls[num_ctrls++]; ctrls[num_ctrls] = NULL; } if( slap_read_controls( op, rs, e, &slap_pre_read_bv, preread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(bdb_modrdn) ": pre-read failed!\n", 0, 0, 0 ); if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ goto return_results; } } } /* nested transaction */ rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, <2, bdb->bi_db_opflags ); rs->sr_text = NULL; if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": txn2 id: %x\n", lt2->id(lt2), 0, 0 ); /* delete old DN */ rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e ); if ( rs->sr_err != 0 ) { Debug(LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(bdb_modrdn) ": dn2id del failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } rs->sr_err = LDAP_OTHER; rs->sr_text = "DN index delete fail"; goto return_results; } /* copy the entry, then override some fields */ dummy = *e; dummy.e_name = new_dn; dummy.e_nname = new_ndn; dummy.e_attrs = NULL; /* add new DN */ rs->sr_err = bdb_dn2id_add( op, lt2, neip ? neip : eip, &dummy ); if ( rs->sr_err != 0 ) { Debug(LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(bdb_modrdn) ": dn2id add failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } rs->sr_err = LDAP_OTHER; rs->sr_text = "DN index add failed"; goto return_results; } dummy.e_attrs = e->e_attrs; /* modify entry */ rs->sr_err = bdb_modify_internal( op, lt2, op->orr_modlist, &dummy, &rs->sr_text, textbuf, textlen ); if( rs->sr_err != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(bdb_modrdn) ": modify failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); if ( ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) && opinfo.boi_err ) { rs->sr_err = opinfo.boi_err; } if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } goto return_results; } /* id2entry index */ rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, &dummy ); if ( rs->sr_err != 0 ) { Debug(LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(bdb_modrdn) ": id2entry failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } rs->sr_err = LDAP_OTHER; rs->sr_text = "entry update failed"; goto return_results; } if ( p_ndn.bv_len != 0 ) { parent_is_glue = is_entry_glue(p); rs->sr_err = bdb_cache_children( op, lt2, p ); if ( rs->sr_err != DB_NOTFOUND ) { switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case 0: break; default: Debug(LDAP_DEBUG_ARGS, "<=- " LDAP_XSTRING(bdb_modrdn) ": has_children failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } parent_is_leaf = 1; } bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p); p = NULL; } if ( TXN_COMMIT( lt2, 0 ) != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "txn_commit(2) failed"; goto return_results; } if( op->o_postread ) { if( postread_ctrl == NULL ) { postread_ctrl = &ctrls[num_ctrls++]; ctrls[num_ctrls] = NULL; } if( slap_read_controls( op, rs, &dummy, &slap_post_read_bv, postread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(bdb_modrdn) ": post-read failed!\n", 0, 0, 0 ); if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ goto return_results; } } } if( op->o_noop ) { if(( rs->sr_err=TXN_ABORT( ltid )) != 0 ) { rs->sr_text = "txn_abort (no-op) failed"; } else { rs->sr_err = LDAP_X_NO_OPERATION; ltid = NULL; /* Only free attrs if they were dup'd. */ if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; goto return_results; } } else { rc = bdb_cache_modrdn( bdb, e, &op->orr_nnewrdn, &dummy, neip, ltid, &lock ); switch( rc ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } dummy.e_attrs = NULL; new_dn.bv_val = NULL; new_ndn.bv_val = NULL; if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) { rs->sr_text = "txn_commit failed"; } else { rs->sr_err = LDAP_SUCCESS; } } ltid = NULL; LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next ); opinfo.boi_oe.oe_key = NULL; if( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": %s : %s (%d)\n", rs->sr_text, db_strerror(rs->sr_err), rs->sr_err ); rs->sr_err = LDAP_OTHER; goto return_results; } Debug(LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": rdn modified%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no-op)" : "", dummy.e_id, op->o_req_dn.bv_val ); rs->sr_text = NULL; if( num_ctrls ) rs->sr_ctrls = ctrls; return_results: if ( dummy.e_attrs ) { attrs_free( dummy.e_attrs ); } send_ldap_result( op, rs ); if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp_kbyte ) { TXN_CHECKPOINT( bdb->bi_dbenv, bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 ); } if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) { op->o_delete_glue_parent = 1; } done: slap_graduate_commit_csn( op ); if( new_dn.bv_val != NULL ) free( new_dn.bv_val ); if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val ); /* LDAP v3 Support */ if( np != NULL ) { /* free new parent and reader lock */ bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np); } if( p != NULL ) { /* free parent and reader lock */ bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p); } /* free entry */ if( e != NULL ) { bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e); } if( ltid != NULL ) { TXN_ABORT( ltid ); } if ( opinfo.boi_oe.oe_key ) { LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next ); } if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) { slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); slap_sl_free( *preread_ctrl, op->o_tmpmemctx ); } if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); } return rs->sr_err; }