Example #1
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;
}
Example #2
0
static int 
my_ber_scanf_attr (BerElement *ber, Slapi_Attr **attr, PRBool *deleted)
{
    char *attrtype = NULL;
    CSN *attr_deletion_csn = NULL;
    PRBool val_deleted;
    char *lasti;
    ber_len_t len;
    ber_tag_t tag;
    char *str = NULL;
    int rc;
    Slapi_Value *value = NULL;

    if (attr == NULL)
    {
        goto loser;
    }

    PR_ASSERT (ber && attr && deleted);

    /* allocate the attribute */
    *attr = slapi_attr_new ();
    if (*attr == NULL)
    {
        goto loser;
    }

	if (ber_scanf(ber, "{a", &attrtype) == LBER_ERROR) /* Begin sequence for this attr */
	{
		goto loser;
	}


    slapi_attr_init(*attr, attrtype);
    slapi_ch_free ((void **)&attrtype);

	/* The attribute deletion CSN is next and is optional? */
    if (ber_peek_tag(ber, &len) == LBER_OCTETSTRING)
    {
	    if (ber_scanf(ber, "a", &str) == LBER_ERROR)
	    {
		    goto loser;
	    }
	    attr_deletion_csn = csn_new_by_string(str);
	    slapi_ch_free((void **)&str);
    }

    if (attr_deletion_csn)
	{
		rc = attr_set_deletion_csn(*attr, attr_deletion_csn);
        csn_free (&attr_deletion_csn);
        if (rc != 0)
        {
            goto loser;
        }
	}

	/* The "attribute deleted" flag is next, and is optional */
	if (ber_peek_tag(ber, &len) == LBER_BOOLEAN)
	{
		if (ber_scanf(ber, "b", deleted) == LBER_DEFAULT)
		{
			goto loser;
		}
	} 
    else /* default is present */
    {
		*deleted = PR_FALSE;
	}
	
    /* loop over the list of attribute values */
	for (tag = ber_first_element(ber, &len, &lasti);
		tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
		tag = ber_next_element(ber, &len, lasti))
	{

		value = NULL;		
		if (my_ber_scanf_value(ber, &value, &val_deleted) == -1)
		{
			goto loser;
		}

        if (val_deleted)
        {
			/* Add the value to the attribute */
			if (attr_add_deleted_value(*attr, value) == -1) /* attr has ownership of value */
			{
				goto loser;
			}
        }
        else
        {
            /* Add the value to the attribute */
			if (slapi_attr_add_value(*attr, value) == -1) /* attr has ownership of value */
			{
				goto loser;
			}
        }
		if (value)
			slapi_value_free(&value);
	}	

	if (ber_scanf(ber, "}") == LBER_ERROR) /* End sequence for this attribute */
	{
		goto loser;
	}

    return 0;
loser:
    if (attr && *attr)
        slapi_attr_free (attr);
    if (value)
        slapi_value_free (&value);

    slapi_ch_free_string(&attrtype);
    slapi_ch_free_string(&str);

    return -1;    
}