Example #1
0
/*
 * Obsolete constraint checking.
 */
int
slap_mods_obsolete_check(
	Operation *op,
	Modifications *ml,
	const char **text,
	char *textbuf,
	size_t textlen )
{
	if( get_relax( op ) ) return LDAP_SUCCESS;

	for ( ; ml != NULL; ml = ml->sml_next ) {
		if ( is_at_obsolete( ml->sml_desc->ad_type ) &&
			(( ml->sml_op != LDAP_MOD_REPLACE &&
				ml->sml_op != LDAP_MOD_DELETE ) ||
					ml->sml_values != NULL ))
		{
			/*
			 * attribute is obsolete,
			 * only allow replace/delete with no values
			 */
			snprintf( textbuf, textlen,
				"%s: attribute is obsolete",
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_CONSTRAINT_VIOLATION;
		}
	}

	return LDAP_SUCCESS;
}
Example #2
0
/*
 * No-user-modification constraint checking.
 */
int
slap_mods_no_user_mod_check(
	Operation *op,
	Modifications *ml,
	const char **text,
	char *textbuf,
	size_t textlen )
{
	for ( ; ml != NULL; ml = ml->sml_next ) {
		if ( !is_at_no_user_mod( ml->sml_desc->ad_type ) ) {
			continue;
		}

		if ( ml->sml_flags & SLAP_MOD_INTERNAL ) {
			continue;
		}

		if ( get_relax( op ) ) {
			if ( ml->sml_desc->ad_type->sat_flags & SLAP_AT_MANAGEABLE ) {
				ml->sml_flags |= SLAP_MOD_MANAGING;
				continue;
			}

			/* attribute not manageable */
			snprintf( textbuf, textlen,
				"%s: no-user-modification attribute not manageable",
				ml->sml_type.bv_val );

		} else {
			/* user modification disallowed */
			snprintf( textbuf, textlen,
				"%s: no user modification allowed",
				ml->sml_type.bv_val );
		}

		*text = textbuf;
		return LDAP_CONSTRAINT_VIOLATION;
	}

	return LDAP_SUCCESS;
}
Example #3
0
int
meta_back_modify( Operation *op, SlapReply *rs )
{
	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
	metatarget_t	*mt;
	metaconn_t	*mc;
	int		rc = 0;
	LDAPMod		**modv = NULL;
	LDAPMod		*mods = NULL;
	Modifications	*ml;
	int		candidate = -1, i;
	int		isupdate;
	struct berval	mdn = BER_BVNULL;
	struct berval	mapped;
	dncookie	dc;
	int		msgid;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
	LDAPControl	**ctrls = NULL;

	mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR );
	if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
		return rs->sr_err;
	}

	assert( mc->mc_conns[ candidate ].msc_ld != NULL );

	/*
	 * Rewrite the modify dn, if needed
	 */
	mt = mi->mi_targets[ candidate ];
	dc.target = mt;
	dc.conn = op->o_conn;
	dc.rs = rs;
	dc.ctx = "modifyDN";

	if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
		send_ldap_result( op, rs );
		goto cleanup;
	}

	for ( i = 0, ml = op->orm_modlist; ml; i++ ,ml = ml->sml_next )
		;

	mods = ch_malloc( sizeof( LDAPMod )*i );
	if ( mods == NULL ) {
		rs->sr_err = LDAP_OTHER;
		send_ldap_result( op, rs );
		goto cleanup;
	}
	modv = ( LDAPMod ** )ch_malloc( ( i + 1 )*sizeof( LDAPMod * ) );
	if ( modv == NULL ) {
		rs->sr_err = LDAP_OTHER;
		send_ldap_result( op, rs );
		goto cleanup;
	}

	dc.ctx = "modifyAttrDN";
	isupdate = be_shadow_update( op );
	for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) {
		int	j, is_oc = 0;

		if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
		{
			continue;
		}

		if ( ml->sml_desc == slap_schema.si_ad_objectClass 
				|| ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
		{
			is_oc = 1;
			mapped = ml->sml_desc->ad_cname;

		} else {
			ldap_back_map( &mt->mt_rwmap.rwm_at,
					&ml->sml_desc->ad_cname, &mapped,
					BACKLDAP_MAP );
			if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
				continue;
			}
		}

		modv[ i ] = &mods[ i ];
		mods[ i ].mod_op = ml->sml_op | LDAP_MOD_BVALUES;
		mods[ i ].mod_type = mapped.bv_val;

		/*
		 * FIXME: dn-valued attrs should be rewritten
		 * to allow their use in ACLs at the back-ldap
		 * level.
		 */
		if ( ml->sml_values != NULL ) {
			if ( is_oc ) {
				for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
					;
				mods[ i ].mod_bvalues =
					(struct berval **)ch_malloc( ( j + 1 ) *
					sizeof( struct berval * ) );
				for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); ) {
					struct ldapmapping	*mapping;

					ldap_back_mapping( &mt->mt_rwmap.rwm_oc,
							&ml->sml_values[ j ], &mapping, BACKLDAP_MAP );

					if ( mapping == NULL ) {
						if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
							continue;
						}
						mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];

					} else {
						mods[ i ].mod_bvalues[ j ] = &mapping->dst;
					}
					j++;
				}
				mods[ i ].mod_bvalues[ j ] = NULL;

			} else {
				if ( ml->sml_desc->ad_type->sat_syntax ==
						slap_schema.si_syn_distinguishedName )
				{
					( void )ldap_dnattr_rewrite( &dc, ml->sml_values );
					if ( ml->sml_values == NULL ) {
						continue;
					}
				}

				for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
					;
				mods[ i ].mod_bvalues =
					(struct berval **)ch_malloc( ( j + 1 ) *
					sizeof( struct berval * ) );
				for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
					mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
				}
				mods[ i ].mod_bvalues[ j ] = NULL;
			}

		} else {
			mods[ i ].mod_bvalues = NULL;
		}

		i++;
	}
	modv[ i ] = 0;

retry:;
	ctrls = op->o_ctrls;
	rc = meta_back_controls_add( op, rs, mc, candidate, &ctrls );
	if ( rc != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		goto cleanup;
	}

	rs->sr_err = ldap_modify_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val,
			modv, ctrls, NULL, &msgid );
	rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
		mt->mt_timeout[ SLAP_OP_MODIFY ], ( LDAP_BACK_SENDRESULT | retrying ) );
	if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
			/* if the identity changed, there might be need to re-authz */
			(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
			goto retry;
		}
	}

cleanup:;
	(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );

	if ( mdn.bv_val != op->o_req_dn.bv_val ) {
		free( mdn.bv_val );
		BER_BVZERO( &mdn );
	}
	if ( modv != NULL ) {
		for ( i = 0; modv[ i ]; i++ ) {
			free( modv[ i ]->mod_bvalues );
		}
	}
	free( mods );
	free( modv );

	if ( mc ) {
		meta_back_release_conn( mi, mc );
	}

	return rs->sr_err;
}
Example #4
0
int
bdb_add(Operation *op, SlapReply *rs )
{
	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
	struct berval	pdn;
	Entry		*p = NULL, *oe = op->ora_e;
	EntryInfo	*ei;
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	DB_TXN		*ltid = NULL, *lt2;
	ID eid = NOID;
	struct bdb_op_info opinfo = {{{ 0 }}};
	int subentry;
	DB_LOCK		lock;

	int		num_retries = 0;
	int		success;

	LDAPControl **postread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

#ifdef LDAP_X_TXN
	int settle = 0;
#endif

	Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(bdb_add) ": %s\n",
		op->ora_e->e_name.bv_val, 0, 0);

#ifdef LDAP_X_TXN
	if( op->o_txnSpec ) {
		/* acquire connection lock */
		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
		if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
			rs->sr_text = "invalid transaction identifier";
			rs->sr_err = LDAP_X_TXN_ID_INVALID;
			goto txnReturn;
		} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
			settle=1;
			goto txnReturn;
		}

		if( op->o_conn->c_txn_backend == NULL ) {
			op->o_conn->c_txn_backend = op->o_bd;

		} else if( op->o_conn->c_txn_backend != op->o_bd ) {
			rs->sr_text = "transaction cannot span multiple database contexts";
			rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
			goto txnReturn;
		}

		/* insert operation into transaction */

		rs->sr_text = "transaction specified";
		rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;

txnReturn:
		/* release connection lock */
		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );

		if( !settle ) {
			send_ldap_result( op, rs );
			return rs->sr_err;
		}
	}
