Example #1
0
/*
 * detect if the plugin should handle this entry and return the entry type
 */
int
ipa_topo_check_entry_type(Slapi_Entry *entry)
{
    int ret = TOPO_IGNORE_ENTRY;
    Slapi_DN *add_dn = NULL;
    char **ocs;

    add_dn = slapi_entry_get_sdn(entry);
    if (slapi_sdn_issuffix(add_dn,ipa_topo_get_plugin_shared_topo_dn())) {
        /* check if it is a toplogy or a segment */
        /* check if segment's left or right node is the local server*/
        int i;
        ocs = slapi_entry_attr_get_charray(entry,"objectclass");

        for (i=0; ocs && ocs[i]; i++) {
            if (strcasecmp(ocs[i],"ipaReplTopoConf") == 0) {
		ret = TOPO_CONFIG_ENTRY;
                break;
            } else if (strcasecmp(ocs[i],"ipaReplTopoSegment") == 0) {
		ret = TOPO_SEGMENT_ENTRY;
                break;
            }
        }
    } else if (slapi_sdn_isparent(ipa_topo_get_plugin_shared_hosts_dn(),add_dn)) {
        ret = TOPO_HOST_ENTRY;
    } else if (slapi_sdn_issuffix(add_dn,ipa_topo_get_domain_level_entry_dn())) {
        ret = TOPO_DOMLEVEL_ENTRY;
    }

    return ret;
}
Example #2
0
static int
linked_attrs_remove_backlinks_callback(Slapi_Entry *e, void *callback_data)
{
    int rc = 0;
    Slapi_DN *sdn = slapi_entry_get_sdn(e);
    char *type = (char *)callback_data;
    Slapi_PBlock *pb = slapi_pblock_new();
    char *val[1];
    LDAPMod mod;
    LDAPMod *mods[2];

    /* Remove all values of the passed in type. */
    val[0] = 0;

    mod.mod_op = LDAP_MOD_DELETE;
    mod.mod_type = type;
    mod.mod_values = val;

    mods[0] = &mod;
    mods[1] = 0;

    slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
                    "Removing backpointer attribute (%s) from entry (%s)\n",
                    type, slapi_sdn_get_dn(sdn));

    /* Perform the operation. */
    slapi_modify_internal_set_pb_ext(pb, sdn, mods, 0, 0,
                                     linked_attrs_get_plugin_id(), 0);
    slapi_modify_internal_pb(pb);

    slapi_pblock_destroy(pb);

    return rc;
}
Example #3
0
/*
 * This routine sets up a "context" for evaluation of access control
 * on a given entry for an anonymous user.
 * It just factors out the scope and targetfilter info into a list
 * of indices of the global anom profile list, that apply to this
 * entry, and stores them in the aclpb.
 * It's use relies on the way that access control is checked in the mailine search
 * code in the core server, namely: check filter, check entry, then check each
 * attribute.  So, we call this in acl_access_allowed() before calling
 * aclanom_match_profile()--therafter, aclanom_match_profile() uses the
 * context to evaluate access to the entry and attributes.
 * 
 * If there are no anom profiles, or the anom profiles get cancelled
 * due to complex anon acis, then that's OK, aclanom_match_profile()
 * returns -1 and the mainline acl code kicks in.
 *
 * The lifetime of this context info is the time it takes to check
 * access control for all parts of this entry (filter, entry, attributes).
 * So, if for an example an entry changes and a given anom profile entry
 * no longer applies, we will not notice until the next round of access
 * control checking on the entry--this is acceptable.
 * 
 * The gain on doing this factoring in the following type of search
 * was approx 6%:
 * anon bind, 20 threads, exact match, ~20 attributes returned, 
 * (searchrate & DirectoryMark).
 * 
*/
void
aclanom_get_suffix_info(Slapi_Entry *e,
							struct acl_pblock *aclpb ) {
	int i;
	char     *ndn = NULL;
	Slapi_DN    *e_sdn;
	const char    *aci_ndn;
	struct scoped_entry_anominfo *s_e_anominfo =
			&aclpb->aclpb_scoped_entry_anominfo;

	ANOM_LOCK_READ ();
		
	s_e_anominfo->anom_e_nummatched=0;

	ndn = slapi_entry_get_ndn ( e ) ;
	e_sdn= slapi_entry_get_sdn ( e ) ;
	for (i=acl_anom_profile->anom_numacls-1; i >= 0; i-- ) {
		aci_ndn = slapi_sdn_get_ndn (acl_anom_profile->anom_targetinfo[i].anom_target);
		if (!slapi_sdn_issuffix(e_sdn,acl_anom_profile->anom_targetinfo[i].anom_target)
				|| (!slapi_is_rootdse(ndn) && slapi_is_rootdse(aci_ndn)))
						continue;
		if ( acl_anom_profile->anom_targetinfo[i].anom_filter ) {
			if ( slapi_vattr_filter_test( aclpb->aclpb_pblock, e,
                               		acl_anom_profile->anom_targetinfo[i].anom_filter, 
					0 /*don't do acess chk*/)  != 0)
				continue;
		}
		s_e_anominfo->anom_e_targetInfo[s_e_anominfo->anom_e_nummatched]=i;
		s_e_anominfo->anom_e_nummatched++;
	}
	ANOM_UNLOCK_READ (); 
}
Example #4
0
static int
handle_agmt_search(Slapi_Entry *e, void *callback_data)
{
	int *agmtcount = (int *)callback_data;
	int rc;

	slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
		"Found replication agreement named \"%s\".\n",
		slapi_sdn_get_dn(slapi_entry_get_sdn(e)));
	rc = add_new_agreement(e);
	if (0 == rc)
	{
		(*agmtcount)++;
	}
	else
	{
		slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "The replication "
			"agreement named \"%s\" could not be correctly parsed. No "
			"replication will occur with this replica.\n",
			slapi_sdn_get_dn(slapi_entry_get_sdn(e)));
	}

	return rc;
}
Example #5
0
/* This function is now fully executed for internal and replicated ops. */
int 
plugin_call_acl_mods_update ( Slapi_PBlock *pb, int optype )
{
	struct slapdplugin	*p;
	int					rc = 0;
	void				*change = NULL;
	void				*mychange[2];
	Slapi_Entry			*te = NULL;
	Slapi_DN			*sdn = NULL;
	Operation			*operation;

	slapi_pblock_get (pb, SLAPI_OPERATION, &operation);

	(void)slapi_pblock_get( pb, SLAPI_TARGET_SDN, &sdn );

	switch ( optype ) {
	  case SLAPI_OPERATION_MODIFY:
		(void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &change );
		break;
	  case SLAPI_OPERATION_ADD:
		(void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &change );
		te = (Slapi_Entry *)change;
		if(!slapi_sdn_isempty(slapi_entry_get_sdn(te)))
		{
			sdn = slapi_entry_get_sdn(te);
		}
		break;
	  case SLAPI_OPERATION_MODRDN:
	  {
		char *newrdn = NULL;
		Slapi_DN *psdn = NULL;
		char *pdn = NULL;

		/* newrdn: "change" is normalized but not case-ignored */
		/* The acl plugin expects normalized newrdn, but no need to be case-
		 * ignored. */
		(void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn );
		(void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &psdn );
		if (psdn) {
			pdn = (char *)slapi_sdn_get_dn(psdn);
		} else {
			(void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR, &pdn );
		}
		mychange[0] = newrdn;
		mychange[1] = pdn;
		change = mychange;
		break;
	  }
	}
	
	if (NULL == sdn) {
		slapi_log_err(SLAPI_LOG_ERR, "plugin_call_acl_mods_update", "NULL target DN\n");
		return LDAP_INVALID_DN_SYNTAX;
	}

	/* 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_UPDATE, pb, sdn)){
			rc = (*p->plg_acl_mods_update)(pb, optype, sdn, change );
			if ( rc != LDAP_SUCCESS ) break;
		}
	}

	return rc;
}
Example #6
0
static int
_ger_g_permission_granted (
	Slapi_PBlock *pb,
	Slapi_Entry *e,
	const char *subjectdn,
	char **errbuf
	)
{
	char *proxydn = NULL;
	Slapi_DN *requestor_sdn, *entry_sdn;
	char *errtext = NULL;
	int isroot;
	int rc;

	/*
	 * Theorically, we should check if the entry has "g"
	 * permission granted to the requestor. If granted,
	 * allows the effective rights on that entry and its
	 * attributes within the entry to be returned for
	 * ANY subject.
	 *
	 * "G" permission granting has not been implemented yet,
	 * the current release assumes that "g" permission be 
	 * granted to root and owner of any entry.
	 */

	/*
	 * The requestor may be either the bind dn or a proxy dn
	 */
	if ((proxyauth_get_dn( pb, &proxydn, &errtext ) == LDAP_SUCCESS) && ( proxydn != NULL ))
	{
		requestor_sdn = slapi_sdn_new_dn_passin ( proxydn );
	}
	else
	{
		slapi_ch_free_string(&proxydn); /* this could still have been set - free it */
		requestor_sdn = &(pb->pb_op->o_sdn);
	}
	if ( slapi_sdn_get_dn (requestor_sdn) == NULL )
	{
		slapi_log_err(SLAPI_LOG_ACL, plugin_name,
				"_ger_g_permission_granted - Anonymous has no g permission\n" );
		rc = LDAP_INSUFFICIENT_ACCESS;
		goto bailout;
	}
	isroot = slapi_dn_isroot ( slapi_sdn_get_dn (requestor_sdn) );
	if ( isroot )
	{
		/* Root has "g" permission on any entry */
		rc = LDAP_SUCCESS;
		goto bailout;
	}

	entry_sdn = slapi_entry_get_sdn ( e );
	if ( entry_sdn == NULL || slapi_sdn_get_dn (entry_sdn) == NULL )
	{
		rc = LDAP_SUCCESS;
		goto bailout;
	}

	if ( slapi_sdn_compare ( requestor_sdn, entry_sdn ) == 0 )
	{
		/* Owner has "g" permission on his own entry */
		rc = LDAP_SUCCESS;
		goto bailout;
	}

	/* if the requestor and the subject user are identical, let's grant it */
	if ( strcasecmp ( slapi_sdn_get_ndn(requestor_sdn), subjectdn ) == 0)
	{
		/* Requestor should see his own permission rights on any entry */
		rc = LDAP_SUCCESS;
		goto bailout;
	}

	aclutil_str_append ( errbuf, "get-effective-rights: requestor has no g permission on the entry" );
	slapi_log_err(SLAPI_LOG_ACL, plugin_name,
				"_ger_g_permission_granted - %s\n", *errbuf);
	rc = LDAP_INSUFFICIENT_ACCESS;

bailout:
	if ( proxydn )
	{
		/* The ownership of proxydn has passed to requestor_sdn */ 
		slapi_sdn_free ( &requestor_sdn );
	}
	return rc;
}
Example #7
0
/***************************************************************************
*
* __aclinit_handler
*
*	For each entry, finds if there is any ACL in that entry. If there is
*	then the ACL is processed and stored in the ACL LIST.
*
*
* Input:
*
*
* Returns:
*	None.
*
* Error Handling:
*	If any error found during the ACL generation, the ACL is
*	logged.  Also, set in the callback_data so that caller can act upon it.
*
**************************************************************************/
static int
__aclinit_handler ( Slapi_Entry *e, void *callback_data)	
{
    Slapi_Attr 		*attr;
	aclinit_handler_callback_data_t *call_back_data = 
		(aclinit_handler_callback_data_t*)callback_data;	
	Slapi_DN			*e_sdn;
	int					rv;
	Slapi_Value 		*sval=NULL;

	call_back_data->retCode = 0;		 /* assume success--if there's an error we overwrite it */
    if (e != NULL) {		

		e_sdn = slapi_entry_get_sdn ( e );	

		/*
	 	 * Take the write lock around all the mods--so that
	 	 * other operations will see the acicache either before the whole mod
		 * or after but not, as it was before, during the mod.
		 * This is in line with the LDAP concept of the operation
		 * on the whole entry being the atomic unit.
	 	 * 
		*/
		
		if ( call_back_data->op == ACL_ADD_ACIS ) {
			slapi_log_err(SLAPI_LOG_ACL, plugin_name,
				"Adding acis for entry '%s'\n", slapi_sdn_get_dn(e_sdn));
			slapi_entry_attr_find ( e, aci_attr_type, &attr );

			if ( attr ) {
				
				const struct berval	*attrValue;				
				
				int i;
				if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
					acllist_acicache_WRITE_LOCK();
				}
				i= slapi_attr_first_value ( attr, &sval );
				while(i != -1) {
		        	attrValue = slapi_value_get_berval(sval);									
					
						if ( 0 != (rv=acllist_insert_aci_needsLock (e_sdn, attrValue))) {
							aclutil_print_err(rv, e_sdn, attrValue, NULL); 

							/* We got an error; Log it  and then march along */
							slapi_log_err(SLAPI_LOG_ERR, plugin_name, 
									  "__aclinit_handler - This  (%s) ACL will not be considered for evaluation"
									  " because of syntax errors.\n", 
									  attrValue->bv_val ? attrValue->bv_val: "NULL");
							call_back_data->retCode = rv;
						}				
					i= slapi_attr_next_value( attr, i, &sval );
				}/* while */
				if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
					acllist_acicache_WRITE_UNLOCK();
				}
			}
		} else if (call_back_data->op == ACL_REMOVE_ACIS) {

			/* Here we are deleting the acis. */
				slapi_log_err(SLAPI_LOG_ACL, plugin_name, "__aclinit_handler - Removing acis\n");
				if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
					acllist_acicache_WRITE_LOCK();
				}	
				if ( 0 != (rv=acllist_remove_aci_needsLock(e_sdn, NULL))) {
					aclutil_print_err(rv, e_sdn, NULL, NULL); 

					/* We got an error; Log it  and then march along */
					slapi_log_err(SLAPI_LOG_ERR, plugin_name, 
									  "__aclinit_handler - ACLs not deleted from %s\n",
                                      slapi_sdn_get_dn(e_sdn));
					call_back_data->retCode = rv;
				}
				if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
					acllist_acicache_WRITE_UNLOCK();
				}
		}
		
	}

	/*
	 * If we get here it's success.
	 * The call_back_data->error is the error code that counts as it's the
	 * one that the original caller will see--this routine is called off a callbacl.
	*/
	
    return ACL_FALSE;	/* "local" error code--it's 0 */
}
Example #8
0
int
update_integrity(char **argv, Slapi_DN *origSDN,
                 char *newrDN, Slapi_DN *newsuperior, 
                 int logChanges)
{
    Slapi_PBlock *search_result_pb = NULL;
    Slapi_PBlock *mod_pb = slapi_pblock_new();
    Slapi_Entry  **search_entries = NULL;
    Slapi_DN *sdn = NULL;
    Slapi_Attr *attr = NULL;
    void *node = NULL;
    const char *origDN = slapi_sdn_get_dn(origSDN);
    const char *search_base = NULL;
    char *attrName = NULL;
    char *filter = NULL;
    char *attrs[2];
    int search_result;
    int nval = 0;
    int i, j;
    int rc;

    if ( argv == NULL ){
        slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
            "referint_postop required config file arguments missing\n" );
        rc = -1;
        goto free_and_return;
    } 
    /*
     *  For now, just putting attributes to keep integrity on in conf file,
     *  until resolve the other timing mode issue
     */
    search_result_pb = slapi_pblock_new();

    /* Search each namingContext in turn */
    for ( sdn = slapi_get_first_suffix( &node, 0 ); sdn != NULL;
          sdn = slapi_get_next_suffix( &node, 0 ))
    {
        Slapi_Backend *be = slapi_be_select(sdn);
        search_base = slapi_sdn_get_dn( sdn );

        for(i = 3; argv[i] != NULL; i++){
            filter = slapi_filter_sprintf("(%s=*%s%s)", argv[i], ESC_NEXT_VAL, origDN);
            if ( filter ) {
                /* Need only the current attribute and its subtypes */
                attrs[0] = argv[i];
                attrs[1] = NULL;

                /* Use new search API */
                slapi_pblock_init(search_result_pb);
                slapi_pblock_set(search_result_pb, SLAPI_BACKEND, be);
                slapi_search_internal_set_pb(search_result_pb, search_base, 
                    LDAP_SCOPE_SUBTREE, filter, attrs, 0 /* attrs only */,
                    NULL, NULL, referint_plugin_identity, 0);
                slapi_search_internal_pb(search_result_pb);
  
                slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);

                /* if search successfull then do integrity update */
                if(search_result == LDAP_SUCCESS)
                {
                    slapi_pblock_get(search_result_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
                                     &search_entries);

                    for(j = 0; search_entries[j] != NULL; j++){
                        attr = NULL;
                        attrName = NULL;
                        /*
                         *  Loop over all the attributes of the entry and search
                         *  for the integrity attribute and its subtypes
                         */
                        for (slapi_entry_first_attr(search_entries[j], &attr); attr; 
                             slapi_entry_next_attr(search_entries[j], attr, &attr))
                        {
                            /*
                             *  Take into account only the subtypes of the attribute
                             *  in argv[i] having the necessary value  - origDN
                             */
                            slapi_attr_get_type(attr, &attrName);
                            if (slapi_attr_type_cmp(argv[i], attrName,
                                                    SLAPI_TYPE_CMP_SUBTYPE) == 0)
                            {
                                nval = 0;
                                slapi_attr_get_numvalues(attr, &nval);
                                /* 
                                 * We want to reduce the "modify" call as much as
                                 * possible. But if an entry contains 1000s of 
                                 * attributes which need to be updated by the 
                                 * referint plugin (e.g., a group containing 1000s 
                                 * of members), we want to avoid to allocate too 
                                 * many mods * in one "modify" call.
                                 * This is a compromise: If an attribute type has
                                 * more than 128 values, we update the attribute 
                                 * value one by one. Otherwise, update all values
                                 * in one "modify" call.
                                 */
                                if (nval > 128) {
                                    rc = _update_one_per_mod(
                                         slapi_entry_get_sdn(search_entries[j]),
                                         attr, attrName, origSDN, newrDN, 
                                         slapi_sdn_get_dn(newsuperior),
                                         mod_pb);
                                } else {
                                    rc = _update_all_per_mod(
                                         slapi_entry_get_sdn(search_entries[j]),
                                         attr, attrName, origSDN, newrDN, 
                                         slapi_sdn_get_dn(newsuperior),
                                         mod_pb);
                                }
                                /* Should we stop if one modify returns an error? */
                            }
                        }
                    }
                } else {
                    if (isFatalSearchError(search_result)){
                        slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
                            "update_integrity search (base=%s filter=%s) returned "
                            "error %d\n", search_base, filter, search_result);
                        rc = -1;
                        goto free_and_return;
                    }
                }
                slapi_ch_free_string(&filter);
            }
            slapi_free_search_results_internal(search_result_pb);
        }
    }
    /* if got here, then everything good rc = 0 */
    rc = 0;

