コード例 #1
0
ファイル: repl5_agmtlist.c プロジェクト: ohamada/389ds
static int
agmtlist_delete_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter,
	int *returncode, char *returntext, void *arg)
{
	Repl_Agmt *ra;
	Object *ro;

	slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_delete: begin\n");
	ro = objset_find(agmt_set, agmt_dn_cmp, (const void *)slapi_entry_get_sdn_const(e));
	ra = (NULL == ro) ? NULL : (Repl_Agmt *)object_get_data(ro);
	if (NULL == ra)
	{
		slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmtlist_delete: "
			"Tried to delete replication agreement \"%s\", but no such "
			"agreement was configured.\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)));
	}
	else
	{
		agmt_stop(ra);
		object_release(ro); /* Release ref acquired in objset_find */
		objset_remove_obj(agmt_set, ro); /* Releases a reference (should be final reference */
	}
	*returncode = LDAP_SUCCESS;
	return SLAPI_DSE_CALLBACK_OK;
}
コード例 #2
0
ファイル: plugin_acl.c プロジェクト: Firstyear/ds
int 
plugin_call_acl_mods_access ( Slapi_PBlock *pb, Slapi_Entry *e, LDAPMod **mods, char **errbuf )
{

	struct slapdplugin	*p;
	int			aclplugin_initialized = 0;
	int			rc = LDAP_INSUFFICIENT_ACCESS;
	Operation	*operation;

	slapi_pblock_get (pb, SLAPI_OPERATION, &operation);

	/* we don't perform acl check for internal operations  and if the plugin has set it not to be checked */
	if (operation_is_flag_set(operation, SLAPI_OP_FLAG_NO_ACCESS_CHECK|OP_FLAG_INTERNAL|OP_FLAG_REPLICATED|OP_FLAG_LEGACY_REPLICATION_DN))
		return LDAP_SUCCESS;
	
	/* call the global plugins first and then the backend specific */
	for ( p = get_plugin_list(PLUGIN_LIST_ACL); p != NULL; p = p->plg_next ) {
		if (plugin_invoke_plugin_sdn (p, SLAPI_PLUGIN_ACL_MODS_ALLOWED, pb, 
									  (Slapi_DN*)slapi_entry_get_sdn_const (e))){
			aclplugin_initialized = 1;
			rc = (*p->plg_acl_mods_allowed)( pb, e, mods, errbuf );
			if ( rc != LDAP_SUCCESS ) break;
		}
	}
	if (! aclplugin_initialized ) {
		rc = acl_default_access ( pb, e, SLAPI_ACL_WRITE);
	}
	return rc;
}
コード例 #3
0
ファイル: plugin_acl.c プロジェクト: Firstyear/ds
int
plugin_call_acl_verify_syntax ( Slapi_PBlock *pb, Slapi_Entry *e, char **errbuf )
{

	struct slapdplugin	*p;
	int			rc = 0;
	int			plugin_called = 0;
	Operation	*operation;

	slapi_pblock_get (pb, SLAPI_OPERATION, &operation);

	/* we don't perform acl check for internal operations  and if the plugin has set it not to be checked */
	if (operation_is_flag_set(operation, SLAPI_OP_FLAG_NO_ACCESS_CHECK|OP_FLAG_INTERNAL|OP_FLAG_REPLICATED|OP_FLAG_LEGACY_REPLICATION_DN))
		return LDAP_SUCCESS;

	/* call the global plugins first and then the backend specific */
	for ( p = get_plugin_list(PLUGIN_LIST_ACL); p != NULL; p = p->plg_next ) {
		if (plugin_invoke_plugin_sdn (p, SLAPI_PLUGIN_ACL_SYNTAX_CHECK, pb, 
									  (Slapi_DN*)slapi_entry_get_sdn_const (e))){
			plugin_called = 1;
			rc = (*p->plg_acl_syntax_check)( pb, e, errbuf );
			if ( rc != LDAP_SUCCESS ) break;
		}
	}

	if ( !plugin_called ) {
		slapi_log_err(SLAPI_LOG_ERR, "plugin_call_acl_verify_syntax",
			"The ACL plugin is not initialized. The aci syntax cannot be verified\n");
	}
	return rc;
}
コード例 #4
0
ファイル: urp.c プロジェクト: ohamada/389ds
/*
 * If an entry is deleted or renamed, a new winner may be
 * chosen from its naming competitors.
 * The entry with the smallest dncsn restores its original DN.
 */
static int
urp_naming_conflict_removal ( Slapi_PBlock *pb, char *sessionid, CSN *opcsn, const char *optype )
{
	Slapi_Entry *min_naming_conflict_entry;
	Slapi_RDN *oldrdn, *newrdn;
	const char *oldrdnstr, *newrdnstr;
	int op_result;

	/*
	 * Backend op has set SLAPI_URP_NAMING_COLLISION_DN to the basedn.
	 */
	min_naming_conflict_entry = urp_get_min_naming_conflict_entry (pb, sessionid, opcsn);
	if (min_naming_conflict_entry == NULL)
	{
		return 0;
	}

	/* Step 1: Restore the entry's original DN */

	oldrdn = slapi_rdn_new_sdn(slapi_entry_get_sdn_const(min_naming_conflict_entry));
	oldrdnstr = slapi_rdn_get_rdn ( oldrdn );

	/* newrdnstr is the old rdn of the entry minus the nsuniqueid part */
	newrdn = slapi_rdn_new_rdn ( oldrdn );
	slapi_rdn_remove_attr (newrdn, SLAPI_ATTR_UNIQUEID );
	newrdnstr = slapi_rdn_get_rdn ( newrdn );		

	/*
	 * Set OP_FLAG_ACTION_INVOKE_FOR_REPLOP since this operation
	 * is done after DB lock was released. The backend modrdn
	 * will acquire the DB lock if it sees this flag.
	 */
	op_result = urp_fixup_rename_entry((const Slapi_Entry *)min_naming_conflict_entry, newrdnstr, OP_FLAG_ACTION_INVOKE_FOR_REPLOP);
	if ( op_result != LDAP_SUCCESS )
	{
	    slapi_log_error (slapi_log_urp, sessionid,
			"Failed to restore RDN of %s, err=%d\n", oldrdnstr, op_result);
		goto bailout;
	}
	slapi_log_error (slapi_log_urp, sessionid,
		"Naming conflict removed by %s. RDN of %s was restored\n", optype, oldrdnstr);
			
	/* Step2: Remove ATTR_NSDS5_REPLCONFLICT from the winning entry */
	/*
	 * A fixup op will not invoke urp_modrdn_operation(). Even it does,
	 * urp_modrdn_operation() will do nothing because of the same CSN.
	 */
	op_result = del_replconflict_attr (min_naming_conflict_entry, opcsn, OP_FLAG_ACTION_INVOKE_FOR_REPLOP);
	if (op_result != LDAP_SUCCESS) {
		slapi_log_error(SLAPI_LOG_REPL, sessionid,
			"Failed to remove nsds5ReplConflict for %s, err=%d\n",
			newrdnstr, op_result);
	}

bailout:
	slapi_entry_free(min_naming_conflict_entry);
	slapi_rdn_free(&oldrdn);
	slapi_rdn_free(&newrdn);
	return op_result;
}
コード例 #5
0
ファイル: urp.c プロジェクト: ohamada/389ds
/* 
 * urp_annotate_dn:
 * Returns 0 on failure
 * Returns > 0 on success (1 on general conflict resolution success, LDAP_NO_SUCH_OBJECT on no-conflict success)
 *
 * Use this function to annotate an existing entry only. To annotate
 * a new entry (the operation entry) see urp_add_operation.
 */
