Beispiel #1
0
static int
ldap_back_monitor_modify(
	Operation	*op,
	SlapReply	*rs,
	Entry		*e,
	void		*priv )
{
	ldapinfo_t		*li = (ldapinfo_t *) priv;
	
	Attribute		*save_attrs = NULL;
	Modifications		*ml,
				*ml_olmDbURIList = NULL;
	struct berval		ul = BER_BVNULL;
	int			got = 0;

	for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
		if ( ml->sml_desc == ad_olmDbURIList ) {
			if ( ml_olmDbURIList != NULL ) {
				rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
				rs->sr_text = "conflicting modifications";
				goto done;
			}

			if ( ml->sml_op != LDAP_MOD_REPLACE ) {
				rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
				rs->sr_text = "modification not allowed";
				goto done;
			}

			ml_olmDbURIList = ml;
			got++;
			continue;
		}
	}

	if ( got == 0 ) {
		return SLAP_CB_CONTINUE;
	}

	save_attrs = attrs_dup( e->e_attrs );

	if ( ml_olmDbURIList != NULL ) {
		Attribute	*a = NULL;
		LDAPURLDesc	*ludlist = NULL;
		int		rc;

		ml = ml_olmDbURIList;
		assert( ml->sml_nvalues != NULL );

		if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
			rs->sr_text = "no value provided";
			goto done;
		}

		if ( !BER_BVISNULL( &ml->sml_nvalues[ 1 ] ) ) {
			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
			rs->sr_text = "multiple values provided";
			goto done;
		}

		rc = ldap_url_parselist_ext( &ludlist,
			ml->sml_nvalues[ 0 ].bv_val, NULL,
			LDAP_PVT_URL_PARSE_NOEMPTY_HOST
				| LDAP_PVT_URL_PARSE_DEF_PORT );
		if ( rc != LDAP_URL_SUCCESS ) {
			rs->sr_err = LDAP_INVALID_SYNTAX;
			rs->sr_text = "unable to parse URI list";
			goto done;
		}

		ul.bv_val = ldap_url_list2urls( ludlist );
		ldap_free_urllist( ludlist );
		if ( ul.bv_val == NULL ) {
			rs->sr_err = LDAP_OTHER;
			goto done;
		}
		ul.bv_len = strlen( ul.bv_val );
		
		a = attr_find( e->e_attrs, ad_olmDbURIList );
		if ( a != NULL ) {
			if ( a->a_nvals == a->a_vals ) {
				a->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
			}

			ber_bvreplace( &a->a_vals[ 0 ], &ul );
			ber_bvreplace( &a->a_nvals[ 0 ], &ul );

		} else {
			attr_merge_normalize_one( e, ad_olmDbURIList, &ul, NULL );
		}
	}

	/* apply changes */
	if ( !BER_BVISNULL( &ul ) ) {
		ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
		if ( li->li_uri ) {
			ch_free( li->li_uri );
		}
		li->li_uri = ul.bv_val;
		ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );

		BER_BVZERO( &ul );
	}

done:;
	if ( !BER_BVISNULL( &ul ) ) {
		ldap_memfree( ul.bv_val );
	}

	if ( rs->sr_err == LDAP_SUCCESS ) {
		attrs_free( save_attrs );
		return SLAP_CB_CONTINUE;
	}

	attrs_free( e->e_attrs );
	e->e_attrs = save_attrs;

	return rs->sr_err;
}
Beispiel #2
0
void
bdb_idl_cache_put(
	struct bdb_info	*bdb,
	DB			*db,
	DBT			*key,
	ID			*ids,
	int			rc )
{
	bdb_idl_cache_entry_t idl_tmp;
	bdb_idl_cache_entry_t *ee, *eprev;

	if ( rc == DB_NOTFOUND || BDB_IDL_IS_ZERO( ids ))
		return;

	DBT2bv( key, &idl_tmp.kstr );

	ee = (bdb_idl_cache_entry_t *) ch_malloc(
		sizeof( bdb_idl_cache_entry_t ) );
	ee->db = db;
	ee->idl = (ID*) ch_malloc( BDB_IDL_SIZEOF ( ids ) );
	BDB_IDL_CPY( ee->idl, ids );

	ee->idl_lru_prev = NULL;
	ee->idl_lru_next = NULL;
	ee->idl_flags = 0;
	ber_dupbv( &ee->kstr, &idl_tmp.kstr );
	ldap_pvt_thread_rdwr_wlock( &bdb->bi_idl_tree_rwlock );
	if ( avl_insert( &bdb->bi_idl_tree, (caddr_t) ee,
		bdb_idl_entry_cmp, avl_dup_error ))
	{
		ch_free( ee->kstr.bv_val );
		ch_free( ee->idl );
		ch_free( ee );
		ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock );
		return;
	}
	ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock );
	/* LRU_ADD */
	if ( bdb->bi_idl_lru_head ) {
		assert( bdb->bi_idl_lru_tail != NULL );
		assert( bdb->bi_idl_lru_head->idl_lru_prev != NULL );
		assert( bdb->bi_idl_lru_head->idl_lru_next != NULL );

		ee->idl_lru_next = bdb->bi_idl_lru_head;
		ee->idl_lru_prev = bdb->bi_idl_lru_head->idl_lru_prev;
		bdb->bi_idl_lru_head->idl_lru_prev->idl_lru_next = ee;
		bdb->bi_idl_lru_head->idl_lru_prev = ee;
	} else {
		ee->idl_lru_next = ee->idl_lru_prev = ee;
		bdb->bi_idl_lru_tail = ee;
	}
	bdb->bi_idl_lru_head = ee;

	if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) {
		int i;
		eprev = bdb->bi_idl_lru_tail;
		for ( i = 0; (ee = eprev) != NULL && i < 10; i++ ) {
			eprev = ee->idl_lru_prev;
			if ( eprev == ee ) {
				eprev = NULL;
			}
			if ( ee->idl_flags & CACHE_ENTRY_REFERENCED ) {
				ee->idl_flags ^= CACHE_ENTRY_REFERENCED;
				continue;
			}
			if ( avl_delete( &bdb->bi_idl_tree, (caddr_t) ee,
				    bdb_idl_entry_cmp ) == NULL ) {
				Debug( LDAP_DEBUG_ANY, "=> bdb_idl_cache_put: "
					"AVL delete failed\n",
					0, 0, 0 );
			}
			IDL_LRU_DELETE( bdb, ee );
			i++;
			--bdb->bi_idl_cache_size;
			ch_free( ee->kstr.bv_val );
			ch_free( ee->idl );
			ch_free( ee );
		}
		bdb->bi_idl_lru_tail = eprev;
		assert( bdb->bi_idl_lru_tail != NULL
			|| bdb->bi_idl_lru_head == NULL );
	}
	bdb->bi_idl_cache_size++;
	ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock );
	ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock );
}
Beispiel #3
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;
}
Beispiel #4
0
void
bdb_cache_return_entry_rw
( DB_ENV *env, Cache *cache, Entry *e, int rw, DB_LOCK *lock )
{
	ID id;
	int refcnt, freeit = 1;

	/* set cache write lock */
	ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );

	assert( e->e_private );

	bdb_cache_entry_db_unlock( env, lock );
#if 0
	bdb_cache_entry_rdwr_unlock(e, rw);
#endif

	id = e->e_id;
	refcnt = --BEI(e)->bei_refcnt;

	/*
	 * if the entry is returned when in CREATING state, it is deleted
	 * but not freed because it may belong to someone else (do_add,
	 * for instance)
	 */
	if (  BEI(e)->bei_state == CACHE_ENTRY_CREATING ) {
		/* set lru mutex */
		ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
		bdb_cache_delete_entry_internal( cache, e );
		/* free lru mutex */
		ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
		freeit = 0;
		/* now the entry is in DELETED state */
	}

	if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) {
		BEI(e)->bei_state = CACHE_ENTRY_READY;

		/* free cache write lock */
		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );

#ifdef NEW_LOGGING
		LDAP_LOG( CACHE, DETAIL1, 
			   "bdb_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n",
			   id, rw ? "w" : "r", refcnt );
#else
		Debug( LDAP_DEBUG_TRACE,
			"====> bdb_cache_return_entry_%s( %ld ): created (%d)\n",
			rw ? "w" : "r", id, refcnt );
#endif


	} else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) {
		if( refcnt > 0 ) {
			/* free cache write lock */
			ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );

#ifdef NEW_LOGGING
			LDAP_LOG( CACHE, DETAIL1, 
				   "bdb_cache_return_entry_rw: %ld, delete pending (%d).\n",
				   id, refcnt, 0 );
#else
			Debug( LDAP_DEBUG_TRACE,
				"====> bdb_cache_return_entry_%s( %ld ): delete pending (%d)\n",
				rw ? "w" : "r", id, refcnt );
#endif

		} else {
			bdb_cache_entry_private_destroy( e );
			if ( freeit ) {
				bdb_entry_return( e );
			}

			/* free cache write lock */
			ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );

#ifdef NEW_LOGGING
			LDAP_LOG( CACHE, DETAIL1, 
				   "bdb_cache_return_entry_rw: (%ld): deleted (%d)\n",
				   id, refcnt, 0 );
#else
			Debug( LDAP_DEBUG_TRACE,
				"====> bdb_cache_return_entry_%s( %ld ): deleted (%d)\n",
				rw ? "w" : "r", id, refcnt );
#endif
		}

	} else {
		/* free cache write lock */
		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );

#ifdef NEW_LOGGING
		LDAP_LOG( CACHE, DETAIL1, 
			   "bdb_cache_return_entry_rw: ID %ld:%s returned (%d)\n",
			   id, rw ? "w": "r", refcnt );
#else
		Debug( LDAP_DEBUG_TRACE,
			"====> bdb_cache_return_entry_%s( %ld ): returned (%d)\n",
			rw ? "w" : "r", id, refcnt);
#endif
	}
}
Beispiel #5
0
int ldap_pvt_gethostbyaddr_a(
	const char *addr,
	int len,
	int type,
	struct hostent *resbuf,
	char **buf,
	struct hostent **result,
	int *herrno_ptr )
{
#if defined( HAVE_GETHOSTBYADDR_R )

# undef NEED_SAFE_REALLOC
# define NEED_SAFE_REALLOC   
	int r=-1;
	int buflen=BUFSTART;
	*buf = NULL;   
	for(;buflen<BUFMAX;) {
		if (safe_realloc( buf, buflen )==NULL)
			return r;
#if (GETHOSTBYADDR_R_NARGS < 8)
		*result=gethostbyaddr_r( addr, len, type,
			resbuf, *buf, buflen, herrno_ptr );
		r = (*result == NULL) ? -1 : 0;
#else
		r = gethostbyaddr_r( addr, len, type,
			resbuf, *buf, buflen, 
			result, herrno_ptr );
#endif

#ifdef NETDB_INTERNAL
		if ((r<0) &&
			(*herrno_ptr==NETDB_INTERNAL) &&
			(errno==ERANGE))
		{
			buflen*=2;
			continue;
		}
#endif
		return r;
	}
	return -1;
#elif defined( LDAP_R_COMPILE )
# undef NEED_COPY_HOSTENT
# define NEED_COPY_HOSTENT   
	struct hostent *he;
	int	retval;
	*buf = NULL;   
	
	ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
	
	he = gethostbyaddr( addr, len, type );
	
	if (he==NULL) {
		*herrno_ptr = h_errno;
		retval = -1;
	} else if (copy_hostent( resbuf, buf, he )<0) {
		*herrno_ptr = -1;
		retval = -1;
	} else {
		*result = resbuf;
		retval = 0;
	}
	
	ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
	
	return retval;

#else /* gethostbyaddr() */
	*buf = NULL;   
	*result = gethostbyaddr( addr, len, type );

	if (*result!=NULL) {
		return 0;
	}
	return -1;
#endif	
}
Beispiel #6
0
int
bdb_modify( Operation *op, SlapReply *rs )
{
	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
	Entry		*e = NULL;
	EntryInfo	*ei = NULL;
	int		manageDSAit = get_manageDSAit( op );
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;
	DB_TXN	*ltid = NULL, *lt2;
	struct bdb_op_info opinfo = {{{ 0 }}};
	Entry		dummy = {0};

	DB_LOCK		lock;

	int		num_retries = 0;

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

	int rc;

#ifdef LDAP_X_TXN
	int settle = 0;
#endif

	Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(bdb_modify) ": %s\n",
		op->o_req_dn.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] = NULL;

	/* Don't touch the opattrs, if this is a contextCSN update
	 * initiated from updatedn */
	if ( !be_isupdate(op) || !op->orm_modlist || op->orm_modlist->sml_next ||
		 op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) {

		slap_mods_opattrs( op, &op->orm_modlist, 1 );
	}

	if( 0 ) {
retry:	/* transaction retry */
		if ( dummy.e_attrs ) {
			attrs_free( dummy.e_attrs );
			dummy.e_attrs = NULL;
		}
		if( e != NULL ) {
			bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
			e = NULL;
		}
		Debug(LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": retrying...\n", 0, 0, 0);

		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_modify) ": 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_modify) ": 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 entry or ancestor */
	rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
		&lock );

	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": dn2entry failed (%d)\n",
			rs->sr_err, 0, 0 );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		case DB_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;
		}
	}

	e = ei->bei_e;

	/* acquire and lock entry */
	/* FIXME: dn2entry() should return non-glue entry */
	if (( rs->sr_err == DB_NOTFOUND ) ||
		( !manageDSAit && e && is_entry_glue( e )))
	{
		if ( e != NULL ) {
			rs->sr_matched = ch_strdup( e->e_dn );
			rs->sr_ref = is_entry_referral( e )
				? get_entry_referrals( op, e )
				: NULL;
			bdb_unlocked_cache_return_entry_r (&bdb->bi_cache, e);
			e = NULL;

		} else {
			rs->sr_ref = referral_rewrite( default_referral, NULL,
				&op->o_req_dn, LDAP_SCOPE_DEFAULT );
		}

		rs->sr_err = LDAP_REFERRAL;
		send_ldap_result( op, rs );

		if ( rs->sr_ref != default_referral ) {
			ber_bvarray_free( rs->sr_ref );
		}
		free( (char *)rs->sr_matched );
		rs->sr_ref = NULL;
		rs->sr_matched = NULL;

		goto done;
	}

	if ( !manageDSAit && is_entry_referral( e ) ) {
		/* entry is a referral, don't allow modify */
		rs->sr_ref = get_entry_referrals( op, e );

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": entry is referral\n",
			0, 0, 0 );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_matched = e->e_name.bv_val;
		send_ldap_result( op, rs );

		ber_bvarray_free( rs->sr_ref );
		rs->sr_ref = NULL;
		rs->sr_matched = NULL;
		goto done;
	}

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

	if( op->o_preread ) {
		if( preread_ctrl == NULL ) {
			preread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if ( slap_read_controls( op, rs, e,
			&slap_pre_read_bv, preread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_modify) ": pre-read "
				"failed!\n", 0, 0, 0 );
			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	/* 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_modify) ": 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_modify) ": txn2 id: %x\n",
		lt2->id(lt2), 0, 0 );
	/* Modify the entry */
	dummy = *e;
	rs->sr_err = bdb_modify_internal( op, lt2, op->orm_modlist,
		&dummy, &rs->sr_text, textbuf, textlen );

	if( rs->sr_err != LDAP_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": modify failed (%d)\n",
			rs->sr_err, 0, 0 );
		if ( (rs->sr_err == LDAP_INSUFFICIENT_ACCESS) && opinfo.boi_err ) {
			rs->sr_err = opinfo.boi_err;
		}
		/* Only free attrs if they were dup'd.  */
		if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		goto return_results;
	}

	/* change the entry itself */
	rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, &dummy );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": id2entry update failed " "(%d)\n",
			rs->sr_err, 0, 0 );
		switch( rs->sr_err ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		rs->sr_text = "entry update 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;
	}

	if( op->o_postread ) {
		if( postread_ctrl == NULL ) {
			postread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, &dummy,
			&slap_post_read_bv, postread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(bdb_modify)
				": 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;
			/* Only free attrs if they were dup'd.  */
			if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
			goto return_results;
		}
	} else {
		/* may have changed in bdb_modify_internal() */
		e->e_ocflags = dummy.e_ocflags;
		rc = bdb_cache_modify( bdb, e, dummy.e_attrs, ltid, &lock );
		switch( rc ) {
		case DB_LOCK_DEADLOCK:
		case DB_LOCK_NOTGRANTED:
			goto retry;
		}
		dummy.e_attrs = NULL;

		rs->sr_err = TXN_COMMIT( ltid, 0 );
	}
	ltid = NULL;
	LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
	opinfo.boi_oe.oe_key = NULL;

	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(bdb_modify) ": txn_%s failed: %s (%d)\n",
			op->o_noop ? "abort (no-op)" : "commit",
			db_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "commit failed";

		goto return_results;
	}

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(bdb_modify) ": updated%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		dummy.e_id, op->o_req_dn.bv_val );

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