free_and_return:
    /* free filter and search_results_pb */
    slapi_ch_free_string(&filter);

    slapi_pblock_destroy(mod_pb);
    if (search_result_pb) {
        slapi_free_search_results_internal(search_result_pb);
        slapi_pblock_destroy(search_result_pb);
    }
 
    return(rc);
}
Example #9
0
/*
 * Read and load configuration.  Validation will also
 * be performed unless skip_validate is set to non-0.
 * Returns PAM_PASSTHRU_SUCCESS if all is well.
 */
int
pam_passthru_load_config(int skip_validate)
{
    int status = PAM_PASSTHRU_SUCCESS;
    int result;
    int i;
    int alternate = 0;
    Slapi_PBlock *search_pb;
    Slapi_Entry **entries = NULL;

    slapi_log_err(SLAPI_LOG_TRACE, PAM_PASSTHRU_PLUGIN_SUBSYSTEM,
                     "=> pam_passthru_load_config\n");

    pam_passthru_write_lock();
    pam_passthru_delete_config();

    search_pb = slapi_pblock_new();

    /* Find all entries in the active config area. */
    slapi_search_internal_set_pb(search_pb, slapi_sdn_get_ndn(pam_passthru_get_config_area()),
                                 LDAP_SCOPE_SUBTREE, "objectclass=*",
                                 NULL, 0, NULL, NULL,
                                 pam_passthruauth_get_plugin_identity(), 0);
    slapi_search_internal_pb(search_pb);
    slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);

    if (LDAP_SUCCESS != result) {
        status = PAM_PASSTHRU_FAILURE;
        goto cleanup;
    }

    slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
                     &entries);
    if (NULL == entries || NULL == entries[0]) {
        status = PAM_PASSTHRU_FAILURE;
        goto cleanup;
    }

    /* Check if we are using an alternate config area.  We do this here
     * so we don't have to check each every time in the loop below. */
    if (slapi_sdn_compare(pam_passthru_get_config_area(),
            pam_passthruauth_get_plugin_sdn()) != 0) {
        alternate = 1;
    }

    /* Validate and apply config if valid.  If skip_validate is set, we skip
     * validation and just apply the config.  This should only be done if the
     * configuration has already been validated. */
    for (i = 0; (entries[i] != NULL); i++) {
        /* If this is the alternate config container, skip it since
         * we don't consider it to be an actual config entry. */
        if (alternate && (slapi_sdn_compare(pam_passthru_get_config_area(),
                slapi_entry_get_sdn(entries[i])) == 0)) {
            continue;
        }

        if (skip_validate || (PAM_PASSTHRU_SUCCESS == pam_passthru_validate_config(entries[i], NULL))) {
            if (PAM_PASSTHRU_FAILURE == pam_passthru_apply_config(entries[i])) {
                slapi_log_err(SLAPI_LOG_ERR, PAM_PASSTHRU_PLUGIN_SUBSYSTEM,
                                 "pam_passthru_load_config - Unable to apply config "
                                 "for entry \"%s\"\n", slapi_entry_get_ndn(entries[i]));
            }
        } else {
            slapi_log_err(SLAPI_LOG_ERR, PAM_PASSTHRU_PLUGIN_SUBSYSTEM,
                             "pam_passthru_load_config - Skipping invalid config "
                             "entry \"%s\"\n", slapi_entry_get_ndn(entries[i]));
        }
    }

  cleanup:
    slapi_free_search_results_internal(search_pb);
    slapi_pblock_destroy(search_pb);
    pam_passthru_unlock();
    slapi_log_err(SLAPI_LOG_TRACE, PAM_PASSTHRU_PLUGIN_SUBSYSTEM,
                    "<= pam_passthru_load_config\n");

    return status;
}
Example #10
0
File: add.c Project: 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);
}
Example #11
0
File: uid.c Project: ohamada/389ds
/*
 * preop_modrdn - Pre-operation call for modify RDN
 *
 * Check that the new RDN does not include attributes that
 * cause a constraint violation
 */