#endif

	ctrls[num_ctrls] = 0;

	/* check entry's schema */
	rs->sr_err = entry_schema_check( op, op->ora_e, NULL,
		get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": entry failed schema check: "
			"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
		goto return_results;
	}

	/* add opattrs to shadow as well, only missing attrs will actually
	 * be added; helps compatibility with older OL versions */
	rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": entry failed op attrs add: "
			"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
		goto return_results;
	}

	if ( get_assert( op ) &&
		( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	subentry = is_entry_subentry( op->ora_e );

	if( 0 ) {
retry:	/* transaction retry */
		if( p ) {
			/* free parent and reader lock */
			if ( p != (Entry *)&slap_entry_root ) {
				bdb_unlocked_cache_return_entry_r( bdb, p );
			}
			p = NULL;
		}
		rs->sr_err = TXN_ABORT( ltid );
		ltid = NULL;
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
		opinfo.boi_oe.oe_key = NULL;
		op->o_do_not_cache = opinfo.boi_acl_cache;
		if( rs->sr_err != 0 ) {
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			goto return_results;
		}
		bdb_trans_backoff( ++num_retries );
	}

	/* begin transaction */
	rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
		bdb->bi_db_opflags );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": txn_begin failed: %s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": txn1 id: %x\n",
		ltid->id(ltid), 0, 0 );

	opinfo.boi_oe.oe_key = bdb;
	opinfo.boi_txn = ltid;
	opinfo.boi_err = 0;
	opinfo.boi_acl_cache = op->o_do_not_cache;
	LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next );

	/*
	 * Get the parent dn and see if the corresponding entry exists.
	 */
	if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
		pdn = slap_empty_bv;
	} else {
		dnParent( &op->ora_e->e_nname, &pdn );
	}

	/* get entry or parent */
	rs->sr_err = bdb_dn2entry( op, ltid, &op->ora_e->e_nname, &ei,
		1, &lock );
	switch( rs->sr_err ) {
	case 0:
		rs->sr_err = LDAP_ALREADY_EXISTS;
		goto return_results;
	case DB_NOTFOUND:
		break;
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	p = ei->bei_e;
	if ( !p )
		p = (Entry *)&slap_entry_root;

	if ( !bvmatch( &pdn, &p->e_nname ) ) {
		rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
			op->o_tmpmemctx );
		rs->sr_ref = is_entry_referral( p )
			? get_entry_referrals( op, p )
			: NULL;
		if ( p != (Entry *)&slap_entry_root )
			bdb_unlocked_cache_return_entry_r( bdb, p );
		p = NULL;
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": parent "
			"does not exist\n", 0, 0, 0 );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	rs->sr_err = access_allowed( op, p,
		children, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		switch( opinfo.boi_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		if ( p != (Entry *)&slap_entry_root )
			bdb_unlocked_cache_return_entry_r( bdb, p );
		p = NULL;

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": no write access to parent\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to parent";
		goto return_results;;
	}

	if ( p != (Entry *)&slap_entry_root ) {
		if ( is_entry_subentry( p ) ) {
			bdb_unlocked_cache_return_entry_r( bdb, p );
			p = NULL;
			/* parent is a subentry, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_add) ": parent is subentry\n",
				0, 0, 0 );
			rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			rs->sr_text = "parent is a subentry";
			goto return_results;;
		}

		if ( is_entry_alias( p ) ) {
			bdb_unlocked_cache_return_entry_r( bdb, p );
			p = NULL;
			/* parent is an alias, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_add) ": parent is alias\n",
				0, 0, 0 );
			rs->sr_err = LDAP_ALIAS_PROBLEM;
			rs->sr_text = "parent is an alias";
			goto return_results;;
		}

		if ( is_entry_referral( p ) ) {
			/* parent is a referral, don't allow add */
			rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
				op->o_tmpmemctx );
			rs->sr_ref = get_entry_referrals( op, p );
			bdb_unlocked_cache_return_entry_r( bdb, p );
			p = NULL;
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_add) ": parent is referral\n",
				0, 0, 0 );

			rs->sr_err = LDAP_REFERRAL;
			rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
			goto return_results;
		}

	}

	if ( subentry ) {
		/* FIXME: */
		/* parent must be an administrative point of the required kind */
	}

	/* free parent and reader lock */
	if ( p != (Entry *)&slap_entry_root ) {
		if ( p->e_nname.bv_len ) {
			struct berval ppdn;

			/* ITS#5326: use parent's DN if differs from provided one */
			dnParent( &op->ora_e->e_name, &ppdn );
			if ( !dn_match( &p->e_name, &ppdn ) ) {
				struct berval rdn;
				struct berval newdn;

				dnRdn( &op->ora_e->e_name, &rdn );

				build_new_dn( &newdn, &p->e_name, &rdn, NULL ); 
				if ( op->ora_e->e_name.bv_val != op->o_req_dn.bv_val )
					ber_memfree( op->ora_e->e_name.bv_val );
				op->ora_e->e_name = newdn;

				/* FIXME: should check whether
				 * dnNormalize(newdn) == e->e_nname ... */
			}
		}

		bdb_unlocked_cache_return_entry_r( bdb, p );
	}
	p = NULL;

	rs->sr_err = access_allowed( op, op->ora_e,
		entry, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		switch( opinfo.boi_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": no write access to entry\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to entry";
		goto return_results;;
	}

	/* 
	 * Check ACL for attribute write access
	 */
	if (!acl_check_modlist(op, oe, op->ora_modlist)) {
		switch( opinfo.boi_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": no write access to attribute\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to attribute";
		goto return_results;;
	}

	if ( eid == NOID ) {
		rs->sr_err = bdb_next_id( op->o_bd, &eid );
		if( rs->sr_err != 0 ) {
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(bdb_add) ": next_id failed (%d)\n",
				rs->sr_err, 0, 0 );
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
		op->ora_e->e_id = eid;
	}

	/* nested transaction */
	rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
		bdb->bi_db_opflags );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": txn_begin(2) failed: "
			"%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": txn2 id: %x\n",
		lt2->id(lt2), 0, 0 );

	/* dn2id index */
	rs->sr_err = bdb_dn2id_add( op, lt2, ei, op->ora_e );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": dn2id_add failed: %s (%d)\n",
			db_strerror(rs->sr_err), rs->sr_err, 0 );

		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		case DB_KEYEXIST:
			rs->sr_err = LDAP_ALREADY_EXISTS;
			break;
		default:
			rs->sr_err = LDAP_OTHER;
		}
		goto return_results;
	}

	/* attribute indexes */
	rs->sr_err = bdb_index_entry_add( op, lt2, op->ora_e );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": index_entry_add failed\n",
			0, 0, 0 );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		default:
			rs->sr_err = LDAP_OTHER;
		}
		rs->sr_text = "index generation failed";
		goto return_results;
	}

	/* id2entry index */
	rs->sr_err = bdb_id2entry_add( op->o_bd, lt2, op->ora_e );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": id2entry_add failed\n",
			0, 0, 0 );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		default:
			rs->sr_err = LDAP_OTHER;
		}
		rs->sr_text = "entry store failed";
		goto return_results;
	}

	if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "txn_commit(2) failed";
		goto return_results;
	}

	/* post-read */
	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if ( slap_read_controls( op, rs, op->ora_e,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_add) ": post-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	if ( op->o_noop ) {
		if (( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
			rs->sr_text = "txn_abort (no-op) failed";
		} else {
			rs->sr_err = LDAP_X_NO_OPERATION;
			ltid = NULL;
			goto return_results;
		}

	} else {
		struct berval nrdn;

		/* pick the RDN if not suffix; otherwise pick the entire DN */
		if (pdn.bv_len) {
			nrdn.bv_val = op->ora_e->e_nname.bv_val;
			nrdn.bv_len = pdn.bv_val - op->ora_e->e_nname.bv_val - 1;
		} else {
			nrdn = op->ora_e->e_nname;
		}

		bdb_cache_add( bdb, ei, op->ora_e, &nrdn, ltid, &lock );

		if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
			rs->sr_text = "txn_commit failed";
		} else {
			rs->sr_err = LDAP_SUCCESS;
		}
	}

	ltid = NULL;
	LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	opinfo.boi_oe.oe_key = NULL;

	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": %s : %s (%d)\n",
			rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	Debug(LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_add) ": added%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		op->ora_e->e_id, op->ora_e->e_dn );

	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	success = rs->sr_err;
	send_ldap_result( op, rs );

	if( ltid != NULL ) {
		TXN_ABORT( ltid );
	}
	if ( opinfo.boi_oe.oe_key ) {
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	}

	if( success == LDAP_SUCCESS ) {
		/* We own the entry now, and it can be purged at will
		 * Check to make sure it's the same entry we entered with.
		 * Possibly a callback may have mucked with it, although
		 * in general callbacks should treat the entry as read-only.
		 */
		bdb_cache_deref( oe->e_private );
		if ( op->ora_e == oe )
			op->ora_e = NULL;

		if ( bdb->bi_txn_cp_kbyte ) {
			TXN_CHECKPOINT( bdb->bi_dbenv,
				bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
		}
	}

	slap_graduate_commit_csn( op );

	if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
		slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
	}
	return rs->sr_err;
}
Example #5
0
int
ldap_back_modify(
		Operation	*op,
		SlapReply	*rs )
{
	ldapinfo_t		*li = (ldapinfo_t *)op->o_bd->be_private;

	ldapconn_t		*lc = NULL;
	LDAPMod			**modv = NULL,
				*mods = NULL;
	Modifications		*ml;
	int			i, j, rc;
	ber_int_t		msgid;
	int			isupdate;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
	LDAPControl		**ctrls = NULL;

	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
		return rs->sr_err;
	}

	for ( i = 0, ml = op->orm_modlist; ml; i++, ml = ml->sml_next )
		/* just count mods */ ;

	modv = (LDAPMod **)ch_malloc( ( i + 1 )*sizeof( LDAPMod * )
			+ i*sizeof( LDAPMod ) );
	if ( modv == NULL ) {
		rc = LDAP_NO_MEMORY;
		goto cleanup;
	}
	mods = (LDAPMod *)&modv[ i + 1 ];

	isupdate = be_shadow_update( op );
	for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) {
		if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
		{
			continue;
		}

		modv[ i ] = &mods[ i ];
		mods[ i ].mod_op = ( ml->sml_op | LDAP_MOD_BVALUES );
		mods[ i ].mod_type = ml->sml_desc->ad_cname.bv_val;

		if ( ml->sml_values != NULL ) {
			if ( ml->sml_values == NULL ) {	
				continue;
			}

			for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
				/* just count mods */ ;
			mods[ i ].mod_bvalues =
				(struct berval **)ch_malloc( ( j + 1 )*sizeof( struct berval * ) );
			for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
			{
				mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
			}
			mods[ i ].mod_bvalues[ j ] = NULL;

		} else {
			mods[ i ].mod_bvalues = NULL;
		}

		i++;
	}
	modv[ i ] = 0;

retry:;
	ctrls = op->o_ctrls;
	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
	if ( rc != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		rc = -1;
		goto cleanup;
	}

	rs->sr_err = ldap_modify_ext( lc->lc_ld, op->o_req_dn.bv_val, modv,
			ctrls, NULL, &msgid );
	rc = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_MODIFY ],
		( LDAP_BACK_SENDRESULT | retrying ) );
	if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
			/* if the identity changed, there might be need to re-authz */
			(void)ldap_back_controls_free( op, rs, &ctrls );
			goto retry;
		}
	}