return_results:
	if( dummy.e_attrs ) {
		attrs_free( dummy.e_attrs );
	}
	send_ldap_result( op, rs );

	if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp_kbyte ) {
		TXN_CHECKPOINT( bdb->bi_dbenv,
			bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
	}

done:
	slap_graduate_commit_csn( op );

	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( e != NULL ) {
		bdb_unlocked_cache_return_entry_w (&bdb->bi_cache, e);
	}

	if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
		slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
		slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
	}
	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 );
	}

	rs->sr_text = NULL;

	return rs->sr_err;
}
Beispiel #7
0
static int
dds_cfgen( ConfigArgs *c )
{
	slap_overinst	*on = (slap_overinst *)c->bi;
	dds_info_t	*di = on->on_bi.bi_private;
	int		rc = 0;
	unsigned long	t;


	if ( c->op == SLAP_CONFIG_EMIT ) {
		char		buf[ SLAP_TEXT_BUFLEN ];
		struct berval	bv;

		switch( c->type ) {
		case DDS_STATE:
			c->value_int = !DDS_OFF( di );
			break;

		case DDS_MAXTTL:
			lutil_unparse_time( buf, sizeof( buf ), di->di_max_ttl );
			ber_str2bv( buf, 0, 0, &bv );
			value_add_one( &c->rvalue_vals, &bv );
			break;

		case DDS_MINTTL:
			if ( di->di_min_ttl ) {
				lutil_unparse_time( buf, sizeof( buf ), di->di_min_ttl );
				ber_str2bv( buf, 0, 0, &bv );
				value_add_one( &c->rvalue_vals, &bv );

			} else {
				rc = 1;
			}
			break;

		case DDS_DEFAULTTTL:
			if ( di->di_default_ttl ) {
				lutil_unparse_time( buf, sizeof( buf ), di->di_default_ttl );
				ber_str2bv( buf, 0, 0, &bv );
				value_add_one( &c->rvalue_vals, &bv );

			} else {
				rc = 1;
			}
			break;

		case DDS_INTERVAL:
			if ( di->di_interval ) {
				lutil_unparse_time( buf, sizeof( buf ), di->di_interval );
				ber_str2bv( buf, 0, 0, &bv );
				value_add_one( &c->rvalue_vals, &bv );

			} else {
				rc = 1;
			}
			break;

		case DDS_TOLERANCE:
			if ( di->di_tolerance ) {
				lutil_unparse_time( buf, sizeof( buf ), di->di_tolerance );
				ber_str2bv( buf, 0, 0, &bv );
				value_add_one( &c->rvalue_vals, &bv );

			} else {
				rc = 1;
			}
			break;

		case DDS_MAXDYNAMICOBJS:
			if ( di->di_max_dynamicObjects > 0 ) {
				c->value_int = di->di_max_dynamicObjects;

			} else {
				rc = 1;
			}
			break;

		default:
			rc = 1;
			break;
		}

		return rc;

	} else if ( c->op == LDAP_MOD_DELETE ) {
		switch( c->type ) {
		case DDS_STATE:
			di->di_flags &= ~DDS_FOFF;
			break;

		case DDS_MAXTTL:
			di->di_min_ttl = DDS_RF2589_DEFAULT_TTL;
			break;

		case DDS_MINTTL:
			di->di_min_ttl = 0;
			break;

		case DDS_DEFAULTTTL:
			di->di_default_ttl = 0;
			break;

		case DDS_INTERVAL:
			di->di_interval = 0;
			break;

		case DDS_TOLERANCE:
			di->di_tolerance = 0;
			break;

		case DDS_MAXDYNAMICOBJS:
			di->di_max_dynamicObjects = 0;
			break;

		default:
			rc = 1;
			break;
		}

		return rc;
	}

	switch ( c->type ) {
	case DDS_STATE:
		if ( c->value_int ) {
			di->di_flags &= ~DDS_FOFF;

		} else {
			di->di_flags |= DDS_FOFF;
		}
		break;

	case DDS_MAXTTL:
		if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg),
				"DDS unable to parse dds-max-ttl \"%s\"",
				c->argv[ 1 ] );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		if ( t < DDS_RF2589_DEFAULT_TTL || t > DDS_RF2589_MAX_TTL ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg ),
				"DDS invalid dds-max-ttl=%ld; must be between %d and %d",
				t, DDS_RF2589_DEFAULT_TTL, DDS_RF2589_MAX_TTL );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		di->di_max_ttl = (time_t)t;
		break;

	case DDS_MINTTL:
		if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg),
				"DDS unable to parse dds-min-ttl \"%s\"",
				c->argv[ 1 ] );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		if ( t < 0 || t > DDS_RF2589_MAX_TTL ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg ),
				"DDS invalid dds-min-ttl=%ld",
				t );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		if ( t == 0 ) {
			di->di_min_ttl = DDS_RF2589_DEFAULT_TTL;

		} else {
			di->di_min_ttl = (time_t)t;
		}
		break;

	case DDS_DEFAULTTTL:
		if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg),
				"DDS unable to parse dds-default-ttl \"%s\"",
				c->argv[ 1 ] );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		if ( t < 0 || t > DDS_RF2589_MAX_TTL ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg ),
				"DDS invalid dds-default-ttl=%ld",
				t );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		if ( t == 0 ) {
			di->di_default_ttl = DDS_RF2589_DEFAULT_TTL;

		} else {
			di->di_default_ttl = (time_t)t;
		}
		break;

	case DDS_INTERVAL:
		if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg),
				"DDS unable to parse dds-interval \"%s\"",
				c->argv[ 1 ] );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		if ( t <= 0 ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg ),
				"DDS invalid dds-interval=%ld",
				t );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		if ( t < 60 ) {
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE,
				"%s: dds-interval=%lu may be too small.\n",
				c->log, t );
		}

		di->di_interval = (time_t)t;
		if ( di->di_expire_task ) {
			ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
			if ( ldap_pvt_runqueue_isrunning( &slapd_rq, di->di_expire_task ) ) {
				ldap_pvt_runqueue_stoptask( &slapd_rq, di->di_expire_task );
			}
			di->di_expire_task->interval.tv_sec = DDS_INTERVAL( di );
			ldap_pvt_runqueue_resched( &slapd_rq, di->di_expire_task, 0 );
			ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
		}
		break;

	case DDS_TOLERANCE:
		if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg),
				"DDS unable to parse dds-tolerance \"%s\"",
				c->argv[ 1 ] );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		if ( t < 0 || t > DDS_RF2589_MAX_TTL ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg ),
				"DDS invalid dds-tolerance=%ld",
				t );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}

		di->di_tolerance = (time_t)t;
		break;

	case DDS_MAXDYNAMICOBJS:
		if ( c->value_int < 0 ) {
			snprintf( c->cr_msg, sizeof( c->cr_msg ),
				"DDS invalid dds-max-dynamicObjects=%d", c->value_int );
			Log2( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
				"%s: %s.\n", c->log, c->cr_msg );
			return 1;
		}
		di->di_max_dynamicObjects = c->value_int;
		break;

	default:
		rc = 1;
		break;
	}

	return rc;
}
Beispiel #8
0
int ldap_pvt_gethostbyname_a(
	const char *name, 
	struct hostent *resbuf,
	char **buf,
	struct hostent **result,
	int *herrno_ptr )
{
#if defined( HAVE_GETHOSTBYNAME_R )

# define NEED_SAFE_REALLOC 1   
	int r=-1;
	int buflen=BUFSTART;
	*buf = NULL;
	for(;buflen<BUFMAX;) {
		if (safe_realloc( buf, buflen )==NULL)
			return r;

#if (GETHOSTBYNAME_R_NARGS < 6)
		*result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr );
		r = (*result == NULL) ?  -1 : 0;
#else
		r = gethostbyname_r( name, resbuf, *buf,
			buflen, result, herrno_ptr );
#endif

		Debug( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
		       name, r, 0 );

#ifdef NETDB_INTERNAL
		if ((r<0) &&
			(*herrno_ptr==NETDB_INTERNAL) &&
			(errno==ERANGE))
		{
			buflen*=2;
			continue;
	 	}
#endif
		return r;
	}
	return -1;
#elif defined( LDAP_R_COMPILE )
# define NEED_COPY_HOSTENT   
	struct hostent *he;
	int	retval;
	*buf = NULL;
	
	ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
	
	he = gethostbyname( name );
	
	if (he==NULL) {
		*herrno_ptr = h_errno;
		retval = -1;
	} else if (copy_hostent( resbuf, buf, he )<0) {
		*herrno_ptr = -1;
		retval = -1;
	} else {
		*result = resbuf;
		retval = 0;
	}
	
	ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
	
	return retval;
#else	
	*buf = NULL;
	*result = gethostbyname( name );

	if (*result!=NULL) {
		return 0;
	}

	*herrno_ptr = h_errno;
	
	return -1;
#endif	
}
Beispiel #9
0
static int
send_ldap_response(
	Operation *op,
	SlapReply *rs )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *) &berbuf;
	int		rc = LDAP_SUCCESS;
	long	bytes;

	/* op was actually aborted, bypass everything if client didn't Cancel */
	if (( rs->sr_err == SLAPD_ABANDON ) && !op->o_cancel ) {
		rc = SLAPD_ABANDON;
		goto clean2;
	}

	if ( op->o_callback ) {
		rc = slap_response_play( op, rs );
		if ( rc != SLAP_CB_CONTINUE ) {
			goto clean2;
		}
	}

	/* op completed, connection aborted, bypass sending response */
	if ( op->o_abandon && !op->o_cancel ) {
		rc = SLAPD_ABANDON;
		goto clean2;
	}

#ifdef LDAP_CONNECTIONLESS
	if (op->o_conn && op->o_conn->c_is_udp)
		ber = op->o_res_ber;
	else
#endif
	{
		ber_init_w_nullc( ber, LBER_USE_DER );
		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
	}

	rc = rs->sr_err;
	if ( rc == SLAPD_ABANDON && op->o_cancel )
		rc = LDAP_CANCELLED;

	Debug( LDAP_DEBUG_TRACE,
		"send_ldap_response: msgid=%d tag=%lu err=%d\n",
		rs->sr_msgid, rs->sr_tag, rc );

	if( rs->sr_ref ) {
		Debug( LDAP_DEBUG_ARGS, "send_ldap_response: ref=\"%s\"\n",
			rs->sr_ref[0].bv_val ? rs->sr_ref[0].bv_val : "NULL",
			NULL, NULL );
	}

#ifdef LDAP_CONNECTIONLESS
	if (op->o_conn && op->o_conn->c_is_udp &&
		op->o_protocol == LDAP_VERSION2 )
	{
		rc = ber_printf( ber, "t{ess" /*"}"*/,
			rs->sr_tag, rc,
		rs->sr_matched == NULL ? "" : rs->sr_matched,
		rs->sr_text == NULL ? "" : rs->sr_text );
	} else 
#endif
	if ( rs->sr_type == REP_INTERMEDIATE ) {
	    rc = ber_printf( ber, "{it{" /*"}}"*/,
			rs->sr_msgid, rs->sr_tag );

	} else {
	    rc = ber_printf( ber, "{it{ess" /*"}}"*/,
		rs->sr_msgid, rs->sr_tag, rc,
		rs->sr_matched == NULL ? "" : rs->sr_matched,
		rs->sr_text == NULL ? "" : rs->sr_text );
	}

	if( rc != -1 ) {
		if ( rs->sr_ref != NULL ) {
			assert( rs->sr_err == LDAP_REFERRAL );
			rc = ber_printf( ber, "t{W}",
				LDAP_TAG_REFERRAL, rs->sr_ref );
		} else {
			assert( rs->sr_err != LDAP_REFERRAL );
		}
	}

	if( rc != -1 && rs->sr_type == REP_SASL && rs->sr_sasldata != NULL ) {
		rc = ber_printf( ber, "tO",
			LDAP_TAG_SASL_RES_CREDS, rs->sr_sasldata );
	}

	if( rc != -1 &&
		( rs->sr_type == REP_EXTENDED || rs->sr_type == REP_INTERMEDIATE ))
	{
		if ( rs->sr_rspoid != NULL ) {
			rc = ber_printf( ber, "ts",
				rs->sr_type == REP_EXTENDED
					? LDAP_TAG_EXOP_RES_OID : LDAP_TAG_IM_RES_OID,
				rs->sr_rspoid );
		}
		if( rc != -1 && rs->sr_rspdata != NULL ) {
			rc = ber_printf( ber, "tO",
				rs->sr_type == REP_EXTENDED
					? LDAP_TAG_EXOP_RES_VALUE : LDAP_TAG_IM_RES_VALUE,
				rs->sr_rspdata );
		}
	}

	if( rc != -1 ) {
		rc = ber_printf( ber, /*"{"*/ "N}" );
	}

	if( rc != -1 ) {
		rc = send_ldap_controls( op, ber, rs->sr_ctrls );
	}

	if( rc != -1 ) {
		rc = ber_printf( ber, /*"{"*/ "N}" );
	}

#ifdef LDAP_CONNECTIONLESS
	if( op->o_conn && op->o_conn->c_is_udp && op->o_protocol == LDAP_VERSION2
		&& rc != -1 )
	{
		rc = ber_printf( ber, /*"{"*/ "N}" );
	}
#endif
		
	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );

#ifdef LDAP_CONNECTIONLESS
		if (!op->o_conn || op->o_conn->c_is_udp == 0)
#endif
		{
			ber_free_buf( ber );
		}
		goto cleanup;
	}

	/* send BER */
	bytes = send_ldap_ber( op, ber );
#ifdef LDAP_CONNECTIONLESS
	if (!op->o_conn || op->o_conn->c_is_udp == 0)
#endif
	{
		ber_free_buf( ber );
	}

	if ( bytes < 0 ) {
		Debug( LDAP_DEBUG_ANY,
			"send_ldap_response: ber write failed\n",
			0, 0, 0 );

		goto cleanup;
	}

	ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
	ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
	ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
	ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );

cleanup:;
	/* Tell caller that we did this for real, as opposed to being
	 * overridden by a callback
	 */
	rc = SLAP_CB_CONTINUE;

clean2:;
	if ( op->o_callback ) {
		(void)slap_cleanup_play( op, rs );
	}

	if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
		rs->sr_flags ^= REP_MATCHED_MUSTBEFREED; /* paranoia */
		if ( rs->sr_matched ) {
			free( (char *)rs->sr_matched );
			rs->sr_matched = NULL;
		}
	}

	if ( rs->sr_flags & REP_REF_MUSTBEFREED ) {
		rs->sr_flags ^= REP_REF_MUSTBEFREED; /* paranoia */
		if ( rs->sr_ref ) {
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;
		}
	}

	if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
		rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
		if ( rs->sr_ctrls ) {
			slap_free_ctrls( op, rs->sr_ctrls );
			rs->sr_ctrls = NULL;
		}
	}

	return rc;
}
Beispiel #10
0
int
slap_send_search_entry( Operation *op, SlapReply *rs )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *) &berbuf;
	Attribute	*a;
	int		i, j, rc = LDAP_UNAVAILABLE, bytes;
	int		userattrs;
	AccessControlState acl_state = ACL_STATE_INIT;
	int			 attrsonly;
	AttributeDescription *ad_entry = slap_schema.si_ad_entry;

	/* a_flags: array of flags telling if the i-th element will be
	 *          returned or filtered out
	 * e_flags: array of a_flags
	 */
	char **e_flags = NULL;

	rs->sr_type = REP_SEARCH;

	if ( op->ors_slimit >= 0 && rs->sr_nentries >= op->ors_slimit ) {
		rc = LDAP_SIZELIMIT_EXCEEDED;
		goto error_return;
	}

	/* Every 64 entries, check for thread pool pause */
	if ( ( ( rs->sr_nentries & 0x3f ) == 0x3f ) &&
		ldap_pvt_thread_pool_pausing( &connection_pool ) > 0 )
	{
		rc = LDAP_BUSY;
		goto error_return;
	}

	/* eventually will loop through generated operational attribute types
	 * currently implemented types include:
	 *	entryDN, subschemaSubentry, and hasSubordinates */
	/* NOTE: moved before overlays callback circling because
	 * they may modify entry and other stuff in rs */
	/* check for special all operational attributes ("+") type */
	/* FIXME: maybe we could set this flag at the operation level;
	 * however, in principle the caller of send_search_entry() may
	 * change the attribute list at each call */
	rs->sr_attr_flags = slap_attr_flags( rs->sr_attrs );

	rc = backend_operational( op, rs );
	if ( rc ) {
		goto error_return;
	}

	if ( op->o_callback ) {
		rc = slap_response_play( op, rs );
		if ( rc != SLAP_CB_CONTINUE ) {
			goto error_return;
		}
	}

	Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: conn %lu dn=\"%s\"%s\n",
		op->o_connid, rs->sr_entry->e_name.bv_val,
		op->ors_attrsonly ? " (attrsOnly)" : "" );

	attrsonly = op->ors_attrsonly;

	if ( !access_allowed( op, rs->sr_entry, ad_entry, NULL, ACL_READ, NULL )) {
		Debug( LDAP_DEBUG_ACL,
			"send_search_entry: conn %lu access to entry (%s) not allowed\n", 
			op->o_connid, rs->sr_entry->e_name.bv_val, 0 );

		rc = LDAP_INSUFFICIENT_ACCESS;
		goto error_return;
	}

	if ( op->o_res_ber ) {
		/* read back control or LDAP_CONNECTIONLESS */
	    ber = op->o_res_ber;
	} else {
		struct berval	bv;

		bv.bv_len = entry_flatsize( rs->sr_entry, 0 );
		bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );

		ber_init2( ber, &bv, LBER_USE_DER );
		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
	}