static int
preop_modrdn(Slapi_PBlock *pb)
{
  int result = LDAP_SUCCESS;
  Slapi_Entry *e = NULL;
  Slapi_Value *sv_requiredObjectClass = NULL;
  char *errtext = NULL;
  char *attrName = NULL;

#ifdef DEBUG
    slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
      "MODRDN begin\n");
#endif

  BEGIN
    int err;
    char *markerObjectClass=NULL;
    char *requiredObjectClass=NULL;
    Slapi_DN *sdn = NULL;
    Slapi_DN *superior;
    char *rdn;
    int deloldrdn = 0;
    int isupdatedn;
    Slapi_Attr *attr;
    int argc;
    char **argv = NULL;

        /*
         * If this is a replication update, just be a noop.
         */
        err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
    if (err) { result = uid_op_error(30); break; }
        if (isupdatedn)
        {
          break;
        }

    /*
     * Get the arguments
     */
        result = getArguments(pb, &attrName, &markerObjectClass,
                                                  &requiredObjectClass);
        if (UNTAGGED_PARAMETER == result)
        {
          result = LDAP_SUCCESS;
          /* Statically defined subtrees to monitor */
          err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
          if (err) { result = uid_op_error(53); break; }

          err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
          if (err) { result = uid_op_error(54); break; }
          argc--; /* First argument was attribute name */
          argv++; 
        } else if (0 != result)
        {
          break;
        }

    /* Create a Slapi_Value for the requiredObjectClass to use
     * for checking the entry. */
    if (requiredObjectClass) {
        sv_requiredObjectClass = slapi_value_new_string(requiredObjectClass);
    }

    /* Get the DN of the entry being renamed */
    err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET_SDN, &sdn);
    if (err) { result = uid_op_error(31); break; }

    /* Get superior value - unimplemented in 3.0/4.0/5.0 DS */
    err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &superior);
    if (err) { result = uid_op_error(32); break; }

    /*
     * No superior means the entry is just renamed at
     * its current level in the tree.  Use the target DN for
     * determining which managed tree this belongs to
     */
    if (!superior) superior = sdn;

    /* Get the new RDN - this has the attribute values */
    err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &rdn);
    if (err) { result = uid_op_error(33); break; }
