Attribute * slap_operational_subschemaSubentry( Backend *be ) { Attribute *a; /* The backend wants to take care of it */ if ( be && !SLAP_FRONTEND(be) && be->be_schemadn.bv_val ) return NULL; a = attr_alloc( slap_schema.si_ad_subschemaSubentry ); a->a_numvals = 1; a->a_vals = ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( a->a_vals, &frontendDB->be_schemadn ); a->a_vals[1].bv_len = 0; a->a_vals[1].bv_val = NULL; a->a_nvals = ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( a->a_nvals, &frontendDB->be_schemandn ); a->a_nvals[1].bv_len = 0; a->a_nvals[1].bv_val = NULL; return a; }
static void attr_dup2( Attribute *tmp, Attribute *a ) { tmp->a_flags = a->a_flags & SLAP_ATTR_PERSISTENT_FLAGS; if ( a->a_vals != NULL ) { unsigned i, j; tmp->a_numvals = a->a_numvals; tmp->a_vals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) ); for ( i = 0; i < tmp->a_numvals; i++ ) { ber_dupbv( &tmp->a_vals[i], &a->a_vals[i] ); if ( BER_BVISNULL( &tmp->a_vals[i] ) ) break; /* FIXME: error? */ } BER_BVZERO( &tmp->a_vals[i] ); /* a_nvals must be non null; it may be equal to a_vals */ assert( a->a_nvals != NULL ); if ( a->a_nvals != a->a_vals ) { tmp->a_nvals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) ); for ( j = 0; !BER_BVISNULL( &a->a_nvals[j] ); j++ ) { assert( j < i ); ber_dupbv( &tmp->a_nvals[j], &a->a_nvals[j] ); if ( BER_BVISNULL( &tmp->a_nvals[j] ) ) break; /* FIXME: error? */ } assert( j == i ); BER_BVZERO( &tmp->a_nvals[j] ); } else { tmp->a_nvals = tmp->a_vals; } } }
void glue_parent(Operation *op) { Operation nop = *op; slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; struct berval ndn = BER_BVNULL; Attribute *a; Entry *e; struct berval pdn; dnParent( &op->o_req_ndn, &pdn ); ber_dupbv_x( &ndn, &pdn, op->o_tmpmemctx ); Debug(LDAP_DEBUG_TRACE, "=> glue_parent: fabricating glue for <%s>\n", ndn.bv_val, 0, 0); e = entry_alloc(); e->e_id = NOID; ber_dupbv(&e->e_name, &ndn); ber_dupbv(&e->e_nname, &ndn); a = attr_alloc( slap_schema.si_ad_objectClass ); a->a_numvals = 2; a->a_vals = ch_malloc(sizeof(struct berval) * 3); ber_dupbv(&a->a_vals[0], &glue[0]); ber_dupbv(&a->a_vals[1], &glue[1]); ber_dupbv(&a->a_vals[2], &glue[2]); a->a_nvals = a->a_vals; a->a_next = e->e_attrs; e->e_attrs = a; a = attr_alloc( slap_schema.si_ad_structuralObjectClass ); a->a_numvals = 1; a->a_vals = ch_malloc(sizeof(struct berval) * 2); ber_dupbv(&a->a_vals[0], &glue[1]); ber_dupbv(&a->a_vals[1], &glue[2]); a->a_nvals = a->a_vals; a->a_next = e->e_attrs; e->e_attrs = a; nop.o_req_dn = ndn; nop.o_req_ndn = ndn; nop.ora_e = e; nop.o_bd->bd_info = (BackendInfo *) on->on_info->oi_orig; syncrepl_add_glue(&nop, e); nop.o_bd->bd_info = (BackendInfo *) on; op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); return; }
int backsql_api_dn2odbc( Operation *op, SlapReply *rs, struct berval *dn ) { backsql_info *bi = (backsql_info *)op->o_bd->be_private; backsql_api *ba; int rc; struct berval bv; ba = bi->sql_api; if ( ba == NULL ) { return 0; } ber_dupbv( &bv, dn ); for ( ; ba; ba = ba->ba_next ) { if ( ba->ba_dn2odbc ) { /* * The dn2odbc() helper is supposed to rewrite * the contents of bv, freeing the original value * with ch_free() if required and replacing it * with a newly allocated one using ch_malloc() * or companion functions. * * NOTE: it is supposed to __always__ free * the value of bv in case of error, and reset * it with BER_BVZERO() . */ rc = ( *ba->ba_dn2odbc )( op, rs, &bv ); if ( rc ) { /* in case of error, dn2odbc() must cleanup */ assert( BER_BVISNULL( &bv ) ); return rc; } } } assert( !BER_BVISNULL( &bv ) ); *dn = bv; return 0; }
int sss_ldap_control_create(const char *oid, int iscritical, struct berval *value, int dupval, LDAPControl **ctrlp) { #ifdef HAVE_LDAP_CONTROL_CREATE return ldap_control_create(oid, iscritical, value, dupval, ctrlp); #else LDAPControl *lc = NULL; if (oid == NULL || ctrlp == NULL) { return LDAP_PARAM_ERROR; } lc = calloc(sizeof(LDAPControl), 1); if (lc == NULL) { return LDAP_NO_MEMORY; } lc->ldctl_oid = strdup(oid); if (lc->ldctl_oid == NULL) { free(lc); return LDAP_NO_MEMORY; } if (value != NULL && value->bv_val != NULL) { if (dupval == 0) { lc->ldctl_value = *value; } else { ber_dupbv(&lc->ldctl_value, value); if (lc->ldctl_value.bv_val == NULL) { free(lc->ldctl_oid); free(lc); return LDAP_NO_MEMORY; } } } lc->ldctl_iscritical = iscritical; *ctrlp = lc; return LDAP_SUCCESS; #endif }
Entry* ndb_tool_entry_get( BackendDB *be, ID id ) { NdbArgs NA; int rc; char text[1024]; Operation op = {0}; Opheader ohdr = {0}; assert( be != NULL ); assert( slapMode & SLAP_TOOL_MODE ); NA.txn = myNdb->startTransaction(); if ( !NA.txn ) { snprintf( text, sizeof(text), "start_transaction failed: %s (%d)", myNdb->getNdbError().message, myNdb->getNdbError().code ); Debug( LDAP_DEBUG_ANY, "=> " LDAP_XSTRING(ndb_tool_entry_get) ": %s\n", text, 0, 0 ); return NULL; } NA.e = entry_alloc(); NA.e->e_id = id; ber_dupbv( &NA.e->e_name, &myDn ); dnNormalize( 0, NULL, NULL, &NA.e->e_name, &NA.e->e_nname, NULL ); op.o_hdr = &ohdr; op.o_bd = be; op.o_tmpmemctx = NULL; op.o_tmpmfuncs = &ch_mfuncs; NA.ndb = myNdb; NA.ocs = myOcList; rc = ndb_entry_get_data( &op, &NA, 0 ); if ( rc ) { entry_free( NA.e ); NA.e = NULL; } NA.txn->close(); return NA.e; }
Attribute * slap_operational_hasSubordinate( int hs ) { Attribute *a; struct berval val; val = hs ? slap_true_bv : slap_false_bv; a = attr_alloc( slap_schema.si_ad_hasSubordinates ); a->a_numvals = 1; a->a_vals = ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &a->a_vals[0], &val ); a->a_vals[1].bv_val = NULL; a->a_nvals = a->a_vals; return a; }
static int vc_cb( Operation *op, SlapReply *rs ) { vc_cb_t *vc = (vc_cb_t *)op->o_callback->sc_private; if ( rs->sr_tag == LDAP_RES_BIND ) { if ( rs->sr_sasldata != NULL ) { ber_dupbv( &vc->sasldata, rs->sr_sasldata ); } if ( rs->sr_ctrls != NULL ) { vc->ctrls = ldap_controls_dup( rs->sr_ctrls ); } } return 0; }
void build_new_dn( struct berval * new_dn, struct berval * parent_dn, struct berval * newrdn ) { char *ptr; if ( parent_dn == NULL ) { ber_dupbv( new_dn, newrdn ); return; } new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1; new_dn->bv_val = (char *) ch_malloc( new_dn->bv_len + 1 ); ptr = lutil_strcopy( new_dn->bv_val, newrdn->bv_val ); *ptr++ = ','; strcpy( ptr, parent_dn->bv_val ); }
int ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx ) { ber_len_t i, l; assert( in != NULL ); assert( out != NULL ); BER_BVZERO( out ); if ( in->bv_len == 0 ) { return 0; } /* assume we'll escape everything */ l = ldap_bv2escaped_filter_value_len( in ); if ( l == in->bv_len ) { if ( inplace ) { *out = *in; } else { ber_dupbv( out, in ); } return 0; } out->bv_val = LDAP_MALLOCX( l + 1, ctx ); if ( out->bv_val == NULL ) { return -1; } for ( i = 0; i < in->bv_len; i++ ) { char c = in->bv_val[ i ]; if ( NEEDFLTESCAPE( c ) ) { assert( out->bv_len < l - 2 ); out->bv_val[out->bv_len++] = '\\'; out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)]; out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c]; } else { assert( out->bv_len < l ); out->bv_val[out->bv_len++] = c; } }
/* This callback actually does some work...*/ static int sasl_sc_sasl2dn( BackendDB *be, Connection *conn, Operation *o, Entry *e, AttributeName *an, int ao, LDAPControl **c) { struct berval *ndn = o->o_callback->sc_private; /* We only want to be called once */ if( ndn->bv_val ) { free(ndn->bv_val); ndn->bv_val = NULL; #ifdef NEW_LOGGING LDAP_LOG( TRANSPORT, DETAIL1, "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 ); #endif return -1; } ber_dupbv(ndn, &e->e_nname); return 0; }
void bdb_idl_cache_put( struct bdb_info *bdb, DB *db, DBT *key, ID *ids, int rc ) { bdb_idl_cache_entry_t idl_tmp; bdb_idl_cache_entry_t *ee, *eprev; if ( rc == DB_NOTFOUND || BDB_IDL_IS_ZERO( ids )) return; DBT2bv( key, &idl_tmp.kstr ); ee = (bdb_idl_cache_entry_t *) ch_malloc( sizeof( bdb_idl_cache_entry_t ) ); ee->db = db; ee->idl = (ID*) ch_malloc( BDB_IDL_SIZEOF ( ids ) ); BDB_IDL_CPY( ee->idl, ids ); ee->idl_lru_prev = NULL; ee->idl_lru_next = NULL; ee->idl_flags = 0; ber_dupbv( &ee->kstr, &idl_tmp.kstr ); ldap_pvt_thread_rdwr_wlock( &bdb->bi_idl_tree_rwlock ); if ( avl_insert( &bdb->bi_idl_tree, (caddr_t) ee, bdb_idl_entry_cmp, avl_dup_error )) { ch_free( ee->kstr.bv_val ); ch_free( ee->idl ); ch_free( ee ); ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock ); return; } ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock ); /* LRU_ADD */ if ( bdb->bi_idl_lru_head ) { assert( bdb->bi_idl_lru_tail != NULL ); assert( bdb->bi_idl_lru_head->idl_lru_prev != NULL ); assert( bdb->bi_idl_lru_head->idl_lru_next != NULL ); ee->idl_lru_next = bdb->bi_idl_lru_head; ee->idl_lru_prev = bdb->bi_idl_lru_head->idl_lru_prev; bdb->bi_idl_lru_head->idl_lru_prev->idl_lru_next = ee; bdb->bi_idl_lru_head->idl_lru_prev = ee; } else { ee->idl_lru_next = ee->idl_lru_prev = ee; bdb->bi_idl_lru_tail = ee; } bdb->bi_idl_lru_head = ee; if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) { int i; eprev = bdb->bi_idl_lru_tail; for ( i = 0; (ee = eprev) != NULL && i < 10; i++ ) { eprev = ee->idl_lru_prev; if ( eprev == ee ) { eprev = NULL; } if ( ee->idl_flags & CACHE_ENTRY_REFERENCED ) { ee->idl_flags ^= CACHE_ENTRY_REFERENCED; continue; } if ( avl_delete( &bdb->bi_idl_tree, (caddr_t) ee, bdb_idl_entry_cmp ) == NULL ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_cache_put: " "AVL delete failed\n", 0, 0, 0 ); } IDL_LRU_DELETE( bdb, ee ); i++; --bdb->bi_idl_cache_size; ch_free( ee->kstr.bv_val ); ch_free( ee->idl ); ch_free( ee ); } bdb->bi_idl_lru_tail = eprev; assert( bdb->bi_idl_lru_tail != NULL || bdb->bi_idl_lru_head == NULL ); } bdb->bi_idl_cache_size++; ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock ); ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock ); }
int fe_op_bind( Operation *op, SlapReply *rs ) { BackendDB *bd = op->o_bd; /* check for inappropriate controls */ if( get_manageDSAit( op ) == SLAP_CONTROL_CRITICAL ) { send_ldap_error( op, rs, LDAP_UNAVAILABLE_CRITICAL_EXTENSION, "manageDSAit control inappropriate" ); goto cleanup; } if ( op->orb_method == LDAP_AUTH_SASL ) { if ( op->o_protocol < LDAP_VERSION3 ) { Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%ld\n", (unsigned long)op->o_protocol ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "SASL bind requires LDAPv3" ); rs->sr_err = SLAPD_DISCONNECT; goto cleanup; } if( BER_BVISNULL( &op->orb_mech ) || BER_BVISEMPTY( &op->orb_mech ) ) { Debug( LDAP_DEBUG_ANY, "do_bind: no sasl mechanism provided\n" ); send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED, "no SASL mechanism provided" ); goto cleanup; } /* check restrictions */ if( backend_check_restrictions( op, rs, &op->orb_mech ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); if ( op->o_conn->c_sasl_bind_in_progress ) { if( !bvmatch( &op->o_conn->c_sasl_bind_mech, &op->orb_mech ) ) { /* mechanism changed between bind steps */ slap_sasl_reset(op->o_conn); } } else { ber_dupbv(&op->o_conn->c_sasl_bind_mech, &op->orb_mech); } /* Set the bindop for the benefit of in-directory SASL lookups */ op->o_conn->c_sasl_bindop = op; ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); rs->sr_err = slap_sasl_bind( op, rs ); goto cleanup; } else { /* Not SASL, cancel any in-progress bind */ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); if ( !BER_BVISNULL( &op->o_conn->c_sasl_bind_mech ) ) { free( op->o_conn->c_sasl_bind_mech.bv_val ); BER_BVZERO( &op->o_conn->c_sasl_bind_mech ); } op->o_conn->c_sasl_bind_in_progress = 0; slap_sasl_reset( op->o_conn ); ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); } if ( op->orb_method == LDAP_AUTH_SIMPLE ) { BER_BVSTR( &op->orb_mech, "SIMPLE" ); /* accept "anonymous" binds */ if ( BER_BVISEMPTY( &op->orb_cred ) || BER_BVISEMPTY( &op->o_req_ndn ) ) { rs->sr_err = LDAP_SUCCESS; if( !BER_BVISEMPTY( &op->orb_cred ) && !( global_allows & SLAP_ALLOW_BIND_ANON_CRED )) { /* cred is not empty, disallow */ rs->sr_err = LDAP_INVALID_CREDENTIALS; } else if ( !BER_BVISEMPTY( &op->o_req_ndn ) && !( global_allows & SLAP_ALLOW_BIND_ANON_DN )) { /* DN is not empty, disallow */ rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "unauthenticated bind (DN with no password) disallowed"; } else if ( global_disallows & SLAP_DISALLOW_BIND_ANON ) { /* disallow */ rs->sr_err = LDAP_INAPPROPRIATE_AUTH; rs->sr_text = "anonymous bind disallowed"; } else { backend_check_restrictions( op, rs, &op->orb_mech ); } /* * we already forced connection to "anonymous", * just need to send success */ send_ldap_result( op, rs ); Debug( LDAP_DEBUG_TRACE, "do_bind: v%d anonymous bind\n", op->o_protocol ); goto cleanup; } else if ( global_disallows & SLAP_DISALLOW_BIND_SIMPLE ) { /* disallow simple authentication */ rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "unwilling to perform simple authentication"; send_ldap_result( op, rs ); Debug( LDAP_DEBUG_TRACE, "do_bind: v%d simple bind(%s) disallowed\n", op->o_protocol, op->o_req_ndn.bv_val ); goto cleanup; } } else { rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED; rs->sr_text = "unknown authentication method"; send_ldap_result( op, rs ); Debug( LDAP_DEBUG_TRACE, "do_bind: v%d unknown authentication method (%d)\n", op->o_protocol, op->orb_method ); goto cleanup; } /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ if ( (op->o_bd = select_backend( &op->o_req_ndn, 0 )) == NULL ) { /* don't return referral for bind requests */ /* noSuchObject is not allowed to be returned by bind */ rs->sr_err = LDAP_INVALID_CREDENTIALS; op->o_bd = bd; send_ldap_result( op, rs ); goto cleanup; } /* check restrictions */ if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } if( op->o_bd->be_bind ) { op->o_conn->c_authz_cookie = NULL; rs->sr_err = (op->o_bd->be_bind)( op, rs ); if ( rs->sr_err == 0 ) { (void)fe_op_bind_success( op, rs ); } else if ( !BER_BVISNULL( &op->orb_edn ) ) { free( op->orb_edn.bv_val ); BER_BVZERO( &op->orb_edn ); } } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "operation not supported within naming context" ); } cleanup:; op->o_bd = bd; return rs->sr_err; }
BerVarray referral_rewrite( BerVarray in, struct berval *base, struct berval *target, int scope ) { int i; BerVarray refs; struct berval *iv, *jv; if ( in == NULL ) { return NULL; } for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) { /* just count them */ } if ( i < 1 ) { return NULL; } refs = ch_malloc( ( i + 1 ) * sizeof( struct berval ) ); for ( iv = in, jv = refs; !BER_BVISNULL( iv ); iv++ ) { LDAPURLDesc *url; char *dn; int rc; rc = ldap_url_parse_ext( iv->bv_val, &url, LDAP_PVT_URL_PARSE_NONE ); if ( rc == LDAP_URL_ERR_BADSCHEME ) { ber_dupbv( jv++, iv ); continue; } else if ( rc != LDAP_URL_SUCCESS ) { continue; } dn = url->lud_dn; url->lud_dn = referral_dn_muck( ( dn && *dn ) ? dn : NULL, base, target ); ldap_memfree( dn ); if ( url->lud_scope == LDAP_SCOPE_DEFAULT ) { url->lud_scope = scope; } jv->bv_val = ldap_url_desc2str( url ); if ( jv->bv_val != NULL ) { jv->bv_len = strlen( jv->bv_val ); } else { ber_dupbv( jv, iv ); } jv++; ldap_free_urldesc( url ); } if ( jv == refs ) { ch_free( refs ); refs = NULL; } else { BER_BVZERO( jv ); } return refs; }
int mdb_search( Operation *op, SlapReply *rs ) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; ID id, cursor, nsubs, ncand, cscope; ID lastid = NOID; ID candidates[MDB_IDL_UM_SIZE]; ID iscopes[MDB_IDL_DB_SIZE]; ID2 *scopes; void *stack; Entry *e = NULL, *base = NULL; Entry *matched = NULL; AttributeName *attrs; slap_mask_t mask; time_t stoptime; int manageDSAit; int tentries = 0; IdScopes isc; MDB_cursor *mci, *mcd; ww_ctx wwctx; slap_callback cb = { 0 }; mdb_op_info opinfo = {{{0}}}, *moi = &opinfo; MDB_txn *ltid = NULL; Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_search) "\n", 0, 0, 0); attrs = op->oq_search.rs_attrs; manageDSAit = get_manageDSAit( op ); rs->sr_err = mdb_opinfo_get( op, mdb, 1, &moi ); switch(rs->sr_err) { case 0: break; default: send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); return rs->sr_err; } ltid = moi->moi_txn; rs->sr_err = mdb_cursor_open( ltid, mdb->mi_id2entry, &mci ); if ( rs->sr_err ) { send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); return rs->sr_err; } rs->sr_err = mdb_cursor_open( ltid, mdb->mi_dn2id, &mcd ); if ( rs->sr_err ) { mdb_cursor_close( mci ); send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); return rs->sr_err; } scopes = scope_chunk_get( op ); stack = search_stack( op ); isc.mt = ltid; isc.mc = mcd; isc.scopes = scopes; isc.oscope = op->ors_scope; isc.sctmp = stack; if ( op->ors_deref & LDAP_DEREF_FINDING ) { MDB_IDL_ZERO(candidates); } dn2entry_retry: /* get entry with reader lock */ rs->sr_err = mdb_dn2entry( op, ltid, mcd, &op->o_req_ndn, &e, &nsubs, 1 ); switch(rs->sr_err) { case MDB_NOTFOUND: matched = e; e = NULL; break; case 0: break; case LDAP_BUSY: send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" ); goto done; default: send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); goto done; } if ( op->ors_deref & LDAP_DEREF_FINDING ) { if ( matched && is_entry_alias( matched )) { struct berval stub; stub.bv_val = op->o_req_ndn.bv_val; stub.bv_len = op->o_req_ndn.bv_len - matched->e_nname.bv_len - 1; e = deref_base( op, rs, matched, &matched, ltid, candidates, NULL ); if ( e ) { build_new_dn( &op->o_req_ndn, &e->e_nname, &stub, op->o_tmpmemctx ); mdb_entry_return(op, e); matched = NULL; goto dn2entry_retry; } } else if ( e && is_entry_alias( e )) { e = deref_base( op, rs, e, &matched, ltid, candidates, NULL ); } } if ( e == NULL ) { struct berval matched_dn = BER_BVNULL; if ( matched != NULL ) { BerVarray erefs = NULL; /* return referral only if "disclose" * is granted on the object */ if ( ! access_allowed( op, matched, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } else { ber_dupbv( &matched_dn, &matched->e_name ); erefs = is_entry_referral( matched ) ? get_entry_referrals( op, matched ) : NULL; if ( rs->sr_err == MDB_NOTFOUND ) rs->sr_err = LDAP_REFERRAL; rs->sr_matched = matched_dn.bv_val; } mdb_entry_return(op, matched); matched = NULL; if ( erefs ) { rs->sr_ref = referral_rewrite( erefs, &matched_dn, &op->o_req_dn, op->oq_search.rs_scope ); ber_bvarray_free( erefs ); } } else { rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, op->oq_search.rs_scope ); rs->sr_err = rs->sr_ref != NULL ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT; } send_ldap_result( op, rs ); if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } if ( !BER_BVISNULL( &matched_dn ) ) { ber_memfree( matched_dn.bv_val ); rs->sr_matched = NULL; } goto done; } /* NOTE: __NEW__ "search" access is required * on searchBase object */ if ( ! access_allowed_mask( op, e, slap_schema.si_ad_entry, NULL, ACL_SEARCH, NULL, &mask ) ) { if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } else { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; } mdb_entry_return( op,e); send_ldap_result( op, rs ); goto done; } if ( !manageDSAit && is_entry_referral( e ) ) { /* entry is a referral */ struct berval matched_dn = BER_BVNULL; BerVarray erefs = NULL; ber_dupbv( &matched_dn, &e->e_name ); erefs = get_entry_referrals( op, e ); rs->sr_err = LDAP_REFERRAL; mdb_entry_return( op, e ); e = NULL; if ( erefs ) { rs->sr_ref = referral_rewrite( erefs, &matched_dn, &op->o_req_dn, op->oq_search.rs_scope ); ber_bvarray_free( erefs ); if ( !rs->sr_ref ) { rs->sr_text = "bad_referral object"; } } Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_search) ": entry is referral\n", 0, 0, 0 ); rs->sr_matched = matched_dn.bv_val; send_ldap_result( op, rs ); ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; ber_memfree( matched_dn.bv_val ); 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; mdb_entry_return( op,e); send_ldap_result( op, rs ); goto done; } /* compute it anyway; root does not use it */ stoptime = op->o_time + op->ors_tlimit; base = e; e = NULL; /* select candidates */ if ( op->oq_search.rs_scope == LDAP_SCOPE_BASE ) { rs->sr_err = base_candidate( op->o_bd, base, candidates ); scopes[0].mid = 0; ncand = 1; } else { if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) { size_t nkids; MDB_val key, data; key.mv_data = &base->e_id; key.mv_size = sizeof( ID ); mdb_cursor_get( mcd, &key, &data, MDB_SET ); mdb_cursor_count( mcd, &nkids ); nsubs = nkids - 1; } else if ( !base->e_id ) { /* we don't maintain nsubs for entryID 0. * just grab entry count from id2entry stat */ MDB_stat ms; mdb_stat( ltid, mdb->mi_id2entry, &ms ); nsubs = ms.ms_entries; } MDB_IDL_ZERO( candidates ); scopes[0].mid = 1; scopes[1].mid = base->e_id; scopes[1].mval.mv_data = NULL; rs->sr_err = search_candidates( op, rs, base, &isc, mci, candidates, stack ); ncand = MDB_IDL_N( candidates ); if ( !base->e_id || ncand == NOID ) { /* grab entry count from id2entry stat */ MDB_stat ms; mdb_stat( ltid, mdb->mi_id2entry, &ms ); if ( !base->e_id ) nsubs = ms.ms_entries; if ( ncand == NOID ) ncand = ms.ms_entries; } } /* start cursor at beginning of candidates. */ cursor = 0; if ( candidates[0] == 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_search) ": no candidates\n", 0, 0, 0 ); goto nochange; } /* if not root and candidates exceed to-be-checked entries, abort */ if ( op->ors_limit /* isroot == FALSE */ && op->ors_limit->lms_s_unchecked != -1 && ncand > (unsigned) op->ors_limit->lms_s_unchecked ) { rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; send_ldap_result( op, rs ); rs->sr_err = LDAP_SUCCESS; goto done; } if ( op->ors_limit == NULL /* isroot == TRUE */ || !op->ors_limit->lms_s_pr_hide ) { tentries = ncand; } wwctx.flag = 0; /* If we're running in our own read txn */ if ( moi == &opinfo ) { cb.sc_writewait = mdb_writewait; cb.sc_private = &wwctx; wwctx.txn = ltid; wwctx.mcd = NULL; cb.sc_next = op->o_callback; op->o_callback = &cb; } if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { PagedResultsState *ps = op->o_pagedresults_state; /* deferred cookie parsing */ rs->sr_err = parse_paged_cookie( op, rs ); if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto done; } cursor = (ID) ps->ps_cookie; if ( cursor && ps->ps_size == 0 ) { rs->sr_err = LDAP_SUCCESS; rs->sr_text = "search abandoned by pagedResult size=0"; send_ldap_result( op, rs ); goto done; } id = mdb_idl_first( candidates, &cursor ); if ( id == NOID ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_search) ": no paged results candidates\n", 0, 0, 0 ); send_paged_response( op, rs, &lastid, 0 ); rs->sr_err = LDAP_OTHER; goto done; } if ( id == (ID)ps->ps_cookie ) id = mdb_idl_next( candidates, &cursor ); nsubs = ncand; /* always bypass scope'd search */ goto loop_begin; } if ( nsubs < ncand ) { int rc; /* Do scope-based search */ /* if any alias scopes were set, save them */ if (scopes[0].mid > 1) { cursor = 1; for (cscope = 1; cscope <= scopes[0].mid; cscope++) { /* Ignore the original base */ if (scopes[cscope].mid == base->e_id) continue; iscopes[cursor++] = scopes[cscope].mid; } iscopes[0] = scopes[0].mid - 1; } else { iscopes[0] = 0; } wwctx.mcd = mcd; isc.id = base->e_id; isc.numrdns = 0; rc = mdb_dn2id_walk( op, &isc ); if ( rc ) id = NOID; else id = isc.id; cscope = 0; } else { id = mdb_idl_first( candidates, &cursor ); } while (id != NOID) { int scopeok; MDB_val edata; loop_begin: /* check for abandon */ if ( op->o_abandon ) { rs->sr_err = SLAPD_ABANDON; send_ldap_result( op, rs ); goto done; } /* mostly needed by internal searches, * e.g. related to syncrepl, for whom * abandon does not get set... */ if ( slapd_shutdown ) { rs->sr_err = LDAP_UNAVAILABLE; send_ldap_disconnect( op, rs ); goto done; } /* check time limit */ if ( op->ors_tlimit != SLAP_NO_LIMIT && slap_get_time() > stoptime ) { rs->sr_err = LDAP_TIMELIMIT_EXCEEDED; rs->sr_ref = rs->sr_v2ref; send_ldap_result( op, rs ); rs->sr_err = LDAP_SUCCESS; goto done; } if ( nsubs < ncand ) { unsigned i; /* Is this entry in the candidate list? */ scopeok = 0; if (MDB_IDL_IS_RANGE( candidates )) { if ( id >= MDB_IDL_RANGE_FIRST( candidates ) && id <= MDB_IDL_RANGE_LAST( candidates )) scopeok = 1; } else { i = mdb_idl_search( candidates, id ); if ( candidates[i] == id ) scopeok = 1; } if ( scopeok ) goto scopeok; goto loop_continue; } /* Does this candidate actually satisfy the search scope? */ scopeok = 0; isc.numrdns = 0; switch( op->ors_scope ) { case LDAP_SCOPE_BASE: /* This is always true, yes? */ if ( id == base->e_id ) scopeok = 1; break; #ifdef LDAP_SCOPE_CHILDREN case LDAP_SCOPE_CHILDREN: if ( id == base->e_id ) break; /* Fall-thru */ #endif case LDAP_SCOPE_SUBTREE: if ( id == base->e_id ) { scopeok = 1; break; } /* Fall-thru */ case LDAP_SCOPE_ONELEVEL: isc.id = id; isc.nscope = 0; rs->sr_err = mdb_idscopes( op, &isc ); if ( rs->sr_err == MDB_SUCCESS ) { if ( isc.nscope ) scopeok = 1; } else { if ( rs->sr_err == MDB_NOTFOUND ) goto notfound; } break; } /* Not in scope, ignore it */ if ( !scopeok ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_search) ": %ld scope not okay\n", (long) id, 0, 0 ); goto loop_continue; } scopeok: if ( id == base->e_id ) { e = base; } else { /* get the entry */ rs->sr_err = mdb_id2edata( op, mci, id, &edata ); if ( rs->sr_err == MDB_NOTFOUND ) { notfound: if( nsubs < ncand ) goto loop_continue; if( !MDB_IDL_IS_RANGE(candidates) ) { /* only complain for non-range IDLs */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_search) ": candidate %ld not found\n", (long) id, 0, 0 ); } else { /* get the next ID from the DB */ rs->sr_err = mdb_get_nextid( mci, &cursor ); if ( rs->sr_err == MDB_NOTFOUND ) { break; } if ( rs->sr_err ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error in get_nextid"; send_ldap_result( op, rs ); goto done; } cursor--; } goto loop_continue; } else if ( rs->sr_err ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error in mdb_id2edata"; send_ldap_result( op, rs ); goto done; } rs->sr_err = mdb_entry_decode( op, ltid, &edata, &e ); if ( rs->sr_err ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error in mdb_entry_decode"; send_ldap_result( op, rs ); goto done; } e->e_id = id; e->e_name.bv_val = NULL; e->e_nname.bv_val = NULL; } if ( is_entry_subentry( e ) ) { if( op->oq_search.rs_scope != LDAP_SCOPE_BASE ) { if(!get_subentries_visibility( op )) { /* only subentries are visible */ goto loop_continue; } } else if ( get_subentries( op ) && !get_subentries_visibility( op )) { /* only subentries are visible */ goto loop_continue; } } else if ( get_subentries_visibility( op )) { /* only subentries are visible */ goto loop_continue; } /* aliases were already dereferenced in candidate list */ if ( op->ors_deref & LDAP_DEREF_SEARCHING ) { /* but if the search base is an alias, and we didn't * deref it when finding, return it. */ if ( is_entry_alias(e) && ((op->ors_deref & LDAP_DEREF_FINDING) || e != base )) { goto loop_continue; } } if ( !manageDSAit && is_entry_glue( e )) { goto loop_continue; } if (e != base) { struct berval pdn, pndn; char *d, *n; int i; /* child of base, just append RDNs to base->e_name */ if ( nsubs < ncand || isc.scopes[isc.nscope].mid == base->e_id ) { pdn = base->e_name; pndn = base->e_nname; } else { mdb_id2name( op, ltid, &isc.mc, scopes[isc.nscope].mid, &pdn, &pndn ); } e->e_name.bv_len = pdn.bv_len; e->e_nname.bv_len = pndn.bv_len; for (i=0; i<isc.numrdns; i++) { e->e_name.bv_len += isc.rdns[i].bv_len + 1; e->e_nname.bv_len += isc.nrdns[i].bv_len + 1; } e->e_name.bv_val = op->o_tmpalloc(e->e_name.bv_len + 1, op->o_tmpmemctx); e->e_nname.bv_val = op->o_tmpalloc(e->e_nname.bv_len + 1, op->o_tmpmemctx); d = e->e_name.bv_val; n = e->e_nname.bv_val; if (nsubs < ncand) { /* RDNs are in top-down order */ for (i=isc.numrdns-1; i>=0; i--) { memcpy(d, isc.rdns[i].bv_val, isc.rdns[i].bv_len); d += isc.rdns[i].bv_len; *d++ = ','; memcpy(n, isc.nrdns[i].bv_val, isc.nrdns[i].bv_len); n += isc.nrdns[i].bv_len; *n++ = ','; } } else { /* RDNs are in bottom-up order */ for (i=0; i<isc.numrdns; i++) { memcpy(d, isc.rdns[i].bv_val, isc.rdns[i].bv_len); d += isc.rdns[i].bv_len; *d++ = ','; memcpy(n, isc.nrdns[i].bv_val, isc.nrdns[i].bv_len); n += isc.nrdns[i].bv_len; *n++ = ','; } } if (pdn.bv_len) { memcpy(d, pdn.bv_val, pdn.bv_len+1); memcpy(n, pndn.bv_val, pndn.bv_len+1); } else { *--d = '\0'; *--n = '\0'; e->e_name.bv_len--; e->e_nname.bv_len--; } if (pndn.bv_val != base->e_nname.bv_val) { op->o_tmpfree(pndn.bv_val, op->o_tmpmemctx); op->o_tmpfree(pdn.bv_val, op->o_tmpmemctx); } } /* * if it's a referral, add it to the list of referrals. only do * this for non-base searches, and don't check the filter * explicitly here since it's only a candidate anyway. */ if ( !manageDSAit && op->oq_search.rs_scope != LDAP_SCOPE_BASE && is_entry_referral( e ) ) { BerVarray erefs = get_entry_referrals( op, e ); rs->sr_ref = referral_rewrite( erefs, &e->e_name, NULL, op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE ); rs->sr_entry = e; rs->sr_flags = 0; send_search_reference( op, rs ); if (e != base) mdb_entry_return( op, e ); rs->sr_entry = NULL; e = NULL; ber_bvarray_free( rs->sr_ref ); ber_bvarray_free( erefs ); rs->sr_ref = NULL; if ( wwctx.flag ) { rs->sr_err = mdb_waitfixup( op, &wwctx, mci, mcd ); if ( rs->sr_err ) { send_ldap_result( op, rs ); goto done; } } goto loop_continue; } /* if it matches the filter and scope, send it */ rs->sr_err = test_filter( op, e, op->oq_search.rs_filter ); if ( rs->sr_err == LDAP_COMPARE_TRUE ) { /* check size limit */ if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) { mdb_entry_return( op, e ); e = NULL; send_paged_response( op, rs, &lastid, tentries ); goto done; } lastid = id; } if (e) { /* safe default */ rs->sr_attrs = op->oq_search.rs_attrs; rs->sr_operational_attrs = NULL; rs->sr_ctrls = NULL; rs->sr_entry = e; RS_ASSERT( e->e_private != NULL ); rs->sr_flags = 0; rs->sr_err = LDAP_SUCCESS; rs->sr_err = send_search_entry( op, rs ); rs->sr_attrs = NULL; rs->sr_entry = NULL; if (e != base) mdb_entry_return( op, e ); e = NULL; switch ( rs->sr_err ) { case LDAP_SUCCESS: /* entry sent ok */ break; default: /* entry not sent */ break; case LDAP_BUSY: send_ldap_result( op, rs ); goto done; case LDAP_UNAVAILABLE: case LDAP_SIZELIMIT_EXCEEDED: if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) { rs->sr_ref = rs->sr_v2ref; send_ldap_result( op, rs ); rs->sr_err = LDAP_SUCCESS; } else { rs->sr_err = LDAP_OTHER; } goto done; } if ( wwctx.flag ) { rs->sr_err = mdb_waitfixup( op, &wwctx, mci, mcd ); if ( rs->sr_err ) { send_ldap_result( op, rs ); goto done; } } } } else { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_search) ": %ld does not match filter\n", (long) id, 0, 0 ); } loop_continue: if( e != NULL ) { if ( e != base ) mdb_entry_return( op, e ); RS_ASSERT( rs->sr_entry == NULL ); e = NULL; rs->sr_entry = NULL; } if ( nsubs < ncand ) { int rc = mdb_dn2id_walk( op, &isc ); if (rc) { id = NOID; /* We got to the end of a subtree. If there are any * alias scopes left, search them too. */ while (iscopes[0] && cscope < iscopes[0]) { cscope++; isc.id = iscopes[cscope]; if ( base ) mdb_entry_return( op, base ); rs->sr_err = mdb_id2entry(op, mci, isc.id, &base); if ( !rs->sr_err ) { mdb_id2name( op, ltid, &isc.mc, isc.id, &base->e_name, &base->e_nname ); isc.numrdns = 0; if (isc.oscope == LDAP_SCOPE_ONELEVEL) isc.oscope = LDAP_SCOPE_BASE; rc = mdb_dn2id_walk( op, &isc ); if ( !rc ) { id = isc.id; break; } } } } else id = isc.id; } else { id = mdb_idl_next( candidates, &cursor ); } } nochange: rs->sr_ctrls = NULL; rs->sr_ref = rs->sr_v2ref; rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL; rs->sr_rspoid = NULL; if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { send_paged_response( op, rs, NULL, 0 ); } else { send_ldap_result( op, rs ); } rs->sr_err = LDAP_SUCCESS; done: if ( cb.sc_private ) { /* remove our writewait callback */ slap_callback **scp = &op->o_callback; while ( *scp ) { if ( *scp == &cb ) { *scp = cb.sc_next; cb.sc_private = NULL; break; } } } mdb_cursor_close( mcd ); mdb_cursor_close( mci ); if ( moi == &opinfo ) { mdb_txn_reset( moi->moi_txn ); LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next ); } else { moi->moi_ref--; } if( rs->sr_v2ref ) { ber_bvarray_free( rs->sr_v2ref ); rs->sr_v2ref = NULL; } if (base) mdb_entry_return( op, base ); scope_chunk_ret( op, scopes ); return rs->sr_err; }
int slap_modrdn2mods( Operation *op, SlapReply *rs ) { int a_cnt, d_cnt; LDAPRDN old_rdn = NULL; LDAPRDN new_rdn = NULL; assert( !BER_BVISEMPTY( &op->oq_modrdn.rs_newrdn ) ); /* if requestDN is empty, silently reset deleteOldRDN */ if ( BER_BVISEMPTY( &op->o_req_dn ) ) op->orr_deleteoldrdn = 0; if ( ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn, (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) { Debug( LDAP_DEBUG_TRACE, "%s slap_modrdn2mods: can't figure out " "type(s)/value(s) of newrdn\n", op->o_log_prefix, 0, 0 ); rs->sr_err = LDAP_INVALID_DN_SYNTAX; rs->sr_text = "unknown type(s)/value(s) used in RDN"; goto done; } if ( op->oq_modrdn.rs_deleteoldrdn ) { if ( ldap_bv2rdn_x( &op->o_req_dn, &old_rdn, (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) { Debug( LDAP_DEBUG_TRACE, "%s slap_modrdn2mods: can't figure out " "type(s)/value(s) of oldrdn\n", op->o_log_prefix, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "cannot parse RDN from old DN"; goto done; } } rs->sr_text = NULL; /* Add new attribute values to the entry */ for ( a_cnt = 0; new_rdn[a_cnt]; a_cnt++ ) { AttributeDescription *desc = NULL; Modifications *mod_tmp; rs->sr_err = slap_bv2ad( &new_rdn[a_cnt]->la_attr, &desc, &rs->sr_text ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "%s slap_modrdn2mods: %s: %s (new)\n", op->o_log_prefix, rs->sr_text, new_rdn[ a_cnt ]->la_attr.bv_val ); goto done; } if ( !desc->ad_type->sat_equality ) { Debug( LDAP_DEBUG_TRACE, "%s slap_modrdn2mods: %s: %s (new)\n", op->o_log_prefix, rs->sr_text, new_rdn[ a_cnt ]->la_attr.bv_val ); rs->sr_text = "naming attribute has no equality matching rule"; rs->sr_err = LDAP_NAMING_VIOLATION; goto done; } /* Apply modification */ mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) ); mod_tmp->sml_desc = desc; BER_BVZERO( &mod_tmp->sml_type ); mod_tmp->sml_numvals = 1; mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod_tmp->sml_values[0], &new_rdn[a_cnt]->la_value ); mod_tmp->sml_values[1].bv_val = NULL; if( desc->ad_type->sat_equality->smr_normalize) { mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) ); rs->sr_err = desc->ad_type->sat_equality->smr_normalize( SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, desc->ad_type->sat_syntax, desc->ad_type->sat_equality, &mod_tmp->sml_values[0], &mod_tmp->sml_nvalues[0], NULL ); if (rs->sr_err != LDAP_SUCCESS) { ch_free(mod_tmp->sml_nvalues); ch_free(mod_tmp->sml_values[0].bv_val); ch_free(mod_tmp->sml_values); ch_free(mod_tmp); goto done; } mod_tmp->sml_nvalues[1].bv_val = NULL; } else { mod_tmp->sml_nvalues = NULL; } mod_tmp->sml_op = SLAP_MOD_SOFTADD; mod_tmp->sml_flags = 0; mod_tmp->sml_next = op->orr_modlist; op->orr_modlist = mod_tmp; } /* Remove old rdn value if required */ if ( op->orr_deleteoldrdn ) { for ( d_cnt = 0; old_rdn[d_cnt]; d_cnt++ ) { AttributeDescription *desc = NULL; Modifications *mod_tmp; rs->sr_err = slap_bv2ad( &old_rdn[d_cnt]->la_attr, &desc, &rs->sr_text ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "%s slap_modrdn2mods: %s: %s (old)\n", op->o_log_prefix, rs->sr_text, old_rdn[d_cnt]->la_attr.bv_val ); goto done; } /* Apply modification */ mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) ); mod_tmp->sml_desc = desc; BER_BVZERO( &mod_tmp->sml_type ); mod_tmp->sml_numvals = 1; mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod_tmp->sml_values[0], &old_rdn[d_cnt]->la_value ); mod_tmp->sml_values[1].bv_val = NULL; if( desc->ad_type->sat_equality->smr_normalize) { mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) ); (void) (*desc->ad_type->sat_equality->smr_normalize)( SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, desc->ad_type->sat_syntax, desc->ad_type->sat_equality, &mod_tmp->sml_values[0], &mod_tmp->sml_nvalues[0], NULL ); mod_tmp->sml_nvalues[1].bv_val = NULL; } else { mod_tmp->sml_nvalues = NULL; } mod_tmp->sml_op = LDAP_MOD_DELETE; mod_tmp->sml_flags = 0; mod_tmp->sml_next = op->orr_modlist; op->orr_modlist = mod_tmp; } } done: /* LDAP v2 supporting correct attribute handling. */ if ( rs->sr_err != LDAP_SUCCESS && op->orr_modlist != NULL ) { Modifications *tmp; for ( ; op->orr_modlist != NULL; op->orr_modlist = tmp ) { tmp = op->orr_modlist->sml_next; ch_free( op->orr_modlist ); } } if ( new_rdn != NULL ) { ldap_rdnfree_x( new_rdn, op->o_tmpmemctx ); } if ( old_rdn != NULL ) { ldap_rdnfree_x( old_rdn, op->o_tmpmemctx ); } return rs->sr_err; }
int bdb_bind( Operation *op, SlapReply *rs ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; Entry *e; Attribute *a; EntryInfo *ei; AttributeDescription *password = slap_schema.si_ad_userPassword; DB_TXN *rtxn; DB_LOCK lock; Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(bdb_bind) ": dn: %s\n", op->o_req_dn.bv_val, 0, 0); /* allow noauth binds */ switch ( be_rootdn_bind( op, NULL ) ) { case LDAP_SUCCESS: /* frontend will send result */ return rs->sr_err = LDAP_SUCCESS; default: /* give the database a chance */ /* NOTE: this behavior departs from that of other backends, * since the others, in case of password checking failure * do not give the database a chance. If an entry with * rootdn's name does not exist in the database the result * will be the same. See ITS#4962 for discussion. */ break; } rs->sr_err = bdb_reader_get(op, bdb->bi_dbenv, &rtxn); switch(rs->sr_err) { case 0: break; default: rs->sr_text = "internal error"; send_ldap_result( op, rs ); return rs->sr_err; } dn2entry_retry: /* get entry with reader lock */ rs->sr_err = bdb_dn2entry( op, rtxn, &op->o_req_ndn, &ei, 1, &lock ); switch(rs->sr_err) { case DB_NOTFOUND: case 0: break; case LDAP_BUSY: send_ldap_error( op, rs, LDAP_BUSY, "ldap_server_busy" ); return LDAP_BUSY; case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto dn2entry_retry; default: send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); return rs->sr_err; } e = ei->bei_e; if ( rs->sr_err == DB_NOTFOUND ) { if( e != NULL ) { bdb_cache_return_entry_r( bdb, e, &lock ); e = NULL; } rs->sr_err = LDAP_INVALID_CREDENTIALS; send_ldap_result( op, rs ); return rs->sr_err; } ber_dupbv( &op->oq_bind.rb_edn, &e->e_name ); /* check for deleted */ if ( is_entry_subentry( e ) ) { /* entry is an subentry, don't allow bind */ Debug( LDAP_DEBUG_TRACE, "entry is subentry\n", 0, 0, 0 ); rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } if ( is_entry_alias( e ) ) { /* entry is an alias, don't allow bind */ Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 ); rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } if ( is_entry_referral( e ) ) { Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, 0, 0 ); rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } switch ( op->oq_bind.rb_method ) { case LDAP_AUTH_SIMPLE: a = attr_find( e->e_attrs, password ); if ( a == NULL ) { rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } if ( slap_passwd_check( op, e, a, &op->oq_bind.rb_cred, &rs->sr_text ) != 0 ) { /* failure; stop front end from sending result */ rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } rs->sr_err = 0; break; default: assert( 0 ); /* should not be reachable */ rs->sr_err = LDAP_STRONG_AUTH_NOT_SUPPORTED; rs->sr_text = "authentication method not supported"; } done: /* free entry and reader lock */ if( e != NULL ) { bdb_cache_return_entry_r( bdb, e, &lock ); } if ( rs->sr_err ) { send_ldap_result( op, rs ); if ( rs->sr_ref ) { ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; } } /* front end will send result on success (rs->sr_err==0) */ return rs->sr_err; }
/* Called for all modify and modrdn ops. If the current op was replicated * from elsewhere, all of the attrs should already be present. */ void slap_mods_opattrs( Operation *op, Modifications **modsp, int manage_ctxcsn ) { struct berval name, timestamp, csn = BER_BVNULL; struct berval nname; char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ]; Modifications *mod, **modtail, *modlast; int gotcsn = 0, gotmname = 0, gotmtime = 0; if ( SLAP_LASTMOD( op->o_bd ) && !op->orm_no_opattrs ) { char *ptr; timestamp.bv_val = timebuf; for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) { if ( (*modtail)->sml_op != LDAP_MOD_ADD && (*modtail)->sml_op != SLAP_MOD_SOFTADD && (*modtail)->sml_op != SLAP_MOD_ADD_IF_NOT_PRESENT && (*modtail)->sml_op != LDAP_MOD_REPLACE ) { continue; } if ( (*modtail)->sml_desc == slap_schema.si_ad_entryCSN ) { csn = (*modtail)->sml_values[0]; gotcsn = 1; } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifiersName ) { gotmname = 1; } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifyTimestamp ) { gotmtime = 1; } } if ( BER_BVISEMPTY( &op->o_csn )) { if ( !gotcsn ) { csn.bv_val = csnbuf; csn.bv_len = sizeof( csnbuf ); slap_get_csn( op, &csn, manage_ctxcsn ); } else { if ( manage_ctxcsn ) { slap_queue_csn( op, &csn ); } } } else { csn = op->o_csn; } ptr = ber_bvchr( &csn, '#' ); if ( ptr ) { timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ"); AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len ); timebuf[timestamp.bv_len-1] = 'Z'; timebuf[timestamp.bv_len] = '\0'; } else { time_t now = slap_get_time(); timestamp.bv_len = sizeof(timebuf); slap_timestamp( &now, ×tamp ); } if ( BER_BVISEMPTY( &op->o_dn ) ) { BER_BVSTR( &name, SLAPD_ANONYMOUS ); nname = name; } else { name = op->o_dn; nname = op->o_ndn; } if ( !gotcsn ) { mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); mod->sml_op = LDAP_MOD_REPLACE; mod->sml_flags = SLAP_MOD_INTERNAL; mod->sml_next = NULL; BER_BVZERO( &mod->sml_type ); mod->sml_desc = slap_schema.si_ad_entryCSN; mod->sml_numvals = 1; mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_values[0], &csn ); BER_BVZERO( &mod->sml_values[1] ); assert( !BER_BVISNULL( &mod->sml_values[0] ) ); mod->sml_nvalues = NULL; *modtail = mod; modlast = mod; modtail = &mod->sml_next; } if ( !gotmname ) { mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); mod->sml_op = LDAP_MOD_REPLACE; mod->sml_flags = SLAP_MOD_INTERNAL; mod->sml_next = NULL; BER_BVZERO( &mod->sml_type ); mod->sml_desc = slap_schema.si_ad_modifiersName; mod->sml_numvals = 1; mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_values[0], &name ); BER_BVZERO( &mod->sml_values[1] ); assert( !BER_BVISNULL( &mod->sml_values[0] ) ); mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_nvalues[0], &nname ); BER_BVZERO( &mod->sml_nvalues[1] ); assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) ); *modtail = mod; modtail = &mod->sml_next; } if ( !gotmtime ) { mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); mod->sml_op = LDAP_MOD_REPLACE; mod->sml_flags = SLAP_MOD_INTERNAL; mod->sml_next = NULL; BER_BVZERO( &mod->sml_type ); mod->sml_desc = slap_schema.si_ad_modifyTimestamp; mod->sml_numvals = 1; mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( &mod->sml_values[0], ×tamp ); BER_BVZERO( &mod->sml_values[1] ); assert( !BER_BVISNULL( &mod->sml_values[0] ) ); mod->sml_nvalues = NULL; *modtail = mod; modtail = &mod->sml_next; } } }
static int aa_operational( Operation *op, SlapReply *rs ) { Attribute *a, **ap; AccessControlState acl_state = ACL_STATE_INIT; struct berval *v; AttributeType **atp = NULL; ObjectClass **ocp = NULL; #define GOT_NONE (0x0U) #define GOT_C (0x1U) #define GOT_CE (0x2U) #define GOT_A (0x4U) #define GOT_AE (0x8U) #define GOT_ALL (GOT_C|GOT_CE|GOT_A|GOT_AE) int got = GOT_NONE; /* only add if requested */ if ( SLAP_OPATTRS( rs->sr_attr_flags ) ) { got = GOT_ALL; } else { if ( ad_inlist( ad_allowedChildClasses, rs->sr_attrs ) ) { got |= GOT_C; } if ( ad_inlist( ad_allowedChildClassesEffective, rs->sr_attrs ) ) { got |= GOT_CE; } if ( ad_inlist( ad_allowedAttributes, rs->sr_attrs ) ) { got |= GOT_A; } if ( ad_inlist( ad_allowedAttributesEffective, rs->sr_attrs ) ) { got |= GOT_AE; } } if ( got == GOT_NONE ) { return SLAP_CB_CONTINUE; } /* shouldn't be called without an entry; please check */ assert( rs->sr_entry != NULL ); for ( ap = &rs->sr_operational_attrs; *ap != NULL; ap = &(*ap)->a_next ) /* go to last */ ; /* see caveats; this is not guaranteed for all backends */ a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass ); if ( a == NULL ) { goto do_oc; } /* if client has no access to objectClass attribute; don't compute */ if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_objectClass, NULL, ACL_READ, &acl_state ) ) { return SLAP_CB_CONTINUE; } for ( v = a->a_nvals; !BER_BVISNULL( v ); v++ ) { ObjectClass *oc = oc_bvfind( v ); assert( oc != NULL ); /* if client has no access to specific value, don't compute */ if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_objectClass, &oc->soc_cname, ACL_READ, &acl_state ) ) { continue; } aa_add_oc( oc, &ocp, &atp ); if ( oc->soc_sups ) { int i; for ( i = 0; oc->soc_sups[ i ] != NULL; i++ ) { aa_add_oc( oc->soc_sups[ i ], &ocp, &atp ); } } } ch_free( ocp ); if ( atp != NULL ) { BerVarray bv_allowed = NULL, bv_effective = NULL; int i, ja = 0, je = 0; for ( i = 0; atp[ i ] != NULL; i++ ) /* just count */ ; if ( got & GOT_A ) { bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); } if ( got & GOT_AE ) { bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); } for ( i = 0, ja = 0, je = 0; atp[ i ] != NULL; i++ ) { if ( got & GOT_A ) { ber_dupbv( &bv_allowed[ ja ], &atp[ i ]->sat_cname ); ja++; } if ( got & GOT_AE ) { AttributeDescription *ad = NULL; const char *text = NULL; if ( slap_bv2ad( &atp[ i ]->sat_cname, &ad, &text ) ) { /* log? */ continue; } if ( access_allowed( op, rs->sr_entry, ad, NULL, ACL_WRITE, NULL ) ) { ber_dupbv( &bv_effective[ je ], &atp[ i ]->sat_cname ); je++; } } } ch_free( atp ); if ( ( got & GOT_A ) && ja > 0 ) { BER_BVZERO( &bv_allowed[ ja ] ); *ap = attr_alloc( ad_allowedAttributes ); (*ap)->a_vals = bv_allowed; (*ap)->a_nvals = bv_allowed; (*ap)->a_numvals = ja; ap = &(*ap)->a_next; } if ( ( got & GOT_AE ) && je > 0 ) { BER_BVZERO( &bv_effective[ je ] ); *ap = attr_alloc( ad_allowedAttributesEffective ); (*ap)->a_vals = bv_effective; (*ap)->a_nvals = bv_effective; (*ap)->a_numvals = je; ap = &(*ap)->a_next; } *ap = NULL; } do_oc:; if ( ( got & GOT_C ) || ( got & GOT_CE ) ) { BerVarray bv_allowed = NULL, bv_effective = NULL; int i, ja = 0, je = 0; ObjectClass *oc; for ( oc_start( &oc ); oc != NULL; oc_next( &oc ) ) { /* we can only add AUXILIARY objectClasses */ if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) { continue; } i++; } if ( got & GOT_C ) { bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); } if ( got & GOT_CE ) { bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); } for ( oc_start( &oc ); oc != NULL; oc_next( &oc ) ) { /* we can only add AUXILIARY objectClasses */ if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) { continue; } if ( got & GOT_C ) { ber_dupbv( &bv_allowed[ ja ], &oc->soc_cname ); ja++; } if ( got & GOT_CE ) { if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_objectClass, &oc->soc_cname, ACL_WRITE, NULL ) ) { goto done_ce; } if ( oc->soc_required ) { for ( i = 0; oc->soc_required[ i ] != NULL; i++ ) { AttributeDescription *ad = NULL; const char *text = NULL; if ( slap_bv2ad( &oc->soc_required[ i ]->sat_cname, &ad, &text ) ) { /* log? */ continue; } if ( !access_allowed( op, rs->sr_entry, ad, NULL, ACL_WRITE, NULL ) ) { goto done_ce; } } } ber_dupbv( &bv_effective[ je ], &oc->soc_cname ); je++; } done_ce:; } if ( ( got & GOT_C ) && ja > 0 ) { BER_BVZERO( &bv_allowed[ ja ] ); *ap = attr_alloc( ad_allowedChildClasses ); (*ap)->a_vals = bv_allowed; (*ap)->a_nvals = bv_allowed; (*ap)->a_numvals = ja; ap = &(*ap)->a_next; } if ( ( got & GOT_CE ) && je > 0 ) { BER_BVZERO( &bv_effective[ je ] ); *ap = attr_alloc( ad_allowedChildClassesEffective ); (*ap)->a_vals = bv_effective; (*ap)->a_nvals = bv_effective; (*ap)->a_numvals = je; ap = &(*ap)->a_next; } *ap = NULL; } return SLAP_CB_CONTINUE; }
static int ndb_tool_next_id( Operation *op, NdbArgs *NA, struct berval *text, int hole ) { struct berval ndn = NA->e->e_nname; int rc; if (ndn.bv_len == 0) { NA->e->e_id = 0; return 0; } rc = ndb_entry_get_info( op, NA, 0, NULL ); if ( rc ) { Attribute *a, tmp = {0}; if ( !be_issuffix( op->o_bd, &ndn ) ) { struct dn_id *dptr; struct berval npdn; dnParent( &ndn, &npdn ); NA->e->e_nname = npdn; NA->rdns->nr_num--; rc = ndb_tool_next_id( op, NA, text, 1 ); NA->e->e_nname = ndn; NA->rdns->nr_num++; if ( rc ) { return rc; } /* If parent didn't exist, it was created just now * and its ID is now in e->e_id. */ dptr = (struct dn_id *)ch_malloc( sizeof( struct dn_id ) + npdn.bv_len + 1); dptr->id = NA->e->e_id; dptr->dn.bv_val = (char *)(dptr+1); strcpy(dptr->dn.bv_val, npdn.bv_val ); dptr->dn.bv_len = npdn.bv_len; if ( avl_insert( &myParents, dptr, ndb_dnid_cmp, avl_dup_error )) { ch_free( dptr ); } } rc = ndb_next_id( op->o_bd, myNdb, &NA->e->e_id ); if ( rc ) { snprintf( text->bv_val, text->bv_len, "next_id failed: %s (%d)", myNdb->getNdbError().message, myNdb->getNdbError().code ); Debug( LDAP_DEBUG_ANY, "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 ); return rc; } if ( hole ) { a = NA->e->e_attrs; NA->e->e_attrs = &tmp; tmp.a_desc = slap_schema.si_ad_objectClass; tmp.a_vals = glueval; tmp.a_nvals = tmp.a_vals; tmp.a_numvals = 1; } rc = ndb_entry_put_info( op->o_bd, NA, 0 ); if ( hole ) { NA->e->e_attrs = a; } if ( rc ) { snprintf( text->bv_val, text->bv_len, "ndb_entry_put_info failed: %s (%d)", myNdb->getNdbError().message, myNdb->getNdbError().code ); Debug( LDAP_DEBUG_ANY, "=> ndb_tool_next_id: %s\n", text->bv_val, 0, 0 ); } else if ( hole ) { if ( nholes == nhmax - 1 ) { if ( holes == hbuf ) { holes = (dn_id *)ch_malloc( nhmax * sizeof(dn_id) * 2 ); AC_MEMCPY( holes, hbuf, sizeof(hbuf) ); } else { holes = (dn_id *)ch_realloc( holes, nhmax * sizeof(dn_id) * 2 ); } nhmax *= 2; } ber_dupbv( &holes[nholes].dn, &ndn ); holes[nholes++].id = NA->e->e_id; } } else if ( !hole ) { unsigned i; for ( i=0; i<nholes; i++) { if ( holes[i].id == NA->e->e_id ) { int j; free(holes[i].dn.bv_val); for (j=i;j<nholes;j++) holes[j] = holes[j+1]; holes[j].id = 0; nholes--; rc = ndb_entry_put_info( op->o_bd, NA, 1 ); break; } else if ( holes[i].id > NA->e->e_id ) { break; } } } return rc; }
/* Parse an LDIF control line of the form control: oid [true/false] [: value] or control: oid [true/false] [:: base64-value] or control: oid [true/false] [:< url] The control is added to the list of controls in *ppctrls. */ static int parse_ldif_control( struct berval *bval, LDAPControl ***ppctrls ) { char *oid = NULL; int criticality = 0; /* Default is false if not present */ int i, rc=0; char *s, *oidStart; LDAPControl *newctrl = NULL; LDAPControl **pctrls = NULL; struct berval type, bv; int freeval; if (ppctrls) pctrls = *ppctrls; /* OID should come first. Validate and extract it. */ s = bval->bv_val; if (*s == 0) return ( LDAP_PARAM_ERROR ); oidStart = s; while (isdigit((unsigned char)*s) || *s == '.') { s++; /* OID should be digits or . */ } if (s == oidStart) { return ( LDAP_PARAM_ERROR ); /* OID was not present */ } if (*s) { /* End of OID should be space or NULL */ if (!isspace((unsigned char)*s)) { return ( LDAP_PARAM_ERROR ); /* else OID contained invalid chars */ } *s++ = 0; /* Replace space with null to terminate */ } oid = ber_strdup(oidStart); if (oid == NULL) return ( LDAP_NO_MEMORY ); /* Optional Criticality field is next. */ while (*s && isspace((unsigned char)*s)) { s++; /* Skip white space before criticality */ } if (strncasecmp(s, "true", 4) == 0) { criticality = 1; s += 4; } else if (strncasecmp(s, "false", 5) == 0) { criticality = 0; s += 5; } /* Optional value field is next */ while (*s && isspace((unsigned char)*s)) { s++; /* Skip white space before value */ } if (*s) { if (*s != ':') { /* If value is present, must start with : */ rc = LDAP_PARAM_ERROR; goto cleanup; } /* Back up so value is in the form a: value a:: base64-value a:< url Then we can use ldif_parse_line2 to extract and decode the value */ s--; *s = 'a'; rc = ldif_parse_line2(s, &type, &bv, &freeval); if (rc < 0) { rc = LDAP_PARAM_ERROR; goto cleanup; } } /* Create a new LDAPControl structure. */ newctrl = (LDAPControl *)ber_memalloc(sizeof(LDAPControl)); if ( newctrl == NULL ) { rc = LDAP_NO_MEMORY; goto cleanup; } newctrl->ldctl_oid = oid; oid = NULL; newctrl->ldctl_iscritical = criticality; if ( freeval ) newctrl->ldctl_value = bv; else ber_dupbv( &newctrl->ldctl_value, &bv ); /* Add the new control to the passed-in list of controls. */ i = 0; if (pctrls) { while ( pctrls[i] ) { /* Count the # of controls passed in */ i++; } } /* Allocate 1 more slot for the new control and 1 for the NULL. */ pctrls = (LDAPControl **) ber_memrealloc(pctrls, (i+2)*(sizeof(LDAPControl *))); if (pctrls == NULL) { rc = LDAP_NO_MEMORY; goto cleanup; } pctrls[i] = newctrl; newctrl = NULL; pctrls[i+1] = NULL; *ppctrls = pctrls; cleanup: if (newctrl) { if (newctrl->ldctl_oid) ber_memfree(newctrl->ldctl_oid); if (newctrl->ldctl_value.bv_val) { ber_memfree(newctrl->ldctl_value.bv_val); } ber_memfree(newctrl); } if (oid) ber_memfree(oid); return( rc ); }
void slapi_int_connection_init_pb( Slapi_PBlock *pb, ber_tag_t tag ) { Connection *conn; Operation *op; ber_len_t max = sockbuf_max_incoming; conn = (Connection *) slapi_ch_calloc( 1, sizeof(Connection) ); LDAP_STAILQ_INIT( &conn->c_pending_ops ); op = (Operation *) slapi_ch_calloc( 1, sizeof(OperationBuffer) ); op->o_hdr = &((OperationBuffer *) op)->ob_hdr; op->o_controls = ((OperationBuffer *) op)->ob_controls; op->o_callback = (slap_callback *) slapi_ch_calloc( 1, sizeof(slap_callback) ); op->o_callback->sc_response = slapi_int_response; op->o_callback->sc_cleanup = NULL; op->o_callback->sc_private = pb; op->o_callback->sc_next = NULL; conn->c_pending_ops.stqh_first = op; /* connection object authorization information */ conn->c_authtype = LDAP_AUTH_NONE; BER_BVZERO( &conn->c_authmech ); BER_BVZERO( &conn->c_dn ); BER_BVZERO( &conn->c_ndn ); conn->c_listener = &slapi_listener; ber_dupbv( &conn->c_peer_domain, (struct berval *)&slap_unknown_bv ); ber_dupbv( &conn->c_peer_name, (struct berval *)&slap_unknown_bv ); LDAP_STAILQ_INIT( &conn->c_ops ); BER_BVZERO( &conn->c_sasl_bind_mech ); conn->c_sasl_authctx = NULL; conn->c_sasl_sockctx = NULL; conn->c_sasl_extra = NULL; conn->c_sb = ber_sockbuf_alloc(); ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max ); conn->c_currentber = NULL; /* should check status of thread calls */ ldap_pvt_thread_mutex_init( &conn->c_mutex ); ldap_pvt_thread_mutex_init( &conn->c_write1_mutex ); ldap_pvt_thread_mutex_init( &conn->c_write2_mutex ); ldap_pvt_thread_cond_init( &conn->c_write1_cv ); ldap_pvt_thread_cond_init( &conn->c_write2_cv ); ldap_pvt_thread_mutex_lock( &conn->c_mutex ); conn->c_n_ops_received = 0; conn->c_n_ops_executing = 0; conn->c_n_ops_pending = 0; conn->c_n_ops_completed = 0; conn->c_n_get = 0; conn->c_n_read = 0; conn->c_n_write = 0; conn->c_protocol = LDAP_VERSION3; conn->c_activitytime = conn->c_starttime = slap_get_time(); /* * A real connection ID is required, because syncrepl associates * pending CSNs with unique ( connection, operation ) tuples. * Setting a fake connection ID will cause slap_get_commit_csn() * to return a stale value. */ connection_assign_nextid( conn ); conn->c_conn_state = 0x01; /* SLAP_C_ACTIVE */ conn->c_struct_state = 0x02; /* SLAP_C_USED */ conn->c_ssf = conn->c_transport_ssf = local_ssf; conn->c_tls_ssf = 0; backend_connection_init( conn ); conn->c_send_ldap_result = slap_send_ldap_result; conn->c_send_search_entry = slap_send_search_entry; conn->c_send_ldap_extended = slap_send_ldap_extended; conn->c_send_search_reference = slap_send_search_reference; /* operation object */ op->o_tag = tag; op->o_protocol = LDAP_VERSION3; BER_BVZERO( &op->o_authmech ); op->o_time = slap_get_time(); op->o_do_not_cache = 1; op->o_threadctx = ldap_pvt_thread_pool_context(); op->o_tmpmemctx = NULL; op->o_tmpmfuncs = &ch_mfuncs; op->o_conn = conn; op->o_connid = conn->c_connid; op->o_bd = frontendDB; /* extensions */ slapi_int_create_object_extensions( SLAPI_X_EXT_OPERATION, op ); slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, conn ); pb->pb_rs = (SlapReply *)slapi_ch_calloc( 1, sizeof(SlapReply) ); pb->pb_op = op; pb->pb_conn = conn; pb->pb_intop = 1; ldap_pvt_thread_mutex_unlock( &conn->c_mutex ); }
int bdb_db_cache( Backend *be, struct berval *name, DB **dbout ) { int i, flags; int rc; struct bdb_info *bdb = (struct bdb_info *) be->be_private; struct bdb_db_info *db; char *file; *dbout = NULL; for( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) { if( !ber_bvcmp( &bdb->bi_databases[i]->bdi_name, name) ) { *dbout = bdb->bi_databases[i]->bdi_db; return 0; } } ldap_pvt_thread_mutex_lock( &bdb->bi_database_mutex ); /* check again! may have been added by another thread */ for( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) { if( !ber_bvcmp( &bdb->bi_databases[i]->bdi_name, name) ) { *dbout = bdb->bi_databases[i]->bdi_db; ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); return 0; } } if( i >= BDB_INDICES ) { ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); return -1; } db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info)); ber_dupbv( &db->bdi_name, name ); rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "bdb_db_cache: db_create(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc ); ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); ch_free( db ); return rc; } if( !BER_BVISNULL( &bdb->bi_db_crypt_key )) { rc = db->bdi_db->set_flags( db->bdi_db, DB_ENCRYPT ); if ( rc ) { Debug( LDAP_DEBUG_ANY, "bdb_db_cache: db set_flags(DB_ENCRYPT)(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc ); ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); db->bdi_db->close( db->bdi_db, 0 ); ch_free( db ); return rc; } } if( bdb->bi_flags & BDB_CHKSUM ) { rc = db->bdi_db->set_flags( db->bdi_db, DB_CHKSUM ); if ( rc ) { Debug( LDAP_DEBUG_ANY, "bdb_db_cache: db set_flags(DB_CHKSUM)(%s) failed: %s (%d)\n", bdb->bi_dbenv_home, db_strerror(rc), rc ); ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); db->bdi_db->close( db->bdi_db, 0 ); ch_free( db ); return rc; } } /* If no explicit size set, use the FS default */ flags = bdb_db_findsize( bdb, name ); if ( flags ) rc = db->bdi_db->set_pagesize( db->bdi_db, flags ); #ifdef BDB_INDEX_USE_HASH rc = db->bdi_db->set_h_hash( db->bdi_db, bdb_db_hash ); #endif rc = db->bdi_db->set_flags( db->bdi_db, DB_DUP | DB_DUPSORT ); file = ch_malloc( db->bdi_name.bv_len + sizeof(BDB_SUFFIX) ); strcpy( file, db->bdi_name.bv_val ); strcpy( file+db->bdi_name.bv_len, BDB_SUFFIX ); #ifdef HAVE_EBCDIC __atoe( file ); #endif flags = DB_CREATE | DB_THREAD; #ifdef DB_AUTO_COMMIT if ( !( slapMode & SLAP_TOOL_QUICK )) flags |= DB_AUTO_COMMIT; #endif /* Cannot Truncate when Transactions are in use */ if ( (slapMode & (SLAP_TOOL_QUICK|SLAP_TRUNCATE_MODE)) == (SLAP_TOOL_QUICK|SLAP_TRUNCATE_MODE)) flags |= DB_TRUNCATE; rc = DB_OPEN( db->bdi_db, file, NULL /* name */, BDB_INDEXTYPE, bdb->bi_db_opflags | flags, bdb->bi_dbenv_mode ); ch_free( file ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "bdb_db_cache: db_open(%s) failed: %s (%d)\n", name->bv_val, db_strerror(rc), rc ); ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); db->bdi_db->close( db->bdi_db, 0 ); ch_free( db ); return rc; } bdb->bi_databases[i] = db; bdb->bi_ndatabases = i+1; *dbout = db->bdi_db; ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex ); return 0; }
extern "C" int ndb_back_bind( Operation *op, SlapReply *rs ) { struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private; Entry e = {0}; Attribute *a; AttributeDescription *password = slap_schema.si_ad_userPassword; NdbArgs NA; Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(ndb_back_bind) ": dn: %s\n", op->o_req_dn.bv_val, 0, 0); /* allow noauth binds */ switch ( be_rootdn_bind( op, NULL ) ) { case LDAP_SUCCESS: /* frontend will send result */ return rs->sr_err = LDAP_SUCCESS; default: /* give the database a chance */ break; } /* Get our NDB handle */ rs->sr_err = ndb_thread_handle( op, &NA.ndb ); e.e_name = op->o_req_dn; e.e_nname = op->o_req_ndn; NA.e = &e; dn2entry_retry: NA.txn = NA.ndb->startTransaction(); rs->sr_text = NULL; if( !NA.txn ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_bind) ": 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 done; } /* get entry */ { NdbRdns rdns; rdns.nr_num = 0; NA.rdns = &rdns; NA.ocs = NULL; rs->sr_err = ndb_entry_get_info( op, &NA, 0, NULL ); } switch(rs->sr_err) { case 0: break; case LDAP_NO_SUCH_OBJECT: rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; case LDAP_BUSY: rs->sr_text = "ldap_server_busy"; goto done; #if 0 case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto dn2entry_retry; #endif default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto done; } rs->sr_err = ndb_entry_get_data( op, &NA, 0 ); ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx ); ber_dupbv( &op->oq_bind.rb_edn, &e.e_name ); /* check for deleted */ if ( is_entry_subentry( &e ) ) { /* entry is an subentry, don't allow bind */ Debug( LDAP_DEBUG_TRACE, "entry is subentry\n", 0, 0, 0 ); rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } if ( is_entry_alias( &e ) ) { /* entry is an alias, don't allow bind */ Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 ); rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } if ( is_entry_referral( &e ) ) { Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, 0, 0 ); rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } switch ( op->oq_bind.rb_method ) { case LDAP_AUTH_SIMPLE: a = attr_find( e.e_attrs, password ); if ( a == NULL ) { rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } if ( slap_passwd_check( op, &e, a, &op->oq_bind.rb_cred, &rs->sr_text ) != 0 ) { /* failure; stop front end from sending result */ rs->sr_err = LDAP_INVALID_CREDENTIALS; goto done; } rs->sr_err = 0; break; default: assert( 0 ); /* should not be reachable */ rs->sr_err = LDAP_STRONG_AUTH_NOT_SUPPORTED; rs->sr_text = "authentication method not supported"; } done: NA.txn->close(); if ( e.e_attrs ) { attrs_free( e.e_attrs ); e.e_attrs = NULL; } if ( rs->sr_err ) { send_ldap_result( op, rs ); } /* front end will send result on success (rs->sr_err==0) */ return rs->sr_err; }
int do_bind( Operation *op, SlapReply *rs ) { BerElement *ber = op->o_ber; ber_int_t version; ber_tag_t method; struct berval mech = BER_BVNULL; struct berval dn = BER_BVNULL; ber_tag_t tag; Backend *be = NULL; Debug( LDAP_DEBUG_TRACE, "%s do_bind\n", op->o_log_prefix ); /* * Force the connection to "anonymous" until bind succeeds. */ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); if ( op->o_conn->c_sasl_bind_in_progress ) { be = op->o_conn->c_authz_backend; } if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) { /* log authorization identity demotion */ Statslog( LDAP_DEBUG_STATS, "%s BIND anonymous mech=implicit ssf=0\n", op->o_log_prefix ); } connection2anonymous( op->o_conn ); if ( op->o_conn->c_sasl_bind_in_progress ) { op->o_conn->c_authz_backend = be; } ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); if ( !BER_BVISNULL( &op->o_dn ) ) { /* NOTE: temporarily wasting few bytes * (until bind is completed), but saving * a couple of ch_free() and ch_strdup("") */ op->o_dn.bv_val[0] = '\0'; op->o_dn.bv_len = 0; } if ( !BER_BVISNULL( &op->o_ndn ) ) { op->o_ndn.bv_val[0] = '\0'; op->o_ndn.bv_len = 0; } /* * Parse the bind request. It looks like this: * * BindRequest ::= SEQUENCE { * version INTEGER, -- version * name DistinguishedName, -- dn * authentication CHOICE { * simple [0] OCTET STRING -- passwd * krbv42ldap [1] OCTET STRING -- OBSOLETE * krbv42dsa [2] OCTET STRING -- OBSOLETE * SASL [3] SaslCredentials * } * } * * SaslCredentials ::= SEQUENCE { * mechanism LDAPString, * credentials OCTET STRING OPTIONAL * } */ tag = ber_scanf( ber, "{imt" /*}*/, &version, &dn, &method ); if ( tag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n", op->o_log_prefix ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto cleanup; } op->o_protocol = version; op->orb_method = method; if( op->orb_method != LDAP_AUTH_SASL ) { tag = ber_scanf( ber, /*{*/ "m}", &op->orb_cred ); } else { tag = ber_scanf( ber, "{m" /*}*/, &mech ); if ( tag != LBER_ERROR ) { ber_len_t len; tag = ber_peek_tag( ber, &len ); if ( tag == LDAP_TAG_LDAPCRED ) { tag = ber_scanf( ber, "m", &op->orb_cred ); } else { tag = LDAP_TAG_LDAPCRED; BER_BVZERO( &op->orb_cred ); } if ( tag != LBER_ERROR ) { tag = ber_scanf( ber, /*{{*/ "}}" ); } } } if ( tag == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n", op->o_log_prefix ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); rs->sr_err = SLAPD_DISCONNECT; goto cleanup; } if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_bind: get_ctrls failed\n", op->o_log_prefix ); goto cleanup; } /* We use the tmpmemctx here because it speeds up normalization. * However, we must dup with regular malloc when storing any * resulting DNs in the op or conn structures. */ rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_bind: invalid dn (%s)\n", op->o_log_prefix, dn.bv_val ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); goto cleanup; } Statslog( LDAP_DEBUG_STATS, "%s BIND dn=\"%s\" method=%ld\n", op->o_log_prefix, op->o_req_dn.bv_val, (unsigned long) op->orb_method ); if( op->orb_method == LDAP_AUTH_SASL ) { Debug( LDAP_DEBUG_TRACE, "do_bind: dn (%s) SASL mech %s\n", op->o_req_dn.bv_val, mech.bv_val ); } else { Debug( LDAP_DEBUG_TRACE, "do_bind: version=%ld dn=\"%s\" method=%ld\n", (unsigned long) version, op->o_req_dn.bv_val, (unsigned long) op->orb_method ); } if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) { Debug( LDAP_DEBUG_ANY, "%s do_bind: unknown version=%ld\n", op->o_log_prefix, (unsigned long) version ); send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "requested protocol version not supported" ); goto cleanup; } else if (!( global_allows & SLAP_ALLOW_BIND_V2 ) && version < LDAP_VERSION3 ) { send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "historical protocol version requested, use LDAPv3 instead" ); goto cleanup; } /* * we set connection version regardless of whether bind succeeds or not. */ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); op->o_conn->c_protocol = version; ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); op->orb_mech = mech; op->o_bd = frontendDB; rs->sr_err = frontendDB->be_bind( op, rs ); cleanup: if ( rs->sr_err == LDAP_SUCCESS ) { if ( op->orb_method != LDAP_AUTH_SASL ) { ber_dupbv( &op->o_conn->c_authmech, &mech ); } op->o_conn->c_authtype = op->orb_method; } if( !BER_BVISNULL( &op->o_req_dn ) ) { slap_sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx ); BER_BVZERO( &op->o_req_dn ); } if( !BER_BVISNULL( &op->o_req_ndn ) ) { slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx ); BER_BVZERO( &op->o_req_ndn ); } return rs->sr_err; }
static int rc_cf_gen( ConfigArgs *c ) { slap_overinst *on = (slap_overinst *)c->bi; retcode_t *rd = (retcode_t *)on->on_bi.bi_private; int rc = ARG_BAD_CONF; if ( c->op == SLAP_CONFIG_EMIT ) { switch( c->type ) { case RC_PARENT: if ( !BER_BVISEMPTY( &rd->rd_pdn )) { rc = value_add_one( &c->rvalue_vals, &rd->rd_pdn ); if ( rc == 0 ) { rc = value_add_one( &c->rvalue_nvals, &rd->rd_npdn ); } return rc; } rc = 0; break; case RC_ITEM: { retcode_item_t *rdi; int i; for ( rdi = rd->rd_item, i = 0; rdi; rdi = rdi->rdi_next, i++ ) { char buf[4096]; struct berval bv; char *ptr; bv.bv_len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i ); bv.bv_len += rdi->rdi_line.bv_len; ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 ); ptr = lutil_strcopy( ptr, buf ); ptr = lutil_strncopy( ptr, rdi->rdi_line.bv_val, rdi->rdi_line.bv_len ); ber_bvarray_add( &c->rvalue_vals, &bv ); } rc = 0; } break; default: LDAP_BUG(); break; } return rc; } else if ( c->op == LDAP_MOD_DELETE ) { switch( c->type ) { case RC_PARENT: if ( rd->rd_pdn.bv_val ) { ber_memfree ( rd->rd_pdn.bv_val ); rc = 0; } if ( rd->rd_npdn.bv_val ) { ber_memfree ( rd->rd_npdn.bv_val ); } break; case RC_ITEM: if ( c->valx == -1 ) { retcode_item_t *rdi, *next; for ( rdi = rd->rd_item; rdi != NULL; rdi = next ) { next = rdi->rdi_next; retcode_item_destroy( rdi ); } } else { retcode_item_t **rdip, *rdi; int i; for ( rdip = &rd->rd_item, i = 0; i <= c->valx && *rdip; i++, rdip = &(*rdip)->rdi_next ) ; if ( *rdip == NULL ) { return 1; } rdi = *rdip; *rdip = rdi->rdi_next; retcode_item_destroy( rdi ); } rc = 0; break; default: LDAP_BUG(); break; } return rc; /* FIXME */ } switch( c->type ) { case RC_PARENT: if ( rd->rd_pdn.bv_val ) { ber_memfree ( rd->rd_pdn.bv_val ); } if ( rd->rd_npdn.bv_val ) { ber_memfree ( rd->rd_npdn.bv_val ); } rd->rd_pdn = c->value_dn; rd->rd_npdn = c->value_ndn; rc = 0; break; case RC_ITEM: { retcode_item_t rdi = { BER_BVNULL }, **rdip; struct berval bv, rdn, nrdn; char *next = NULL; int i; if ( c->argc < 3 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "\"retcode-item <RDN> <retcode> [<text>]\": " "missing args" ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } ber_str2bv( c->argv[ 1 ], 0, 0, &bv ); rc = dnPrettyNormal( NULL, &bv, &rdn, &nrdn, NULL ); if ( rc != LDAP_SUCCESS ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "unable to normalize RDN \"%s\": %d", c->argv[ 1 ], rc ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } if ( !dnIsOneLevelRDN( &nrdn ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "value \"%s\" is not a RDN", c->argv[ 1 ] ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } if ( BER_BVISNULL( &rd->rd_npdn ) ) { /* FIXME: we use the database suffix */ if ( c->be->be_nsuffix == NULL ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "either \"retcode-parent\" " "or \"suffix\" must be defined" ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } ber_dupbv( &rd->rd_pdn, &c->be->be_suffix[ 0 ] ); ber_dupbv( &rd->rd_npdn, &c->be->be_nsuffix[ 0 ] ); } build_new_dn( &rdi.rdi_dn, &rd->rd_pdn, &rdn, NULL ); build_new_dn( &rdi.rdi_ndn, &rd->rd_npdn, &nrdn, NULL ); ch_free( rdn.bv_val ); ch_free( nrdn.bv_val ); rdi.rdi_err = strtol( c->argv[ 2 ], &next, 0 ); if ( next == c->argv[ 2 ] || next[ 0 ] != '\0' ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "unable to parse return code \"%s\"", c->argv[ 2 ] ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } rdi.rdi_mask = SN_DG_OP_ALL; if ( c->argc > 3 ) { for ( i = 3; i < c->argc; i++ ) { if ( strncasecmp( c->argv[ i ], "op=", STRLENOF( "op=" ) ) == 0 ) { char **ops; int j; ops = ldap_str2charray( &c->argv[ i ][ STRLENOF( "op=" ) ], "," ); assert( ops != NULL ); rdi.rdi_mask = SN_DG_OP_NONE; for ( j = 0; ops[ j ] != NULL; j++ ) { if ( strcasecmp( ops[ j ], "add" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_ADD; } else if ( strcasecmp( ops[ j ], "bind" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_BIND; } else if ( strcasecmp( ops[ j ], "compare" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_COMPARE; } else if ( strcasecmp( ops[ j ], "delete" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_DELETE; } else if ( strcasecmp( ops[ j ], "modify" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_MODIFY; } else if ( strcasecmp( ops[ j ], "rename" ) == 0 || strcasecmp( ops[ j ], "modrdn" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_RENAME; } else if ( strcasecmp( ops[ j ], "search" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_SEARCH; } else if ( strcasecmp( ops[ j ], "extended" ) == 0 ) { rdi.rdi_mask |= SN_DG_EXTENDED; } else if ( strcasecmp( ops[ j ], "auth" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_AUTH; } else if ( strcasecmp( ops[ j ], "read" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_READ; } else if ( strcasecmp( ops[ j ], "write" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_WRITE; } else if ( strcasecmp( ops[ j ], "all" ) == 0 ) { rdi.rdi_mask |= SN_DG_OP_ALL; } else { snprintf( c->cr_msg, sizeof(c->cr_msg), "unknown op \"%s\"", ops[ j ] ); ldap_charray_free( ops ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } } ldap_charray_free( ops ); } else if ( strncasecmp( c->argv[ i ], "text=", STRLENOF( "text=" ) ) == 0 ) { if ( !BER_BVISNULL( &rdi.rdi_text ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "\"text\" already provided" ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } ber_str2bv( &c->argv[ i ][ STRLENOF( "text=" ) ], 0, 1, &rdi.rdi_text ); } else if ( strncasecmp( c->argv[ i ], "matched=", STRLENOF( "matched=" ) ) == 0 ) { struct berval dn; if ( !BER_BVISNULL( &rdi.rdi_matched ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "\"matched\" already provided" ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } ber_str2bv( &c->argv[ i ][ STRLENOF( "matched=" ) ], 0, 0, &dn ); if ( dnPretty( NULL, &dn, &rdi.rdi_matched, NULL ) != LDAP_SUCCESS ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "unable to prettify matched DN \"%s\"", &c->argv[ i ][ STRLENOF( "matched=" ) ] ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } } else if ( strncasecmp( c->argv[ i ], "ref=", STRLENOF( "ref=" ) ) == 0 ) { char **refs; int j; if ( rdi.rdi_ref != NULL ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "\"ref\" already provided" ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } if ( rdi.rdi_err != LDAP_REFERRAL ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "providing \"ref\" " "along with a non-referral " "resultCode may cause slapd failures " "related to internal checks" ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); } refs = ldap_str2charray( &c->argv[ i ][ STRLENOF( "ref=" ) ], " " ); assert( refs != NULL ); for ( j = 0; refs[ j ] != NULL; j++ ) { struct berval bv; ber_str2bv( refs[ j ], 0, 1, &bv ); ber_bvarray_add( &rdi.rdi_ref, &bv ); } ldap_charray_free( refs ); } else if ( strncasecmp( c->argv[ i ], "sleeptime=", STRLENOF( "sleeptime=" ) ) == 0 ) { if ( rdi.rdi_sleeptime != 0 ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "\"sleeptime\" already provided" ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } if ( lutil_atoi( &rdi.rdi_sleeptime, &c->argv[ i ][ STRLENOF( "sleeptime=" ) ] ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "unable to parse \"sleeptime=%s\"", &c->argv[ i ][ STRLENOF( "sleeptime=" ) ] ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } } else if ( strncasecmp( c->argv[ i ], "unsolicited=", STRLENOF( "unsolicited=" ) ) == 0 ) { char *data; if ( !BER_BVISNULL( &rdi.rdi_unsolicited_oid ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "\"unsolicited\" already provided" ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } data = strchr( &c->argv[ i ][ STRLENOF( "unsolicited=" ) ], ':' ); if ( data != NULL ) { struct berval oid; if ( ldif_parse_line2( &c->argv[ i ][ STRLENOF( "unsolicited=" ) ], &oid, &rdi.rdi_unsolicited_data, NULL ) ) { snprintf( c->cr_msg, sizeof(c->cr_msg), "unable to parse \"unsolicited\"" ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } ber_dupbv( &rdi.rdi_unsolicited_oid, &oid ); } else { ber_str2bv( &c->argv[ i ][ STRLENOF( "unsolicited=" ) ], 0, 1, &rdi.rdi_unsolicited_oid ); } } else if ( strncasecmp( c->argv[ i ], "flags=", STRLENOF( "flags=" ) ) == 0 ) { char *arg = &c->argv[ i ][ STRLENOF( "flags=" ) ]; if ( strcasecmp( arg, "disconnect" ) == 0 ) { rdi.rdi_flags |= RDI_PRE_DISCONNECT; } else if ( strcasecmp( arg, "pre-disconnect" ) == 0 ) { rdi.rdi_flags |= RDI_PRE_DISCONNECT; } else if ( strcasecmp( arg, "post-disconnect" ) == 0 ) { rdi.rdi_flags |= RDI_POST_DISCONNECT; } else { snprintf( c->cr_msg, sizeof(c->cr_msg), "unknown flag \"%s\"", arg ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } } else { snprintf( c->cr_msg, sizeof(c->cr_msg), "unknown option \"%s\"", c->argv[ i ] ); Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", c->log, c->cr_msg ); return ARG_BAD_CONF; } } } rdi.rdi_line.bv_len = 2*(c->argc - 1) + c->argc - 2; for ( i = 1; i < c->argc; i++ ) { rdi.rdi_line.bv_len += strlen( c->argv[ i ] ); } next = rdi.rdi_line.bv_val = ch_malloc( rdi.rdi_line.bv_len + 1 ); for ( i = 1; i < c->argc; i++ ) { *next++ = '"'; next = lutil_strcopy( next, c->argv[ i ] ); *next++ = '"'; *next++ = ' '; } *--next = '\0'; for ( rdip = &rd->rd_item; *rdip; rdip = &(*rdip)->rdi_next ) /* go to last */ ; *rdip = ( retcode_item_t * )ch_malloc( sizeof( retcode_item_t ) ); *(*rdip) = rdi; rc = 0; } break; default: rc = SLAP_CONF_UNKNOWN; break; } return rc; }
static int do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr, int maxloop, int force, int chaserefs, int noinit, int delay, int action_type, void *action ) { LDAP *ld = NULL; int i = 0; int rc = LDAP_SUCCESS; ber_int_t msgid; LDAPMessage *res, *msg; char **dns = NULL; struct berval *creds = NULL; char *attrs[] = { LDAP_NO_ATTRS, NULL }; int ndns = 0; #ifdef _WIN32 DWORD beg, end; #else struct timeval beg, end; #endif int version = LDAP_VERSION3; char *nullstr = ""; ldap_initialize( &ld, uri ); if ( ld == NULL ) { tester_perror( "ldap_initialize", NULL ); exit( EXIT_FAILURE ); } (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF ); rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); exit( EXIT_FAILURE ); } fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n", (long) pid, maxloop, base, filter, pwattr ); if ( pwattr != NULL ) { attrs[ 0 ] = pwattr; } rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, 0, 0, &msgid ); if ( rc != LDAP_SUCCESS ) { tester_ldap_error( ld, "ldap_search_ext", NULL ); exit( EXIT_FAILURE ); } while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 ) { BerElement *ber; struct berval bv; int done = 0; for ( msg = ldap_first_message( ld, res ); msg; msg = ldap_next_message( ld, msg ) ) { switch ( ldap_msgtype( msg ) ) { case LDAP_RES_SEARCH_ENTRY: rc = ldap_get_dn_ber( ld, msg, &ber, &bv ); dns = realloc( dns, (ndns + 1)*sizeof(char *) ); dns[ndns] = ber_strdup( bv.bv_val ); if ( pwattr != NULL ) { struct berval **values = ldap_get_values_len( ld, msg, pwattr ); creds = realloc( creds, (ndns + 1)*sizeof(struct berval) ); if ( values == NULL ) { novals:; creds[ndns].bv_len = 0; creds[ndns].bv_val = nullstr; } else { static struct berval cleartext = BER_BVC( "{CLEARTEXT} " ); struct berval value = *values[ 0 ]; if ( value.bv_val[ 0 ] == '{' ) { char *end = ber_bvchr( &value, '}' ); if ( end ) { if ( ber_bvcmp( &value, &cleartext ) == 0 ) { value.bv_val += cleartext.bv_len; value.bv_len -= cleartext.bv_len; } else { ldap_value_free_len( values ); goto novals; } } } ber_dupbv( &creds[ndns], &value ); ldap_value_free_len( values ); } } ndns++; ber_free( ber, 0 ); break; case LDAP_RES_SEARCH_RESULT: done = 1; break; } if ( done ) break; } ldap_msgfree( res ); if ( done ) break; } #ifdef _WIN32 beg = GetTickCount(); #else gettimeofday( &beg, NULL ); #endif if ( ndns == 0 ) { tester_error( "No DNs" ); return 1; } fprintf( stderr, " PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n", (long) pid, base, filter, ndns ); /* Ok, got list of DNs, now start binding to each */ for ( i = 0; i < maxloop; i++ ) { int j; struct berval cred = { 0, NULL }; #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */ j = rand() % ndns; #endif j = ((double)ndns)*rand()/(RAND_MAX + 1.0); if ( creds && !BER_BVISEMPTY( &creds[j] ) ) { cred = creds[j]; } if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld, action_type, action ) && !force ) { break; } if ( delay ) { sleep( delay ); } } if ( ld != NULL ) { ldap_unbind_ext( ld, NULL, NULL ); ld = NULL; } #ifdef _WIN32 end = GetTickCount(); end -= beg; fprintf( stderr, " PID=%ld - Bind done %d in %d.%03d seconds.\n", (long) pid, i, end / 1000, end % 1000 ); #else gettimeofday( &end, NULL ); end.tv_usec -= beg.tv_usec; if (end.tv_usec < 0 ) { end.tv_usec += 1000000; end.tv_sec -= 1; } end.tv_sec -= beg.tv_sec; fprintf( stderr, " PID=%ld - Bind done %d in %ld.%06ld seconds.\n", (long) pid, i, (long) end.tv_sec, (long) end.tv_usec ); #endif if ( dns ) { for ( i = 0; i < ndns; i++ ) { ber_memfree( dns[i] ); } free( dns ); } if ( creds ) { for ( i = 0; i < ndns; i++ ) { if ( creds[i].bv_val != nullstr ) { ber_memfree( creds[i].bv_val ); } } free( creds ); } return 0; }
int slapi_add_internal_pb( Slapi_PBlock *pb ) { SlapReply *rs; Slapi_Entry *entry_orig = NULL; OpExtraDB oex; int rc; if ( pb == NULL ) { return -1; } PBLOCK_ASSERT_INTOP( pb, LDAP_REQ_ADD ); rs = pb->pb_rs; entry_orig = pb->pb_op->ora_e; pb->pb_op->ora_e = NULL; /* * The caller can specify a new entry, or a target DN and set * of modifications, but not both. */ if ( entry_orig != NULL ) { if ( pb->pb_op->ora_modlist != NULL || !BER_BVISNULL( &pb->pb_op->o_req_ndn )) { rs->sr_err = LDAP_PARAM_ERROR; goto cleanup; } assert( BER_BVISNULL( &pb->pb_op->o_req_dn ) ); /* shouldn't get set */ ber_dupbv( &pb->pb_op->o_req_dn, &entry_orig->e_name ); ber_dupbv( &pb->pb_op->o_req_ndn, &entry_orig->e_nname ); } else if ( pb->pb_op->ora_modlist == NULL || BER_BVISNULL( &pb->pb_op->o_req_ndn )) { rs->sr_err = LDAP_PARAM_ERROR; goto cleanup; } pb->pb_op->ora_e = (Entry *)slapi_ch_calloc( 1, sizeof(Entry) ); ber_dupbv( &pb->pb_op->ora_e->e_name, &pb->pb_op->o_req_dn ); ber_dupbv( &pb->pb_op->ora_e->e_nname, &pb->pb_op->o_req_ndn ); if ( entry_orig != NULL ) { assert( pb->pb_op->ora_modlist == NULL ); rs->sr_err = slap_entry2mods( entry_orig, &pb->pb_op->ora_modlist, &rs->sr_text, pb->pb_textbuf, sizeof( pb->pb_textbuf ) ); if ( rs->sr_err != LDAP_SUCCESS ) { goto cleanup; } } else { assert( pb->pb_op->ora_modlist != NULL ); } rs->sr_err = slap_mods_check( pb->pb_op, pb->pb_op->ora_modlist, &rs->sr_text, pb->pb_textbuf, sizeof( pb->pb_textbuf ), NULL ); if ( rs->sr_err != LDAP_SUCCESS ) { goto cleanup; } /* Duplicate the values, because we may call slapi_entry_free() */ rs->sr_err = slap_mods2entry( pb->pb_op->ora_modlist, &pb->pb_op->ora_e, 1, 0, &rs->sr_text, pb->pb_textbuf, sizeof( pb->pb_textbuf ) ); if ( rs->sr_err != LDAP_SUCCESS ) { goto cleanup; } oex.oe.oe_key = (void *)do_add; oex.oe_db = NULL; LDAP_SLIST_INSERT_HEAD(&pb->pb_op->o_extra, &oex.oe, oe_next); rc = slapi_int_func_internal_pb( pb, op_add ); LDAP_SLIST_REMOVE(&pb->pb_op->o_extra, &oex.oe, OpExtra, oe_next); if ( !rc ) { if ( pb->pb_op->ora_e != NULL && oex.oe_db != NULL ) { BackendDB *bd = pb->pb_op->o_bd; pb->pb_op->o_bd = oex.oe_db; be_entry_release_w( pb->pb_op, pb->pb_op->ora_e ); pb->pb_op->ora_e = NULL; pb->pb_op->o_bd = bd; } } cleanup: if ( pb->pb_op->ora_e != NULL ) { slapi_entry_free( pb->pb_op->ora_e ); pb->pb_op->ora_e = NULL; } if ( entry_orig != NULL ) { pb->pb_op->ora_e = entry_orig; slap_mods_free( pb->pb_op->ora_modlist, 1 ); pb->pb_op->ora_modlist = NULL; } return 0; }
int schema_info( Entry **entry, const char **text ) { AttributeDescription *ad_structuralObjectClass = slap_schema.si_ad_structuralObjectClass; AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; AttributeDescription *ad_createTimestamp = slap_schema.si_ad_createTimestamp; AttributeDescription *ad_modifyTimestamp = slap_schema.si_ad_modifyTimestamp; Entry *e; struct berval vals[5]; struct berval nvals[5]; e = entry_alloc(); if( e == NULL ) { /* Out of memory, do something about it */ Debug( LDAP_DEBUG_ANY, "schema_info: entry_alloc failed - out of memory.\n", 0, 0, 0 ); *text = "out of memory"; return LDAP_OTHER; } e->e_attrs = NULL; /* backend-specific schema info should be created by the * backend itself */ ber_dupbv( &e->e_name, &frontendDB->be_schemadn ); ber_dupbv( &e->e_nname, &frontendDB->be_schemandn ); e->e_private = NULL; BER_BVSTR( &vals[0], "subentry" ); if( attr_merge_one( e, ad_structuralObjectClass, vals, NULL ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } BER_BVSTR( &vals[0], "top" ); BER_BVSTR( &vals[1], "subentry" ); BER_BVSTR( &vals[2], "subschema" ); BER_BVSTR( &vals[3], "extensibleObject" ); BER_BVZERO( &vals[4] ); if ( attr_merge( e, ad_objectClass, vals, NULL ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } { int rc; AttributeDescription *desc = NULL; struct berval rdn = frontendDB->be_schemadn; vals[0].bv_val = ber_bvchr( &rdn, '=' ); if( vals[0].bv_val == NULL ) { *text = "improperly configured subschema subentry"; return LDAP_OTHER; } vals[0].bv_val++; vals[0].bv_len = rdn.bv_len - (vals[0].bv_val - rdn.bv_val); rdn.bv_len -= vals[0].bv_len + 1; rc = slap_bv2ad( &rdn, &desc, text ); if( rc != LDAP_SUCCESS ) { entry_free( e ); *text = "improperly configured subschema subentry"; return LDAP_OTHER; } nvals[0].bv_val = ber_bvchr( &frontendDB->be_schemandn, '=' ); assert( nvals[0].bv_val != NULL ); nvals[0].bv_val++; nvals[0].bv_len = frontendDB->be_schemandn.bv_len - (nvals[0].bv_val - frontendDB->be_schemandn.bv_val); if ( attr_merge_one( e, desc, vals, nvals ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } } { char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; /* * According to RFC 4512: Servers SHOULD maintain the 'creatorsName', 'createTimestamp', 'modifiersName', and 'modifyTimestamp' attributes for all entries of the DIT. * to be conservative, we declare schema created * AND modified at server startup time ... */ vals[0].bv_val = timebuf; vals[0].bv_len = sizeof( timebuf ); slap_timestamp( &starttime, vals ); if( attr_merge_one( e, ad_createTimestamp, vals, NULL ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } if( attr_merge_one( e, ad_modifyTimestamp, vals, NULL ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } } if ( syn_schema_info( e ) || mr_schema_info( e ) || mru_schema_info( e ) || at_schema_info( e ) || oc_schema_info( e ) || cr_schema_info( e ) ) { /* Out of memory, do something about it */ entry_free( e ); *text = "out of memory"; return LDAP_OTHER; } *entry = e; return LDAP_SUCCESS; }
static int bdb_db_open( BackendDB *be, ConfigReply *cr ) { int rc, i; struct bdb_info *bdb = (struct bdb_info *) be->be_private; struct stat stat1, stat2; u_int32_t flags; char path[MAXPATHLEN]; char *dbhome; Entry *e = NULL; int do_recover = 0, do_alock_recover = 0; int alockt, quick = 0; int do_retry = 1; if ( be->be_suffix == NULL ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": need suffix.\n", 1, 0, 0 ); return -1; } Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(bdb_db_open) ": \"%s\"\n", be->be_suffix[0].bv_val, 0, 0 ); /* Check existence of dbenv_home. Any error means trouble */ rc = stat( bdb->bi_dbenv_home, &stat1 ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "cannot access database directory \"%s\" (%d).\n", be->be_suffix[0].bv_val, bdb->bi_dbenv_home, errno ); return -1; } /* Perform database use arbitration/recovery logic */ alockt = (slapMode & SLAP_TOOL_READONLY) ? ALOCK_LOCKED : ALOCK_UNIQUE; if ( slapMode & SLAP_TOOL_QUICK ) { alockt |= ALOCK_NOSAVE; quick = 1; } rc = alock_open( &bdb->bi_alock_info, "slapd", bdb->bi_dbenv_home, alockt ); /* alockt is TRUE if the existing environment was created in Quick mode */ alockt = (rc & ALOCK_NOSAVE) ? 1 : 0; rc &= ~ALOCK_NOSAVE; if( rc == ALOCK_RECOVER ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "unclean shutdown detected; attempting recovery.\n", be->be_suffix[0].bv_val, 0, 0 ); do_alock_recover = 1; do_recover = DB_RECOVER; } else if( rc == ALOCK_BUSY ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "database already in use.\n", be->be_suffix[0].bv_val, 0, 0 ); return -1; } else if( rc != ALOCK_CLEAN ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "alock package is unstable.\n", be->be_suffix[0].bv_val, 0, 0 ); return -1; } if ( rc == ALOCK_CLEAN ) be->be_flags |= SLAP_DBFLAG_CLEAN; /* * The DB_CONFIG file may have changed. If so, recover the * database so that new settings are put into effect. Also * note the possible absence of DB_CONFIG in the log. */ if( stat( bdb->bi_db_config_path, &stat1 ) == 0 ) { if ( !do_recover ) { char *ptr = lutil_strcopy(path, bdb->bi_dbenv_home); *ptr++ = LDAP_DIRSEP[0]; strcpy( ptr, "__db.001" ); if( stat( path, &stat2 ) == 0 ) { if( stat2.st_mtime < stat1.st_mtime ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": DB_CONFIG for suffix \"%s\" has changed.\n", be->be_suffix[0].bv_val, 0, 0 ); if ( quick ) { Debug( LDAP_DEBUG_ANY, "Cannot use Quick mode; perform manual recovery first.\n", 0, 0, 0 ); slapMode ^= SLAP_TOOL_QUICK; rc = -1; goto fail; } else { Debug( LDAP_DEBUG_ANY, "Performing database recovery to activate new settings.\n", 0, 0, 0 ); } do_recover = DB_RECOVER; } } } } else { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": warning - no DB_CONFIG file found " "in directory %s: (%d).\n" "Expect poor performance for suffix \"%s\".\n", bdb->bi_dbenv_home, errno, be->be_suffix[0].bv_val ); } /* Always let slapcat run, regardless of environment state. * This can be used to cause a cache flush after an unclean * shutdown. */ if ( do_recover && ( slapMode & SLAP_TOOL_READONLY )) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "recovery skipped in read-only mode. " "Run manual recovery if errors are encountered.\n", be->be_suffix[0].bv_val, 0, 0 ); do_recover = 0; do_alock_recover = 0; quick = alockt; } /* An existing environment in Quick mode has nothing to recover. */ if ( alockt && do_recover ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "cannot recover, database must be reinitialized.\n", be->be_suffix[0].bv_val, 0, 0 ); rc = -1; goto fail; } rc = db_env_create( &bdb->bi_dbenv, 0 ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "db_env_create failed: %s (%d).\n", be->be_suffix[0].bv_val, db_strerror(rc), rc ); goto fail; } #ifdef HAVE_EBCDIC strcpy( path, bdb->bi_dbenv_home ); __atoe( path ); dbhome = path; #else dbhome = bdb->bi_dbenv_home; #endif /* If existing environment is clean but doesn't support * currently requested modes, remove it. */ if ( !do_recover && ( alockt ^ quick )) { shm_retry: rc = bdb->bi_dbenv->remove( bdb->bi_dbenv, dbhome, DB_FORCE ); if ( rc ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "dbenv remove failed: %s (%d).\n", be->be_suffix[0].bv_val, db_strerror(rc), rc ); bdb->bi_dbenv = NULL; goto fail; } rc = db_env_create( &bdb->bi_dbenv, 0 ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "db_env_create failed: %s (%d).\n", be->be_suffix[0].bv_val, db_strerror(rc), rc ); goto fail; } } bdb->bi_dbenv->set_errpfx( bdb->bi_dbenv, be->be_suffix[0].bv_val ); bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall ); bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect ); if ( !BER_BVISNULL( &bdb->bi_db_crypt_key )) { rc = bdb->bi_dbenv->set_encrypt( bdb->bi_dbenv, bdb->bi_db_crypt_key.bv_val, DB_ENCRYPT_AES ); if ( rc ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "dbenv set_encrypt failed: %s (%d).\n", be->be_suffix[0].bv_val, db_strerror(rc), rc ); goto fail; } } /* One long-lived TXN per thread, two TXNs per write op */ bdb->bi_dbenv->set_tx_max( bdb->bi_dbenv, connection_pool_max * 3 ); if( bdb->bi_dbenv_xflags != 0 ) { rc = bdb->bi_dbenv->set_flags( bdb->bi_dbenv, bdb->bi_dbenv_xflags, 1); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "dbenv_set_flags failed: %s (%d).\n", be->be_suffix[0].bv_val, db_strerror(rc), rc ); goto fail; } } #define BDB_TXN_FLAGS (DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN) Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "dbenv_open(%s).\n", be->be_suffix[0].bv_val, bdb->bi_dbenv_home, 0); flags = DB_INIT_MPOOL | DB_CREATE | DB_THREAD; if ( !quick ) flags |= BDB_TXN_FLAGS; /* If a key was set, use shared memory for the BDB environment */ if ( bdb->bi_shm_key ) { bdb->bi_dbenv->set_shm_key( bdb->bi_dbenv, bdb->bi_shm_key ); flags |= DB_SYSTEM_MEM; } rc = (bdb->bi_dbenv->open)( bdb->bi_dbenv, dbhome, flags | do_recover, bdb->bi_dbenv_mode ); if ( rc ) { /* Regular open failed, probably a missing shm environment. * Start over, do a recovery. */ if ( !do_recover && bdb->bi_shm_key && do_retry ) { bdb->bi_dbenv->close( bdb->bi_dbenv, 0 ); rc = db_env_create( &bdb->bi_dbenv, 0 ); if( rc == 0 ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": " "shared memory env open failed, assuming stale env.\n", be->be_suffix[0].bv_val, 0, 0 ); do_retry = 0; goto shm_retry; } } Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\" cannot be %s, err %d. " "Restore from backup!\n", be->be_suffix[0].bv_val, do_recover ? "recovered" : "opened", rc ); goto fail; } if ( do_alock_recover && alock_recover (&bdb->bi_alock_info) != 0 ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": database \"%s\": alock_recover failed\n", be->be_suffix[0].bv_val, 0, 0 ); rc = -1; goto fail; } #ifdef SLAP_ZONE_ALLOC if ( bdb->bi_cache.c_maxsize ) { bdb->bi_cache.c_zctx = slap_zn_mem_create( SLAP_ZONE_INITSIZE, SLAP_ZONE_MAXSIZE, SLAP_ZONE_DELTA, SLAP_ZONE_SIZE); } #endif /* dncache defaults to 0 == unlimited * must be >= entrycache */ if ( bdb->bi_cache.c_eimax && bdb->bi_cache.c_eimax < bdb->bi_cache.c_maxsize ) { bdb->bi_cache.c_eimax = bdb->bi_cache.c_maxsize; } if ( bdb->bi_idl_cache_max_size ) { bdb->bi_idl_tree = NULL; bdb->bi_idl_cache_size = 0; } flags = DB_THREAD | bdb->bi_db_opflags; #ifdef DB_AUTO_COMMIT if ( !quick ) flags |= DB_AUTO_COMMIT; #endif bdb->bi_databases = (struct bdb_db_info **) ch_malloc( BDB_INDICES * sizeof(struct bdb_db_info *) ); /* open (and create) main database */ for( i = 0; bdbi_databases[i].name.bv_val; i++ ) { struct bdb_db_info *db; db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info)); rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 ); if( rc != 0 ) { snprintf(cr->msg, sizeof(cr->msg), "database \"%s\": db_create(%s) failed: %s (%d).", be->be_suffix[0].bv_val, bdb->bi_dbenv_home, db_strerror(rc), rc ); Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": %s\n", cr->msg, 0, 0 ); goto fail; } if( !BER_BVISNULL( &bdb->bi_db_crypt_key )) { rc = db->bdi_db->set_flags( db->bdi_db, DB_ENCRYPT ); if ( rc ) { snprintf(cr->msg, sizeof(cr->msg), "database \"%s\": db set_flags(DB_ENCRYPT)(%s) failed: %s (%d).", be->be_suffix[0].bv_val, bdb->bi_dbenv_home, db_strerror(rc), rc ); Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": %s\n", cr->msg, 0, 0 ); goto fail; } } if( bdb->bi_flags & BDB_CHKSUM ) { rc = db->bdi_db->set_flags( db->bdi_db, DB_CHKSUM ); if ( rc ) { snprintf(cr->msg, sizeof(cr->msg), "database \"%s\": db set_flags(DB_CHKSUM)(%s) failed: %s (%d).", be->be_suffix[0].bv_val, bdb->bi_dbenv_home, db_strerror(rc), rc ); Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": %s\n", cr->msg, 0, 0 ); goto fail; } } rc = bdb_db_findsize( bdb, (struct berval *)&bdbi_databases[i].name ); if( i == BDB_ID2ENTRY ) { if ( !rc ) rc = BDB_ID2ENTRY_PAGESIZE; rc = db->bdi_db->set_pagesize( db->bdi_db, rc ); if ( slapMode & SLAP_TOOL_MODE ) db->bdi_db->mpf->set_priority( db->bdi_db->mpf, DB_PRIORITY_VERY_LOW ); if ( slapMode & SLAP_TOOL_READMAIN ) { flags |= DB_RDONLY; } else { flags |= DB_CREATE; } } else { /* Use FS default size if not configured */ if ( rc ) rc = db->bdi_db->set_pagesize( db->bdi_db, rc ); rc = db->bdi_db->set_flags( db->bdi_db, DB_DUP | DB_DUPSORT ); #ifndef BDB_HIER if ( slapMode & SLAP_TOOL_READONLY ) { flags |= DB_RDONLY; } else { flags |= DB_CREATE; } #else rc = db->bdi_db->set_dup_compare( db->bdi_db, bdb_dup_compare ); if ( slapMode & (SLAP_TOOL_READONLY|SLAP_TOOL_READMAIN) ) { flags |= DB_RDONLY; } else { flags |= DB_CREATE; } #endif } #ifdef HAVE_EBCDIC strcpy( path, bdbi_databases[i].file ); __atoe( path ); rc = DB_OPEN( db->bdi_db, path, /* bdbi_databases[i].name, */ NULL, bdbi_databases[i].type, bdbi_databases[i].flags | flags, bdb->bi_dbenv_mode ); #else rc = DB_OPEN( db->bdi_db, bdbi_databases[i].file, /* bdbi_databases[i].name, */ NULL, bdbi_databases[i].type, bdbi_databases[i].flags | flags, bdb->bi_dbenv_mode ); #endif if ( rc != 0 ) { snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": " "db_open(%s/%s) failed: %s (%d).", be->be_suffix[0].bv_val, bdb->bi_dbenv_home, bdbi_databases[i].file, db_strerror(rc), rc ); Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": %s\n", cr->msg, 0, 0 ); db->bdi_db->close( db->bdi_db, 0 ); goto fail; } flags &= ~(DB_CREATE | DB_RDONLY); db->bdi_name = bdbi_databases[i].name; bdb->bi_databases[i] = db; } bdb->bi_databases[i] = NULL; bdb->bi_ndatabases = i; /* get nextid */ rc = bdb_last_id( be, NULL ); if( rc != 0 ) { snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": " "last_id(%s) failed: %s (%d).", be->be_suffix[0].bv_val, bdb->bi_dbenv_home, db_strerror(rc), rc ); Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_db_open) ": %s\n", cr->msg, 0, 0 ); goto fail; } if ( !quick ) { TXN_BEGIN(bdb->bi_dbenv, NULL, &bdb->bi_cache.c_txn, DB_READ_COMMITTED | DB_TXN_NOWAIT); } entry_prealloc( bdb->bi_cache.c_maxsize ); attr_prealloc( bdb->bi_cache.c_maxsize * 20 ); /* setup for empty-DN contexts */ if ( BER_BVISEMPTY( &be->be_nsuffix[0] )) { rc = bdb_id2entry( be, NULL, 0, &e ); } if ( !e ) { struct berval gluebv = BER_BVC("glue"); Operation op = {0}; Opheader ohdr = {0}; e = entry_alloc(); e->e_id = 0; ber_dupbv( &e->e_name, (struct berval *)&slap_empty_bv ); ber_dupbv( &e->e_nname, (struct berval *)&slap_empty_bv ); attr_merge_one( e, slap_schema.si_ad_objectClass, &gluebv, NULL ); attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, &gluebv, NULL ); op.o_hdr = &ohdr; op.o_bd = be; op.ora_e = e; op.o_dn = be->be_rootdn; op.o_ndn = be->be_rootndn; slap_add_opattrs( &op, NULL, NULL, 0, 0 ); } e->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END; e->e_private = &bdb->bi_cache.c_dntree; bdb->bi_cache.c_dntree.bei_e = e; /* monitor setup */ rc = bdb_monitor_db_open( be ); if ( rc != 0 ) { goto fail; } bdb->bi_flags |= BDB_IS_OPEN; return 0; fail: bdb_db_close( be, NULL ); return rc; }