Esempio n. 1
0
Slapi_Entry *
sync_deleted_entry_from_changelog(Slapi_Entry *cl_entry)
{
	Slapi_Entry *db_entry = NULL;
	char *entrydn = NULL;
	char *uniqueid = NULL;
	
	entrydn = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_ENTRYDN);
	uniqueid = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_UNIQUEID);

	/* when the Retro CL can provide the deleted entry 
	 * the entry will be taken from th RCL.
	 * For now. just create an entry to holde the nsuniqueid
	 */ 
	db_entry = slapi_entry_alloc();
	slapi_entry_init(db_entry, entrydn, NULL);
	slapi_entry_add_string(db_entry, "nsuniqueid", uniqueid);
	slapi_ch_free((void**)&uniqueid);

	return(db_entry);
}
Esempio n. 2
0
File: urp.c Progetto: 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;
}
Esempio n. 3
0
/**
   Apply the mods to the ec entry.  Check for syntax, schema problems.
   Check for abandon.

   Return code:
   -1 - error - result code and message are set appropriately
   0 - successfully applied and checked
   1 - not an error - no mods to apply or op abandoned
 */
static int
modify_apply_check_expand(
	Slapi_PBlock *pb,
	Slapi_Operation *operation,
	LDAPMod **mods, /* list of mods to apply */
	struct backentry *e, /* original "before" entry */
	struct backentry *ec, /* "after" entry with mods applied */
	Slapi_Entry **postentry,
	int *ldap_result_code,
	char **ldap_result_message
)
{
	int rc = 0;
	int i;
	int repl_op;
	int change_entry = 0;
	Slapi_Mods smods = {0};
	CSN *csn = operation_get_csn(operation);

	slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
	slapi_mods_init_byref( &smods, mods );

	if ( (change_entry = mods_have_effect (ec->ep_entry, &smods)) ) {
		*ldap_result_code = entry_apply_mods_wsi(ec->ep_entry, &smods, csn,
												 operation_is_flag_set(operation, OP_FLAG_REPLICATED));
		/*
		 * XXXmcs: it would be nice to get back an error message from
		 * the above call so we could pass it along to the client, e.g.,
		 * "duplicate value for attribute givenName."
		 */
	} else {
		Slapi_Entry *epostop = NULL;
		/* If the entry was not actually changed, we still need to
		 * set the SLAPI_ENTRY_POST_OP field in the pblock (post-op
		 * plugins expect that field to be present for all modify
		 * operations that return LDAP_SUCCESS).
		 */
		slapi_pblock_get ( pb, SLAPI_ENTRY_POST_OP, &epostop );
		slapi_entry_free ( epostop ); /* free existing one, if any */
		slapi_pblock_set ( pb, SLAPI_ENTRY_POST_OP, slapi_entry_dup( e->ep_entry ) );
		*postentry = NULL; /* to avoid free in main error cleanup code */
	}
	if ( !change_entry || *ldap_result_code != 0 ) {
		/* change_entry == 0 is not an error just a no-op */
		rc = change_entry ? -1 : 1;
		goto done;
	}

	/*
	 * If the objectClass attribute type was modified in any way, expand
	 * the objectClass values to reflect the inheritance hierarchy.
	 */
	for ( i = 0; mods && mods[i]; ++i ) {
		if ( 0 == strcasecmp( SLAPI_ATTR_OBJECTCLASS, mods[i]->mod_type )) {
			slapi_schema_expand_objectclasses( ec->ep_entry );
			break;
		}
	}

	/*
	 * We are about to pass the last abandon test, so from now on we are
	 * committed to finish this operation. Set status to "will complete"
	 * before we make our last abandon check to avoid race conditions in
	 * the code that processes abandon operations.
	 */
	operation->o_status = SLAPI_OP_STATUS_WILL_COMPLETE;
	if ( slapi_op_abandoned( pb ) ) {
		rc = 1;
		goto done;
	}

	/* multimaster replication can result in a schema violation,
	 * although the individual operations on each master were valid
	 * It is too late to resolve this. But we can check schema and
	 * add a replication conflict attribute.
	 */
	/* check that the entry still obeys the schema */
	if ((operation_is_flag_set(operation,OP_FLAG_ACTION_SCHEMA_CHECK)) &&
			slapi_entry_schema_check_ext( pb, ec->ep_entry, 1 ) != 0 ) {
		if(repl_op){
			Slapi_Attr *attr;
			Slapi_Mods smods;
			LDAPMod **lmods;
			if (slapi_entry_attr_find (ec->ep_entry, ATTR_NSDS5_REPLCONFLICT, &attr) == 0)
			{
				/* add value */ 
				Slapi_Value *val = slapi_value_new_string("Schema violation");
				slapi_attr_add_value(attr,val);
				slapi_value_free(&val);
			} else {
				/* Add new attribute */
				slapi_entry_add_string (ec->ep_entry, ATTR_NSDS5_REPLCONFLICT, "Schema violation");
			}
			/* the replconflict attribute is indexed and the index is built from the mods,
			 * so we need to extend the mods */
			slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &lmods);
			slapi_mods_init_passin(&smods, lmods);
			slapi_mods_add_string (&smods, LDAP_MOD_ADD, ATTR_NSDS5_REPLCONFLICT, "Schema violation");
			lmods = slapi_mods_get_ldapmods_passout(&smods);
			slapi_pblock_set(pb, SLAPI_MODIFY_MODS, lmods);
			slapi_mods_done(&smods);
			
		} else {
			*ldap_result_code = LDAP_OBJECT_CLASS_VIOLATION;
			slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, ldap_result_message);
			rc = -1;
			goto done;
		}
	}

	if(!repl_op){
		/* check attribute syntax for the new values */
		if (slapi_mods_syntax_check(pb, mods, 0) != 0) {
			*ldap_result_code = LDAP_INVALID_SYNTAX;
			slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, ldap_result_message);
			rc = -1;
			goto done;
		}

		/*
		 * make sure the entry contains all values in the RDN.
		 * if not, the modification must have removed them.
		 */
		if ( ! slapi_entry_rdn_values_present( ec->ep_entry ) ) {
			*ldap_result_code= LDAP_NOT_ALLOWED_ON_RDN;
			rc = -1;
			goto done;
		}
	}

done:
	slapi_mods_done( &smods );

	return rc;
}