static int
urp_annotate_dn (char *sessionid, const Slapi_Entry *entry, CSN *opcsn, const char *optype)
{
	int rc = 0; /* Fail */
	int op_result;
	char *newrdn;
	const char *uniqueid;
	const Slapi_DN *basesdn;
	const char *basedn;

	uniqueid = slapi_entry_get_uniqueid (entry);
	basesdn = slapi_entry_get_sdn_const (entry);
	basedn = slapi_entry_get_dn_const (entry);
	newrdn = get_rdn_plus_uniqueid ( sessionid, basedn, uniqueid );
	if(newrdn!=NULL)
	{
		mod_namingconflict_attr (uniqueid, basesdn, basesdn, opcsn);
		op_result = urp_fixup_rename_entry ( entry, newrdn, 0 );
		switch(op_result)
		{
		case LDAP_SUCCESS:
			slapi_log_error(slapi_log_urp, sessionid,
				"Naming conflict %s. Renamed existing entry to %s\n",
				optype, newrdn);
			rc = 1;
			break;
		case LDAP_NO_SUCH_OBJECT:
			/* This means that entry did not really exist!!!
			 * This is clearly indicating that there is a
			 * get_copy_of_entry -> dn2entry returned 
			 * an entry (entry) that was already removed
			 * from the ldbm database...
			 * This is bad, because it clearly indicates
			 * some kind of db or cache corruption. We need to print 
			 * this fact clearly in the errors log to try
			 * to solve this corruption one day.
			 * However, as far as the conflict is concerned,
			 * this error is completely harmless:
			 * if thew entry did not exist in the first place,
			 * there was never a room
			 * for a conflict!! After fix for 558293, this
			 * state can't be reproduced anymore (5-Oct-01)
			 */
			slapi_log_error( SLAPI_LOG_FATAL, sessionid,
				"Entry %s exists in cache but not in DB\n",
				basedn );
			rc = LDAP_NO_SUCH_OBJECT;
			break;
		default:
		    slapi_log_error( slapi_log_urp, sessionid,
				"Failed to annotate %s, err=%d\n", newrdn, op_result);
		}
		slapi_ch_free ( (void**)&newrdn );
	}
	return rc;
}
コード例 #6
0
ファイル: urp.c プロジェクト: ohamada/389ds
static int
del_replconflict_attr (const Slapi_Entry *entry, CSN *opcsn, int opflags)
{
	Slapi_Attr *attr;
	int op_result = 0;

	if (slapi_entry_attr_find (entry, ATTR_NSDS5_REPLCONFLICT, &attr) == 0)
	{
		Slapi_Mods smods;
		const char *uniqueid;
		const Slapi_DN *entrysdn;

		uniqueid = slapi_entry_get_uniqueid (entry);
		entrysdn = slapi_entry_get_sdn_const (entry);
		slapi_mods_init (&smods, 2);
		slapi_mods_add (&smods, LDAP_MOD_DELETE, ATTR_NSDS5_REPLCONFLICT, 0, NULL);
		op_result = urp_fixup_modify_entry (uniqueid, entrysdn, opcsn, &smods, opflags);
		slapi_mods_done (&smods);
	}
	return op_result;
}
コード例 #7
0
ファイル: urp.c プロジェクト: ohamada/389ds
int
urp_fixup_rename_entry (const Slapi_Entry *entry, const char *newrdn, int opflags)
{
	Slapi_PBlock *newpb;
    Slapi_Operation *op;
	CSN *opcsn;
	int op_result;

	newpb = slapi_pblock_new();

	/*
	 * Must mark this operation as replicated,
	 * so that the frontend doesn't add extra attributes.
	 */
	slapi_rename_internal_set_pb_ext (
					newpb,
					slapi_entry_get_sdn_const (entry),
					newrdn, /*NewRDN*/
					NULL, /*NewSuperior*/
					0, /* !Delete Old RDNS */
					NULL, /*Controls*/
					slapi_entry_get_uniqueid (entry), /*uniqueid*/
					repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
					OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | opflags);

    /* set operation csn to the entry's dncsn */
	opcsn = (CSN *)entry_get_dncsn (entry);
    slapi_pblock_get (newpb, SLAPI_OPERATION, &op);
    operation_set_csn (op, opcsn);

	slapi_modrdn_internal_pb(newpb); 
    slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);

	slapi_pblock_destroy(newpb);
	return op_result;
}
コード例 #8
0
ファイル: add.c プロジェクト: Firstyear/ds
/* This function is called to process operation that come over external connections */
void
do_add( Slapi_PBlock *pb )
{
	Slapi_Operation *operation;
	BerElement		*ber;
	char			*last;
	ber_len_t		len = LBER_ERROR;
	ber_tag_t		tag;
	Slapi_Entry		*e = NULL;
	int			err;
	int			rc;
	PRBool  searchsubentry=PR_TRUE;

	slapi_log_err(SLAPI_LOG_TRACE, "do_add", "==>\n");

	slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
    ber = operation->o_ber;

	/* count the add request */
	slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps);

	/*
	 * Parse the add request.  It looks like this:
	 *
	 *	AddRequest := [APPLICATION 14] SEQUENCE {
	 *		name	DistinguishedName,
	 *		attrs	SEQUENCE OF SEQUENCE {
	 *			type	AttributeType,
	 *			values	SET OF AttributeValue
	 *		}
	 *	}
	 */
	/* get the name */
	{
		char *rawdn = NULL;
		Slapi_DN mysdn;
		if ( ber_scanf( ber, "{a", &rawdn ) == LBER_ERROR ) {
			slapi_ch_free_string(&rawdn);
			slapi_log_err(SLAPI_LOG_ERR, "do_add",
				"ber_scanf failed (op=Add; params=DN)\n");
			op_shared_log_error_access (pb, "ADD", "???", "decoding error");
			send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
				"decoding error", 0, NULL );
			return;
		}
		/* Check if we should be performing strict validation. */
		if (config_get_dn_validate_strict()) {
			/* check that the dn is formatted correctly */
			rc = slapi_dn_syntax_check(pb, rawdn, 1);
			if (rc) { /* syntax check failed */
				op_shared_log_error_access(pb, "ADD", rawdn?rawdn:"",
										   "strict: invalid dn");
				send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, 
								 NULL, "invalid dn", 0, NULL);
				slapi_ch_free_string(&rawdn);
				return;
			}
		}
		slapi_sdn_init_dn_passin(&mysdn, rawdn);
		if (rawdn && (strlen(rawdn) > 0) &&
		    (NULL == slapi_sdn_get_dn(&mysdn))) {
			/* normalization failed */
			op_shared_log_error_access(pb, "ADD", rawdn, "invalid dn");
			send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL,
			                 "invalid dn", 0, NULL);
			slapi_sdn_done(&mysdn);
			return;
		}
		e = slapi_entry_alloc();
		/* Responsibility for DN is passed to the Entry. */
		slapi_entry_init_ext(e, &mysdn, NULL);
		slapi_sdn_done(&mysdn);
	}
	slapi_log_err(SLAPI_LOG_ARGS, "do_add", "dn (%s)\n", (char *)slapi_entry_get_dn_const(e));

	/* get the attrs */
	for ( tag = ber_first_element( ber, &len, &last );
	      tag != LBER_DEFAULT && tag != LBER_END_OF_SEQORSET;
	      tag = ber_next_element( ber, &len, last ) ) {
		char *type = NULL, *normtype = NULL;
		struct berval	**vals = NULL;
		len = -1; /* reset - not used in loop */
		if ( ber_scanf( ber, "{a{V}}", &type, &vals ) == LBER_ERROR ) {
			op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "decoding error");
			send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
			    "decoding error", 0, NULL );
            slapi_ch_free_string(&type);
            ber_bvecfree( vals );
			goto free_and_return;
		}

		if ( vals == NULL ) {
			slapi_log_err(SLAPI_LOG_ERR, "do_add - no values for type %s\n", type, 0, 0 );
			op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "null value");
			send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL,
			    0, NULL );
            slapi_ch_free_string(&type);
			goto free_and_return;
		}

		normtype = slapi_attr_syntax_normalize(type);
		if ( !normtype || !*normtype ) {
			char ebuf[SLAPI_DSE_RETURNTEXT_SIZE];
			rc = LDAP_INVALID_SYNTAX;
			slapi_create_errormsg(ebuf, sizeof(ebuf), "invalid type '%s'", type);
			op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), ebuf);
			send_ldap_result( pb, rc, NULL, ebuf, 0, NULL );
            slapi_ch_free_string(&type);
			slapi_ch_free( (void**)&normtype );
			ber_bvecfree( vals );
			goto free_and_return;
		}
		slapi_ch_free_string(&type);
	
       /* for now we just ignore attributes that client is not allowed
          to modify so not to break existing clients */
		if (op_shared_is_allowed_attr (normtype, pb->pb_conn->c_isreplication_session)){		
			if (( rc = slapi_entry_add_values( e, normtype, vals ))
				!= LDAP_SUCCESS ) {
				slapi_log_access( LDAP_DEBUG_STATS, 
					"conn=%" NSPRIu64 " op=%d ADD dn=\"%s\", add values for type %s failed\n",
					pb->pb_conn->c_connid, operation->o_opid,
					slapi_entry_get_dn_const(e), normtype );
				send_ldap_result( pb, rc, NULL, NULL, 0, NULL );

				slapi_ch_free( (void**)&normtype );
				ber_bvecfree( vals );
				goto free_and_return;
			}

			/* if this is uniqueid attribute, set uniqueid field of the entry */
			if (strcasecmp (normtype, SLAPI_ATTR_UNIQUEID) == 0)
			{
				e->e_uniqueid = slapi_ch_strdup (vals[0]->bv_val);
			}
			if(searchsubentry) searchsubentry=check_oc_subentry(e,vals,normtype);
		}

		slapi_ch_free( (void**)&normtype );
		ber_bvecfree( vals );
	}

	/* Ensure that created attributes are not used in the RDN. */
	if (check_rdn_for_created_attrs(e)) {
		op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)), "invalid DN");
		send_ldap_result( pb, LDAP_INVALID_DN_SYNTAX, NULL, "illegal attribute in RDN", 0, NULL );
		goto free_and_return;
	}

    /* len, is ber_len_t, which is uint. Can't be -1. May be better to remove (len != 0) check */
	if ( (tag != LBER_END_OF_SEQORSET) && (len != -1) ) {
		op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "decoding error");
		send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
		    "decoding error", 0, NULL );
		goto free_and_return;
	}

	/*
	 * in LDAPv3 there can be optional control extensions on
	 * the end of an LDAPMessage. we need to read them in and
	 * pass them to the backend.
	 */
	if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
		op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), 
								    "failed to decode LDAP controls");
		send_ldap_result( pb, err, NULL, NULL, 0, NULL );
		goto free_and_return;
	}

	slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &operation->o_isroot );
	slapi_pblock_set( pb, SLAPI_ADD_ENTRY, e );

        if (pb->pb_conn->c_flags & CONN_FLAG_IMPORT) {
            /* this add is actually part of a bulk import -- punt */
            handle_fast_add(pb, e);
        } else {
            op_shared_add ( pb );
        }

	/* make sure that we don't free entry if it is successfully added */
	e = NULL;