cleanup:;
	(void)ldap_back_controls_free( op, rs, &ctrls );

	for ( i = 0; modv[ i ]; i++ ) {
		ch_free( modv[ i ]->mod_bvalues );
	}
	ch_free( modv );

	if ( lc != NULL ) {
		ldap_back_release_conn( li, lc );
	}

	return rc;
}
Example #6
0
int ndb_modify_internal(
	Operation *op,
	NdbArgs *NA,
	const char **text,
	char *textbuf,
	size_t textlen )
{
	struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
	Modification	*mod;
	Modifications	*ml;
	Modifications	*modlist = op->orm_modlist;
	NdbAttrInfo **modai, *atmp;
	const NdbDictionary::Dictionary *myDict;
	const NdbDictionary::Table *myTable;
	int got_oc = 0, nmods = 0, nai = 0, i, j;
	int rc, indexed = 0;
	Attribute *old = NULL;

	Debug( LDAP_DEBUG_TRACE, "ndb_modify_internal: 0x%08lx: %s\n",
		NA->e->e_id, NA->e->e_dn, 0);

	if ( !acl_check_modlist( op, NA->e, modlist )) {
		return LDAP_INSUFFICIENT_ACCESS;
	}

	old = attrs_dup( NA->e->e_attrs );

	for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
		mod = &ml->sml_mod;
		nmods++;

		switch ( mod->sm_op ) {
		case LDAP_MOD_ADD:
			Debug(LDAP_DEBUG_ARGS,
				"ndb_modify_internal: add %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
			rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
				text, textbuf, textlen );
			if( rc != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
					rc, *text, 0);
			}
			break;

		case LDAP_MOD_DELETE:
			Debug(LDAP_DEBUG_ARGS,
				"ndb_modify_internal: delete %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
			rc = ndb_modify_delete( NA->e, mod, get_permissiveModify(op),
				text, textbuf, textlen, NULL );
			assert( rc != LDAP_TYPE_OR_VALUE_EXISTS );
			if( rc != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
					rc, *text, 0);
			}
			break;

		case LDAP_MOD_REPLACE:
			Debug(LDAP_DEBUG_ARGS,
				"ndb_modify_internal: replace %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
			rc = modify_replace_values( NA->e, mod, get_permissiveModify(op),
				text, textbuf, textlen );
			if( rc != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
					rc, *text, 0);
			}
			break;

		case LDAP_MOD_INCREMENT:
			Debug(LDAP_DEBUG_ARGS,
				"ndb_modify_internal: increment %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
			rc = modify_increment_values( NA->e, mod, get_permissiveModify(op),
				text, textbuf, textlen );
			if( rc != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS,
					"ndb_modify_internal: %d %s\n",
					rc, *text, 0);
			}
			break;

		case SLAP_MOD_SOFTADD:
			Debug(LDAP_DEBUG_ARGS,
				"ndb_modify_internal: softadd %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
 			mod->sm_op = LDAP_MOD_ADD;

			rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
				text, textbuf, textlen );

 			mod->sm_op = SLAP_MOD_SOFTADD;

 			if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
 				rc = LDAP_SUCCESS;
 			}

			if( rc != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
					rc, *text, 0);
			}
 			break;

		case SLAP_MOD_SOFTDEL:
			Debug(LDAP_DEBUG_ARGS,
				"ndb_modify_internal: softdel %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
 			mod->sm_op = LDAP_MOD_DELETE;

			rc = modify_delete_values( NA->e, mod, get_permissiveModify(op),
				text, textbuf, textlen );

 			mod->sm_op = SLAP_MOD_SOFTDEL;

 			if ( rc == LDAP_NO_SUCH_ATTRIBUTE) {
 				rc = LDAP_SUCCESS;
 			}

			if( rc != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
					rc, *text, 0);
			}
 			break;

		case SLAP_MOD_ADD_IF_NOT_PRESENT:
			Debug(LDAP_DEBUG_ARGS,
				"ndb_modify_internal: add_if_not_present %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
			if ( attr_find( NA->e->e_attrs, mod->sm_desc ) ) {
				rc = LDAP_SUCCESS;
				break;
			}

 			mod->sm_op = LDAP_MOD_ADD;

			rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
				text, textbuf, textlen );

 			mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;

			if( rc != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
					rc, *text, 0);
			}
 			break;

		default:
			Debug(LDAP_DEBUG_ANY, "ndb_modify_internal: invalid op %d\n",
				mod->sm_op, 0, 0);
			*text = "Invalid modify operation";
			rc = LDAP_OTHER;
			Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
				rc, *text, 0);
		}

		if ( rc != LDAP_SUCCESS ) {
			attrs_free( old );
			return rc; 
		}

		/* If objectClass was modified, reset the flags */
		if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
			NA->e->e_ocflags = 0;
			got_oc = 1;
		}
	}

	/* check that the entry still obeys the schema */
	rc = entry_schema_check( op, NA->e, NULL, get_relax(op), 0, NULL,
		text, textbuf, textlen );
	if ( rc != LDAP_SUCCESS || op->o_noop ) {
		if ( rc != LDAP_SUCCESS ) {
			Debug( LDAP_DEBUG_ANY,
				"entry failed schema check: %s\n",
				*text, 0, 0 );
		}
		attrs_free( old );
		return rc;
	}

	if ( got_oc ) {
		rc = ndb_entry_put_info( op->o_bd, NA, 1 );
		if ( rc ) {
			attrs_free( old );
			return rc;
		}
	}

	/* apply modifications to DB */
	modai = (NdbAttrInfo **)op->o_tmpalloc( nmods * sizeof(NdbAttrInfo*), op->o_tmpmemctx );

	/* Get the unique list of modified attributes */
	ldap_pvt_thread_rdwr_rlock( &ni->ni_ai_rwlock );
	for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
		/* Already took care of objectclass */
		if ( ml->sml_desc == slap_schema.si_ad_objectClass )
			continue;
		for ( i=0; i<nai; i++ ) {
			if ( ml->sml_desc->ad_type == modai[i]->na_attr )
				break;
		}
		/* This attr was already updated */
		if ( i < nai )
			continue;
		modai[nai] = ndb_ai_find( ni, ml->sml_desc->ad_type );
		if ( modai[nai]->na_flag & NDB_INFO_INDEX )
			indexed++;
		nai++;
	}
	ldap_pvt_thread_rdwr_runlock( &ni->ni_ai_rwlock );

	/* If got_oc, this was already done above */
	if ( indexed && !got_oc) {
		rc = ndb_entry_put_info( op->o_bd, NA, 1 );
		if ( rc ) {
			attrs_free( old );
			return rc;
		}
	}

	myDict = NA->ndb->getDictionary();

	/* sort modai so that OcInfo's are contiguous */
	{
		int j, k;
		for ( i=0; i<nai; i++ ) {
			for ( j=i+1; j<nai; j++ ) {
				if ( modai[i]->na_oi == modai[j]->na_oi )
					continue;
				for ( k=j+1; k<nai; k++ ) {
					if ( modai[i]->na_oi == modai[k]->na_oi ) {
						atmp = modai[j];
						modai[j] = modai[k];
						modai[k] = atmp;
						break;
					}
				}
				/* there are no more na_oi's that match modai[i] */
				if ( k == nai ) {
					i = j;
				}
			}
		}
	}

	/* One call per table... */
	for ( i=0; i<nai; i += j ) {
		atmp = modai[i];
		for ( j=i+1; j<nai; j++ )
			if ( atmp->na_oi != modai[j]->na_oi )
				break;
		j -= i;
		myTable = myDict->getTable( atmp->na_oi->no_table.bv_val );
		if ( !myTable )
			continue;
		rc = ndb_oc_attrs( NA->txn, myTable, NA->e, atmp->na_oi, &modai[i], j, old );
		if ( rc ) break;
	}
	attrs_free( old );
	return rc;
}
Example #7
0
static int 
pblock_get( Slapi_PBlock *pb, int param, void **value ) 
{
	int rc = PBLOCK_SUCCESS;

	pblock_lock( pb );

	switch ( param ) {
	case SLAPI_OPERATION:
		*value = pb->pb_op;
		break;
	case SLAPI_OPINITIATED_TIME:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((long *)value) = pb->pb_op->o_time;
		break;
	case SLAPI_OPERATION_ID:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((long *)value) = pb->pb_op->o_opid;
		break;
	case SLAPI_OPERATION_TYPE:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((ber_tag_t *)value) = pb->pb_op->o_tag;
		break;
	case SLAPI_OPERATION_MSGID:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((long *)value) = pb->pb_op->o_msgid;
		break;
	case SLAPI_X_OPERATION_DELETE_GLUE_PARENT:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((int *)value) = pb->pb_op->o_delete_glue_parent;
		break;
	case SLAPI_X_OPERATION_NO_SCHEMA_CHECK:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((int *)value) = get_no_schema_check( pb->pb_op );
		break;
	case SLAPI_X_ADD_STRUCTURAL_CLASS:
		PBLOCK_ASSERT_OP( pb, 0 );

		if ( pb->pb_op->o_tag == LDAP_REQ_ADD ) {
			struct berval tmpval = BER_BVNULL;

			rc = mods_structural_class( pb->pb_op->ora_modlist,
				&tmpval, &pb->pb_rs->sr_text,
				pb->pb_textbuf, sizeof( pb->pb_textbuf ),
				pb->pb_op->o_tmpmemctx );
			*((char **)value) = tmpval.bv_val;
		} else {
			rc = PBLOCK_ERROR;
		}
		break;
	case SLAPI_X_OPERATION_NO_SUBORDINATE_GLUE:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((int *)value) = pb->pb_op->o_no_subordinate_glue;
		break;
	case SLAPI_REQCONTROLS:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((LDAPControl ***)value) = pb->pb_op->o_ctrls;
		break;
	case SLAPI_REQUESTOR_DN:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((char **)value) = pb->pb_op->o_dn.bv_val;
		break;
	case SLAPI_MANAGEDSAIT:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((int *)value) = get_manageDSAit( pb->pb_op );
		break;
	case SLAPI_X_RELAX:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((int *)value) = get_relax( pb->pb_op );
		break;
	case SLAPI_BACKEND:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((BackendDB **)value) = select_backend( &pb->pb_op->o_req_ndn, 0 );
		break;
	case SLAPI_BE_TYPE:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_bd != NULL )
			*((char **)value) = pb->pb_op->o_bd->bd_info->bi_type;
		else
			*value = NULL;
		break;
	case SLAPI_CONNECTION:
		*value = pb->pb_conn;
		break;
	case SLAPI_X_CONN_SSF:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((slap_ssf_t *)value) = pb->pb_conn->c_ssf;
		break;
	case SLAPI_X_CONN_SASL_CONTEXT:
		PBLOCK_ASSERT_CONN( pb );
		if ( pb->pb_conn->c_sasl_authctx != NULL )
			*value = pb->pb_conn->c_sasl_authctx;
		else
			*value = pb->pb_conn->c_sasl_sockctx;
		break;
	case SLAPI_TARGET_DN:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((char **)value) = pb->pb_op->o_req_dn.bv_val;
		break;
	case SLAPI_REQUESTOR_ISROOT:
		*((int *)value) = pblock_be_call( pb, be_isroot );
		break;
	case SLAPI_IS_REPLICATED_OPERATION:
		*((int *)value) = pblock_be_call( pb, be_slurp_update );
		break;
	case SLAPI_CONN_AUTHTYPE:
	case SLAPI_CONN_AUTHMETHOD: /* XXX should return SASL mech */
		PBLOCK_ASSERT_CONN( pb );
		*((char **)value) = pblock_get_authtype( &pb->pb_conn->c_authz,
#ifdef HAVE_TLS
							 pb->pb_conn->c_is_tls
#else
							 0
#endif
							 );
		break;
	case SLAPI_IS_INTERNAL_OPERATION:
		*((int *)value) = pb->pb_intop;
		break;
	case SLAPI_X_CONN_IS_UDP:
		PBLOCK_ASSERT_CONN( pb );
#ifdef LDAP_CONNECTIONLESS
		*((int *)value) = pb->pb_conn->c_is_udp;
#else
		*((int *)value) = 0;
#endif
		break;
	case SLAPI_CONN_ID:
		PBLOCK_ASSERT_CONN( pb );
		*((long *)value) = pb->pb_conn->c_connid;
		break;
	case SLAPI_CONN_DN:
		PBLOCK_ASSERT_CONN( pb );
#if 0
		/* This would be necessary to keep plugin compat after the fix in ITS#4158 */
		if ( pb->pb_op->o_tag == LDAP_REQ_BIND && pb->pb_rs->sr_err == LDAP_SUCCESS )
			*((char **)value) = pb->pb_op->orb_edn.bv_val;
		else
#endif
		*((char **)value) = pb->pb_conn->c_dn.bv_val;
		break;
	case SLAPI_CONN_CLIENTIP:
		PBLOCK_ASSERT_CONN( pb );
		if ( strncmp( pb->pb_conn->c_peer_name.bv_val, "IP=", 3 ) == 0 )
			*((char **)value) = &pb->pb_conn->c_peer_name.bv_val[3];
		else
			*value = NULL;
		break;
	case SLAPI_X_CONN_CLIENTPATH:
		PBLOCK_ASSERT_CONN( pb );
		if ( strncmp( pb->pb_conn->c_peer_name.bv_val, "PATH=", 3 ) == 0 )
			*((char **)value) = &pb->pb_conn->c_peer_name.bv_val[5];
		else
			*value = NULL;
		break;
	case SLAPI_CONN_SERVERIP:
		PBLOCK_ASSERT_CONN( pb );
		if ( strncmp( pb->pb_conn->c_sock_name.bv_val, "IP=", 3 ) == 0 )
			*((char **)value) = &pb->pb_conn->c_sock_name.bv_val[3];
		else
			*value = NULL;
		break;
	case SLAPI_X_CONN_SERVERPATH:
		PBLOCK_ASSERT_CONN( pb );
		if ( strncmp( pb->pb_conn->c_sock_name.bv_val, "PATH=", 3 ) == 0 )
			*((char **)value) = &pb->pb_conn->c_sock_name.bv_val[5];
		else
			*value = NULL;
		break;
	case SLAPI_RESULT_CODE:
	case SLAPI_PLUGIN_INTOP_RESULT:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((int *)value) = pb->pb_rs->sr_err;
		break;
        case SLAPI_RESULT_TEXT:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((const char **)value) = pb->pb_rs->sr_text;
		break;
        case SLAPI_RESULT_MATCHED:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((const char **)value) = pb->pb_rs->sr_matched;
		break;
	case SLAPI_ADD_ENTRY:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_ADD )
			*((Slapi_Entry **)value) = pb->pb_op->ora_e;
		else
			*value = NULL;
		break;
	case SLAPI_MODIFY_MODS: {
		LDAPMod **mods = NULL;
		Modifications *ml = NULL;

		pblock_get_default( pb, param, (void **)&mods );
		if ( mods == NULL && pb->pb_intop == 0 ) {
			switch ( pb->pb_op->o_tag ) {
			case LDAP_REQ_MODIFY:
				ml = pb->pb_op->orm_modlist;
				break;
			case LDAP_REQ_MODRDN:
				ml = pb->pb_op->orr_modlist;
				break;
			default:
				rc = PBLOCK_ERROR;
				break;
			}
			if ( rc != PBLOCK_ERROR ) {
				mods = slapi_int_modifications2ldapmods( ml );
				pblock_set_default( pb, param, (void *)mods );
			}
		}
		*((LDAPMod ***)value) = mods;
		break;
	}
	case SLAPI_MODRDN_NEWRDN:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN )
			*((char **)value) = pb->pb_op->orr_newrdn.bv_val;
		else
			*value = NULL;
		break;
	case SLAPI_MODRDN_NEWSUPERIOR:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN && pb->pb_op->orr_newSup != NULL )
			*((char **)value) = pb->pb_op->orr_newSup->bv_val;
		else
			*value = NULL;
		break;
	case SLAPI_MODRDN_DELOLDRDN:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_MODRDN )
			*((int *)value) = pb->pb_op->orr_deleteoldrdn;
		else
			*((int *)value) = 0;
		break;
	case SLAPI_SEARCH_SCOPE:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH )
			*((int *)value) = pb->pb_op->ors_scope;
		else
			*((int *)value) = 0;
		break;
	case SLAPI_SEARCH_DEREF:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH )
			*((int *)value) = pb->pb_op->ors_deref;
		else
			*((int *)value) = 0;
		break;
	case SLAPI_SEARCH_SIZELIMIT:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH )
			*((int *)value) = pb->pb_op->ors_slimit;
		else
			*((int *)value) = 0;
		break;
	case SLAPI_SEARCH_TIMELIMIT:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH )
			*((int *)value) = pb->pb_op->ors_tlimit;
		else
			*((int *)value) = 0;
		break;
	case SLAPI_SEARCH_FILTER:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH )
			*((Slapi_Filter **)value) = pb->pb_op->ors_filter;
		else
			*((Slapi_Filter **)value) = NULL;
		break;
	case SLAPI_SEARCH_STRFILTER:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH )
			*((char **)value) = pb->pb_op->ors_filterstr.bv_val;
		else
			*((char **)value) = NULL;
		break;
	case SLAPI_SEARCH_ATTRS: {
		char **attrs = NULL;

		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag != LDAP_REQ_SEARCH ) {
			rc = PBLOCK_ERROR;
			break;
		}
		pblock_get_default( pb, param, (void **)&attrs );
		if ( attrs == NULL && pb->pb_intop == 0 ) {
			attrs = anlist2charray_x( pb->pb_op->ors_attrs, 0, pb->pb_op->o_tmpmemctx );
			pblock_set_default( pb, param, (void *)attrs );
		}
		*((char ***)value) = attrs;
		break;
	}
	case SLAPI_SEARCH_ATTRSONLY:
		PBLOCK_ASSERT_OP( pb, 0 );
		if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH )
			*((int *)value) = pb->pb_op->ors_attrsonly;
		else
			*((int *)value) = 0;
		break;
	case SLAPI_SEARCH_RESULT_ENTRY:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((Slapi_Entry **)value) = pb->pb_rs->sr_entry;
		break;
	case SLAPI_BIND_RET_SASLCREDS:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((struct berval **)value) = pb->pb_rs->sr_sasldata;
		break;
	case SLAPI_EXT_OP_REQ_OID:
		*((const char **)value) = pb->pb_op->ore_reqoid.bv_val;
		break;
	case SLAPI_EXT_OP_REQ_VALUE:
		*((struct berval **)value) = pb->pb_op->ore_reqdata;
		break;
	case SLAPI_EXT_OP_RET_OID:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((const char **)value) = pb->pb_rs->sr_rspoid;
		break;
	case SLAPI_EXT_OP_RET_VALUE:
		PBLOCK_ASSERT_OP( pb, 0 );
		*((struct berval **)value) = pb->pb_rs->sr_rspdata;
		break;
	case SLAPI_BIND_METHOD:
		if ( pb->pb_op->o_tag == LDAP_REQ_BIND )
			*((int *)value) = pb->pb_op->orb_method;
		else
			*((int *)value) = 0;
		break;
	case SLAPI_BIND_CREDENTIALS:
		if ( pb->pb_op->o_tag == LDAP_REQ_BIND )
			*((struct berval **)value) = &pb->pb_op->orb_cred;
		else
			*value = NULL;
		break;
	case SLAPI_COMPARE_TYPE:
		if ( pb->pb_op->o_tag == LDAP_REQ_COMPARE )
			*((char **)value) = pb->pb_op->orc_ava->aa_desc->ad_cname.bv_val;
		else
			*value = NULL;
		break;
	case SLAPI_COMPARE_VALUE:
		if ( pb->pb_op->o_tag == LDAP_REQ_COMPARE )
			*((struct berval **)value) = &pb->pb_op->orc_ava->aa_value;
		else
			*value = NULL;
		break;
	case SLAPI_ABANDON_MSGID:
		if ( pb->pb_op->o_tag == LDAP_REQ_ABANDON )
			*((int *)value) = pb->pb_op->orn_msgid;
		else
			*((int *)value) = 0;
		break;
	default:
		rc = pblock_get_default( pb, param, value );
		break;
	}

	pblock_unlock( pb );

	return rc;
}
Example #8
0
int
meta_back_add( Operation *op, SlapReply *rs )
{
	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
	metatarget_t	*mt;
	metaconn_t	*mc;
	int		i, candidate = -1;
	int		isupdate;
	Attribute	*a;
	LDAPMod		**attrs;
	struct berval	mdn = BER_BVNULL, mapped;
	dncookie	dc;
	int		msgid;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
	LDAPControl	**ctrls = NULL;

	Debug(LDAP_DEBUG_ARGS, "==> meta_back_add: %s\n",
			op->o_req_dn.bv_val );

	/*
	 * get the current connection
	 */
	mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR );
	if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
		return rs->sr_err;
	}

	assert( mc->mc_conns[ candidate ].msc_ld != NULL );

	/*
	 * Rewrite the add dn, if needed
	 */
	mt = mi->mi_targets[ candidate ];
	dc.target = mt;
	dc.conn = op->o_conn;
	dc.rs = rs;
	dc.ctx = "addDN";

	if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
		send_ldap_result( op, rs );
		goto done;
	}

	/* Count number of attributes in entry ( +1 ) */
	for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next );

	/* Create array of LDAPMods for ldap_add() */
	attrs = ch_malloc( sizeof( LDAPMod * )*i );

	dc.ctx = "addAttrDN";
	isupdate = be_shadow_update( op );
	for ( i = 0, a = op->ora_e->e_attrs; a; a = a->a_next ) {
		int			j, is_oc = 0;

		if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod  )
		{
			continue;
		}

		if ( a->a_desc == slap_schema.si_ad_objectClass
				|| a->a_desc == slap_schema.si_ad_structuralObjectClass )
		{
			is_oc = 1;
			mapped = a->a_desc->ad_cname;

		} else {
			ldap_back_map( &mt->mt_rwmap.rwm_at,
					&a->a_desc->ad_cname, &mapped, BACKLDAP_MAP );
			if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
				continue;
			}
		}

		attrs[ i ] = ch_malloc( sizeof( LDAPMod ) );
		if ( attrs[ i ] == NULL ) {
			continue;
		}
		attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
		attrs[ i ]->mod_type = mapped.bv_val;

		if ( is_oc ) {
			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ )
				;

			attrs[ i ]->mod_bvalues =
				(struct berval **)ch_malloc( ( j + 1 ) *
				sizeof( struct berval * ) );

			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); ) {
				struct ldapmapping	*mapping;

				ldap_back_mapping( &mt->mt_rwmap.rwm_oc,
						&a->a_vals[ j ], &mapping, BACKLDAP_MAP );

				if ( mapping == NULL ) {
					if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
						continue;
					}
					attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];

				} else {
					attrs[ i ]->mod_bvalues[ j ] = &mapping->dst;
				}
				j++;
			}
			attrs[ i ]->mod_bvalues[ j ] = NULL;

		} else {
			/*
			 * FIXME: dn-valued attrs should be rewritten
			 * to allow their use in ACLs at the back-ldap
			 * level.
			 */
			if ( a->a_desc->ad_type->sat_syntax ==
				slap_schema.si_syn_distinguishedName )
			{
				(void)ldap_dnattr_rewrite( &dc, a->a_vals );
				if ( a->a_vals == NULL ) {
					continue;
				}
			}

			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ )
				;

			attrs[ i ]->mod_bvalues = ch_malloc( ( j + 1 ) * sizeof( struct berval * ) );
			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
				attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];
			}
			attrs[ i ]->mod_bvalues[ j ] = NULL;
		}
		i++;
	}
	attrs[ i ] = NULL;

