예제 #1
0
int
bdb_modify( Operation *op, SlapReply *rs )
{
	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
	Entry		*e = NULL;
	EntryInfo	*ei = NULL;
	int		manageDSAit = get_manageDSAit( op );
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;
	DB_TXN	*ltid = NULL, *lt2;
	struct bdb_op_info opinfo = {{{ 0 }}};
	Entry		dummy = {0};

	DB_LOCK		lock;

	int		num_retries = 0;

	LDAPControl **preread_ctrl = NULL;
	LDAPControl **postread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

	int rc;

	Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(bdb_modify) ": %s\n",
		op->o_req_dn.bv_val, 0, 0 );

#ifdef LDAP_X_TXN
	if( op->o_txnSpec && txn_preop( op, rs ))
		return rs->sr_err;
#endif

	ctrls[num_ctrls] = NULL;

	/* Don't touch the opattrs, if this is a contextCSN update
	 * initiated from updatedn */
	if ( !be_isupdate(op) || !op->orm_modlist || op->orm_modlist->sml_next ||
		 op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) {

		slap_mods_opattrs( op, &op->orm_modlist, 1 );
	}

	if( 0 ) {
retry:	/* transaction retry */
		if ( dummy.e_attrs ) {
			attrs_free( dummy.e_attrs );
			dummy.e_attrs = NULL;
		}
		if( e != NULL ) {
			bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
			e = NULL;
		}
		Debug(LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": retrying...\n", 0, 0, 0);

		rs->sr_err = TXN_ABORT( ltid );
		ltid = NULL;
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
		opinfo.boi_oe.oe_key = NULL;
		op->o_do_not_cache = opinfo.boi_acl_cache;
		if( rs->sr_err != 0 ) {
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			goto return_results;
		}
		bdb_trans_backoff( ++num_retries );
	}

	/* begin transaction */
	{
		int tflags = bdb->bi_db_opflags;
		if ( get_lazyCommit( op ))
			tflags |= DB_TXN_NOSYNC;
		rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, tflags );
	}
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": txn_begin failed: "
			"%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modify) ": txn1 id: %x\n",
		ltid->id(ltid), 0, 0 );

	opinfo.boi_oe.oe_key = bdb;
	opinfo.boi_txn = ltid;
	opinfo.boi_err = 0;
	opinfo.boi_acl_cache = op->o_do_not_cache;
	LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next );

	/* get entry or ancestor */
	rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
		&lock );

	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": dn2entry failed (%d)\n",
			rs->sr_err, 0, 0 );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		case DB_NOTFOUND:
			break;
		case LDAP_BUSY:
			rs->sr_text = "ldap server busy";
			goto return_results;
		default:
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
	}

	e = ei->bei_e;

	/* acquire and lock entry */
	/* FIXME: dn2entry() should return non-glue entry */
	if (( rs->sr_err == DB_NOTFOUND ) ||
		( !manageDSAit && e && is_entry_glue( e )))
	{
		if ( e != NULL ) {
			rs->sr_matched = ch_strdup( e->e_dn );
			rs->sr_ref = is_entry_referral( e )
				? get_entry_referrals( op, e )
				: NULL;
			bdb_unlocked_cache_return_entry_r (&bdb->bi_cache, e);
			e = NULL;

		} else {
			rs->sr_ref = referral_rewrite( default_referral, NULL,
				&op->o_req_dn, LDAP_SCOPE_DEFAULT );
		}

		rs->sr_err = LDAP_REFERRAL;
		send_ldap_result( op, rs );

		if ( rs->sr_ref != default_referral ) {
			ber_bvarray_free( rs->sr_ref );
		}
		free( (char *)rs->sr_matched );
		rs->sr_ref = NULL;
		rs->sr_matched = NULL;

		goto done;
	}

	if ( !manageDSAit && is_entry_referral( e ) ) {
		/* entry is a referral, don't allow modify */
		rs->sr_ref = get_entry_referrals( op, e );

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": entry is referral\n",
			0, 0, 0 );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_matched = e->e_name.bv_val;
		send_ldap_result( op, rs );

		ber_bvarray_free( rs->sr_ref );
		rs->sr_ref = NULL;
		rs->sr_matched = NULL;
		goto done;
	}

	if ( get_assert( op ) &&
		( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	if( op->o_preread ) {
		if( preread_ctrl == NULL ) {
			preread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if ( slap_read_controls( op, rs, e,
			&slap_pre_read_bv, preread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_modify) ": pre-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	/* nested transaction */
	rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, bdb->bi_db_opflags );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": txn_begin(2) failed: " "%s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modify) ": txn2 id: %x\n",
		lt2->id(lt2), 0, 0 );
	/* Modify the entry */
	dummy = *e;
	rs->sr_err = bdb_modify_internal( op, lt2, op->orm_modlist,
		&dummy, &rs->sr_text, textbuf, textlen );

	if( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": modify failed (%d)\n",
			rs->sr_err, 0, 0 );
		if ( (rs->sr_err == LDAP_INSUFFICIENT_ACCESS) && opinfo.boi_err ) {
			rs->sr_err = opinfo.boi_err;
		}
		/* Only free attrs if they were dup'd.  */
		if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		goto return_results;
	}

	/* change the entry itself */
	rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, &dummy );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": id2entry update failed " "(%d)\n",
			rs->sr_err, 0, 0 );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		rs->sr_text = "entry update failed";
		goto return_results;
	}

	if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "txn_commit(2) failed";
		goto return_results;
	}

	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, &dummy,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_modify)
				": post-read failed!\n", 0, 0, 0 );
			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	if( op->o_noop ) {
		if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
			rs->sr_text = "txn_abort (no-op) failed";
		} else {
			rs->sr_err = LDAP_X_NO_OPERATION;
			ltid = NULL;
			/* Only free attrs if they were dup'd.  */
			if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
			goto return_results;
		}
	} else {
		/* may have changed in bdb_modify_internal() */
		e->e_ocflags = dummy.e_ocflags;
		rc = bdb_cache_modify( bdb, e, dummy.e_attrs, ltid, &lock );
		switch( rc ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		dummy.e_attrs = NULL;

		rs->sr_err = TXN_COMMIT( ltid, 0 );
	}
	ltid = NULL;
	LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	opinfo.boi_oe.oe_key = NULL;

	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": txn_%s failed: %s (%d)\n",
			op->o_noop ? "abort (no-op)" : "commit",
			db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "commit failed";

		goto return_results;
	}

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_modify) ": updated%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		dummy.e_id, op->o_req_dn.bv_val );

	rs->sr_err = LDAP_SUCCESS;
	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	if( dummy.e_attrs ) {
		attrs_free( dummy.e_attrs );
	}
	send_ldap_result( op, rs );

	if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp_kbyte ) {
		TXN_CHECKPOINT( bdb->bi_dbenv,
			bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
	}

done:
	slap_graduate_commit_csn( op );

	if( ltid != NULL ) {
		TXN_ABORT( ltid );
	}
	if ( opinfo.boi_oe.oe_key ) {
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	}

	if( e != NULL ) {
		bdb_unlocked_cache_return_entry_w (&bdb->bi_cache, e);
	}

	if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
		slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
	}
	if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
		slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
	}

	rs->sr_text = NULL;

	return rs->sr_err;
}
예제 #2
0
파일: bind.c 프로젝트: cptaffe/openldap
int
wt_bind( Operation *op, SlapReply *rs )
{
    struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
	WT_SESSION *session;
	wt_ctx *wc;
	int rc;
	Entry *e = NULL;
	Attribute *a;
	AttributeDescription *password = slap_schema.si_ad_userPassword;

    Debug( LDAP_DEBUG_ARGS,
		   "==> " LDAP_XSTRING(wt_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;
	}

	wc = wt_ctx_get(op, wi);
	if( !wc ){
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_bind)
			   ": wt_ctx_get failed\n",
			   0, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
        send_ldap_result( op, rs );
        return rs->sr_err;
	}

	/* get entry */
	rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e);
	switch( rc ) {
	case 0:
		break;
	case WT_NOTFOUND:
		rs->sr_err = LDAP_INVALID_CREDENTIALS;
		send_ldap_result( op, rs );
		return rs->sr_err;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
        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:
		rs->sr_err = LDAP_STRONG_AUTH_NOT_SUPPORTED;
		rs->sr_text = "authentication method not supported";
	}

done:
	/* free entry */
	if (e) {
		wt_entry_return(e);
	}
	if (rs->sr_err) {
		send_ldap_result( op, rs );
        if ( rs->sr_ref ) {
            ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;
		}
	}
	return rs->sr_err;
}
예제 #3
0
int
mdb_back_initialize(
	BackendInfo	*bi )
{
	int rc;

	static char *controls[] = {
		LDAP_CONTROL_ASSERT,
		LDAP_CONTROL_MANAGEDSAIT,
		LDAP_CONTROL_NOOP,
		LDAP_CONTROL_PAGEDRESULTS,
		LDAP_CONTROL_PRE_READ,
		LDAP_CONTROL_POST_READ,
		LDAP_CONTROL_SUBENTRIES,
		LDAP_CONTROL_X_PERMISSIVE_MODIFY,
#ifdef LDAP_X_TXN
		LDAP_CONTROL_X_TXN_SPEC,
#endif
		NULL
	};

	/* initialize the underlying database system */
	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(mdb_back_initialize) ": initialize " 
		MDB_UCTYPE " backend\n", 0, 0, 0 );

	bi->bi_flags |=
		SLAP_BFLAG_INCREMENT |
		SLAP_BFLAG_SUBENTRIES |
		SLAP_BFLAG_ALIASES |
		SLAP_BFLAG_REFERRALS;

	bi->bi_controls = controls;

	{	/* version check */
		int major, minor, patch, ver;
		char *version = mdb_version( &major, &minor, &patch );
#ifdef HAVE_EBCDIC
		char v2[1024];

		/* All our stdio does an ASCII to EBCDIC conversion on
		 * the output. Strings from the MDB library are already
		 * in EBCDIC; we have to go back and forth...
		 */
		strcpy( v2, version );
		__etoa( v2 );
		version = v2;
#endif
		ver = (major << 24) | (minor << 16) | patch;
		if( ver != MDB_VERSION_FULL ) {
			/* fail if a versions don't match */
			Debug( LDAP_DEBUG_ANY,
				LDAP_XSTRING(mdb_back_initialize) ": "
				"MDB library version mismatch:"
				" expected " MDB_VERSION_STRING ","
				" got %s\n", version, 0, 0 );
			return -1;
		}

		Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_back_initialize)
			": %s\n", version, 0, 0 );
	}

	bi->bi_open = 0;
	bi->bi_close = 0;
	bi->bi_config = 0;
	bi->bi_destroy = 0;

	bi->bi_db_init = mdb_db_init;
	bi->bi_db_config = config_generic_wrapper;
	bi->bi_db_open = mdb_db_open;
	bi->bi_db_close = mdb_db_close;
	bi->bi_db_destroy = mdb_db_destroy;

	bi->bi_op_add = mdb_add;
	bi->bi_op_bind = mdb_bind;
	bi->bi_op_compare = mdb_compare;
	bi->bi_op_delete = mdb_delete;
	bi->bi_op_modify = mdb_modify;
	bi->bi_op_modrdn = mdb_modrdn;
	bi->bi_op_search = mdb_search;

	bi->bi_op_unbind = 0;

	bi->bi_extended = mdb_extended;

	bi->bi_chk_referrals = 0;
	bi->bi_operational = mdb_operational;

	bi->bi_has_subordinates = mdb_hasSubordinates;
	bi->bi_entry_release_rw = mdb_entry_release;
	bi->bi_entry_get_rw = mdb_entry_get;

	/*
	 * hooks for slap tools
	 */
	bi->bi_tool_entry_open = mdb_tool_entry_open;
	bi->bi_tool_entry_close = mdb_tool_entry_close;
	bi->bi_tool_entry_first = backend_tool_entry_first;
	bi->bi_tool_entry_first_x = mdb_tool_entry_first_x;
	bi->bi_tool_entry_next = mdb_tool_entry_next;
	bi->bi_tool_entry_get = mdb_tool_entry_get;
	bi->bi_tool_entry_put = mdb_tool_entry_put;
	bi->bi_tool_entry_reindex = mdb_tool_entry_reindex;
	bi->bi_tool_sync = 0;
	bi->bi_tool_dn2id_get = mdb_tool_dn2id_get;
	bi->bi_tool_entry_modify = mdb_tool_entry_modify;

	bi->bi_connection_init = 0;
	bi->bi_connection_destroy = 0;

	rc = mdb_back_init_cf( bi );

	return rc;
}
예제 #4
0
ID bdb_tool_entry_put(
	BackendDB *be,
	Entry *e,
	struct berval *text )
{
	int rc;
	struct bdb_info *bdb = (struct bdb_info *) be->be_private;
	DB_TXN *tid = NULL;
	Operation op = {0};
	Opheader ohdr = {0};

	assert( be != NULL );
	assert( slapMode & SLAP_TOOL_MODE );

	assert( text != NULL );
	assert( text->bv_val != NULL );
	assert( text->bv_val[0] == '\0' );	/* overconservative? */

	Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_tool_entry_put)
		"( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );

	if (! (slapMode & SLAP_TOOL_QUICK)) {
	rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
		bdb->bi_db_opflags );
	if( rc != 0 ) {
		snprintf( text->bv_val, text->bv_len,
			"txn_begin failed: %s (%d)",
			db_strerror(rc), rc );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
			 text->bv_val, 0, 0 );
		return NOID;
	}
	}

	op.o_hdr = &ohdr;
	op.o_bd = be;
	op.o_tmpmemctx = NULL;
	op.o_tmpmfuncs = &ch_mfuncs;

	/* add dn2id indices */
	rc = bdb_tool_next_id( &op, tid, e, text, 0 );
	if( rc != 0 ) {
		goto done;
	}

	if (( slapMode & SLAP_TOOL_QUICK ) && (( e->e_id & 0xfff ) == 0xfff )) {
		ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex );
		ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond );
		ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex );
	}

	if ( !bdb->bi_linear_index )
		rc = bdb_tool_index_add( &op, tid, e );
	if( rc != 0 ) {
		snprintf( text->bv_val, text->bv_len,
				"index_entry_add failed: %s (%d)",
				rc == LDAP_OTHER ? "Internal error" :
				db_strerror(rc), rc );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
			text->bv_val, 0, 0 );
		goto done;
	}

	/* id2entry index */
	rc = bdb_id2entry_add( be, tid, e );
	if( rc != 0 ) {
		snprintf( text->bv_val, text->bv_len,
				"id2entry_add failed: %s (%d)",
				db_strerror(rc), rc );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
			text->bv_val, 0, 0 );
		goto done;
	}

done:
	if( rc == 0 ) {
		if ( !( slapMode & SLAP_TOOL_QUICK )) {
		rc = TXN_COMMIT( tid, 0 );
		if( rc != 0 ) {
			snprintf( text->bv_val, text->bv_len,
					"txn_commit failed: %s (%d)",
					db_strerror(rc), rc );
			Debug( LDAP_DEBUG_ANY,
				"=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
				text->bv_val, 0, 0 );
			e->e_id = NOID;
		}
		}

	} else {
		if ( !( slapMode & SLAP_TOOL_QUICK )) {
		TXN_ABORT( tid );
		snprintf( text->bv_val, text->bv_len,
			"txn_aborted! %s (%d)",
			rc == LDAP_OTHER ? "Internal error" :
			db_strerror(rc), rc );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
			text->bv_val, 0, 0 );
		}
		e->e_id = NOID;
	}

	return e->e_id;
}
예제 #5
0
ID bdb_tool_entry_modify(
	BackendDB *be,
	Entry *e,
	struct berval *text )
{
	int rc;
	struct bdb_info *bdb = (struct bdb_info *) be->be_private;
	DB_TXN *tid = NULL;
	Operation op = {0};
	Opheader ohdr = {0};

	assert( be != NULL );
	assert( slapMode & SLAP_TOOL_MODE );

	assert( text != NULL );
	assert( text->bv_val != NULL );
	assert( text->bv_val[0] == '\0' );	/* overconservative? */

	assert ( e->e_id != NOID );

	Debug( LDAP_DEBUG_TRACE,
		"=> " LDAP_XSTRING(bdb_tool_entry_modify) "( %ld, \"%s\" )\n",
		(long) e->e_id, e->e_dn, 0 );

	if (! (slapMode & SLAP_TOOL_QUICK)) {
		if( cursor ) {
			cursor->c_close( cursor );
			cursor = NULL;
		}
		rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
			bdb->bi_db_opflags );
		if( rc != 0 ) {
			snprintf( text->bv_val, text->bv_len,
				"txn_begin failed: %s (%d)",
				db_strerror(rc), rc );
			Debug( LDAP_DEBUG_ANY,
				"=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
				 text->bv_val, 0, 0 );
			return NOID;
		}
	}

	op.o_hdr = &ohdr;
	op.o_bd = be;
	op.o_tmpmemctx = NULL;
	op.o_tmpmfuncs = &ch_mfuncs;

	/* id2entry index */
	rc = bdb_id2entry_update( be, tid, e );
	if( rc != 0 ) {
		snprintf( text->bv_val, text->bv_len,
				"id2entry_add failed: %s (%d)",
				db_strerror(rc), rc );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
			text->bv_val, 0, 0 );
		goto done;
	}

done:
	if( rc == 0 ) {
		if (! (slapMode & SLAP_TOOL_QUICK)) {
		rc = TXN_COMMIT( tid, 0 );
		if( rc != 0 ) {
			snprintf( text->bv_val, text->bv_len,
					"txn_commit failed: %s (%d)",
					db_strerror(rc), rc );
			Debug( LDAP_DEBUG_ANY,
				"=> " LDAP_XSTRING(bdb_tool_entry_modify) ": "
				"%s\n", text->bv_val, 0, 0 );
			e->e_id = NOID;
		}
		}

	} else {
		if (! (slapMode & SLAP_TOOL_QUICK)) {
		TXN_ABORT( tid );
		snprintf( text->bv_val, text->bv_len,
			"txn_aborted! %s (%d)",
			db_strerror(rc), rc );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
			text->bv_val, 0, 0 );
		}
		e->e_id = NOID;
	}

	return e->e_id;
}
예제 #6
0
int
bdb_referrals( Operation *op, SlapReply *rs )
{
	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
	Entry *e = NULL;
	EntryInfo *ei;
	int rc = LDAP_SUCCESS;

	BDB_LOCKER	locker;
	DB_LOCK		lock;

	if( op->o_tag == LDAP_REQ_SEARCH ) {
		/* let search take care of itself */
		return rc;
	}

	if( get_manageDSAit( op ) ) {
		/* let op take care of DSA management */
		return rc;
	} 

	rc = LOCK_ID(bdb->bi_dbenv, &locker);
	switch(rc) {
	case 0:
		break;
	default:
		return LDAP_OTHER;
	}

dn2entry_retry:
	/* get entry */
	rc = bdb_dn2entry( op, NULL, &op->o_req_ndn, &ei, 1, locker, &lock );

	/* bdb_dn2entry() may legally leave ei == NULL
	 * if rc != 0 and rc != DB_NOTFOUND
	 */
	if ( ei ) {
		e = ei->bei_e;
	}

	switch(rc) {
	case DB_NOTFOUND:
	case 0:
		break;
	case LDAP_BUSY:
		LOCK_ID_FREE ( bdb->bi_dbenv, locker );
		rs->sr_text = "ldap server busy";
		return LDAP_BUSY;
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto dn2entry_retry;
	default:
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_referrals)
			": dn2entry failed: %s (%d)\n",
			db_strerror(rc), rc, 0 ); 
		LOCK_ID_FREE ( bdb->bi_dbenv, locker );
		rs->sr_text = "internal error";
		return LDAP_OTHER;
	}

	if ( rc == DB_NOTFOUND ) {
		rc = LDAP_SUCCESS;
		rs->sr_matched = NULL;
		if ( e != NULL ) {
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_referrals)
				": tag=%lu target=\"%s\" matched=\"%s\"\n",
				(unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val );

			if( is_entry_referral( e ) ) {
				BerVarray ref = get_entry_referrals( op, e );
				rc = LDAP_OTHER;
				rs->sr_ref = referral_rewrite( ref, &e->e_name,
					&op->o_req_dn, LDAP_SCOPE_DEFAULT );
				ber_bvarray_free( ref );
				if ( rs->sr_ref ) {
					rs->sr_matched = ber_strdup_x(
					e->e_name.bv_val, op->o_tmpmemctx );
				}
			}

			bdb_cache_return_entry_r (bdb, e, &lock);
			e = NULL;
		}

		if( rs->sr_ref != NULL ) {
			/* send referrals */
			rc = rs->sr_err = LDAP_REFERRAL;
			send_ldap_result( op, rs );
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;
		} else if ( rc != LDAP_SUCCESS ) {
			rs->sr_text = rs->sr_matched ? "bad referral object" : NULL;
		}

		LOCK_ID_FREE ( bdb->bi_dbenv, locker );
		if (rs->sr_matched) {
			op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
			rs->sr_matched = NULL;
		}
		return rc;
	}

	if ( is_entry_referral( e ) ) {
		/* entry is a referral */
		BerVarray refs = get_entry_referrals( op, e );
		rs->sr_ref = referral_rewrite(
			refs, &e->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT );

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_referrals)
			": tag=%lu target=\"%s\" matched=\"%s\"\n",
			(unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val );

		rs->sr_matched = e->e_name.bv_val;
		if( rs->sr_ref != NULL ) {
			rc = rs->sr_err = LDAP_REFERRAL;
			send_ldap_result( op, rs );
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;
		} else {
			rc = LDAP_OTHER;
			rs->sr_text = "bad referral object";
		}

		rs->sr_matched = NULL;
		ber_bvarray_free( refs );
	}

	bdb_cache_return_entry_r(bdb, e, &lock);
	LOCK_ID_FREE ( bdb->bi_dbenv, locker );
	return rc;
}
예제 #7
0
ID ndb_tool_entry_put(
	BackendDB *be,
	Entry *e,
	struct berval *text )
{
	struct dn_id dtmp, *dptr;
	NdbArgs NA;
	NdbRdns rdns;
	int rc, slow = 0;
	Operation op = {0};
	Opheader ohdr = {0};

	assert( be != NULL );
	assert( slapMode & SLAP_TOOL_MODE );