free_and_return:;
	if (e)
		slapi_entry_free (e);

}
コード例 #9
0
ファイル: add.c プロジェクト: Firstyear/ds
/* Code shared between regular and internal add operation */
static void op_shared_add (Slapi_PBlock *pb)
{
	Slapi_Operation *operation;
	Slapi_Entry	*e, *pse;
	Slapi_Backend *be = NULL;
	int	err;
	int internal_op, repl_op, legacy_op, lastmod;
	char *pwdtype = NULL;
	Slapi_Attr *attr = NULL;
	Slapi_Entry *referral;
	char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
	struct slapdplugin  *p = NULL;
	char *proxydn = NULL;
	char *proxystr = NULL;
	int proxy_err = LDAP_SUCCESS;
	char *errtext = NULL;
	Slapi_DN *sdn = NULL;
	passwdPolicy *pwpolicy;

	slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
	slapi_pblock_get (pb, SLAPI_ADD_ENTRY, &e);
	slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);	
	slapi_pblock_get (pb, SLAPI_IS_LEGACY_REPLICATED_OPERATION, &legacy_op);
	internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
	pwpolicy = new_passwdPolicy(pb, slapi_entry_get_dn(e));

	/* target spec is used to decide which plugins are applicable for the operation */
	operation_set_target_spec (operation, slapi_entry_get_sdn (e));

	if ((err = slapi_entry_add_rdn_values(e)) != LDAP_SUCCESS) 
	{
	  send_ldap_result(pb, err, NULL, "failed to add RDN values", 0, NULL);
	  goto done;
	}

	/* get the proxy auth dn if the proxy auth control is present */
	proxy_err = proxyauth_get_dn(pb, &proxydn, &errtext);

	if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
	{
		if (proxydn)
		{
			proxystr = slapi_ch_smprintf(" authzid=\"%s\"", proxydn);
		}

		if ( !internal_op )
		{
			slapi_log_access(LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d ADD dn=\"%s\"%s\n",
							 pb->pb_conn->c_connid,
							 operation->o_opid,
							 slapi_entry_get_dn_const(e),
							 proxystr ? proxystr : "");
		}
		else
		{
			slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d ADD dn=\"%s\"\n",
							 LOG_INTERNAL_OP_CON_ID,
							 LOG_INTERNAL_OP_OP_ID,
							 slapi_entry_get_dn_const(e));
		}
	}

	/* If we encountered an error parsing the proxy control, return an error
	 * to the client.  We do this here to ensure that we log the operation first. */
	if (proxy_err != LDAP_SUCCESS)
	{
		send_ldap_result(pb, proxy_err, NULL, errtext, 0, NULL);
		goto done;
	}

	/*
	 * We could be serving multiple database backends.  Select the
	 * appropriate one.
	 */
	if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf, sizeof(errorbuf))) != LDAP_SUCCESS) {
		send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
		be = NULL;
		goto done;
	}

	if (referral)
	{
		int managedsait;

		slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
		if (managedsait)
		{
			send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
							 "cannot update referral", 0, NULL);
			slapi_entry_free(referral);
			goto done;
		}
	
		slapi_pblock_set(pb, SLAPI_TARGET_SDN, (void*)operation_get_target_spec (operation));
		send_referrals_from_entry(pb,referral);
		slapi_entry_free(referral);
		goto done;
	}

	if (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)) {
		Slapi_Value **unhashed_password_vals = NULL;
		Slapi_Value **present_values = NULL;

		/* Setting unhashed password to the entry extension. */
		if (repl_op) {
			/* replicated add ==> get unhashed pw from entry, if any.
			 * set it to the extension */
			slapi_entry_attr_find(e, PSEUDO_ATTR_UNHASHEDUSERPASSWORD, &attr);
			if (attr) {
				present_values = attr_get_present_values(attr);
				valuearray_add_valuearray(&unhashed_password_vals,
				                          present_values, 0);
#if !defined(USE_OLD_UNHASHED)
			 	/* and remove it from the entry. */
				slapi_entry_attr_delete(e, PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
#endif
			}
		} else {
			/* ordinary add ==>
			 * get unhashed pw from userpassword before encrypting it */
			/* look for user password attribute */
			slapi_entry_attr_find(e, SLAPI_USERPWD_ATTR, &attr);
			if (attr) {
				Slapi_Value **vals = NULL;

				/* Set the backend in the pblock. 
				 * The slapi_access_allowed function
				 * needs this set to work properly. */
				slapi_pblock_set(pb, SLAPI_BACKEND,
				                 slapi_be_select(slapi_entry_get_sdn_const(e)));

				/* Check ACI before checking password syntax */
				if ((err = slapi_access_allowed(pb, e, SLAPI_USERPWD_ATTR, NULL,
				                              SLAPI_ACL_ADD)) != LDAP_SUCCESS) {
					send_ldap_result(pb, err, NULL,
					                 "Insufficient 'add' privilege to the "
					                 "'userPassword' attribute", 0, NULL);
					goto done;
				}

				/*
				 * Check password syntax, unless this is a pwd admin/rootDN
				 */
				present_values = attr_get_present_values(attr);
				if (!pw_is_pwp_admin(pb, pwpolicy) &&
				    check_pw_syntax(pb, slapi_entry_get_sdn_const(e),
				                    present_values, NULL, e, 0) != 0) {
					/* error result is sent from check_pw_syntax */
					goto done;
				}
				/* pw syntax is valid */
				valuearray_add_valuearray(&unhashed_password_vals,
				                          present_values, 0);
				valuearray_add_valuearray(&vals, present_values, 0);
				pw_encodevals_ext(pb, slapi_entry_get_sdn (e), vals);
				add_password_attrs(pb, operation, e);
				slapi_entry_attr_replace_sv(e, SLAPI_USERPWD_ATTR, vals);
				valuearray_free(&vals);
#if defined(USE_OLD_UNHASHED)
				/* Add the unhashed password pseudo-attribute to the entry */
				pwdtype = 
				  slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
				slapi_entry_add_values_sv(e, pwdtype, unhashed_password_vals);
#endif
			}
		}
		if (unhashed_password_vals &&
		    (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch())) {
			/* unhashed_password_vals is consumed if successful. */
			err = slapi_pw_set_entry_ext(e, unhashed_password_vals,
			                             SLAPI_EXT_SET_ADD);
			if (err) {
				valuearray_free(&unhashed_password_vals);
			}
		}

#if defined(THISISTEST)
		{
			/* test code to retrieve an unhashed pw from the entry extention &
			 * PSEUDO_ATTR_UNHASHEDUSERPASSWORD attribute */
			char *test_str = slapi_get_first_clear_text_pw(e);
			if (test_str) {
				slapi_log_err(SLAPI_LOG_ERR,
				              "Value from extension: %s\n", test_str);
				slapi_ch_free_string(&test_str);
			}
#if defined(USE_OLD_UNHASHED)
			test_str = slapi_entry_attr_get_charptr(e,
			                                  PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
			if (test_str) {
				slapi_log_err(SLAPI_LOG_ERR,
				              "Value from attr: %s\n", test_str);
				slapi_ch_free_string(&test_str);
			}
#endif /* USE_OLD_UNHASHED */
		}
#endif /* THISISTEST */

        /* look for multiple backend local credentials or replication local credentials */
        for ( p = get_plugin_list(PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME); p != NULL && !repl_op;
            p = p->plg_next )
        {
            char *L_attr = NULL;
            int i=0;

            /* Get the appropriate decoding function */
            for ( L_attr = p->plg_argv[i]; i<p->plg_argc; L_attr = p->plg_argv[++i])
            {
                /* look for multiple backend local credentials or replication local credentials */
                char *L_normalized = slapi_attr_syntax_normalize(L_attr);
                slapi_entry_attr_find(e, L_normalized, &attr);
                if (attr)
                {
                    Slapi_Value **present_values = NULL;
                    Slapi_Value **vals = NULL;

                    present_values= attr_get_present_values(attr);

                    valuearray_add_valuearray(&vals, present_values, 0);
                    pw_rever_encode(vals, L_normalized);
                    slapi_entry_attr_replace_sv(e, L_normalized, vals);
                    valuearray_free(&vals);
                }
                if (L_normalized)
                    slapi_ch_free ((void**)&L_normalized);
            }
        }
    }

	slapi_pblock_set(pb, SLAPI_BACKEND, be);

	if (!repl_op)
	{
		/* can get lastmod only after backend is selected */
		slapi_pblock_get(pb, SLAPI_BE_LASTMOD, &lastmod);

		if (lastmod && add_created_attrs(pb, e) != 0)
		{
			send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
				"cannot insert computed attributes", 0, NULL);
			goto done;
		}
		/* expand objectClass values to reflect the inheritance hierarchy */
		slapi_schema_expand_objectclasses( e );
	}

    /* uniqueid needs to be generated for entries added during legacy replication */
    if (legacy_op){
    	if (add_uniqueid(e) != UID_SUCCESS)
    	{
    		send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
    				"cannot insert computed attributes", 0, NULL);
    		goto done;
    	}
    }

	/*
	 * call the pre-add plugins. if they succeed, call
	 * the backend add function. then call the post-add
	 * plugins.
	 */
	
	sdn = slapi_sdn_dup(slapi_entry_get_sdn_const(e));
	slapi_pblock_set(pb, SLAPI_ADD_TARGET_SDN, (void *)sdn);
	if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN :
	                        SLAPI_PLUGIN_PRE_ADD_FN) == SLAPI_PLUGIN_SUCCESS)
	{
		int	rc;
		Slapi_Entry	*ec;
		Slapi_DN *add_target_sdn = NULL;
		Slapi_Entry *save_e = NULL;

		slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
		set_db_default_result_handlers(pb);
		/* because be_add frees the entry */
		ec = slapi_entry_dup(e);
		add_target_sdn = slapi_sdn_dup(slapi_entry_get_sdn_const(ec));
		slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn);
		slapi_sdn_free(&sdn);
		slapi_pblock_set(pb, SLAPI_ADD_TARGET_SDN, add_target_sdn);
		
		if (be->be_add != NULL)
		{
			rc = (*be->be_add)(pb);
			/* backend may change this if errors and not consumed */
			slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &save_e);
			slapi_pblock_set(pb, SLAPI_ADD_ENTRY, ec);
			if (rc == 0)
			{
				/* acl is not enabled for internal operations */
				/* don't update aci store for remote acis     */
				if ((!internal_op) && 
					(!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
				{
					plugin_call_acl_mods_update (pb, SLAPI_OPERATION_ADD);
				}

				if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
				{ 
					write_audit_log_entry(pb); /* Record the operation in the audit log */
				}

				slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
				do_ps_service(pse, NULL, LDAP_CHANGETYPE_ADD, 0);
				/* 
				 * If be_add succeeded, then e is consumed except the resurrect case.
				 * If it is resurrect, the corresponding tombstone entry is resurrected
				 * and put into the cache.
				 * Otherwise, we set e to NULL to prevent freeing it ourselves.
				 */
				if (operation_is_flag_set(operation,OP_FLAG_RESURECT_ENTRY) && save_e) {
					e = save_e;
				} else {
					e = NULL;
				}
			}
			else
			{
				/* PR_ASSERT(!save_e); save_e is supposed to be freed in the backend.  */
				e = save_e;
				if (rc == SLAPI_FAIL_DISKFULL)
				{
					operation_out_of_disk_space();
					goto done;
				}
				/* If the disk is full we don't want to make it worse ... */
				if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
				{ 
					write_auditfail_log_entry(pb); /* Record the operation in the audit log */
				}
			}
		}
		else
		{
			send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
							 "Function not implemented", 0, NULL);
		}
		slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
		plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_ADD_FN : 
							SLAPI_PLUGIN_POST_ADD_FN);
		slapi_entry_free(ec);
	}
	slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn);
	slapi_sdn_free(&sdn);