retry:;
	ctrls = op->o_ctrls;
	if ( meta_back_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
	{
		send_ldap_result( op, rs );
		goto cleanup;
	}

	rs->sr_err = ldap_add_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val,
			      attrs, ctrls, NULL, &msgid );
	rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
		mt->mt_timeout[ SLAP_OP_ADD ], ( LDAP_BACK_SENDRESULT | retrying ) );
	if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
			/* if the identity changed, there might be need to re-authz */
			(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
			goto retry;
		}
	}

cleanup:;
	(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );

	for ( --i; i >= 0; --i ) {
		free( attrs[ i ]->mod_bvalues );
		free( attrs[ i ] );
	}
	free( attrs );
	if ( mdn.bv_val != op->ora_e->e_dn ) {
		free( mdn.bv_val );
		BER_BVZERO( &mdn );
	}

done:;
	if ( mc ) {
		meta_back_release_conn( mi, mc );
	}

	return rs->sr_err;
}
Example #9
0
int mdb_modify_internal(
	Operation *op,
	MDB_txn *tid,
	Modifications *modlist,
	Entry *e,
	const char **text,
	char *textbuf,
	size_t textlen )
{
	int rc, err;
	Modification	*mod;
	Modifications	*ml;
	Attribute	*save_attrs;
	Attribute 	*ap;
	int			glue_attr_delete = 0;
	int			got_delete;

	Debug( LDAP_DEBUG_TRACE, "mdb_modify_internal: 0x%08lx: %s\n",
		e->e_id, e->e_dn, 0);

	if ( !acl_check_modlist( op, e, modlist )) {
		return LDAP_INSUFFICIENT_ACCESS;
	}

	/* save_attrs will be disposed of by caller */
	save_attrs = e->e_attrs;
	e->e_attrs = attrs_dup( e->e_attrs );

	for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
		int match;
		mod = &ml->sml_mod;
		switch( mod->sm_op ) {
		case LDAP_MOD_ADD:
		case LDAP_MOD_REPLACE:
			if ( mod->sm_desc == slap_schema.si_ad_structuralObjectClass ) {
				value_match( &match, slap_schema.si_ad_structuralObjectClass,
					slap_schema.si_ad_structuralObjectClass->
						ad_type->sat_equality,
					SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
					&mod->sm_values[0], &scbva[0], text );
				if ( !match ) glue_attr_delete = 1;
			}
		}
		if ( glue_attr_delete )
			break;
	}

	if ( glue_attr_delete ) {
		Attribute	**app = &e->e_attrs;
		while ( *app != NULL ) {
			if ( !is_at_operational( (*app)->a_desc->ad_type )) {
				Attribute *save = *app;
				*app = (*app)->a_next;
				attr_free( save );
				continue;
			}
			app = &(*app)->a_next;
		}
	}

	for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
		mod = &ml->sml_mod;
		got_delete = 0;

		switch ( mod->sm_op ) {
		case LDAP_MOD_ADD:
			Debug(LDAP_DEBUG_ARGS,
				"mdb_modify_internal: add %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
			err = modify_add_values( e, mod, get_permissiveModify(op),
				text, textbuf, textlen );
			if( err != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
					err, *text, 0);
			}
			break;

		case LDAP_MOD_DELETE:
			if ( glue_attr_delete ) {
				err = LDAP_SUCCESS;
				break;
			}

			Debug(LDAP_DEBUG_ARGS,
				"mdb_modify_internal: delete %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
			err = modify_delete_values( e, mod, get_permissiveModify(op),
				text, textbuf, textlen );
			if( err != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
					err, *text, 0);
			} else {
				got_delete = 1;
			}
			break;

		case LDAP_MOD_REPLACE:
			Debug(LDAP_DEBUG_ARGS,
				"mdb_modify_internal: replace %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
			err = modify_replace_values( e, mod, get_permissiveModify(op),
				text, textbuf, textlen );
			if( err != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
					err, *text, 0);
			} else {
				got_delete = 1;
			}
			break;

		case LDAP_MOD_INCREMENT:
			Debug(LDAP_DEBUG_ARGS,
				"mdb_modify_internal: increment %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
			err = modify_increment_values( e, mod, get_permissiveModify(op),
				text, textbuf, textlen );
			if( err != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS,
					"mdb_modify_internal: %d %s\n",
					err, *text, 0);
			} else {
				got_delete = 1;
			}
			break;

		case SLAP_MOD_SOFTADD:
			Debug(LDAP_DEBUG_ARGS,
				"mdb_modify_internal: softadd %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
 			/* Avoid problems in index_add_mods()
 			 * We need to add index if necessary.
 			 */
 			mod->sm_op = LDAP_MOD_ADD;

			err = modify_add_values( e, mod, get_permissiveModify(op),
				text, textbuf, textlen );

 			mod->sm_op = SLAP_MOD_SOFTADD;

 			if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
 				err = LDAP_SUCCESS;
 			}

			if( err != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
					err, *text, 0);
			}
 			break;

		case SLAP_MOD_SOFTDEL:
			Debug(LDAP_DEBUG_ARGS,
				"mdb_modify_internal: softdel %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
 			/* Avoid problems in index_delete_mods()
 			 * We need to add index if necessary.
 			 */
 			mod->sm_op = LDAP_MOD_DELETE;

			err = modify_delete_values( e, mod, get_permissiveModify(op),
				text, textbuf, textlen );

 			mod->sm_op = SLAP_MOD_SOFTDEL;

 			if ( err == LDAP_NO_SUCH_ATTRIBUTE ) {
 				err = LDAP_SUCCESS;
 			}

			if( err != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
					err, *text, 0);
			}
 			break;

		case SLAP_MOD_ADD_IF_NOT_PRESENT:
			if ( attr_find( e->e_attrs, mod->sm_desc ) != NULL ) {
				/* skip */
				err = LDAP_SUCCESS;
				break;
			}

			Debug(LDAP_DEBUG_ARGS,
				"mdb_modify_internal: add_if_not_present %s\n",
				mod->sm_desc->ad_cname.bv_val, 0, 0);
 			/* Avoid problems in index_add_mods()
 			 * We need to add index if necessary.
 			 */
 			mod->sm_op = LDAP_MOD_ADD;

			err = modify_add_values( e, mod, get_permissiveModify(op),
				text, textbuf, textlen );

 			mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;

			if( err != LDAP_SUCCESS ) {
				Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
					err, *text, 0);
			}
 			break;

		default:
			Debug(LDAP_DEBUG_ANY, "mdb_modify_internal: invalid op %d\n",
				mod->sm_op, 0, 0);
			*text = "Invalid modify operation";
			err = LDAP_OTHER;
			Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
				err, *text, 0);
		}

		if ( err != LDAP_SUCCESS ) {
			attrs_free( e->e_attrs );
			e->e_attrs = save_attrs;
			/* unlock entry, delete from cache */
			return err; 
		}

		/* If objectClass was modified, reset the flags */
		if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
			e->e_ocflags = 0;
		}

		if ( glue_attr_delete ) e->e_ocflags = 0;


		/* check if modified attribute was indexed
		 * but not in case of NOOP... */
		if ( !op->o_noop ) {
			mdb_modify_idxflags( op, mod->sm_desc, got_delete, e->e_attrs, save_attrs );
		}
	}

	/* check that the entry still obeys the schema */
	ap = NULL;
	rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0, &ap,
		text, textbuf, textlen );
	if ( rc != LDAP_SUCCESS || op->o_noop ) {
		attrs_free( e->e_attrs );
		/* clear the indexing flags */
		for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
			ap->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL);
		}
		e->e_attrs = save_attrs;

		if ( rc != LDAP_SUCCESS ) {
			Debug( LDAP_DEBUG_ANY,
				"entry failed schema check: %s\n",
				*text, 0, 0 );
		}

		/* if NOOP then silently revert to saved attrs */
		return rc;
	}

	/* structuralObjectClass modified! */
	if ( ap ) {
		assert( ap->a_desc == slap_schema.si_ad_structuralObjectClass );
		if ( !op->o_noop ) {
			mdb_modify_idxflags( op, slap_schema.si_ad_structuralObjectClass,
				1, e->e_attrs, save_attrs );
		}
	}

	/* update the indices of the modified attributes */

	/* start with deleting the old index entries */
	for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
		if ( ap->a_flags & SLAP_ATTR_IXDEL ) {
			struct berval *vals;
			Attribute *a2;
			ap->a_flags &= ~SLAP_ATTR_IXDEL;
			a2 = attr_find( e->e_attrs, ap->a_desc );
			if ( a2 ) {
				/* need to detect which values were deleted */
				int i, j;
				vals = op->o_tmpalloc( (ap->a_numvals + 1) *
					sizeof(struct berval), op->o_tmpmemctx );
				j = 0;
				for ( i=0; i < ap->a_numvals; i++ ) {
					rc = attr_valfind( a2, SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
						&ap->a_nvals[i], NULL, op->o_tmpmemctx );
					/* Save deleted values */
					if ( rc == LDAP_NO_SUCH_ATTRIBUTE )
						vals[j++] = ap->a_nvals[i];
				}
				BER_BVZERO(vals+j);
			} else {
				/* attribute was completely deleted */
				vals = ap->a_nvals;
			}
			rc = 0;
			if ( !BER_BVISNULL( vals )) {
				rc = mdb_index_values( op, tid, ap->a_desc,
					vals, e->e_id, SLAP_INDEX_DELETE_OP );
				if ( rc != LDAP_SUCCESS ) {
					Debug( LDAP_DEBUG_ANY,
						"%s: attribute \"%s\" index delete failure\n",
						op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 );
					attrs_free( e->e_attrs );
					e->e_attrs = save_attrs;
				}
			}
			if ( vals != ap->a_nvals )
				op->o_tmpfree( vals, op->o_tmpmemctx );
			if ( rc ) return rc;
		}
	}

	/* add the new index entries */
	for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
		if (ap->a_flags & SLAP_ATTR_IXADD) {
			ap->a_flags &= ~SLAP_ATTR_IXADD;
			rc = mdb_index_values( op, tid, ap->a_desc,
				ap->a_nvals,
				e->e_id, SLAP_INDEX_ADD_OP );
			if ( rc != LDAP_SUCCESS ) {
				Debug( LDAP_DEBUG_ANY,
				       "%s: attribute \"%s\" index add failure\n",
					op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 );
				attrs_free( e->e_attrs );
				e->e_attrs = save_attrs;
				return rc;
			}
		}
	}

	return rc;
}
Example #10
0
int
mdb_add(Operation *op, SlapReply *rs )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
	struct berval	pdn;
	Entry		*p = NULL, *oe = op->ora_e;
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	MDB_txn		*txn = NULL;
	MDB_cursor	*mc = NULL;
	MDB_cursor	*mcd;
	ID eid, pid = 0;
	mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
	int subentry;
	int numads = mdb->mi_numads;

	int		success;

	LDAPControl **postread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