	assert( text != NULL );
	assert( text->bv_val != NULL );
	assert( text->bv_val[0] == '\0' );	/* overconservative? */

	Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(ndb_tool_entry_put)
		"( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn );

	if ( !be_issuffix( be, &e->e_nname )) {
		dnParent( &e->e_nname, &dtmp.dn );
		dptr = (struct dn_id *)avl_find( myParents, &dtmp, ndb_dnid_cmp );
		if ( !dptr )
			slow = 1;
	}

	rdns.nr_num = 0;

	op.o_hdr = &ohdr;
	op.o_bd = be;
	op.o_tmpmemctx = NULL;
	op.o_tmpmfuncs = &ch_mfuncs;

	if ( !slow ) {
		rc = ndb_next_id( be, myNdb, &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 );
			return rc;
		}
	}

	if ( !myPutTxn )
		myPutTxn = myNdb->startTransaction();
	if ( !myPutTxn ) {
		snprintf( text->bv_val, text->bv_len,
			"start_transaction failed: %s (%d)",
			myNdb->getNdbError().message, myNdb->getNdbError().code );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n", text->bv_val );
		return NOID;
	}

	/* add dn2id indices */
	ndb_dn2rdns( &e->e_name, &rdns );
	NA.rdns = &rdns;
	NA.e = e;
	NA.ndb = myNdb;
	NA.txn = myPutTxn;
	if ( slow ) {
		rc = ndb_tool_next_id( &op, &NA, text, 0 );
		if( rc != 0 ) {
			goto done;
		}
	} else {
		rc = ndb_entry_put_info( be, &NA, 0 );
		if ( rc != 0 ) {
			goto done;
		}
	}

	/* id2entry index */
	rc = ndb_entry_put_data( be, &NA );
	if( rc != 0 ) {
		snprintf( text->bv_val, text->bv_len,
				"ndb_entry_put_data failed: %s (%d)",
				myNdb->getNdbError().message, myNdb->getNdbError().code );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n", text->bv_val );
		goto done;
	}