#ifdef DEBUG
    slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
      "MODRDN newrdn=%s\n", rdn);
#endif

    /* See if the old RDN value is being deleted. */
    err = slapi_pblock_get(pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn);
    if (err) { result = uid_op_error(34); break; }

    /* Get the entry that is being renamed so we can make a dummy copy
     * of what it will look like after the rename. */
    err = slapi_search_internal_get_entry(sdn, NULL, &e, plugin_identity);
    if (err != LDAP_SUCCESS) {
        result = uid_op_error(35);
        /* We want to return a no such object error if the target doesn't exist. */
        if (err == LDAP_NO_SUCH_OBJECT) {
            result = err;
        }
        break;
    }

    /* Apply the rename operation to the dummy entry. */
    /* slapi_entry_rename does not expect rdn normalized */
    err = slapi_entry_rename(e, rdn, deloldrdn, superior);
    if (err != LDAP_SUCCESS) { result = uid_op_error(36); break; }

        /*
         * Find any unique attribute data in the new RDN
         */
        err = slapi_entry_attr_find(e, attrName, &attr);
        if (err) break;  /* no UID attribute */

        /*
         * Check if it has the required object class
         */
        if (requiredObjectClass &&
            !slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sv_requiredObjectClass)) { break; }

        /*
         * Passed all the requirements - this is an operation we
         * need to enforce uniqueness on. Now find all parent entries
         * with the marker object class, and do a search for each one.
         */
        if (NULL != markerObjectClass)
        {
          /* Subtree defined by location of marker object class */
                result = findSubtreeAndSearch(slapi_entry_get_sdn(e), attrName, attr, NULL,
                                              requiredObjectClass, sdn,
                                              markerObjectClass);
        } else
        {
          /* Subtrees listed on invocation line */
          result = searchAllSubtrees(argc, argv, attrName, attr, NULL,
                                     requiredObjectClass, sdn);
        }
  END
  /* Clean-up */
  slapi_value_free(&sv_requiredObjectClass);
  if (e) slapi_entry_free(e);

  if (result)
  {
    slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
      "MODRDN result %d\n", result);

    if (result == LDAP_CONSTRAINT_VIOLATION) {
      errtext = slapi_ch_smprintf(moreInfo, attrName);
    } else {
      errtext = slapi_ch_strdup("Error checking for attribute uniqueness.");
    }

    slapi_send_ldap_result(pb, result, 0, errtext, 0, 0);

    slapi_ch_free_string(&errtext);
  }

  return (result==LDAP_SUCCESS)?0:-1;

}
Example #12
0
File: uid.c Project: ohamada/389ds
static int
search_one_berval(Slapi_DN *baseDN, const char *attrName,
		const struct berval *value, const char *requiredObjectClass,
		Slapi_DN *target)
{
	int result;
    char *filter;
    Slapi_PBlock *spb;

	result = LDAP_SUCCESS;

	/* If no value, can't possibly be a conflict */
	if ( (struct berval *)NULL == value )
		return result;

    filter = 0;
    spb = 0;

    BEGIN
      int err;
      int sres;
      Slapi_Entry **entries;
      static char *attrs[] = { "1.1", 0 };

      /* Create the filter - this needs to be freed */
      filter = create_filter(attrName, value, requiredObjectClass);

#ifdef DEBUG
      slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
        "SEARCH filter=%s\n", filter);