#ifdef LDAP_X_TXN
	int settle = 0;
#endif

	Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(mdb_add) ": %s\n",
		op->ora_e->e_name.bv_val, 0, 0);

#ifdef LDAP_X_TXN
	if( op->o_txnSpec ) {
		/* acquire connection lock */
		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
		if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
			rs->sr_text = "invalid transaction identifier";
			rs->sr_err = LDAP_X_TXN_ID_INVALID;
			goto txnReturn;
		} else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
			settle=1;
			goto txnReturn;
		}

		if( op->o_conn->c_txn_backend == NULL ) {
			op->o_conn->c_txn_backend = op->o_bd;

		} else if( op->o_conn->c_txn_backend != op->o_bd ) {
			rs->sr_text = "transaction cannot span multiple database contexts";
			rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
			goto txnReturn;
		}

		/* insert operation into transaction */

		rs->sr_text = "transaction specified";
		rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;

txnReturn:
		/* release connection lock */
		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );

		if( !settle ) {
			send_ldap_result( op, rs );
			return rs->sr_err;
		}
	}
#endif

	ctrls[num_ctrls] = 0;

	/* check entry's schema */
	rs->sr_err = entry_schema_check( op, op->ora_e, NULL,
		get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": entry failed schema check: "
			"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
		goto return_results;
	}

	/* begin transaction */
	rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
	rs->sr_text = NULL;
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": txn_begin failed: %s (%d)\n",
			mdb_strerror(rs->sr_err), rs->sr_err, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	txn = moi->moi_txn;

	/* add opattrs to shadow as well, only missing attrs will actually
	 * be added; helps compatibility with older OL versions */
	rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": entry failed op attrs add: "
			"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
		goto return_results;
	}

	if ( get_assert( op ) &&
		( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto return_results;
	}

	subentry = is_entry_subentry( op->ora_e );

	/*
	 * Get the parent dn and see if the corresponding entry exists.
	 */
	if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
		pdn = slap_empty_bv;
	} else {
		dnParent( &op->ora_e->e_nname, &pdn );
	}

	rs->sr_err = mdb_cursor_open( txn, mdb->mi_dn2id, &mcd );
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": mdb_cursor_open failed (%d)\n",
			rs->sr_err, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* get entry or parent */
	rs->sr_err = mdb_dn2entry( op, txn, mcd, &op->ora_e->e_nname, &p, NULL, 1 );
	switch( rs->sr_err ) {
	case 0:
		rs->sr_err = LDAP_ALREADY_EXISTS;
		mdb_entry_return( op, p );
		p = NULL;
		goto return_results;
	case MDB_NOTFOUND:
		break;
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	if ( !p )
		p = (Entry *)&slap_entry_root;

	if ( !bvmatch( &pdn, &p->e_nname ) ) {
		rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
			op->o_tmpmemctx );
		if ( p != (Entry *)&slap_entry_root && is_entry_referral( p )) {
			BerVarray ref = get_entry_referrals( op, p );
			rs->sr_ref = referral_rewrite( ref, &p->e_name,
				&op->o_req_dn, LDAP_SCOPE_DEFAULT );
			ber_bvarray_free( ref );
		} else {
			rs->sr_ref = NULL;
		}
		if ( p != (Entry *)&slap_entry_root )
			mdb_entry_return( op, p );
		p = NULL;
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": parent "
			"does not exist\n", 0, 0, 0 );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	rs->sr_err = access_allowed( op, p,
		children, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		if ( p != (Entry *)&slap_entry_root )
			mdb_entry_return( op, p );
		p = NULL;

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": no write access to parent\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to parent";
		goto return_results;;
	}

	if ( p != (Entry *)&slap_entry_root ) {
		if ( is_entry_subentry( p ) ) {
			mdb_entry_return( op, p );
			p = NULL;
			/* parent is a subentry, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_add) ": parent is subentry\n",
				0, 0, 0 );
			rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			rs->sr_text = "parent is a subentry";
			goto return_results;;
		}

		if ( is_entry_alias( p ) ) {
			mdb_entry_return( op, p );
			p = NULL;
			/* parent is an alias, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_add) ": parent is alias\n",
				0, 0, 0 );
			rs->sr_err = LDAP_ALIAS_PROBLEM;
			rs->sr_text = "parent is an alias";
			goto return_results;;
		}

		if ( is_entry_referral( p ) ) {
			BerVarray ref = get_entry_referrals( op, p );
			/* parent is a referral, don't allow add */
			rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
				op->o_tmpmemctx );
			rs->sr_ref = referral_rewrite( ref, &p->e_name,
				&op->o_req_dn, LDAP_SCOPE_DEFAULT );
			ber_bvarray_free( ref );
			mdb_entry_return( op, p );
			p = NULL;
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_add) ": parent is referral\n",
				0, 0, 0 );

			rs->sr_err = LDAP_REFERRAL;
			rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
			goto return_results;
		}

	}

	if ( subentry ) {
		/* FIXME: */
		/* parent must be an administrative point of the required kind */
	}

	/* free parent */
	if ( p != (Entry *)&slap_entry_root ) {
		pid = p->e_id;
		if ( p->e_nname.bv_len ) {
			struct berval ppdn;

			/* ITS#5326: use parent's DN if differs from provided one */
			dnParent( &op->ora_e->e_name, &ppdn );
			if ( !dn_match( &p->e_name, &ppdn ) ) {
				struct berval rdn;
				struct berval newdn;

				dnRdn( &op->ora_e->e_name, &rdn );

				build_new_dn( &newdn, &p->e_name, &rdn, NULL ); 
				if ( op->ora_e->e_name.bv_val != op->o_req_dn.bv_val )
					ber_memfree( op->ora_e->e_name.bv_val );
				op->ora_e->e_name = newdn;

				/* FIXME: should check whether
				 * dnNormalize(newdn) == e->e_nname ... */
			}
		}

		mdb_entry_return( op, p );
	}
	p = NULL;

	rs->sr_err = access_allowed( op, op->ora_e,
		entry, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": no write access to entry\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to entry";
		goto return_results;;
	}

	/* 
	 * Check ACL for attribute write access
	 */
	if (!acl_check_modlist(op, oe, op->ora_modlist)) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": no write access to attribute\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to attribute";
		goto return_results;;
	}

	rs->sr_err = mdb_cursor_open( txn, mdb->mi_id2entry, &mc );
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": mdb_cursor_open failed (%d)\n",
			rs->sr_err, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	rs->sr_err = mdb_next_id( op->o_bd, mc, &eid );
	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": next_id failed (%d)\n",
			rs->sr_err, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	op->ora_e->e_id = eid;

	/* dn2id index */
	rs->sr_err = mdb_dn2id_add( op, mcd, mcd, pid, 1, 1, op->ora_e );
	mdb_cursor_close( mcd );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": dn2id_add failed: %s (%d)\n",
			mdb_strerror(rs->sr_err), rs->sr_err, 0 );

		switch( rs->sr_err ) {
		case MDB_KEYEXIST:
			rs->sr_err = LDAP_ALREADY_EXISTS;
			break;
		default:
			rs->sr_err = LDAP_OTHER;
		}
		goto return_results;
	}

	/* attribute indexes */
	rs->sr_err = mdb_index_entry_add( op, txn, op->ora_e );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": index_entry_add failed\n",
			0, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "index generation failed";
		goto return_results;
	}

	/* id2entry index */
	rs->sr_err = mdb_id2entry_add( op, txn, mc, op->ora_e );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_add) ": id2entry_add failed\n",
			0, 0, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "entry store failed";
		goto return_results;
	}

	/* post-read */
	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if ( slap_read_controls( op, rs, op->ora_e,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(mdb_add) ": post-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	if ( moi == &opinfo ) {
		LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
		opinfo.moi_oe.oe_key = NULL;
		if ( op->o_noop ) {
			mdb->mi_numads = numads;
			mdb_txn_abort( txn );
			rs->sr_err = LDAP_X_NO_OPERATION;
			txn = NULL;
			goto return_results;
		}

		rs->sr_err = mdb_txn_commit( txn );
		txn = NULL;
		if ( rs->sr_err != 0 ) {
			mdb->mi_numads = numads;
			rs->sr_text = "txn_commit failed";
			Debug( LDAP_DEBUG_ANY,
				LDAP_XSTRING(mdb_add) ": %s : %s (%d)\n",
				rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err );
			rs->sr_err = LDAP_OTHER;
			goto return_results;
		}
	}

	Debug(LDAP_DEBUG_TRACE,
		LDAP_XSTRING(mdb_add) ": added%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		op->ora_e->e_id, op->ora_e->e_dn );

	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	success = rs->sr_err;
	send_ldap_result( op, rs );

	if( moi == &opinfo ) {
		if( txn != NULL ) {
			mdb->mi_numads = numads;
			mdb_txn_abort( txn );
		}
		if ( opinfo.moi_oe.oe_key ) {
			LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
		}
	} else {
		moi->moi_ref--;
	}

	if( success == LDAP_SUCCESS ) {
#if 0
		if ( mdb->bi_txn_cp_kbyte ) {
			TXN_CHECKPOINT( mdb->bi_dbenv,
				mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
		}
#endif
	}

	slap_graduate_commit_csn( op );

	if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
		slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
	}
	return rs->sr_err;
}
Example #11
0
int
ldap_back_add(
	Operation	*op,
	SlapReply	*rs )
{
	ldapinfo_t		*li = (ldapinfo_t *)op->o_bd->be_private;

	ldapconn_t		*lc = NULL;
	int			i = 0,
				j = 0;
	Attribute		*a;
	LDAPMod			**attrs = NULL,
				*attrs2 = NULL;
	ber_int_t		msgid;
	int			isupdate;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
	LDAPControl		**ctrls = NULL;

	rs->sr_err = LDAP_SUCCESS;
	
	Debug( LDAP_DEBUG_ARGS, "==> ldap_back_add(\"%s\")\n",
			op->o_req_dn.bv_val, 0, 0 );

	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
		lc = NULL;
		goto cleanup;
	}

	/* Count number of attributes in entry */
	for ( i = 1, a = op->oq_add.rs_e->e_attrs; a; i++, a = a->a_next )
		/* just count attrs */ ;
	
	/* Create array of LDAPMods for ldap_add() */
	attrs = (LDAPMod **)ch_malloc( sizeof( LDAPMod * )*i 
			+ sizeof( LDAPMod )*( i - 1 ) );
	attrs2 = ( LDAPMod * )&attrs[ i ];

	isupdate = be_shadow_update( op );
	for ( i = 0, a = op->oq_add.rs_e->e_attrs; a; a = a->a_next ) {
		if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod  )
		{
			continue;
		}

		attrs[ i ] = &attrs2[ i ];
		attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
		attrs[ i ]->mod_type = a->a_desc->ad_cname.bv_val;

		for ( j = 0; a->a_vals[ j ].bv_val; j++ )
			/* just count vals */ ;
		attrs[i]->mod_vals.modv_bvals = 
			ch_malloc( ( j + 1 )*sizeof( struct berval * ) );
		for ( j = 0; a->a_vals[ j ].bv_val; j++ ) {
			attrs[ i ]->mod_vals.modv_bvals[ j ] = &a->a_vals[ j ];
		}
		attrs[ i ]->mod_vals.modv_bvals[ j ] = NULL;
		i++;
	}
	attrs[ i ] = NULL;