done:
	if( rc == 0 ) {
		myPutCnt++;
		if ( !( myPutCnt & 0x0f )) {
			rc = myPutTxn->execute(NdbTransaction::Commit);
			if( rc != 0 ) {
				snprintf( text->bv_val, text->bv_len,
					"txn_commit failed: %s (%d)",
					myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
				Debug( LDAP_DEBUG_ANY,
					"=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n", text->bv_val );
				e->e_id = NOID;
			}
			myPutTxn->close();
			myPutTxn = NULL;
		}
	} else {
		snprintf( text->bv_val, text->bv_len,
			"txn_aborted! %s (%d)",
			myPutTxn->getNdbError().message, myPutTxn->getNdbError().code );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(ndb_tool_entry_put) ": %s\n", text->bv_val );
		e->e_id = NOID;
		myPutTxn->close();
	}

	return e->e_id;
}
예제 #8
0
파일: config.c 프로젝트: benegon/openldap
/* reindex entries on the fly */
static void *
mdb_online_index( void *ctx, void *arg )
{
	struct re_s *rtask = arg;
	BackendDB *be = rtask->arg;
	struct mdb_info *mdb = be->be_private;

	Connection conn = {0};
	OperationBuffer opbuf;
	Operation *op;

	MDB_cursor *curs;
	MDB_val key, data;
	MDB_txn *txn;
	ID id;
	Entry *e;
	int rc, getnext = 1;
	int i;

	connection_fake_init( &conn, &opbuf, ctx );
	op = &opbuf.ob_op;

	op->o_bd = be;

	id = 1;
	key.mv_size = sizeof(ID);

	while ( 1 ) {
		if ( slapd_shutdown )
			break;

		rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
		if ( rc )
			break;
		rc = mdb_cursor_open( txn, mdb->mi_id2entry, &curs );
		if ( rc ) {
			mdb_txn_abort( txn );
			break;
		}
		if ( getnext ) {
			getnext = 0;
			key.mv_data = &id;
			rc = mdb_cursor_get( curs, &key, &data, MDB_SET_RANGE );
			if ( rc ) {
				mdb_txn_abort( txn );
				if ( rc == MDB_NOTFOUND )
					rc = 0;
				break;
			}
			memcpy( &id, key.mv_data, sizeof( id ));
		}

		rc = mdb_id2entry( op, curs, id, &e );
		mdb_cursor_close( curs );
		if ( rc ) {
			mdb_txn_abort( txn );
			if ( rc == MDB_NOTFOUND ) {
				id++;
				getnext = 1;
				continue;
			}
			break;
		}
		rc = mdb_index_entry( op, txn, MDB_INDEX_UPDATE_OP, e );
		mdb_entry_return( op, e );
		if ( rc == 0 ) {
			rc = mdb_txn_commit( txn );
			txn = NULL;
		} else {
			mdb_txn_abort( txn );
			txn = NULL;
		}
		if ( rc ) {
			Debug( LDAP_DEBUG_ANY,
				LDAP_XSTRING(mdb_online_index) ": database %s: "
				"txn_commit failed: %s (%d)\n",
				be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
			break;
		}
		id++;
		getnext = 1;
	}

	for ( i = 0; i < mdb->mi_nattrs; i++ ) {
		if ( mdb->mi_attrs[ i ]->ai_indexmask & MDB_INDEX_DELETING
			|| mdb->mi_attrs[ i ]->ai_newmask == 0 )
		{
			continue;
		}
		mdb->mi_attrs[ i ]->ai_indexmask = mdb->mi_attrs[ i ]->ai_newmask;
		mdb->mi_attrs[ i ]->ai_newmask = 0;
	}

	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
	ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
	mdb->mi_index_task = NULL;
	ldap_pvt_runqueue_remove( &slapd_rq, rtask );
	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );

	return NULL;
}
예제 #9
0
파일: config.c 프로젝트: benegon/openldap
static int
mdb_cf_gen( ConfigArgs *c )
{
	struct mdb_info *mdb = c->be->be_private;
	int rc;

	if ( c->op == SLAP_CONFIG_EMIT ) {
		rc = 0;
		switch( c->type ) {
		case MDB_MODE: {
			char buf[64];
			struct berval bv;
			bv.bv_len = snprintf( buf, sizeof(buf), "0%o", mdb->mi_dbenv_mode );
			if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
				bv.bv_val = buf;
				value_add_one( &c->rvalue_vals, &bv );
			} else {
				rc = 1;
			}
			} break;

		case MDB_CHKPT:
			if ( mdb->mi_txn_cp ) {
				char buf[64];
				struct berval bv;
				bv.bv_len = snprintf( buf, sizeof(buf), "%ld %ld",
					(long) mdb->mi_txn_cp_kbyte, (long) mdb->mi_txn_cp_min );
				if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
					bv.bv_val = buf;
					value_add_one( &c->rvalue_vals, &bv );
				} else {
					rc = 1;
				}
			} else {
				rc = 1;
			}
			break;

		case MDB_DIRECTORY:
			if ( mdb->mi_dbenv_home ) {
				c->value_string = ch_strdup( mdb->mi_dbenv_home );
			} else {
				rc = 1;
			}
			break;

		case MDB_DBNOSYNC:
			if ( mdb->mi_dbenv_flags & MDB_NOSYNC )
				c->value_int = 1;
			break;

		case MDB_ENVFLAGS:
			if ( mdb->mi_dbenv_flags ) {
				mask_to_verbs( mdb_envflags, mdb->mi_dbenv_flags, &c->rvalue_vals );
			}
			if ( !c->rvalue_vals ) rc = 1;
			break;

		case MDB_INDEX:
			mdb_attr_index_unparse( mdb, &c->rvalue_vals );
			if ( !c->rvalue_vals ) rc = 1;
			break;

		case MDB_SSTACK:
			c->value_int = mdb->mi_search_stack_depth;
			break;

		case MDB_MAXREADERS:
			c->value_int = mdb->mi_readers;
			break;

		case MDB_MAXSIZE:
			c->value_ulong = mdb->mi_mapsize;
			break;
		}
		return rc;
	} else if ( c->op == LDAP_MOD_DELETE ) {
		rc = 0;
		switch( c->type ) {
		case MDB_MODE:
#if 0
			/* FIXME: does it make any sense to change the mode,
			 * if we don't exec a chmod()? */
			mdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
			break;
#endif

		/* single-valued no-ops */
		case MDB_SSTACK:
		case MDB_MAXREADERS:
		case MDB_MAXSIZE:
			break;

		case MDB_CHKPT:
			if ( mdb->mi_txn_cp_task ) {
				struct re_s *re = mdb->mi_txn_cp_task;
				mdb->mi_txn_cp_task = NULL;
				ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
				if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
					ldap_pvt_runqueue_stoptask( &slapd_rq, re );
				ldap_pvt_runqueue_remove( &slapd_rq, re );
				ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
			}
			mdb->mi_txn_cp = 0;
			break;
		case MDB_DIRECTORY:
			mdb->mi_flags |= MDB_RE_OPEN;
			ch_free( mdb->mi_dbenv_home );
			mdb->mi_dbenv_home = NULL;
			c->cleanup = mdb_cf_cleanup;
			ldap_pvt_thread_pool_purgekey( mdb->mi_dbenv );
			break;
		case MDB_DBNOSYNC:
			mdb_env_set_flags( mdb->mi_dbenv, MDB_NOSYNC, 0 );
			mdb->mi_dbenv_flags &= ~MDB_NOSYNC;
			break;

		case MDB_ENVFLAGS:
			if ( c->valx == -1 ) {
				int i;
				for ( i=0; mdb_envflags[i].mask; i++) {
					if ( mdb->mi_dbenv_flags & mdb_envflags[i].mask ) {
						/* not all flags are runtime resettable */
						rc = mdb_env_set_flags( mdb->mi_dbenv, mdb_envflags[i].mask, 0 );
						if ( rc ) {
							mdb->mi_flags |= MDB_RE_OPEN;
							c->cleanup = mdb_cf_cleanup;
							rc = 0;
						}
						mdb->mi_dbenv_flags ^= mdb_envflags[i].mask;
					}
				}
			} else {
				int i = verb_to_mask( c->line, mdb_envflags );
				if ( mdb_envflags[i].mask & mdb->mi_dbenv_flags ) {
					rc = mdb_env_set_flags( mdb->mi_dbenv, mdb_envflags[i].mask, 0 );
					if ( rc ) {
						mdb->mi_flags |= MDB_RE_OPEN;
						c->cleanup = mdb_cf_cleanup;
						rc = 0;
					}
					mdb->mi_dbenv_flags ^= mdb_envflags[i].mask;
				} else {
					/* unknown keyword */
					rc = 1;
				}
			}
			break;

		case MDB_INDEX:
			if ( c->valx == -1 ) {
				int i;

				/* delete all (FIXME) */
				for ( i = 0; i < mdb->mi_nattrs; i++ ) {
					mdb->mi_attrs[i]->ai_indexmask |= MDB_INDEX_DELETING;
				}
				mdb->mi_flags |= MDB_DEL_INDEX;
				c->cleanup = mdb_cf_cleanup;

			} else {
				struct berval bv, def = BER_BVC("default");
				char *ptr;

				for (ptr = c->line; !isspace( (unsigned char) *ptr ); ptr++);

				bv.bv_val = c->line;
				bv.bv_len = ptr - bv.bv_val;
				if ( bvmatch( &bv, &def )) {
					mdb->mi_defaultmask = 0;

				} else {
					int i;
					char **attrs;
					char sep;

					sep = bv.bv_val[ bv.bv_len ];
					bv.bv_val[ bv.bv_len ] = '\0';
					attrs = ldap_str2charray( bv.bv_val, "," );

					for ( i = 0; attrs[ i ]; i++ ) {
						AttributeDescription *ad = NULL;
						const char *text;
						AttrInfo *ai;

						slap_str2ad( attrs[ i ], &ad, &text );
						/* if we got here... */
						assert( ad != NULL );

						ai = mdb_attr_mask( mdb, ad );
						/* if we got here... */
						assert( ai != NULL );

						ai->ai_indexmask |= MDB_INDEX_DELETING;
						mdb->mi_flags |= MDB_DEL_INDEX;
						c->cleanup = mdb_cf_cleanup;
					}

					bv.bv_val[ bv.bv_len ] = sep;
					ldap_charray_free( attrs );
				}
			}
			break;
		}
		return rc;
	}

	switch( c->type ) {
	case MDB_MODE:
		if ( ASCII_DIGIT( c->argv[1][0] ) ) {
			long mode;
			char *next;
			errno = 0;
			mode = strtol( c->argv[1], &next, 0 );
			if ( errno != 0 || next == c->argv[1] || next[0] != '\0' ) {
				fprintf( stderr, "%s: "
					"unable to parse mode=\"%s\".\n",
					c->log, c->argv[1] );
				return 1;
			}
			mdb->mi_dbenv_mode = mode;

		} else {
			char *m = c->argv[1];
			int who, what, mode = 0;

			if ( strlen( m ) != STRLENOF("-rwxrwxrwx") ) {
				return 1;
			}

			if ( m[0] != '-' ) {
				return 1;
			}

			m++;
			for ( who = 0; who < 3; who++ ) {
				for ( what = 0; what < 3; what++, m++ ) {
					if ( m[0] == '-' ) {
						continue;
					} else if ( m[0] != "rwx"[what] ) {
						return 1;
					}
					mode += ((1 << (2 - what)) << 3*(2 - who));
				}
			}
			mdb->mi_dbenv_mode = mode;
		}
		break;
	case MDB_CHKPT: {
		long	l;
		mdb->mi_txn_cp = 1;
		if ( lutil_atolx( &l, c->argv[1], 0 ) != 0 ) {
			fprintf( stderr, "%s: "
				"invalid kbyte \"%s\" in \"checkpoint\".\n",
				c->log, c->argv[1] );
			return 1;
		}
		mdb->mi_txn_cp_kbyte = l;
		if ( lutil_atolx( &l, c->argv[2], 0 ) != 0 ) {
			fprintf( stderr, "%s: "
				"invalid minutes \"%s\" in \"checkpoint\".\n",
				c->log, c->argv[2] );
			return 1;
		}
		mdb->mi_txn_cp_min = l;
		/* If we're in server mode and time-based checkpointing is enabled,
		 * submit a task to perform periodic checkpoints.
		 */
		if ((slapMode & SLAP_SERVER_MODE) && mdb->mi_txn_cp_min ) {
			struct re_s *re = mdb->mi_txn_cp_task;
			if ( re ) {
				re->interval.tv_sec = mdb->mi_txn_cp_min * 60;
			} else {
				if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
					fprintf( stderr, "%s: "
						"\"checkpoint\" must occur after \"suffix\".\n",
						c->log );
					return 1;
				}
				ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
				mdb->mi_txn_cp_task = ldap_pvt_runqueue_insert( &slapd_rq,
					mdb->mi_txn_cp_min * 60, mdb_checkpoint, mdb,
					LDAP_XSTRING(mdb_checkpoint), c->be->be_suffix[0].bv_val );
				ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
			}
		}
		} break;

	case MDB_DIRECTORY: {
		FILE *f;
		char *ptr, *testpath;
		int len;

		len = strlen( c->value_string );
		testpath = ch_malloc( len + STRLENOF(LDAP_DIRSEP) + STRLENOF("DUMMY") + 1 );
		ptr = lutil_strcopy( testpath, c->value_string );
		*ptr++ = LDAP_DIRSEP[0];
		strcpy( ptr, "DUMMY" );
		f = fopen( testpath, "w" );
		if ( f ) {
			fclose( f );
			unlink( testpath );
		}
		ch_free( testpath );
		if ( !f ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: invalid path: %s",
				c->log, strerror( errno ));
			Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
			return -1;
		}

		if ( mdb->mi_dbenv_home )
			ch_free( mdb->mi_dbenv_home );
		mdb->mi_dbenv_home = c->value_string;

		}
		break;

	case MDB_DBNOSYNC:
		if ( c->value_int )
			mdb->mi_dbenv_flags |= MDB_NOSYNC;
		else
			mdb->mi_dbenv_flags ^= MDB_NOSYNC;
		if ( mdb->mi_flags & MDB_IS_OPEN ) {
			mdb_env_set_flags( mdb->mi_dbenv, MDB_NOSYNC,
				c->value_int );
		}
		break;

	case MDB_ENVFLAGS: {
		int i, j;
		for ( i=1; i<c->argc; i++ ) {
			j = verb_to_mask( c->argv[i], mdb_envflags );
			if ( mdb_envflags[j].mask ) {
				if ( mdb->mi_flags & MDB_IS_OPEN )
					rc = mdb_env_set_flags( mdb->mi_dbenv, mdb_envflags[j].mask, 1 );
				else
					rc = 0;
				if ( rc ) {
					mdb->mi_flags |= MDB_RE_OPEN;
					c->cleanup = mdb_cf_cleanup;
					rc = 0;
				}
				mdb->mi_dbenv_flags |= mdb_envflags[j].mask;
			} else {
				/* unknown keyword */
				rc = 1;
			}
		}
		}
		break;

	case MDB_INDEX:
		rc = mdb_attr_index_config( mdb, c->fname, c->lineno,
			c->argc - 1, &c->argv[1], &c->reply);

		if( rc != LDAP_SUCCESS ) return 1;
		c->cleanup = mdb_cf_cleanup;
		mdb->mi_flags |= MDB_OPEN_INDEX;
		if (( mdb->mi_flags & MDB_IS_OPEN ) && !mdb->mi_index_task ) {
			/* Start the task as soon as we finish here. Set a long
			 * interval (10 hours) so that it only gets scheduled once.
			 */
			if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
				fprintf( stderr, "%s: "
					"\"index\" must occur after \"suffix\".\n",
					c->log );
				return 1;
			}
			ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
			mdb->mi_index_task = ldap_pvt_runqueue_insert( &slapd_rq, 36000,
				mdb_online_index, c->be,
				LDAP_XSTRING(mdb_online_index), c->be->be_suffix[0].bv_val );
			ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
		}
		break;

	case MDB_SSTACK:
		if ( c->value_int < MINIMUM_SEARCH_STACK_DEPTH ) {
			fprintf( stderr,
		"%s: depth %d too small, using %d\n",
			c->log, c->value_int, MINIMUM_SEARCH_STACK_DEPTH );
			c->value_int = MINIMUM_SEARCH_STACK_DEPTH;
		}
		mdb->mi_search_stack_depth = c->value_int;
		break;

	case MDB_MAXREADERS:
		mdb->mi_readers = c->value_int;
		if ( mdb->mi_flags & MDB_IS_OPEN ) {
			mdb->mi_flags |= MDB_RE_OPEN;
			c->cleanup = mdb_cf_cleanup;
		}
		break;

	case MDB_MAXSIZE:
		mdb->mi_mapsize = c->value_ulong;
		if ( mdb->mi_flags & MDB_IS_OPEN ) {
			mdb->mi_flags |= MDB_RE_OPEN;
			c->cleanup = mdb_cf_cleanup;
		}
		break;

	}
	return 0;
}
예제 #10
0
파일: config.c 프로젝트: bagel/openldap-ga
/* reindex entries on the fly */
static void *
bdb_online_index( void *ctx, void *arg )
{
	struct re_s *rtask = arg;
	BackendDB *be = rtask->arg;
	struct bdb_info *bdb = be->be_private;

	Connection conn = {0};
	OperationBuffer opbuf;
	Operation *op;

	DBC *curs;
	DBT key, data;
	DB_TXN *txn;
	DB_LOCK lock;
	ID id, nid;
	EntryInfo *ei;
	int rc, getnext = 1;
	int i;

	connection_fake_init( &conn, &opbuf, ctx );
	op = &opbuf.ob_op;

	op->o_bd = be;

	DBTzero( &key );
	DBTzero( &data );
	
	id = 1;
	key.data = &nid;
	key.size = key.ulen = sizeof(ID);
	key.flags = DB_DBT_USERMEM;

	data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
	data.dlen = data.ulen = 0;

	while ( 1 ) {
		if ( slapd_shutdown )
			break;

		rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &txn, bdb->bi_db_opflags );
		if ( rc ) 
			break;
		Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_online_index) ": txn id: %x\n",
			txn->id(txn), 0, 0 );
		if ( getnext ) {
			getnext = 0;
			BDB_ID2DISK( id, &nid );
			rc = bdb->bi_id2entry->bdi_db->cursor(
				bdb->bi_id2entry->bdi_db, txn, &curs, bdb->bi_db_opflags );
			if ( rc ) {
				TXN_ABORT( txn );
				break;
			}
			rc = curs->c_get( curs, &key, &data, DB_SET_RANGE );
			curs->c_close( curs );
			if ( rc ) {
				TXN_ABORT( txn );
				if ( rc == DB_NOTFOUND )
					rc = 0;
				if ( rc == DB_LOCK_DEADLOCK ) {
					ldap_pvt_thread_yield();
					continue;
				}
				break;
			}
			BDB_DISK2ID( &nid, &id );
		}

		ei = NULL;
		rc = bdb_cache_find_id( op, txn, id, &ei, 0, &lock );
		if ( rc ) {
			TXN_ABORT( txn );
			if ( rc == DB_LOCK_DEADLOCK ) {
				ldap_pvt_thread_yield();
				continue;
			}
			if ( rc == DB_NOTFOUND ) {
				id++;
				getnext = 1;
				continue;
			}
			break;
		}
		if ( ei->bei_e ) {
			rc = bdb_index_entry( op, txn, BDB_INDEX_UPDATE_OP, ei->bei_e );
			if ( rc ) {
				TXN_ABORT( txn );
				if ( rc == DB_LOCK_DEADLOCK ) {
					ldap_pvt_thread_yield();
					continue;
				}
				break;
			}
			rc = TXN_COMMIT( txn, 0 );
			txn = NULL;
		}
		id++;
		getnext = 1;
	}

	for ( i = 0; i < bdb->bi_nattrs; i++ ) {
		if ( bdb->bi_attrs[ i ]->ai_indexmask & BDB_INDEX_DELETING
			|| bdb->bi_attrs[ i ]->ai_newmask == 0 )
		{
			continue;
		}
		bdb->bi_attrs[ i ]->ai_indexmask = bdb->bi_attrs[ i ]->ai_newmask;
		bdb->bi_attrs[ i ]->ai_newmask = 0;
	}

	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
	ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
	bdb->bi_index_task = NULL;
	ldap_pvt_runqueue_remove( &slapd_rq, rtask );
	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );

	return NULL;
}
예제 #11
0
파일: config.c 프로젝트: bagel/openldap-ga
static int
bdb_cf_gen( ConfigArgs *c )
{
	struct bdb_info *bdb = c->be->be_private;
	int rc;

	if ( c->op == SLAP_CONFIG_EMIT ) {
		rc = 0;
		switch( c->type ) {
		case BDB_MODE: {
			char buf[64];
			struct berval bv;
			bv.bv_len = snprintf( buf, sizeof(buf), "0%o", bdb->bi_dbenv_mode );
			if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
				bv.bv_val = buf;
				value_add_one( &c->rvalue_vals, &bv );
			} else {
				rc = 1;
			}
			} break;

		case BDB_CHKPT:
			if ( bdb->bi_txn_cp ) {
				char buf[64];
				struct berval bv;
				bv.bv_len = snprintf( buf, sizeof(buf), "%ld %ld",
					(long) bdb->bi_txn_cp_kbyte, (long) bdb->bi_txn_cp_min );
				if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
					bv.bv_val = buf;
					value_add_one( &c->rvalue_vals, &bv );
				} else {
					rc = 1;
				}
			} else {
				rc = 1;
			}
			break;

		case BDB_CRYPTFILE:
			if ( bdb->bi_db_crypt_file ) {
				c->value_string = ch_strdup( bdb->bi_db_crypt_file );
			} else {
				rc = 1;
			}
			break;

		/* If a crypt file has been set, its contents are copied here.
		 * But we don't want the key to be incorporated here.
		 */
		case BDB_CRYPTKEY:
			if ( !bdb->bi_db_crypt_file && !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
				value_add_one( &c->rvalue_vals, &bdb->bi_db_crypt_key );
			} else {
				rc = 1;
			}
			break;

		case BDB_DIRECTORY:
			if ( bdb->bi_dbenv_home ) {
				c->value_string = ch_strdup( bdb->bi_dbenv_home );
			} else {
				rc = 1;
			}
			break;

		case BDB_CONFIG:
			if ( !( bdb->bi_flags & BDB_IS_OPEN )
				&& !bdb->bi_db_config )
			{
				char	buf[SLAP_TEXT_BUFLEN];
				FILE *f = fopen( bdb->bi_db_config_path, "r" );
				struct berval bv;

				if ( f ) {
					bdb->bi_flags |= BDB_HAS_CONFIG;
					while ( fgets( buf, sizeof(buf), f )) {
						ber_str2bv( buf, 0, 1, &bv );
						if ( bv.bv_len > 0 && bv.bv_val[bv.bv_len-1] == '\n' ) {
							bv.bv_len--;
							bv.bv_val[bv.bv_len] = '\0';
						}
						/* shouldn't need this, but ... */
						if ( bv.bv_len > 0 && bv.bv_val[bv.bv_len-1] == '\r' ) {
							bv.bv_len--;
							bv.bv_val[bv.bv_len] = '\0';
						}
						ber_bvarray_add( &bdb->bi_db_config, &bv );
					}
					fclose( f );
				}
			}
			if ( bdb->bi_db_config ) {
				int i;
				struct berval bv;

				bv.bv_val = c->log;
				for (i=0; !BER_BVISNULL(&bdb->bi_db_config[i]); i++) {
					bv.bv_len = sprintf( bv.bv_val, "{%d}%s", i,
						bdb->bi_db_config[i].bv_val );
					value_add_one( &c->rvalue_vals, &bv );
				}
			}
			if ( !c->rvalue_vals ) rc = 1;
			break;

		case BDB_NOSYNC:
			if ( bdb->bi_dbenv_xflags & DB_TXN_NOSYNC )
				c->value_int = 1;
			break;
			
		case BDB_CHECKSUM:
			if ( bdb->bi_flags & BDB_CHKSUM )
				c->value_int = 1;
			break;

		case BDB_INDEX:
			bdb_attr_index_unparse( bdb, &c->rvalue_vals );
			if ( !c->rvalue_vals ) rc = 1;
			break;

		case BDB_LOCKD:
			rc = 1;
			if ( bdb->bi_lock_detect != DB_LOCK_DEFAULT ) {
				int i;
				for (i=0; !BER_BVISNULL(&bdb_lockd[i].word); i++) {
					if ( bdb->bi_lock_detect == (u_int32_t)bdb_lockd[i].mask ) {
						value_add_one( &c->rvalue_vals, &bdb_lockd[i].word );
						rc = 0;
						break;
					}
				}
			}
			break;

		case BDB_SSTACK:
			c->value_int = bdb->bi_search_stack_depth;
			break;

		case BDB_PGSIZE: {
				struct bdb_db_pgsize *ps;
				char buf[SLAP_TEXT_BUFLEN];
				struct berval bv;
				int rc = 1;

				bv.bv_val = buf;
				for ( ps = bdb->bi_pagesizes; ps; ps = ps->bdp_next ) {
					bv.bv_len = sprintf( buf, "%s %d", ps->bdp_name.bv_val,
						ps->bdp_size / 1024 );
					value_add_one( &c->rvalue_vals, &bv );
					rc = 0;

				}
				break;
			}
		}
		return rc;
	} else if ( c->op == LDAP_MOD_DELETE ) {
		rc = 0;
		switch( c->type ) {
		case BDB_MODE:
#if 0
			/* FIXME: does it make any sense to change the mode,
			 * if we don't exec a chmod()? */
			bdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
			break;
#endif

		/* single-valued no-ops */
		case BDB_LOCKD:
		case BDB_SSTACK:
			break;

		case BDB_CHKPT:
			if ( bdb->bi_txn_cp_task ) {
				struct re_s *re = bdb->bi_txn_cp_task;
				bdb->bi_txn_cp_task = NULL;
				ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
				if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
					ldap_pvt_runqueue_stoptask( &slapd_rq, re );
				ldap_pvt_runqueue_remove( &slapd_rq, re );
				ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
			}
			bdb->bi_txn_cp = 0;
			break;
		case BDB_CONFIG:
			if ( c->valx < 0 ) {
				ber_bvarray_free( bdb->bi_db_config );
				bdb->bi_db_config = NULL;
			} else {
				int i = c->valx;
				ch_free( bdb->bi_db_config[i].bv_val );
				for (; bdb->bi_db_config[i].bv_val; i++)
					bdb->bi_db_config[i] = bdb->bi_db_config[i+1];
			}
			bdb->bi_flags |= BDB_UPD_CONFIG|BDB_RE_OPEN;
			c->cleanup = bdb_cf_cleanup;
			break;
		/* Doesn't really make sense to change these on the fly;
		 * the entire DB must be dumped and reloaded
		 */
		case BDB_CRYPTFILE:
			if ( bdb->bi_db_crypt_file ) {
				ch_free( bdb->bi_db_crypt_file );
				bdb->bi_db_crypt_file = NULL;
			}
			/* FALLTHRU */
		case BDB_CRYPTKEY:
			if ( !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
				ch_free( bdb->bi_db_crypt_key.bv_val );
				BER_BVZERO( &bdb->bi_db_crypt_key );
			}
			break;
		case BDB_DIRECTORY:
			bdb->bi_flags |= BDB_RE_OPEN;
			bdb->bi_flags ^= BDB_HAS_CONFIG;
			ch_free( bdb->bi_dbenv_home );
			bdb->bi_dbenv_home = NULL;
			ch_free( bdb->bi_db_config_path );
			bdb->bi_db_config_path = NULL;
			c->cleanup = bdb_cf_cleanup;
			ldap_pvt_thread_pool_purgekey( bdb->bi_dbenv );
			break;
		case BDB_NOSYNC:
			bdb->bi_dbenv->set_flags( bdb->bi_dbenv, DB_TXN_NOSYNC, 0 );
			break;
		case BDB_CHECKSUM:
			bdb->bi_flags &= ~BDB_CHKSUM;
			break;
		case BDB_INDEX:
			if ( c->valx == -1 ) {
				int i;

				/* delete all (FIXME) */
				for ( i = 0; i < bdb->bi_nattrs; i++ ) {
					bdb->bi_attrs[i]->ai_indexmask |= BDB_INDEX_DELETING;
				}
				bdb->bi_flags |= BDB_DEL_INDEX;
				c->cleanup = bdb_cf_cleanup;

			} else {
				struct berval bv, def = BER_BVC("default");
				char *ptr;

				for (ptr = c->line; !isspace( (unsigned char) *ptr ); ptr++);

				bv.bv_val = c->line;
				bv.bv_len = ptr - bv.bv_val;
				if ( bvmatch( &bv, &def )) {
					bdb->bi_defaultmask = 0;

				} else {
					int i;
					char **attrs;
					char sep;

					sep = bv.bv_val[ bv.bv_len ];
					bv.bv_val[ bv.bv_len ] = '\0';
					attrs = ldap_str2charray( bv.bv_val, "," );

					for ( i = 0; attrs[ i ]; i++ ) {
						AttributeDescription *ad = NULL;
						const char *text;
						AttrInfo *ai;

						slap_str2ad( attrs[ i ], &ad, &text );
						/* if we got here... */
						assert( ad != NULL );

						ai = bdb_attr_mask( bdb, ad );
						/* if we got here... */
						assert( ai != NULL );

						ai->ai_indexmask |= BDB_INDEX_DELETING;
						bdb->bi_flags |= BDB_DEL_INDEX;
						c->cleanup = bdb_cf_cleanup;
					}

					bv.bv_val[ bv.bv_len ] = sep;
					ldap_charray_free( attrs );
				}
			}
			break;
		/* doesn't make sense on the fly; the DB file must be
		 * recreated
		 */
		case BDB_PGSIZE: {
				struct bdb_db_pgsize *ps, **prev;
				int i;

				for ( i = 0, prev = &bdb->bi_pagesizes, ps = *prev; ps;
					prev = &ps->bdp_next, ps = ps->bdp_next, i++ ) {
					if ( c->valx == -1 || i == c->valx ) {
						*prev = ps->bdp_next;
						ch_free( ps );
						ps = *prev;
						if ( i == c->valx ) break;
					}
				}
			}
			break;
		}
		return rc;
	}

	switch( c->type ) {
	case BDB_MODE:
		if ( ASCII_DIGIT( c->argv[1][0] ) ) {
			long mode;
			char *next;
			errno = 0;
			mode = strtol( c->argv[1], &next, 0 );
			if ( errno != 0 || next == c->argv[1] || next[0] != '\0' ) {
				fprintf( stderr, "%s: "
					"unable to parse mode=\"%s\".\n",
					c->log, c->argv[1] );
				return 1;
			}
			bdb->bi_dbenv_mode = mode;

		} else {
			char *m = c->argv[1];
			int who, what, mode = 0;

			if ( strlen( m ) != STRLENOF("-rwxrwxrwx") ) {
				return 1;
			}

			if ( m[0] != '-' ) {
				return 1;
			}

			m++;
			for ( who = 0; who < 3; who++ ) {
				for ( what = 0; what < 3; what++, m++ ) {
					if ( m[0] == '-' ) {
						continue;
					} else if ( m[0] != "rwx"[what] ) {
						return 1;
					}
					mode += ((1 << (2 - what)) << 3*(2 - who));
				}
			}
			bdb->bi_dbenv_mode = mode;
		}
		break;
	case BDB_CHKPT: {
		long	l;
		bdb->bi_txn_cp = 1;
		if ( lutil_atolx( &l, c->argv[1], 0 ) != 0 ) {
			fprintf( stderr, "%s: "
				"invalid kbyte \"%s\" in \"checkpoint\".\n",
				c->log, c->argv[1] );
			return 1;
		}
		bdb->bi_txn_cp_kbyte = l;
		if ( lutil_atolx( &l, c->argv[2], 0 ) != 0 ) {
			fprintf( stderr, "%s: "
				"invalid minutes \"%s\" in \"checkpoint\".\n",
				c->log, c->argv[2] );
			return 1;
		}
		bdb->bi_txn_cp_min = l;
		/* If we're in server mode and time-based checkpointing is enabled,
		 * submit a task to perform periodic checkpoints.
		 */
		if ((slapMode & SLAP_SERVER_MODE) && bdb->bi_txn_cp_min ) {
			struct re_s *re = bdb->bi_txn_cp_task;
			if ( re ) {
				re->interval.tv_sec = bdb->bi_txn_cp_min * 60;
			} else {
				if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
					fprintf( stderr, "%s: "
						"\"checkpoint\" must occur after \"suffix\".\n",
						c->log );
					return 1;
				}
				ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
				bdb->bi_txn_cp_task = ldap_pvt_runqueue_insert( &slapd_rq,
					bdb->bi_txn_cp_min * 60, bdb_checkpoint, bdb,
					LDAP_XSTRING(bdb_checkpoint), c->be->be_suffix[0].bv_val );
				ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
			}
		}
		} break;

	case BDB_CONFIG: {
		char *ptr = c->line;
		struct berval bv;

		if ( c->op == SLAP_CONFIG_ADD ) {
			ptr += STRLENOF("dbconfig");
			while (!isspace((unsigned char)*ptr)) ptr++;
			while (isspace((unsigned char)*ptr)) ptr++;
		}

		if ( bdb->bi_flags & BDB_IS_OPEN ) {
			bdb->bi_flags |= BDB_UPD_CONFIG|BDB_RE_OPEN;
			c->cleanup = bdb_cf_cleanup;
		} else {
		/* If we're just starting up...
		 */
			FILE *f;
			/* If a DB_CONFIG file exists, or we don't know the path
			 * to the DB_CONFIG file, ignore these directives
			 */
			if (( bdb->bi_flags & BDB_HAS_CONFIG ) || !bdb->bi_db_config_path )
				break;
			f = fopen( bdb->bi_db_config_path, "a" );
			if ( f ) {
				/* FIXME: EBCDIC probably needs special handling */
				fprintf( f, "%s\n", ptr );
				fclose( f );
			}
		}
		ber_str2bv( ptr, 0, 1, &bv );
		ber_bvarray_add( &bdb->bi_db_config, &bv );
		}
		break;

	case BDB_CRYPTFILE:
		rc = lutil_get_filed_password( c->value_string, &bdb->bi_db_crypt_key );
		if ( rc == 0 ) {
			bdb->bi_db_crypt_file = c->value_string;
		}
		break;

	/* Cannot set key if file was already set */
	case BDB_CRYPTKEY:
		if ( bdb->bi_db_crypt_file ) {
			rc = 1;
		} else {
			bdb->bi_db_crypt_key = c->value_bv;
		}
		break;

	case BDB_DIRECTORY: {
		FILE *f;
		char *ptr, *testpath;
		int len;

		len = strlen( c->value_string );
		testpath = ch_malloc( len + STRLENOF(LDAP_DIRSEP) + STRLENOF("DUMMY") + 1 );
		ptr = lutil_strcopy( testpath, c->value_string );
		*ptr++ = LDAP_DIRSEP[0];
		strcpy( ptr, "DUMMY" );
		f = fopen( testpath, "w" );
		if ( f ) {
			fclose( f );
			unlink( testpath );
		}
		ch_free( testpath );
		if ( !f ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: invalid path: %s",
				c->log, strerror( errno ));
			Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
			return -1;
		}

		if ( bdb->bi_dbenv_home )
			ch_free( bdb->bi_dbenv_home );
		bdb->bi_dbenv_home = c->value_string;

		/* See if a DB_CONFIG file already exists here */
		if ( bdb->bi_db_config_path )
			ch_free( bdb->bi_db_config_path );
		bdb->bi_db_config_path = ch_malloc( len +
			STRLENOF(LDAP_DIRSEP) + STRLENOF("DB_CONFIG") + 1 );
		ptr = lutil_strcopy( bdb->bi_db_config_path, bdb->bi_dbenv_home );
		*ptr++ = LDAP_DIRSEP[0];
		strcpy( ptr, "DB_CONFIG" );

		f = fopen( bdb->bi_db_config_path, "r" );
		if ( f ) {
			bdb->bi_flags |= BDB_HAS_CONFIG;
			fclose(f);
		}
		}
		break;

	case BDB_NOSYNC:
		if ( c->value_int )
			bdb->bi_dbenv_xflags |= DB_TXN_NOSYNC;
		else
			bdb->bi_dbenv_xflags &= ~DB_TXN_NOSYNC;
		if ( bdb->bi_flags & BDB_IS_OPEN ) {
			bdb->bi_dbenv->set_flags( bdb->bi_dbenv, DB_TXN_NOSYNC,
				c->value_int );
		}
		break;

	case BDB_CHECKSUM:
		if ( c->value_int )
			bdb->bi_flags |= BDB_CHKSUM;
		else
			bdb->bi_flags &= ~BDB_CHKSUM;
		break;

	case BDB_INDEX:
		rc = bdb_attr_index_config( bdb, c->fname, c->lineno,
			c->argc - 1, &c->argv[1], &c->reply);

		if( rc != LDAP_SUCCESS ) return 1;
		if (( bdb->bi_flags & BDB_IS_OPEN ) && !bdb->bi_index_task ) {
			/* Start the task as soon as we finish here. Set a long
			 * interval (10 hours) so that it only gets scheduled once.
			 */
			if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
				fprintf( stderr, "%s: "
					"\"index\" must occur after \"suffix\".\n",
					c->log );
				return 1;
			}
			ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
			bdb->bi_index_task = ldap_pvt_runqueue_insert( &slapd_rq, 36000,
				bdb_online_index, c->be,
				LDAP_XSTRING(bdb_online_index), c->be->be_suffix[0].bv_val );
			ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
		}
		break;

	case BDB_LOCKD:
		rc = verb_to_mask( c->argv[1], bdb_lockd );
		if ( BER_BVISNULL(&bdb_lockd[rc].word) ) {
			fprintf( stderr, "%s: "
				"bad policy (%s) in \"lockDetect <policy>\" line\n",
				c->log, c->argv[1] );
			return 1;
		}
		bdb->bi_lock_detect = (u_int32_t)rc;
		break;

	case BDB_SSTACK:
		if ( c->value_int < MINIMUM_SEARCH_STACK_DEPTH ) {
			fprintf( stderr,
		"%s: depth %d too small, using %d\n",
			c->log, c->value_int, MINIMUM_SEARCH_STACK_DEPTH );
			c->value_int = MINIMUM_SEARCH_STACK_DEPTH;
		}
		bdb->bi_search_stack_depth = c->value_int;
		break;

	case BDB_PGSIZE: {
		struct bdb_db_pgsize *ps, **prev;
		int i, s;
		
		s = atoi(c->argv[2]);
		if ( s < 1 || s > 64 ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg ),
				"%s: size must be > 0 and <= 64: %d",
				c->log, s );
			Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
			return -1;
		}
		i = strlen(c->argv[1]);
		ps = ch_malloc( sizeof(struct bdb_db_pgsize) + i + 1 );
		ps->bdp_next = NULL;
		ps->bdp_name.bv_len = i;
		ps->bdp_name.bv_val = (char *)(ps+1);
		strcpy( ps->bdp_name.bv_val, c->argv[1] );
		ps->bdp_size = s * 1024;
		for ( prev = &bdb->bi_pagesizes; *prev; prev = &(*prev)->bdp_next )
			;
		*prev = ps;
		}
		break;
	}
	return 0;
}
예제 #12
0
파일: init.c 프로젝트: osstech-jp/openldap
static int
wt_db_open( BackendDB *be, ConfigReply *cr )
{
	struct wt_info *wi = (struct wt_info *) be->be_private;
	int rc;
	struct stat st;
	WT_CONNECTION *conn;
	WT_SESSION *session;

	if ( be->be_suffix == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": need suffix.\n",
			   1, 0, 0 );
		return -1;
	}

	Debug( LDAP_DEBUG_ARGS,
		   LDAP_XSTRING(wt_db_open) ": \"%s\"\n",
		   be->be_suffix[0].bv_val, 0, 0 );

	/* Check existence of home. Any error means trouble */
	rc = stat( wi->wi_dbenv_home, &st );
	if( rc ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": database \"%s\": "
			   "cannot access database directory \"%s\" (%d).\n",
			   be->be_suffix[0].bv_val, wi->wi_dbenv_home, errno );
		return -1;
	}

	/* Open and create database */
	rc = wiredtiger_open(wi->wi_dbenv_home, NULL,
						 wi->wi_dbenv_config, &conn);
	if( rc ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": database \"%s\": "
			   "cannot open database \"%s\" (%d).\n",
			   be->be_suffix[0].bv_val, wi->wi_dbenv_home, errno );
		return -1;
	}

	rc = conn->open_session(conn, NULL, NULL, &session);
	if( rc ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": database \"%s\": "
			   "cannot open session: \"%s\"\n",
			   be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
		return -1;
	}

	rc = session->create(session,
						 WT_TABLE_ID2ENTRY,
						 "key_format=Q,"
						 "value_format=Su,"
						 "columns=(id,dn,entry)");
	if( rc ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": database \"%s\": "
			   "cannot create entry table: \"%s\"\n",
			   be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
		return -1;
	}

	rc = session->create(session,
						 WT_TABLE_DN2ID,
						 "key_format=S,"
						 "value_format=QQS,"
						 "columns=(ndn,id,pid,revdn)");
	if( rc ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": database \"%s\": "
			   "cannot create entry table: \"%s\"\n",
			   be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
		return -1;
	}

	/* not using dn2id index for id2entry table */
	rc = session->create(session, WT_INDEX_DN, "columns=(dn)");
	if( rc ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": database \"%s\": "
			   "cannot create dn index: \"%s\"\n",
			   be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
		return -1;
	}

	rc = session->create(session, WT_INDEX_PID, "columns=(pid)");
	if( rc ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": database \"%s\": "
			   "cannot create pid index: \"%s\"\n",
			   be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
		return -1;
	}

	rc = session->create(session, WT_INDEX_REVDN, "columns=(revdn)");
	if( rc ) {
		Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": database \"%s\": "
			   "cannot create revdn index: \"%s\"\n",
			   be->be_suffix[0].bv_val, wiredtiger_strerror(rc), 0);
		return -1;
	}

	rc = wt_last_id( be, session, &wi->wi_lastid);
	if (rc) {
		snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
				  "last_id() failed: %s(%d).",
				  be->be_suffix[0].bv_val, wiredtiger_strerror(rc), rc );
        Debug( LDAP_DEBUG_ANY,
			   LDAP_XSTRING(wt_db_open) ": %s\n",
			   cr->msg, 0, 0 );
		return rc;
	}

	session->close(session, NULL);
	wi->wi_conn = conn;
	wi->wi_flags |= WT_IS_OPEN;

    return LDAP_SUCCESS;
}
예제 #13
0
파일: init.c 프로젝트: osstech-jp/openldap
int
wt_back_initialize( BackendInfo *bi )
{
	static char *controls[] = {
		LDAP_CONTROL_ASSERT,
		LDAP_CONTROL_MANAGEDSAIT,
		LDAP_CONTROL_NOOP,
		LDAP_CONTROL_PAGEDRESULTS,
		LDAP_CONTROL_PRE_READ,
		LDAP_CONTROL_POST_READ,
		LDAP_CONTROL_SUBENTRIES,
		LDAP_CONTROL_X_PERMISSIVE_MODIFY,
		NULL
	};

	/* initialize the database system */
	Debug( LDAP_DEBUG_TRACE,
		   LDAP_XSTRING(wt_back_initialize)
		   ": initialize WiredTiger backend\n",
		   0, 0, 0 );

	bi->bi_flags |=
		SLAP_BFLAG_INCREMENT |
		SLAP_BFLAG_SUBENTRIES |
		SLAP_BFLAG_ALIASES |
		SLAP_BFLAG_REFERRALS;

	bi->bi_controls = controls;

	{ /* version check */
		Debug( LDAP_DEBUG_TRACE,
			   LDAP_XSTRING(wt_back_initialize) ": %s\n",
			   wiredtiger_version(NULL, NULL, NULL), 0, 0 );
	}

	bi->bi_open = 0;
	bi->bi_close = 0;
	bi->bi_config = 0;
	bi->bi_destroy = 0;

	bi->bi_db_init = wt_db_init;
	bi->bi_db_config = config_generic_wrapper;
	bi->bi_db_open = wt_db_open;
	bi->bi_db_close = wt_db_close;
	bi->bi_db_destroy = wt_db_destroy;

	bi->bi_op_add = wt_add;
	bi->bi_op_bind = wt_bind;
	bi->bi_op_unbind = 0;
	bi->bi_op_search = wt_search;
	bi->bi_op_compare = wt_compare;
	bi->bi_op_modify = wt_modify;
	bi->bi_op_modrdn = 0;
	bi->bi_op_delete = wt_delete;
	bi->bi_op_abandon = 0;

	bi->bi_extended = 0;

	bi->bi_chk_referrals = 0;
	bi->bi_operational = wt_operational;

	bi->bi_entry_release_rw = wt_entry_release;
	bi->bi_entry_get_rw = wt_entry_get;

	bi->bi_tool_entry_open = wt_tool_entry_open;
	bi->bi_tool_entry_close = wt_tool_entry_close;
	bi->bi_tool_entry_first = backend_tool_entry_first;
	bi->bi_tool_entry_first_x = wt_tool_entry_first_x;
	bi->bi_tool_entry_next = wt_tool_entry_next;
	bi->bi_tool_entry_get = wt_tool_entry_get;
	bi->bi_tool_entry_put = wt_tool_entry_put;
	bi->bi_tool_entry_reindex = wt_tool_entry_reindex;

	bi->bi_connection_init = 0;
	bi->bi_connection_destroy = 0;

	return wt_back_init_cf( bi );
}
예제 #14
0
파일: delete.c 프로젝트: benegon/openldap
int
mdb_delete( Operation *op, SlapReply *rs )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
	struct berval	pdn = {0, NULL};
	Entry	*e = NULL;
	Entry	*p = NULL;
	int		manageDSAit = get_manageDSAit( op );
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	MDB_txn		*txn = NULL;
	MDB_cursor	*mc;
	mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;

	LDAPControl **preread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

	int	parent_is_glue = 0;
	int parent_is_leaf = 0;