#ifdef LDAP_CONNECTIONLESS
	if ( op->o_conn && op->o_conn->c_is_udp ) {
		/* CONNECTIONLESS */
		if ( op->o_protocol == LDAP_VERSION2 ) {
	    	rc = ber_printf(ber, "t{O{" /*}}*/,
				LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
		} else {
	    	rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
				LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
		}
	} else
#endif
	if ( op->o_res_ber ) {
		/* read back control */
	    rc = ber_printf( ber, "t{O{" /*}}*/,
			LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
	} else {
	    rc = ber_printf( ber, "{it{O{" /*}}}*/, op->o_msgid,
			LDAP_RES_SEARCH_ENTRY, &rs->sr_entry->e_name );
	}

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY, 
			"send_search_entry: conn %lu  ber_printf failed\n", 
			op->o_connid, 0, 0 );

		if ( op->o_res_ber == NULL ) ber_free_buf( ber );
		set_ldap_error( rs, LDAP_OTHER, "encoding DN error" );
		rc = rs->sr_err;
		goto error_return;
	}

	/* check for special all user attributes ("*") type */
	userattrs = SLAP_USERATTRS( rs->sr_attr_flags );

	/* create an array of arrays of flags. Each flag corresponds
	 * to particular value of attribute and equals 1 if value matches
	 * to ValuesReturnFilter or 0 if not
	 */	
	if ( op->o_vrFilter != NULL ) {
		int	k = 0;
		size_t	size;

		for ( a = rs->sr_entry->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
			for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
		}

		size = i * sizeof(char *) + k;
		if ( size > 0 ) {
			char	*a_flags;
			e_flags = slap_sl_calloc ( 1, i * sizeof(char *) + k, op->o_tmpmemctx );
			if( e_flags == NULL ) {
		    	Debug( LDAP_DEBUG_ANY, 
					"send_search_entry: conn %lu slap_sl_calloc failed\n",
					op->o_connid, 0, 0 );
				ber_free( ber, 1 );
	
				set_ldap_error( rs, LDAP_OTHER, "out of memory" );
				goto error_return;
			}
			a_flags = (char *)(e_flags + i);
			memset( a_flags, 0, k );
			for ( a=rs->sr_entry->e_attrs, i=0; a != NULL; a=a->a_next, i++ ) {
				for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
				e_flags[i] = a_flags;
				a_flags += j;
			}
	
			rc = filter_matched_values(op, rs->sr_entry->e_attrs, &e_flags) ; 
			if ( rc == -1 ) {
			    	Debug( LDAP_DEBUG_ANY, "send_search_entry: "
					"conn %lu matched values filtering failed\n",
					op->o_connid, 0, 0 );
				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
				set_ldap_error( rs, LDAP_OTHER,
					"matched values filtering error" );
				rc = rs->sr_err;
				goto error_return;
			}
		}
	}

	for ( a = rs->sr_entry->e_attrs, j = 0; a != NULL; a = a->a_next, j++ ) {
		AttributeDescription *desc = a->a_desc;
		int finish = 0;

		if ( rs->sr_attrs == NULL ) {
			/* all user attrs request, skip operational attributes */
			if( is_at_operational( desc->ad_type ) ) {
				continue;
			}

		} else {
			/* specific attrs requested */
			if ( is_at_operational( desc->ad_type ) ) {
				/* if not explicitly requested */
				if ( !ad_inlist( desc, rs->sr_attrs )) {
					/* if not all op attrs requested, skip */
					if ( !SLAP_OPATTRS( rs->sr_attr_flags ))
						continue;
					/* if DSA-specific and replicating, skip */
					if ( op->o_sync != SLAP_CONTROL_NONE &&
						desc->ad_type->sat_usage == LDAP_SCHEMA_DSA_OPERATION )
						continue;
				}
			} else {
				if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
					continue;
				}
			}
		}

		if ( attrsonly ) {
			if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
				ACL_READ, &acl_state ) )
			{
				Debug( LDAP_DEBUG_ACL, "send_search_entry: "
					"conn %lu access to attribute %s not allowed\n",
				        op->o_connid, desc->ad_cname.bv_val, 0 );
				continue;
			}

			if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) {
				Debug( LDAP_DEBUG_ANY, 
					"send_search_entry: conn %lu  ber_printf failed\n", 
					op->o_connid, 0, 0 );

				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
				set_ldap_error( rs, LDAP_OTHER,
					"encoding description error");
				rc = rs->sr_err;
				goto error_return;
			}
			finish = 1;

		} else {
			int first = 1;
			for ( i = 0; a->a_nvals[i].bv_val != NULL; i++ ) {
				if ( ! access_allowed( op, rs->sr_entry,
					desc, &a->a_nvals[i], ACL_READ, &acl_state ) )
				{
					Debug( LDAP_DEBUG_ACL,
						"send_search_entry: conn %lu "
						"access to attribute %s, value #%d not allowed\n",
						op->o_connid, desc->ad_cname.bv_val, i );

					continue;
				}

				if ( op->o_vrFilter && e_flags[j][i] == 0 ){
					continue;
				}

				if ( first ) {
					first = 0;
					finish = 1;
					if (( rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname )) == -1 ) {
						Debug( LDAP_DEBUG_ANY,
							"send_search_entry: conn %lu  ber_printf failed\n", 
							op->o_connid, 0, 0 );

						if ( op->o_res_ber == NULL ) ber_free_buf( ber );
						set_ldap_error( rs, LDAP_OTHER,
							"encoding description error");
						rc = rs->sr_err;
						goto error_return;
					}
				}
				if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
					Debug( LDAP_DEBUG_ANY,
						"send_search_entry: conn %lu  "
						"ber_printf failed.\n", op->o_connid, 0, 0 );

					if ( op->o_res_ber == NULL ) ber_free_buf( ber );
					set_ldap_error( rs, LDAP_OTHER,
						"encoding values error" );
					rc = rs->sr_err;
					goto error_return;
				}
			}
		}

		if ( finish && ( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
			Debug( LDAP_DEBUG_ANY,
				"send_search_entry: conn %lu ber_printf failed\n", 
				op->o_connid, 0, 0 );

			if ( op->o_res_ber == NULL ) ber_free_buf( ber );
			set_ldap_error( rs, LDAP_OTHER, "encode end error" );
			rc = rs->sr_err;
			goto error_return;
		}
	}

	/* NOTE: moved before overlays callback circling because
	 * they may modify entry and other stuff in rs */
	if ( rs->sr_operational_attrs != NULL && op->o_vrFilter != NULL ) {
		int	k = 0;
		size_t	size;

		for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
			for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
		}

		size = i * sizeof(char *) + k;
		if ( size > 0 ) {
			char	*a_flags, **tmp;
		
			/*
			 * Reuse previous memory - we likely need less space
			 * for operational attributes
			 */
			tmp = slap_sl_realloc( e_flags, i * sizeof(char *) + k,
				op->o_tmpmemctx );
			if ( tmp == NULL ) {
			    	Debug( LDAP_DEBUG_ANY,
					"send_search_entry: conn %lu "
					"not enough memory "
					"for matched values filtering\n",
					op->o_connid, 0, 0 );
				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
				set_ldap_error( rs, LDAP_OTHER,
					"not enough memory for matched values filtering" );
				goto error_return;
			}
			e_flags = tmp;
			a_flags = (char *)(e_flags + i);
			memset( a_flags, 0, k );
			for ( a = rs->sr_operational_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
				for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
				e_flags[i] = a_flags;
				a_flags += j;
			}
			rc = filter_matched_values(op, rs->sr_operational_attrs, &e_flags) ; 
		    
			if ( rc == -1 ) {
			    	Debug( LDAP_DEBUG_ANY,
					"send_search_entry: conn %lu "
					"matched values filtering failed\n", 
					op->o_connid, 0, 0);
				if ( op->o_res_ber == NULL ) ber_free_buf( ber );
				set_ldap_error( rs, LDAP_OTHER,
					"matched values filtering error" );
				rc = rs->sr_err;
				goto error_return;
			}
		}
	}

	for (a = rs->sr_operational_attrs, j=0; a != NULL; a = a->a_next, j++ ) {
		AttributeDescription *desc = a->a_desc;

		if ( rs->sr_attrs == NULL ) {
			/* all user attrs request, skip operational attributes */
			if( is_at_operational( desc->ad_type ) ) {
				continue;
			}

		} else {
			/* specific attrs requested */
			if( is_at_operational( desc->ad_type ) ) {
				if ( !SLAP_OPATTRS( rs->sr_attr_flags ) && 
					!ad_inlist( desc, rs->sr_attrs ) )
				{
					continue;
				}
				/* if DSA-specific and replicating, skip */
				if ( op->o_sync != SLAP_CONTROL_NONE &&
					desc->ad_type->sat_usage == LDAP_SCHEMA_DSA_OPERATION )
					continue;
			} else {
				if ( !userattrs && !ad_inlist( desc, rs->sr_attrs ) ) {
					continue;
				}
			}
		}

		if ( ! access_allowed( op, rs->sr_entry, desc, NULL,
			ACL_READ, &acl_state ) )
		{
			Debug( LDAP_DEBUG_ACL,
				"send_search_entry: conn %lu "
				"access to attribute %s not allowed\n",
				op->o_connid, desc->ad_cname.bv_val, 0 );

			continue;
		}

		rc = ber_printf( ber, "{O[" /*]}*/ , &desc->ad_cname );
		if ( rc == -1 ) {
			Debug( LDAP_DEBUG_ANY,
				"send_search_entry: conn %lu  "
				"ber_printf failed\n", op->o_connid, 0, 0 );

			if ( op->o_res_ber == NULL ) ber_free_buf( ber );
			set_ldap_error( rs, LDAP_OTHER,
				"encoding description error" );
			rc = rs->sr_err;
			goto error_return;
		}

		if ( ! attrsonly ) {
			for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) {
				if ( ! access_allowed( op, rs->sr_entry,
					desc, &a->a_vals[i], ACL_READ, &acl_state ) )
				{
					Debug( LDAP_DEBUG_ACL,
						"send_search_entry: conn %lu "
						"access to %s, value %d not allowed\n",
						op->o_connid, desc->ad_cname.bv_val, i );

					continue;
				}

				if ( op->o_vrFilter && e_flags[j][i] == 0 ){
					continue;
				}

				if (( rc = ber_printf( ber, "O", &a->a_vals[i] )) == -1 ) {
					Debug( LDAP_DEBUG_ANY,
						"send_search_entry: conn %lu  ber_printf failed\n", 
						op->o_connid, 0, 0 );

					if ( op->o_res_ber == NULL ) ber_free_buf( ber );
					set_ldap_error( rs, LDAP_OTHER,
						"encoding values error" );
					rc = rs->sr_err;
					goto error_return;
				}
			}
		}

		if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
			Debug( LDAP_DEBUG_ANY,
				"send_search_entry: conn %lu  ber_printf failed\n",
				op->o_connid, 0, 0 );

			if ( op->o_res_ber == NULL ) ber_free_buf( ber );
			set_ldap_error( rs, LDAP_OTHER, "encode end error" );
			rc = rs->sr_err;
			goto error_return;
		}
	}

	/* free e_flags */
	if ( e_flags ) {
		slap_sl_free( e_flags, op->o_tmpmemctx );
		e_flags = NULL;
	}

	rc = ber_printf( ber, /*{{*/ "}N}" );

	if( rc != -1 ) {
		rc = send_ldap_controls( op, ber, rs->sr_ctrls );
	}

	if( rc != -1 ) {
#ifdef LDAP_CONNECTIONLESS
		if( op->o_conn && op->o_conn->c_is_udp ) {
			if ( op->o_protocol != LDAP_VERSION2 ) {
				rc = ber_printf( ber, /*{*/ "N}" );
			}
		} else
#endif
		if ( op->o_res_ber == NULL ) {
			rc = ber_printf( ber, /*{*/ "N}" );
		}
	}

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );

		if ( op->o_res_ber == NULL ) ber_free_buf( ber );
		set_ldap_error( rs, LDAP_OTHER, "encode entry end error" );
		rc = rs->sr_err;
		goto error_return;
	}

	Statslog( LDAP_DEBUG_STATS2, "%s ENTRY dn=\"%s\"\n",
	    op->o_log_prefix, rs->sr_entry->e_nname.bv_val, 0, 0, 0 );

	rs_flush_entry( op, rs, NULL );

	if ( op->o_res_ber == NULL ) {
		bytes = send_ldap_ber( op, ber );
		ber_free_buf( ber );

		if ( bytes < 0 ) {
			Debug( LDAP_DEBUG_ANY,
				"send_search_entry: conn %lu  ber write failed.\n", 
				op->o_connid, 0, 0 );

			rc = LDAP_UNAVAILABLE;
			goto error_return;
		}
		rs->sr_nentries++;

		ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_entries, 1 );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
		ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
	}

	Debug( LDAP_DEBUG_TRACE,
		"<= send_search_entry: conn %lu exit.\n", op->o_connid, 0, 0 );

	rc = LDAP_SUCCESS;

error_return:;
	if ( op->o_callback ) {
		(void)slap_cleanup_play( op, rs );
	}

	if ( e_flags ) {
		slap_sl_free( e_flags, op->o_tmpmemctx );
	}

	/* FIXME: Can break if rs now contains an extended response */
	if ( rs->sr_operational_attrs ) {
		attrs_free( rs->sr_operational_attrs );
		rs->sr_operational_attrs = NULL;
	}
	rs->sr_attr_flags = SLAP_ATTRS_UNDEFINED;

	if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
		rs_flush_entry( op, rs, NULL );
	} else {
		RS_ASSERT( (rs->sr_flags & REP_ENTRY_MASK) == 0 );
	}

	if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
		rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
		if ( rs->sr_ctrls ) {
			slap_free_ctrls( op, rs->sr_ctrls );
			rs->sr_ctrls = NULL;
		}
	}

	return( rc );
}
Beispiel #11
0
static long send_ldap_ber(
	Operation *op,
	BerElement *ber )
{
	Connection *conn = op->o_conn;
	ber_len_t bytes;
	long ret = 0;
	char *close_reason;

	ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes );

	/* write only one pdu at a time - wait til it's our turn */
	ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
	if (( op->o_abandon && !op->o_cancel ) || !connection_valid( conn ) ||
		conn->c_writers < 0 ) {
		ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
		return 0;
	}

	conn->c_writers++;

	while ( conn->c_writers > 0 && conn->c_writing ) {
		ldap_pvt_thread_pool_idle( &connection_pool );
		ldap_pvt_thread_cond_wait( &conn->c_write1_cv, &conn->c_write1_mutex );
		ldap_pvt_thread_pool_unidle( &connection_pool );
	}

	/* connection was closed under us */
	if ( conn->c_writers < 0 ) {
		/* we're the last waiter, let the closer continue */
		if ( conn->c_writers == -1 )
			ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
		conn->c_writers++;
		ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
		return 0;
	}

	/* Our turn */
	conn->c_writing = 1;

	/* write the pdu */
	while( 1 ) {
		int err;

		if ( ber_flush2( conn->c_sb, ber, LBER_FLUSH_FREE_NEVER ) == 0 ) {
			ret = bytes;
			break;
		}

		err = sock_errno();

		/*
		 * we got an error.  if it's ewouldblock, we need to
		 * wait on the socket being writable.  otherwise, figure
		 * it's a hard error and return.
		 */

		Debug( LDAP_DEBUG_CONNS, "ber_flush2 failed errno=%d reason=\"%s\"\n",
		    err, sock_errstr(err), 0 );

		if ( err != EWOULDBLOCK && err != EAGAIN ) {
			close_reason = "connection lost on write";
fail:
			conn->c_writers--;
			conn->c_writing = 0;
			ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
			ldap_pvt_thread_mutex_lock( &conn->c_mutex );
			connection_closing( conn, close_reason );
			ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
			return -1;
		}

		/* wait for socket to be write-ready */
		conn->c_writewaiter = 1;
		ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
		ldap_pvt_thread_pool_idle( &connection_pool );
		slap_writewait_play( op );
		err = slapd_wait_writer( conn->c_sd );
		conn->c_writewaiter = 0;
		ldap_pvt_thread_pool_unidle( &connection_pool );
		ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
		/* 0 is timeout, so we close it.
		 * -1 is an error, close it.
		 */
		if ( err <= 0 ) {
			if ( err == 0 )
				close_reason = "writetimeout";
			else
				close_reason = "connection lost on writewait";
			goto fail;
		}

		if ( conn->c_writers < 0 ) {
			ret = 0;
			break;
		}
	}

	conn->c_writing = 0;
	if ( conn->c_writers < 0 ) {
		conn->c_writers++;
		if ( !conn->c_writers )
			ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
	} else {
		conn->c_writers--;
		ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
	}
	ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );

	return ret;
}
Beispiel #12
0
int
slap_send_search_reference( Operation *op, SlapReply *rs )
{
	BerElementBuffer berbuf;
	BerElement	*ber = (BerElement *) &berbuf;
	int rc = 0;
	int bytes;
	char *edn = rs->sr_entry ? rs->sr_entry->e_name.bv_val : "(null)";

	AttributeDescription *ad_ref = slap_schema.si_ad_ref;
	AttributeDescription *ad_entry = slap_schema.si_ad_entry;

	rs->sr_type = REP_SEARCHREF;
	if ( op->o_callback ) {
		rc = slap_response_play( op, rs );
		if ( rc != SLAP_CB_CONTINUE ) {
			goto rel;
		}
	}

	Debug( LDAP_DEBUG_TRACE,
		"=> send_search_reference: dn=\"%s\"\n",
		edn, 0, 0 );

	if (  rs->sr_entry && ! access_allowed( op, rs->sr_entry,
		ad_entry, NULL, ACL_READ, NULL ) )
	{
		Debug( LDAP_DEBUG_ACL,
			"send_search_reference: access to entry not allowed\n",
		    0, 0, 0 );
		rc = 1;
		goto rel;
	}

	if ( rs->sr_entry && ! access_allowed( op, rs->sr_entry,
		ad_ref, NULL, ACL_READ, NULL ) )
	{
		Debug( LDAP_DEBUG_ACL,
			"send_search_reference: access "
			"to reference not allowed\n",
		    0, 0, 0 );
		rc = 1;
		goto rel;
	}

	if( op->o_domain_scope ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_reference: domainScope control in (%s)\n", 
			edn, 0, 0 );
		rc = 0;
		goto rel;
	}

	if( rs->sr_ref == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_reference: null ref in (%s)\n", 
			edn, 0, 0 );
		rc = 1;
		goto rel;
	}

	if( op->o_protocol < LDAP_VERSION3 ) {
		rc = 0;
		/* save the references for the result */
		if( rs->sr_ref[0].bv_val != NULL ) {
			if( value_add( &rs->sr_v2ref, rs->sr_ref ) )
				rc = LDAP_OTHER;
		}
		goto rel;
	}