retry:
	ctrls = op->o_ctrls;
	rs->sr_err = ldap_back_controls_add( op, rs, lc, &ctrls );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		goto cleanup;
	}

	rs->sr_err = ldap_add_ext( lc->lc_ld, op->o_req_dn.bv_val, attrs,
			ctrls, NULL, &msgid );
	rs->sr_err = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_ADD ],
		( LDAP_BACK_SENDRESULT | retrying ) );
	if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
			/* if the identity changed, there might be need to re-authz */
			(void)ldap_back_controls_free( op, rs, &ctrls );
			goto retry;
		}
	}

	ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
	ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_ADD ], 1 );
	ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );

cleanup:
	(void)ldap_back_controls_free( op, rs, &ctrls );

	if ( attrs ) {
		for ( --i; i >= 0; --i ) {
			ch_free( attrs[ i ]->mod_vals.modv_bvals );
		}
		ch_free( attrs );
	}

	if ( lc ) {
		ldap_back_release_conn( li, lc );
	}

	Debug( LDAP_DEBUG_ARGS, "<== ldap_back_add(\"%s\"): %d\n",
			op->o_req_dn.bv_val, rs->sr_err, 0 );

	return rs->sr_err;
}
Example #12
0
static int
constraint_update( Operation *op, SlapReply *rs )
{
	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
	Backend *be = op->o_bd;
	constraint *c = on->on_bi.bi_private, *cp;
	Entry *target_entry = NULL, *target_entry_copy = NULL;
	Modifications *modlist, *m;
	BerVarray b = NULL;
	int i;
	struct berval rsv = BER_BVC("modify breaks constraint");
	int rc;
	char *msg = NULL;

	if (get_relax(op)) {
		return SLAP_CB_CONTINUE;
	}

	switch ( op->o_tag ) {
	case LDAP_REQ_MODIFY:
		modlist = op->orm_modlist;
		break;

	case LDAP_REQ_MODRDN:
		modlist = op->orr_modlist;
		break;

	default:
		/* impossible! assert? */
		return LDAP_OTHER;
	}
	
	Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "constraint_update()\n", 0,0,0);
	if ((m = modlist) == NULL) {
		op->o_bd->bd_info = (BackendInfo *)(on->on_info);
		send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
						"constraint_update() got null modlist");
		return(rs->sr_err);
	}

	/* Do we need to count attributes? */
	for(cp = c; cp; cp = cp->ap_next) {
		if (cp->count != 0 || cp->set || cp->restrict_lud != 0) {
			op->o_bd = on->on_info->oi_origdb;
			rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &target_entry );
			op->o_bd = be;

			if (rc != 0 || target_entry == NULL) {
				Debug(LDAP_DEBUG_TRACE, 
					"==> constraint_update rc = %d DN=\"%s\"%s\n",
					rc, op->o_req_ndn.bv_val,
					target_entry ? "" : " not found" );
				if ( rc == 0 ) 
					rc = LDAP_CONSTRAINT_VIOLATION;
				goto mod_violation;
			}
			break;
		}
	}

	rc = LDAP_CONSTRAINT_VIOLATION;
	for(;m; m = m->sml_next) {
		unsigned ce = 0;

		if (is_at_operational( m->sml_desc->ad_type )) continue;

		if ((( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_ADD) &&
			(( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_REPLACE) &&
			(( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_DELETE))
			continue;
		/* we only care about ADD and REPLACE modifications */
		/* and DELETE are used to track attribute count */
		if ((( b = m->sml_values ) == NULL ) || (b[0].bv_val == NULL))
			continue;

		/* Get this attribute count, if needed */
		if (target_entry)
			ce = constraint_count_attr(target_entry, m->sml_desc);

		for(cp = c; cp; cp = cp->ap_next) {
			int j;
			for (j = 0; cp->ap[j]; j++) {
				if (cp->ap[j] == m->sml_desc) {
					break;
				}
			}
			if (cp->ap[j] == NULL) continue;

			if (cp->restrict_lud != NULL && constraint_check_restrict(op, cp, target_entry) == 0) {
				continue;
			}

			if (cp->count != 0) {
				unsigned ca;

				if (m->sml_op == LDAP_MOD_DELETE)
					ce = 0;

				for (ca = 0; b[ca].bv_val; ++ca);

				Debug(LDAP_DEBUG_TRACE, 
					"==> constraint_update ce = %u, "
					"ca = %u, cp->count = %lu\n",
					ce, ca, (unsigned long) cp->count);

				if (m->sml_op == LDAP_MOD_ADD) {
					if (ca + ce > cp->count) {
						rc = LDAP_CONSTRAINT_VIOLATION;
						goto mod_violation;
					}
				}
				if (m->sml_op == LDAP_MOD_REPLACE) {
					if (ca > cp->count) {
						rc = LDAP_CONSTRAINT_VIOLATION;
						goto mod_violation;
					}
					ce = ca;
				}
			} 

			/* DELETE are to be ignored beyond this point */
			if (( m->sml_op & LDAP_MOD_OP ) == LDAP_MOD_DELETE)
				continue;

			for ( i = 0; b[i].bv_val; i++ ) {
				rc = constraint_violation( cp, &b[i], op, rs );
				if ( rc ) {
					goto mod_violation;
				}
			}

			if (cp->set && target_entry) {
				if (target_entry_copy == NULL) {
					Modifications *ml;

					target_entry_copy = entry_dup(target_entry);

					/* if rename, set the new entry's name
					 * (in normalized form only) */
					if ( op->o_tag == LDAP_REQ_MODRDN ) {
						struct berval pdn, ndn = BER_BVNULL;

						if ( op->orr_nnewSup ) {
							pdn = *op->orr_nnewSup;

						} else {
							dnParent( &target_entry_copy->e_nname, &pdn );
						}

						build_new_dn( &ndn, &pdn, &op->orr_nnewrdn, NULL ); 

						ber_memfree( target_entry_copy->e_nname.bv_val );
						target_entry_copy->e_nname = ndn;
						ber_bvreplace( &target_entry_copy->e_name, &ndn );
					}

					/* apply modifications, in an attempt
					 * to estimate what the entry would
					 * look like in case all modifications
					 * pass */
					for ( ml = modlist; ml; ml = ml->sml_next ) {
						Modification *mod = &ml->sml_mod;
						const char *text;
						char textbuf[SLAP_TEXT_BUFLEN];
						size_t textlen = sizeof(textbuf);
						int err;

						switch ( mod->sm_op ) {
						case LDAP_MOD_ADD:
							err = modify_add_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
							break;

						case LDAP_MOD_DELETE:
							err = modify_delete_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
							break;

						case LDAP_MOD_REPLACE:
							err = modify_replace_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
							break;

						case LDAP_MOD_INCREMENT:
							err = modify_increment_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
							break;

						case SLAP_MOD_SOFTADD:
 							mod->sm_op = LDAP_MOD_ADD;
							err = modify_add_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
 							mod->sm_op = SLAP_MOD_SOFTADD;
 							if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
 								err = LDAP_SUCCESS;
 							}
							break;

						case SLAP_MOD_SOFTDEL:
 							mod->sm_op = LDAP_MOD_ADD;
							err = modify_delete_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
 							mod->sm_op = SLAP_MOD_SOFTDEL;
 							if ( err == LDAP_NO_SUCH_ATTRIBUTE ) {
 								err = LDAP_SUCCESS;
 							}
							break;

						case SLAP_MOD_ADD_IF_NOT_PRESENT:
							if ( attr_find( target_entry_copy->e_attrs, mod->sm_desc ) ) {
								err = LDAP_SUCCESS;
								break;
							}
 							mod->sm_op = LDAP_MOD_ADD;
							err = modify_add_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
 							mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
							break;

						default:
							err = LDAP_OTHER;
							break;
						}

						if ( err != LDAP_SUCCESS ) {
							rc = err;
							goto mod_violation;
						}
					}
				}

				if ( acl_match_set(&cp->val, op, target_entry_copy, NULL) == 0) {
					rc = LDAP_CONSTRAINT_VIOLATION;
					goto mod_violation;
				}
			}
		}
	}

	if (target_entry) {
		op->o_bd = on->on_info->oi_origdb;
		be_entry_release_r(op, target_entry);
		op->o_bd = be;
	}

	if (target_entry_copy) {
		entry_free(target_entry_copy);
	}

	return SLAP_CB_CONTINUE;

mod_violation:
	/* violation */
	if (target_entry) {
		op->o_bd = on->on_info->oi_origdb;
		be_entry_release_r(op, target_entry);
		op->o_bd = be;
	}

	if (target_entry_copy) {
		entry_free(target_entry_copy);
	}

	op->o_bd->bd_info = (BackendInfo *)(on->on_info);
	if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
		msg = print_message( &rsv, m->sml_desc );
	}
	send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, msg );
	ch_free(msg);
	return (rs->sr_err);
}
Example #13
0
static int
constraint_add( Operation *op, SlapReply *rs )
{
	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
	Attribute *a;
	constraint *c = on->on_bi.bi_private, *cp;
	BerVarray b = NULL;
	int i;
	struct berval rsv = BER_BVC("add breaks constraint");
	int rc;
	char *msg = NULL;

	if (get_relax(op)) {
		return SLAP_CB_CONTINUE;
	}

	if ((a = op->ora_e->e_attrs) == NULL) {
		op->o_bd->bd_info = (BackendInfo *)(on->on_info);
		send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
			"constraint_add: no attrs");
		return(rs->sr_err);
	}

	for(; a; a = a->a_next ) {
		/* we don't constrain operational attributes */
		if (is_at_operational(a->a_desc->ad_type)) continue;

		for(cp = c; cp; cp = cp->ap_next) {
			int j;
			for (j = 0; cp->ap[j]; j++) {
				if (cp->ap[j] == a->a_desc) break;
			}
			if (cp->ap[j] == NULL) continue;
			if ((b = a->a_vals) == NULL) continue;

			if (cp->restrict_lud != NULL && constraint_check_restrict(op, cp, op->ora_e) == 0) {
				continue;
			}

			Debug(LDAP_DEBUG_TRACE, 
				"==> constraint_add, "
				"a->a_numvals = %u, cp->count = %lu\n",
				a->a_numvals, (unsigned long) cp->count, 0);

			if ((cp->count != 0) && (a->a_numvals > cp->count)) {
				rc = LDAP_CONSTRAINT_VIOLATION;
				goto add_violation;
			}

			for ( i = 0; b[i].bv_val; i++ ) {
				rc = constraint_violation( cp, &b[i], op, rs );
				if ( rc ) {
					goto add_violation;
				}
			}

			if (cp->set && acl_match_set(&cp->val, op, op->ora_e, NULL) == 0) {
				rc = LDAP_CONSTRAINT_VIOLATION;
				goto add_violation; /* constraint violation */
			}

		}
	}

	/* Default is to just fall through to the normal processing */
	return SLAP_CB_CONTINUE;

