예제 #1
0
void
be_unbindall(Connection *conn, Operation *op)
{
    int     i;
    Slapi_PBlock pb = {0};

    for ( i = 0; i < maxbackends; i++ )
    {
        if ( backends[i] && (backends[i]->be_unbind != NULL) )
        {
            /* This is the modern, and faster way to do pb memset(0) 
             * It also doesn't trigger the HORRIBLE stack overflows I found ...
             */
            pblock_init_common( &pb, backends[i], conn, op );

            if ( plugin_call_plugins( &pb, SLAPI_PLUGIN_PRE_UNBIND_FN ) == 0 )
            {
                int rc = 0;
                slapi_pblock_set( &pb, SLAPI_PLUGIN, backends[i]->be_database );
                if(backends[i]->be_state != BE_STATE_DELETED && 
                   backends[i]->be_unbind!=NULL)
                {
                    rc = (*backends[i]->be_unbind)( &pb );
                }
                slapi_pblock_set( &pb, SLAPI_PLUGIN_OPRETURN, &rc );
                (void) plugin_call_plugins( &pb, SLAPI_PLUGIN_POST_UNBIND_FN );
            }
        }
    }
}
예제 #2
0
파일: compare.c 프로젝트: Firstyear/ds
void
do_compare( Slapi_PBlock *pb )
{
	BerElement	*ber = pb->pb_op->o_ber;
	char		*rawdn = NULL;
	const char	*dn = NULL;
	struct ava	ava = {0};
	Slapi_Backend		*be = NULL;
	int		err;
	Slapi_DN sdn;
	Slapi_Entry *referral = NULL;
	char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];

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

	/* count the compare request */
	slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsCompareOps);

    /* have to init this here so we can "done" it below if we short circuit */
    slapi_sdn_init(&sdn);

	/*
	 * Parse the compare request.  It looks like this:
	 *
	 *	CompareRequest := [APPLICATION 14] SEQUENCE {
	 *		entry	DistinguishedName,
	 *		ava	SEQUENCE {
	 *			type	AttributeType,
	 *			value	AttributeValue
	 *		}
	 *	}
	 */

	if ( ber_scanf( ber, "{a{ao}}", &rawdn, &ava.ava_type,
	    &ava.ava_value ) == LBER_ERROR ) {
		slapi_log_err(SLAPI_LOG_ERR,
		    "do_compare", "ber_scanf failed (op=Compare; params=DN,Type,Value)\n");
		send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
			NULL );
		goto free_and_return;
	}
	/* Check if we should be performing strict validation. */
	if (config_get_dn_validate_strict()) {
		/* check that the dn is formatted correctly */
		err = slapi_dn_syntax_check(pb, rawdn, 1);
		if (err) { /* syntax check failed */
			op_shared_log_error_access(pb, "CMP",
							rawdn?rawdn:"", "strict: invalid dn");
			send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, 
							 NULL, "invalid dn", 0, NULL);
			slapi_ch_free((void **) &rawdn);
			return;
		}
	}
	slapi_sdn_init_dn_passin(&sdn, rawdn);
	dn = slapi_sdn_get_dn(&sdn);
    if (rawdn && (strlen(rawdn) > 0) && (NULL == dn)) {
        /* normalization failed */
        op_shared_log_error_access(pb, "CMP", rawdn, "invalid dn");
        send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL,
                         "invalid dn", 0, NULL);
        slapi_sdn_done(&sdn);
        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 ) {
		send_ldap_result( pb, err, NULL, NULL, 0, NULL );
		goto free_and_return;
	}

	/* target spec is used to decide which plugins are applicable for the operation */
	operation_set_target_spec (pb->pb_op, &sdn);

	slapi_log_err(SLAPI_LOG_ARGS, "do_compare: dn (%s) attr (%s)\n",
	    rawdn, ava.ava_type, 0 );

	slapi_log_access( LDAP_DEBUG_STATS,
	    "conn=%" NSPRIu64 " op=%d CMP dn=\"%s\" attr=\"%s\"\n",
	    pb->pb_conn->c_connid, pb->pb_op->o_opid, dn, ava.ava_type );

	/*
	 * 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 free_and_return;
	}

	if (referral)
	{
		int managedsait;

		slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
		if (managedsait)
		{
			send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
					"cannot compare referral", 0, NULL);
			slapi_entry_free(referral);
			goto free_and_return;
		}
	
		send_referrals_from_entry(pb,referral);
		slapi_entry_free(referral);
		goto free_and_return;
	}

	if ( be->be_compare != NULL ) {
		int		isroot;
		    
		slapi_pblock_set( pb, SLAPI_BACKEND, be );
		isroot = pb->pb_op->o_isroot;

		slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
		/* EXCEPTION: compare target does not allocate memory. */
		/* target never be modified by plugins. */
		slapi_pblock_set( pb, SLAPI_COMPARE_TARGET_SDN, (void*)&sdn );
		slapi_pblock_set( pb, SLAPI_COMPARE_TYPE, ava.ava_type);
		slapi_pblock_set( pb, SLAPI_COMPARE_VALUE, &ava.ava_value );
		/*
		 * call the pre-compare plugins. if they succeed, call
		 * the backend compare function. then call the
		 * post-compare plugins.
		 */
		if ( plugin_call_plugins( pb,
				SLAPI_PLUGIN_PRE_COMPARE_FN ) == 0 ) {
			int	rc;

			slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database );
			set_db_default_result_handlers(pb);
			rc = (*be->be_compare)( pb );

			slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc );
			plugin_call_plugins( pb, SLAPI_PLUGIN_POST_COMPARE_FN );
		}
	} else {
		send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
		    "Function not implemented", 0, NULL );
	}