#ifdef LDAP_X_TXN
	int settle = 0;
#endif

	Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(mdb_delete) ": %s\n",
		op->o_req_dn.bv_val, 0, 0 );

#ifdef LDAP_X_TXN
	if( op->o_txnSpec ) {
		/* acquire connection lock */
		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
		if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
			rs->sr_text = "invalid transaction identifier";
			rs->sr_err = LDAP_X_TXN_ID_INVALID;
			goto txnReturn;
		} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
			settle=1;
			goto txnReturn;
		}

		if( op->o_conn->c_txn_backend == NULL ) {
			op->o_conn->c_txn_backend = op->o_bd;

		} else if( op->o_conn->c_txn_backend != op->o_bd ) {
			rs->sr_text = "transaction cannot span multiple database contexts";
			rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
			goto txnReturn;
		}

		/* insert operation into transaction */

		rs->sr_text = "transaction specified";
		rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;

txnReturn:
		/* release connection lock */
		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );

		if( !settle ) {
			send_ldap_result( op, rs );
			return rs->sr_err;
		}
	}
#endif

	ctrls[num_ctrls] = 0;

	/* begin transaction */
	rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_delete) ": txn_begin failed: "
			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	txn = moi->moi_txn;

	/* allocate CSN */
	if ( BER_BVISNULL( &op->o_csn ) ) {
		struct berval csn;
		char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];

		csn.bv_val = csnbuf;
		csn.bv_len = sizeof(csnbuf);
		slap_get_csn( op, &csn, 1 );
	}

	if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
		dnParent( &op->o_req_ndn, &pdn );
	}

	rs->sr_err = mdb_cursor_open( txn, mdb->mi_dn2id, &mc );
	if ( rs->sr_err ) {
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	/* get parent */
	rs->sr_err = mdb_dn2entry( op, txn, mc, &pdn, &p, NULL, 1 );
	switch( rs->sr_err ) {
	case 0:
	case MDB_NOTFOUND:
		break;
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	if ( rs->sr_err == MDB_NOTFOUND ) {
		Debug( LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
			op->o_req_dn.bv_val, 0, 0);

		if ( p && !BER_BVISEMPTY( &p->e_name )) {
			rs->sr_matched = ch_strdup( p->e_name.bv_val );
			if ( is_entry_referral( p )) {
				BerVarray ref = get_entry_referrals( op, p );
				rs->sr_ref = referral_rewrite( ref, &p->e_name,
					&op->o_req_dn, LDAP_SCOPE_DEFAULT );
				ber_bvarray_free( ref );
			} else {
				rs->sr_ref = NULL;
			}
		} else {
			rs->sr_ref = referral_rewrite( default_referral, NULL,
					&op->o_req_dn, LDAP_SCOPE_DEFAULT );
		}
		if ( p ) {
			mdb_entry_return( op, p );
			p = NULL;
		}

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	/* get entry */
	rs->sr_err = mdb_dn2entry( op, txn, mc, &op->o_req_ndn, &e, NULL, 0 );
	switch( rs->sr_err ) {
	case MDB_NOTFOUND:
		e = p;
		p = NULL;
	case 0:
		break;
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* FIXME : dn2entry() should return non-glue entry */
	if ( rs->sr_err == MDB_NOTFOUND || ( !manageDSAit && is_entry_glue( e ))) {
		Debug( LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
			op->o_req_dn.bv_val, 0, 0);

		rs->sr_matched = ch_strdup( e->e_dn );
		if ( is_entry_referral( e )) {
			BerVarray ref = get_entry_referrals( op, e );
			rs->sr_ref = referral_rewrite( ref, &e->e_name,
				&op->o_req_dn, LDAP_SCOPE_DEFAULT );
			ber_bvarray_free( ref );
		} else {
			rs->sr_ref = NULL;
		}
		mdb_entry_return( op, e );
		e = NULL;

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	if ( pdn.bv_len != 0 ) {
		/* check parent for "children" acl */
		rs->sr_err = access_allowed( op, p,
			children, NULL, ACL_WDEL, NULL );

		if ( !rs->sr_err  ) {
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(mdb_delete) ": no write "
				"access to parent\n", 0, 0, 0 );
			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
			rs->sr_text = "no write access to parent";
			goto return_results;
		}

	} else {
		/* no parent, must be root to delete */
		if( ! be_isroot( op ) ) {
			if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
				|| be_shadow_update( op ) ) {
				p = (Entry *)&slap_entry_root;

				/* check parent for "children" acl */
				rs->sr_err = access_allowed( op, p,
					children, NULL, ACL_WDEL, NULL );

				p = NULL;

				if ( !rs->sr_err  ) {
					Debug( LDAP_DEBUG_TRACE,
						"<=- " LDAP_XSTRING(mdb_delete)
						": no access to parent\n",
						0, 0, 0 );
					rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
					rs->sr_text = "no write access to parent";
					goto return_results;
				}

			} else {
				Debug( LDAP_DEBUG_TRACE,
					"<=- " LDAP_XSTRING(mdb_delete)
					": no parent and not root\n", 0, 0, 0 );
				rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
				goto return_results;
			}
		}
	}

	if ( get_assert( op ) &&
		( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	rs->sr_err = access_allowed( op, e,
		entry, NULL, ACL_WDEL, NULL );

	if ( !rs->sr_err  ) {
		Debug( LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(mdb_delete) ": no write access "
			"to entry\n", 0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to entry";
		goto return_results;
	}

	if ( !manageDSAit && is_entry_referral( e ) ) {
		/* entry is a referral, don't allow delete */
		rs->sr_ref = get_entry_referrals( op, e );

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_delete) ": entry is referral\n",
			0, 0, 0 );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_matched = ch_strdup( e->e_name.bv_val );
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	/* pre-read */
	if( op->o_preread ) {
		if( preread_ctrl == NULL ) {
			preread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, e,
			&slap_pre_read_bv, preread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(mdb_delete) ": pre-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	rs->sr_text = NULL;

	/* Can't do it if we have kids */
	rs->sr_err = mdb_dn2id_children( op, txn, e );
	if( rs->sr_err != MDB_NOTFOUND ) {
		switch( rs->sr_err ) {
		case 0:
			Debug(LDAP_DEBUG_ARGS,
				"<=- " LDAP_XSTRING(mdb_delete)
				": non-leaf %s\n",
				op->o_req_dn.bv_val, 0, 0);
			rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
			rs->sr_text = "subordinate objects must be deleted first";
			break;
		default:
			Debug(LDAP_DEBUG_ARGS,
				"<=- " LDAP_XSTRING(mdb_delete)
				": has_children failed: %s (%d)\n",
				mdb_strerror(rs->sr_err), rs->sr_err, 0 );
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
		}
		goto return_results;
	}

	/* delete from dn2id */
	rs->sr_err = mdb_dn2id_delete( op, mc, e->e_id, 1 );
	mdb_cursor_close( mc );
	if ( rs->sr_err != 0 ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(mdb_delete) ": dn2id failed: "
			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_text = "DN index delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	/* delete indices for old attributes */
	rs->sr_err = mdb_index_entry_del( op, txn, e );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(mdb_delete) ": index failed: "
			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_text = "entry index delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	/* fixup delete CSN */
	if ( !SLAP_SHADOW( op->o_bd )) {
		struct berval vals[2];

		assert( !BER_BVISNULL( &op->o_csn ) );
		vals[0] = op->o_csn;
		BER_BVZERO( &vals[1] );
		rs->sr_err = mdb_index_values( op, txn, slap_schema.si_ad_entryCSN,
			vals, 0, SLAP_INDEX_ADD_OP );
		if ( rs->sr_err != LDAP_SUCCESS ) {
			rs->sr_text = "entryCSN index update failed";
			rs->sr_err = LDAP_OTHER;
			goto return_results;
		}
	}

	/* delete from id2entry */
	rs->sr_err = mdb_id2entry_delete( op->o_bd, txn, e );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(mdb_delete) ": id2entry failed: "
			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_text = "entry delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	if ( pdn.bv_len != 0 ) {
		parent_is_glue = is_entry_glue(p);
		rs->sr_err = mdb_dn2id_children( op, txn, p );
		if ( rs->sr_err != MDB_NOTFOUND ) {
			switch( rs->sr_err ) {
			case 0:
				break;
			default:
				Debug(LDAP_DEBUG_ARGS,
					"<=- " LDAP_XSTRING(mdb_delete)
					": has_children failed: %s (%d)\n",
					mdb_strerror(rs->sr_err), rs->sr_err, 0 );
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "internal error";
				goto return_results;
			}
			parent_is_leaf = 1;
		}
		mdb_entry_return( op, p );
		p = NULL;
	}

	if( moi == &opinfo ) {
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
		opinfo.moi_oe.oe_key = NULL;
		if( op->o_noop ) {
			mdb_txn_abort( txn );
			rs->sr_err = LDAP_X_NO_OPERATION;
			txn = NULL;
			goto return_results;
		} else {
			rs->sr_err = mdb_txn_commit( txn );
		}
		txn = NULL;
	}

	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_delete) ": txn_%s failed: %s (%d)\n",
			op->o_noop ? "abort (no-op)" : "commit",
			mdb_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "commit failed";

		goto return_results;
	}

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(mdb_delete) ": deleted%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		e->e_id, op->o_req_dn.bv_val );
	rs->sr_err = LDAP_SUCCESS;
	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
		op->o_delete_glue_parent = 1;
	}

	if ( p != NULL ) {
		mdb_entry_return( op, p );
	}

	/* free entry */
	if( e != NULL ) {
		mdb_entry_return( op, e );
	}

	if( moi == &opinfo ) {
		if( txn != NULL ) {
			mdb_txn_abort( txn );
		}
		if ( opinfo.moi_oe.oe_key ) {
			LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
		}
	} else {
		moi->moi_ref--;
	}

	send_ldap_result( op, rs );
	slap_graduate_commit_csn( op );

	if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
		slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
	}

#if 0
	if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
		TXN_CHECKPOINT( mdb->bi_dbenv,
			mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
	}
#endif
	return rs->sr_err;
}
예제 #15
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;
}
예제 #16
0
int
ndb_back_modrdn( Operation *op, SlapReply *rs )
{
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	struct berval	new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
	Entry		e = {0};
	Entry		e2 = {0};
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;

	struct berval	*np_dn = NULL;			/* newSuperior dn */
	struct berval	*np_ndn = NULL;			/* newSuperior ndn */

	int		manageDSAit = get_manageDSAit( op );
#ifdef NDB_RETRY
	int		num_retries = 0;
#endif

	NdbArgs NA, NA2;
	NdbRdns rdns, rdn2;
	struct berval matched;

	LDAPControl **preread_ctrl = NULL;
	LDAPControl **postread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

	int	rc;

	Debug( LDAP_DEBUG_ARGS, "==>" LDAP_XSTRING(ndb_back_modrdn) "(%s,%s,%s)\n",
		op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
		op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );

	ctrls[num_ctrls] = NULL;

	slap_mods_opattrs( op, &op->orr_modlist, 1 );

	e.e_name = op->o_req_dn;
	e.e_nname = op->o_req_ndn;

	/* Get our NDB handle */
	rs->sr_err = ndb_thread_handle( op, &NA.ndb );
	rdns.nr_num = 0;
	NA.rdns = &rdns;
	NA.e = &e;
	NA2.ndb = NA.ndb;
	NA2.e = &e2;
	NA2.rdns = &rdn2;

#ifdef NDB_RETRY
	if( 0 ) {
retry:	/* transaction retry */
		NA.txn->close();
		NA.txn = NULL;
		if ( e.e_attrs ) {
			attrs_free( e.e_attrs );
			e.e_attrs = NULL;
		}
		Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(ndb_back_modrdn)
				": retrying...\n" );
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			goto return_results;
		}
		if ( NA2.ocs ) {
			ber_bvarray_free_x( NA2.ocs, op->o_tmpmemctx );
		}
		if ( NA.ocs ) {
			ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
		}
		ndb_trans_backoff( ++num_retries );
	}
#endif

	NA.ocs = NULL;
	NA2.ocs = NULL;

	/* begin transaction */
	NA.txn = NA.ndb->startTransaction();
	rs->sr_text = NULL;
	if( !NA.txn ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_modrdn) ": startTransaction failed: %s (%d)\n",
			NA.ndb->getNdbError().message, NA.ndb->getNdbError().code );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	NA2.txn = NA.txn;

	/* get entry */
	rs->sr_err = ndb_entry_get_info( op, &NA, 1, &matched );
	switch( rs->sr_err ) {
	case 0:
		break;
	case LDAP_NO_SUCH_OBJECT:
		Debug( LDAP_DEBUG_ARGS,
			"<=- ndb_back_modrdn: no such object %s\n", op->o_req_dn.bv_val );
		rs->sr_matched = matched.bv_val;
		if ( NA.ocs )
			ndb_check_referral( op, rs, &NA );
		goto return_results;
#ifdef NDB_RETRY
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
#endif
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* acquire and lock entry */
	rs->sr_err = ndb_entry_get_data( op, &NA, 1 );
	if ( rs->sr_err )
		goto return_results;

	if ( !manageDSAit && is_entry_glue( &e )) {
		rs->sr_err = LDAP_NO_SUCH_OBJECT;
		goto return_results;
	}

	if ( get_assert( op ) &&
		( test_filter( op, &e, (Filter *)get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	/* check write on old entry */
	rs->sr_err = access_allowed( op, &e, entry, NULL, ACL_WRITE, NULL );
	if ( ! rs->sr_err ) {
		Debug( LDAP_DEBUG_TRACE, "no access to entry\n" );
		rs->sr_text = "no write access to old entry";
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		goto return_results;
	}

	/* Can't do it if we have kids */
	rs->sr_err = ndb_has_children( &NA, &rc );
	if ( rs->sr_err ) {
		Debug(LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(ndb_back_modrdn)
			": has_children failed: %s (%d)\n",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	if ( rc == LDAP_COMPARE_TRUE ) {
		Debug(LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(ndb_back_modrdn) ": non-leaf %s\n",
			op->o_req_dn.bv_val);
		rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
		rs->sr_text = "subtree rename not supported";
		goto return_results;
	}

	if (!manageDSAit && is_entry_referral( &e ) ) {
		/* entry is a referral, don't allow modrdn */
		rs->sr_ref = get_entry_referrals( op, &e );

		Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn)
			": entry %s is referral\n", e.e_dn );

		rs->sr_err = LDAP_REFERRAL,
		rs->sr_matched = op->o_req_dn.bv_val;
		rs->sr_flags = REP_REF_MUSTBEFREED;
		goto return_results;
	}

	if ( be_issuffix( op->o_bd, &e.e_nname ) ) {
		/* There can only be one suffix entry */
		rs->sr_err = LDAP_NAMING_VIOLATION;
		rs->sr_text = "cannot rename suffix entry";
		goto return_results;
	} else {
		dnParent( &e.e_nname, &e2.e_nname );
		dnParent( &e.e_name, &e2.e_name );
	}

	/* check parent for "children" acl */
	rs->sr_err = access_allowed( op, &e2,
		children, NULL,
		op->oq_modrdn.rs_newSup == NULL ?
			ACL_WRITE : ACL_WDEL,
		NULL );

	if ( ! rs->sr_err ) {
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		Debug( LDAP_DEBUG_TRACE, "no access to parent\n" );
		rs->sr_text = "no write access to old parent's children";
		goto return_results;
	}

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(ndb_back_modrdn) ": wr to children "
		"of entry %s OK\n", e2.e_name.bv_val );

	if ( op->oq_modrdn.rs_newSup != NULL ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_modrdn)
			": new parent \"%s\" requested...\n",
			op->oq_modrdn.rs_newSup->bv_val );

		/*  newSuperior == oldParent? */
		if( dn_match( &e2.e_nname, op->oq_modrdn.rs_nnewSup ) ) {
			Debug( LDAP_DEBUG_TRACE, "bdb_back_modrdn: "
				"new parent \"%s\" same as the old parent \"%s\"\n",
				op->oq_modrdn.rs_newSup->bv_val, e2.e_name.bv_val );
			op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
		}
	}

	if ( op->oq_modrdn.rs_newSup != NULL ) {
		if ( op->oq_modrdn.rs_newSup->bv_len ) {
			rdn2.nr_num = 0;
			np_dn = op->oq_modrdn.rs_newSup;
			np_ndn = op->oq_modrdn.rs_nnewSup;

			/* newSuperior == oldParent? - checked above */
			/* newSuperior == entry being moved?, if so ==> ERROR */
			if ( dnIsSuffix( np_ndn, &e.e_nname )) {
				rs->sr_err = LDAP_NO_SUCH_OBJECT;
				rs->sr_text = "new superior not found";
				goto return_results;
			}
			/* Get Entry with dn=newSuperior. Does newSuperior exist? */

			e2.e_name = *np_dn;
			e2.e_nname = *np_ndn;
			rs->sr_err = ndb_entry_get_info( op, &NA2, 1, NULL );
			switch( rs->sr_err ) {
			case 0:
				break;
			case LDAP_NO_SUCH_OBJECT:
				Debug( LDAP_DEBUG_TRACE,
					LDAP_XSTRING(ndb_back_modrdn)
					": newSup(ndn=%s) not here!\n", np_ndn->bv_val );
				rs->sr_text = "new superior not found";
				goto return_results;
#if 0
			case DB_LOCK_DEADLOCK:
			case DB_LOCK_NOTGRANTED:
				goto retry;
#endif
			case LDAP_BUSY:
				rs->sr_text = "ldap server busy";
				goto return_results;
			default:
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "internal error";
				goto return_results;
			}
			if ( NA2.ocs ) {
				Attribute a;
				int i;

				for ( i=0; !BER_BVISNULL( &NA2.ocs[i] ); i++);
				a.a_numvals = i;
				a.a_desc = slap_schema.si_ad_objectClass;
				a.a_vals = NA2.ocs;
				a.a_nvals = NA2.ocs;
				a.a_next = NULL;
				e2.e_attrs = &a;

				if ( is_entry_alias( &e2 )) {
					/* parent is an alias, don't allow move */
					Debug( LDAP_DEBUG_TRACE,
						LDAP_XSTRING(ndb_back_modrdn)
						": entry is alias\n" );
					rs->sr_text = "new superior is an alias";
					rs->sr_err = LDAP_ALIAS_PROBLEM;
					goto return_results;
				}

				if ( is_entry_referral( &e2 ) ) {
					/* parent is a referral, don't allow move */
					Debug( LDAP_DEBUG_TRACE,
						LDAP_XSTRING(ndb_back_modrdn)
						": entry is referral\n" );
					rs->sr_text = "new superior is a referral";
					rs->sr_err = LDAP_OTHER;
					goto return_results;
				}
			}
		}

		/* check newSuperior for "children" acl */
		rs->sr_err = access_allowed( op, &e2, children,
			NULL, ACL_WADD, NULL );
		if( ! rs->sr_err ) {
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(ndb_back_modrdn)
				": no wr to newSup children\n" );
			rs->sr_text = "no write access to new superior's children";
			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
			goto return_results;
		}

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_modrdn)
			": wr to new parent OK id=%ld\n", (long) e2.e_id );
	}

	/* Build target dn and make sure target entry doesn't exist already. */
	if (!new_dn.bv_val) {
		build_new_dn( &new_dn, &e2.e_name, &op->oq_modrdn.rs_newrdn, NULL );
	}

	if (!new_ndn.bv_val) {
		build_new_dn( &new_ndn, &e2.e_nname, &op->oq_modrdn.rs_nnewrdn, NULL );
	}

	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_modrdn) ": new ndn=%s\n",
		new_ndn.bv_val );

	/* Allow rename to same DN */
	if ( !bvmatch ( &new_ndn, &e.e_nname )) {
		rdn2.nr_num = 0;
		e2.e_name = new_dn;
		e2.e_nname = new_ndn;
		NA2.ocs = &matched;
		rs->sr_err = ndb_entry_get_info( op, &NA2, 1, NULL );
		NA2.ocs = NULL;
		switch( rs->sr_err ) {
#if 0
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
#endif
		case LDAP_NO_SUCH_OBJECT:
			break;
		case 0:
			rs->sr_err = LDAP_ALREADY_EXISTS;
			goto return_results;
		default:
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
	}

	assert( op->orr_modlist != NULL );

	if( op->o_preread ) {
		if( preread_ctrl == NULL ) {
			preread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, &e,
			&slap_pre_read_bv, preread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(ndb_back_modrdn)
				": pre-read failed!\n" );
			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	/* delete old DN */
	rs->sr_err = ndb_entry_del_info( op->o_bd, &NA );
	if ( rs->sr_err != 0 ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(ndb_back_modrdn)
			": dn2id del failed: %s (%d)\n",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code );
#if 0
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
#endif
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "DN index delete fail";
		goto return_results;
	}

	/* copy entry fields */
	e2.e_attrs = e.e_attrs;
	e2.e_id = e.e_id;

	/* add new DN */
	rs->sr_err = ndb_entry_put_info( op->o_bd, &NA2, 0 );
	if ( rs->sr_err != 0 ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(ndb_back_modrdn)
			": dn2id add failed: %s (%d)\n",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code );
#if 0
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
#endif
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "DN index add failed";
		goto return_results;
	}

	/* modify entry */
	rs->sr_err = ndb_modify_internal( op, &NA2,
		&rs->sr_text, textbuf, textlen );
	if( rs->sr_err != LDAP_SUCCESS ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(ndb_back_modrdn)
			": modify failed: %s (%d)\n",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code );