#endif

      /* Perform the search using the new internal API */
      spb = slapi_pblock_new();
      if (!spb) { result = uid_op_error(2); break; }

      slapi_search_internal_set_pb_ext(spb, baseDN, LDAP_SCOPE_SUBTREE,
      	filter, attrs, 0 /* attrs only */, NULL, NULL, plugin_identity, 0 /* actions */);
      slapi_search_internal_pb(spb);

      err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_RESULT, &sres);
      if (err) { result = uid_op_error(3); break; }
    
      /* Allow search to report that there is nothing in the subtree */
      if (sres == LDAP_NO_SUCH_OBJECT) break;

      /* Other errors are bad */
      if (sres) { result = uid_op_error(3); break; }

      err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
              &entries);
      if (err) { result = uid_op_error(4); break; }

      /*
       * Look at entries returned.  Any entry found must be the
       * target entry or the constraint fails.
       */
      for(;*entries;entries++)
      {
#ifdef DEBUG
        slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
                        "SEARCH entry dn=%s\n", slapi_entry_get_dn(*entries));
#endif

        /*
         * It is a Constraint Violation if any entry is found, unless
         * the entry is the target entry (if any).
         */
        if (!target || slapi_sdn_compare(slapi_entry_get_sdn(*entries), target) != 0)
        {
          result = LDAP_CONSTRAINT_VIOLATION;
          break;
        }
      }