#ifdef LDAP_CONNECTIONLESS
	if( op->o_conn && op->o_conn->c_is_udp ) {
		ber = op->o_res_ber;
	} else
#endif
	{
		ber_init_w_nullc( ber, LBER_USE_DER );
		ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
	}

	rc = ber_printf( ber, "{it{W}" /*"}"*/ , op->o_msgid,
		LDAP_RES_SEARCH_REFERENCE, rs->sr_ref );

	if( rc != -1 ) {
		rc = send_ldap_controls( op, ber, rs->sr_ctrls );
	}

	if( rc != -1 ) {
		rc = ber_printf( ber, /*"{"*/ "N}" );
	}

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_reference: ber_printf failed\n", 0, 0, 0 );

#ifdef LDAP_CONNECTIONLESS
		if (!op->o_conn || op->o_conn->c_is_udp == 0)
#endif
		ber_free_buf( ber );
		set_ldap_error( rs, LDAP_OTHER, "encode DN error" );
		goto rel;
	}

	rc = 0;
	rs_flush_entry( op, rs, NULL );

#ifdef LDAP_CONNECTIONLESS
	if (!op->o_conn || op->o_conn->c_is_udp == 0) {
#endif
	bytes = send_ldap_ber( op, ber );
	ber_free_buf( ber );

	if ( bytes < 0 ) {
		rc = LDAP_UNAVAILABLE;
	} else {
		ldap_pvt_thread_mutex_lock( &op->o_counters->sc_mutex );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_bytes, (unsigned long)bytes );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_refs, 1 );
		ldap_pvt_mp_add_ulong( op->o_counters->sc_pdu, 1 );
		ldap_pvt_thread_mutex_unlock( &op->o_counters->sc_mutex );
	}
#ifdef LDAP_CONNECTIONLESS
	}
#endif
	if ( rs->sr_ref != NULL ) {
		int	r;

		for ( r = 0; !BER_BVISNULL( &rs->sr_ref[ r ] ); r++ ) {
			Statslog( LDAP_DEBUG_STATS2, "%s REF #%d \"%s\"\n",
				op->o_log_prefix, r, rs->sr_ref[0].bv_val,
				0, 0 );
		}

	} else {
		Statslog( LDAP_DEBUG_STATS2, "%s REF \"(null)\"\n",
			op->o_log_prefix, 0, 0, 0, 0 );
	}

	Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );

	if ( 0 ) {
rel:
	    rs_flush_entry( op, rs, NULL );
	}

	if ( op->o_callback ) {
		(void)slap_cleanup_play( op, rs );
	}

	if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
		rs->sr_flags ^= REP_CTRLS_MUSTBEFREED; /* paranoia */
		if ( rs->sr_ctrls ) {
			slap_free_ctrls( op, rs->sr_ctrls );
			rs->sr_ctrls = NULL;
		}
	}

	return rc;
}
Beispiel #13
0
static int sssvlv_op_search(
    Operation		*op,
    SlapReply		*rs)
{
    slap_overinst			*on			= (slap_overinst *)op->o_bd->bd_info;
    sssvlv_info				*si			= on->on_bi.bi_private;
    int						rc			= SLAP_CB_CONTINUE;
    int	ok;
    sort_op *so = NULL, so2;
    sort_ctrl *sc;
    PagedResultsState *ps;
    vlv_ctrl *vc;
    int sess_id;

    if ( op->o_ctrlflag[sss_cid] <= SLAP_CONTROL_IGNORED ) {
        if ( op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ) {
            LDAPControl *ctrls[2];
            so2.so_vcontext = 0;
            so2.so_vlv_target = 0;
            so2.so_nentries = 0;
            so2.so_vlv_rc = LDAP_VLV_SSS_MISSING;
            so2.so_vlv = op->o_ctrlflag[vlv_cid];
            rc = pack_vlv_response_control( op, rs, &so2, ctrls );
            if ( rc == LDAP_SUCCESS ) {
                ctrls[1] = NULL;
                slap_add_ctrls( op, rs, ctrls );
            }
            rs->sr_err = LDAP_VLV_ERROR;
            rs->sr_text = "Sort control is required with VLV";
            goto leave;
        }
        /* Not server side sort so just continue */
        return SLAP_CB_CONTINUE;
    }

    Debug(LDAP_DEBUG_TRACE,
          "==> sssvlv_search: <%s> %s, control flag: %d\n",
          op->o_req_dn.bv_val, op->ors_filterstr.bv_val,
          op->o_ctrlflag[sss_cid]);

    sc = op->o_controls[sss_cid];
    if ( sc->sc_nkeys > si->svi_max_keys ) {
        rs->sr_text = "Too many sort keys";
        rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
        goto leave;
    }

    ps = ( op->o_pagedresults > SLAP_CONTROL_IGNORED ) ?
         (PagedResultsState*)(op->o_pagedresults_state) : NULL;
    vc = op->o_ctrlflag[vlv_cid] > SLAP_CONTROL_IGNORED ?
         op->o_controls[vlv_cid] : NULL;

    if ( ps && vc ) {
        rs->sr_text = "VLV incompatible with PagedResults";
        rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
        goto leave;
    }

    ok = 1;
    ldap_pvt_thread_mutex_lock( &sort_conns_mutex );
    /* Is there already a sort running on this conn? */
    sess_id = find_session_by_context( si->svi_max_percon, op->o_conn->c_conn_idx, vc ? vc->vc_context : NO_VC_CONTEXT, ps ? ps->ps_cookie : NO_PS_COOKIE );
    if ( sess_id >= 0 ) {
        so = sort_conns[op->o_conn->c_conn_idx][sess_id];
        /* Is it a continuation of a VLV search? */
        if ( !vc || so->so_vlv <= SLAP_CONTROL_IGNORED ||
                vc->vc_context != so->so_vcontext ) {
            /* Is it a continuation of a paged search? */
            if ( !ps || so->so_paged <= SLAP_CONTROL_IGNORED ||
                    op->o_conn->c_pagedresults_state.ps_cookie != ps->ps_cookie ) {
                ok = 0;
            } else if ( !ps->ps_size ) {
                /* Abandoning current request */
                ok = 0;
                so->so_nentries = 0;
                rs->sr_err = LDAP_SUCCESS;
            }
        }
        if (( vc && so->so_paged > SLAP_CONTROL_IGNORED ) ||
                ( ps && so->so_vlv > SLAP_CONTROL_IGNORED )) {
            /* changed from paged to vlv or vice versa, abandon */
            ok = 0;
            so->so_nentries = 0;
            rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
        }
        /* Are there too many running overall? */
    } else if ( si->svi_num >= si->svi_max ) {
        ok = 0;
    } else if ( ( sess_id = find_next_session(si->svi_max_percon, op->o_conn->c_conn_idx ) ) < 0 ) {
        ok = 0;
    } else {
        /* OK, this connection now has a sort running */
        si->svi_num++;
        sort_conns[op->o_conn->c_conn_idx][sess_id] = &so2;
        sort_conns[op->o_conn->c_conn_idx][sess_id]->so_session = sess_id;
    }
    ldap_pvt_thread_mutex_unlock( &sort_conns_mutex );
    if ( ok ) {
        /* If we're a global overlay, this check got bypassed */
        if ( !op->ors_limit && limits_check( op, rs ))
            return rs->sr_err;
        /* are we continuing a VLV search? */
        if ( so && vc && vc->vc_context ) {
            so->so_ctrl = sc;
            send_list( op, rs, so );
            send_result( op, rs, so );
            rc = LDAP_SUCCESS;
            /* are we continuing a paged search? */
        } else if ( so && ps && ps->ps_cookie ) {
            so->so_ctrl = sc;
            send_page( op, rs, so );
            send_result( op, rs, so );
            rc = LDAP_SUCCESS;
        } else {
            slap_callback *cb = op->o_tmpalloc( sizeof(slap_callback),
                                                op->o_tmpmemctx );
            /* Install serversort response callback to handle a new search */
            if ( ps || vc ) {
                so = ch_calloc( 1, sizeof(sort_op));
            } else {
                so = op->o_tmpcalloc( 1, sizeof(sort_op), op->o_tmpmemctx );
            }
            sort_conns[op->o_conn->c_conn_idx][sess_id] = so;

            cb->sc_cleanup		= NULL;
            cb->sc_response		= sssvlv_op_response;
            cb->sc_next			= op->o_callback;
            cb->sc_private		= so;

            so->so_tree = NULL;
            so->so_ctrl = sc;
            so->so_info = si;
            if ( ps ) {
                so->so_paged = op->o_pagedresults;
                so->so_page_size = ps->ps_size;
                op->o_pagedresults = SLAP_CONTROL_IGNORED;
            } else {
                so->so_paged = 0;
                so->so_page_size = 0;
                if ( vc ) {
                    so->so_vlv = op->o_ctrlflag[vlv_cid];
                    so->so_vlv_target = 0;
                    so->so_vlv_rc = 0;
                } else {
                    so->so_vlv = SLAP_CONTROL_NONE;
                }
            }
            so->so_session = sess_id;
            so->so_vlv = op->o_ctrlflag[vlv_cid];
            so->so_vcontext = (unsigned long)so;
            so->so_nentries = 0;

            op->o_callback		= cb;
        }
    } else {
        if ( so && !so->so_nentries ) {
            free_sort_op( op->o_conn, so );
        } else {
            rs->sr_text = "Other sort requests already in progress";
            rs->sr_err = LDAP_BUSY;
        }
leave:
        rc = rs->sr_err;
        send_ldap_result( op, rs );
    }

    return rc;
}
Beispiel #14
0
static int
tlsg_mutex_lock( void **lock )
{
	return ldap_pvt_thread_mutex_lock( *lock );
}
Beispiel #15
0
static int
dds_db_open(
	BackendDB	*be,
	ConfigReply	*cr )
{
	slap_overinst	*on = (slap_overinst *)be->bd_info;
	dds_info_t	*di = on->on_bi.bi_private;
	int		rc = 0;
	void		*thrctx = ldap_pvt_thread_pool_context();

	if ( DDS_OFF( di ) ) {
		goto done;
	}

	if ( SLAP_SINGLE_SHADOW( be ) ) {
		Log1( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
			"DDS incompatible with shadow database \"%s\".\n",
			be->be_suffix[ 0 ].bv_val );
		return 1;
	}

	if ( di->di_max_ttl == 0 ) {
		di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
	}

	if ( di->di_min_ttl == 0 ) {
		di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
	}

	di->di_suffix = be->be_suffix;
	di->di_nsuffix = be->be_nsuffix;

	/* ... so that count, if required, is accurate */
	if ( di->di_max_dynamicObjects > 0 ) {
		/* force deletion of expired entries... */
		be->bd_info = (BackendInfo *)on->on_info;
		rc = dds_expire( thrctx, di );
		be->bd_info = (BackendInfo *)on;
		if ( rc != LDAP_SUCCESS ) {
			rc = 1;
			goto done;
		}

		rc = dds_count( thrctx, be );
		if ( rc != LDAP_SUCCESS ) {
			rc = 1;
			goto done;
		}
	}

	/* start expire task */
	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
	di->di_expire_task = ldap_pvt_runqueue_insert( &slapd_rq,
		DDS_INTERVAL( di ),
		dds_expire_fn, di, "dds_expire_fn",
		be->be_suffix[ 0 ].bv_val );
	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );

	/* register dinamicSubtrees root DSE info support */
	rc = entry_info_register( dds_entry_info, (void *)di );

done:;

	return rc;
}
Beispiel #16
0
int
mdb_delete( Operation *op, SlapReply *rs )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
	struct berval	pdn = {0, NULL};
	Entry	*e = NULL;
	Entry	*p = NULL;
	int		manageDSAit = get_manageDSAit( op );
	AttributeDescription *children = slap_schema.si_ad_children;
	AttributeDescription *entry = slap_schema.si_ad_entry;
	MDB_txn		*txn = NULL;
	MDB_cursor	*mc;
	mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;

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

	int	parent_is_glue = 0;
	int parent_is_leaf = 0;

#ifdef LDAP_X_TXN
	int settle = 0;
#endif

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

#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;

	/* 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_delete) ": txn_begin failed: "
			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	txn = moi->moi_txn;

	/* allocate CSN */
	if ( BER_BVISNULL( &op->o_csn ) ) {
		struct berval csn;
		char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];

		csn.bv_val = csnbuf;
		csn.bv_len = sizeof(csnbuf);
		slap_get_csn( op, &csn, 1 );
	}

	if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
		dnParent( &op->o_req_ndn, &pdn );
	}

	rs->sr_err = mdb_cursor_open( txn, mdb->mi_dn2id, &mc );
	if ( rs->sr_err ) {
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "internal error";
		goto return_results;
	}
	/* get parent */
	rs->sr_err = mdb_dn2entry( op, txn, mc, &pdn, &p, NULL, 1 );
	switch( rs->sr_err ) {
	case 0:
	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 ( rs->sr_err == MDB_NOTFOUND ) {
		Debug( LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
			op->o_req_dn.bv_val);

		if ( p && !BER_BVISEMPTY( &p->e_name )) {
			rs->sr_matched = ch_strdup( p->e_name.bv_val );
			if ( 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;
			}
		} else {
			rs->sr_ref = referral_rewrite( default_referral, NULL,
					&op->o_req_dn, LDAP_SCOPE_DEFAULT );
		}
		if ( p ) {
			mdb_entry_return( op, p );
			p = NULL;
		}

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

	/* get entry */
	rs->sr_err = mdb_dn2entry( op, txn, mc, &op->o_req_ndn, &e, NULL, 0 );
	switch( rs->sr_err ) {
	case MDB_NOTFOUND:
		e = p;
		p = NULL;
	case 0:
		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;
	}

	/* FIXME : dn2entry() should return non-glue entry */
	if ( rs->sr_err == MDB_NOTFOUND || ( !manageDSAit && is_entry_glue( e ))) {
		Debug( LDAP_DEBUG_ARGS,
			"<=- " LDAP_XSTRING(mdb_delete) ": no such object %s\n",
			op->o_req_dn.bv_val);

		rs->sr_matched = ch_strdup( e->e_dn );
		if ( is_entry_referral( e )) {
			BerVarray ref = get_entry_referrals( op, e );
			rs->sr_ref = referral_rewrite( ref, &e->e_name,
				&op->o_req_dn, LDAP_SCOPE_DEFAULT );
			ber_bvarray_free( ref );
		} else {
			rs->sr_ref = NULL;
		}
		mdb_entry_return( op, e );
		e = NULL;

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

	if ( pdn.bv_len != 0 ) {
		/* check parent for "children" acl */
		rs->sr_err = access_allowed( op, p,
			children, NULL, ACL_WDEL, NULL );

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

	} else {
		/* no parent, must be root to delete */
		if( ! be_isroot( op ) ) {
			if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
				|| be_shadow_update( op ) ) {
				p = (Entry *)&slap_entry_root;

				/* check parent for "children" acl */
				rs->sr_err = access_allowed( op, p,
					children, NULL, ACL_WDEL, NULL );

				p = NULL;

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

			} else {
				Debug( LDAP_DEBUG_TRACE,
					"<=- " LDAP_XSTRING(mdb_delete)
					": no parent and not root\n" );
				rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
				goto return_results;
			}
		}
	}

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

	rs->sr_err = access_allowed( op, e,
		entry, NULL, ACL_WDEL, NULL );

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

	if ( !manageDSAit && is_entry_referral( e ) ) {
		/* entry is a referral, don't allow delete */
		rs->sr_ref = get_entry_referrals( op, e );

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_delete) ": entry is referral\n" );

		rs->sr_err = LDAP_REFERRAL;
		rs->sr_matched = ch_strdup( e->e_name.bv_val );
		rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
		goto return_results;
	}

	/* pre-read */
	if( op->o_preread ) {
		if( preread_ctrl == NULL ) {
			preread_ctrl = &ctrls[num_ctrls++];
			ctrls[num_ctrls] = NULL;
		}
		if( slap_read_controls( op, rs, e,
			&slap_pre_read_bv, preread_ctrl ) )
		{
			Debug( LDAP_DEBUG_TRACE,
				"<=- " LDAP_XSTRING(mdb_delete) ": pre-read "
				"failed!\n" );
			if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
				/* FIXME: is it correct to abort
				 * operation if control fails? */
				goto return_results;
			}
		}
	}

	rs->sr_text = NULL;

	/* Can't do it if we have kids */
	rs->sr_err = mdb_dn2id_children( op, txn, e );
	if( rs->sr_err != MDB_NOTFOUND ) {
		switch( rs->sr_err ) {
		case 0:
			Debug(LDAP_DEBUG_ARGS,
				"<=- " LDAP_XSTRING(mdb_delete)
				": non-leaf %s\n",
				op->o_req_dn.bv_val);
			rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
			rs->sr_text = "subordinate objects must be deleted first";
			break;
		default:
			Debug(LDAP_DEBUG_ARGS,
				"<=- " LDAP_XSTRING(mdb_delete)
				": has_children failed: %s (%d)\n",
				mdb_strerror(rs->sr_err), rs->sr_err );
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "internal error";
		}
		goto return_results;
	}

	/* delete from dn2id */
	rs->sr_err = mdb_dn2id_delete( op, mc, e->e_id, 1 );
	mdb_cursor_close( mc );
	if ( rs->sr_err != 0 ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(mdb_delete) ": dn2id failed: "
			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err );
		rs->sr_text = "DN index delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	/* delete indices for old attributes */
	rs->sr_err = mdb_index_entry_del( op, txn, e );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		Debug(LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(mdb_delete) ": index failed: "
			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err );
		rs->sr_text = "entry index delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	/* fixup delete CSN */
	if ( !SLAP_SHADOW( op->o_bd )) {
		struct berval vals[2];

		assert( !BER_BVISNULL( &op->o_csn ) );
		vals[0] = op->o_csn;
		BER_BVZERO( &vals[1] );
		rs->sr_err = mdb_index_values( op, txn, slap_schema.si_ad_entryCSN,
			vals, 0, SLAP_INDEX_ADD_OP );
		if ( rs->sr_err != LDAP_SUCCESS ) {
			rs->sr_text = "entryCSN index update failed";
			rs->sr_err = LDAP_OTHER;
			goto return_results;
		}
	}

	/* delete from id2entry */
	rs->sr_err = mdb_id2entry_delete( op->o_bd, txn, e );
	if ( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			"<=- " LDAP_XSTRING(mdb_delete) ": id2entry failed: "
			"%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err );
		rs->sr_text = "entry delete failed";
		rs->sr_err = LDAP_OTHER;
		goto return_results;
	}

	if ( pdn.bv_len != 0 ) {
		parent_is_glue = is_entry_glue(p);
		rs->sr_err = mdb_dn2id_children( op, txn, p );
		if ( rs->sr_err != MDB_NOTFOUND ) {
			switch( rs->sr_err ) {
			case 0:
				break;
			default:
				Debug(LDAP_DEBUG_ARGS,
					"<=- " LDAP_XSTRING(mdb_delete)
					": has_children failed: %s (%d)\n",
					mdb_strerror(rs->sr_err), rs->sr_err );
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "internal error";
				goto return_results;
			}
			parent_is_leaf = 1;
		}
		mdb_entry_return( op, p );
		p = NULL;
	}

	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_txn_abort( txn );
			rs->sr_err = LDAP_X_NO_OPERATION;
			txn = NULL;
			goto return_results;
		} else {
			rs->sr_err = mdb_txn_commit( txn );
		}
		txn = NULL;
	}

	if( rs->sr_err != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			LDAP_XSTRING(mdb_delete) ": txn_%s failed: %s (%d)\n",
			op->o_noop ? "abort (no-op)" : "commit",
			mdb_strerror(rs->sr_err), rs->sr_err );
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "commit failed";

		goto return_results;
	}

	Debug( LDAP_DEBUG_TRACE,
		LDAP_XSTRING(mdb_delete) ": deleted%s id=%08lx dn=\"%s\"\n",
		op->o_noop ? " (no-op)" : "",
		e->e_id, op->o_req_dn.bv_val );
	rs->sr_err = LDAP_SUCCESS;
	rs->sr_text = NULL;
	if( num_ctrls ) rs->sr_ctrls = ctrls;