#if 0
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
#endif
		goto return_results;
	}

	e.e_attrs = e2.e_attrs;

	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, &e2,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(ndb_back_modrdn) ": post-read failed!\n" );
			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	if( op->o_noop ) {
		if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
			NdbOperation::AbortOnError, 1 )) != 0 ) {
			rs->sr_text = "txn_abort (no-op) failed";
		} else {
			rs->sr_err = LDAP_X_NO_OPERATION;
		}
	} else {
		if (( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
			NdbOperation::AbortOnError, 1 )) != 0 ) {
			rs->sr_text = "txn_commit failed";
		} else {
			rs->sr_err = LDAP_SUCCESS;
		}
	}

	if( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_modrdn) ": txn_%s failed: %s (%d)\n",
			op->o_noop ? "abort (no-op)" : "commit",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code );
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}
	NA.txn->close();
	NA.txn = NULL;

	Debug(LDAP_DEBUG_TRACE,
		LDAP_XSTRING(ndb_back_modrdn)
		": rdn modified%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		e.e_id, op->o_req_dn.bv_val );

	rs->sr_err = LDAP_SUCCESS;
	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	if ( NA2.ocs ) {
		ber_bvarray_free_x( NA2.ocs, op->o_tmpmemctx );
		NA2.ocs = NULL;
	}

	if ( NA.ocs ) {
		ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
		NA.ocs = NULL;
	}

	if ( e.e_attrs ) {
		attrs_free( e.e_attrs );
		e.e_attrs = NULL;
	}

	if( NA.txn != NULL ) {
		NA.txn->execute( Rollback );
		NA.txn->close();
	}

	send_ldap_result( op, rs );
	slap_graduate_commit_csn( op );

	if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
	if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );

	if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
		slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
	}
	if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
		slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
	}

	rs->sr_text = NULL;
	return rs->sr_err;
}
예제 #17
0
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);

	/* 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" );
		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" );
		rs->sr_err = LDAP_INVALID_CREDENTIALS;
		goto done;
	}

	if ( is_entry_referral( e ) ) {
		Debug( LDAP_DEBUG_TRACE, "entry is referral\n" );
		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:
		LDAP_BUG(); /* 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 );
		rs_send_cleanup( rs );
	}
	/* front end will send result on success (rs->sr_err==0) */
	return rs->sr_err;
}
예제 #18
0
파일: bind.c 프로젝트: benegon/openldap
int
mdb_bind( Operation *op, SlapReply *rs )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
	Entry		*e;
	Attribute	*a;

	AttributeDescription *password = slap_schema.si_ad_userPassword;

	MDB_txn		*rtxn;
	mdb_op_info	opinfo = {{{0}}}, *moi = &opinfo;

	Debug( LDAP_DEBUG_ARGS,
		"==> " LDAP_XSTRING(mdb_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 = mdb_opinfo_get(op, mdb, 1, &moi);
	switch(rs->sr_err) {
	case 0:
		break;
	default:
		rs->sr_text = "internal error";
		send_ldap_result( op, rs );
		return rs->sr_err;
	}

	rtxn = moi->moi_txn;

	/* get entry with reader lock */
	rs->sr_err = mdb_dn2entry( op, rtxn, NULL, &op->o_req_ndn, &e, NULL, 0 );

	switch(rs->sr_err) {
	case MDB_NOTFOUND:
		rs->sr_err = LDAP_INVALID_CREDENTIALS;
		goto done;
	case 0:
		break;
	case LDAP_BUSY:
		rs->sr_text = "ldap_server_busy";
		goto done;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto done;
	}

	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:
	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--;
	}
	/* free entry and reader lock */
	if( e != NULL ) {
		mdb_entry_return( op, e );
	}

	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;
}
예제 #19
0
파일: search.c 프로젝트: fcelda/openldap
int
mdb_search( Operation *op, SlapReply *rs )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
	ID		id, cursor;
	ID		lastid = NOID;
	ID		candidates[MDB_IDL_UM_SIZE];
	ID2		*scopes;
	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;

	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;
	}

	scopes = scope_chunk_get( op );
	isc.mt = ltid;
	isc.mc = NULL;
	isc.scopes = scopes;

	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, NULL, &op->o_req_ndn, &e, 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 );

	} else {
		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,
			ltid, mci, candidates, scopes );
	}

	/* 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 &&
		MDB_IDL_N(candidates) > (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 = MDB_IDL_N(candidates);
	}

	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 );
		goto loop_begin;
	}

	for ( id = mdb_idl_first( candidates, &cursor );
		  id != NOID ; id = mdb_idl_next( candidates, &cursor ) )
	{
		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 ( 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 ) {
				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;
			}
		}

		/* 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;
			if ( mdb_idscopes( op, &isc ) == MDB_SUCCESS ) scopeok = 1;
			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;
		}

		if ( id != base->e_id ) {
			rs->sr_err = mdb_entry_decode( op, &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) ||
					!bvmatch(&e->e_nname, &op->o_req_ndn)))
			{
				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 ( isc.nscope == 1 ) {
				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;
			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 (isc.nscope != 1) {
				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 );

			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;

			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_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;
				}
			}

		} 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;
		}
	}

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( isc.mc )
		mdb_cursor_close( isc.mc );
	if (mci)
		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 );
	}
	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;
}
예제 #20
0
파일: delete.cpp 프로젝트: dago/openldap
int
ndb_back_delete( Operation *op, SlapReply *rs )
{
	struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
	Entry	e = {0};
	Entry	p = {0};
	int		manageDSAit = get_manageDSAit( op );
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;

	NdbArgs NA;
	NdbRdns rdns;
	struct berval matched;

	int	num_retries = 0;

	int     rc;

	LDAPControl **preread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

	Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(ndb_back_delete) ": %s\n",
		op->o_req_dn.bv_val, 0, 0 );

	ctrls[num_ctrls] = 0;

	/* allocate CSN */
	if ( BER_BVISNULL( &op->o_csn ) ) {
		struct berval csn;
		char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];

		csn.bv_val = csnbuf;
		csn.bv_len = sizeof(csnbuf);
		slap_get_csn( op, &csn, 1 );
	}

	if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
		dnParent( &op->o_req_dn, &p.e_name );
		dnParent( &op->o_req_ndn, &p.e_nname );
	}

	/* Get our NDB handle */
	rs->sr_err = ndb_thread_handle( op, &NA.ndb );
	rdns.nr_num = 0;
	NA.rdns = &rdns;
	NA.ocs = NULL;
	NA.e = &e;
	e.e_name = op->o_req_dn;
	e.e_nname = op->o_req_ndn;

	if( 0 ) {
retry:	/* transaction retry */
		NA.txn->close();
		NA.txn = NULL;
		Debug( LDAP_DEBUG_TRACE,
			"==> " LDAP_XSTRING(ndb_back_delete) ": retrying...\n",
			0, 0, 0 );
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			goto return_results;
		}
		if ( NA.ocs ) {
			ber_bvarray_free( NA.ocs );
			NA.ocs = NULL;
		}
		ndb_trans_backoff( ++num_retries );
	}

	/* begin transaction */
	NA.txn = NA.ndb->startTransaction();
	rs->sr_text = NULL;
	if( !NA.txn ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_delete) ": startTransaction failed: %s (%d)\n",
			NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* get entry */
	rs->sr_err = ndb_entry_get_info( op, &NA, 1, &matched );
	switch( rs->sr_err ) {
	case 0:
	case LDAP_NO_SUCH_OBJECT:
		break;
#if 0
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
#endif
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ||
		( !manageDSAit && bvmatch( NA.ocs, &glue_bv ))) {
		Debug( LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(ndb_back_delete) ": no such object %s\n",
			op->o_req_dn.bv_val, 0, 0);

		if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
			rs->sr_matched = matched.bv_val;
			if ( NA.ocs )
				ndb_check_referral( op, rs, &NA );
		} else {
			rs->sr_matched = p.e_name.bv_val;
			rs->sr_err = LDAP_NO_SUCH_OBJECT;
		}
		goto return_results;
	}

	/* check parent for "children" acl */
	rs->sr_err = access_allowed( op, &p,
		children, NULL, ACL_WDEL, NULL );

	if ( !rs->sr_err  ) {
		Debug( LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(ndb_back_delete) ": no write "
			"access to parent\n", 0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to parent";
		goto return_results;
	}

	rs->sr_err = ndb_entry_get_data( op, &NA, 1 );

	rs->sr_err = access_allowed( op, &e,
		entry, NULL, ACL_WDEL, NULL );

	if ( !rs->sr_err  ) {
		Debug( LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(ndb_back_delete) ": no write access "
			"to entry\n", 0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to entry";
		goto return_results;
	}

	if ( !manageDSAit && is_entry_referral( &e ) ) {
		/* entry is a referral, don't allow delete */
		rs->sr_ref = get_entry_referrals( op, &e );

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_delete) ": entry is referral\n",
			0, 0, 0 );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_matched = e.e_name.bv_val;
		rs->sr_flags = REP_REF_MUSTBEFREED;
		goto return_results;
	}

	if ( get_assert( op ) &&
		( test_filter( op, &e, (Filter *)get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	/* pre-read */
	if( op->o_preread ) {
		if( preread_ctrl == NULL ) {
			preread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, &e,
			&slap_pre_read_bv, preread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(ndb_back_delete) ": pre-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	/* Can't do it if we have kids */
	rs->sr_err = ndb_has_children( &NA, &rc );
	if ( rs->sr_err ) {
		Debug(LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(ndb_back_delete)
			": has_children failed: %s (%d)\n",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	if ( rc == LDAP_COMPARE_TRUE ) {
		Debug(LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(ndb_back_delete)
			": non-leaf %s\n",
			op->o_req_dn.bv_val, 0, 0);
		rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
		rs->sr_text = "subordinate objects must be deleted first";
		goto return_results;
	}

	/* delete info */
	rs->sr_err = ndb_entry_del_info( op->o_bd, &NA );
	if ( rs->sr_err != 0 ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(ndb_back_delete) ": del_info failed: %s (%d)\n",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 );
		rs->sr_text = "DN index delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	/* delete data */
	rs->sr_err = ndb_entry_del_data( op->o_bd, &NA );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(ndb_back_delete) ": del_data failed: %s (%d)\n",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code, 0 );
		rs->sr_text = "entry delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	if( op->o_noop ) {
		if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
			NdbOperation::AbortOnError, 1 )) != 0 ) {
			rs->sr_text = "txn (no-op) failed";
		} else {
			rs->sr_err = LDAP_X_NO_OPERATION;
		}
	} else {
		if (( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
			NdbOperation::AbortOnError, 1 )) != 0 ) {
			rs->sr_text = "txn_commit failed";
		} else {
			rs->sr_err = LDAP_SUCCESS;
		}
	}

	if( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_delete) ": txn_%s failed: %s (%d)\n",
			op->o_noop ? "abort (no-op)" : "commit",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "commit failed";

		goto return_results;
	}
	NA.txn->close();
	NA.txn = NULL;

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(ndb_back_delete) ": deleted%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		e.e_id, op->o_req_dn.bv_val );
	rs->sr_err = LDAP_SUCCESS;
	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	if ( NA.ocs ) {
		ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
		NA.ocs = NULL;
	}

	/* free entry */
	if( e.e_attrs != NULL ) {
		attrs_free( e.e_attrs );
		e.e_attrs = NULL;
	}

	if( NA.txn != NULL ) {
		NA.txn->execute( Rollback );
		NA.txn->close();
	}

	send_ldap_result( op, rs );
	slap_graduate_commit_csn( op );

	if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
		slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
	}
	return rs->sr_err;
}
예제 #21
0
int
mdb_referrals( Operation *op, SlapReply *rs )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
	Entry *e = NULL;
	int rc = LDAP_SUCCESS;

	MDB_txn		*rtxn;
	mdb_op_info	opinfo = {0}, *moi = &opinfo;

	if( op->o_tag == LDAP_REQ_SEARCH ) {
		/* let search take care of itself */
		return rc;
	}

	if( get_manageDSAit( op ) ) {
		/* let op take care of DSA management */
		return rc;
	} 

	rc = mdb_opinfo_get(op, mdb, 1, &moi);
	switch(rc) {
	case 0:
		break;
	default:
		return LDAP_OTHER;
	}

	rtxn = moi->moi_txn;

	/* get entry */
	rc = mdb_dn2entry( op, rtxn, &op->o_req_ndn, &e, 1 );

	switch(rc) {
	case MDB_NOTFOUND:
	case 0:
		break;
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto done;
	default:
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_referrals)
			": dn2entry failed: %s (%d)\n",
			mdb_strerror(rc), rc, 0 );
		rs->sr_text = "internal error";
		rc = LDAP_OTHER;
		goto done;
	}

	if ( rc == MDB_NOTFOUND ) {
		rc = LDAP_SUCCESS;
		rs->sr_matched = NULL;
		if ( e != NULL ) {
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_referrals)
				": tag=%lu target=\"%s\" matched=\"%s\"\n",
				(unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val );

			if( is_entry_referral( e ) ) {
				BerVarray ref = get_entry_referrals( op, e );
				rc = LDAP_OTHER;
				rs->sr_ref = referral_rewrite( ref, &e->e_name,
					&op->o_req_dn, LDAP_SCOPE_DEFAULT );
				ber_bvarray_free( ref );
				if ( rs->sr_ref ) {
					rs->sr_matched = ber_strdup_x(
					e->e_name.bv_val, op->o_tmpmemctx );
				}
			}

			mdb_entry_return( op, e );
			e = NULL;
		}

		if( rs->sr_ref != NULL ) {
			/* send referrals */
			rc = rs->sr_err = LDAP_REFERRAL;
			send_ldap_result( op, rs );
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;
		} else if ( rc != LDAP_SUCCESS ) {
			rs->sr_text = rs->sr_matched ? "bad referral object" : NULL;
		}

		if (rs->sr_matched) {
			op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
			rs->sr_matched = NULL;
		}
		goto done;
	}

	if ( is_entry_referral( e ) ) {
		/* entry is a referral */
		BerVarray refs = get_entry_referrals( op, e );
		rs->sr_ref = referral_rewrite(
			refs, &e->e_name, &op->o_req_dn, LDAP_SCOPE_DEFAULT );

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_referrals)
			": tag=%lu target=\"%s\" matched=\"%s\"\n",
			(unsigned long)op->o_tag, op->o_req_dn.bv_val, e->e_name.bv_val );

		rs->sr_matched = e->e_name.bv_val;
		if( rs->sr_ref != NULL ) {
			rc = rs->sr_err = LDAP_REFERRAL;
			send_ldap_result( op, rs );
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;
		} else {
			rc = LDAP_OTHER;
			rs->sr_text = "bad referral object";
		}

		rs->sr_matched = NULL;
		ber_bvarray_free( refs );
	}

done:
	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 ( e )
		mdb_entry_return( op, e );
	return rc;
}
예제 #22
0
파일: delete.c 프로젝트: 1ack/Impala
int
bdb_delete( Operation *op, SlapReply *rs )
{
	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
	Entry	*matched = NULL;
	struct berval	pdn = {0, NULL};
	Entry	*e = NULL;
	Entry	*p = NULL;
	EntryInfo	*ei = NULL, *eip = NULL;
	int		manageDSAit = get_manageDSAit( op );
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	DB_TXN		*ltid = NULL, *lt2;
	struct bdb_op_info opinfo = {{{ 0 }}};
	ID	eid;

	DB_LOCK		lock, plock;

	int		num_retries = 0;

	int     rc;

	LDAPControl **preread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

	int	parent_is_glue = 0;
	int parent_is_leaf = 0;

#ifdef LDAP_X_TXN
	int settle = 0;
#endif

	Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(bdb_delete) ": %s\n",
		op->o_req_dn.bv_val, 0, 0 );

#ifdef LDAP_X_TXN
	if( op->o_txnSpec ) {
		/* acquire connection lock */
		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
		if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
			rs->sr_text = "invalid transaction identifier";
			rs->sr_err = LDAP_X_TXN_ID_INVALID;
			goto txnReturn;
		} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
			settle=1;
			goto txnReturn;
		}

		if( op->o_conn->c_txn_backend == NULL ) {
			op->o_conn->c_txn_backend = op->o_bd;

		} else if( op->o_conn->c_txn_backend != op->o_bd ) {
			rs->sr_text = "transaction cannot span multiple database contexts";
			rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
			goto txnReturn;
		}

		/* insert operation into transaction */

		rs->sr_text = "transaction specified";
		rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;

txnReturn:
		/* release connection lock */
		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );

		if( !settle ) {
			send_ldap_result( op, rs );
			return rs->sr_err;
		}
	}