#ifdef DEBUG
      slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
        "SEARCH complete result=%d\n", result);
#endif
    END

    /* Clean-up */
    if (spb) {
	slapi_free_search_results_internal(spb);
	slapi_pblock_destroy(spb);
    }

    slapi_ch_free((void**)&filter);

  return result;
}
Example #13
0
File: urp.c Project: 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;
}
Example #14
0
File: urp.c Project: 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;
}
Example #15
0
File: urp.c Project: ohamada/389ds
static int
is_suffix_entry ( Slapi_PBlock *pb, Slapi_Entry *entry, Slapi_DN **parentdn )
{
	return is_suffix_dn ( pb, slapi_entry_get_sdn(entry), parentdn );
}
Example #16
0
/*
 * Get a Slapi_Entry ready to send over the wire as part of
 * a total update protocol stream. Convert the entry and all
 * of its state information to a BerElement which will be the
 * payload of an extended LDAP operation.
 *
 * Entries consist of:
 * - An entry DN
 * - A uniqueID
 * - A set of present attributes, each of which consists of:
 *   - A set of present values, each of which consists of:
 *     - A value
 *     - A set of CSNs
 *   - A set of deleted values, each of which consists of:
 *     - A value
 *     - A set of CSNs
 * - A set of deleted attibutes, each of which consists of:
 *   - An attribute type
 *   - A set of CSNs. Note that this list of CSNs will always contain exactly one CSN.
 * 
 * This all gets mashed into one BerElement, ready to be blasted over the wire to
 * a replica.
 *
 */