done:
	if (be)
		slapi_be_Unlock(be);
	slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
	slapi_entry_free(pse);
	slapi_ch_free((void **)&operation->o_params.p.p_add.parentuniqueid);
	slapi_entry_free(e);
	slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL);
	slapi_ch_free((void**)&pwdtype);
	slapi_ch_free_string(&proxydn);
	slapi_ch_free_string(&proxystr);
}
コード例 #10
0
ファイル: config.c プロジェクト: leto/389-ds
/*
  Extract just the configuration information we need for bootstrapping
  purposes
  1) set up error logging
  2) disable syntax checking
  3) load the syntax plugins
  etc.
*/
int
slapd_bootstrap_config(const char *configdir)
{
	char configfile[MAXPATHLEN+1];
    PRFileInfo prfinfo;
    int rc = 0; /* Fail */
	int done = 0;
    PRInt32 nr = 0;
	PRFileDesc *prfd = 0;
	char *buf = 0;
	char *lastp = 0;
	char *entrystr = 0;

	if (NULL == configdir) {
		slapi_log_error(SLAPI_LOG_FATAL,
						"startup", "Passed null config directory\n");
		return rc; /* Fail */
	}
	PR_snprintf(configfile, sizeof(configfile), "%s/%s", configdir,
				CONFIG_FILENAME);
	if ( (rc = PR_GetFileInfo( configfile, &prfinfo )) != PR_SUCCESS )
	{
		/* the "real" file does not exist; see if there is a tmpfile */
		char tmpfile[MAXPATHLEN+1];
		slapi_log_error(SLAPI_LOG_FATAL, "config",
					"The configuration file %s does not exist\n", configfile);
		PR_snprintf(tmpfile, sizeof(tmpfile), "%s/%s.tmp", configdir,
					CONFIG_FILENAME);
		if ( PR_GetFileInfo( tmpfile, &prfinfo ) == PR_SUCCESS ) {
			rc = PR_Rename(tmpfile, configfile);
			if (rc == PR_SUCCESS) {
				slapi_log_error(SLAPI_LOG_FATAL, "config",
								"The configuration file %s was restored from backup %s\n",
								configfile, tmpfile);
			} else {
				slapi_log_error(SLAPI_LOG_FATAL, "config",
								"The configuration file %s was not restored from backup %s, error %d\n",
								configfile, tmpfile, rc);
				return rc; /* Fail */
			}
		} else {
			slapi_log_error(SLAPI_LOG_FATAL, "config",
				"The backup configuration file %s does not exist, either.\n",
				tmpfile);
			return rc; /* Fail */
		}
	}
	if ( (rc = PR_GetFileInfo( configfile, &prfinfo )) != PR_SUCCESS )
	{
		PRErrorCode prerr = PR_GetError();
		slapi_log_error(SLAPI_LOG_FATAL, "config", "The given config file %s could not be accessed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
						configfile, prerr, slapd_pr_strerror(prerr));
		return rc;
	}
	else if (( prfd = PR_Open( configfile, PR_RDONLY,
							   SLAPD_DEFAULT_FILE_MODE )) == NULL )
	{
		PRErrorCode prerr = PR_GetError();
		slapi_log_error(SLAPI_LOG_FATAL, "config", "The given config file %s could not be opened for reading, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
						configfile, prerr, slapd_pr_strerror(prerr));
		return rc; /* Fail */
	}
	else
	{
		/* read the entire file into core */
		buf = slapi_ch_malloc( prfinfo.size + 1 );
		if (( nr = slapi_read_buffer( prfd, buf, prfinfo.size )) < 0 )
		{
			slapi_log_error(SLAPI_LOG_FATAL, "config", "Could only read %d of %d bytes from config file %s\n",
							nr, prfinfo.size, configfile);
			rc = 0; /* Fail */
			done= 1;
		}
                          
		(void)PR_Close(prfd);
		buf[ nr ] = '\0';

		if(!done)
		{
			char workpath[MAXPATHLEN+1];
			char loglevel[BUFSIZ];
			char maxdescriptors[BUFSIZ];
			char val[BUFSIZ];
			char _localuser[BUFSIZ];
			char logenabled[BUFSIZ];
			char schemacheck[BUFSIZ];
			char syntaxcheck[BUFSIZ];
			char syntaxlogging[BUFSIZ];
			char plugintracking[BUFSIZ];
			char dn_validate_strict[BUFSIZ];
			Slapi_DN plug_dn;

			workpath[0] = loglevel[0] = maxdescriptors[0] = '\0';
			val[0] = logenabled[0] = schemacheck[0] = syntaxcheck[0] = '\0';
			syntaxlogging[0] = _localuser[0] = '\0';
			plugintracking [0] = dn_validate_strict[0] = '\0';

			/* Convert LDIF to entry structures */
			slapi_sdn_init_ndn_byref(&plug_dn, PLUGIN_BASE_DN);
			while ((entrystr = dse_read_next_entry(buf, &lastp)) != NULL)
			{
				char errorbuf[BUFSIZ];
				/*
				 * XXXmcs: it would be better to also pass
				 * SLAPI_STR2ENTRY_REMOVEDUPVALS in the flags, but
				 * duplicate value checking requires that the syntax
				 * and schema subsystems be initialized... and they
				 * are not yet.
				 */
				Slapi_Entry	*e = slapi_str2entry(entrystr,
							SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF);
				if (e == NULL)
				{
					  LDAPDebug(LDAP_DEBUG_ANY, "The entry [%s] in the configfile %s was empty or could not be parsed\n",
								entrystr, configfile, 0);
					continue;
				}
				/* increase file descriptors */
#if !defined(_WIN32) && !defined(AIX)
				if (!maxdescriptors[0] &&
					entry_has_attr_and_value(e, CONFIG_MAXDESCRIPTORS_ATTRIBUTE,
									 maxdescriptors, sizeof(maxdescriptors)))
				{
					if (config_set_maxdescriptors(
									CONFIG_MAXDESCRIPTORS_ATTRIBUTE,
									maxdescriptors, errorbuf, CONFIG_APPLY)
						!= LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								  CONFIG_MAXDESCRIPTORS_ATTRIBUTE, errorbuf);
					}
				}
#endif /* !defined(_WIN32) && !defined(AIX) */

				/* see if we need to enable error logging */
				if (!logenabled[0] &&
					entry_has_attr_and_value(e,
											 CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE,
											 logenabled, sizeof(logenabled)))
				{
					if (log_set_logging(
						CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE,
						logenabled, SLAPD_ERROR_LOG, errorbuf, CONFIG_APPLY)
						!= LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								  CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE, errorbuf);
					}
				}

#ifndef _WIN32
				/* set the local user name; needed to set up error log */
				if (!_localuser[0] &&
					entry_has_attr_and_value(e, CONFIG_LOCALUSER_ATTRIBUTE,
								_localuser, sizeof(_localuser)))
				{
					if (config_set_localuser(CONFIG_LOCALUSER_ATTRIBUTE,
						_localuser, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile,
								  CONFIG_LOCALUSER_ATTRIBUTE, errorbuf);
					}
				}
#endif
				
				/* set the log file name */
				workpath[0] = '\0';
				if (!workpath[0] &&
					entry_has_attr_and_value(e, CONFIG_ERRORLOG_ATTRIBUTE,
								workpath, sizeof(workpath)))
				{
					if (config_set_errorlog(CONFIG_ERRORLOG_ATTRIBUTE,
						workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile,
								  CONFIG_ERRORLOG_ATTRIBUTE, errorbuf);
					}
				}
				/* set the error log level */
				if (!loglevel[0] &&
					entry_has_attr_and_value(e, CONFIG_LOGLEVEL_ATTRIBUTE,
						loglevel, sizeof(loglevel)))
				{
					if (should_detach || !config_get_errorlog_level())
					{ /* -d wasn't on command line */
						if (config_set_errorlog_level(CONFIG_LOGLEVEL_ATTRIBUTE,
							loglevel, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
						{
							LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile,
									  CONFIG_LOGLEVEL_ATTRIBUTE, errorbuf);
						}
					}
					else
					{
						LDAPDebug(LDAP_DEBUG_ANY,
								  "%s: ignoring %s (since -d %d was given on "
								  "the command line)\n",
								  CONFIG_LOGLEVEL_ATTRIBUTE, loglevel,
								  config_get_errorlog_level());
					}
				}

				/* set the cert dir; needed in slapd_nss_init */
				workpath[0] = '\0';
				if (entry_has_attr_and_value(e, CONFIG_CERTDIR_ATTRIBUTE,
						workpath, sizeof(workpath)))
				{
					if (config_set_certdir(CONFIG_CERTDIR_ATTRIBUTE,
							workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile,
									  CONFIG_CERTDIR_ATTRIBUTE, errorbuf);
					}
				}

				/* set the sasl path; needed in main */
				 workpath[0] = '\0';
				if (entry_has_attr_and_value(e, CONFIG_SASLPATH_ATTRIBUTE,
						workpath, sizeof(workpath)))
				{
					if (config_set_saslpath(CONFIG_SASLPATH_ATTRIBUTE,
							workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile,
									  CONFIG_SASLPATH_ATTRIBUTE, errorbuf);
					}
				}
#if defined(ENABLE_LDAPI)
				/* set the ldapi file path; needed in main */
				workpath[0] = '\0';
				if (entry_has_attr_and_value(e, CONFIG_LDAPI_FILENAME_ATTRIBUTE,
						workpath, sizeof(workpath)))
				{
					if (config_set_ldapi_filename(CONFIG_LDAPI_FILENAME_ATTRIBUTE,
							workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile,
									  CONFIG_LDAPI_FILENAME_ATTRIBUTE, errorbuf);
					}
				}

				/* set the ldapi switch; needed in main */
				workpath[0] = '\0';
				if (entry_has_attr_and_value(e, CONFIG_LDAPI_SWITCH_ATTRIBUTE,
						workpath, sizeof(workpath)))
				{
					if (config_set_ldapi_switch(CONFIG_LDAPI_SWITCH_ATTRIBUTE,
							workpath, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile,
									  CONFIG_LDAPI_SWITCH_ATTRIBUTE, errorbuf);
					}
				}
#endif
				/* see if the entry is a child of the plugin base dn */
				if (slapi_sdn_isparent(&plug_dn,
									   slapi_entry_get_sdn_const(e)))
				{
					if (entry_has_attr_and_value(e, "objectclass",
												 "nsSlapdPlugin", 0) &&
						(entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE,
												 "syntax", 0) ||
						 entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE,
												  "matchingrule", 0)))
					{
						/* add the syntax/matching scheme rule plugin */
						if (plugin_setup(e, 0, 0, 1))
						{
							LDAPDebug(LDAP_DEBUG_ANY, "The plugin entry [%s] in the configfile %s was invalid\n", slapi_entry_get_dn(e), configfile, 0);
							rc = 0;
							slapi_sdn_done(&plug_dn);
							goto bail;
						}
					}
				}

				/* see if the entry is a grand child of the plugin base dn */
				if (slapi_sdn_isgrandparent(&plug_dn,
											slapi_entry_get_sdn_const(e)))
				{
					if (entry_has_attr_and_value(e, "objectclass",
												 "nsSlapdPlugin", 0) &&
						(	entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE,
												"pwdstoragescheme", 0) ||
							entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE,
												"reverpwdstoragescheme", 0)	) )
					{
						/* add the pwd storage scheme rule plugin */
						if (plugin_setup(e, 0, 0, 1))
						{
							LDAPDebug(LDAP_DEBUG_ANY, "The plugin entry [%s] in the configfile %s was invalid\n", slapi_entry_get_dn(e), configfile, 0);
							rc = 0;
							slapi_sdn_done(&plug_dn);
							goto bail;
						}
					}
				}

				/* see if we need to disable schema checking */
				if (!schemacheck[0] &&
					entry_has_attr_and_value(e, CONFIG_SCHEMACHECK_ATTRIBUTE,
											 schemacheck, sizeof(schemacheck)))
				{
					if (config_set_schemacheck(CONFIG_SCHEMACHECK_ATTRIBUTE,
								schemacheck, errorbuf, CONFIG_APPLY)
								!= LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								  CONFIG_SCHEMACHECK_ATTRIBUTE, errorbuf);
					}
				}

				/* see if we need to enable plugin binddn tracking */
				if (!plugintracking[0] &&
					entry_has_attr_and_value(e, CONFIG_PLUGIN_BINDDN_TRACKING_ATTRIBUTE,
											 plugintracking, sizeof(plugintracking)))
				{
					if (config_set_plugin_tracking(CONFIG_PLUGIN_BINDDN_TRACKING_ATTRIBUTE,
							plugintracking, errorbuf, CONFIG_APPLY)
								!= LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								CONFIG_PLUGIN_BINDDN_TRACKING_ATTRIBUTE, errorbuf);
					}
				}

				/* see if we need to enable syntax checking */
				if (!syntaxcheck[0] &&
				    entry_has_attr_and_value(e, CONFIG_SYNTAXCHECK_ATTRIBUTE,
				    syntaxcheck, sizeof(syntaxcheck)))
				{
					if (config_set_syntaxcheck(CONFIG_SYNTAXCHECK_ATTRIBUTE,
					                           syntaxcheck, errorbuf, CONFIG_APPLY)
						                   != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
						          CONFIG_SYNTAXCHECK_ATTRIBUTE, errorbuf);
					}
				}

				/* see if we need to enable syntax warnings */
				if (!syntaxlogging[0] &&
				    entry_has_attr_and_value(e, CONFIG_SYNTAXLOGGING_ATTRIBUTE,
				    syntaxlogging, sizeof(syntaxlogging)))
				{
					if (config_set_syntaxlogging(CONFIG_SYNTAXLOGGING_ATTRIBUTE,
					                          syntaxlogging, errorbuf, CONFIG_APPLY)
					                          != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
						          CONFIG_SYNTAXLOGGING_ATTRIBUTE, errorbuf);
					}
				}

				/* see if we need to enable strict dn validation */
				if (!dn_validate_strict[0] &&
				    entry_has_attr_and_value(e, CONFIG_DN_VALIDATE_STRICT_ATTRIBUTE,
				    dn_validate_strict, sizeof(dn_validate_strict)))
				{
					if (config_set_dn_validate_strict(CONFIG_DN_VALIDATE_STRICT_ATTRIBUTE,
					                           dn_validate_strict, errorbuf, CONFIG_APPLY)
					                           != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
						          CONFIG_DN_VALIDATE_STRICT_ATTRIBUTE, errorbuf);
					}
				}

				/* see if we need to expect quoted schema values */
				if (entry_has_attr_and_value(e, CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE,
											 val, sizeof(val)))
				{
					if (config_set_enquote_sup_oc(
								CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, val, errorbuf, 
								CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								  CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, errorbuf);
					}
					val[0] = 0;
				}

				/* see if we need to maintain case in AT and OC names */
				if (entry_has_attr_and_value(e,
						CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, val, sizeof(val)))
				{
					if (config_set_return_exact_case(
								CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, val,
								errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								  CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, errorbuf);
					}
					val[0] = 0;
				}

				/* see if we should allow attr. name exceptions, e.g. '_'s */
				if (entry_has_attr_and_value(e,
						CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE,
						val, sizeof(val)))
				{
					if (config_set_attrname_exceptions(
								CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE, val,
								errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								  CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE,
								  errorbuf);
					}
					val[0] = 0;
				}

				/* see if we need to maintain schema compatibility with 4.x */
				if (entry_has_attr_and_value(e,
						CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE, val, sizeof(val)))
				{
					if (config_set_ds4_compatible_schema(
								CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE, val,
								errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								  CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE,
								  errorbuf);
					}
					val[0] = 0;
				}

				/* see if we need to allow trailing spaces in OC and AT names */
				if (entry_has_attr_and_value(e,
						CONFIG_SCHEMA_IGNORE_TRAILING_SPACES, val, sizeof(val)))
				{
					if (config_set_schema_ignore_trailing_spaces(
								CONFIG_SCHEMA_IGNORE_TRAILING_SPACES, val,
								errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								  CONFIG_SCHEMA_IGNORE_TRAILING_SPACES,
								  errorbuf);
					}
					val[0] = 0;
				}

				/* rfc1274-rewrite */
				if (entry_has_attr_and_value(e, 
							     CONFIG_REWRITE_RFC1274_ATTRIBUTE,
							     val, sizeof(val))) {
				  if (config_set_rewrite_rfc1274(
								 CONFIG_REWRITE_RFC1274_ATTRIBUTE, val, 
								 errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) {
				    LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", 
					      configfile,
					      CONFIG_REWRITE_RFC1274_ATTRIBUTE, 
					      errorbuf);
				  }
				  val[0] = 0;
				}

				/* what is our localhost name */
				if (entry_has_attr_and_value(e, CONFIG_LOCALHOST_ATTRIBUTE,
											 val, sizeof(val)))
				{
					if (config_set_localhost(
								CONFIG_LOCALHOST_ATTRIBUTE, val, errorbuf, 
								CONFIG_APPLY) != LDAP_SUCCESS)
					{
						LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
								  CONFIG_LOCALHOST_ATTRIBUTE, errorbuf);
					}
					val[0] = 0;
				}

				if (e)
					slapi_entry_free(e);
			}
			/* kexcoff: initialize rootpwstoragescheme and pw_storagescheme
			 *			if not explicilty set in the config file
			 */
			if ( config_set_storagescheme() ) {		/* default scheme plugin not loaded */
				slapi_log_error(SLAPI_LOG_FATAL, "startup",
								"The default password storage scheme SSHA could not be read or was not found in the file %s. It is mandatory.\n",
								configfile);
				exit (1);
			}
			else {
				slapi_sdn_done(&plug_dn);
				rc= 1; /* OK */
			}
		}

		slapi_ch_free_string(&buf);
	}