free_and_return:;
	if (be)
		slapi_be_Unlock(be);
	slapi_sdn_done(&sdn);
	ava_done( &ava );
}
예제 #3
0
파일: modrdn.c 프로젝트: ohamada/389ds
/*
 * op_shared_rename() -- common frontend code for modDN operations.
 *
 * Beware: this function resets the following pblock elements that were
 * set by the caller:
 *
 *	SLAPI_MODRDN_TARGET_SDN
 *	SLAPI_MODRDN_NEWRDN
 *	SLAPI_MODRDN_NEWSUPERIOR_SDN
 */
static void
op_shared_rename(Slapi_PBlock *pb, int passin_args)
{
	char			*dn, *newrdn, *newdn = NULL;
	const char		*newsuperior;
	char			**rdns;
	int				deloldrdn;
	Slapi_Backend	*be = NULL;
	Slapi_DN		*origsdn = NULL;
	Slapi_Mods		smods;
	int				internal_op, repl_op, lastmod;
	Slapi_Operation *operation;
	Slapi_Entry *referral;
	char errorbuf[BUFSIZ];
	int			err;
	char			*proxydn = NULL;
	char			*proxystr = NULL;
	int			proxy_err = LDAP_SUCCESS;
	char			*errtext = NULL;
	Slapi_DN *sdn = NULL;
	Slapi_DN *newsuperiorsdn = NULL;

	slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET, &dn);
	slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &newrdn);
	slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperiorsdn);
	slapi_pblock_get(pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn);
	slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
	slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
	slapi_pblock_get(pb, SLAPI_MODRDN_TARGET_SDN, &origsdn);
	internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);

	/*
	 * If ownership has not been passed to this function, we replace the
	 * string input fields within the pblock with strdup'd copies.  Why?
	 * Because some pre- and post-op plugins may change them, and the
	 * convention is that plugins should place a malloc'd string in the
	 * pblock.  Therefore, we need to be able to retrieve and free them
	 * later.  But the callers of the internal modrdn calls are promised
	 * that we will not free these parameters... so if passin_args is
	 * zero, we need to make copies.
	 *
	 * In the case of SLAPI_MODRDN_TARGET_SDN and SLAPI_MODRDN_NEWSUPERIOR_SDN,
	 * we replace the existing values with normalized values (because plugins
	 * expect these DNs to be normalized).
	 */

	if (NULL == origsdn) {
		sdn = slapi_sdn_new_dn_byval(dn);
		slapi_pblock_set(pb, SLAPI_MODRDN_TARGET_SDN, sdn);
    }
	if (passin_args) {
		if (NULL == sdn) { /* origsdn is not NULL, so use it. */
			sdn = origsdn;
		}
	} else {
		if (NULL == sdn) {
			sdn = slapi_sdn_dup(origsdn);
		}
		newrdn = slapi_ch_strdup(newrdn);
		newsuperiorsdn = slapi_sdn_dup(newsuperiorsdn);
		slapi_pblock_set(pb, SLAPI_MODRDN_TARGET_SDN, sdn);
		slapi_pblock_set(pb, SLAPI_MODRDN_NEWRDN, (void *)newrdn);
		slapi_pblock_set(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, newsuperiorsdn);
	}
	/* normdn = slapi_sdn_get_dn(sdn); */
	newsuperior = slapi_sdn_get_dn(newsuperiorsdn);

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

	/*
	 * first, log the operation to the access log,
	 * then check rdn and newsuperior,
	 * and - if applicable - log reason of any error to the errors log
	 */
	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 MODRDN dn=\"%s\" newrdn=\"%s\" newsuperior=\"%s\"%s\n",
					 pb->pb_conn->c_connid, 
					 pb->pb_op->o_opid,
					 dn,
					 newrdn ? newrdn : "(null)",
					 newsuperior ? newsuperior : "(null)",
					 proxystr ? proxystr : "");
		}
		else
		{
			slapi_log_access(LDAP_DEBUG_ARGS,
					 "conn=%s op=%d MODRDN dn=\"%s\" newrdn=\"%s\" newsuperior=\"%s\"%s\n",
					 LOG_INTERNAL_OP_CON_ID,
					 LOG_INTERNAL_OP_OP_ID,
					 dn,
					 newrdn ? newrdn : "(null)",
					 newsuperior ? newsuperior : "(null)",
					 proxystr ? proxystr : "");
		}
	}

	/* 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 free_and_return_nolock;
	}

	/* check that the rdn is formatted correctly */
	if ((rdns = slapi_ldap_explode_rdn(newrdn, 0)) == NULL) 
	{
		if ( !internal_op ) {
			slapi_log_error(SLAPI_LOG_ARGS, NULL, 
				 "conn=%" NSPRIu64 " op=%d MODRDN invalid new RDN (\"%s\")\n",
				 pb->pb_conn->c_connid,
				 pb->pb_op->o_opid,
				 (NULL == newrdn) ? "(null)" : newrdn);
		} else {
			slapi_log_error(SLAPI_LOG_ARGS, NULL, 
				 "conn=%s op=%d MODRDN invalid new RDN (\"%s\")\n",
				 LOG_INTERNAL_OP_CON_ID,
				 LOG_INTERNAL_OP_OP_ID,
				 (NULL == newrdn) ? "(null)" : newrdn);
		}
		send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid RDN", 0, NULL);
		goto free_and_return_nolock;
	} 
	else 
	{
		slapi_ldap_value_free(rdns);
	}

	/* check if created attributes are used in the new RDN */
	/* check_rdn_for_created_attrs ignores the cases */
	if (check_rdn_for_created_attrs((const char *)newrdn)) {
		send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid attribute in RDN", 0, NULL);
		goto free_and_return_nolock;
	}

	/* check that the dn is formatted correctly */
	err = slapi_dn_syntax_check(pb, newsuperior, 1);
	if (err)
	{
		LDAPDebug0Args(LDAP_DEBUG_ARGS, "Syntax check of newSuperior failed\n");
		if (!internal_op) {
			slapi_log_error(SLAPI_LOG_ARGS, NULL,
				 "conn=%" NSPRIu64 " op=%d MODRDN invalid new superior (\"%s\")",
				 pb->pb_conn->c_connid,
				 pb->pb_op->o_opid,
				 newsuperior ? newsuperior : "(null)");
		} else {
			slapi_log_error(SLAPI_LOG_ARGS, NULL,
				 "conn=%s op=%d MODRDN invalid new superior (\"%s\")",
				 LOG_INTERNAL_OP_CON_ID,
				 LOG_INTERNAL_OP_OP_ID,
				 newsuperior ? newsuperior : "(null)");
		}
		send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL,
						 "newSuperior does not look like a DN", 0, NULL);
		goto free_and_return_nolock;
	} 

	if (newsuperior != NULL) 
	{
		LDAPDebug(LDAP_DEBUG_ARGS, "do_moddn: newsuperior (%s)\n", newsuperior, 0, 0);
	}

	/* target spec is used to decide which plugins are applicable for the operation */
	operation_set_target_spec (pb->pb_op, sdn);

	/*
	 * Construct the new DN (code sdn from backend
	 * and modified to handle newsuperior)
	 */
	newdn = slapi_moddn_get_newdn(sdn, newrdn, newsuperior);

	/*
	 * We could be serving multiple database backends.  Select the
	 * appropriate one, or send a referral to our "referral server"
	 * if we don't hold it.
	 */
	/* slapi_mapping_tree_select_and_check ignores the case of newdn
	 * which is generated using newrdn above. */
	if ((err = slapi_mapping_tree_select_and_check(pb, newdn, &be, &referral, errorbuf)) != LDAP_SUCCESS)
	{
		send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
		goto free_and_return_nolock;
	}

	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 free_and_return;
		}
	
		send_referrals_from_entry(pb,referral);
		slapi_entry_free(referral);
		goto free_and_return;
	}

	slapi_pblock_set(pb, SLAPI_BACKEND, be);

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

	/* if it is a replicated operation - leave lastmod attributes alone */
	slapi_mods_init (&smods, 2);
	if (!repl_op && lastmod)
	{
		modify_update_last_modified_attr(pb, &smods);
		slapi_pblock_set(pb, SLAPI_MODIFY_MODS, (void*)slapi_mods_get_ldapmods_passout(&smods));
	}
	else {
		slapi_mods_done (&smods);
	}

	/*
	 * call the pre-modrdn plugins. if they succeed, call
	 * the backend modrdn function. then call the
	 * post-modrdn plugins.
	 */
	if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN :
							SLAPI_PLUGIN_PRE_MODRDN_FN) == 0)
	{
		int	rc= LDAP_OPERATIONS_ERROR;
		slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
		set_db_default_result_handlers(pb);
		if (be->be_modrdn != NULL)
		{
			if ((rc = (*be->be_modrdn)(pb)) == 0)
			{
				Slapi_Entry	*pse;
				Slapi_Entry	*ecopy;
				/* we don't perform acl check for internal operations */
				/* dont 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_MODRDN);

				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);
				slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
				/* GGOODREPL persistent search system needs the changenumber, oops. */
				do_ps_service(pse, ecopy, LDAP_CHANGETYPE_MODDN, 0);
			}
		}
		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_MODRDN_FN : 
							SLAPI_PLUGIN_POST_MODRDN_FN);
	}