#endif

	ctrls[num_ctrls] = 0;

	/* allocate CSN */
	if ( BER_BVISNULL( &op->o_csn ) ) {
		struct berval csn;
		char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];

		csn.bv_val = csnbuf;
		csn.bv_len = sizeof(csnbuf);
		slap_get_csn( op, &csn, 1 );
	}

	if( 0 ) {
retry:	/* transaction retry */
		if( e != NULL ) {
			bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
			e = NULL;
		}
		if( p != NULL ) {
			bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
			p = NULL;
		}
		Debug( LDAP_DEBUG_TRACE,
			"==> " LDAP_XSTRING(bdb_delete) ": retrying...\n",
			0, 0, 0 );
		rs->sr_err = TXN_ABORT( ltid );
		ltid = NULL;
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
		opinfo.boi_oe.oe_key = NULL;
		op->o_do_not_cache = opinfo.boi_acl_cache;
		if( rs->sr_err != 0 ) {
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			goto return_results;
		}
		parent_is_glue = 0;
		parent_is_leaf = 0;
		bdb_trans_backoff( ++num_retries );
	}

	/* begin transaction */
	rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
		bdb->bi_db_opflags );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_delete) ": txn_begin failed: "
			"%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	opinfo.boi_oe.oe_key = bdb;
	opinfo.boi_txn = ltid;
	opinfo.boi_err = 0;
	opinfo.boi_acl_cache = op->o_do_not_cache;
	LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next );

	if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
		dnParent( &op->o_req_ndn, &pdn );
	}

	/* get entry */
	rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
		&lock );

	switch( rs->sr_err ) {
	case 0:
	case DB_NOTFOUND:
		break;
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	if ( rs->sr_err == 0 ) {
		e = ei->bei_e;
		eip = ei->bei_parent;
	} else {
		matched = ei->bei_e;
	}

	/* FIXME : dn2entry() should return non-glue entry */
	if ( e == NULL || ( !manageDSAit && is_entry_glue( e ))) {
		Debug( LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(bdb_delete) ": no such object %s\n",
			op->o_req_dn.bv_val, 0, 0);

		if ( matched != NULL ) {
			rs->sr_matched = ch_strdup( matched->e_dn );
			rs->sr_ref = is_entry_referral( matched )
				? get_entry_referrals( op, matched )
				: NULL;
			bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, matched);
			matched = NULL;

		} else {
			rs->sr_ref = referral_rewrite( default_referral, NULL,
					&op->o_req_dn, LDAP_SCOPE_DEFAULT );
		}

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	rc = bdb_cache_find_id( op, ltid, eip->bei_id, &eip, 0, &plock );
	switch( rc ) {
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
	case 0:
	case DB_NOTFOUND:
		break;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	if ( eip ) p = eip->bei_e;

	if ( pdn.bv_len != 0 ) {
		if( p == NULL || !bvmatch( &pdn, &p->e_nname )) {
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_delete) ": parent "
				"does not exist\n", 0, 0, 0 );
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "could not locate parent of entry";
			goto return_results;
		}

		/* check parent for "children" acl */
		rs->sr_err = access_allowed( op, p,
			children, NULL, ACL_WDEL, NULL );

		if ( !rs->sr_err  ) {
			switch( opinfo.boi_err ) {
			case DB_LOCK_DEADLOCK:
			case DB_LOCK_NOTGRANTED:
				goto retry;
			}

			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_delete) ": no write "
				"access to parent\n", 0, 0, 0 );
			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
			rs->sr_text = "no write access to parent";
			goto return_results;
		}

	} else {
		/* no parent, must be root to delete */
		if( ! be_isroot( op ) ) {
			if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
				|| be_shadow_update( op ) ) {
				p = (Entry *)&slap_entry_root;

				/* check parent for "children" acl */
				rs->sr_err = access_allowed( op, p,
					children, NULL, ACL_WDEL, NULL );

				p = NULL;

				if ( !rs->sr_err  ) {
					switch( opinfo.boi_err ) {
					case DB_LOCK_DEADLOCK:
					case DB_LOCK_NOTGRANTED:
						goto retry;
					}

					Debug( LDAP_DEBUG_TRACE,
						"<=- " LDAP_XSTRING(bdb_delete)
						": no access to parent\n",
						0, 0, 0 );
					rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
					rs->sr_text = "no write access to parent";
					goto return_results;
				}

			} else {
				Debug( LDAP_DEBUG_TRACE,
					"<=- " LDAP_XSTRING(bdb_delete)
					": no parent and not root\n", 0, 0, 0 );
				rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
				goto return_results;
			}
		}
	}

	if ( get_assert( op ) &&
		( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	rs->sr_err = access_allowed( op, e,
		entry, NULL, ACL_WDEL, NULL );

	if ( !rs->sr_err  ) {
		switch( opinfo.boi_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		Debug( LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(bdb_delete) ": no write access "
			"to entry\n", 0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to entry";
		goto return_results;
	}

	if ( !manageDSAit && is_entry_referral( e ) ) {
		/* entry is a referral, don't allow delete */
		rs->sr_ref = get_entry_referrals( op, e );

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_delete) ": entry is referral\n",
			0, 0, 0 );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_matched = ch_strdup( e->e_name.bv_val );
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	/* pre-read */
	if( op->o_preread ) {
		if( preread_ctrl == NULL ) {
			preread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, e,
			&slap_pre_read_bv, preread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_delete) ": pre-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	/* nested transaction */
	rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
		bdb->bi_db_opflags );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_delete) ": txn_begin(2) failed: "
			"%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	BDB_LOG_PRINTF( bdb->bi_dbenv, lt2, "slapd Starting delete %s(%d)",
		e->e_nname.bv_val, e->e_id );

	/* Can't do it if we have kids */
	rs->sr_err = bdb_cache_children( op, lt2, e );
	if( rs->sr_err != DB_NOTFOUND ) {
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		case 0:
			Debug(LDAP_DEBUG_ARGS,
				"<=- " LDAP_XSTRING(bdb_delete)
				": non-leaf %s\n",
				op->o_req_dn.bv_val, 0, 0);
			rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
			rs->sr_text = "subordinate objects must be deleted first";
			break;
		default:
			Debug(LDAP_DEBUG_ARGS,
				"<=- " LDAP_XSTRING(bdb_delete)
				": has_children failed: %s (%d)\n",
				db_strerror(rs->sr_err), rs->sr_err, 0 );
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
		}
		goto return_results;
	}

	/* delete from dn2id */
	rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e );
	if ( rs->sr_err != 0 ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(bdb_delete) ": dn2id failed: "
			"%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		rs->sr_text = "DN index delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	/* delete indices for old attributes */
	rs->sr_err = bdb_index_entry_del( op, lt2, e );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(bdb_delete) ": index failed: "
			"%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		rs->sr_text = "entry index delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	/* fixup delete CSN */
	if ( !SLAP_SHADOW( op->o_bd )) {
		struct berval vals[2];

		assert( !BER_BVISNULL( &op->o_csn ) );
		vals[0] = op->o_csn;
		BER_BVZERO( &vals[1] );
		rs->sr_err = bdb_index_values( op, lt2, slap_schema.si_ad_entryCSN,
			vals, 0, SLAP_INDEX_ADD_OP );
	if ( rs->sr_err != LDAP_SUCCESS ) {
			switch( rs->sr_err ) {
			case DB_LOCK_DEADLOCK:
			case DB_LOCK_NOTGRANTED:
				goto retry;
			}
			rs->sr_text = "entryCSN index update failed";
			rs->sr_err = LDAP_OTHER;
			goto return_results;
		}
	}

	/* delete from id2entry */
	rs->sr_err = bdb_id2entry_delete( op->o_bd, lt2, e );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(bdb_delete) ": id2entry failed: "
			"%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		rs->sr_text = "entry delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	if ( pdn.bv_len != 0 ) {
		parent_is_glue = is_entry_glue(p);
		rs->sr_err = bdb_cache_children( op, lt2, p );
		if ( rs->sr_err != DB_NOTFOUND ) {
			switch( rs->sr_err ) {
			case DB_LOCK_DEADLOCK:
			case DB_LOCK_NOTGRANTED:
				goto retry;
			case 0:
				break;
			default:
				Debug(LDAP_DEBUG_ARGS,
					"<=- " LDAP_XSTRING(bdb_delete)
					": has_children failed: %s (%d)\n",
					db_strerror(rs->sr_err), rs->sr_err, 0 );
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "internal error";
				goto return_results;
			}
			parent_is_leaf = 1;
		}
		bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
		p = NULL;
	}

	BDB_LOG_PRINTF( bdb->bi_dbenv, lt2, "slapd Commit1 delete %s(%d)",
		e->e_nname.bv_val, e->e_id );

	if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "txn_commit(2) failed";
		goto return_results;
	}

	eid = e->e_id;

#if 0	/* Do we want to reclaim deleted IDs? */
	ldap_pvt_thread_mutex_lock( &bdb->bi_lastid_mutex );
	if ( e->e_id == bdb->bi_lastid ) {
		bdb_last_id( op->o_bd, ltid );
	}
	ldap_pvt_thread_mutex_unlock( &bdb->bi_lastid_mutex );
#endif

	if( op->o_noop ) {
		if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
			rs->sr_text = "txn_abort (no-op) failed";
		} else {
			rs->sr_err = LDAP_X_NO_OPERATION;
			ltid = NULL;
			goto return_results;
		}
	} else {

		BDB_LOG_PRINTF( bdb->bi_dbenv, ltid, "slapd Cache delete %s(%d)",
			e->e_nname.bv_val, e->e_id );

		rc = bdb_cache_delete( bdb, e, ltid, &lock );
		switch( rc ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		rs->sr_err = TXN_COMMIT( ltid, 0 );
	}
	ltid = NULL;
	LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	opinfo.boi_oe.oe_key = NULL;

	BDB_LOG_PRINTF( bdb->bi_dbenv, NULL, "slapd Committed delete %s(%d)",
		e->e_nname.bv_val, e->e_id );

	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_delete) ": txn_%s failed: %s (%d)\n",
			op->o_noop ? "abort (no-op)" : "commit",
			db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "commit failed";

		goto return_results;
	}

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_delete) ": deleted%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		eid, op->o_req_dn.bv_val );
	rs->sr_err = LDAP_SUCCESS;
	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
		op->o_delete_glue_parent = 1;
	}

	if ( p )
		bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);

	/* free entry */
	if( e != NULL ) {
		if ( rs->sr_err == LDAP_SUCCESS ) {
			/* Free the EntryInfo and the Entry */
			bdb_cache_entryinfo_lock( BEI(e) );
			bdb_cache_delete_cleanup( &bdb->bi_cache, BEI(e) );
		} else {
			bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
		}
	}

	if( ltid != NULL ) {
		TXN_ABORT( ltid );
	}
	if ( opinfo.boi_oe.oe_key ) {
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	}

	send_ldap_result( op, rs );
	slap_graduate_commit_csn( op );

	if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
		slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
	}

	if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp_kbyte ) {
		TXN_CHECKPOINT( bdb->bi_dbenv,
			bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
	}
	return rs->sr_err;
}
예제 #23
0
int bdb_tool_entry_reindex(
	BackendDB *be,
	ID id,
	AttributeDescription **adv )
{
	struct bdb_info *bi = (struct bdb_info *) be->be_private;
	int rc;
	Entry *e;
	DB_TXN *tid = NULL;
	Operation op = {0};
	Opheader ohdr = {0};

	Debug( LDAP_DEBUG_ARGS,
		"=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
		(long) id, 0, 0 );

	/* No indexes configured, nothing to do. Could return an
	 * error here to shortcut things.
	 */
	if (!bi->bi_attrs) {
		return 0;
	}

	/* Check for explicit list of attrs to index */
	if ( adv ) {
		int i, j, n;

		if ( bi->bi_attrs[0]->ai_desc != adv[0] ) {
			/* count */
			for ( n = 0; adv[n]; n++ ) ;

			/* insertion sort */
			for ( i = 0; i < n; i++ ) {
				AttributeDescription *ad = adv[i];
				for ( j = i-1; j>=0; j--) {
					if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
					adv[j+1] = adv[j];
				}
				adv[j+1] = ad;
			}
		}

		for ( i = 0; adv[i]; i++ ) {
			if ( bi->bi_attrs[i]->ai_desc != adv[i] ) {
				for ( j = i+1; j < bi->bi_nattrs; j++ ) {
					if ( bi->bi_attrs[j]->ai_desc == adv[i] ) {
						AttrInfo *ai = bi->bi_attrs[i];
						bi->bi_attrs[i] = bi->bi_attrs[j];
						bi->bi_attrs[j] = ai;
						break;
					}
				}
				if ( j == bi->bi_nattrs ) {
					Debug( LDAP_DEBUG_ANY,
						LDAP_XSTRING(bdb_tool_entry_reindex)
						": no index configured for %s\n",
						adv[i]->ad_cname.bv_val, 0, 0 );
					return -1;
				}
			}
		}
		bi->bi_nattrs = i;
	}

	/* Get the first attribute to index */
	if (bi->bi_linear_index && !index_nattrs) {
		index_nattrs = bi->bi_nattrs - 1;
		bi->bi_nattrs = 1;
	}

	e = bdb_tool_entry_get( be, id );

	if( e == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(bdb_tool_entry_reindex)
			": could not locate id=%ld\n",
			(long) id, 0, 0 );
		return -1;
	}

	if (! (slapMode & SLAP_TOOL_QUICK)) {
	rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(bdb_tool_entry_reindex) ": "
			"txn_begin failed: %s (%d)\n",
			db_strerror(rc), rc, 0 );
		goto done;
	}
	}
 	
	/*
	 * just (re)add them for now
	 * assume that some other routine (not yet implemented)
	 * will zap index databases
	 *
	 */

	Debug( LDAP_DEBUG_TRACE,
		"=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
		(long) id, e->e_dn, 0 );

	op.o_hdr = &ohdr;
	op.o_bd = be;
	op.o_tmpmemctx = NULL;
	op.o_tmpmfuncs = &ch_mfuncs;

	rc = bdb_tool_index_add( &op, tid, e );

done:
	if( rc == 0 ) {
		if (! (slapMode & SLAP_TOOL_QUICK)) {
		rc = TXN_COMMIT( tid, 0 );
		if( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
				"=> " LDAP_XSTRING(bdb_tool_entry_reindex)
				": txn_commit failed: %s (%d)\n",
				db_strerror(rc), rc, 0 );
			e->e_id = NOID;
		}
		}

	} else {
		if (! (slapMode & SLAP_TOOL_QUICK)) {
		TXN_ABORT( tid );
		Debug( LDAP_DEBUG_ANY,
			"=> " LDAP_XSTRING(bdb_tool_entry_reindex)
			": txn_aborted! %s (%d)\n",
			db_strerror(rc), rc, 0 );
		}
		e->e_id = NOID;
	}
	bdb_entry_release( &op, e, 0 );

	return rc;
}
예제 #24
0
int
bdb_modrdn( Operation	*op, SlapReply *rs )
{
	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	struct berval	p_dn, p_ndn;
	struct berval	new_dn = {0, NULL}, new_ndn = {0, NULL};
	Entry		*e = NULL;
	Entry		*p = NULL;
	EntryInfo	*ei = NULL, *eip = NULL, *nei = NULL, *neip = NULL;
	/* LDAP v2 supporting correct attribute handling. */
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;
	DB_TXN		*ltid = NULL, *lt2;
	struct bdb_op_info opinfo = {{{ 0 }}};
	Entry dummy = {0};

	Entry		*np = NULL;			/* newSuperior Entry */
	struct berval	*np_dn = NULL;			/* newSuperior dn */
	struct berval	*np_ndn = NULL;			/* newSuperior ndn */
	struct berval	*new_parent_dn = NULL;	/* np_dn, p_dn, or NULL */

	int		manageDSAit = get_manageDSAit( op );

	DB_LOCK		lock, plock, nplock;

	int		num_retries = 0;

	LDAPControl **preread_ctrl = NULL;
	LDAPControl **postread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

	int	rc;

	int parent_is_glue = 0;
	int parent_is_leaf = 0;

#ifdef LDAP_X_TXN
	int settle = 0;
#endif

	Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(bdb_modrdn) "(%s,%s,%s)\n",
		op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
		op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );

#ifdef LDAP_X_TXN
	if( op->o_txnSpec ) {
		/* acquire connection lock */
		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
		if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
			rs->sr_text = "invalid transaction identifier";
			rs->sr_err = LDAP_X_TXN_ID_INVALID;
			goto txnReturn;
		} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
			settle=1;
			goto txnReturn;
		}

		if( op->o_conn->c_txn_backend == NULL ) {
			op->o_conn->c_txn_backend = op->o_bd;

		} else if( op->o_conn->c_txn_backend != op->o_bd ) {
			rs->sr_text = "transaction cannot span multiple database contexts";
			rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
			goto txnReturn;
		}

		/* insert operation into transaction */

		rs->sr_text = "transaction specified";
		rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;

txnReturn:
		/* release connection lock */
		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );

		if( !settle ) {
			send_ldap_result( op, rs );
			return rs->sr_err;
		}
	}
#endif

	ctrls[num_ctrls] = NULL;

	slap_mods_opattrs( op, &op->orr_modlist, 1 );

	if( 0 ) {
retry:	/* transaction retry */
		if ( dummy.e_attrs ) {
			attrs_free( dummy.e_attrs );
			dummy.e_attrs = NULL;
		}
		if (e != NULL) {
			bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
			e = NULL;
		}
		if (p != NULL) {
			bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
			p = NULL;
		}
		if (np != NULL) {
			bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
			np = NULL;
		}
		Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(bdb_modrdn)
				": retrying...\n" );

		rs->sr_err = TXN_ABORT( ltid );
		ltid = NULL;
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
		opinfo.boi_oe.oe_key = NULL;
		op->o_do_not_cache = opinfo.boi_acl_cache;
		if( rs->sr_err != 0 ) {
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
		if ( slap_get_op_abandon(op) ) {
			rs->sr_err = SLAPD_ABANDON;
			goto return_results;
		}
		parent_is_glue = 0;
		parent_is_leaf = 0;
		bdb_trans_backoff( ++num_retries );
	}

	/* begin transaction */
	rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid,
		bdb->bi_db_opflags );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modrdn) ": txn_begin failed: "
			"%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": txn1 id: %x\n",
		ltid->id(ltid) );

	opinfo.boi_oe.oe_key = bdb;
	opinfo.boi_txn = ltid;
	opinfo.boi_err = 0;
	opinfo.boi_acl_cache = op->o_do_not_cache;
	LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next );

	/* get entry */
	rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
		&lock );

	switch( rs->sr_err ) {
	case 0:
	case DB_NOTFOUND:
		break;
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	e = ei->bei_e;
	/* FIXME: dn2entry() should return non-glue entry */
	if (( rs->sr_err == DB_NOTFOUND ) ||
		( !manageDSAit && e && is_entry_glue( e )))
	{
		if( e != NULL ) {
			rs->sr_matched = ch_strdup( e->e_dn );
			rs->sr_ref = is_entry_referral( e )
				? get_entry_referrals( op, e )
				: NULL;
			bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, e);
			e = NULL;

		} else {
			rs->sr_ref = referral_rewrite( default_referral, NULL,
					&op->o_req_dn, LDAP_SCOPE_DEFAULT );
		}

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		send_ldap_result( op, rs );
		goto done;
	}

	if ( get_assert( op ) &&
		( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	/* check write on old entry */
	rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL );
	if ( ! rs->sr_err ) {
		switch( opinfo.boi_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		Debug( LDAP_DEBUG_TRACE, "no access to entry\n" );
		rs->sr_text = "no write access to old entry";
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		goto return_results;
	}

#ifndef BDB_HIER
	rs->sr_err = bdb_cache_children( op, ltid, e );
	if ( rs->sr_err != DB_NOTFOUND ) {
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		case 0:
			Debug(LDAP_DEBUG_ARGS,
				"<=- " LDAP_XSTRING(bdb_modrdn)
				": non-leaf %s\n",
				op->o_req_dn.bv_val);
			rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
			rs->sr_text = "subtree rename not supported";
			break;
		default:
			Debug(LDAP_DEBUG_ARGS,
				"<=- " LDAP_XSTRING(bdb_modrdn)
				": has_children failed: %s (%d)\n",
				db_strerror(rs->sr_err), rs->sr_err );
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
		}
		goto return_results;
	}
	ei->bei_state |= CACHE_ENTRY_NO_KIDS;
#endif

	if (!manageDSAit && is_entry_referral( e ) ) {
		/* parent is a referral, don't allow add */
		rs->sr_ref = get_entry_referrals( op, e );

		Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn)
			": entry %s is referral\n", e->e_dn );

		rs->sr_err = LDAP_REFERRAL,
		rs->sr_matched = e->e_name.bv_val;
		rs->sr_flags = REP_REF_MUSTBEFREED;
		send_ldap_result( op, rs );
		goto done;
	}

	if ( be_issuffix( op->o_bd, &e->e_nname ) ) {
#ifdef BDB_MULTIPLE_SUFFIXES
		/* Allow renaming one suffix entry to another */
		p_ndn = slap_empty_bv;
#else
		/* There can only be one suffix entry */
		rs->sr_err = LDAP_NAMING_VIOLATION;
		rs->sr_text = "cannot rename suffix entry";
		goto return_results;
#endif
	} else {
		dnParent( &e->e_nname, &p_ndn );
	}
	np_ndn = &p_ndn;
	eip = ei->bei_parent;
	if ( eip && eip->bei_id ) {
		/* Make sure parent entry exist and we can write its
		 * children.
		 */
		rs->sr_err = bdb_cache_find_id( op, ltid,
			eip->bei_id, &eip, 0, &plock );

		switch( rs->sr_err ) {
		case 0:
		case DB_NOTFOUND:
			break;
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		case LDAP_BUSY:
			rs->sr_text = "ldap server busy";
			goto return_results;
		default:
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}

		p = eip->bei_e;
		if( p == NULL) {
			Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn)
				": parent does not exist\n" );
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "old entry's parent does not exist";
			goto return_results;
		}
	} else {
		p = (Entry *)&slap_entry_root;
	}

	/* check parent for "children" acl */
	rs->sr_err = access_allowed( op, p,
		children, NULL,
		op->oq_modrdn.rs_newSup == NULL ?
			ACL_WRITE : ACL_WDEL,
		NULL );

	if ( !p_ndn.bv_len )
		p = NULL;

	if ( ! rs->sr_err ) {
		switch( opinfo.boi_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		Debug( LDAP_DEBUG_TRACE, "no access to parent\n" );
		rs->sr_text = "no write access to old parent's children";
		goto return_results;
	}

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_modrdn) ": wr to children "
		"of entry %s OK\n", p_ndn.bv_val );

	if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
		p_dn = slap_empty_bv;
	} else {
		dnParent( &e->e_name, &p_dn );
	}

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_modrdn) ": parent dn=%s\n",
		p_dn.bv_val );

	new_parent_dn = &p_dn;	/* New Parent unless newSuperior given */

	if ( op->oq_modrdn.rs_newSup != NULL ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modrdn)
			": new parent \"%s\" requested...\n",
			op->oq_modrdn.rs_newSup->bv_val );

		/*  newSuperior == oldParent? */
		if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) {
			Debug( LDAP_DEBUG_TRACE, "bdb_back_modrdn: "
				"new parent \"%s\" same as the old parent \"%s\"\n",
				op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val );
			op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
		}
	}

	/* There's a BDB_MULTIPLE_SUFFIXES case here that this code doesn't
	 * support. E.g., two suffixes dc=foo,dc=com and dc=bar,dc=net.
	 * We do not allow modDN
	 *   dc=foo,dc=com
	 *    newrdn dc=bar
	 *    newsup dc=net
	 * and we probably should. But since MULTIPLE_SUFFIXES is deprecated
	 * I'm ignoring this problem for now.
	 */
	if ( op->oq_modrdn.rs_newSup != NULL ) {
		if ( op->oq_modrdn.rs_newSup->bv_len ) {
			np_dn = op->oq_modrdn.rs_newSup;
			np_ndn = op->oq_modrdn.rs_nnewSup;

			/* newSuperior == oldParent? - checked above */
			/* newSuperior == entry being moved?, if so ==> ERROR */
			if ( dnIsSuffix( np_ndn, &e->e_nname )) {
				rs->sr_err = LDAP_NO_SUCH_OBJECT;
				rs->sr_text = "new superior not found";
				goto return_results;
			}
			/* Get Entry with dn=newSuperior. Does newSuperior exist? */

			rs->sr_err = bdb_dn2entry( op, ltid, np_ndn,
				&neip, 0, &nplock );

			switch( rs->sr_err ) {
			case 0: np = neip->bei_e;
			case DB_NOTFOUND:
				break;
			case DB_LOCK_DEADLOCK:
			case DB_LOCK_NOTGRANTED:
				goto retry;
			case LDAP_BUSY:
				rs->sr_text = "ldap server busy";
				goto return_results;
			default:
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "internal error";
				goto return_results;
			}

			if( np == NULL) {
				Debug( LDAP_DEBUG_TRACE,
					LDAP_XSTRING(bdb_modrdn)
					": newSup(ndn=%s) not here!\n",
					np_ndn->bv_val );
				rs->sr_text = "new superior not found";
				rs->sr_err = LDAP_NO_SUCH_OBJECT;
				goto return_results;
			}

			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_modrdn)
				": wr to new parent OK np=%p, id=%ld\n",
				(void *) np, (long) np->e_id );

			/* check newSuperior for "children" acl */
			rs->sr_err = access_allowed( op, np, children,
				NULL, ACL_WADD, NULL );

			if( ! rs->sr_err ) {
				switch( opinfo.boi_err ) {
				case DB_LOCK_DEADLOCK:
				case DB_LOCK_NOTGRANTED:
					goto retry;
				}

				Debug( LDAP_DEBUG_TRACE,
					LDAP_XSTRING(bdb_modrdn)
					": no wr to newSup children\n" );
				rs->sr_text = "no write access to new superior's children";
				rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
				goto return_results;
			}

			if ( is_entry_alias( np ) ) {
				/* parent is an alias, don't allow add */
				Debug( LDAP_DEBUG_TRACE,
					LDAP_XSTRING(bdb_modrdn)
					": entry is alias\n" );
				rs->sr_text = "new superior is an alias";
				rs->sr_err = LDAP_ALIAS_PROBLEM;
				goto return_results;
			}

			if ( is_entry_referral( np ) ) {
				/* parent is a referral, don't allow add */
				Debug( LDAP_DEBUG_TRACE,
					LDAP_XSTRING(bdb_modrdn)
					": entry is referral\n" );
				rs->sr_text = "new superior is a referral";
				rs->sr_err = LDAP_OTHER;
				goto return_results;
			}

		} else {
			np_dn = NULL;

			/* no parent, modrdn entry directly under root */
			if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
				|| be_isupdate( op ) ) {
				np = (Entry *)&slap_entry_root;

				/* check parent for "children" acl */
				rs->sr_err = access_allowed( op, np,
					children, NULL, ACL_WADD, NULL );

				np = NULL;

				if ( ! rs->sr_err ) {
					switch( opinfo.boi_err ) {
					case DB_LOCK_DEADLOCK:
					case DB_LOCK_NOTGRANTED:
						goto retry;
					}

					rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
					Debug( LDAP_DEBUG_TRACE,
						"no access to new superior\n" );
					rs->sr_text =
						"no write access to new superior's children";
					goto return_results;
				}
			}
		}

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modrdn)
			": wr to new parent's children OK\n" );

		new_parent_dn = np_dn;
	}

	/* Build target dn and make sure target entry doesn't exist already. */
	if (!new_dn.bv_val) {
		build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, NULL );
	}

	if (!new_ndn.bv_val) {
		struct berval bv = {0, NULL};
		dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx );
		ber_dupbv( &new_ndn, &bv );
		/* FIXME: why not call dnNormalize() w/o ctx? */
		op->o_tmpfree( bv.bv_val, op->o_tmpmemctx );
	}

	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": new ndn=%s\n",
		new_ndn.bv_val );

	/* Shortcut the search */
	nei = neip ? neip : eip;
	rs->sr_err = bdb_cache_find_ndn ( op, ltid, &new_ndn, &nei );
	if ( nei ) bdb_cache_entryinfo_unlock( nei );
	switch( rs->sr_err ) {
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
	case DB_NOTFOUND:
		break;
	case 0:
		/* Allow rename to same DN */
		if ( nei == ei )
			break;
		rs->sr_err = LDAP_ALREADY_EXISTS;
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	assert( op->orr_modlist != NULL );

	if( op->o_preread ) {
		if( preread_ctrl == NULL ) {
			preread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, e,
			&slap_pre_read_bv, preread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_modrdn)
				": pre-read failed!\n" );
			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	/* nested transaction */
	rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, bdb->bi_db_opflags );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modrdn)
			": txn_begin(2) failed: %s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": txn2 id: %x\n",
		lt2->id(lt2) );

	/* delete old DN */
	rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e );
	if ( rs->sr_err != 0 ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(bdb_modrdn)
			": dn2id del failed: %s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "DN index delete fail";
		goto return_results;
	}

	/* copy the entry, then override some fields */
	dummy = *e;
	dummy.e_name = new_dn;
	dummy.e_nname = new_ndn;
	dummy.e_attrs = NULL;

	/* add new DN */
	rs->sr_err = bdb_dn2id_add( op, lt2, neip ? neip : eip, &dummy );
	if ( rs->sr_err != 0 ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(bdb_modrdn)
			": dn2id add failed: %s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "DN index add failed";
		goto return_results;
	}

	dummy.e_attrs = e->e_attrs;

	/* modify entry */
	rs->sr_err = bdb_modify_internal( op, lt2, op->orr_modlist, &dummy,
		&rs->sr_text, textbuf, textlen );
	if( rs->sr_err != LDAP_SUCCESS ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(bdb_modrdn)
			": modify failed: %s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err );
		if ( ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) && opinfo.boi_err ) {
			rs->sr_err = opinfo.boi_err;
		}
		if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		goto return_results;
	}

	/* id2entry index */
	rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, &dummy );
	if ( rs->sr_err != 0 ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(bdb_modrdn)
			": id2entry failed: %s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "entry update failed";
		goto return_results;
	}

	if ( p_ndn.bv_len != 0 ) {
		parent_is_glue = is_entry_glue(p);
		rs->sr_err = bdb_cache_children( op, lt2, p );
		if ( rs->sr_err != DB_NOTFOUND ) {
			switch( rs->sr_err ) {
			case DB_LOCK_DEADLOCK:
			case DB_LOCK_NOTGRANTED:
				goto retry;
			case 0:
				break;
			default:
				Debug(LDAP_DEBUG_ARGS,
					"<=- " LDAP_XSTRING(bdb_modrdn)
					": has_children failed: %s (%d)\n",
					db_strerror(rs->sr_err), rs->sr_err );
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "internal error";
				goto return_results;
			}
			parent_is_leaf = 1;
		}
		bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
		p = NULL;
	}

	if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "txn_commit(2) failed";
		goto return_results;
	}

	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, &dummy,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_modrdn)
				": post-read failed!\n" );
			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	if( op->o_noop ) {
		if(( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
			rs->sr_text = "txn_abort (no-op) failed";
		} else {
			rs->sr_err = LDAP_X_NO_OPERATION;
			ltid = NULL;
			/* Only free attrs if they were dup'd.  */
			if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
			goto return_results;
		}

	} else {
		rc = bdb_cache_modrdn( bdb, e, &op->orr_nnewrdn, &dummy, neip,
			ltid, &lock );
		switch( rc ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		dummy.e_attrs = NULL;
		new_dn.bv_val = NULL;
		new_ndn.bv_val = NULL;

		if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
			rs->sr_text = "txn_commit failed";
		} else {
			rs->sr_err = LDAP_SUCCESS;
		}
	}

	ltid = NULL;
	LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	opinfo.boi_oe.oe_key = NULL;

	if( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modrdn) ": %s : %s (%d)\n",
			rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;

		goto return_results;
	}

	Debug(LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_modrdn)
		": rdn modified%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		dummy.e_id, op->o_req_dn.bv_val );
	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	if ( dummy.e_attrs ) {
		attrs_free( dummy.e_attrs );
	}
	send_ldap_result( op, rs );

	if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp_kbyte ) {
		TXN_CHECKPOINT( bdb->bi_dbenv,
			bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
	}

	if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
		op->o_delete_glue_parent = 1;
	}