add_violation:
	op->o_bd->bd_info = (BackendInfo *)(on->on_info);
	if (rc == LDAP_CONSTRAINT_VIOLATION ) {
		msg = print_message( &rsv, a->a_desc );
	}
	send_ldap_error(op, rs, rc, msg );
	ch_free(msg);
	return (rs->sr_err);
}
Example #14
0
meta_search_candidate_t
asyncmeta_back_add_start(Operation *op,
			 SlapReply *rs,
			 a_metaconn_t *mc,
			 bm_context_t *bc,
			 int candidate)
{
	int		isupdate;
	Attribute	*a;
	int i;
	LDAPMod		**attrs;
	struct berval	mapped;
	a_dncookie	dc;
	a_metainfo_t	*mi = mc->mc_info;
	a_metatarget_t	*mt = mi->mi_targets[ candidate ];
	struct berval   mdn;
	meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
	BerElement *ber = NULL;
	a_metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
	SlapReply		*candidates = bc->candidates;
	ber_int_t	msgid;
	LDAPControl		**ctrls = NULL;
	int rc, nretries = 1;


	dc.target = mt;
	dc.conn = op->o_conn;
	dc.rs = rs;
	dc.ctx = "addDN";

	mdn.bv_len = 0;

	switch (asyncmeta_dn_massage( &dc, &bc->op->o_req_dn, &mdn ) )
	{
	case LDAP_SUCCESS:
		break;
	case LDAP_UNWILLING_TO_PERFORM:
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		rs->sr_text = "Operation not allowed";
		retcode = META_SEARCH_ERR;
		goto doreturn;
	default:
		rs->sr_err = LDAP_NO_SUCH_OBJECT;
		retcode = META_SEARCH_NOT_CANDIDATE;
		goto doreturn;
	}

	/* Count number of attributes in entry ( +1 ) */
	for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next );

	/* Create array of LDAPMods for ldap_add() */
	attrs = ch_malloc( sizeof( LDAPMod * )*i );

	dc.ctx = "addAttrDN";
	isupdate = be_shadow_update( op );
	for ( i = 0, a = op->ora_e->e_attrs; a; a = a->a_next ) {
		int j, is_oc = 0;

		if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod  )
		{
			continue;
		}

		if ( a->a_desc == slap_schema.si_ad_objectClass
				|| a->a_desc == slap_schema.si_ad_structuralObjectClass )
		{
			is_oc = 1;
			mapped = a->a_desc->ad_cname;

		} else {
			asyncmeta_map( &mt->mt_rwmap.rwm_at,
					&a->a_desc->ad_cname, &mapped, BACKLDAP_MAP );
			if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
				continue;
			}
		}

		attrs[ i ] = ch_malloc( sizeof( LDAPMod ) );
		if ( attrs[ i ] == NULL ) {
			continue;
		}
		attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
		attrs[ i ]->mod_type = mapped.bv_val;

		if ( is_oc ) {
			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ );

			attrs[ i ]->mod_bvalues =
				(struct berval **)ch_malloc( ( j + 1 ) *
				sizeof( struct berval * ) );
			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); ) {
				struct ldapmapping	*mapping;

				asyncmeta_mapping( &mt->mt_rwmap.rwm_oc,
						&a->a_vals[ j ], &mapping, BACKLDAP_MAP );

				if ( mapping == NULL ) {
					if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
						continue;
					}
					attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];

				} else {
					attrs[ i ]->mod_bvalues[ j ] = &mapping->dst;
				}
				j++;
			}
			attrs[ i ]->mod_bvalues[ j ] = NULL;

		} else {
			/*
			 * FIXME: dn-valued attrs should be rewritten
			 * to allow their use in ACLs at the back-ldap
			 * level.
			 */
			if ( a->a_desc->ad_type->sat_syntax ==
				slap_schema.si_syn_distinguishedName )
			{
				(void)asyncmeta_dnattr_rewrite( &dc, a->a_vals );
				if ( a->a_vals == NULL ) {
					continue;
				}
			}

			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ )
				;

			attrs[ i ]->mod_bvalues = ch_malloc( ( j + 1 ) * sizeof( struct berval * ) );
			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
				attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];
			}
			attrs[ i ]->mod_bvalues[ j ] = NULL;
		}
		i++;
	}
	attrs[ i ] = NULL;

retry:;
	ctrls = op->o_ctrls;
	if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
	{
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
		retcode = META_SEARCH_ERR;
		goto done;
	}

	ber = ldap_build_add_req( msc->msc_ld, mdn.bv_val, attrs, ctrls, NULL, &msgid);
	if (ber) {
		candidates[ candidate ].sr_msgid = msgid;
		rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_ADD,
						mdn.bv_val, ber, msgid );
		if (rc == msgid)
			rc = LDAP_SUCCESS;
		else
			rc = LDAP_SERVER_DOWN;

		switch ( rc ) {
		case LDAP_SUCCESS:
			retcode = META_SEARCH_CANDIDATE;
			asyncmeta_set_msc_time(msc);
			break;

		case LDAP_SERVER_DOWN:
			ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
			asyncmeta_clear_one_msc(NULL, mc, candidate);
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
			if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
				nretries = 0;
				/* if the identity changed, there might be need to re-authz */
				(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
				goto retry;
			}

		default:
			candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
			retcode = META_SEARCH_ERR;
		}
	}

done:

	(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );

	for ( --i; i >= 0; --i ) {
		free( attrs[ i ]->mod_bvalues );
		free( attrs[ i ] );
	}
	free( attrs );
	if ( mdn.bv_val != op->ora_e->e_dn ) {
		free( mdn.bv_val );
		BER_BVZERO( &mdn );
	}

doreturn:;
	Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_add_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
	return retcode;
}
Example #15
0
static int
dds_op_modify( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
	dds_info_t	*di = (dds_info_t *)on->on_bi.bi_private;
	Modifications	*mod;
	Entry		*e = NULL;
	BackendInfo	*bi = op->o_bd->bd_info;
	int		was_dynamicObject = 0,
			is_dynamicObject = 0;
	struct berval	bv_entryTtl = BER_BVNULL;
	time_t		entryTtl = 0;
	char		textbuf[ SLAP_TEXT_BUFLEN ];

	if ( DDS_OFF( di ) ) {
		return SLAP_CB_CONTINUE;
	}

	/* bv_entryTtl stores the string representation of the entryTtl
	 * across modifies for consistency checks of the final value;
	 * the bv_val points to a static buffer; the bv_len is zero when
	 * the attribute is deleted.
	 * entryTtl stores the integer representation of the entryTtl;
	 * its value is -1 when the attribute is deleted; it is 0 only
	 * if no modifications of the entryTtl occurred, as an entryTtl
	 * of 0 is invalid. */
	bv_entryTtl.bv_val = textbuf;

	op->o_bd->bd_info = (BackendInfo *)on->on_info;
	rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
		slap_schema.si_oc_dynamicObject, slap_schema.si_ad_entryTtl, 0, &e );
	if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) {
		Attribute	*a = attr_find( e->e_attrs, slap_schema.si_ad_entryTtl );

		/* the value of the entryTtl is saved for later checks */
		if ( a != NULL ) {
			unsigned long	ttl;
			int		rc;

			bv_entryTtl.bv_len = a->a_nvals[ 0 ].bv_len;
			memcpy( bv_entryTtl.bv_val, a->a_nvals[ 0 ].bv_val, bv_entryTtl.bv_len );
			bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0';
			rc = lutil_atoul( &ttl, bv_entryTtl.bv_val );
			assert( rc == 0 );
			entryTtl = (time_t)ttl;
		}

		be_entry_release_r( op, e );
		e = NULL;
		was_dynamicObject = is_dynamicObject = 1;
	}
	op->o_bd->bd_info = bi;

	rs->sr_err = LDAP_SUCCESS;
	for ( mod = op->orm_modlist; mod; mod = mod->sml_next ) {
		if ( mod->sml_desc == slap_schema.si_ad_objectClass ) {
			int		i;
			ObjectClass	*oc;

			switch ( mod->sml_op ) {
			case LDAP_MOD_DELETE:
				if ( mod->sml_values == NULL ) {
					is_dynamicObject = 0;
					break;
				}

				for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) {
					oc = oc_bvfind( &mod->sml_values[ i ] );
					if ( oc == slap_schema.si_oc_dynamicObject ) {
						is_dynamicObject = 0;
						break;
					}
				}

				break;

			case LDAP_MOD_REPLACE:
				if ( mod->sml_values == NULL ) {
					is_dynamicObject = 0;
					break;
				}
				/* fallthru */

			case LDAP_MOD_ADD:
				for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) {
					oc = oc_bvfind( &mod->sml_values[ i ] );
					if ( oc == slap_schema.si_oc_dynamicObject ) {
						is_dynamicObject = 1;
						break;
					}
				}
				break;
			}

		} else if ( mod->sml_desc == slap_schema.si_ad_entryTtl ) {
			unsigned long	uttl;
			time_t		ttl;
			int		rc;

			switch ( mod->sml_op ) {
			case LDAP_MOD_DELETE:
			case SLAP_MOD_SOFTDEL: /* FIXME? */
				if ( mod->sml_values != NULL ) {
					if ( BER_BVISEMPTY( &bv_entryTtl )
						|| !bvmatch( &bv_entryTtl, &mod->sml_values[ 0 ] ) )
					{
						rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn,
							slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
						if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) {
							rs->sr_err = LDAP_NO_SUCH_OBJECT;

						} else {
							rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
						}
						goto done;
					}
				}
				bv_entryTtl.bv_len = 0;
				entryTtl = -1;
				break;

			case LDAP_MOD_REPLACE:
				bv_entryTtl.bv_len = 0;
				entryTtl = -1;
				/* fallthru */

			case LDAP_MOD_ADD:
			case SLAP_MOD_SOFTADD: /* FIXME? */
			case SLAP_MOD_ADD_IF_NOT_PRESENT: /* FIXME? */
				assert( mod->sml_values != NULL );
				assert( BER_BVISNULL( &mod->sml_values[ 1 ] ) );

				if ( !BER_BVISEMPTY( &bv_entryTtl ) ) {
					rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn,
						slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
					if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) {
						rs->sr_err = LDAP_NO_SUCH_OBJECT;

					} else {
						rs->sr_text = "attribute 'entryTtl' cannot have multiple values";
						rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
					}
					goto done;
				}

				rc = lutil_atoul( &uttl, mod->sml_values[ 0 ].bv_val );
				ttl = (time_t)uttl;
				assert( rc == 0 );
				if ( ttl > DDS_RF2589_MAX_TTL ) {
					rs->sr_err = LDAP_PROTOCOL_ERROR;
					rs->sr_text = "invalid time-to-live for dynamicObject";
					goto done;
				}

				if ( ttl <= 0 || ttl > di->di_max_ttl ) {
					/* FIXME: I don't understand if this has to be an error,
					 * or an indication that the requested Ttl has been
					 * shortened to di->di_max_ttl >= 1 day */
					rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
					rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit";
					goto done;
				}

				entryTtl = ttl;
				bv_entryTtl.bv_len = mod->sml_values[ 0 ].bv_len;
				memcpy( bv_entryTtl.bv_val, mod->sml_values[ 0 ].bv_val, bv_entryTtl.bv_len );
				bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0';
				break;

			case LDAP_MOD_INCREMENT:
				if ( BER_BVISEMPTY( &bv_entryTtl ) ) {
					rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn,
						slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
					if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) {
						rs->sr_err = LDAP_NO_SUCH_OBJECT;

					} else {
						rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
						rs->sr_text = "modify/increment: entryTtl: no such attribute";
					}
					goto done;
				}

				entryTtl++;
				if ( entryTtl > DDS_RF2589_MAX_TTL ) {
					rs->sr_err = LDAP_PROTOCOL_ERROR;
					rs->sr_text = "invalid time-to-live for dynamicObject";

				} else if ( entryTtl <= 0 || entryTtl > di->di_max_ttl ) {
					/* FIXME: I don't understand if this has to be an error,
					 * or an indication that the requested Ttl has been
					 * shortened to di->di_max_ttl >= 1 day */
					rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
					rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit";
				}

				if ( rs->sr_err != LDAP_SUCCESS ) {
					rc = backend_attribute( op, NULL, &op->o_req_ndn,
						slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
					if ( rc == LDAP_INSUFFICIENT_ACCESS ) {
						rs->sr_text = NULL;
						rs->sr_err = LDAP_NO_SUCH_OBJECT;

					}
					goto done;
				}

				bv_entryTtl.bv_len = snprintf( textbuf, sizeof( textbuf ), "%ld", entryTtl );
				break;

			default:
				LDAP_BUG();
				break;
			}

		} else if ( mod->sml_desc == ad_entryExpireTimestamp ) {
			/* should have been trapped earlier */
			assert( mod->sml_flags & SLAP_MOD_INTERNAL );
		}
	}