free_and_return:
	if (be)
		slapi_be_Unlock(be);
free_and_return_nolock:
	{
		/* Free up everything left in the PBlock */
		Slapi_Entry	*pse;
		Slapi_Entry	*ecopy;
		LDAPMod **mods;
		char	*s;

		if (passin_args) {
			if (NULL == origsdn) {
				slapi_sdn_free(&sdn);
			}
		} else {
			slapi_pblock_get(pb, SLAPI_MODRDN_TARGET_SDN, &sdn);
			slapi_sdn_free(&sdn);
			/* get newrdn to free the string */
			slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &newrdn);
			slapi_ch_free_string(&newrdn);
			slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperiorsdn);
			slapi_sdn_free(&newsuperiorsdn);
		}
		slapi_ch_free_string(&newdn);

		slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
		slapi_entry_free(ecopy);
		slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
		slapi_entry_free(pse);
		slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
		ldap_mods_free( mods, 1 );
		slapi_ch_free_string(&proxydn);
		slapi_ch_free_string(&proxystr);

		slapi_pblock_get(pb, SLAPI_URP_NAMING_COLLISION_DN, &s);
		slapi_ch_free((void **)&s);
	}
}
예제 #4
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);
}
예제 #5
0
파일: delete.c 프로젝트: leto/389-ds
static void op_shared_delete (Slapi_PBlock *pb)
{
	char			*rawdn = NULL;
	const char		*dn = NULL;
	Slapi_Backend	*be = NULL;
	int				internal_op;
	Slapi_DN		*sdn = NULL;
	Slapi_Operation *operation;
	Slapi_Entry *referral;
	Slapi_Entry	*ecopy = NULL;
	char errorbuf[BUFSIZ];
	int				err;
	char		*proxydn = NULL;
	char		*proxystr = NULL;
	int		proxy_err = LDAP_SUCCESS;
	char		*errtext = NULL;

	slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET, &rawdn);
	slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
	internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);

	sdn = slapi_sdn_new_dn_byval(rawdn);
	dn = slapi_sdn_get_dn(sdn);
	slapi_pblock_set(pb, SLAPI_DELETE_TARGET_SDN, (void*)sdn);
	if (rawdn && (strlen(rawdn) > 0) && (NULL == dn)) {
		/* normalization failed */
		op_shared_log_error_access(pb, "DEL", rawdn, "invalid dn");
		send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, 
		                 NULL, "invalid dn", 0, NULL);
		goto free_and_return;
	}

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

	/* 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 DEL dn=\"%s\"%s\n",
							pb->pb_conn->c_connid, 
							pb->pb_op->o_opid,
							slapi_sdn_get_dn(sdn),
							proxystr ? proxystr: "");
		}
		else
		{
			slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d DEL dn=\"%s\"%s\n",
							LOG_INTERNAL_OP_CON_ID,
							LOG_INTERNAL_OP_OP_ID,
							slapi_sdn_get_dn(sdn),
							proxystr ? proxystr: "");
		}
	}

	/* 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 free_and_return;
	}

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

	if (referral)
	{
		int managedsait;

		slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
		if (managedsait)
		{
			send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
					"cannot delete referral", 0, NULL);
			slapi_entry_free(referral);
			goto free_and_return;
		}
	
		send_referrals_from_entry(pb,referral);
		slapi_entry_free(referral);
		goto free_and_return;
	}

	slapi_pblock_set(pb, SLAPI_BACKEND, be);			

	/*
	 * call the pre-delete plugins. if they succeed, call
	 * the backend delete function. then call the
	 * post-delete plugins.
	 */
	if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN : 
							SLAPI_PLUGIN_PRE_DELETE_FN) == 0)
	{
		int	rc;

		slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
		set_db_default_result_handlers(pb);
		if (be->be_delete != NULL)
		{
			if ((rc = (*be->be_delete)(pb)) == 0)
			{
				/* we don't perform acl check for internal operations */
				/* Dont 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_DELETE);

				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_PRE_OP, &ecopy);
				do_ps_service(ecopy, NULL, LDAP_CHANGETYPE_DELETE, 0);
			}
			else
			{
				if (rc == SLAPI_FAIL_DISKFULL)
				{
					operation_out_of_disk_space();
					goto free_and_return;
				}
			}
		}

		slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
		plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN :
							SLAPI_PLUGIN_POST_DELETE_FN);
	}

free_and_return:
	if (be) {
		slapi_be_Unlock(be);
	}
	{
		char *coldn = NULL;
		Slapi_Entry *epre = NULL, *eparent = NULL;
		slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &epre);
		slapi_pblock_get(pb, SLAPI_DELETE_GLUE_PARENT_ENTRY, &eparent);
		slapi_pblock_set(pb, SLAPI_ENTRY_PRE_OP, NULL);
		slapi_pblock_set(pb, SLAPI_DELETE_GLUE_PARENT_ENTRY, NULL);
		if (epre == eparent) {
			eparent = NULL;
		}
		slapi_entry_free(epre);
		slapi_entry_free(eparent);
		slapi_pblock_get(pb, SLAPI_URP_NAMING_COLLISION_DN, &coldn);
		slapi_ch_free_string(&coldn);
	}

	slapi_pblock_get(pb, SLAPI_DELETE_TARGET_SDN, &sdn);
	slapi_sdn_free(&sdn);
	slapi_ch_free_string(&proxydn);
	slapi_ch_free_string(&proxystr);
}
예제 #6
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;
}
예제 #7
0
파일: extendop.c 프로젝트: Firstyear/ds
void
do_extended( Slapi_PBlock *pb )
{
    char        *extoid = NULL, *errmsg;
    struct berval   extval = {0};
    struct slapdplugin *p = NULL;
    int     lderr, rc;
    ber_len_t   len;
    ber_tag_t   tag;
    const char  *name;

    slapi_log_err(SLAPI_LOG_TRACE, "do_extended", "->\n");

    /*
     * Parse the extended request. It looks like this:
     *
     *  ExtendedRequest := [APPLICATION 23] SEQUENCE {
     *      requestName [0] LDAPOID,
     *      requestValue    [1] OCTET STRING OPTIONAL
     *  }
     */

    if ( ber_scanf( pb->pb_op->o_ber, "{a", &extoid )
        == LBER_ERROR ) {
        slapi_log_err(SLAPI_LOG_ERR,
            "do_extended", "ber_scanf failed (op=extended; params=OID)\n");
        op_shared_log_error_access (pb, "EXT", "???", "decoding error: fail to get extension OID");
        send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
            NULL );
        goto free_and_return;
    }
    tag = ber_peek_tag(pb->pb_op->o_ber, &len);

    if (tag == LDAP_TAG_EXOP_REQ_VALUE) {
        if ( ber_scanf( pb->pb_op->o_ber, "o}", &extval ) == LBER_ERROR ) {
            op_shared_log_error_access (pb, "EXT", "???", "decoding error: fail to get extension value");
            send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
                              NULL );
            goto free_and_return;
        }
    } else {
        if ( ber_scanf( pb->pb_op->o_ber, "}") == LBER_ERROR ) {
            op_shared_log_error_access (pb, "EXT", "???", "decoding error"); 
            send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
                              NULL );
            goto free_and_return;
        }
    }
    if ( NULL == ( name = extended_op_oid2string( extoid ))) {
        slapi_log_err(SLAPI_LOG_ARGS, "do_extended", "oid (%s)\n", extoid);

        slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d EXT oid=\"%s\"\n",
                pb->pb_conn->c_connid, pb->pb_op->o_opid, extoid );
    } else {
        slapi_log_err(SLAPI_LOG_ARGS, "do_extended", "oid (%s-%s)\n",
                extoid, name);

        slapi_log_access( LDAP_DEBUG_STATS,
            "conn=%" NSPRIu64 " op=%d EXT oid=\"%s\" name=\"%s\"\n",
            pb->pb_conn->c_connid, pb->pb_op->o_opid, extoid, name );
    }

    /* during a bulk import, only BULK_IMPORT_DONE is allowed! 
     * (and this is the only time it's allowed)
     */
    if (pb->pb_conn->c_flags & CONN_FLAG_IMPORT) {
        if (strcmp(extoid, EXTOP_BULK_IMPORT_DONE_OID) != 0) {
            send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL);
            goto free_and_return;
        }
        extop_handle_import_done(pb, extoid, &extval);
        goto free_and_return;
    }
    
    if (strcmp(extoid, EXTOP_BULK_IMPORT_START_OID) == 0) {
        extop_handle_import_start(pb, extoid, &extval);
        goto free_and_return;
    }

    if (strcmp(extoid, START_TLS_OID) != 0) {
        int minssf = config_get_minssf();

        /* If anonymous access is disabled and we haven't
         * authenticated yet, only allow startTLS. */
        if ((config_get_anon_access_switch() != SLAPD_ANON_ACCESS_ON) && ((pb->pb_op->o_authtype == NULL) ||
                    (strcasecmp(pb->pb_op->o_authtype, SLAPD_AUTH_NONE) == 0))) {
            send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
                "Anonymous access is not allowed.", 0, NULL );
            goto free_and_return;
        }

        /* If the minssf is not met, only allow startTLS. */
        if ((pb->pb_conn->c_sasl_ssf < minssf) && (pb->pb_conn->c_ssl_ssf < minssf) &&
            (pb->pb_conn->c_local_ssf < minssf)) {
            send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
                "Minimum SSF not met.", 0, NULL );
            goto free_and_return;
        }
    }

    /* If a password change is required, only allow the password
     * modify extended operation */
    if (!pb->pb_conn->c_isreplication_session &&
                pb->pb_conn->c_needpw && (strcmp(extoid, EXTOP_PASSWD_OID) != 0))
    {
        char *dn = NULL;
        slapi_pblock_get(pb, SLAPI_CONN_DN, &dn);

        (void)slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
        op_shared_log_error_access (pb, "EXT", dn ? dn : "", "need new password");
        send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, NULL, 0, NULL );

        slapi_ch_free_string(&dn);
        goto free_and_return;
    }

    /* decode the optional controls - put them in the pblock */
    if ( (lderr = get_ldapmessage_controls( pb, pb->pb_op->o_ber, NULL )) != 0 )
    {
        char *dn = NULL;
        slapi_pblock_get(pb, SLAPI_CONN_DN, &dn);

        op_shared_log_error_access (pb, "EXT", dn ? dn : "", "failed to decode LDAP controls");
        send_ldap_result( pb, lderr, NULL, NULL, 0, NULL );

        slapi_ch_free_string(&dn);
        goto free_and_return;
    }

    slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_OID, extoid );
    slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_VALUE, &extval );
    slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot);

    rc = plugin_determine_exop_plugins( extoid, &p );
    slapi_log_err(SLAPI_LOG_TRACE, "do_extended", "Plugin_determine_exop_plugins rc %d\n", rc);

    if (plugin_call_plugins(pb, SLAPI_PLUGIN_PRE_EXTOP_FN) != SLAPI_PLUGIN_SUCCESS) {
        goto free_and_return;
    }

    if (rc == SLAPI_PLUGIN_EXTENDEDOP && p != NULL) {
        slapi_log_err(SLAPI_LOG_TRACE, "do_extended", "Calling plugin ... \n");
        /*
         * Return values:
         *  SLAPI_PLUGIN_EXTENDED_SENT_RESULT: The result is already sent to the client. 
         *                                     There is nothing to do further.
         *  SLAPI_PLUGIN_EXTENDED_NOT_HANDLED: Unsupported extended operation
         *  LDAP codes (e.g., LDAP_SUCCESS): The result is not sent yet. Call send_ldap_result.
         */
        rc = plugin_call_exop_plugins( pb, p);

        slapi_log_err(SLAPI_LOG_TRACE, "do_extended", "Called exop, got %d \n", rc);

    } else if (rc == SLAPI_PLUGIN_BETXNEXTENDEDOP && p != NULL) {

        slapi_log_err(SLAPI_LOG_TRACE, "do_extended", "Calling betxn plugin ... \n");
        /* Look up the correct backend to use. */
        Slapi_Backend *be = plugin_extended_op_getbackend( pb, p );

        if ( be == NULL ) {
            slapi_log_err(SLAPI_LOG_ERR, "do_extended", "Plugin_extended_op_getbackend was unable to retrieve a backend!\n");
            rc = LDAP_OPERATIONS_ERROR;
        } else {
            /* We need to make a new be pb here because when you set SLAPI_BACKEND
             * you overwrite the plg parts of the pb. So if we re-use pb
             * you actually nuke the request, and everything hangs. (╯°□°)╯︵ ┻━┻
             */
            Slapi_PBlock *be_pb = NULL;
            be_pb = slapi_pblock_new();
            slapi_pblock_set(be_pb, SLAPI_BACKEND, be);

            int txn_rc = slapi_back_transaction_begin(be_pb);
            if (txn_rc) {
                slapi_log_err(SLAPI_LOG_ERR, "do_extended", "Failed to start be_txn for plugin_call_exop_plugins %d\n", txn_rc);
            } else {
                /*
                 * Return values:
                 *  SLAPI_PLUGIN_EXTENDED_SENT_RESULT: The result is already sent to the client. 
                 *                                     There is nothing to do further.
                 *  SLAPI_PLUGIN_EXTENDED_NOT_HANDLED: Unsupported extended operation
                 *  LDAP codes (e.g., LDAP_SUCCESS): The result is not sent yet. Call send_ldap_result.
                 */
                rc = plugin_call_exop_plugins( pb, p );
                slapi_log_err(SLAPI_LOG_TRACE, "do_extended", "Called betxn exop, got %d \n", rc);
                if (rc == LDAP_SUCCESS || rc == SLAPI_PLUGIN_EXTENDED_SENT_RESULT) {
                    /* commit */
                    txn_rc = slapi_back_transaction_commit(be_pb);
                    if (txn_rc == 0) {
                        slapi_log_err(SLAPI_LOG_TRACE, "do_extended", "Commit with result %d \n", txn_rc);
                    } else {
                        slapi_log_err(SLAPI_LOG_ERR, "do_extended", "Unable to commit commit with result %d \n", txn_rc);
                    }
                } else {
                    /* abort */
                    txn_rc = slapi_back_transaction_abort(be_pb);
                    slapi_log_err(SLAPI_LOG_ERR, "do_extended", "Abort with result %d \n", txn_rc);
                }
            } /* txn_rc */
            slapi_pblock_destroy(be_pb); /* Clean up after ourselves */
        } /* if be */
    }

    if (plugin_call_plugins(pb, SLAPI_PLUGIN_POST_EXTOP_FN) != SLAPI_PLUGIN_SUCCESS) {
        goto free_and_return;
    }

    if ( SLAPI_PLUGIN_EXTENDED_SENT_RESULT != rc ) {
        if ( SLAPI_PLUGIN_EXTENDED_NOT_HANDLED == rc ) {
            lderr = LDAP_PROTOCOL_ERROR;    /* no plugin handled the op */
            errmsg = "unsupported extended operation";
        } else {
            if (rc != LDAP_SUCCESS) {
                slapi_log_err(SLAPI_LOG_ERR, "do_extended", "Failed with result %d \n", rc);
            }
            errmsg = NULL;
            lderr = rc;
        }
        send_ldap_result( pb, lderr, NULL, errmsg, 0, NULL );
    }