return_results:
	if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
		op->o_delete_glue_parent = 1;
	}

	if ( p != NULL ) {
		mdb_entry_return( op, p );
	}

	/* free entry */
	if( e != NULL ) {
		mdb_entry_return( op, e );
	}

	if( moi == &opinfo ) {
		if( txn != NULL ) {
			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--;
	}

	send_ldap_result( op, rs );
	slap_graduate_commit_csn( op );

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

#if 0
	if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
		TXN_CHECKPOINT( mdb->bi_dbenv,
			mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
	}
#endif
	return rs->sr_err;
}
Beispiel #17
0
static int
dds_op_add( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
	dds_info_t	*di = on->on_bi.bi_private;
	int		is_dynamicObject;

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

	is_dynamicObject = is_entry_dynamicObject( op->ora_e );

	/* FIXME: do not allow this right now, pending clarification */
	if ( is_dynamicObject ) {
		rs->sr_err = LDAP_SUCCESS;

		if ( is_entry_referral( op->ora_e ) ) {
			rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			rs->sr_text = "a referral cannot be a dynamicObject";

		} else if ( is_entry_alias( op->ora_e ) ) {
			rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			rs->sr_text = "an alias cannot be a dynamicObject";
		}

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

	/* we don't allow dynamicObjects to have static subordinates */
	if ( !dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) {
		struct berval	p_ndn;
		Entry		*e = NULL;
		int		rc;
		BackendInfo	*bi = op->o_bd->bd_info;

		dnParent( &op->o_req_ndn, &p_ndn );
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
		rc = be_entry_get_rw( op, &p_ndn,
			slap_schema.si_oc_dynamicObject, NULL, 0, &e );
		if ( rc == LDAP_SUCCESS && e != NULL ) {
			if ( !is_dynamicObject ) {
				/* return referral only if "disclose"
				 * is granted on the object */
				if ( ! access_allowed( op, e,
						slap_schema.si_ad_entry,
						NULL, ACL_DISCLOSE, NULL ) )
				{
					rc = rs->sr_err = LDAP_NO_SUCH_OBJECT;
					send_ldap_result( op, rs );

				} else {
					rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
					send_ldap_error( op, rs, rc, "no static subordinate entries allowed for dynamicObject" );
				}
			}

			be_entry_release_r( op, e );
			if ( rc != LDAP_SUCCESS ) {
				return rc;
			}
		}
		op->o_bd->bd_info = bi;
	}

	/* handle dynamic object operational attr(s) */
	if ( is_dynamicObject ) {
		time_t		ttl, expire;
		char		ttlbuf[STRLENOF("31557600") + 1];
		char		tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
		struct berval	bv;

		if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
			ldap_pvt_thread_mutex_lock( &di->di_mutex );
			rs->sr_err = ( di->di_max_dynamicObjects &&
				di->di_num_dynamicObjects >= di->di_max_dynamicObjects );
			ldap_pvt_thread_mutex_unlock( &di->di_mutex );
			if ( rs->sr_err ) {
				op->o_bd->bd_info = (BackendInfo *)on->on_info;
				send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
					"too many dynamicObjects in context" );
				return rs->sr_err;
			}
		}

		ttl = DDS_DEFAULT_TTL( di );

		/* assert because should be checked at configure */
		assert( ttl <= DDS_RF2589_MAX_TTL );

		bv.bv_val = ttlbuf;
		bv.bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl );
		assert( bv.bv_len < sizeof( ttlbuf ) );

		/* FIXME: apparently, values in op->ora_e are malloc'ed
		 * on the thread's slab; works fine by chance,
		 * only because the attribute doesn't exist yet. */
		assert( attr_find( op->ora_e->e_attrs, slap_schema.si_ad_entryTtl ) == NULL );
		attr_merge_one( op->ora_e, slap_schema.si_ad_entryTtl, &bv, &bv );

		expire = slap_get_time() + ttl;
		bv.bv_val = tsbuf;
		bv.bv_len = sizeof( tsbuf );
		slap_timestamp( &expire, &bv );
		assert( attr_find( op->ora_e->e_attrs, ad_entryExpireTimestamp ) == NULL );
		attr_merge_one( op->ora_e, ad_entryExpireTimestamp, &bv, &bv );

		/* if required, install counter callback */
		if ( di->di_max_dynamicObjects > 0) {
			slap_callback	*sc;

			sc = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
			sc->sc_cleanup = dds_freeit_cb;
			sc->sc_response = dds_counter_cb;
			sc->sc_private = di;
			sc->sc_next = op->o_callback;

			op->o_callback = sc;
		}
	}

	return SLAP_CB_CONTINUE;
}
Beispiel #18
0
int ldap_pvt_get_hname(
	const struct sockaddr *sa,
	int len,
	char *name,
	int namelen,
	char **err )
{
	int rc;
#if defined( HAVE_GETNAMEINFO )

#if defined( LDAP_R_COMPILE )
	ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
#endif
	rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
#if defined( LDAP_R_COMPILE )
	ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
#endif
	if ( rc ) *err = AC_GAI_STRERROR( rc );
	return rc;

#else /* !HAVE_GETNAMEINFO */
	char *addr;
	int alen;
	struct hostent *hp = NULL;
#ifdef HAVE_GETHOSTBYADDR_R
	struct hostent hb;
	int buflen=BUFSTART, h_errno;
	char *buf=NULL;
#endif

#ifdef LDAP_PF_INET6
	if (sa->sa_family == AF_INET6) {
		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
		addr = (char *)&sin->sin6_addr;
		alen = sizeof(sin->sin6_addr);
	} else
#endif
	if (sa->sa_family == AF_INET) {
		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
		addr = (char *)&sin->sin_addr;
		alen = sizeof(sin->sin_addr);
	} else {
		rc = NO_RECOVERY;
		*err = (char *)hp_strerror( rc );
		return rc;
	}
#if defined( HAVE_GETHOSTBYADDR_R )
	for(;buflen<BUFMAX;) {
		if (safe_realloc( &buf, buflen )==NULL) {
			*err = (char *)STRERROR( ENOMEM );
			return ENOMEM;
		}
#if (GETHOSTBYADDR_R_NARGS < 8)
		hp=gethostbyaddr_r( addr, alen, sa->sa_family,
			&hb, buf, buflen, &h_errno );
		rc = (hp == NULL) ? -1 : 0;
#else
		rc = gethostbyaddr_r( addr, alen, sa->sa_family,
			&hb, buf, buflen, 
			&hp, &h_errno );
#endif
#ifdef NETDB_INTERNAL
		if ((rc<0) &&
			(h_errno==NETDB_INTERNAL) &&
			(errno==ERANGE))
		{
			buflen*=2;
			continue;
		}
#endif
		break;
	}
	if (hp) {
		strncpy( name, hp->h_name, namelen );
	} else {
		*err = (char *)hp_strerror( h_errno );
	}
	LDAP_FREE(buf);
#else /* HAVE_GETHOSTBYADDR_R */

#if defined( LDAP_R_COMPILE )
	ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
#endif
	hp = gethostbyaddr( addr, alen, sa->sa_family );
	if (hp) {
		strncpy( name, hp->h_name, namelen );
		rc = 0;
	} else {
		rc = h_errno;
		*err = (char *)hp_strerror( h_errno );
	}
#if defined( LDAP_R_COMPILE )
	ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
#endif

#endif	/* !HAVE_GETHOSTBYADDR_R */
	return rc;
#endif	/* !HAVE_GETNAMEINFO */
}
Beispiel #19
0
void
slapi_int_connection_init_pb( Slapi_PBlock *pb, ber_tag_t tag )
{
	Connection		*conn;
	Operation		*op;
	ber_len_t		max = sockbuf_max_incoming;

	conn = (Connection *) slapi_ch_calloc( 1, sizeof(Connection) );

	LDAP_STAILQ_INIT( &conn->c_pending_ops );

	op = (Operation *) slapi_ch_calloc( 1, sizeof(OperationBuffer) );
	op->o_hdr = &((OperationBuffer *) op)->ob_hdr;
	op->o_controls = ((OperationBuffer *) op)->ob_controls;

	op->o_callback = (slap_callback *) slapi_ch_calloc( 1, sizeof(slap_callback) );
	op->o_callback->sc_response = slapi_int_response;
	op->o_callback->sc_cleanup = NULL;
	op->o_callback->sc_private = pb;
	op->o_callback->sc_next = NULL;

	conn->c_pending_ops.stqh_first = op;

	/* connection object authorization information */
	conn->c_authtype = LDAP_AUTH_NONE;
	BER_BVZERO( &conn->c_authmech );
	BER_BVZERO( &conn->c_dn );
	BER_BVZERO( &conn->c_ndn );

	conn->c_listener = &slapi_listener;
	ber_dupbv( &conn->c_peer_domain, (struct berval *)&slap_unknown_bv );
	ber_dupbv( &conn->c_peer_name, (struct berval *)&slap_unknown_bv );

	LDAP_STAILQ_INIT( &conn->c_ops );

	BER_BVZERO( &conn->c_sasl_bind_mech );
	conn->c_sasl_authctx = NULL;
	conn->c_sasl_sockctx = NULL;
	conn->c_sasl_extra = NULL;

	conn->c_sb = ber_sockbuf_alloc();

	ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );

	conn->c_currentber = NULL;

	/* should check status of thread calls */
	ldap_pvt_thread_mutex_init( &conn->c_mutex );
	ldap_pvt_thread_mutex_init( &conn->c_write1_mutex );
	ldap_pvt_thread_mutex_init( &conn->c_write2_mutex );
	ldap_pvt_thread_cond_init( &conn->c_write1_cv );
	ldap_pvt_thread_cond_init( &conn->c_write2_cv );

	ldap_pvt_thread_mutex_lock( &conn->c_mutex );

	conn->c_n_ops_received = 0;
	conn->c_n_ops_executing = 0;
	conn->c_n_ops_pending = 0;
	conn->c_n_ops_completed = 0;

	conn->c_n_get = 0;
	conn->c_n_read = 0;
	conn->c_n_write = 0;

	conn->c_protocol = LDAP_VERSION3; 

	conn->c_activitytime = conn->c_starttime = slap_get_time();

	/*
	 * A real connection ID is required, because syncrepl associates
	 * pending CSNs with unique ( connection, operation ) tuples.
	 * Setting a fake connection ID will cause slap_get_commit_csn()
	 * to return a stale value.
	 */
	connection_assign_nextid( conn );

	conn->c_conn_state  = 0x01;	/* SLAP_C_ACTIVE */
	conn->c_struct_state = 0x02;	/* SLAP_C_USED */

	conn->c_ssf = conn->c_transport_ssf = local_ssf;
	conn->c_tls_ssf = 0;

	backend_connection_init( conn );

	conn->c_send_ldap_result = slap_send_ldap_result;
	conn->c_send_search_entry = slap_send_search_entry;
	conn->c_send_ldap_extended = slap_send_ldap_extended;
	conn->c_send_search_reference = slap_send_search_reference;

	/* operation object */
	op->o_tag = tag;
	op->o_protocol = LDAP_VERSION3; 
	BER_BVZERO( &op->o_authmech );
	op->o_time = slap_get_time();
	op->o_do_not_cache = 1;
	op->o_threadctx = ldap_pvt_thread_pool_context();
	op->o_tmpmemctx = NULL;
	op->o_tmpmfuncs = &ch_mfuncs;
	op->o_conn = conn;
	op->o_connid = conn->c_connid;
	op->o_bd = frontendDB;

	/* extensions */
	slapi_int_create_object_extensions( SLAPI_X_EXT_OPERATION, op );
	slapi_int_create_object_extensions( SLAPI_X_EXT_CONNECTION, conn );

	pb->pb_rs = (SlapReply *)slapi_ch_calloc( 1, sizeof(SlapReply) );
	pb->pb_op = op;
	pb->pb_conn = conn;
	pb->pb_intop = 1;

	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
}
Beispiel #20
0
static int
vc_exop(
	Operation	*op,
	SlapReply	*rs )
{
	int rc = LDAP_SUCCESS;
	ber_tag_t tag;
	ber_len_t len = -1;
	BerElementBuffer berbuf;
	BerElement *ber = (BerElement *)&berbuf;
	struct berval reqdata = BER_BVNULL;

	struct berval cookie = BER_BVNULL;
	struct berval bdn = BER_BVNULL;
	ber_tag_t authtag;
	struct berval cred = BER_BVNULL;
	struct berval ndn = BER_BVNULL;
	struct berval mechanism = BER_BVNULL;

	vc_conn_t *conn = NULL;
	vc_cb_t vc = { 0 };
	slap_callback sc = { 0 };
	SlapReply rs2 = { 0 };

	if ( op->ore_reqdata == NULL || op->ore_reqdata->bv_len == 0 ) {
		rs->sr_text = "empty request data field in VerifyCredentials exop";
		return LDAP_PROTOCOL_ERROR;
	}

	/* optimistic */
	rs->sr_err = LDAP_SUCCESS;

	ber_dupbv_x( &reqdata, op->ore_reqdata, op->o_tmpmemctx );

	/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
	ber_init2( ber, &reqdata, 0 );

	tag = ber_scanf( ber, "{" /*}*/ );
	if ( tag != LBER_SEQUENCE ) {
		rs->sr_err = LDAP_PROTOCOL_ERROR;
		goto done;
	}

	tag = ber_peek_tag( ber, &len );
	if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE ) {
		/*
		 * cookie: the pointer to the connection
		 * of this operation
		 */

		ber_scanf( ber, "m", &cookie );
		if ( cookie.bv_len != sizeof(Connection *) ) {
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			goto done;
		}
	}

	/* DN, authtag */
	tag = ber_scanf( ber, "mt", &bdn, &authtag );
	if ( tag == LBER_ERROR ) {
		rs->sr_err = LDAP_PROTOCOL_ERROR;
		goto done;
	}

	rc = dnNormalize( 0, NULL, NULL, &bdn, &ndn, op->o_tmpmemctx );
	if ( rc != LDAP_SUCCESS ) {
		rs->sr_err = LDAP_PROTOCOL_ERROR;
		goto done;
	}

	switch ( authtag ) {
	case LDAP_AUTH_SIMPLE:
		/* cookie only makes sense for SASL bind (so far) */
		if ( !BER_BVISNULL( &cookie ) ) {
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			goto done;
		}

		tag = ber_scanf( ber, "m", &cred );
		if ( tag == LBER_ERROR ) {
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			goto done;
		}
		break;

	case LDAP_AUTH_SASL:
		tag = ber_scanf( ber, "{s" /*}*/ , &mechanism );
		if ( tag == LBER_ERROR || 
			BER_BVISNULL( &mechanism ) || BER_BVISEMPTY( &mechanism ) )
		{
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			goto done;
		}

		tag = ber_peek_tag( ber, &len );
		if ( tag == LBER_OCTETSTRING ) {
			ber_scanf( ber, "m", &cred );
		}

		tag = ber_scanf( ber, /*{*/ "}" );
		break;

	default:
		rs->sr_err = LDAP_PROTOCOL_ERROR;
		goto done;
	}

	if ( !BER_BVISNULL( &cookie ) ) {
		vc_conn_t tmp = { 0 };

		AC_MEMCPY( (char *)&tmp.conn, (const char *)cookie.bv_val, cookie.bv_len );
		ldap_pvt_thread_mutex_lock( &vc_mutex );
		conn = (vc_conn_t *)avl_find( vc_tree, (caddr_t)&tmp, vc_conn_cmp );
		if ( conn == NULL || ( conn != NULL && conn->refcnt != 0 ) ) {
			conn = NULL;
			ldap_pvt_thread_mutex_unlock( &vc_mutex );
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			goto done;
		}
		conn->refcnt++;
		ldap_pvt_thread_mutex_unlock( &vc_mutex );

	} else {
		void *thrctx;

		conn = (vc_conn_t *)SLAP_CALLOC( 1, sizeof( vc_conn_t ) );
		conn->refcnt = 1;

		thrctx = ldap_pvt_thread_pool_context();
		connection_fake_init2( &conn->connbuf, &conn->opbuf, thrctx, 0 );
		conn->op = &conn->opbuf.ob_op;
		snprintf( conn->op->o_log_prefix, sizeof( conn->op->o_log_prefix ),
			"%s VERIFYCREDENTIALS", op->o_log_prefix );
	}

	conn->op->o_tag = LDAP_REQ_BIND;
	memset( &conn->op->oq_bind, 0, sizeof( conn->op->oq_bind ) );
	conn->op->o_req_dn = ndn;
	conn->op->o_req_ndn = ndn;
	conn->op->o_protocol = LDAP_VERSION3;
	conn->op->orb_method = authtag;
	conn->op->o_callback = &sc;

	/* TODO: controls */
	tag = ber_peek_tag( ber, &len );
	if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS ) {
		conn->op->o_ber = ber;
		rc = get_ctrls2( conn->op, &rs2, 0, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS );
		if ( rc != LDAP_SUCCESS ) {
			rs->sr_err = LDAP_PROTOCOL_ERROR;
			goto done;
		}
	}

	tag = ber_skip_tag( ber, &len );
	if ( len || tag != LBER_DEFAULT ) {
		rs->sr_err = LDAP_PROTOCOL_ERROR;
		goto done;
	}

	switch ( authtag ) {
	case LDAP_AUTH_SIMPLE:
		break;

	case LDAP_AUTH_SASL:
		conn->op->orb_mech = mechanism;
		break;
	}

	conn->op->orb_cred = cred;
	sc.sc_response = vc_cb;
	sc.sc_private = &vc;

	conn->op->o_bd = frontendDB;
	rs->sr_err = frontendDB->be_bind( conn->op, &rs2 );

	if ( conn->op->o_conn->c_sasl_bind_in_progress ) {
		rc = vc_create_response( conn, rs2.sr_err, rs2.sr_text,
			!BER_BVISEMPTY( &vc.sasldata ) ? &vc.sasldata : NULL,
			NULL,
			vc.ctrls, &rs->sr_rspdata );

	} else {
		rc = vc_create_response( NULL, rs2.sr_err, rs2.sr_text,
			NULL,
			&conn->op->o_conn->c_dn,
			vc.ctrls, &rs->sr_rspdata );
	}

	if ( rc != 0 ) {
		rs->sr_err = LDAP_OTHER;
		goto done;
	}

	if ( !BER_BVISNULL( &conn->op->o_conn->c_dn ) &&
		conn->op->o_conn->c_dn.bv_val != conn->op->o_conn->c_ndn.bv_val )
		ber_memfree( conn->op->o_conn->c_dn.bv_val );
	if ( !BER_BVISNULL( &conn->op->o_conn->c_ndn ) )
		ber_memfree( conn->op->o_conn->c_ndn.bv_val );