bail:
	slapi_ch_free_string(&buf);
	return rc;
}
コード例 #11
0
ファイル: urp.c プロジェクト: ohamada/389ds
static int
urp_add_resolve_parententry (Slapi_PBlock *pb, char *sessionid, Slapi_Entry *entry, Slapi_Entry *parententry, CSN *opcsn)
{
	Slapi_DN *parentdn = NULL;
	Slapi_RDN *add_rdn = NULL;
	char *newdn = NULL;
	int ldap_rc;
	int rc = 0;
	Slapi_DN *sdn = NULL;

	if( is_suffix_entry (pb, entry, &parentdn) )
	{
		/* It's OK for the suffix entry's parent to be absent */ 
		rc= 0;
		PROFILE_POINT; /* Add Conflict; Suffix Entry */
		goto bailout;
	}

	/* The entry is not a suffix. */
	if(parententry==NULL) /* The parent entry was not found. */
	{
		/* Create a glue entry to stand in for the absent parent */
		slapi_operation_parameters *op_params;
		slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
		ldap_rc = create_glue_entry (pb, sessionid, parentdn, op_params->p.p_add.parentuniqueid, opcsn);
		if ( LDAP_SUCCESS == ldap_rc )
		{
			/* The backend code should now search for the parent again. */
			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY);
			PROFILE_POINT; /* Add Conflict; Orphaned Entry; Glue Parent */
		}
		else
		{
			/*
			 * Error. The parent can't be created as a glue entry.
			 * This will cause replication divergence and will
			 * require admin intercession
			 */
			ldap_rc= LDAP_OPERATIONS_ERROR;
			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_rc);
			rc= -1; /* Abort this Operation */
			PROFILE_POINT; /* Add Conflict; Orphaned Entry; Impossible to create parent; Refuse Change. */
		}
		goto bailout;
	}

	if(is_tombstone_entry(parententry)) /* The parent is a tombstone */
	{
		/* The parent entry must be resurected from the dead. */
		ldap_rc = tombstone_to_glue (pb, sessionid, parententry, parentdn, REASON_RESURRECT_ENTRY, opcsn);
		if ( ldap_rc != LDAP_SUCCESS )
		{
			ldap_rc= LDAP_OPERATIONS_ERROR;
			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_rc);
			rc = -1; /* Abort the operation */
		}
		else
		{
			/* The backend add code should now search for the parent again. */
			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY);
		}
		PROFILE_POINT; /* Add Conflict; Orphaned Entry; Parent Was Tombstone */
		goto bailout;
	}

	/* The parent is healthy */
	/* Now we need to check that the parent has the correct DN */
	if (slapi_sdn_isparent(slapi_entry_get_sdn(parententry), slapi_entry_get_sdn(entry)))
	{
		rc= 0; /* OK, Add the entry */
		PROFILE_POINT; /* Add Conflict; Parent Exists */
		goto bailout;
	}

	/* 
	 * Parent entry doesn't have a DN parent to the entry.
	 * This can happen if parententry was renamed due to
	 * conflict and the child entry was created before
	 * replication occured. See defect 530942.
	 * We need to rename the entry to be child of its parent.
	 */
	add_rdn = slapi_rdn_new_dn(slapi_entry_get_dn_const (entry));
	newdn = slapi_dn_plus_rdn(slapi_entry_get_dn_const (parententry), slapi_rdn_get_rdn(add_rdn));
	slapi_entry_set_normdn ( entry, newdn );

	/* slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn); */
	slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn);
	slapi_sdn_free(&sdn);

	sdn = slapi_sdn_dup(slapi_entry_get_sdn_const(entry));
	slapi_pblock_set(pb, SLAPI_ADD_TARGET_SDN, sdn);

	slapi_log_error ( slapi_log_urp, sessionid,
			"Parent was renamed. Renamed the child to %s\n", newdn );
	rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
	PROFILE_POINT; /* Add Conflict; Parent Renamed; Rename Operation Entry */

bailout:
	if (parentdn)
		slapi_sdn_free(&parentdn);
	slapi_rdn_free(&add_rdn);
	return rc;
}
コード例 #12
0
ファイル: urp.c プロジェクト: ohamada/389ds
/*
 * Return 0 for OK, -1 for Error, >0 for action code
 * Action Code Bit 0: Fetch existing entry.
 * Action Code Bit 1: Fetch parent entry.
 */
int
urp_modrdn_operation( Slapi_PBlock *pb )
{
	slapi_operation_parameters *op_params = NULL;
	Slapi_Entry *parent_entry;
	Slapi_Entry *new_parent_entry;
	Slapi_DN *newsuperior = NULL;
	Slapi_DN *parentdn = NULL;
	const Slapi_Entry *target_entry;
	Slapi_Entry *existing_entry;
	const CSN *target_entry_dncsn;
	CSN *opcsn= NULL;
	char *op_uniqueid = NULL;
	const char *existing_uniqueid = NULL;
	const Slapi_DN *target_sdn;
	const Slapi_DN *existing_sdn;
	char *newrdn;
	char sessionid[REPL_SESSION_ID_SIZE];
	int r;
	int op_result= 0;
	int rc= 0; /* OK */
	int del_old_replconflict_attr = 0;

	if ( slapi_op_abandoned(pb) )
	{
		return rc;
	}

	slapi_pblock_get (pb, SLAPI_MODRDN_TARGET_ENTRY, &target_entry);
	if(target_entry==NULL)
	{
		/* An entry can't be found for the Unique Identifier */
		op_result= LDAP_NO_SUCH_OBJECT;
		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
		rc= -1; /* No entry to modrdn */
		PROFILE_POINT; /* ModRDN Conflict; Entry does not Exist; Discard ModRDN */
		goto bailout;
	}

	get_repl_session_id (pb, sessionid, &opcsn);
	target_entry_dncsn = entry_get_dncsn (target_entry);
	if ( csn_compare (target_entry_dncsn, opcsn) >= 0 )
	{
		/*
		 * The Operation CSN is not newer than the DN CSN.
		 * Either we're beaten by another ModRDN or we've applied the op.
		 */
		/* op_result= LDAP_SUCCESS; */
		/* 
		 * This operation won't be replayed.  That is, this CSN won't update
		 * the max csn in RUV. The CSN is left uncommitted in RUV unless an
		 * error is set to op_result.  Just to get rid of this CSN from RUV,
		 * setting an error to op_result
		 */
		slapi_log_error(slapi_log_urp, sessionid,
		           "urp_modrdn (%s): operation CSN is newer than the DN CSN.\n",
		           slapi_entry_get_dn_const(target_entry));
		op_result= LDAP_UNWILLING_TO_PERFORM;
		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
		rc = SLAPI_PLUGIN_NOOP; /* Ignore the modrdn */
		PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; OPCSN is not newer. */
		goto bailout;
	}

	/* The DN CSN is older than the Operation CSN. Apply the operation */
	target_sdn = slapi_entry_get_sdn_const (target_entry);
	/* newrdn is no need to be case-ignored (get_rdn_plus_uniqueid) */
	slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &newrdn);
	slapi_pblock_get(pb, SLAPI_TARGET_UNIQUEID, &op_uniqueid);
	slapi_pblock_get(pb, SLAPI_MODRDN_PARENT_ENTRY, &parent_entry);
	slapi_pblock_get(pb, SLAPI_MODRDN_NEWPARENT_ENTRY, &new_parent_entry);
	slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior);

	if ( is_tombstone_entry (target_entry) )
	{
		/*
		 * It is a non-trivial task to rename a tombstone.
		 * This op has been ignored so far by 
		 * setting SLAPI_RESULT_CODE to LDAP_NO_SUCH_OBJECT
		 * and rc to -1.
		 */

		/* Turn the tombstone to glue before rename it */
		/*
		op_result = tombstone_to_glue (pb, sessionid, target_entry,
			slapi_entry_get_sdn (target_entry), "renameTombstone", opcsn);
		*/
		op_result = LDAP_NO_SUCH_OBJECT;
		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
		if (op_result == 0)
		{
			/*
			 * Remember to turn this entry back to tombstone in post op.
			 * We'll just borrow an obsolete pblock type here.
			 */
			slapi_pblock_set (pb, SLAPI_URP_TOMBSTONE_UNIQUEID, slapi_ch_strdup(op_uniqueid));
			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_TARGET_ENTRY);
			rc = 0;
		}
		else
		{
			slapi_log_error(slapi_log_urp, sessionid,
			                "urp_modrdn (%s): target entry is a tombstone.\n",
			                slapi_entry_get_dn_const(target_entry));
			rc = SLAPI_PLUGIN_NOOP; /* Ignore the modrdn */
		}
		PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; OPCSN is not newer. */
		goto bailout;
	}

	slapi_pblock_get(pb, SLAPI_MODRDN_EXISTING_ENTRY, &existing_entry);
	if(existing_entry!=NULL) 
	{
	    /*
	     * An entry with the target DN already exists.
	     * The smaller dncsn wins. The loser changes its RDN to
	     * uniqueid+baserdn, and adds operational attribute
	     * ATTR_NSDS5_REPLCONFLIC
	     */

		existing_uniqueid = slapi_entry_get_uniqueid (existing_entry);
		existing_sdn = slapi_entry_get_sdn_const ( existing_entry);

		/*
		 * It used to dismiss the operation if the existing entry is 
		 * the same as the target one.
		 * But renaming the RDN with the one which only cases are different,
		 * cn=ABC --> cn=Abc, this case matches.  We should go forward the op.
		 */
		if (strcmp(op_uniqueid, existing_uniqueid) == 0) {
			op_result= LDAP_SUCCESS;
			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
			rc = 0; /* Don't ignore the op */
			PROFILE_POINT; /* ModRDN Replay */
			goto bailout;
		}

		r= csn_compare ( entry_get_dncsn (existing_entry), opcsn);
		if (r == 0)
		{
			/*
			 * The CSN of the Operation and the Entry DN are the same
			 * but the uniqueids are not.
			 * There might be two replicas with the same ReplicaID.
			 */
			slapi_log_error(slapi_log_urp, sessionid,
				"urp_modrdn: Duplicated CSN for different uniqueids [%s][%s]",
				existing_uniqueid, op_uniqueid);
			op_result= LDAP_OPERATIONS_ERROR;
			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
			rc = SLAPI_PLUGIN_NOOP; /* Ignore this Operation */
			PROFILE_POINT; /* ModRDN Conflict; Duplicated CSN for Different Entries */
			goto bailout;
		}

		if(r<0)
		{
			/* The target entry is a loser */

			char *newrdn_with_uniqueid;
			newrdn_with_uniqueid= get_rdn_plus_uniqueid (sessionid, newrdn, op_uniqueid);
			if(newrdn_with_uniqueid==NULL)
			{
				op_result= LDAP_OPERATIONS_ERROR;
				slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
				rc= -1; /* Ignore this Operation */
				PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists;
								  Unique ID already in RDN - Change to Lost and Found entry */
				goto bailout;
			}
			mod_namingconflict_attr (op_uniqueid, target_sdn, existing_sdn, opcsn);
			slapi_pblock_set(pb, SLAPI_MODRDN_NEWRDN, newrdn_with_uniqueid); 
			slapi_log_error(slapi_log_urp, sessionid,
			  "urp_modrdn: Naming conflict MODRDN. Rename target entry to %s\n",
			  newrdn_with_uniqueid );

			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
			PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; Rename Operation Entry */
			goto bailout;
		}

		if ( r>0 )
		{
			/* The existing entry is a loser */

			int resolve = urp_annotate_dn (sessionid, existing_entry, opcsn, "MODRDN");
			if(!resolve)
			{
				op_result= LDAP_OPERATIONS_ERROR;
				slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
				rc= -1; /* Abort this Operation */
				goto bailout;
			}
			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_NEWPARENT_ENTRY);
			if (LDAP_NO_SUCH_OBJECT == resolve) {
				/* This means that existing_dn_entry did not really exist!!!
				 * This indicates that a get_copy_of_entry -> dn2entry returned 
				 * an entry (existing_dn_entry) that was already removed from the ldbm.
				 * This is bad, because it indicates a dn cache or DB corruption.
				 * However, as far as the conflict is concerned, this error is harmless:
				 * if the existing_dn_entry did not exist in the first place, there was no
				 * conflict!! Return 0 for success to break the ldbm_back_modrdn loop 
				 * and get out of this inexistent conflict resolution ASAP.
				 */
				rc = 0;
			}
			/* Set flag to remove possible old naming conflict */
			del_old_replconflict_attr = 1;
			PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; Rename Entry with Target DN */
			goto bailout;
		}
	}
	else
	{
		/*
		 * No entry with the target DN exists.
		 */

		/* Set flag to remove possible old naming conflict */
		del_old_replconflict_attr = 1;

		if(new_parent_entry!=NULL)
		{
			/* The new superior entry exists */
			rc= 0; /* OK, Apply the ModRDN */
			PROFILE_POINT; /* ModRDN Conflict; OK */
			goto bailout;
		}

		/* The new superior entry doesn't exist */

		slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior);
		if(newsuperior == NULL)
		{
			/* (new_parent_entry==NULL && newsuperiordn==NULL)
			 * This is ok - SLAPI_MODRDN_NEWPARENT_ENTRY will
			 * only be set if SLAPI_MODRDN_NEWSUPERIOR_SDN was
			 * suplied by the client. If it wasn't, we're just
			 * changing the RDN of the entry. In that case,
			 * if the entry exists, its parent won't change
			 * when it's renamed, and therefore we can assume
			 * its parent exists.
			 */
			rc=0;
			PROFILE_POINT; /* ModRDN OK */
			goto bailout;
		}

		if((0 == slapi_sdn_compare(slapi_entry_get_sdn(parent_entry),
		                           newsuperior)) || 
		   is_suffix_dn (pb, newsuperior, &parentdn) )
		{
			/*
			 * The new superior is the same as the current one, or
			 * this entry is a suffix whose parent can be absent.
			 */ 
			rc= 0; /* OK, Move the entry */
			PROFILE_POINT; /* ModRDN Conflict; Absent Target Parent; Create Suffix Entry */
			goto bailout;
		}

		/*
		 * This entry is not a suffix entry, so the parent entry should exist.
		 * (This shouldn't happen in a ds5 server)
		 */
		slapi_pblock_get ( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
		op_result = create_glue_entry (pb, sessionid, newsuperior,
			op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid, opcsn);
		if (LDAP_SUCCESS != op_result)
		{
			/* 
			 * FATAL ERROR 
			 * We should probably just abort the rename
			 * this will cause replication divergence requiring
			 * admin intercession
			 */
			slapi_log_error( SLAPI_LOG_FATAL, sessionid,
				 "urp_modrdn: Parent %s couldn't be found, nor recreated as a glue entry\n",
				 slapi_sdn_get_dn(newsuperior) );
			op_result= LDAP_OPERATIONS_ERROR;
			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
			rc = SLAPI_PLUGIN_FAILURE; /* Ignore this Operation */
			PROFILE_POINT;
			goto bailout;
		}

		/* The backend add code should now search for the parent again. */
		rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_NEWPARENT_ENTRY);
		PROFILE_POINT; /* ModRDN Conflict; Absent Target Parent - Change to Lost and Found entry */
		goto bailout;
	}