BerElement *
entry2bere(const Slapi_Entry *e, char **excluded_attrs)
{
	BerElement *ber = NULL;
	const char *str = NULL;
	const char *dnstr = NULL;
    char *type;
	Slapi_DN *sdn = NULL;
	Slapi_Attr *attr = NULL, *prev_attr;
    int rc;

	PR_ASSERT(NULL != e);

	if ((ber = ber_alloc()) == NULL)
	{
		goto loser;
	}
	BER_DEBUG("{");
	if (ber_printf(ber, "{") == -1) /* Begin outer sequence */
	{
		goto loser;
	}

	/* Get the entry's uniqueid */
	if ((str = slapi_entry_get_uniqueid(e)) == NULL)
	{
		goto loser;
	}
	BER_DEBUG("s(uniqueid)");
	if (ber_printf(ber, "s", str) == -1)
	{
		goto loser;
	}

	/* Get the entry's DN */
	if ((sdn = slapi_entry_get_sdn((Slapi_Entry *)e)) == NULL) /* XXXggood had to cast away const */
	{
		goto loser;
	}
	if ((dnstr = slapi_sdn_get_dn(sdn)) == NULL)
	{
		goto loser;
	}
	BER_DEBUG("s(dn)");
	if (ber_printf(ber, "s", dnstr) == -1)
	{
		goto loser;
	}

	/* Next comes the annoted list of the entry's attributes */
	BER_DEBUG("[");
	if (ber_printf(ber, "[") == -1) /* Begin set of attributes */
	{
		goto loser;
	}
	/*
	 * We iterate over all of the non-deleted attributes first.
	 */ 
	slapi_entry_first_attr(e, &attr);
	while (NULL != attr)
	{
        /* ONREPL - skip uniqueid attribute since we already sent uniqueid 
           This is a hack; need to figure a better way of storing uniqueid
           in an entry */
        slapi_attr_get_type (attr, &type);
        if (strcasecmp (type, SLAPI_ATTR_UNIQUEID) != 0)
        {
			/* Check to see if this attribute is excluded by the fractional list */
			if ( (NULL == excluded_attrs) || !charray_inlist(excluded_attrs,type)) 
			{
				/* Process this attribute */
				rc = my_ber_printf_attr (ber, attr, PR_FALSE);
				if (rc != 0)
				{
					goto loser;
				}
			}
        }
		
		prev_attr = attr;
		slapi_entry_next_attr(e, prev_attr, &attr);
	}

	/*
	 * Now iterate over the deleted attributes.
	 */ 
	entry_first_deleted_attribute(e, &attr);
	while (attr != NULL)
	{
		slapi_attr_get_type (attr, &type);
		/* Check to see if this attribute is excluded by the fractional list */
		if ( (NULL == excluded_attrs) || !charray_inlist(excluded_attrs,type)) 
		{
			/* Process this attribute */
			rc = my_ber_printf_attr (ber, attr, PR_TRUE);
			if (rc != 0)
			{
				goto loser;
			}
		}
		entry_next_deleted_attribute(e, &attr);
	}
	BER_DEBUG("]");
	if (ber_printf(ber, "]") == -1) /* End set for attributes */
	{
		goto loser;
	}
	BER_DEBUG("}");
	if (ber_printf(ber, "}") == -1) /* End sequence for this entry */
	{
		goto loser;
	}
	
	/* If we get here, everything went ok */
	BER_DEBUG("\n");
	goto free_and_return;
loser:
	if (NULL != ber)
	{
		ber_free(ber, 1);
		ber = NULL;
	}

free_and_return:
	return ber;
}