done:;
	if ( conn ) {
		if ( conn->op->o_conn->c_sasl_bind_in_progress ) {
			if ( conn->conn == NULL ) {
				conn->conn = conn;
				conn->refcnt--;
				ldap_pvt_thread_mutex_lock( &vc_mutex );
				rc = avl_insert( &vc_tree, (caddr_t)conn,
					vc_conn_cmp, vc_conn_dup );
				ldap_pvt_thread_mutex_unlock( &vc_mutex );
				assert( rc == 0 );

			} else {
				ldap_pvt_thread_mutex_lock( &vc_mutex );
				conn->refcnt--;
				ldap_pvt_thread_mutex_unlock( &vc_mutex );
			}

		} else {
			if ( conn->conn != NULL ) {
				vc_conn_t *tmp;

				ldap_pvt_thread_mutex_lock( &vc_mutex );
				tmp = avl_delete( &vc_tree, (caddr_t)conn, vc_conn_cmp );
				ldap_pvt_thread_mutex_unlock( &vc_mutex );
			}
			SLAP_FREE( conn );
		}
	}

	if ( vc.ctrls ) {
		ldap_controls_free( vc.ctrls );
		vc.ctrls = NULL;
	}

	if ( !BER_BVISNULL( &ndn ) ) {
		op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
		BER_BVZERO( &ndn );
	}

	op->o_tmpfree( reqdata.bv_val, op->o_tmpmemctx );
	BER_BVZERO( &reqdata );

        return rs->sr_err;
}
Beispiel #21
0
int
starttls_extop ( Operation *op, SlapReply *rs )
{
	int rc;

	Statslog( LDAP_DEBUG_STATS, "%s STARTTLS\n",
	    op->o_log_prefix, 0, 0, 0, 0 );

	if ( op->ore_reqdata != NULL ) {
		/* no request data should be provided */
		rs->sr_text = "no request data expected";
		return LDAP_PROTOCOL_ERROR;
	}

	/* acquire connection lock */
	ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );

	/* can't start TLS if it is already started */
	if (op->o_conn->c_is_tls != 0) {
		rs->sr_text = "TLS already started";
		rc = LDAP_OPERATIONS_ERROR;
		goto done;
	}

	/* can't start TLS if there are other op's around */
	if (( !LDAP_STAILQ_EMPTY(&op->o_conn->c_ops) &&
			(LDAP_STAILQ_FIRST(&op->o_conn->c_ops) != op ||
			LDAP_STAILQ_NEXT(op, o_next) != NULL)) ||
		( !LDAP_STAILQ_EMPTY(&op->o_conn->c_pending_ops) ))
	{
		rs->sr_text = "cannot start TLS when operations are outstanding";
		rc = LDAP_OPERATIONS_ERROR;
		goto done;
	}

	if ( !( global_disallows & SLAP_DISALLOW_TLS_2_ANON ) &&
		( op->o_conn->c_dn.bv_len != 0 ) )
	{
		Statslog( LDAP_DEBUG_STATS,
			"%s AUTHZ anonymous mech=starttls ssf=0\n",
			op->o_log_prefix, 0, 0, 0, 0 );

		/* force to anonymous */
		connection2anonymous( op->o_conn );
	}

	if ( ( global_disallows & SLAP_DISALLOW_TLS_AUTHC ) &&
		( op->o_conn->c_dn.bv_len != 0 ) )
	{
		rs->sr_text = "cannot start TLS after authentication";
		rc = LDAP_OPERATIONS_ERROR;
		goto done;
	}

	/* fail if TLS could not be initialized */
	if ( slap_tls_ctx == NULL ) {
		if (default_referral != NULL) {
			/* caller will put the referral in the result */
			rc = LDAP_REFERRAL;
			goto done;
		}

		rs->sr_text = "Could not initialize TLS";
		rc = LDAP_UNAVAILABLE;
		goto done;
	}

    op->o_conn->c_is_tls = 1;
    op->o_conn->c_needs_tls_accept = 1;

    rc = LDAP_SUCCESS;

done:
	/* give up connection lock */
	ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );

	/* FIXME: RACE CONDITION! we give up lock before sending result
	 * Should be resolved by reworking connection state, not
	 * by moving send here (so as to ensure proper TLS sequencing)
	 */

	return rc;
}
Beispiel #22
0
int
passwd_back_search(
    Operation	*op,
    SlapReply	*rs )
{
	struct passwd	*pw;
	time_t		stoptime = (time_t)-1;

	LDAPRDN rdn = NULL;
	struct berval parent = BER_BVNULL;

	AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;

	if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
		stoptime = op->o_time + op->ors_tlimit;
	}

	/* Handle a query for the base of this backend */
	if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
		struct berval	val;

		rs->sr_matched = op->o_req_dn.bv_val;

		if( op->ors_scope != LDAP_SCOPE_ONELEVEL ) {
			AttributeDescription	*desc = NULL;
			char			*next;
			Entry			e = { 0 };

			/* Create an entry corresponding to the base DN */
			e.e_name.bv_val = ch_strdup( op->o_req_dn.bv_val );
			e.e_name.bv_len = op->o_req_dn.bv_len;
			e.e_nname.bv_val =  ch_strdup( op->o_req_ndn.bv_val );
			e.e_nname.bv_len = op->o_req_ndn.bv_len;

			/* Use the first attribute of the DN
		 	* as an attribute within the entry itself.
		 	*/
			if( ldap_bv2rdn( &op->o_req_dn, &rdn, &next, 
				LDAP_DN_FORMAT_LDAP ) )
			{
				rs->sr_err = LDAP_INVALID_DN_SYNTAX;
				goto done;
			}

			if( slap_bv2ad( &rdn[0]->la_attr, &desc, &rs->sr_text )) {
				rs->sr_err = LDAP_NO_SUCH_OBJECT;
				ldap_rdnfree(rdn);
				goto done;
			}

			attr_merge_normalize_one( &e, desc, &rdn[0]->la_value, NULL );

			ldap_rdnfree(rdn);
			rdn = NULL;

			/* Every entry needs an objectclass. We don't really
			 * know if our hardcoded choice here agrees with the
			 * DN that was configured for this backend, but it's
			 * better than nothing.
			 *
			 * should be a configuratable item
			 */
			BER_BVSTR( &val, "organizationalUnit" );
			attr_merge_one( &e, ad_objectClass, &val, NULL );
	
			if ( test_filter( op, &e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
				rs->sr_entry = &e;
				rs->sr_attrs = op->ors_attrs;
				rs->sr_flags = REP_ENTRY_MODIFIABLE;
				send_search_entry( op, rs );
			}

			entry_clean( &e );
		}

		if ( op->ors_scope != LDAP_SCOPE_BASE ) {
			/* check all our "children" */

			ldap_pvt_thread_mutex_lock( &passwd_mutex );
			pw_start( op->o_bd );
			for ( pw = getpwent(); pw != NULL; pw = getpwent() ) {
				Entry		e = { 0 };

				/* check for abandon */
				if ( op->o_abandon ) {
					endpwent();
					ldap_pvt_thread_mutex_unlock( &passwd_mutex );
					return( SLAPD_ABANDON );
				}

				/* check time limit */
				if ( op->ors_tlimit != SLAP_NO_LIMIT
						&& slap_get_time() > stoptime )
				{
					send_ldap_error( op, rs, LDAP_TIMELIMIT_EXCEEDED, NULL );
					endpwent();
					ldap_pvt_thread_mutex_unlock( &passwd_mutex );
					return( 0 );
				}

				if ( pw2entry( op->o_bd, pw, &e ) ) {
					rs->sr_err = LDAP_OTHER;
					endpwent();
					ldap_pvt_thread_mutex_unlock( &passwd_mutex );
					goto done;
				}

				if ( test_filter( op, &e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
					/* check size limit */
					if ( --op->ors_slimit == -1 ) {
						send_ldap_error( op, rs, LDAP_SIZELIMIT_EXCEEDED, NULL );
						endpwent();
						ldap_pvt_thread_mutex_unlock( &passwd_mutex );
						return( 0 );
					}

					rs->sr_entry = &e;
					rs->sr_attrs = op->ors_attrs;
					rs->sr_flags = REP_ENTRY_MODIFIABLE;
					send_search_entry( op, rs );
				}

				entry_clean( &e );
			}
			endpwent();
			ldap_pvt_thread_mutex_unlock( &passwd_mutex );
		}

	} else {
		char	*next;
		Entry	e = { 0 };
		int	rc;

		if (! be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
			dnParent( &op->o_req_ndn, &parent );
		}

		/* This backend is only one layer deep. Don't answer requests for
		 * anything deeper than that.
		 */
		if( !be_issuffix( op->o_bd, &parent ) ) {
			int i;
			for( i=0; op->o_bd->be_nsuffix[i].bv_val != NULL; i++ ) {
				if( dnIsSuffix( &op->o_req_ndn, &op->o_bd->be_nsuffix[i] ) ) {
					rs->sr_matched = op->o_bd->be_suffix[i].bv_val;
					break;
				}
			}
			rs->sr_err = LDAP_NO_SUCH_OBJECT;
			goto done;
		}

		if( op->ors_scope == LDAP_SCOPE_ONELEVEL ) {
			goto done;
		}

		if ( ldap_bv2rdn( &op->o_req_dn, &rdn, &next,
			LDAP_DN_FORMAT_LDAP ))
		{ 
			rs->sr_err = LDAP_OTHER;
			goto done;
		}

		ldap_pvt_thread_mutex_lock( &passwd_mutex );
		pw_start( op->o_bd );
		pw = getpwnam( rdn[0]->la_value.bv_val );
		if ( pw == NULL ) {
			rs->sr_matched = parent.bv_val;
			rs->sr_err = LDAP_NO_SUCH_OBJECT;
			ldap_pvt_thread_mutex_unlock( &passwd_mutex );
			goto done;
		}

		rc = pw2entry( op->o_bd, pw, &e );
		ldap_pvt_thread_mutex_unlock( &passwd_mutex );
		if ( rc ) {
			rs->sr_err = LDAP_OTHER;
			goto done;
		}

		if ( test_filter( op, &e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
			rs->sr_entry = &e;
			rs->sr_attrs = op->ors_attrs;
			rs->sr_flags = REP_ENTRY_MODIFIABLE;
			send_search_entry( op, rs );
		}

		entry_clean( &e );
	}

done:
	if( rs->sr_err != LDAP_NO_SUCH_OBJECT ) rs->sr_matched = NULL;
	send_ldap_result( op, rs );

	if( rdn != NULL ) ldap_rdnfree( rdn );

	return( 0 );
}
Beispiel #23
0
/* This is best-effort only. If all entries in the cache are
 * busy, they will all be kept. This is unlikely to happen
 * unless the cache is very much smaller than the working set.
 */
static void
bdb_cache_lru_purge( struct bdb_info *bdb )
{
	DB_LOCK		lock, *lockp;
	EntryInfo *elru, *elnext = NULL;
	int islocked;
	ID eicount, ecount;
	ID count, efree, eifree = 0;
#ifdef LDAP_DEBUG
	int iter;
#endif

	/* Wait for the mutex; we're the only one trying to purge. */
	ldap_pvt_thread_mutex_lock( &bdb->bi_cache.c_lru_mutex );

	if ( bdb->bi_cache.c_cursize > bdb->bi_cache.c_maxsize ) {
		efree = bdb->bi_cache.c_cursize - bdb->bi_cache.c_maxsize;
		efree += bdb->bi_cache.c_minfree;
	} else {
		efree = 0;
	}

	/* maximum number of EntryInfo leaves to cache. In slapcat
	 * we always free all leaf nodes.
	 */

	if ( slapMode & SLAP_TOOL_READONLY ) {
		eifree = bdb->bi_cache.c_leaves;
	} else if ( bdb->bi_cache.c_eimax &&
		bdb->bi_cache.c_leaves > bdb->bi_cache.c_eimax ) {
		eifree = bdb->bi_cache.c_minfree * 10;
		if ( eifree >= bdb->bi_cache.c_leaves )
			eifree /= 2;
	}

	if ( !efree && !eifree ) {
		ldap_pvt_thread_mutex_unlock( &bdb->bi_cache.c_lru_mutex );
		bdb->bi_cache.c_purging = 0;
		return;
	}

	if ( bdb->bi_cache.c_txn ) {
		lockp = &lock;
	} else {
		lockp = NULL;
	}

	count = 0;
	eicount = 0;
	ecount = 0;
#ifdef LDAP_DEBUG
	iter = 0;
#endif

	/* Look for an unused entry to remove */
	for ( elru = bdb->bi_cache.c_lruhead; elru; elru = elnext ) {
		elnext = elru->bei_lrunext;

		if ( bdb_cache_entryinfo_trylock( elru ))
			goto bottom;

		/* This flag implements the clock replacement behavior */
		if ( elru->bei_state & ( CACHE_ENTRY_REFERENCED )) {
			elru->bei_state &= ~CACHE_ENTRY_REFERENCED;
			bdb_cache_entryinfo_unlock( elru );
			goto bottom;
		}

		/* If this node is in the process of linking into the cache,
		 * or this node is being deleted, skip it.
		 */
		if (( elru->bei_state & ( CACHE_ENTRY_NOT_LINKED |
			CACHE_ENTRY_DELETED | CACHE_ENTRY_LOADING |
			CACHE_ENTRY_ONELEVEL )) ||
			elru->bei_finders > 0 ) {
			bdb_cache_entryinfo_unlock( elru );
			goto bottom;
		}

		if ( bdb_cache_entryinfo_trylock( elru->bei_parent )) {
			bdb_cache_entryinfo_unlock( elru );
			goto bottom;
		}

		/* entryinfo is locked */
		islocked = 1;

		/* If we can successfully writelock it, then
		 * the object is idle.
		 */
		if ( bdb_cache_entry_db_lock( bdb,
			bdb->bi_cache.c_txn, elru, 1, 1, lockp ) == 0 ) {

			/* Free entry for this node if it's present */
			if ( elru->bei_e ) {
				ecount++;

				/* the cache may have gone over the limit while we
				 * weren't looking, so double check.
				 */
				if ( !efree && ecount > bdb->bi_cache.c_maxsize )
					efree = bdb->bi_cache.c_minfree;

				if ( count < efree ) {
					elru->bei_e->e_private = NULL;
#ifdef SLAP_ZONE_ALLOC
					bdb_entry_return( bdb, elru->bei_e, elru->bei_zseq );
#else
					bdb_entry_return( elru->bei_e );
#endif
					elru->bei_e = NULL;
					count++;
				} else {
					/* Keep this node cached, skip to next */
					bdb_cache_entry_db_unlock( bdb, lockp );
					goto next;
				}
			}
			bdb_cache_entry_db_unlock( bdb, lockp );

			/* 
			 * If it is a leaf node, and we're over the limit, free it.
			 */
			if ( elru->bei_kids ) {
				/* Drop from list, we ignore it... */
				LRU_DEL( &bdb->bi_cache, elru );
			} else if ( eicount < eifree ) {
				/* Too many leaf nodes, free this one */
				bdb_cache_delete_internal( &bdb->bi_cache, elru, 0 );
				bdb_cache_delete_cleanup( &bdb->bi_cache, elru );
				islocked = 0;
				eicount++;
			}	/* Leave on list until we need to free it */
		}

next:
		if ( islocked ) {
			bdb_cache_entryinfo_unlock( elru );
			bdb_cache_entryinfo_unlock( elru->bei_parent );
		}

		if ( count >= efree && eicount >= eifree )
			break;
bottom:
		if ( elnext == bdb->bi_cache.c_lruhead )
			break;
#ifdef LDAP_DEBUG
		iter++;
#endif
	}

	if ( count || ecount > bdb->bi_cache.c_cursize ) {
		ldap_pvt_thread_mutex_lock( &bdb->bi_cache.c_count_mutex );
		/* HACK: we seem to be losing track, fix up now */
		if ( ecount > bdb->bi_cache.c_cursize )
			bdb->bi_cache.c_cursize = ecount;
		bdb->bi_cache.c_cursize -= count;
		ldap_pvt_thread_mutex_unlock( &bdb->bi_cache.c_count_mutex );
	}
	bdb->bi_cache.c_lruhead = elnext;
	ldap_pvt_thread_mutex_unlock( &bdb->bi_cache.c_lru_mutex );
	bdb->bi_cache.c_purging = 0;
}
Beispiel #24
0
int
ldap_back_search(
		Operation	*op,
		SlapReply	*rs )
{
	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;

	ldapconn_t	*lc = NULL;
	struct timeval	tv;
	time_t		stoptime = (time_t)(-1);
	LDAPMessage	*res,
			*e;
	int		rc = 0,
			msgid; 
	struct berval	match = BER_BVNULL,
			filter = BER_BVNULL;
	int		i, x;
	char		**attrs = NULL;
	int		freetext = 0, filter_undef = 0;
	int		do_retry = 1, dont_retry = 0;
	LDAPControl	**ctrls = NULL;
	char		**references = NULL;

	rs_assert_ready( rs );
	rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */

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

	/*
	 * FIXME: in case of values return filter, we might want
	 * to map attrs and maybe rewrite value
	 */

	if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
		tv.tv_sec = op->ors_tlimit;
		tv.tv_usec = 0;
		stoptime = op->o_time + op->ors_tlimit;

	} else {
		LDAP_BACK_TV_SET( &tv );
	}

	i = 0;
	if ( op->ors_attrs ) {
		for ( ; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ )
			/* just count attrs */ ;
	}

	x = 0;
	if ( op->o_bd->be_extra_anlist ) {
		for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ )
			/* just count attrs */ ;
	}

	if ( i > 0 || x > 0 ) {
		int j = 0;

		attrs = op->o_tmpalloc( ( i + x + 1 )*sizeof( char * ),
			op->o_tmpmemctx );
		if ( attrs == NULL ) {
			rs->sr_err = LDAP_NO_MEMORY;
			rc = -1;
			goto finish;
		}

		if ( i > 0 ) {	
			for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++, j++ ) {
				attrs[ j ] = op->ors_attrs[i].an_name.bv_val;
			}
		}

		if ( x > 0 ) {
			for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++, j++ ) {
				if ( op->o_bd->be_extra_anlist[x].an_desc &&
					ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, op->ors_attrs ) )
				{
					continue;
				}

				attrs[ j ] = op->o_bd->be_extra_anlist[x].an_name.bv_val;
			}
		}

		attrs[ j ] = NULL;
	}

	ctrls = op->o_ctrls;
	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
	if ( rc != LDAP_SUCCESS ) {
		goto finish;
	}

	/* deal with <draft-zeilenga-ldap-t-f> filters */
	filter = op->ors_filterstr;