bailout:
	if ( del_old_replconflict_attr && rc == 0 )
	{
		del_replconflict_attr (target_entry, opcsn, 0);
	}
	if ( parentdn )
		slapi_sdn_free(&parentdn);
    return rc;
}
コード例 #13
0
ファイル: urp.c プロジェクト: ohamada/389ds
/*
 * Return 0 for OK,
 *       -1 for Ignore or Error depending on SLAPI_RESULT_CODE,
 *       >0 for action code
 * Action Code Bit 0: Fetch existing entry.
 * Action Code Bit 1: Fetch parent entry.
 * The function is called as a be pre-op on consumers.
 */
int 
urp_add_operation( Slapi_PBlock *pb )
{
	Slapi_Entry	*existing_uniqueid_entry;
	Slapi_Entry	*existing_dn_entry;
	Slapi_Entry	*addentry;
	const char *adduniqueid;
	CSN *opcsn;
	const char *basedn;
	char sessionid[REPL_SESSION_ID_SIZE];
	int r;
	int op_result= 0;
	int rc= 0; /* OK */
	Slapi_DN *sdn = NULL;

	if ( slapi_op_abandoned(pb) )
	{
		return rc;
	}

	get_repl_session_id (pb, sessionid, &opcsn);
	slapi_pblock_get( pb, SLAPI_ADD_EXISTING_UNIQUEID_ENTRY, &existing_uniqueid_entry );
	if (existing_uniqueid_entry!=NULL)
	{
		/* 
		 * An entry with this uniqueid already exists.
		 * - It could be a replay of the same Add, or
		 * - It could be a UUID generation collision, or
		 */
		/* 
		 * This operation won't be replayed.  That is, this CSN won't update
		 * the max csn in RUV. The CSN is left uncommitted in RUV unless an
		 * error is set to op_result.  Just to get rid of this CSN from RUV,
		 * setting an error to op_result
		 */
		/* op_result = LDAP_SUCCESS; */
		slapi_log_error(slapi_log_urp, sessionid,
		          "urp_add (%s): an entry with this uniqueid already exists.\n",
		          slapi_entry_get_dn_const(existing_uniqueid_entry));
		op_result= LDAP_UNWILLING_TO_PERFORM;
		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
		rc = SLAPI_PLUGIN_NOOP; /* Ignore this Operation */
		PROFILE_POINT; /* Add Conflict; UniqueID Exists;  Ignore */
		goto bailout;
	}

	slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &addentry );
	slapi_pblock_get( pb, SLAPI_ADD_EXISTING_DN_ENTRY, &existing_dn_entry );
	if (existing_dn_entry==NULL) /* The target DN does not exist */
	{
		/* Check for parent entry... this could be an orphan. */
		Slapi_Entry *parententry;
		slapi_pblock_get( pb, SLAPI_ADD_PARENT_ENTRY, &parententry );
		rc = urp_add_resolve_parententry (pb, sessionid, addentry, parententry, opcsn);
		PROFILE_POINT; /* Add Entry */
		goto bailout;
	}

	/*
	 * Naming conflict: an entry with the target DN already exists.
	 * Compare the DistinguishedNameCSN of the existing entry
	 * and the OperationCSN. The smaller CSN wins. The loser changes
	 * its RDN to uniqueid+baserdn, and adds operational attribute
	 * ATTR_NSDS5_REPLCONFLIC.
	 */
	basedn = slapi_entry_get_ndn (addentry);
	adduniqueid = slapi_entry_get_uniqueid (addentry);
	r = csn_compare (entry_get_dncsn(existing_dn_entry), opcsn);
	if (r<0)
	{
		/* Entry to be added is a loser */
		char *newdn= get_dn_plus_uniqueid (sessionid, basedn, adduniqueid);
		if(newdn==NULL)
		{
			op_result= LDAP_OPERATIONS_ERROR;
			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
			rc = SLAPI_PLUGIN_NOOP; /* Abort this Operation */
			slapi_log_error(slapi_log_urp, sessionid,
			      "urp_add (%s): Add conflict; Unique ID (%s) already in RDN\n",
			      basedn, adduniqueid);
			PROFILE_POINT; /* Add Conflict; Entry Exists; Unique ID already in RDN - Abort this update. */
		}
		else
		{
			/* Add the nsds5ReplConflict attribute in the mods */
			Slapi_Attr *attr = NULL;
			Slapi_Value **vals = NULL;
			Slapi_RDN *rdn;
			char buf[BUFSIZ];

			PR_snprintf(buf, BUFSIZ, "%s %s", REASON_ANNOTATE_DN, basedn);
			if (slapi_entry_attr_find (addentry, ATTR_NSDS5_REPLCONFLICT, &attr) == 0)
			{
				/* ATTR_NSDS5_REPLCONFLICT exists */
				slapi_log_error(SLAPI_LOG_FATAL, sessionid,
				          "urp_add: New entry has nsds5ReplConflict already\n");
				vals = attr_get_present_values (attr); /* this returns a pointer to the contents */
			}
			if ( vals == NULL || *vals == NULL )
			{
				/* Add new attribute */
				slapi_entry_add_string (addentry, ATTR_NSDS5_REPLCONFLICT, buf);
			}
			else
			{
				/*
				 * Replace old attribute. We don't worry about the index
				 * change here since the entry is yet to be added.
				 */
				slapi_value_set_string (*vals, buf);
			}
			/* slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn); */
			slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn);
			slapi_sdn_free(&sdn);

			slapi_entry_set_normdn(addentry, newdn); /* dn: passin */

			sdn = slapi_sdn_dup(slapi_entry_get_sdn_const(addentry));
			slapi_pblock_set(pb, SLAPI_ADD_TARGET_SDN, sdn);

			rdn = slapi_rdn_new_sdn ( slapi_entry_get_sdn_const(addentry) );
			slapi_log_error (slapi_log_urp, sessionid,
			                 "urp_add: Naming conflict ADD. Add %s instead\n",
			                 slapi_rdn_get_rdn(rdn));
			slapi_rdn_free(&rdn);

			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
			PROFILE_POINT; /* Add Conflict; Entry Exists; Rename Operation Entry */
		}
	}
	else if(r>0)
	{
		/* Existing entry is a loser */
		if (!urp_annotate_dn(sessionid, existing_dn_entry, opcsn, "ADD"))
		{
			op_result= LDAP_OPERATIONS_ERROR;
			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
			slapi_log_error(slapi_log_urp, sessionid,
			                "urp_add (%s): Entry to be added is a loser; "
			                "urp_annotate_dn failed.\n", basedn);
			rc = SLAPI_PLUGIN_NOOP; /* Ignore this Operation */
		}
		else
		{
			/* The backend add code should now search for the existing entry again. */
			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
			rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY);
		}
		PROFILE_POINT; /* Add Conflict; Entry Exists; Rename Existing Entry */
	}
	else /* r==0 */
	{
		/* The CSN of the Operation and the Entry DN are the same.
		 * This could only happen if:
		 * a) There are two replicas with the same ReplicaID.
		 * b) We've seen the Operation before.
		 * Let's go with (b) and ignore the little bastard.
		 */
		/* 
		 * This operation won't be replayed.  That is, this CSN won't update
		 * the max csn in RUV. The CSN is left uncommitted in RUV unless an
		 * error is set to op_result.  Just to get rid of this CSN from RUV,
		 * setting an error to op_result
		 */
		/* op_result = LDAP_SUCCESS; */
		slapi_log_error(slapi_log_urp, sessionid,
		"urp_add (%s): The CSN of the Operation and the Entry DN are the same.",
		slapi_entry_get_dn_const(existing_dn_entry));
		op_result= LDAP_UNWILLING_TO_PERFORM;
		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
		rc = SLAPI_PLUGIN_NOOP; /* Ignore this Operation */
		PROFILE_POINT; /* Add Conflict; Entry Exists; Same CSN */
	}