done:
	rs_send_cleanup( rs );
	slap_graduate_commit_csn( op );

	if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
	if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );

	/* LDAP v3 Support */
	if( np != NULL ) {
		/* free new parent and reader lock */
		bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
	}

	if( p != NULL ) {
		/* free parent and reader lock */
		bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
	}

	/* free entry */
	if( e != NULL ) {
		bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e);
	}

	if( ltid != NULL ) {
		TXN_ABORT( ltid );
	}
	if ( opinfo.boi_oe.oe_key ) {
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	}

	if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
		slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
	}
	if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
		slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
	}
	return rs->sr_err;
}
예제 #25
0
int
mdb_add(Operation *op, SlapReply *rs )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
	struct berval	pdn;
	Entry		*p = NULL, *oe = op->ora_e;
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	MDB_txn		*txn = NULL;
	MDB_cursor	*mc = NULL;
	MDB_cursor	*mcd;
	ID eid, pid = 0;
	mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
	int subentry;
	int numads = mdb->mi_numads;

	int		success;

	LDAPControl **postread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

#ifdef LDAP_X_TXN
	int settle = 0;
#endif

	Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(mdb_add) ": %s\n",
		op->ora_e->e_name.bv_val, 0, 0);

#ifdef LDAP_X_TXN
	if( op->o_txnSpec ) {
		/* acquire connection lock */
		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
		if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
			rs->sr_text = "invalid transaction identifier";
			rs->sr_err = LDAP_X_TXN_ID_INVALID;
			goto txnReturn;
		} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
			settle=1;
			goto txnReturn;
		}

		if( op->o_conn->c_txn_backend == NULL ) {
			op->o_conn->c_txn_backend = op->o_bd;

		} else if( op->o_conn->c_txn_backend != op->o_bd ) {
			rs->sr_text = "transaction cannot span multiple database contexts";
			rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
			goto txnReturn;
		}

		/* insert operation into transaction */

		rs->sr_text = "transaction specified";
		rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;

txnReturn:
		/* release connection lock */
		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );

		if( !settle ) {
			send_ldap_result( op, rs );
			return rs->sr_err;
		}
	}
#endif

	ctrls[num_ctrls] = 0;

	/* check entry's schema */
	rs->sr_err = entry_schema_check( op, op->ora_e, NULL,
		get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": entry failed schema check: "
			"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
		goto return_results;
	}

	/* begin transaction */
	rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": txn_begin failed: %s (%d)\n",
			mdb_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	txn = moi->moi_txn;

	/* add opattrs to shadow as well, only missing attrs will actually
	 * be added; helps compatibility with older OL versions */
	rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": entry failed op attrs add: "
			"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
		goto return_results;
	}

	if ( get_assert( op ) &&
		( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	subentry = is_entry_subentry( op->ora_e );

	/*
	 * Get the parent dn and see if the corresponding entry exists.
	 */
	if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
		pdn = slap_empty_bv;
	} else {
		dnParent( &op->ora_e->e_nname, &pdn );
	}

	rs->sr_err = mdb_cursor_open( txn, mdb->mi_dn2id, &mcd );
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": mdb_cursor_open failed (%d)\n",
			rs->sr_err, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* get entry or parent */
	rs->sr_err = mdb_dn2entry( op, txn, mcd, &op->ora_e->e_nname, &p, NULL, 1 );
	switch( rs->sr_err ) {
	case 0:
		rs->sr_err = LDAP_ALREADY_EXISTS;
		mdb_entry_return( op, p );
		p = NULL;
		goto return_results;
	case MDB_NOTFOUND:
		break;
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	if ( !p )
		p = (Entry *)&slap_entry_root;

	if ( !bvmatch( &pdn, &p->e_nname ) ) {
		rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
			op->o_tmpmemctx );
		if ( p != (Entry *)&slap_entry_root && is_entry_referral( p )) {
			BerVarray ref = get_entry_referrals( op, p );
			rs->sr_ref = referral_rewrite( ref, &p->e_name,
				&op->o_req_dn, LDAP_SCOPE_DEFAULT );
			ber_bvarray_free( ref );
		} else {
			rs->sr_ref = NULL;
		}
		if ( p != (Entry *)&slap_entry_root )
			mdb_entry_return( op, p );
		p = NULL;
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": parent "
			"does not exist\n", 0, 0, 0 );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	rs->sr_err = access_allowed( op, p,
		children, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		if ( p != (Entry *)&slap_entry_root )
			mdb_entry_return( op, p );
		p = NULL;

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": no write access to parent\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to parent";
		goto return_results;;
	}

	if ( p != (Entry *)&slap_entry_root ) {
		if ( is_entry_subentry( p ) ) {
			mdb_entry_return( op, p );
			p = NULL;
			/* parent is a subentry, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_add) ": parent is subentry\n",
				0, 0, 0 );
			rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			rs->sr_text = "parent is a subentry";
			goto return_results;;
		}

		if ( is_entry_alias( p ) ) {
			mdb_entry_return( op, p );
			p = NULL;
			/* parent is an alias, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_add) ": parent is alias\n",
				0, 0, 0 );
			rs->sr_err = LDAP_ALIAS_PROBLEM;
			rs->sr_text = "parent is an alias";
			goto return_results;;
		}

		if ( is_entry_referral( p ) ) {
			BerVarray ref = get_entry_referrals( op, p );
			/* parent is a referral, don't allow add */
			rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
				op->o_tmpmemctx );
			rs->sr_ref = referral_rewrite( ref, &p->e_name,
				&op->o_req_dn, LDAP_SCOPE_DEFAULT );
			ber_bvarray_free( ref );
			mdb_entry_return( op, p );
			p = NULL;
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_add) ": parent is referral\n",
				0, 0, 0 );

			rs->sr_err = LDAP_REFERRAL;
			rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
			goto return_results;
		}

	}

	if ( subentry ) {
		/* FIXME: */
		/* parent must be an administrative point of the required kind */
	}

	/* free parent */
	if ( p != (Entry *)&slap_entry_root ) {
		pid = p->e_id;
		if ( p->e_nname.bv_len ) {
			struct berval ppdn;

			/* ITS#5326: use parent's DN if differs from provided one */
			dnParent( &op->ora_e->e_name, &ppdn );
			if ( !dn_match( &p->e_name, &ppdn ) ) {
				struct berval rdn;
				struct berval newdn;

				dnRdn( &op->ora_e->e_name, &rdn );

				build_new_dn( &newdn, &p->e_name, &rdn, NULL ); 
				if ( op->ora_e->e_name.bv_val != op->o_req_dn.bv_val )
					ber_memfree( op->ora_e->e_name.bv_val );
				op->ora_e->e_name = newdn;

				/* FIXME: should check whether
				 * dnNormalize(newdn) == e->e_nname ... */
			}
		}

		mdb_entry_return( op, p );
	}
	p = NULL;

	rs->sr_err = access_allowed( op, op->ora_e,
		entry, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": no write access to entry\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to entry";
		goto return_results;;
	}

	/* 
	 * Check ACL for attribute write access
	 */
	if (!acl_check_modlist(op, oe, op->ora_modlist)) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": no write access to attribute\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to attribute";
		goto return_results;;
	}

	rs->sr_err = mdb_cursor_open( txn, mdb->mi_id2entry, &mc );
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": mdb_cursor_open failed (%d)\n",
			rs->sr_err, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	rs->sr_err = mdb_next_id( op->o_bd, mc, &eid );
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": next_id failed (%d)\n",
			rs->sr_err, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	op->ora_e->e_id = eid;

	/* dn2id index */
	rs->sr_err = mdb_dn2id_add( op, mcd, mcd, pid, 1, 1, op->ora_e );
	mdb_cursor_close( mcd );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": dn2id_add failed: %s (%d)\n",
			mdb_strerror(rs->sr_err), rs->sr_err, 0 );

		switch( rs->sr_err ) {
		case MDB_KEYEXIST:
			rs->sr_err = LDAP_ALREADY_EXISTS;
			break;
		default:
			rs->sr_err = LDAP_OTHER;
		}
		goto return_results;
	}

	/* attribute indexes */
	rs->sr_err = mdb_index_entry_add( op, txn, op->ora_e );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": index_entry_add failed\n",
			0, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "index generation failed";
		goto return_results;
	}

	/* id2entry index */
	rs->sr_err = mdb_id2entry_add( op, txn, mc, op->ora_e );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": id2entry_add failed\n",
			0, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "entry store failed";
		goto return_results;
	}

	/* post-read */
	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if ( slap_read_controls( op, rs, op->ora_e,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(mdb_add) ": post-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	if ( moi == &opinfo ) {
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
		opinfo.moi_oe.oe_key = NULL;
		if ( op->o_noop ) {
			mdb->mi_numads = numads;
			mdb_txn_abort( txn );
			rs->sr_err = LDAP_X_NO_OPERATION;
			txn = NULL;
			goto return_results;
		}

		rs->sr_err = mdb_txn_commit( txn );
		txn = NULL;
		if ( rs->sr_err != 0 ) {
			mdb->mi_numads = numads;
			rs->sr_text = "txn_commit failed";
			Debug( LDAP_DEBUG_ANY,
				LDAP_XSTRING(mdb_add) ": %s : %s (%d)\n",
				rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err );
			rs->sr_err = LDAP_OTHER;
			goto return_results;
		}
	}

	Debug(LDAP_DEBUG_TRACE,
		LDAP_XSTRING(mdb_add) ": added%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		op->ora_e->e_id, op->ora_e->e_dn );

	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	success = rs->sr_err;
	send_ldap_result( op, rs );

	if( moi == &opinfo ) {
		if( txn != NULL ) {
			mdb->mi_numads = numads;
			mdb_txn_abort( txn );
		}
		if ( opinfo.moi_oe.oe_key ) {
			LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
		}
	} else {
		moi->moi_ref--;
	}

	if( success == LDAP_SUCCESS ) {
#if 0
		if ( mdb->bi_txn_cp_kbyte ) {
			TXN_CHECKPOINT( mdb->bi_dbenv,
				mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
		}
#endif
	}

	slap_graduate_commit_csn( op );

	if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
		slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
	}
	return rs->sr_err;
}
예제 #26
0
/*
 * call from within bdb_initialize()
 */
static int
bdb_monitor_initialize( void )
{
	int		i, code;
	ConfigArgs c;
	char	*argv[ 3 ];

	static int	bdb_monitor_initialized = 0;

	/* set to 0 when successfully initialized; otherwise, remember failure */
	static int	bdb_monitor_initialized_failure = 1;

	if ( bdb_monitor_initialized++ ) {
		return bdb_monitor_initialized_failure;
	}

	if ( backend_info( "monitor" ) == NULL ) {
		return -1;
	}

	/* register schema here */

	argv[ 0 ] = "back-bdb/back-hdb monitor";
	c.argv = argv;
	c.argc = 3;
	c.fname = argv[0];

	for ( i = 0; s_oid[ i ].name; i++ ) {
		c.lineno = i;
		argv[ 1 ] = s_oid[ i ].name;
		argv[ 2 ] = s_oid[ i ].oid;

		if ( parse_oidm( &c, 0, NULL ) != 0 ) {
			Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_monitor_initialize)
				": unable to add "
				"objectIdentifier \"%s=%s\"\n",
				s_oid[ i ].name, s_oid[ i ].oid, 0 );
			return 2;
		}
	}

	for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
		code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
		if ( code != LDAP_SUCCESS ) {
			Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_monitor_initialize)
				": register_at failed for attributeType (%s)\n",
				s_at[ i ].desc, 0, 0 );
			return 3;

		} else {
			(*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
		}
	}

	for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
		code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
		if ( code != LDAP_SUCCESS ) {
			Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_monitor_initialize)
				": register_oc failed for objectClass (%s)\n",
				s_oc[ i ].desc, 0, 0 );
			return 4;

		} else {
			(*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
		}
	}

	return ( bdb_monitor_initialized_failure = LDAP_SUCCESS );
}
예제 #27
0
파일: add.c 프로젝트: tiniesst/ReOpenLDAP
int
bdb_add(Operation *op, SlapReply *rs )
{
	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
	struct berval	pdn;
	Entry		*p = NULL, *oe = op->ora_e;
	EntryInfo	*ei;
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	DB_TXN		*ltid = NULL, *lt2;
	ID eid = NOID;
	struct bdb_op_info opinfo = {{{ 0 }}};
	int subentry;
	DB_LOCK		lock;

	int		num_retries = 0;
	int		success;

	LDAPControl **postread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

#ifdef LDAP_X_TXN
	int settle = 0;
#endif

	Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(bdb_add) ": %s\n",
		op->ora_e->e_name.bv_val);

#ifdef LDAP_X_TXN
	if( op->o_txnSpec ) {
		/* acquire connection lock */
		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
		if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
			rs->sr_text = "invalid transaction identifier";
			rs->sr_err = LDAP_X_TXN_ID_INVALID;
			goto txnReturn;
		} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
			settle=1;
			goto txnReturn;
		}

		if( op->o_conn->c_txn_backend == NULL ) {
			op->o_conn->c_txn_backend = op->o_bd;

		} else if( op->o_conn->c_txn_backend != op->o_bd ) {
			rs->sr_text = "transaction cannot span multiple database contexts";
			rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
			goto txnReturn;
		}

		/* insert operation into transaction */

		rs->sr_text = "transaction specified";
		rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;

txnReturn:
		/* release connection lock */
		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );

		if( !settle ) {
			send_ldap_result( op, rs );
			return rs->sr_err;
		}
	}