done:;
	if ( rs->sr_err == LDAP_SUCCESS ) {
		int	rc;

		/* FIXME: this could be allowed when the Relax control is used...
		 * in that case:
		 *
		 * TODO
		 *
		 *	static => dynamic:
		 *		entryTtl must be provided; add
		 *		entryExpireTimestamp accordingly
		 *
		 *	dynamic => static:
		 *		entryTtl must be removed; remove
		 *		entryTimestamp accordingly
		 *
		 * ... but we need to make sure that there are no subordinate
		 * issues...
		 */
		rc = is_dynamicObject - was_dynamicObject;
		if ( rc ) {
#if 0 /* fix subordinate issues first */
			if ( get_relax( op ) ) {
				switch ( rc ) {
				case -1:
					/* need to delete entryTtl to have a consistent entry */
					if ( entryTtl != -1 ) {
						rs->sr_text = "objectClass modification from dynamicObject to static entry requires entryTtl deletion";
						rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
					}
					break;

				case 1:
					/* need to add entryTtl to have a consistent entry */
					if ( entryTtl <= 0 ) {
						rs->sr_text = "objectClass modification from static entry to dynamicObject requires entryTtl addition";
						rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
					}
					break;
				}

			} else
#endif
			{
				switch ( rc ) {
				case -1:
					rs->sr_text = "objectClass modification cannot turn dynamicObject into static entry";
					break;

				case 1:
					rs->sr_text = "objectClass modification cannot turn static entry into dynamicObject";
					break;
				}
				rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			}

			if ( rc != LDAP_SUCCESS ) {
				rc = backend_attribute( op, NULL, &op->o_req_ndn,
					slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
				if ( rc == LDAP_INSUFFICIENT_ACCESS ) {
					rs->sr_text = NULL;
					rs->sr_err = LDAP_NO_SUCH_OBJECT;
				}
			}
		}
	}

	if ( rs->sr_err == LDAP_SUCCESS && entryTtl != 0 ) {
		Modifications	*tmpmod = NULL, **modp;

		for ( modp = &op->orm_modlist; *modp; modp = &(*modp)->sml_next )
			;

		tmpmod = ch_calloc( 1, sizeof( Modifications ) );
		tmpmod->sml_flags = SLAP_MOD_INTERNAL;
		tmpmod->sml_type = ad_entryExpireTimestamp->ad_cname;
		tmpmod->sml_desc = ad_entryExpireTimestamp;

		*modp = tmpmod;

		if ( entryTtl == -1 ) {
			/* delete entryExpireTimestamp */
			tmpmod->sml_op = LDAP_MOD_DELETE;

		} else {
			time_t		expire;
			char		tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
			struct berval	bv;

			/* keep entryExpireTimestamp consistent
			 * with entryTtl */
			expire = slap_get_time() + entryTtl;
			bv.bv_val = tsbuf;
			bv.bv_len = sizeof( tsbuf );
			slap_timestamp( &expire, &bv );

			tmpmod->sml_op = LDAP_MOD_REPLACE;
			value_add_one( &tmpmod->sml_values, &bv );
			value_add_one( &tmpmod->sml_nvalues, &bv );
			tmpmod->sml_numvals = 1;
		}
	}

	if ( rs->sr_err ) {
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
		send_ldap_result( op, rs );
		return rs->sr_err;
	}

	return SLAP_CB_CONTINUE;
}
Example #16
0
extern "C" int
ndb_back_add(Operation *op, SlapReply *rs )
{
	struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
	Entry		p = {0};
	Attribute	poc;
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	NdbArgs NA;
	NdbRdns rdns;
	struct berval matched;
	struct berval pdn, pndn;

	int		num_retries = 0;
	int		success;

	LDAPControl **postread_ctrl = NULL;
	LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
	int num_ctrls = 0;

	Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(ndb_back_add) ": %s\n",
		op->oq_add.rs_e->e_name.bv_val, 0, 0);

	ctrls[num_ctrls] = 0;

	/* check entry's schema */
	rs->sr_err = entry_schema_check( op, op->oq_add.rs_e, NULL,
		get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_add) ": entry failed schema check: "
			"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
		goto return_results;
	}

	/* add opattrs to shadow as well, only missing attrs will actually
	 * be added; helps compatibility with older OL versions */
	rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_add) ": entry failed op attrs add: "
			"%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
		goto return_results;
	}

	/* Get our NDB handle */
	rs->sr_err = ndb_thread_handle( op, &NA.ndb );

	/*
	 * Get the parent dn and see if the corresponding entry exists.
	 */
	if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
		pdn = slap_empty_bv;
		pndn = slap_empty_bv;
	} else {
		dnParent( &op->ora_e->e_name, &pdn );
		dnParent( &op->ora_e->e_nname, &pndn );
	}
	p.e_name = op->ora_e->e_name;
	p.e_nname = op->ora_e->e_nname;

	op->ora_e->e_id = NOID;
	rdns.nr_num = 0;
	NA.rdns = &rdns;

	if( 0 ) {
retry:	/* transaction retry */
		NA.txn->close();
		NA.txn = NULL;
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			goto return_results;
		}
		ndb_trans_backoff( ++num_retries );
	}

	NA.txn = NA.ndb->startTransaction();
	rs->sr_text = NULL;
	if( !NA.txn ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_add) ": startTransaction failed: %s (%d)\n",
			NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* get entry or parent */
	NA.e = &p;
	NA.ocs = NULL;
	rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
	switch( rs->sr_err ) {
	case 0:
		rs->sr_err = LDAP_ALREADY_EXISTS;
		goto return_results;
	case LDAP_NO_SUCH_OBJECT:
		break;
#if 0
	case DB_LOCK_DEADLOCK:
	case DB_LOCK_NOTGRANTED:
		goto retry;
#endif
	case LDAP_BUSY:
		rs->sr_text = "ldap server busy";
		goto return_results;
	default:
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}

	if ( NA.ocs ) {
		int i;
		for ( i=0; !BER_BVISNULL( &NA.ocs[i] ); i++ );
		poc.a_numvals = i;
		poc.a_desc = slap_schema.si_ad_objectClass;
		poc.a_vals = NA.ocs;
		poc.a_nvals = poc.a_vals;
		poc.a_next = NULL;
		p.e_attrs = &poc;
	}

	if ( ber_bvstrcasecmp( &pndn, &matched ) ) {
		rs->sr_matched = matched.bv_val;
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_add) ": parent "
			"does not exist\n", 0, 0, 0 );

		rs->sr_text = "parent does not exist";
		rs->sr_err = LDAP_NO_SUCH_OBJECT;
		if ( p.e_attrs && is_entry_referral( &p )) {
is_ref:			p.e_attrs = NULL;
			ndb_entry_get_data( op, &NA, 0 );
			rs->sr_ref = get_entry_referrals( op, &p );
			rs->sr_err = LDAP_REFERRAL;
			rs->sr_flags = REP_REF_MUSTBEFREED;
			attrs_free( p.e_attrs );
			p.e_attrs = NULL;
		}
		goto return_results;
	}

	p.e_name = pdn;
	p.e_nname = pndn;
	rs->sr_err = access_allowed( op, &p,
		children, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_add) ": no write access to parent\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to parent";
		goto return_results;
	}

	if ( NA.ocs ) {
		if ( is_entry_subentry( &p )) {
			/* parent is a subentry, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(ndb_back_add) ": parent is subentry\n",
				0, 0, 0 );
			rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			rs->sr_text = "parent is a subentry";
			goto return_results;
		}

		if ( is_entry_alias( &p ) ) {
			/* parent is an alias, don't allow add */
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(ndb_back_add) ": parent is alias\n",
				0, 0, 0 );
			rs->sr_err = LDAP_ALIAS_PROBLEM;
			rs->sr_text = "parent is an alias";
			goto return_results;
		}

		if ( is_entry_referral( &p ) ) {
			/* parent is a referral, don't allow add */
			rs->sr_matched = p.e_name.bv_val;
			goto is_ref;
		}
	}

	rs->sr_err = access_allowed( op, op->ora_e,
		entry, NULL, ACL_WADD, NULL );

	if ( ! rs->sr_err ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_add) ": no write access to entry\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to entry";
		goto return_results;;
	}

	/* 
	 * Check ACL for attribute write access
	 */
	if (!acl_check_modlist(op, op->ora_e, op->ora_modlist)) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_add) ": no write access to attribute\n",
			0, 0, 0 );
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		rs->sr_text = "no write access to attribute";
		goto return_results;;
	}


	/* acquire entry ID */
	if ( op->ora_e->e_id == NOID ) {
		rs->sr_err = ndb_next_id( op->o_bd, NA.ndb, &op->ora_e->e_id );
		if( rs->sr_err != 0 ) {
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(ndb_back_add) ": next_id failed (%d)\n",
				rs->sr_err, 0, 0 );
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
			goto return_results;
		}
	}

	if ( matched.bv_val )
		rdns.nr_num++;
	NA.e = op->ora_e;
	/* dn2id index */
	rs->sr_err = ndb_entry_put_info( op->o_bd, &NA, 0 );
	if ( rs->sr_err ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_add) ": ndb_entry_put_info failed (%d)\n",
			rs->sr_err, 0, 0 );
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* id2entry index */
	rs->sr_err = ndb_entry_put_data( op->o_bd, &NA );
	if ( rs->sr_err ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_add) ": ndb_entry_put_data failed (%d) %s(%d)\n",
			rs->sr_err, NA.txn->getNdbError().message, NA.txn->getNdbError().code );
		rs->sr_text = "internal error";
		goto return_results;
	}

	/* post-read */
	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if ( slap_read_controls( op, rs, op->oq_add.rs_e,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(ndb_back_add) ": post-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	if ( op->o_noop ) {
		if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
			NdbOperation::AbortOnError, 1 )) != 0 ) {
			rs->sr_text = "txn (no-op) failed";
		} else {
			rs->sr_err = LDAP_X_NO_OPERATION;
		}

	} else {
		if(( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
			NdbOperation::AbortOnError, 1 )) != 0 ) {
			rs->sr_text = "txn_commit failed";
		} else {
			rs->sr_err = LDAP_SUCCESS;
		}
	}

	if ( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(ndb_back_add) ": %s : %s (%d)\n",
			rs->sr_text, NA.txn->getNdbError().message, NA.txn->getNdbError().code );
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}
	NA.txn->close();
	NA.txn = NULL;

	Debug(LDAP_DEBUG_TRACE,
		LDAP_XSTRING(ndb_back_add) ": added%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		op->oq_add.rs_e->e_id, op->oq_add.rs_e->e_dn );

	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	success = rs->sr_err;
	send_ldap_result( op, rs );
	slap_graduate_commit_csn( op );

	if( NA.txn != NULL ) {
		NA.txn->execute( Rollback );
		NA.txn->close();
	}

	if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
		slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
	}

	return rs->sr_err;
}