bailout:
	return rc;
}
コード例 #14
0
ファイル: ldbm_modify.c プロジェクト: Firstyear/ds
int
ldbm_back_modify( Slapi_PBlock *pb )
{
	backend *be;
	ldbm_instance *inst = NULL;
	struct ldbminfo		*li;
	struct backentry	*e = NULL, *ec = NULL;
	struct backentry	*original_entry = NULL, *tmpentry = NULL;
	Slapi_Entry		*postentry = NULL;
	LDAPMod			**mods = NULL;
	LDAPMod			**mods_original = NULL;
	Slapi_Mods smods = {0};
	back_txn txn;
	back_txnid		parent_txn;
	modify_context		ruv_c = {0};
	int			ruv_c_init = 0;
	int			retval = -1;
	char			*msg;
	char			*errbuf = NULL;
	int retry_count = 0;
	int disk_full = 0;
	int ldap_result_code= LDAP_SUCCESS;
	char *ldap_result_message= NULL;
	int rc = 0;
	Slapi_Operation *operation;
	entry_address *addr;
	int is_fixup_operation= 0;
	int is_ruv = 0;                 /* True if the current entry is RUV */
	CSN *opcsn = NULL;
	int repl_op;
	int opreturn = 0;
	int mod_count = 0;
	int not_an_error = 0;
	int fixup_tombstone = 0;
	int ec_locked = 0;
	int result_sent = 0;

	slapi_pblock_get( pb, SLAPI_BACKEND, &be);
	slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
	slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr );
	slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
	slapi_pblock_get( pb, SLAPI_TXN, (void**)&parent_txn );
	slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
	slapi_pblock_get( pb, SLAPI_OPERATION, &operation );

	fixup_tombstone = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_FIXUP);

	dblayer_txn_init(li,&txn); /* must do this before first goto error_return */
	/* the calls to perform searches require the parent txn if any
	   so set txn to the parent_txn until we begin the child transaction */
	if (parent_txn) {
		txn.back_txn_txn = parent_txn;
	} else {
		parent_txn = txn.back_txn_txn;
		slapi_pblock_set( pb, SLAPI_TXN, parent_txn );
	}

	if (NULL == operation)
	{
		ldap_result_code = LDAP_OPERATIONS_ERROR;
		goto error_return;
	}

	is_fixup_operation = operation_is_flag_set(operation, OP_FLAG_REPL_FIXUP);
	is_ruv = operation_is_flag_set(operation, OP_FLAG_REPL_RUV);
	inst = (ldbm_instance *) be->be_instance_info;

	if (NULL == addr)
	{
		goto error_return;
	}
	if (inst && inst->inst_ref_count) {
		slapi_counter_increment(inst->inst_ref_count);
	} else {
		slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
		              "Instance \"%s\" does not exist.\n",
		              inst ? inst->inst_name : "null instance");
		goto error_return;
	}

	/* no need to check the dn syntax as this is a replicated op */
	if(!repl_op){
		ldap_result_code = slapi_dn_syntax_check(pb, slapi_sdn_get_dn(addr->sdn), 1);
		if (ldap_result_code)
		{
			ldap_result_code = LDAP_INVALID_DN_SYNTAX;
			slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
			goto error_return;
		}
	}

	/* The dblock serializes writes to the database,
	 * which reduces deadlocking in the db code,
	 * which means that we run faster.
	 *
	 * But, this lock is re-enterant for the fixup
	 * operations that the URP code in the Replication
	 * plugin generates.
	 *
	 * SERIALLOCK is moved to dblayer_txn_begin along with exposing be
	 * transaction to plugins (see slapi_back_transaction_* APIs).
	 *
	if(SERIALLOCK(li) && !operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP)) {
		dblayer_lock_backend(be);
		dblock_acquired= 1;
	}
	 */
	if ( MANAGE_ENTRY_BEFORE_DBLOCK(li)) {
		/* find and lock the entry we are about to modify */
		if (fixup_tombstone) {
			e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
		} else {
			e = find_entry2modify( pb, be, addr, &txn, &result_sent );
		}
		if (e == NULL) {
			ldap_result_code = -1;
			goto error_return; /* error result sent by find_entry2modify() */
		}
	}

	txn.back_txn_txn = NULL; /* ready to create the child transaction */
	for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) {
		int cache_rc = 0;
		int new_mod_count = 0;
		if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) {
			/* don't release SERIAL LOCK */
			dblayer_txn_abort_ext(li, &txn, PR_FALSE); 
			slapi_pblock_set(pb, SLAPI_TXN, parent_txn);
			/*
			 * Since be_txn_preop functions could have modified the entry/mods,
			 * We need to grab the current mods, free them, and restore the
			 * originals.  Same thing for the entry.
			 */
			
			slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
			ldap_mods_free(mods, 1);
			slapi_pblock_set(pb, SLAPI_MODIFY_MODS, copy_mods(mods_original));

			/* reset ec set cache in id2entry_add_ext */
			if (ec) {
				/* must duplicate ec before returning it to cache,
				 * which could free the entry. */
				if ((tmpentry = backentry_dup(original_entry?original_entry:ec)) == NULL) {
					ldap_result_code= LDAP_OPERATIONS_ERROR;
					goto error_return;
				}
				if (cache_is_in_cache(&inst->inst_cache, ec)) {
					CACHE_REMOVE(&inst->inst_cache, ec);
				}
				CACHE_RETURN(&inst->inst_cache, &ec);
				slapi_pblock_set( pb, SLAPI_MODIFY_EXISTING_ENTRY, original_entry->ep_entry );
				ec = original_entry;
				original_entry = tmpentry;
				tmpentry = NULL;
			}

			if (ruv_c_init) {
				/* reset the ruv txn stuff */
				modify_term(&ruv_c, be);
				ruv_c_init = 0;
			}

			slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_modify",
			               "Modify Retrying Transaction\n");
#ifndef LDBM_NO_BACKOFF_DELAY
			{
			PRIntervalTime interval;
			interval = PR_MillisecondsToInterval(slapi_rand() % 100);
			DS_Sleep(interval);
			}
#endif
		}

		/* Nothing above here modifies persistent store, everything after here is subject to the transaction */
		/* dblayer_txn_begin holds SERIAL lock, 
		 * which should be outside of locking the entry (find_entry2modify) */
		if (0 == retry_count) {
			/* First time, hold SERIAL LOCK */
			retval = dblayer_txn_begin(be, parent_txn, &txn);
		} else {
			/* Otherwise, no SERIAL LOCK */
			retval = dblayer_txn_begin_ext(li, parent_txn, &txn, PR_FALSE);
		}
		if (0 != retval) {
			if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
			ldap_result_code= LDAP_OPERATIONS_ERROR;
			goto error_return;
		}
		/* stash the transaction for plugins */
		slapi_pblock_set(pb, SLAPI_TXN, txn.back_txn_txn);

		if (0 == retry_count) { /* just once */
			if ( !MANAGE_ENTRY_BEFORE_DBLOCK(li)) {
				/* find and lock the entry we are about to modify */
				if (fixup_tombstone) {
					e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent );
				} else {
					e = find_entry2modify( pb, be, addr, &txn, &result_sent );
				}
				if (e == NULL) {
					ldap_result_code = -1;
					goto error_return; /* error result sent by find_entry2modify() */
				}
			}
		
			if ( !is_fixup_operation && !fixup_tombstone)
			{
				if (!repl_op && slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE))
				{
					ldap_result_code = LDAP_UNWILLING_TO_PERFORM;
                			ldap_result_message = "Operation not allowed on tombstone entry.";
					slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
						"Attempt to modify a tombstone entry %s\n",
						slapi_sdn_get_dn(slapi_entry_get_sdn_const( e->ep_entry )));
					goto error_return;
				}
				opcsn = operation_get_csn (operation);
				if (NULL == opcsn && operation->o_csngen_handler)
				{
					/*
					 * Current op is a user request. Opcsn will be assigned
					 * if the dn is in an updatable replica.
					 */
					opcsn = entry_assign_operation_csn ( pb, e->ep_entry, NULL );
				}
				if (opcsn)
				{
					entry_set_maxcsn (e->ep_entry, opcsn);
				}
			}
		
			/* Save away a copy of the entry, before modifications */
			slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( e->ep_entry ));
			
			if ( (ldap_result_code = plugin_call_acl_mods_access( pb, e->ep_entry, mods, &errbuf)) != LDAP_SUCCESS ) {
				ldap_result_message= errbuf;
				goto error_return;
			}
		
			/* create a copy of the entry and apply the changes to it */
			if ( (ec = backentry_dup( e )) == NULL ) {
				ldap_result_code= LDAP_OPERATIONS_ERROR;
				goto error_return;
			}
		
			if(!repl_op){
			    remove_illegal_mods(mods);
			}
		
			/* ec is the entry that our bepreop should get to mess with */
			slapi_pblock_set( pb, SLAPI_MODIFY_EXISTING_ENTRY, ec->ep_entry );
			slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
		
			opreturn = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN);
			if (opreturn ||
				(slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code) && ldap_result_code) ||
				(slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn) && opreturn)) {
				slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
				slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
				if (!ldap_result_code) {
					slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
						"SLAPI_PLUGIN_BE_PRE_MODIFY_FN "
						"returned error but did not set SLAPI_RESULT_CODE\n");
					ldap_result_code = LDAP_OPERATIONS_ERROR;
				}
				if (SLAPI_PLUGIN_NOOP == opreturn) {
					not_an_error = 1;
					rc = opreturn = LDAP_SUCCESS;
				} else if (!opreturn) {
					opreturn = SLAPI_PLUGIN_FAILURE;
					slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
				}
				slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
				goto error_return;
			}
			/* The Plugin may have messed about with some of the PBlock parameters... ie. mods */
			slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
		
			/* apply the mods, check for syntax, schema problems, etc. */
			if (modify_apply_check_expand(pb, operation, mods, e, ec, &postentry,
										  &ldap_result_code, &ldap_result_message)) {
				goto error_return;
			}
			/* the schema check could have added a repl conflict mod
			 * get the mods again */
			slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
			slapi_mods_init_byref(&smods,mods);
			mod_count = slapi_mods_get_num_mods(&smods);
			/*
			 * Grab a copy of the mods and the entry in case the be_txn_preop changes
			 * the them.  If we have a failure, then we need to reset the mods to their
			 * their original state;
			 */
			mods_original = copy_mods(mods);
			if ( (original_entry = backentry_dup( ec )) == NULL ) {
				ldap_result_code= LDAP_OPERATIONS_ERROR;
				goto error_return;
			}
		} /* if (0 == retry_count) just once */

		/* call the transaction pre modify plugins just after creating the transaction */
		retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN);
		if (retval) {
			slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify", "SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN plugin "
						   "returned error code %d\n", retval );
			slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
			slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
			if (SLAPI_PLUGIN_NOOP == retval) {
				not_an_error = 1;
				rc = retval = LDAP_SUCCESS;
			}
			if (!opreturn) {
				slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
			}
			slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
			goto error_return;
		}

		/* the mods might have been changed, so get the latest */
		slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );

		/* make sure the betxnpreop did not alter any of the mods that
		   had already previously been applied */
		slapi_mods_done(&smods);
		slapi_mods_init_byref(&smods,mods);
		new_mod_count = slapi_mods_get_num_mods(&smods);
		if (new_mod_count < mod_count) {
			slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
				"Error: BE_TXN_PRE_MODIFY plugin has removed "
				"mods from the original list - mod count was [%d] now [%d] "
				"mods will not be applied - mods list changes must be done "
				"in the BE_PRE_MODIFY plugin, not the BE_TXN_PRE_MODIFY\n",
				mod_count, new_mod_count );
		} else if (new_mod_count > mod_count) { /* apply the new betxnpremod mods */
			/* apply the mods, check for syntax, schema problems, etc. */
			if (modify_apply_check_expand(pb, operation, &mods[mod_count], e, ec, &postentry,
										  &ldap_result_code, &ldap_result_message)) {
				goto error_return;
			}
		} /* else if new_mod_count == mod_count then betxnpremod plugin did nothing */
			
		/*
		 * Update the ID to Entry index. 
		 * Note that id2entry_add replaces the entry, so the Entry ID 
		 * stays the same.
		 */
		retval = id2entry_add_ext( be, ec, &txn, 1, &cache_rc ); 
		if (DB_LOCK_DEADLOCK == retval)
		{
			/* Abort and re-try */
			continue;
		}
		if (0 != retval) {
			slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
				"id2entry_add failed, err=%d %s\n",
				retval, (msg = dblayer_strerror( retval )) ? msg : "");
			if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
			MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
			goto error_return;
		}
		retval = index_add_mods( be, mods, e, ec, &txn );
		if (DB_LOCK_DEADLOCK == retval)
		{
			/* Abort and re-try */
			continue;
		}
		if (0 != retval) {
			slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
				"index_add_mods failed, err=%d %s\n",
				retval, (msg = dblayer_strerror( retval )) ? msg : "");
			if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
			MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
			goto error_return;
		}
		/*
		 * Remove the old entry from the Virtual List View indexes.
		 * Add the new entry to the Virtual List View indexes.
		 * If the entry is ruv, no need to update vlv.
		 */
		if (!is_ruv) {
			retval= vlv_update_all_indexes(&txn, be, pb, e, ec);
			if (DB_LOCK_DEADLOCK == retval)
			{
				/* Abort and re-try */
				continue;
			}
			if (0 != retval) {
				slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
					"vlv_update_index failed, err=%d %s\n",
					retval, (msg = dblayer_strerror( retval )) ? msg : "");
				if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
				MOD_SET_ERROR(ldap_result_code, 
							  LDAP_OPERATIONS_ERROR, retry_count);
				goto error_return;
			}

		}

		if (!is_ruv && !is_fixup_operation && !NO_RUV_UPDATE(li)) {
			ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c );
			if (-1 == ruv_c_init) {
				slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
					"ldbm_txn_ruv_modify_context failed to construct RUV modify context\n");
				ldap_result_code= LDAP_OPERATIONS_ERROR;
				retval = 0;
				goto error_return;
			}
		}

		if (ruv_c_init) {
			retval = modify_update_all( be, pb, &ruv_c, &txn );
			if (DB_LOCK_DEADLOCK == retval) {
				/* Abort and re-try */
				continue;
			}
			if (0 != retval) {
				slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
					"modify_update_all failed, err=%d %s\n", retval,
					(msg = dblayer_strerror( retval )) ? msg : "");
				if (LDBM_OS_ERR_IS_DISKFULL(retval))
					disk_full = 1;
				ldap_result_code= LDAP_OPERATIONS_ERROR;
				goto error_return;
			}
		}

		if (0 == retval) {
			break;
		}
	}
	if (retry_count == RETRY_TIMES) {
		slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
			"Retry count exceeded in modify\n");
	   	ldap_result_code= LDAP_BUSY;
		goto error_return;
	}

	if (ruv_c_init) {
		if (modify_switch_entries(&ruv_c, be) != 0 ) {
			ldap_result_code= LDAP_OPERATIONS_ERROR;
			slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify",
				"modify_switch_entries failed\n");
			goto error_return;
		}
	}
	
	if (cache_replace( &inst->inst_cache, e, ec ) != 0 ) {
		MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
		goto error_return;
	}
	/* e uncached */
	/* we must return both e (which has been deleted) and new entry ec to cache */
	/* cache_replace removes e from the cache hash tables */
	cache_unlock_entry( &inst->inst_cache, e );
	CACHE_RETURN( &inst->inst_cache, &e );
	/* lock new entry in cache to prevent usage until we are complete */
	cache_lock_entry( &inst->inst_cache, ec );
	ec_locked = 1;
	postentry = slapi_entry_dup( ec->ep_entry );
	slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, postentry );

	/* invalidate virtual cache */
	ec->ep_entry->e_virtual_watermark = 0;

	/* 
	 * LP Fix of crash when the commit will fail:
	 * If the commit fail, the common error path will
	 * try to unlock the entry again and crash (PR_ASSERT
	 * in debug mode.
	 * By just setting e to NULL, we avoid this. It's OK since
	 * we don't use e after that in the normal case.
	 */
	e = NULL;
	
	/* call the transaction post modify plugins just before the commit */
	if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN))) {
		slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify",
			"SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN plugin "
			"returned error code %d\n", retval );
		if (!ldap_result_code) {
			slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
		}
		if (!opreturn) {
			slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
		}
		if (!opreturn) {
			slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
		}
		slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
		goto error_return;
	}

	/* Release SERIAL LOCK */
	retval = dblayer_txn_commit(be, &txn);
	/* after commit - txn is no longer valid - replace SLAPI_TXN with parent */
	slapi_pblock_set(pb, SLAPI_TXN, parent_txn);
	if (0 != retval) {
		if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
		ldap_result_code= LDAP_OPERATIONS_ERROR;
		goto error_return;
	}

	rc= 0;
	goto common_return;