#endif

	ctrls[num_ctrls] = 0;

	/* check entry's schema */
	rs->sr_err = entry_schema_check( op, op->ora_e, NULL,
		get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": entry failed schema check: "
			"%s (%d)\n", rs->sr_text, rs->sr_err );
		goto return_results;
	}

	/* add opattrs to shadow as well, only missing attrs will actually
	 * be added; helps compatibility with older OL versions */
	rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": entry failed op attrs add: "
			"%s (%d)\n", rs->sr_text, rs->sr_err );
		goto return_results;
	}

	if ( get_assert( op ) &&
		( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	subentry = is_entry_subentry( op->ora_e );

	if( 0 ) {
retry:	/* transaction retry */
		if( p ) {
			/* free parent and reader lock */
			if ( p != (Entry *)&slap_entry_root ) {
				bdb_unlocked_cache_return_entry_r( bdb, p );
			}
			p = NULL;
		}
		rs->sr_err = TXN_ABORT( ltid );
		ltid = NULL;
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
		opinfo.boi_oe.oe_key = NULL;
		op->o_do_not_cache = opinfo.boi_acl_cache;
		if( rs->sr_err != 0 ) {
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			goto return_results;
		}
		bdb_trans_backoff( ++num_retries );
	}

	/* begin transaction */
	rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid,
		bdb->bi_db_opflags );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": txn_begin failed: %s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": txn1 id: %x\n",
		ltid->id(ltid) );

	opinfo.boi_oe.oe_key = bdb;
	opinfo.boi_txn = ltid;
	opinfo.boi_err = 0;
	opinfo.boi_acl_cache = op->o_do_not_cache;
	LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next );

	/*
	 * Get the parent dn and see if the corresponding entry exists.
	 */
	if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
		pdn = slap_empty_bv;
	} else {
		dnParent( &op->ora_e->e_nname, &pdn );
	}

	/* get entry or parent */
	rs->sr_err = bdb_dn2entry( op, ltid, &op->ora_e->e_nname, &ei,
		1, &lock );
	switch( rs->sr_err ) {
	case 0:
		rs->sr_err = LDAP_ALREADY_EXISTS;
		goto return_results;
	case DB_NOTFOUND:
		break;
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	p = ei->bei_e;
	if ( !p )
		p = (Entry *)&slap_entry_root;

	if ( !bvmatch( &pdn, &p->e_nname ) ) {
		rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
			op->o_tmpmemctx );
		rs->sr_ref = is_entry_referral( p )
			? get_entry_referrals( op, p )
			: NULL;
		if ( p != (Entry *)&slap_entry_root )
			bdb_unlocked_cache_return_entry_r( bdb, p );
		p = NULL;
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": parent "
			"does not exist\n" );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	rs->sr_err = access_allowed( op, p,
		children, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		switch( opinfo.boi_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		if ( p != (Entry *)&slap_entry_root )
			bdb_unlocked_cache_return_entry_r( bdb, p );
		p = NULL;

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": no write access to parent\n" );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to parent";
		goto return_results;;
	}

	if ( p != (Entry *)&slap_entry_root ) {
		if ( is_entry_subentry( p ) ) {
			bdb_unlocked_cache_return_entry_r( bdb, p );
			p = NULL;
			/* parent is a subentry, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_add) ": parent is subentry\n" );
			rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			rs->sr_text = "parent is a subentry";
			goto return_results;;
		}

		if ( is_entry_alias( p ) ) {
			bdb_unlocked_cache_return_entry_r( bdb, p );
			p = NULL;
			/* parent is an alias, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_add) ": parent is alias\n" );
			rs->sr_err = LDAP_ALIAS_PROBLEM;
			rs->sr_text = "parent is an alias";
			goto return_results;;
		}

		if ( is_entry_referral( p ) ) {
			/* parent is a referral, don't allow add */
			rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
				op->o_tmpmemctx );
			rs->sr_ref = get_entry_referrals( op, p );
			bdb_unlocked_cache_return_entry_r( bdb, p );
			p = NULL;
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_add) ": parent is referral\n" );

			rs->sr_err = LDAP_REFERRAL;
			rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
			goto return_results;
		}

	}

	if ( subentry ) {
		/* FIXME: */
		/* parent must be an administrative point of the required kind */
	}

	/* free parent and reader lock */
	if ( p != (Entry *)&slap_entry_root ) {
		if ( p->e_nname.bv_len ) {
			struct berval ppdn;

			/* ITS#5326: use parent's DN if differs from provided one */
			dnParent( &op->ora_e->e_name, &ppdn );
			if ( !dn_match( &p->e_name, &ppdn ) ) {
				struct berval rdn;
				struct berval newdn;

				dnRdn( &op->ora_e->e_name, &rdn );

				build_new_dn( &newdn, &p->e_name, &rdn, NULL );
				if ( op->ora_e->e_name.bv_val != op->o_req_dn.bv_val )
					ber_memfree( op->ora_e->e_name.bv_val );
				op->ora_e->e_name = newdn;

				/* FIXME: should check whether
				 * dnNormalize(newdn) == e->e_nname ... */
			}
		}

		bdb_unlocked_cache_return_entry_r( bdb, p );
	}
	p = NULL;

	rs->sr_err = access_allowed( op, op->ora_e,
		entry, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		switch( opinfo.boi_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": no write access to entry\n" );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to entry";
		goto return_results;;
	}

	/*
	 * Check ACL for attribute write access
	 */
	if (!acl_check_modlist(op, oe, op->ora_modlist)) {
		switch( opinfo.boi_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": no write access to attribute\n" );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to attribute";
		goto return_results;;
	}

	if ( eid == NOID ) {
		rs->sr_err = bdb_next_id( op->o_bd, &eid );
		if( rs->sr_err != 0 ) {
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_add) ": next_id failed (%d)\n",
				rs->sr_err );
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
		op->ora_e->e_id = eid;
	}

	/* nested transaction */
	rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2,
		bdb->bi_db_opflags );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": txn_begin(2) failed: "
			"%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": txn2 id: %x\n",
		lt2->id(lt2) );

	/* dn2id index */
	rs->sr_err = bdb_dn2id_add( op, lt2, ei, op->ora_e );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": dn2id_add failed: %s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err );

		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		case DB_KEYEXIST:
			rs->sr_err = LDAP_ALREADY_EXISTS;
			break;
		default:
			rs->sr_err = LDAP_OTHER;
		}
		goto return_results;
	}

	/* attribute indexes */
	rs->sr_err = bdb_index_entry_add( op, lt2, op->ora_e );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": index_entry_add failed\n" );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		default:
			rs->sr_err = LDAP_OTHER;
		}
		rs->sr_text = "index generation failed";
		goto return_results;
	}

	/* id2entry index */
	rs->sr_err = bdb_id2entry_add( op->o_bd, lt2, op->ora_e );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": id2entry_add failed\n" );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		default:
			rs->sr_err = LDAP_OTHER;
		}
		rs->sr_text = "entry store failed";
		goto return_results;
	}

	if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "txn_commit(2) failed";
		goto return_results;
	}

	/* post-read */
	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if ( slap_read_controls( op, rs, op->ora_e,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_add) ": post-read "
				"failed!\n" );
			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	if ( op->o_noop ) {
		if (( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
			rs->sr_text = "txn_abort (no-op) failed";
		} else {
			rs->sr_err = LDAP_X_NO_OPERATION;
			ltid = NULL;
			goto return_results;
		}

	} else {
		struct berval nrdn;

		/* pick the RDN if not suffix; otherwise pick the entire DN */
		if (pdn.bv_len) {
			nrdn.bv_val = op->ora_e->e_nname.bv_val;
			nrdn.bv_len = pdn.bv_val - op->ora_e->e_nname.bv_val - 1;
		} else {
			nrdn = op->ora_e->e_nname;
		}

		bdb_cache_add( bdb, ei, op->ora_e, &nrdn, ltid, &lock );

		if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
			rs->sr_text = "txn_commit failed";
		} else {
			rs->sr_err = LDAP_SUCCESS;
		}
	}

	ltid = NULL;
	LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	opinfo.boi_oe.oe_key = NULL;

	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": %s : %s (%d)\n",
			rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	Debug(LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_add) ": added%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		op->ora_e->e_id, op->ora_e->e_dn );

	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	success = rs->sr_err;
	send_ldap_result( op, rs );

	if( ltid != NULL ) {
		TXN_ABORT( ltid );
	}
	if ( opinfo.boi_oe.oe_key ) {
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	}

	if( success == LDAP_SUCCESS ) {
		/* We own the entry now, and it can be purged at will
		 * Check to make sure it's the same entry we entered with.
		 * Possibly a callback may have mucked with it, although
		 * in general callbacks should treat the entry as read-only.
		 */
		bdb_cache_deref( oe->e_private );
		if ( op->ora_e == oe )
			op->ora_e = NULL;

		if ( bdb->bi_txn_cp_kbyte ) {
			TXN_CHECKPOINT( bdb->bi_dbenv,
				bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
		}
	}

	slap_graduate_commit_csn( op );

	if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
		slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
	}
	return rs->sr_err;
}
예제 #28
0
/*
 * call from within bdb_db_open()
 */
int
bdb_monitor_db_open( BackendDB *be )
{
	struct bdb_info		*bdb = (struct bdb_info *) be->be_private;
	Attribute		*a, *next;
	monitor_callback_t	*cb = NULL;
	int			rc = 0;
	BackendInfo		*mi;
	monitor_extra_t		*mbe;

	if ( !SLAP_DBMONITORING( be ) ) {
		return 0;
	}

	mi = backend_info( "monitor" );
	if ( !mi || !mi->bi_extra ) {
		SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
		return 0;
	}
	mbe = mi->bi_extra;

	/* don't bother if monitor is not configured */
	if ( !mbe->is_configured() ) {
		static int warning = 0;

		if ( warning++ == 0 ) {
			Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_monitor_db_open)
				": monitoring disabled; "
				"configure monitor database to enable\n",
				0, 0, 0 );
		}

		return 0;
	}

	/* alloc as many as required (plus 1 for objectClass) */
	a = attrs_alloc( 1 + 4 );
	if ( a == NULL ) {
		rc = 1;
		goto cleanup;
	}

	a->a_desc = slap_schema.si_ad_objectClass;
	attr_valadd( a, &oc_olmBDBDatabase->soc_cname, NULL, 1 );
	next = a->a_next;

	{
		struct berval	bv = BER_BVC( "0" );

		next->a_desc = ad_olmBDBEntryCache;
		attr_valadd( next, &bv, NULL, 1 );
		next = next->a_next;

		next->a_desc = ad_olmBDBDNCache;
		attr_valadd( next, &bv, NULL, 1 );
		next = next->a_next;

		next->a_desc = ad_olmBDBIDLCache;
		attr_valadd( next, &bv, NULL, 1 );
		next = next->a_next;
	}

	{
		struct berval	bv, nbv;
		ber_len_t	pathlen = 0, len = 0;
		char		path[ MAXPATHLEN ] = { '\0' };
		char		*fname = bdb->bi_dbenv_home,
				*ptr;

		len = strlen( fname );
		if ( fname[ 0 ] != '/' ) {
			/* get full path name */
			getcwd( path, sizeof( path ) );
			pathlen = strlen( path );

			if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
				fname += 2;
				len -= 2;
			}
		}

		bv.bv_len = pathlen + STRLENOF( "/" ) + len;
		ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
		if ( pathlen ) {
			ptr = lutil_strncopy( ptr, path, pathlen );
			ptr[ 0 ] = '/';
			ptr++;
		}
		ptr = lutil_strncopy( ptr, fname, len );
		if ( ptr[ -1 ] != '/' ) {
			ptr[ 0 ] = '/';
			ptr++;
		}
		ptr[ 0 ] = '\0';
		
		attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );

		next->a_desc = ad_olmDbDirectory;
		next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
		next->a_vals[ 0 ] = bv;
		next->a_numvals = 1;

		if ( BER_BVISNULL( &nbv ) ) {
			next->a_nvals = next->a_vals;

		} else {
			next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
			next->a_nvals[ 0 ] = nbv;
		}

		next = next->a_next;
	}

	cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
	cb->mc_update = bdb_monitor_update;
#if 0	/* uncomment if required */
	cb->mc_modify = bdb_monitor_modify;
#endif
	cb->mc_free = bdb_monitor_free;
	cb->mc_private = (void *)bdb;

	/* make sure the database is registered; then add monitor attributes */
	rc = mbe->register_database( be, &bdb->bi_monitor.bdm_ndn );
	if ( rc == 0 ) {
		rc = mbe->register_entry_attrs( &bdb->bi_monitor.bdm_ndn, a, cb,
			NULL, 0, NULL );
	}

cleanup:;
	if ( rc != 0 ) {
		if ( cb != NULL ) {
			ch_free( cb );
			cb = NULL;
		}

		if ( a != NULL ) {
			attrs_free( a );
			a = NULL;
		}
	}

	/* store for cleanup */
	bdb->bi_monitor.bdm_cb = (void *)cb;

	/* we don't need to keep track of the attributes, because
	 * bdb_monitor_free() takes care of everything */
	if ( a != NULL ) {
		attrs_free( a );
	}

	return rc;
}
예제 #29
0
static int
mdb_db_open( BackendDB *be, ConfigReply *cr )
{
	int rc, i;
	struct mdb_info *mdb = (struct mdb_info *) be->be_private;
	struct stat stat1;
	uint32_t flags;
	char *dbhome;
	MDB_txn *txn;

	if ( be->be_suffix == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_db_open) ": need suffix.\n",
			1, 0, 0 );
		return -1;
	}

	Debug( LDAP_DEBUG_ARGS,
		LDAP_XSTRING(mdb_db_open) ": \"%s\"\n",
		be->be_suffix[0].bv_val, 0, 0 );

	/* Check existence of dbenv_home. Any error means trouble */
	rc = stat( mdb->mi_dbenv_home, &stat1 );
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
			"cannot access database directory \"%s\" (%d).\n",
			be->be_suffix[0].bv_val, mdb->mi_dbenv_home, errno );
		return -1;
	}

	/* mdb is always clean */
	be->be_flags |= SLAP_DBFLAG_CLEAN;

	rc = mdb_env_create( &mdb->mi_dbenv );
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
			"mdb_env_create failed: %s (%d).\n",
			be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
		goto fail;
	}

	if ( mdb->mi_readers ) {
		rc = mdb_env_set_maxreaders( mdb->mi_dbenv, mdb->mi_readers );
		if( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY,
				LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
				"mdb_env_set_maxreaders failed: %s (%d).\n",
				be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
			goto fail;
		}
	}

	rc = mdb_env_set_mapsize( mdb->mi_dbenv, mdb->mi_mapsize );
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
			"mdb_env_set_mapsize failed: %s (%d).\n",
			be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
		goto fail;
	}

	rc = mdb_env_set_maxdbs( mdb->mi_dbenv, MDB_INDICES );
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
			"mdb_env_set_maxdbs failed: %s (%d).\n",
			be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
		goto fail;
	}

#ifdef HAVE_EBCDIC
	strcpy( path, mdb->mi_dbenv_home );
	__atoe( path );
	dbhome = path;
#else
	dbhome = mdb->mi_dbenv_home;
#endif

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(mdb_db_open) ": database \"%s\": "
		"dbenv_open(%s).\n",
		be->be_suffix[0].bv_val, mdb->mi_dbenv_home, 0);

	flags = mdb->mi_dbenv_flags;

	if ( slapMode & SLAP_TOOL_QUICK )
		flags |= MDB_NOSYNC|MDB_WRITEMAP;

	if ( slapMode & SLAP_TOOL_READONLY)
		flags |= MDB_RDONLY;

	rc = mdb_env_open( mdb->mi_dbenv, dbhome,
			flags, mdb->mi_dbenv_mode );

	if ( rc ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_db_open) ": database \"%s\" cannot be opened, err %d. "
			"Restore from backup!\n",
			be->be_suffix[0].bv_val, rc, 0 );
		goto fail;
	}

	rc = mdb_txn_begin( mdb->mi_dbenv, NULL, flags & MDB_RDONLY, &txn );
	if ( rc ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_db_open) ": database \"%s\" cannot be opened, err %d. "
			"Restore from backup!\n",
			be->be_suffix[0].bv_val, rc, 0 );
		goto fail;
	}

	/* open (and create) main databases */
	for( i = 0; mdmi_databases[i].bv_val; i++ ) {
		flags = MDB_INTEGERKEY;
		if( i == MDB_ID2ENTRY ) {
			if ( !(slapMode & (SLAP_TOOL_READMAIN|SLAP_TOOL_READONLY) ))
				flags |= MDB_CREATE;
		} else {
			if ( i == MDB_DN2ID )
				flags |= MDB_DUPSORT;
			if ( !(slapMode & SLAP_TOOL_READONLY) )
				flags |= MDB_CREATE;
		}

		rc = mdb_dbi_open( txn,
			mdmi_databases[i].bv_val,
			flags,
			&mdb->mi_dbis[i] );

		if ( rc != 0 ) {
			snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
				"mdb_dbi_open(%s/%s) failed: %s (%d).", 
				be->be_suffix[0].bv_val, 
				mdb->mi_dbenv_home, mdmi_databases[i].bv_val,
				mdb_strerror(rc), rc );
			Debug( LDAP_DEBUG_ANY,
				LDAP_XSTRING(mdb_db_open) ": %s\n",
				cr->msg, 0, 0 );
			goto fail;
		}

		if ( i == MDB_ID2ENTRY )
			mdb_set_compare( txn, mdb->mi_dbis[i], mdb_id_compare );
		else if ( i == MDB_DN2ID ) {
			MDB_cursor *mc;
			MDB_val key, data;
			ID id;
			mdb_set_dupsort( txn, mdb->mi_dbis[i], mdb_dup_compare );
			/* check for old dn2id format */
			rc = mdb_cursor_open( txn, mdb->mi_dbis[i], &mc );
			/* first record is always ID 0 */
			rc = mdb_cursor_get( mc, &key, &data, MDB_FIRST );
			if ( rc == 0 ) {
				rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT );
				if ( rc == 0 ) {
					int len;
					unsigned char *ptr;
					ptr = data.mv_data;
					len = (ptr[0] & 0x7f) << 8 | ptr[1];
					if (data.mv_size < 2*len + 4 + 2*sizeof(ID)) {
						snprintf( cr->msg, sizeof(cr->msg),
						"database \"%s\": DN index needs upgrade, "
						"run \"slapindex entryDN\".",
						be->be_suffix[0].bv_val );
						Debug( LDAP_DEBUG_ANY,
							LDAP_XSTRING(mdb_db_open) ": %s\n",
							cr->msg, 0, 0 );
						if ( !(slapMode & SLAP_TOOL_READMAIN ))
							rc = LDAP_OTHER;
						mdb->mi_flags |= MDB_NEED_UPGRADE;
					}
				}
			}
			mdb_cursor_close( mc );
			if ( rc == LDAP_OTHER )
				goto fail;
		}
	}

	rc = mdb_ad_read( mdb, txn );
	if ( rc ) {
		mdb_txn_abort( txn );
		goto fail;
	}

	rc = mdb_attr_dbs_open( be, txn, cr );
	if ( rc ) {
		mdb_txn_abort( txn );
		goto fail;
	}

	rc = mdb_txn_commit(txn);
	if ( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_db_open) ": database %s: "
			"txn_commit failed: %s (%d)\n",
			be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
		goto fail;
	}

	/* monitor setup */
	rc = mdb_monitor_db_open( be );
	if ( rc != 0 ) {
		goto fail;
	}

	mdb->mi_flags |= MDB_IS_OPEN;

	return 0;

fail:
	mdb_db_close( be, NULL );
	return rc;
}
예제 #30
0
int
ndb_back_modify( Operation *op, SlapReply *rs )
{
	struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
	Entry		e = {0};
	int		manageDSAit = get_manageDSAit( op );
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;

	int		num_retries = 0;

	NdbArgs NA;
	NdbRdns rdns;
	struct berval matched;

	LDAPControl **preread_ctrl = NULL;
	LDAPControl **postread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

	Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(ndb_back_modify) ": %s\n",
		op->o_req_dn.bv_val, 0, 0 );

	ctrls[num_ctrls] = NULL;

	slap_mods_opattrs( op, &op->orm_modlist, 1 );

	e.e_name = op->o_req_dn;
	e.e_nname = op->o_req_ndn;

	/* Get our NDB handle */
	rs->sr_err = ndb_thread_handle( op, &NA.ndb );
	rdns.nr_num = 0;
	NA.rdns = &rdns;
	NA.e = &e;

	if( 0 ) {
retry:	/* transaction retry */
		NA.txn->close();
		NA.txn = NULL;
		if( e.e_attrs ) {
			attrs_free( e.e_attrs );
			e.e_attrs = NULL;
		}
		Debug(LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_modify) ": retrying...\n", 0, 0, 0);
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			goto return_results;
		}
		if ( NA.ocs ) {
			ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
		}
		ndb_trans_backoff( ++num_retries );
	}
	NA.ocs = NULL;

	/* begin transaction */
	NA.txn = NA.ndb->startTransaction();
	rs->sr_text = NULL;
	if( !NA.txn ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_modify) ": startTransaction failed: %s (%d)\n",
			NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* get entry or ancestor */
	rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
	switch( rs->sr_err ) {
	case 0:
		break;
	case LDAP_NO_SUCH_OBJECT:
		Debug( LDAP_DEBUG_ARGS,
			"<=- ndb_back_modify: no such object %s\n",
			op->o_req_dn.bv_val, 0, 0 );
		rs->sr_matched = matched.bv_val;
		if (NA.ocs )
			ndb_check_referral( op, rs, &NA );
		goto return_results;
#if 0
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
#endif
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* acquire and lock entry */
	rs->sr_err = ndb_entry_get_data( op, &NA, 1 );

	if ( !manageDSAit && is_entry_referral( &e ) ) {
		/* entry is a referral, don't allow modify */
		rs->sr_ref = get_entry_referrals( op, &e );

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_modify) ": entry is referral\n",
			0, 0, 0 );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_matched = e.e_name.bv_val;
		rs->sr_flags = REP_REF_MUSTBEFREED;
		goto return_results;
	}

	if ( get_assert( op ) &&
		( test_filter( op, &e, (Filter*)get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	if( op->o_preread ) {
		if( preread_ctrl == NULL ) {
			preread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if ( slap_read_controls( op, rs, &e,
			&slap_pre_read_bv, preread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(ndb_back_modify) ": pre-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	/* Modify the entry */
	rs->sr_err = ndb_modify_internal( op, &NA, &rs->sr_text, textbuf, textlen );

	if( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_modify) ": modify failed (%d)\n",
			rs->sr_err, 0, 0 );
#if 0
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
#endif
		goto return_results;
	}

	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, &e,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(ndb_back_modify)
				": post-read failed!\n", 0, 0, 0 );
			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	if( op->o_noop ) {
		if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
			NdbOperation::AbortOnError, 1 )) != 0 ) {
			rs->sr_text = "txn_abort (no-op) failed";
		} else {
			rs->sr_err = LDAP_X_NO_OPERATION;
		}
	} else {
		if (( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
			NdbOperation::AbortOnError, 1 )) != 0 ) {
			rs->sr_text = "txn_commit failed";
		} else {
			rs->sr_err = LDAP_SUCCESS;
		}
	}

	if( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_modify) ": txn_%s failed: %s (%d)\n",
			op->o_noop ? "abort (no-op)" : "commit",
			NA.txn->getNdbError().message, NA.txn->getNdbError().code );
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}
	NA.txn->close();
	NA.txn = NULL;

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(ndb_back_modify) ": updated%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		e.e_id, op->o_req_dn.bv_val );

	rs->sr_err = LDAP_SUCCESS;
	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	if ( NA.ocs ) {
		ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
		NA.ocs = NULL;
	}

	if ( e.e_attrs != NULL ) {
		attrs_free( e.e_attrs );
		e.e_attrs = NULL;
	}

	if( NA.txn != NULL ) {
		NA.txn->execute( Rollback );
		NA.txn->close();
	}

	send_ldap_result( op, rs );
	slap_graduate_commit_csn( op );

	if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
		slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
	}
	if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
		slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
	}

	rs->sr_text = NULL;
	return rs->sr_err;
}