retry:
	/* this goes after retry because ldap_back_munge_filter()
	 * optionally replaces RFC 4526 T-F filters (&) (|)
	 * if already computed, they will be re-installed
	 * by filter2bv_undef_x() later */
	if ( !LDAP_BACK_T_F( li ) ) {
		ldap_back_munge_filter( op, &filter );
	}

	rs->sr_err = ldap_pvt_search( lc->lc_ld, op->o_req_dn.bv_val,
			op->ors_scope, filter.bv_val,
			attrs, op->ors_attrsonly, ctrls, NULL,
			tv.tv_sec ? &tv : NULL,
			op->ors_slimit, op->ors_deref, &msgid );

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

	if ( rs->sr_err != LDAP_SUCCESS ) {
		switch ( rs->sr_err ) {
		case LDAP_SERVER_DOWN:
			if ( do_retry ) {
				do_retry = 0;
				if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
					goto retry;
				}
			}

			if ( lc == NULL ) {
				/* reset by ldap_back_retry ... */
				rs->sr_err = slap_map_api2result( rs );

			} else {
				rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_DONTSEND );
			}
				
			goto finish;

		case LDAP_FILTER_ERROR:
			/* first try? */
			if ( !filter_undef &&
				strstr( filter.bv_val, "(?" ) &&
				!LDAP_BACK_NOUNDEFFILTER( li ) )
			{
				BER_BVZERO( &filter );
				filter2bv_undef_x( op, op->ors_filter, 1, &filter );
				filter_undef = 1;
				goto retry;
			}

			/* invalid filters return success with no data */
			rs->sr_err = LDAP_SUCCESS;
			rs->sr_text = NULL;
			goto finish;
		
		default:
			rs->sr_err = slap_map_api2result( rs );
			rs->sr_text = NULL;
			goto finish;
		}
	}

	/* if needed, initialize timeout */
	if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
		if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) {
			tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ];
			tv.tv_usec = 0;
		}
	}

	/* We pull apart the ber result, stuff it into a slapd entry, and
	 * let send_search_entry stuff it back into ber format. Slow & ugly,
	 * but this is necessary for version matching, and for ACL processing.
	 */

	for ( rc = -2; rc != -1; rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ONE, &tv, &res ) )
	{
		/* check for abandon */
		if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( lc ) ) {
			if ( rc > 0 ) {
				ldap_msgfree( res );
			}
			(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
			rc = SLAPD_ABANDON;
			goto finish;
		}

		if ( rc == 0 || rc == -2 ) {
			ldap_pvt_thread_yield();

			/* check timeout */
			if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
				if ( rc == 0 ) {
					(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
					rs->sr_text = "Operation timed out";
					rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
						LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
					goto finish;
				}

			} else {
				LDAP_BACK_TV_SET( &tv );
			}

			/* check time limit */
			if ( op->ors_tlimit != SLAP_NO_LIMIT
					&& slap_get_time() > stoptime )
			{
				(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
				rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
				goto finish;
			}
			continue;

		} else {
			/* only touch when activity actually took place... */
			if ( li->li_idle_timeout ) {
				lc->lc_time = op->o_time;
			}

			/* don't retry any more */
			dont_retry = 1;
		}


		if ( rc == LDAP_RES_SEARCH_ENTRY ) {
			Entry		ent = { 0 };
			struct berval	bdn = BER_BVNULL;

			do_retry = 0;

			e = ldap_first_entry( lc->lc_ld, res );
			rc = ldap_build_entry( op, e, &ent, &bdn );
			if ( rc == LDAP_SUCCESS ) {
				ldap_get_entry_controls( lc->lc_ld, res, &rs->sr_ctrls );
				rs->sr_entry = &ent;
				rs->sr_attrs = op->ors_attrs;
				rs->sr_operational_attrs = NULL;
				rs->sr_flags = 0;
				rs->sr_err = LDAP_SUCCESS;
				rc = rs->sr_err = send_search_entry( op, rs );
				if ( rs->sr_ctrls ) {
					ldap_controls_free( rs->sr_ctrls );
					rs->sr_ctrls = NULL;
				}
				rs->sr_entry = NULL;
				rs->sr_flags = 0;
				if ( !BER_BVISNULL( &ent.e_name ) ) {
					assert( ent.e_name.bv_val != bdn.bv_val );
					op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx );
					BER_BVZERO( &ent.e_name );
				}
				if ( !BER_BVISNULL( &ent.e_nname ) ) {
					op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx );
					BER_BVZERO( &ent.e_nname );
				}
				entry_clean( &ent );
			}
			ldap_msgfree( res );
			switch ( rc ) {
			case LDAP_SUCCESS:
			case LDAP_INSUFFICIENT_ACCESS:
				break;

			default:
				if ( rc == LDAP_UNAVAILABLE ) {
					rc = rs->sr_err = LDAP_OTHER;
				} else {
					(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
				}
				goto finish;
			}

		} else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
			if ( LDAP_BACK_NOREFS( li ) ) {
				ldap_msgfree( res );
				continue;
			}

			do_retry = 0;
			rc = ldap_parse_reference( lc->lc_ld, res,
					&references, &rs->sr_ctrls, 1 );

			if ( rc != LDAP_SUCCESS ) {
				continue;
			}

			/* FIXME: there MUST be at least one */
			if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) {
				int		cnt;

				for ( cnt = 0; references[ cnt ]; cnt++ )
					/* NO OP */ ;

				/* FIXME: there MUST be at least one */
				rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
					op->o_tmpmemctx );

				for ( cnt = 0; references[ cnt ]; cnt++ ) {
					ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
				}
				BER_BVZERO( &rs->sr_ref[ cnt ] );

				/* ignore return value by now */
				RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
				rs->sr_entry = NULL;
				( void )send_search_reference( op, rs );

			} else {
				Debug( LDAP_DEBUG_ANY,
					"%s ldap_back_search: "
					"got SEARCH_REFERENCE "
					"with no referrals\n",
					op->o_log_prefix, 0, 0 );
			}

			/* cleanup */
			if ( references ) {
				ber_memvfree( (void **)references );
				op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
				rs->sr_ref = NULL;
				references = NULL;
			}

			if ( rs->sr_ctrls ) {
				ldap_controls_free( rs->sr_ctrls );
				rs->sr_ctrls = NULL;
			}

		} else if ( rc == LDAP_RES_INTERMEDIATE ) {
			/* FIXME: response controls
			 * are passed without checks */
			rc = ldap_parse_intermediate( lc->lc_ld,
				res,
				(char **)&rs->sr_rspoid,
				&rs->sr_rspdata,
				&rs->sr_ctrls,
				0 );
			if ( rc != LDAP_SUCCESS ) {
				continue;
			}

			slap_send_ldap_intermediate( op, rs );

			if ( rs->sr_rspoid != NULL ) {
				ber_memfree( (char *)rs->sr_rspoid );
				rs->sr_rspoid = NULL;
			}

			if ( rs->sr_rspdata != NULL ) {
				ber_bvfree( rs->sr_rspdata );
				rs->sr_rspdata = NULL;
			}

			if ( rs->sr_ctrls != NULL ) {
				ldap_controls_free( rs->sr_ctrls );
				rs->sr_ctrls = NULL;
			}

		} else {
			char		*err = NULL;

			rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
					&match.bv_val, &err,
					&references, &rs->sr_ctrls, 1 );
			if ( rc == LDAP_SUCCESS ) {
				if ( err ) {
					rs->sr_text = err;
					freetext = 1;
				}
			} else {
				rs->sr_err = rc;
			}
			rs->sr_err = slap_map_api2result( rs );

			/* RFC 4511: referrals can only appear
			 * if result code is LDAP_REFERRAL */
			if ( references 
				&& references[ 0 ]
				&& references[ 0 ][ 0 ] )
			{
				if ( rs->sr_err != LDAP_REFERRAL ) {
					Debug( LDAP_DEBUG_ANY,
						"%s ldap_back_search: "
						"got referrals with err=%d\n",
						op->o_log_prefix,
						rs->sr_err, 0 );

				} else {
					int	cnt;

					for ( cnt = 0; references[ cnt ]; cnt++ )
						/* NO OP */ ;
				
					rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
						op->o_tmpmemctx );

					for ( cnt = 0; references[ cnt ]; cnt++ ) {
						/* duplicating ...*/
						ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
					}
					BER_BVZERO( &rs->sr_ref[ cnt ] );
				}

			} else if ( rs->sr_err == LDAP_REFERRAL ) {
				Debug( LDAP_DEBUG_ANY,
					"%s ldap_back_search: "
					"got err=%d with null "
					"or empty referrals\n",
					op->o_log_prefix,
					rs->sr_err, 0 );

				rs->sr_err = LDAP_NO_SUCH_OBJECT;
			}

			if ( match.bv_val != NULL ) {
				match.bv_len = strlen( match.bv_val );
			}

			rc = 0;
			break;
		}

		/* if needed, restore timeout */
		if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
			if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) {
				tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ];
				tv.tv_usec = 0;
			}
		}
	}

 	if ( rc == -1 ) {
		if ( dont_retry == 0 ) {
			if ( do_retry ) {
				do_retry = 0;
				if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
					goto retry;
				}
			}

			rs->sr_err = LDAP_SERVER_DOWN;
			rs->sr_err = slap_map_api2result( rs );
			goto finish;

		} else if ( LDAP_BACK_ONERR_STOP( li ) ) {
			/* if onerr == STOP */
			rs->sr_err = LDAP_SERVER_DOWN;
			rs->sr_err = slap_map_api2result( rs );
			goto finish;
		}
	}

	/*
	 * Rewrite the matched portion of the search base, if required
	 */
	if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) {
		struct berval	pmatch;

		if ( dnPretty( NULL, &match, &pmatch, op->o_tmpmemctx ) != LDAP_SUCCESS ) {
			pmatch.bv_val = match.bv_val;
			match.bv_val = NULL;
		}
		rs->sr_matched = pmatch.bv_val;
		rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
	}

finish:;
	if ( !BER_BVISNULL( &match ) ) {
		ber_memfree( match.bv_val );
	}

	if ( rs->sr_v2ref ) {
		rs->sr_err = LDAP_REFERRAL;
	}

	if ( LDAP_BACK_QUARANTINE( li ) ) {
		ldap_back_quarantine( op, rs );
	}

	if ( filter.bv_val != op->ors_filterstr.bv_val ) {
		op->o_tmpfree( filter.bv_val, op->o_tmpmemctx );
	}

#if 0
	/* let send_ldap_result play cleanup handlers (ITS#4645) */
	if ( rc != SLAPD_ABANDON )