error_return:
	if ( postentry != NULL ) 
	{
		slapi_entry_free( postentry );
		postentry = NULL;
		slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, NULL );
	}
	if (retval == DB_RUNRECOVERY) {
	  dblayer_remember_disk_filled(li);
	  ldbm_nasty("ldbm_back_modify","Modify",81,retval);
	  disk_full = 1;
	}

	if (disk_full) {
	    rc= return_on_disk_full(li);
	} else {
		if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) {
			/* make sure SLAPI_RESULT_CODE and SLAPI_PLUGIN_OPRETURN are set */
			int val = 0;
			slapi_pblock_get(pb, SLAPI_RESULT_CODE, &val);
			if (!val) {
				if (!ldap_result_code) {
					ldap_result_code = LDAP_OPERATIONS_ERROR;
				}
				slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
			}
			slapi_pblock_get( pb, SLAPI_PLUGIN_OPRETURN, &val );
			if (!val) {
				opreturn = -1;
				slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &opreturn );
			}
			/* call the transaction post modify plugins just before the abort */
			/* plugins called before abort should check for the OPRETURN or RESULT_CODE
			   and skip processing if they don't want do anything - some plugins that
			   keep track of a counter (usn, dna) may want to "rollback" the counter
			   in this case */
			if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN))) {
				slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify",
					"SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN plugin returned error code %d\n", retval );
				slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
				slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
				slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn);
				if (!opreturn) {
					slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
				}
			}

			/* It is safer not to abort when the transaction is not started. */
			/* Release SERIAL LOCK */
			dblayer_txn_abort(be, &txn); /* abort crashes in case disk full */
			/* txn is no longer valid - reset the txn pointer to the parent */
			slapi_pblock_set(pb, SLAPI_TXN, parent_txn);
		}
		if (!not_an_error) {
			rc = SLAPI_FAIL_GENERAL;
		}
	}

	/* if ec is in cache, remove it, then add back e if we still have it */
	if (inst && cache_is_in_cache(&inst->inst_cache, ec)) {
		CACHE_REMOVE( &inst->inst_cache, ec );
		/* if ec was in cache, e was not - add back e */
		if (e) {
			if (CACHE_ADD( &inst->inst_cache, e, NULL ) < 0) {
				slapi_log_err(SLAPI_LOG_CACHE, "ldbm_back_modify", "CACHE_ADD %s failed\n",
				              slapi_entry_get_dn(e->ep_entry));
			}
		}
	}

common_return:
	slapi_mods_done(&smods);
	
	if (inst) {
		if (ec_locked || cache_is_in_cache(&inst->inst_cache, ec)) {
			cache_unlock_entry(&inst->inst_cache, ec);
		} else if (e) {
			/* if ec was not in cache, cache_replace was not done.
			 * i.e., e was not unlocked. */
			cache_unlock_entry(&inst->inst_cache, e);
			CACHE_RETURN(&inst->inst_cache, &e);
		}
		CACHE_RETURN(&inst->inst_cache, &ec);
		if (inst->inst_ref_count) {
			slapi_counter_decrement(inst->inst_ref_count);
		}
	}

	/* result code could be used in the bepost plugin functions. */
	slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);

	/* The bepostop is called even if the operation fails. */
	if (!disk_full)
		plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_MODIFY_FN);

	if (ruv_c_init) {
		modify_term(&ruv_c, be);
	}

	if (ldap_result_code == -1) {
		/* Reset to LDAP_NO_SUCH_OBJECT*/
		ldap_result_code = LDAP_NO_SUCH_OBJECT;
		slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
	} else {
		if (not_an_error) {
			/* This is mainly used by urp.  Solved conflict is not an error.
			 * And we don't want the supplier to halt sending the updates. */
			ldap_result_code = LDAP_SUCCESS;
		}
		if (!result_sent) {
			/* result is already sent in find_entry. */
			slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
		}
	}

	/* free our backups */
	ldap_mods_free(mods_original, 1);
	backentry_free(&original_entry);
	backentry_free(&tmpentry);
	slapi_ch_free_string(&errbuf);

	return rc;
}
コード例 #15
0
ファイル: psearch.c プロジェクト: leto/389-ds
/*
 * Check if there are any persistent searches.  If so,
 * the check to see if the chgtype is one of those the
 * client is interested in.  If so, then check to see if
 * the entry matches any of the filters the searches.
 * If so, then enqueue the entry on that persistent search's
 * ps_entryqueue and signal it to wake up and send the entry.
 *
 * Note that if eprev is NULL we assume that the entry's DN
 * was not changed by the op. that called this function.  If
 * chgnum is 0 it is unknown so we won't ever send it to a
 * client in the EntryChangeNotification control.
 */
void
ps_service_persistent_searches( Slapi_Entry *e, Slapi_Entry *eprev, ber_int_t chgtype,
	ber_int_t chgnum )
{
	LDAPControl *ctrl = NULL;
	PSearch	*ps = NULL;
	PSEQNode *pe = NULL;
	int  matched = 0;
	const char *edn;

	if ( !PS_IS_INITIALIZED()) {
		return;
	}

	if ( NULL == e ) {
		/* For now, some backends such as the chaining backend do not provide a post-op entry */
		return;
	}

	PSL_LOCK_READ();
	edn = slapi_entry_get_dn_const(e);

	for ( ps = psearch_list ? psearch_list->pl_head : NULL; NULL != ps; ps = ps->ps_next ) {
		char *origbase = NULL;
		Slapi_DN *base = NULL;
		Slapi_Filter	*f;
		int		scope;

		/* Skip the node that doesn't meet the changetype,
		 * or is unable to use the change in ps_send_results()
		 */
		if (( ps->ps_changetypes & chgtype ) == 0 ||
				ps->ps_pblock->pb_op == NULL ||
				slapi_op_abandoned( ps->ps_pblock ) ) {
			continue;
		}

		slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
						"conn=%" NSPRIu64 " op=%d entry %s with chgtype %d "
						"matches the ps changetype %d\n",
						ps->ps_pblock->pb_conn->c_connid,
						ps->ps_pblock->pb_op->o_opid,
						edn, chgtype, ps->ps_changetypes);

		slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_FILTER, &f );
		slapi_pblock_get( ps->ps_pblock, SLAPI_ORIGINAL_TARGET_DN, &origbase );
		slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, &base );
		slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_SCOPE, &scope );
		if (NULL == base) {
			base = slapi_sdn_new_dn_byref(origbase);
			slapi_pblock_set(ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, base);
		}

		/*
		 * See if the entry meets the scope and filter criteria.
		 * We cannot do the acl check here as this thread
		 * would then potentially clash with the ps_send_results()
		 * thread on the aclpb in ps->ps_pblock.
		 * By avoiding the acl check in this thread, and leaving all the acl
		 * checking to the ps_send_results() thread we avoid
		 * the ps_pblock contention problem.
		 * The lesson here is "Do not give multiple threads arbitary access
		 * to the same pblock" this kind of muti-threaded access
		 * to the same pblock must be done carefully--there is currently no
		 * generic satisfactory way to do this.
		*/
		if ( slapi_sdn_scope_test( slapi_entry_get_sdn_const(e), base, scope ) &&
			 slapi_vattr_filter_test( ps->ps_pblock, e, f, 0 /* verify_access */ ) == 0 ) {
			PSEQNode *pOldtail;

			/* The scope and the filter match - enqueue it */

			matched++;
			pe = (PSEQNode *)slapi_ch_calloc( 1, sizeof( PSEQNode ));
			pe->pe_entry = slapi_entry_dup( e );
			if ( ps->ps_send_entchg_controls ) {
				/* create_entrychange_control() is more
				 * expensive than slapi_dup_control()
				 */
				if ( ctrl == NULL ) {
					int rc;
					rc = create_entrychange_control( chgtype, chgnum,
							eprev ? slapi_entry_get_dn_const(eprev) : NULL,
							&ctrl );
					if ( rc != LDAP_SUCCESS ) {
		   				LDAPDebug( LDAP_DEBUG_ANY, "ps_service_persistent_searches:"
						" unable to create EntryChangeNotification control for"
						" entry \"%s\" -- control won't be sent.\n",
						slapi_entry_get_dn_const(e), 0, 0 );
					}
				}
				if ( ctrl ) {
					pe->pe_ctrls[0] = slapi_dup_control( ctrl );
				}
			}

			/* Put it on the end of the list for this pers search */
			PR_Lock( ps->ps_lock );
			pOldtail = ps->ps_eq_tail;
			ps->ps_eq_tail = pe;
			if ( NULL == ps->ps_eq_head ) {
				ps->ps_eq_head = ps->ps_eq_tail;
			}
			else {
				pOldtail->pe_next = ps->ps_eq_tail;
			}
			PR_Unlock( ps->ps_lock );
		}
	}

   	PSL_UNLOCK_READ();

	/* Were there any matches? */
	if ( matched ) {
		ldap_control_free( ctrl );
		/* Turn 'em loose */
		ps_wakeup_all();
		LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: enqueued entry "
			"\"%s\" on %d persistent search lists\n", slapi_entry_get_dn_const(e), matched, 0 );
	} else {
		LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: entry "
			"\"%s\" not enqueued on any persistent search lists\n", slapi_entry_get_dn_const(e), 0, 0 );
	}

}