free_and_return:
    if (extoid)
        slapi_ch_free((void **)&extoid);
    if (extval.bv_val)
        slapi_ch_free((void **)&extval.bv_val);
    return;
}
예제 #8
0
파일: psearch.c 프로젝트: leto/389-ds
/*
 * Thread routine for sending search results to a client
 * which is persistently waiting for them.
 *
 * This routine will terminate when either (a) the ps_complete
 * flag is set, or (b) the associated operation is abandoned.
 * In any case, the thread won't notice until it wakes from
 * sleeping on the ps_list condition variable, so it needs
 * to be awakened.
 */
static void
ps_send_results( void *arg )
{
    PSearch *ps = (PSearch *)arg;
	PSEQNode *peq, *peqnext;
	struct slapi_filter *filter = 0;
	char *base = NULL;
	Slapi_DN *sdn = NULL;
	char *fstr = NULL;
	char **pbattrs = NULL;
	int conn_acq_flag = 0;
    
    g_incr_active_threadcnt();

    /* need to acquire a reference to this connection so that it will not
       be released or cleaned up out from under us */
    PR_Lock( ps->ps_pblock->pb_conn->c_mutex );
    conn_acq_flag = connection_acquire_nolock(ps->ps_pblock->pb_conn);    
    PR_Unlock( ps->ps_pblock->pb_conn->c_mutex );

	if (conn_acq_flag) {
		slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
						"conn=%" NSPRIu64 " op=%d Could not acquire the connection - psearch aborted\n",
						ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid);
	}

    PR_Lock( psearch_list->pl_cvarlock );

    while ( (conn_acq_flag == 0) && !ps->ps_complete ) {
	/* Check for an abandoned operation */
	if ( ps->ps_pblock->pb_op == NULL || slapi_op_abandoned( ps->ps_pblock ) ) {
		slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
						"conn=%" NSPRIu64 " op=%d The operation has been abandoned\n",
						ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid);
	    break;
	}
	if ( NULL == ps->ps_eq_head ) {
	    /* Nothing to do */
	    PR_WaitCondVar( psearch_list->pl_cvar, PR_INTERVAL_NO_TIMEOUT );
	} else {
	    /* dequeue the item */
	    int		attrsonly;
	    char	**attrs;
	    LDAPControl	**ectrls;
	    Slapi_Entry	*ec;
		Slapi_Filter	*f = NULL;
		
	    PR_Lock( ps->ps_lock );

		peq = ps->ps_eq_head;
		ps->ps_eq_head = peq->pe_next;
	    if ( NULL == ps->ps_eq_head ) {
			ps->ps_eq_tail = NULL;
	    }

	    PR_Unlock( ps->ps_lock );

	    /* Get all the information we need to send the result */
	    ec = peq->pe_entry;
	    slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_ATTRS, &attrs );
	    slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
	    if ( !ps->ps_send_entchg_controls || peq->pe_ctrls[0] == NULL ) {
		ectrls = NULL;
	    } else {
		ectrls = peq->pe_ctrls;
	    }

	    /*
	     * Send the result.  Since send_ldap_search_entry can block for
	     * up to 30 minutes, we relinquish all locks before calling it.
	     */
	    PR_Unlock(psearch_list->pl_cvarlock);

		/*
		 * The entry is in the right scope and matches the filter
		 * but we need to redo the filter test here to check access
		 * controls. See the comments at the slapi_filter_test()
		 * call in ps_service_persistent_searches().		 
		*/
		slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_FILTER, &f );			

		/* See if the entry meets the filter and ACL criteria */
		if ( slapi_vattr_filter_test( ps->ps_pblock, ec, f,
			    1 /* verify_access */ ) == 0 ) {
			int rc = 0;
	    	slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_RESULT_ENTRY, ec );
	    	rc = send_ldap_search_entry( ps->ps_pblock, ec,
										 ectrls, attrs, attrsonly );
			if (rc) {
				slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
								"conn=%" NSPRIu64 " op=%d Error %d sending entry %s with op status %d\n",
								ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid,
								rc, slapi_entry_get_dn_const(ec), ps->ps_pblock->pb_op->o_status);
			}
		}
	    
		PR_Lock(psearch_list->pl_cvarlock);

		/* Deallocate our wrapper for this entry */
		pe_ch_free( &peq );
	}
    }
    PR_Unlock( psearch_list->pl_cvarlock );
    ps_remove( ps );

    /* indicate the end of search */
    plugin_call_plugins( ps->ps_pblock , SLAPI_PLUGIN_POST_SEARCH_FN );

	/* free things from the pblock that were not free'd in do_search() */
	/* we strdup'd this in search.c - need to free */
	slapi_pblock_get( ps->ps_pblock, SLAPI_ORIGINAL_TARGET_DN, &base );
	slapi_pblock_set( ps->ps_pblock, SLAPI_ORIGINAL_TARGET_DN, NULL );
	slapi_ch_free_string(&base);

	/* Free SLAPI_SEARCH_* before deleting op since those are held by op */
	slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, &sdn );
	slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, NULL );
	slapi_sdn_free(&sdn);

    slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_STRFILTER, &fstr );
    slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_STRFILTER, NULL );
	slapi_ch_free_string(&fstr);

    slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_ATTRS, &pbattrs );
    slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_ATTRS, NULL );
	if ( pbattrs != NULL )
	{
		charray_free( pbattrs );
	}
	
	slapi_pblock_get(ps->ps_pblock, SLAPI_SEARCH_FILTER, &filter );
	slapi_pblock_set(ps->ps_pblock, SLAPI_SEARCH_FILTER, NULL );
	slapi_filter_free(filter, 1);

    /* Clean up the connection structure */
    PR_Lock( ps->ps_pblock->pb_conn->c_mutex );

	slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
					"conn=%" NSPRIu64 " op=%d Releasing the connection and operation\n",
					ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid);
    /* Delete this op from the connection's list */
    connection_remove_operation( ps->ps_pblock->pb_conn, ps->ps_pblock->pb_op );
    operation_free(&(ps->ps_pblock->pb_op),ps->ps_pblock->pb_conn);
    ps->ps_pblock->pb_op=NULL;

    /* Decrement the connection refcnt */
    if (conn_acq_flag == 0) { /* we acquired it, so release it */
	connection_release_nolock (ps->ps_pblock->pb_conn);
    }
    PR_Unlock( ps->ps_pblock->pb_conn->c_mutex );

    PR_DestroyLock ( ps->ps_lock );
    ps->ps_lock = NULL;

    slapi_ch_free((void **) &ps->ps_pblock );
	for ( peq = ps->ps_eq_head; peq; peq = peqnext) {
		peqnext = peq->pe_next;
		pe_ch_free( &peq );
	}
    slapi_ch_free((void **) &ps );
    g_decr_active_threadcnt();
}