#endif
	{
		send_ldap_result( op, rs );
	}

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

	if ( rs->sr_ctrls ) {
		ldap_controls_free( rs->sr_ctrls );
		rs->sr_ctrls = NULL;
	}

	if ( rs->sr_text ) {
		if ( freetext ) {
			ber_memfree( (char *)rs->sr_text );
		}
		rs->sr_text = NULL;
	}

	if ( rs->sr_ref ) {
		op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
		rs->sr_ref = NULL;
	}

	if ( references ) {
		ber_memvfree( (void **)references );
	}

	if ( attrs ) {
		op->o_tmpfree( attrs, op->o_tmpmemctx );
	}

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

	if ( rs->sr_err == LDAP_UNAVAILABLE &&
		/* if we originally bound and wanted rebind-as-user, must drop
		 * the connection now because we just discarded the credentials.
		 * ITS#7464, #8142
		 */
		LDAP_BACK_SAVECRED( li ) && SLAP_IS_AUTHZ_BACKEND( op ) )
		rs->sr_err = SLAPD_DISCONNECT;
	return rs->sr_err;
}
Beispiel #25
0
int
bdb_cache_find_id(
	Operation *op,
	DB_TXN	*tid,
	ID				id,
	EntryInfo	**eip,
	int		flag,
	DB_LOCK		*lock )
{
	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
	Entry	*ep = NULL;
	int	rc = 0, load = 0;
	EntryInfo ei = { 0 };

	ei.bei_id = id;

#ifdef SLAP_ZONE_ALLOC
	slap_zh_rlock(bdb->bi_cache.c_zctx);
#endif
	/* If we weren't given any info, see if we have it already cached */
	if ( !*eip ) {
again:	ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock );
		*eip = (EntryInfo *) avl_find( bdb->bi_cache.c_idtree,
			(caddr_t) &ei, bdb_id_cmp );
		if ( *eip ) {
			/* If the lock attempt fails, the info is in use */
			if ( bdb_cache_entryinfo_trylock( *eip )) {
				int del = (*eip)->bei_state & CACHE_ENTRY_DELETED;
				ldap_pvt_thread_rdwr_runlock( &bdb->bi_cache.c_rwlock );
				/* If this node is being deleted, treat
				 * as if the delete has already finished
				 */
				if ( del ) {
					return DB_NOTFOUND;
				}
				/* otherwise, wait for the info to free up */
				ldap_pvt_thread_yield();
				goto again;
			}
			/* If this info isn't hooked up to its parent yet,
			 * unlock and wait for it to be fully initialized
			 */
			if ( (*eip)->bei_state & CACHE_ENTRY_NOT_LINKED ) {
				bdb_cache_entryinfo_unlock( *eip );
				ldap_pvt_thread_rdwr_runlock( &bdb->bi_cache.c_rwlock );
				ldap_pvt_thread_yield();
				goto again;
			}
			flag |= ID_LOCKED;
		}
		ldap_pvt_thread_rdwr_runlock( &bdb->bi_cache.c_rwlock );
	}

	/* See if the ID exists in the database; add it to the cache if so */
	if ( !*eip ) {
#ifndef BDB_HIER
		rc = bdb_id2entry( op->o_bd, tid, id, &ep );
		if ( rc == 0 ) {
			rc = bdb_cache_find_ndn( op, tid,
				&ep->e_nname, eip );
			if ( *eip ) flag |= ID_LOCKED;
			if ( rc ) {
				ep->e_private = NULL;
#ifdef SLAP_ZONE_ALLOC
				bdb_entry_return( bdb, ep, (*eip)->bei_zseq );
#else
				bdb_entry_return( ep );
#endif
				ep = NULL;
			}
		}
#else
		rc = hdb_cache_find_parent(op, tid, id, eip );
		if ( rc == 0 ) flag |= ID_LOCKED;
#endif
	}

	/* Ok, we found the info, do we have the entry? */
	if ( rc == 0 ) {
		if ( !( flag & ID_LOCKED )) {
			bdb_cache_entryinfo_lock( *eip );
			flag |= ID_LOCKED;
		}

		if ( (*eip)->bei_state & CACHE_ENTRY_DELETED ) {
			rc = DB_NOTFOUND;
		} else {
			(*eip)->bei_finders++;
			(*eip)->bei_state |= CACHE_ENTRY_REFERENCED;
			if ( flag & ID_NOENTRY ) {
				bdb_cache_entryinfo_unlock( *eip );
				return 0;
			}
			/* Make sure only one thread tries to load the entry */
load1:
#ifdef SLAP_ZONE_ALLOC
			if ((*eip)->bei_e && !slap_zn_validate(
					bdb->bi_cache.c_zctx, (*eip)->bei_e, (*eip)->bei_zseq)) {
				(*eip)->bei_e = NULL;
				(*eip)->bei_zseq = 0;
			}
#endif
			if ( !(*eip)->bei_e && !((*eip)->bei_state & CACHE_ENTRY_LOADING)) {
				load = 1;
				(*eip)->bei_state |= CACHE_ENTRY_LOADING;
				flag |= ID_CHKPURGE;
			}

			if ( !load ) {
				/* Clear the uncached state if we are not
				 * loading it, i.e it is already cached or
				 * another thread is currently loading it.
				 */
				if ( (*eip)->bei_state & CACHE_ENTRY_NOT_CACHED ) {
					(*eip)->bei_state ^= CACHE_ENTRY_NOT_CACHED;
					flag |= ID_CHKPURGE;
				}
			}

			if ( flag & ID_LOCKED ) {
				bdb_cache_entryinfo_unlock( *eip );
				flag ^= ID_LOCKED;
			}
			rc = bdb_cache_entry_db_lock( bdb, tid, *eip, load, 0, lock );
			if ( (*eip)->bei_state & CACHE_ENTRY_DELETED ) {
				rc = DB_NOTFOUND;
				bdb_cache_entry_db_unlock( bdb, lock );
				bdb_cache_entryinfo_lock( *eip );
				(*eip)->bei_finders--;
				bdb_cache_entryinfo_unlock( *eip );
			} else if ( rc == 0 ) {
				if ( load ) {
					if ( !ep) {
						rc = bdb_id2entry( op->o_bd, tid, id, &ep );
					}
					if ( rc == 0 ) {
						ep->e_private = *eip;
#ifdef BDB_HIER
						while ( (*eip)->bei_state & CACHE_ENTRY_NOT_LINKED )
							ldap_pvt_thread_yield();
						bdb_fix_dn( ep, 0 );
#endif
						bdb_cache_entryinfo_lock( *eip );

						(*eip)->bei_e = ep;
#ifdef SLAP_ZONE_ALLOC
						(*eip)->bei_zseq = *((ber_len_t *)ep - 2);
#endif
						ep = NULL;
						if ( flag & ID_NOCACHE ) {
							/* Set the cached state only if no other thread
							 * found the info while we were loading the entry.
							 */
							if ( (*eip)->bei_finders == 1 ) {
								(*eip)->bei_state |= CACHE_ENTRY_NOT_CACHED;
								flag ^= ID_CHKPURGE;
							}
						}
						bdb_cache_entryinfo_unlock( *eip );
						bdb_cache_lru_link( bdb, *eip );
					}
					if ( rc == 0 ) {
						/* If we succeeded, downgrade back to a readlock. */
						rc = bdb_cache_entry_db_relock( bdb, tid,
							*eip, 0, 0, lock );
					} else {
						/* Otherwise, release the lock. */
						bdb_cache_entry_db_unlock( bdb, lock );
					}
				} else if ( !(*eip)->bei_e ) {
					/* Some other thread is trying to load the entry,
					 * wait for it to finish.
					 */
					bdb_cache_entry_db_unlock( bdb, lock );
					bdb_cache_entryinfo_lock( *eip );
					flag |= ID_LOCKED;
					goto load1;
#ifdef BDB_HIER
				} else {
					/* Check for subtree renames
					 */
					rc = bdb_fix_dn( (*eip)->bei_e, 1 );
					if ( rc ) {
						bdb_cache_entry_db_relock( bdb,
							tid, *eip, 1, 0, lock );
						/* check again in case other modifier did it already */
						if ( bdb_fix_dn( (*eip)->bei_e, 1 ) )
							rc = bdb_fix_dn( (*eip)->bei_e, 2 );
						bdb_cache_entry_db_relock( bdb,
							tid, *eip, 0, 0, lock );
					}
#endif
				}
				bdb_cache_entryinfo_lock( *eip );
				(*eip)->bei_finders--;
				if ( load )
					(*eip)->bei_state ^= CACHE_ENTRY_LOADING;
				bdb_cache_entryinfo_unlock( *eip );
			}
		}
	}
	if ( flag & ID_LOCKED ) {
		bdb_cache_entryinfo_unlock( *eip );
	}
	if ( ep ) {
		ep->e_private = NULL;
#ifdef SLAP_ZONE_ALLOC
		bdb_entry_return( bdb, ep, (*eip)->bei_zseq );
#else
		bdb_entry_return( ep );
#endif
	}
	if ( rc == 0 ) {
		int purge = 0;

		if (( flag & ID_CHKPURGE ) || bdb->bi_cache.c_eimax ) {
			ldap_pvt_thread_mutex_lock( &bdb->bi_cache.c_count_mutex );
			if ( flag & ID_CHKPURGE ) {
				bdb->bi_cache.c_cursize++;
				if ( !bdb->bi_cache.c_purging && bdb->bi_cache.c_cursize > bdb->bi_cache.c_maxsize ) {
					purge = 1;
					bdb->bi_cache.c_purging = 1;
				}
			} else if ( !bdb->bi_cache.c_purging && bdb->bi_cache.c_eimax && bdb->bi_cache.c_leaves > bdb->bi_cache.c_eimax ) {
				purge = 1;
				bdb->bi_cache.c_purging = 1;
			}
			ldap_pvt_thread_mutex_unlock( &bdb->bi_cache.c_count_mutex );
		}
		if ( purge )
			bdb_cache_lru_purge( bdb );
	}

#ifdef SLAP_ZONE_ALLOC
	if (rc == 0 && (*eip)->bei_e) {
		slap_zn_rlock(bdb->bi_cache.c_zctx, (*eip)->bei_e);
	}
	slap_zh_runlock(bdb->bi_cache.c_zctx);
#endif
	return rc;
}
Beispiel #26
0
/*
 * cache_add_entry_rw - create and lock an entry in the cache
 * returns:	0	entry has been created and locked
 *		1	entry already existed
 *		-1	something bad happened
 *             other    Berkeley DB locking error code
 */
int
bdb_cache_add_entry_rw(
    DB_ENV	*env,
    Cache	*cache,
    Entry	*e,
    int		rw,
    u_int32_t	locker,
    DB_LOCK	*lock
)
{
	int	i, rc;
	Entry	*ee;

#ifdef NEW_LOGGING
	LDAP_LOG( CACHE, ENTRY, 
		"bdb_cache_add_entry_rw: add (%s):%s to cache\n",
		e->e_dn, rw ? "w" : "r", 0 );
#endif
	/* set cache write lock */
	ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );

	assert( e->e_private == NULL );

	if( bdb_cache_entry_private_init(e) != 0 ) {
		/* free cache write lock */
		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );

#ifdef NEW_LOGGING
		LDAP_LOG( CACHE, ERR, 
			"bdb_cache_add_entry_rw: add (%s):%ld private init failed!\n",
			e->e_dn, e->e_id, 0 );
#else
		Debug( LDAP_DEBUG_ANY,
			"====> bdb_cache_add_entry( %ld ): \"%s\": private init failed!\n",
		    e->e_id, e->e_dn, 0 );
#endif


		return( -1 );
	}

	if ( avl_insert( &cache->c_dntree, (caddr_t) e,
	                 entry_dn_cmp, avl_dup_error ) != 0 )
	{
		/* free cache write lock */
		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );

#ifdef NEW_LOGGING
		LDAP_LOG( CACHE, DETAIL1, 
			"bdb_cache_add_entry: (%s):%ld already in cache.\n",
			e->e_dn, e->e_id, 0 );
#else
		Debug( LDAP_DEBUG_TRACE,
			"====> bdb_cache_add_entry( %ld ): \"%s\": already in dn cache\n",
		    e->e_id, e->e_dn, 0 );
#endif

		bdb_cache_entry_private_destroy(e);

		return( 1 );
	}

	/* id tree */
	if ( avl_insert( &cache->c_idtree, (caddr_t) e,
	                 entry_id_cmp, avl_dup_error ) != 0 )
	{
#ifdef NEW_LOGGING
		LDAP_LOG( CACHE, DETAIL1, 
			"bdb_cache_add_entry: (%s):%ls already in cache.\n",
			e->e_dn, e->e_id, 0 );
#else
		Debug( LDAP_DEBUG_ANY,
			"====> bdb_cache_add_entry( %ld ): \"%s\": already in id cache\n",
		    e->e_id, e->e_dn, 0 );
#endif

		/* delete from dn tree inserted above */
		if ( avl_delete( &cache->c_dntree, (caddr_t) e,
		                 entry_dn_cmp ) == NULL )
		{
#ifdef NEW_LOGGING
			LDAP_LOG( CACHE, INFO, 
				"bdb_cache_add_entry: can't delete (%s) from cache.\n", 
				e->e_dn, 0, 0 );
#else
			Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n",
			    0, 0, 0 );
#endif
		}

		bdb_cache_entry_private_destroy(e);

		/* free cache write lock */
		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
		return( -1 );
	}

	rc = bdb_cache_entry_db_lock( env, locker, e, rw, 0, lock );
	switch ( rc ) {
	case 0 :
		break;
	case DB_LOCK_DEADLOCK :
	case DB_LOCK_NOTGRANTED :
		/* undo avl changes immediately */
		if ( avl_delete( &cache->c_idtree, (caddr_t) e,
		                 entry_id_cmp ) == NULL ) {
#ifdef NEW_LOGGING
			LDAP_LOG( CACHE, INFO, 
				"bdb_cache_add_entry: can't delete (%s) from cache.\n", 
				e->e_dn, 0, 0 );
#else
			Debug( LDAP_DEBUG_ANY, "====> can't delete from id cache\n", 0, 0, 0 );
#endif
		}
		if ( avl_delete( &cache->c_dntree, (caddr_t) e,
		                 entry_dn_cmp ) == NULL ) {
#ifdef NEW_LOGGING
			LDAP_LOG( CACHE, INFO, 
				"bdb_cache_add_entry: can't delete (%s) from cache.\n", 
				e->e_dn, 0, 0 );
#else
			Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 );
#endif
		}
		/* fall through */
	default :
		bdb_cache_entry_private_destroy(e);
		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
		return rc;
	}

	/* put the entry into 'CREATING' state */
	/* will be marked after when entry is returned */
	BEI(e)->bei_state = CACHE_ENTRY_CREATING;
	BEI(e)->bei_refcnt = 1;

	/* set lru mutex */
	ldap_pvt_thread_mutex_lock( &cache->lru_mutex );
	/* lru */
	LRU_ADD( cache, e );
	if ( ++cache->c_cursize > cache->c_maxsize ) {
		/*
		 * find the lru entry not currently in use and delete it.
		 * in case a lot of entries are in use, only look at the
		 * first 10 on the tail of the list.
		 */
		i = 0;
		while ( cache->c_lrutail != NULL &&
			BEI(cache->c_lrutail)->bei_refcnt != 0 &&
			i < 10 )
		{
			/* move this in-use entry to the front of the q */
			ee = cache->c_lrutail;
			LRU_DELETE( cache, ee );
			LRU_ADD( cache, ee );
			i++;
		}

		/*
		 * found at least one to delete - try to get back under
		 * the max cache size.
		 */
		while ( cache->c_lrutail != NULL &&
			BEI(cache->c_lrutail)->bei_refcnt == 0 &&
			cache->c_cursize > cache->c_maxsize )
		{
			e = cache->c_lrutail;

			/* delete from cache and lru q */
			/* XXX do we need rc ? */
			rc = bdb_cache_delete_entry_internal( cache, e );
			bdb_cache_entry_private_destroy( e );
			bdb_entry_return( e );
		}
	}

	/* free lru mutex */
	ldap_pvt_thread_mutex_unlock( &cache->lru_mutex );
	/* free cache write lock */
	ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );
	return( 0 );
}
Beispiel #27
0
static int
chk_radius(
	const struct berval	*sc,
	const struct berval	*passwd,
	const struct berval	*cred,
	const char		**text )
{
	unsigned int		i;
	int			rc = LUTIL_PASSWD_ERR;

	struct rad_handle	*h = NULL;

	for ( i = 0; i < cred->bv_len; i++ ) {
		if ( cred->bv_val[ i ] == '\0' ) {
			return LUTIL_PASSWD_ERR;	/* NUL character in cred */
		}
	}

	if ( cred->bv_val[ i ] != '\0' ) {
		return LUTIL_PASSWD_ERR;	/* cred must behave like a string */
	}

	for ( i = 0; i < passwd->bv_len; i++ ) {
		if ( passwd->bv_val[ i ] == '\0' ) {
			return LUTIL_PASSWD_ERR;	/* NUL character in password */
		}
	}

	if ( passwd->bv_val[ i ] != '\0' ) {
		return LUTIL_PASSWD_ERR;	/* passwd must behave like a string */
	}

	ldap_pvt_thread_mutex_lock( &libradius_mutex );

	h = rad_auth_open();
	if ( h == NULL ) {
		ldap_pvt_thread_mutex_unlock( &libradius_mutex );
		return LUTIL_PASSWD_ERR;
	}

	if ( rad_config( h, config_filename ) != 0 ) {
		goto done;
	}

	if ( rad_create_request( h, RAD_ACCESS_REQUEST ) ) {
		goto done;
	}

	if ( rad_put_string( h, RAD_USER_NAME, passwd->bv_val ) != 0 ) {
		goto done;
	}

	if ( rad_put_string( h, RAD_USER_PASSWORD, cred->bv_val ) != 0 ) {
		goto done;
	}

	if ( rad_put_string( h, RAD_NAS_IDENTIFIER, global_host ) != 0 ) {
		goto done;
	}

	switch ( rad_send_request( h ) ) {
	case RAD_ACCESS_ACCEPT:
		rc = LUTIL_PASSWD_OK;
		break;

	case RAD_ACCESS_REJECT:
		rc = LUTIL_PASSWD_ERR;
		break;

	case RAD_ACCESS_CHALLENGE:
		rc = LUTIL_PASSWD_ERR;
		break;

	case -1:
		/* no valid response is received */
		break;
	}

done:;
	rad_close( h );

	ldap_pvt_thread_mutex_unlock( &libradius_mutex );
	return rc;
}