Exemplo n.º 1
0
Operation *
slap_op_alloc(
    BerElement		*ber,
    ber_int_t	msgid,
    ber_tag_t	tag,
    ber_int_t	id
)
{
	Operation	*op;

	ldap_pvt_thread_mutex_lock( &slap_op_mutex );
	if (op = LDAP_STAILQ_FIRST( &slap_free_ops )) {
		LDAP_STAILQ_REMOVE_HEAD( &slap_free_ops, o_next );
	}
	ldap_pvt_thread_mutex_unlock( &slap_op_mutex );

	if (!op)
		op = (Operation *) ch_calloc( 1, sizeof(Operation) );

	op->o_ber = ber;
	op->o_msgid = msgid;
	op->o_tag = tag;

	op->o_time = slap_get_time();
	op->o_opid = id;
#ifdef LDAP_CONNECTIONLESS
	op->o_res_ber = NULL;
#endif

#if defined( LDAP_SLAPI )
	op->o_pb = slapi_pblock_new();
#endif /* defined( LDAP_SLAPI ) */

	return( op );
}
Exemplo n.º 2
0
idattr_id_to_dn (
    Operation	*op,
    AttributeDescription *searchAttr,
    struct berval* searchID,
    struct berval* resultDN)
{
    Operation nop = *op;
    char			filter_str[128];
    AttributeAssertion	ava = { NULL, BER_BVNULL };
    Filter			filter = {LDAP_FILTER_EQUALITY};
    SlapReply 		sreply = {REP_RESULT};
    slap_callback cb = { NULL, idattr_id_to_dn_cb, NULL, NULL };
    BackendDB	*target_bd = NULL;
    idattr_id_to_dn_t dn_result =  {0};
    int rc = 0;

    target_bd = select_backend(&op->o_req_ndn, 0);

    if (!target_bd || !target_bd->be_search)
        return LDAP_NOT_SUPPORTED;

    sreply.sr_entry = NULL;
    sreply.sr_nentries = 0;
    nop.ors_filterstr.bv_len = snprintf(filter_str, sizeof(filter_str),
                                        "(%s=%s)",searchAttr->ad_cname.bv_val, searchID->bv_val);
    filter.f_ava = &ava;
    filter.f_av_desc = searchAttr;
    filter.f_av_value = *searchID;

    nop.o_tag = LDAP_REQ_SEARCH;
    nop.o_protocol = LDAP_VERSION3;
    nop.o_callback = &cb;
    nop.o_time = slap_get_time();
    nop.o_do_not_cache = 0;
    nop.o_dn = target_bd->be_rootdn;
    nop.o_ndn = target_bd->be_rootndn;
    nop.o_bd = target_bd;

    nop.o_req_dn = target_bd->be_suffix[0];
    nop.o_req_ndn = target_bd->be_nsuffix[0];
    nop.ors_scope = LDAP_SCOPE_SUBTREE;
    nop.ors_deref = LDAP_DEREF_NEVER;
    nop.ors_slimit = SLAP_NO_LIMIT;
    nop.ors_tlimit = SLAP_NO_LIMIT;
    nop.ors_filter = &filter;
    nop.ors_filterstr.bv_val = filter_str;
    nop.ors_filterstr.bv_len = strlen(filter_str);
    nop.ors_attrs = NULL;
    nop.ors_attrsonly = 0;

    cb.sc_private = &dn_result;

    rc = nop.o_bd->be_search( &nop, &sreply );
    if (dn_result.found) {
        ber_dupbv(resultDN, &dn_result.target_dn );
    }

    return 0;
}
Exemplo n.º 3
0
/*
 * meta_dncache_update_entry
 *
 * updates target and lastupdated of a struct metadncacheentry if exists,
 * otherwise it gets created; returns -1 in case of error
 */
int
meta_dncache_update_entry(
	metadncache_t	*cache,
	struct berval	*ndn,
	int 		target )
{
	metadncacheentry_t	*entry,
				tmp_entry;
	time_t			curr_time = 0L;
	int			err = 0;

	assert( cache != NULL );
	assert( ndn != NULL );

	/*
	 * if cache->ttl < 0, cache never expires;
	 * if cache->ttl = 0 no cache is used; shouldn't get here
	 * else, cache is used with ttl
	 */
	if ( cache->ttl > 0 ) {
		curr_time = slap_get_time();
	}

	tmp_entry.dn = *ndn;

	ldap_pvt_thread_mutex_lock( &cache->mutex );
	entry = ( metadncacheentry_t * )avl_find( cache->tree,
			( caddr_t )&tmp_entry, meta_dncache_cmp );

	if ( entry != NULL ) {
		entry->target = target;
		entry->lastupdated = curr_time;

	} else {
		entry = ch_malloc( sizeof( metadncacheentry_t ) + ndn->bv_len + 1 );
		if ( entry == NULL ) {
			err = -1;
			goto error_return;
		}

		entry->dn.bv_len = ndn->bv_len;
		entry->dn.bv_val = (char *)&entry[ 1 ];
		AC_MEMCPY( entry->dn.bv_val, ndn->bv_val, ndn->bv_len );
		entry->dn.bv_val[ ndn->bv_len ] = '\0';

		entry->target = target;
		entry->lastupdated = curr_time;

		err = avl_insert( &cache->tree, ( caddr_t )entry,
				meta_dncache_cmp, meta_dncache_dup );
	}

error_return:;
	ldap_pvt_thread_mutex_unlock( &cache->mutex );

	return err;
}
Exemplo n.º 4
0
static Connection* connection_get( ber_socket_t s )
{
	Connection *c;

	Debug( LDAP_DEBUG_ARGS,
		"connection_get(%ld)\n",
		(long) s, 0, 0 );

	assert( connections != NULL );

	if(s == AC_SOCKET_INVALID) return NULL;

	assert( s < dtblsize );
	c = &connections[s];

	if( c != NULL ) {
		ldap_pvt_thread_mutex_lock( &c->c_mutex );

		assert( c->c_struct_state != SLAP_C_UNINITIALIZED );

		if( c->c_struct_state != SLAP_C_USED ) {
			/* connection must have been closed due to resched */

			assert( c->c_conn_state == SLAP_C_INVALID );
			assert( c->c_sd == AC_SOCKET_INVALID );

			Debug( LDAP_DEBUG_TRACE,
				"connection_get(%d): connection not used\n",
				s, 0, 0 );

			ldap_pvt_thread_mutex_unlock( &c->c_mutex );
			return NULL;
		}

		Debug( LDAP_DEBUG_TRACE,
			"connection_get(%d): got connid=%lu\n",
			s, c->c_connid, 0 );

		c->c_n_get++;

		assert( c->c_struct_state == SLAP_C_USED );
		assert( c->c_conn_state != SLAP_C_INVALID );
		assert( c->c_sd != AC_SOCKET_INVALID );

#ifndef SLAPD_MONITOR
		if ( global_idletimeout > 0 )
#endif /* ! SLAPD_MONITOR */
		{
			c->c_activitytime = slap_get_time();
		}
	}

	return c;
}
Exemplo n.º 5
0
void
slap_op_time(time_t *t, int *nop)
{
    ldap_pvt_thread_mutex_lock( &slap_op_mutex );
    *t = slap_get_time();
    if ( *t == last_time ) {
        *nop = ++last_incr;
    } else {
        last_time = *t;
        last_incr = 0;
        *nop = 0;
    }
    ldap_pvt_thread_mutex_unlock( &slap_op_mutex );
}
Exemplo n.º 6
0
idattr_is_member (
    Operation	*op,
    struct berval* groupDN,
    AttributeDescription *searchAttr,
    struct berval* searchID,
    u_int32_t * result)
{
    Operation nop = *op;
    AttributeAssertion	ava = { NULL, BER_BVNULL };
    SlapReply 		sreply = {REP_RESULT};
    slap_callback cb = { NULL, idattr_is_member_cb, NULL, NULL };
    BackendDB	*target_bd = NULL;
    idattr_ismember_t ismember =  {0};
    int rc = 0;

    target_bd = select_backend(&op->o_req_ndn, 0);

    if (!target_bd || !target_bd->be_compare)
        return LDAP_NOT_SUPPORTED;

    sreply.sr_entry = NULL;
    sreply.sr_nentries = 0;

    nop.orc_ava = &ava;
    nop.orc_ava->aa_desc = searchAttr;
    nop.orc_ava->aa_value = *searchID;

    nop.o_tag = LDAP_REQ_COMPARE;
    nop.o_protocol = LDAP_VERSION3;
    nop.o_callback = &cb;
    nop.o_time = slap_get_time();
    nop.o_do_not_cache = 0;
    nop.o_dn = target_bd->be_rootdn;
    nop.o_ndn = target_bd->be_rootndn;
    nop.o_bd = target_bd;

    nop.o_req_dn = *groupDN;
    nop.o_req_ndn = *groupDN;
    cb.sc_private = &ismember;

    rc = nop.o_bd->be_compare( &nop, &sreply );
    Debug(LDAP_DEBUG_ACL, "idattr_is_member be_compare[%d] ismember[%d]\n", rc, ismember.found, 0);
    if (ismember.found)
        *result = 1;
    else
        *result = 0;
    return 0;
}
Exemplo n.º 7
0
/*
 * meta_dncache_get_target
 *
 * returns the target a dn belongs to, or -1 in case the dn is not
 * in the cache
 */
int
meta_dncache_get_target(
	metadncache_t	*cache,
	struct berval	*ndn )
{
	metadncacheentry_t	tmp_entry,
				*entry;
	int			target = META_TARGET_NONE;

	assert( cache != NULL );
	assert( ndn != NULL );

	tmp_entry.dn = *ndn;
	ldap_pvt_thread_mutex_lock( &cache->mutex );
	entry = ( metadncacheentry_t * )avl_find( cache->tree,
			( caddr_t )&tmp_entry, meta_dncache_cmp );

	if ( entry != NULL ) {
		
		/*
		 * if cache->ttl < 0, cache never expires;
		 * if cache->ttl = 0 no cache is used; shouldn't get here
		 * else, cache is used with ttl
		 */
		if ( cache->ttl < 0 ) { 
			target = entry->target;

		} else {
			if ( entry->lastupdated+cache->ttl > slap_get_time() ) {
				target = entry->target;
			}
		}
	}
	ldap_pvt_thread_mutex_unlock( &cache->mutex );

	return target;
}
Exemplo n.º 8
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 );
}
Exemplo n.º 9
0
static int
monitor_subsys_time_update(
	Operation		*op,
	SlapReply		*rs,
	Entry                   *e )
{
	monitor_info_t		*mi = ( monitor_info_t * )op->o_bd->be_private;
	static struct berval	bv_current = BER_BVC( "cn=current" ),
				bv_uptime = BER_BVC( "cn=uptime" );
	struct berval		rdn;

	assert( mi != NULL );
	assert( e != NULL );

	dnRdn( &e->e_nname, &rdn );
	
	if ( dn_match( &rdn, &bv_current ) ) {
		struct tm	tm;
		char		tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
		Attribute	*a;
		ber_len_t	len;
		time_t		currtime;

		currtime = slap_get_time();

		ldap_pvt_gmtime( &currtime, &tm );
		lutil_gentime( tmbuf, sizeof( tmbuf ), &tm );

		len = strlen( tmbuf );

		a = attr_find( e->e_attrs, mi->mi_ad_monitorTimestamp );
		if ( a == NULL ) {
			return rs->sr_err = LDAP_OTHER;
		}

		assert( len == a->a_vals[ 0 ].bv_len );
		AC_MEMCPY( a->a_vals[ 0 ].bv_val, tmbuf, len );

		/* FIXME: touch modifyTimestamp? */

	} else if ( dn_match( &rdn, &bv_uptime ) ) {
		Attribute	*a;
		double		diff;
		char		buf[ BACKMONITOR_BUFSIZE ];
		struct berval	bv;

		a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo );
		if ( a == NULL ) {
			return rs->sr_err = LDAP_OTHER;
		}

		diff = difftime( slap_get_time(), starttime );
		bv.bv_len = snprintf( buf, sizeof( buf ), "%lu",
			(unsigned long) diff );
		bv.bv_val = buf;

		ber_bvreplace( &a->a_vals[ 0 ], &bv );
		if ( a->a_nvals != a->a_vals ) {
			ber_bvreplace( &a->a_nvals[ 0 ], &bv );
		}

		/* FIXME: touch modifyTimestamp? */
	}

	return SLAP_CB_CONTINUE;
}
Exemplo n.º 10
0
static int
lastbind_bind_response( Operation *op, SlapReply *rs )
{
	Modifications *mod = NULL;
	BackendInfo *bi = op->o_bd->bd_info;
	Entry *e;
	int rc;

	/* we're only interested if the bind was successful */
	if ( rs->sr_err != LDAP_SUCCESS )
		return SLAP_CB_CONTINUE;

	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
	op->o_bd->bd_info = bi;

	if ( rc != LDAP_SUCCESS ) {
		return SLAP_CB_CONTINUE;
	}

	{
		lastbind_info *lbi = (lastbind_info *) op->o_callback->sc_private;

		time_t now, bindtime = (time_t)-1;
		Attribute *a;
		Modifications *m;
		char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
		struct berval timestamp;

		/* get the current time */
		now = slap_get_time();

		/* get authTimestamp attribute, if it exists */
		if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL) {
			bindtime = parse_time( a->a_nvals[0].bv_val );

			if (bindtime != (time_t)-1) {
				/* if the recorded bind time is within our precision, we're done
				 * it doesn't need to be updated (save a write for nothing) */
				if ((now - bindtime) < lbi->timestamp_precision) {
					goto done;
				}
			}
		}

		/* update the authTimestamp in the user's entry with the current time */
		timestamp.bv_val = nowstr;
		timestamp.bv_len = sizeof(nowstr);
		slap_timestamp( &now, &timestamp );

		m = ch_calloc( sizeof(Modifications), 1 );
		m->sml_op = LDAP_MOD_REPLACE;
		m->sml_flags = 0;
		m->sml_type = ad_authTimestamp->ad_cname;
		m->sml_desc = ad_authTimestamp;
		m->sml_numvals = 1;
		m->sml_values = ch_calloc( sizeof(struct berval), 2 );
		m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );

		ber_dupbv( &m->sml_values[0], &timestamp );
		ber_dupbv( &m->sml_nvalues[0], &timestamp );
		m->sml_next = mod;
		mod = m;
	}

done:
	be_entry_release_r( op, e );

	/* perform the update, if necessary */
	if ( mod ) {
		Operation op2 = *op;
		SlapReply r2 = { REP_RESULT };
		slap_callback cb = { NULL, slap_null_cb, NULL, NULL };

		/* This is a DSA-specific opattr, it never gets replicated. */
		op2.o_tag = LDAP_REQ_MODIFY;
		op2.o_callback = &cb;
		op2.orm_modlist = mod;
		op2.o_dn = op->o_bd->be_rootdn;
		op2.o_ndn = op->o_bd->be_rootndn;
		op2.o_dont_replicate = 1;
		rc = op->o_bd->be_modify( &op2, &r2 );
		slap_mods_free( mod, 1 );
	}

	op->o_bd->bd_info = bi;
	return SLAP_CB_CONTINUE;
}
Exemplo n.º 11
0
/* Called for all modify and modrdn ops. If the current op was replicated
 * from elsewhere, all of the attrs should already be present.
 */
void slap_mods_opattrs(
	Operation *op,
	Modifications **modsp,
	int manage_ctxcsn )
{
	struct berval name, timestamp, csn = BER_BVNULL;
	struct berval nname;
	char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
	char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
	Modifications *mod, **modtail, *modlast;
	int gotcsn = 0, gotmname = 0, gotmtime = 0;

	if ( SLAP_LASTMOD( op->o_bd ) && !op->orm_no_opattrs ) {
		char *ptr;
		timestamp.bv_val = timebuf;
		for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) {
			if ( (*modtail)->sml_op != LDAP_MOD_ADD &&
				(*modtail)->sml_op != SLAP_MOD_SOFTADD &&
				(*modtail)->sml_op != SLAP_MOD_ADD_IF_NOT_PRESENT &&
				(*modtail)->sml_op != LDAP_MOD_REPLACE )
			{
				continue;
			}

			if ( (*modtail)->sml_desc == slap_schema.si_ad_entryCSN )
			{
				csn = (*modtail)->sml_values[0];
				gotcsn = 1;

			} else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifiersName )
			{
				gotmname = 1;

			} else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifyTimestamp )
			{
				gotmtime = 1;
			}
		}

		if ( BER_BVISEMPTY( &op->o_csn )) {
			if ( !gotcsn ) {
				csn.bv_val = csnbuf;
				csn.bv_len = sizeof( csnbuf );
				slap_get_csn( op, &csn, manage_ctxcsn );

			} else {
				if ( manage_ctxcsn ) {
					slap_queue_csn( op, &csn );
				}
			}

		} else {
			csn = op->o_csn;
		}

		ptr = ber_bvchr( &csn, '#' );
		if ( ptr ) {
			timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ");
			AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len );
			timebuf[timestamp.bv_len-1] = 'Z';
			timebuf[timestamp.bv_len] = '\0';

		} else {
			time_t now = slap_get_time();

			timestamp.bv_len = sizeof(timebuf);

			slap_timestamp( &now, &timestamp );
		}

		if ( BER_BVISEMPTY( &op->o_dn ) ) {
			BER_BVSTR( &name, SLAPD_ANONYMOUS );
			nname = name;

		} else {
			name = op->o_dn;
			nname = op->o_ndn;
		}

		if ( !gotcsn ) {
			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
			mod->sml_op = LDAP_MOD_REPLACE;
			mod->sml_flags = SLAP_MOD_INTERNAL;
			mod->sml_next = NULL;
			BER_BVZERO( &mod->sml_type );
			mod->sml_desc = slap_schema.si_ad_entryCSN;
			mod->sml_numvals = 1;
			mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
			ber_dupbv( &mod->sml_values[0], &csn );
			BER_BVZERO( &mod->sml_values[1] );
			assert( !BER_BVISNULL( &mod->sml_values[0] ) );
			mod->sml_nvalues = NULL;
			*modtail = mod;
			modlast = mod;
			modtail = &mod->sml_next;
		}

		if ( !gotmname ) {
			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
			mod->sml_op = LDAP_MOD_REPLACE;
			mod->sml_flags = SLAP_MOD_INTERNAL;
			mod->sml_next = NULL;
			BER_BVZERO( &mod->sml_type );
			mod->sml_desc = slap_schema.si_ad_modifiersName;
			mod->sml_numvals = 1;
			mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
			ber_dupbv( &mod->sml_values[0], &name );
			BER_BVZERO( &mod->sml_values[1] );
			assert( !BER_BVISNULL( &mod->sml_values[0] ) );
			mod->sml_nvalues =
				(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
			ber_dupbv( &mod->sml_nvalues[0], &nname );
			BER_BVZERO( &mod->sml_nvalues[1] );
			assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) );
			*modtail = mod;
			modtail = &mod->sml_next;
		}

		if ( !gotmtime ) {
			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
			mod->sml_op = LDAP_MOD_REPLACE;
			mod->sml_flags = SLAP_MOD_INTERNAL;
			mod->sml_next = NULL;
			BER_BVZERO( &mod->sml_type );
			mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
			mod->sml_numvals = 1;
			mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
			ber_dupbv( &mod->sml_values[0], &timestamp );
			BER_BVZERO( &mod->sml_values[1] );
			assert( !BER_BVISNULL( &mod->sml_values[0] ) );
			mod->sml_nvalues = NULL;
			*modtail = mod;
			modtail = &mod->sml_next;
		}
	}
}
Exemplo n.º 12
0
int
asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc, int candidate)
{
	a_metainfo_t	*mi;
	a_metatarget_t	*mt;
	a_metasingleconn_t *msc;
	Operation *op = bc->op;
	SlapReply *rs;
	int	   i, rc = LDAP_SUCCESS, sres;
	SlapReply *candidates;
	char		**references = NULL;
	LDAPControl	**ctrls = NULL;
	a_dncookie dc;
	LDAPMessage *msg;
	ber_int_t id;

	rs = &bc->rs;
	mi = mc->mc_info;
	mt = mi->mi_targets[ candidate ];
	msc = &mc->mc_conns[ candidate ];
	dc.op = op;
	dc.target = mt;
	dc.to_from = MASSAGE_REP;
	id = ldap_msgid(res);


	candidates = bc->candidates;
	i = candidate;

	while (res && !META_BACK_CONN_INVALID(msc)) {
	for (msg = ldap_first_message(msc->msc_ldr, res); msg; msg = ldap_next_message(msc->msc_ldr, msg)) {
		switch(ldap_msgtype(msg)) {
		case LDAP_RES_SEARCH_ENTRY:
			Debug( LDAP_DEBUG_TRACE,
				"%s asyncmeta_handle_search_msg: msc %p entry\n",
				op->o_log_prefix, msc );
			if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
				/* don't retry any more... */
				candidates[ i ].sr_type = REP_RESULT;
			}
			/* count entries returned by target */
			candidates[ i ].sr_nentries++;
			if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !op->o_abandon) {
				rs->sr_err = asyncmeta_send_entry( &bc->copy_op, rs, mc, i, msg );
			} else {
				goto err_cleanup;
			}
			switch ( rs->sr_err ) {
			case LDAP_SIZELIMIT_EXCEEDED:
				asyncmeta_send_ldap_result(bc, op, rs);
				rs->sr_err = LDAP_SUCCESS;
				goto err_cleanup;
			case LDAP_UNAVAILABLE:
				rs->sr_err = LDAP_OTHER;
				break;
			default:
				break;
			}
			bc->is_ok++;
			break;

		case LDAP_RES_SEARCH_REFERENCE:
			if ( META_BACK_TGT_NOREFS( mt ) ) {
				rs->sr_err = LDAP_OTHER;
				asyncmeta_send_ldap_result(bc, op, rs);
				goto err_cleanup;
			}
			if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
				/* don't retry any more... */
				candidates[ i ].sr_type = REP_RESULT;
			}
			bc->is_ok++;
			rc = ldap_parse_reference( msc->msc_ldr, msg,
				   &references, &rs->sr_ctrls, 0 );

			if ( rc != LDAP_SUCCESS || references == NULL ) {
				rs->sr_err = LDAP_OTHER;
				asyncmeta_send_ldap_result(bc, op, rs);
				goto err_cleanup;
			}

			/* FIXME: merge all and return at the end */

			{
				int cnt;
				for ( cnt = 0; references[ cnt ]; cnt++ )
					;

				rs->sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
								 op->o_tmpmemctx );

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

			{
				dc.memctx = op->o_tmpmemctx;
				( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref );
			}

			if ( rs->sr_ref != NULL ) {
				if (!BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
					/* ignore return value by now */
					( void )send_search_reference( op, rs );
				}

				ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx );
				rs->sr_ref = NULL;
			}

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

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

		case LDAP_RES_INTERMEDIATE:
			if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
				/* don't retry any more... */
				candidates[ i ].sr_type = REP_RESULT;
			}
			bc->is_ok++;

			/* FIXME: response controls
			 * are passed without checks */
			rs->sr_err = ldap_parse_intermediate( msc->msc_ldr,
								  msg,
								  (char **)&rs->sr_rspoid,
								  &rs->sr_rspdata,
								  &rs->sr_ctrls,
								  0 );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				candidates[ i ].sr_type = REP_RESULT;
				rs->sr_err = LDAP_OTHER;
				asyncmeta_send_ldap_result(bc, op, rs);
				goto err_cleanup;
			}

			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;
			}
			break;

		case LDAP_RES_SEARCH_RESULT:
			if ( mi->mi_idle_timeout != 0 ) {
				asyncmeta_set_msc_time(msc);
			}
			Debug( LDAP_DEBUG_TRACE,
			       "%s asyncmeta_handle_search_msg: msc %p result\n",
			       op->o_log_prefix, msc );
			candidates[ i ].sr_type = REP_RESULT;
			candidates[ i ].sr_msgid = META_MSGID_IGNORE;
			/* NOTE: ignores response controls
			 * (and intermediate response controls
			 * as well, except for those with search
			 * references); this may not be correct,
			 * but if they're not ignored then
			 * back-meta would need to merge them
			 * consistently (think of pagedResults...)
			 */
			/* FIXME: response controls? */
			rs->sr_err = ldap_parse_result( msc->msc_ldr,
							msg,
							&candidates[ i ].sr_err,
								(char **)&candidates[ i ].sr_matched,
							(char **)&candidates[ i ].sr_text,
							&references,
							&ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
							0 );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				candidates[ i ].sr_err = rs->sr_err;
				sres = slap_map_api2result( &candidates[ i ] );
				candidates[ i ].sr_type = REP_RESULT;
				goto finish;
			}

			rs->sr_err = candidates[ i ].sr_err;

			/* massage matchedDN if need be */
			if ( candidates[ i ].sr_matched != NULL ) {
				struct berval	match, mmatch;

				ber_str2bv( candidates[ i ].sr_matched,
						0, 0, &match );
				candidates[ i ].sr_matched = NULL;

				dc.memctx = NULL;
				asyncmeta_dn_massage( &dc, &match, &mmatch );
				if ( mmatch.bv_val == match.bv_val ) {
					candidates[ i ].sr_matched
						= ch_strdup( mmatch.bv_val );

				} else {
					candidates[ i ].sr_matched = mmatch.bv_val;
				}

				bc->candidate_match++;
				ldap_memfree( match.bv_val );
			}

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

				} else {
					BerVarray	sr_ref;
					int		cnt;

					for ( cnt = 0; references[ cnt ]; cnt++ )
						;

					sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
								 op->o_tmpmemctx );

					for ( cnt = 0; references[ cnt ]; cnt++ ) {
						ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ],
								  op->o_tmpmemctx );
					}
					BER_BVZERO( &sr_ref[ cnt ] );

					dc.memctx = op->o_tmpmemctx;
					( void )asyncmeta_referral_result_rewrite( &dc, sr_ref );

					if ( rs->sr_v2ref == NULL ) {
						rs->sr_v2ref = sr_ref;

					} else {
						for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
							ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ],
									   op->o_tmpmemctx );
						}
						ber_memfree_x( sr_ref, op->o_tmpmemctx );
					}
				}

			} else if ( rs->sr_err == LDAP_REFERRAL ) {
				Debug( LDAP_DEBUG_TRACE,
					   "%s asyncmeta_search_result[%d]: "
					   "got err=%d with null "
					   "or empty referrals\n",
					   op->o_log_prefix,
					   i, rs->sr_err );

				rs->sr_err = LDAP_NO_SUCH_OBJECT;
			}

			/* cleanup */
			ber_memvfree( (void **)references );

			sres = slap_map_api2result( rs );

			if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d] "
				       "match=\"%s\" err=%ld",
				       op->o_log_prefix, i,
				       candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
				       (long) candidates[ i ].sr_err );
			} else {
					Debug( LDAP_DEBUG_ANY,  "%s asyncmeta_search_result[%d] "
				       "match=\"%s\" err=%ld (%s)",
				       op->o_log_prefix, i,
				       candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
					       (long) candidates[ i ].sr_err, ldap_err2string( candidates[ i ].sr_err ) );
			}

			switch ( sres ) {
			case LDAP_NO_SUCH_OBJECT:
				/* is_ok is touched any time a valid
				 * (even intermediate) result is
				 * returned; as a consequence, if
				 * a candidate returns noSuchObject
				 * it is ignored and the candidate
				 * is simply demoted. */
				if ( bc->is_ok ) {
					sres = LDAP_SUCCESS;
				}
				break;

			case LDAP_SUCCESS:
				if ( ctrls != NULL && ctrls[0] != NULL ) {
#ifdef SLAPD_META_CLIENT_PR
					LDAPControl *pr_c;

					pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
					if ( pr_c != NULL ) {
						BerElementBuffer berbuf;
						BerElement *ber = (BerElement *)&berbuf;
						ber_tag_t tag;
						ber_int_t prsize;
						struct berval prcookie;

						/* unsolicited, do not accept */
						if ( mt->mt_ps == 0 ) {
							rs->sr_err = LDAP_OTHER;
							goto err_pr;
						}

						ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );

						tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
						if ( tag == LBER_ERROR ) {
							rs->sr_err = LDAP_OTHER;
							goto err_pr;
						}

						/* more pages? new search request */
						if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
							if ( mt->mt_ps > 0 ) {
								/* ignore size if specified */
								prsize = 0;

							} else if ( prsize == 0 ) {
								/* guess the page size from the entries returned so far */
								prsize = candidates[ i ].sr_nentries;
							}

							candidates[ i ].sr_nentries = 0;
							candidates[ i ].sr_msgid = META_MSGID_IGNORE;
							candidates[ i ].sr_type = REP_INTERMEDIATE;

							assert( candidates[ i ].sr_matched == NULL );
							assert( candidates[ i ].sr_text == NULL );
							assert( candidates[ i ].sr_ref == NULL );

							switch ( asyncmeta_back_search_start( &bc->copy_op, rs, mc, bc, i, &prcookie, prsize, 1 ) )
							{
							case META_SEARCH_CANDIDATE:
								assert( candidates[ i ].sr_msgid >= 0 );
								ldap_controls_free( ctrls );
								//	goto free_message;

							case META_SEARCH_ERR:
							case META_SEARCH_NEED_BIND:
err_pr:;
								candidates[ i ].sr_err = rs->sr_err;
								candidates[ i ].sr_type = REP_RESULT;
								if ( META_BACK_ONERR_STOP( mi ) ) {
									asyncmeta_send_ldap_result(bc, op, rs);
									ldap_controls_free( ctrls );
									goto err_cleanup;
								}
								/* fallthru */

							case META_SEARCH_NOT_CANDIDATE:
								/* means that asyncmeta_back_search_start()
								 * failed but onerr == continue */
								candidates[ i ].sr_msgid = META_MSGID_IGNORE;
								candidates[ i ].sr_type = REP_RESULT;
								break;

							default:
								/* impossible */
								assert( 0 );
								break;
							}
							break;
						}
					}
#endif /* SLAPD_META_CLIENT_PR */

					ldap_controls_free( ctrls );
				}
				/* fallthru */

			case LDAP_REFERRAL:
				bc->is_ok++;
				break;

			case LDAP_SIZELIMIT_EXCEEDED:
				/* if a target returned sizelimitExceeded
				 * and the entry count is equal to the
				 * proxy's limit, the target would have
				 * returned more, and the error must be
				 * propagated to the client; otherwise,
				 * the target enforced a limit lower
				 * than what requested by the proxy;
				 * ignore it */
				candidates[ i ].sr_err = rs->sr_err;
				if ( rs->sr_nentries == op->ors_slimit
					 || META_BACK_ONERR_STOP( mi ) )
				{
					const char *save_text;
got_err:
					save_text = rs->sr_text;
					rs->sr_text = candidates[ i ].sr_text;
					asyncmeta_send_ldap_result(bc, op, rs);
					if (candidates[ i ].sr_text != NULL) {
						ch_free( (char *)candidates[ i ].sr_text );
						candidates[ i ].sr_text = NULL;
					}
					rs->sr_text = save_text;
					ldap_controls_free( ctrls );
					goto err_cleanup;
				}
				break;

			default:
				candidates[ i ].sr_err = rs->sr_err;
				if ( META_BACK_ONERR_STOP( mi ) ) {
					goto got_err;
				}
				break;
			}
			/* if this is the last result we will ever receive, send it back  */
			rc = rs->sr_err;
			if (asyncmeta_is_last_result(mc, bc, i) == 0) {
				Debug( LDAP_DEBUG_TRACE,
					"%s asyncmeta_handle_search_msg: msc %p last result\n",
					op->o_log_prefix, msc );
				asyncmeta_search_last_result(mc, bc, i, sres);
err_cleanup:
				rc = rs->sr_err;
				ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
				asyncmeta_drop_bc( mc, bc);
				asyncmeta_clear_bm_context(bc);
				ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
				ldap_msgfree(res);
				return rc;
			}
finish:
			break;

		default:
			continue;
		}
	}
		ldap_msgfree(res);
		res = NULL;
		if (candidates[ i ].sr_type != REP_RESULT) {
			struct timeval	tv = {0};
			rc = ldap_result( msc->msc_ldr, id, LDAP_MSG_RECEIVED, &tv, &res );
			if (res != NULL) {
				msc->msc_result_time = slap_get_time();
			}
		}
	}
	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
	bc->bc_active--;
	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );

	return rc;
}
Exemplo n.º 13
0
static int
meta_back_bind_op_result(
	Operation		*op,
	SlapReply		*rs,
	metaconn_t		*mc,
	int			candidate,
	int			msgid,
	ldap_back_send_t	sendok,
	int			dolock )
{
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
	metatarget_t		*mt = mi->mi_targets[ candidate ];
	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
	LDAPMessage		*res;
	struct timeval		tv;
	int			rc;
	int			nretries = mt->mt_nretries;
	char			buf[ SLAP_TEXT_BUFLEN ];

	Debug( LDAP_DEBUG_TRACE,
		">>> %s meta_back_bind_op_result[%d]\n",
		op->o_log_prefix, candidate );

	/* make sure this is clean */
	assert( rs->sr_ctrls == NULL );

	if ( rs->sr_err == LDAP_SUCCESS ) {
		time_t		stoptime = (time_t)(-1),
				timeout;
		int		timeout_err = op->o_protocol >= LDAP_VERSION3 ?
				LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
		const char	*timeout_text = "Operation timed out";
		slap_op_t	opidx = slap_req2op( op->o_tag );

		/* since timeout is not specified, compute and use
		 * the one specific to the ongoing operation */
		if ( opidx == (slap_op_t) LDAP_REQ_SEARCH ) {
			if ( op->ors_tlimit <= 0 ) {
				timeout = 0;

			} else {
				timeout = op->ors_tlimit;
				timeout_err = LDAP_TIMELIMIT_EXCEEDED;
				timeout_text = NULL;
			}

		} else {
			timeout = mt->mt_timeout[ opidx ];
		}

		/* better than nothing :) */
		if ( timeout == 0 ) {
			if ( mi->mi_idle_timeout ) {
				timeout = mi->mi_idle_timeout;

			} else if ( mi->mi_conn_ttl ) {
				timeout = mi->mi_conn_ttl;
			}
		}

		if ( timeout ) {
			stoptime = op->o_time + timeout;
		}

		LDAP_BACK_TV_SET( &tv );

		/*
		 * handle response!!!
		 */
retry:;
		rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
		switch ( rc ) {
		case 0:
			if ( nretries != META_RETRY_NEVER
				|| ( timeout && slap_get_time() <= stoptime ) )
			{
				ldap_pvt_thread_yield();
				if ( nretries > 0 ) {
					nretries--;
				}
				tv = mt->mt_bind_timeout;
				goto retry;
			}

			/* don't let anyone else use this handler,
			 * because there's a pending bind that will not
			 * be acknowledged */
			if ( dolock) {
				ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
			}
			assert( LDAP_BACK_CONN_BINDING( msc ) );

#ifdef DEBUG_205
			Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n",
				op->o_log_prefix, candidate, (void *)msc->msc_ld );
#endif /* DEBUG_205 */

			meta_clear_one_candidate( op, mc, candidate );
			if ( dolock ) {
				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
			}

			rs->sr_err = timeout_err;
			rs->sr_text = timeout_text;
			break;

		case -1:
			ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
				&rs->sr_err );

			snprintf( buf, sizeof( buf ),
				"err=%d (%s) nretries=%d",
				rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
			Debug( LDAP_DEBUG_ANY,
				"### %s meta_back_bind_op_result[%d]: %s.\n",
				op->o_log_prefix, candidate, buf );
			break;

		default:
			/* only touch when activity actually took place... */
			if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
				msc->msc_time = op->o_time;
			}

			/* FIXME: matched? referrals? response controls? */
			rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
					NULL, NULL, NULL, NULL, 1 );
			if ( rc != LDAP_SUCCESS ) {
				rs->sr_err = rc;
			}
			rs->sr_err = slap_map_api2result( rs );
			break;
		}
	}

	rs->sr_err = slap_map_api2result( rs );

	Debug( LDAP_DEBUG_TRACE,
		"<<< %s meta_back_bind_op_result[%d] err=%d\n",
		op->o_log_prefix, candidate, rs->sr_err );

	return rs->sr_err;
}
Exemplo n.º 14
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 );
                rs->sr_flags = 0;
                rs->sr_attrs = NULL;
            }

            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 );
                    rs->sr_flags = 0;
                    rs->sr_entry = NULL;
                }

                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 );
            rs->sr_flags = 0;
            rs->sr_entry = NULL;
            rs->sr_attrs = NULL;
        }

        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 );
}
Exemplo n.º 15
0
void* asyncmeta_timeout_loop(void *ctx, void *arg)
{
	struct re_s* rtask = arg;
	a_metainfo_t *mi = rtask->arg;
	bm_context_t *bc, *onext;
	time_t current_time = slap_get_time();
	int i, j;
	LDAP_STAILQ_HEAD(BCList, bm_context_t) timeout_list;
	LDAP_STAILQ_INIT( &timeout_list );

	Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time );
	void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);
	for (i=0; i<mi->mi_num_conns; i++) {
		a_metaconn_t * mc= &mi->mi_conns[i];
		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
			onext = LDAP_STAILQ_NEXT(bc, bc_next);
			if (bc->bc_active > 0) {
				continue;
			}

			if (bc->op->o_abandon ) {
					/* set our memctx */
				bc->op->o_threadctx = ctx;
				bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
				slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
				Operation *op = bc->op;

				LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
				mc->pending_ops--;
				for (j=0; j<mi->mi_ntargets; j++) {
					if (bc->candidates[j].sr_msgid >= 0) {
						a_metasingleconn_t *msc = &mc->mc_conns[j];
						if ( op->o_tag == LDAP_REQ_SEARCH ) {
							msc->msc_active++;
							asyncmeta_back_cancel( mc, op,
									       bc->candidates[ j ].sr_msgid, j );
							msc->msc_active--;
						}
					}
				}
				asyncmeta_clear_bm_context(bc);
				continue;
			}
			if (bc->bc_invalid) {
				LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
				mc->pending_ops--;
				LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next);
				continue;
			}

			if (bc->timeout && bc->stoptime < current_time) {
				Operation *op = bc->op;
				LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
				mc->pending_ops--;
				LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next);
				for (j=0; j<mi->mi_ntargets; j++) {
					if (bc->candidates[j].sr_msgid >= 0) {
						a_metasingleconn_t *msc = &mc->mc_conns[j];
						asyncmeta_set_msc_time(msc);
						if ( op->o_tag == LDAP_REQ_SEARCH ) {
							msc->msc_active++;
							asyncmeta_back_cancel( mc, op,
									       bc->candidates[ j ].sr_msgid, j );
							msc->msc_active--;
						}
					}
				}
			}
		}
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );

		for (bc = LDAP_STAILQ_FIRST(&timeout_list); bc; bc = onext) {
			Operation *op = bc->op;
			SlapReply *rs = &bc->rs;
			int		timeout_err;
			const char *timeout_text;

			onext = LDAP_STAILQ_NEXT(bc, bc_next);
			LDAP_STAILQ_REMOVE(&timeout_list, bc, bm_context_t, bc_next);
			/* set our memctx */
			bc->op->o_threadctx = ctx;
			bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
			slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);

			if (bc->searchtime) {
				timeout_err = LDAP_TIMELIMIT_EXCEEDED;
			} else {
				timeout_err = op->o_protocol >= LDAP_VERSION3 ?
					LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
			}

			if ( bc->bc_invalid ) {
				timeout_text = "Operation is invalid - target connection has been reset";
			} else {
				a_metasingleconn_t *log_msc =  &mc->mc_conns[0];
				Debug( asyncmeta_debug,
				       "asyncmeta_timeout_loop:Timeout op %s loop[%p], "
				       "current_time:%ld, op->o_time:%ld msc: %p, "
				       "msc->msc_binding_time: %x, msc->msc_flags:%x \n",
				       bc->op->o_log_prefix, rtask, current_time, bc->op->o_time,
				       log_msc, (unsigned int)log_msc->msc_binding_time, log_msc->msc_mscflags );

				if (bc->searchtime) {
					timeout_text = NULL;
				} else {
					timeout_text = "Operation timed out";
				}

				for (j=0; j<mi->mi_ntargets; j++) {
					if (bc->candidates[j].sr_msgid >= 0) {
						a_metatarget_t     *mt = mi->mi_targets[j];
						if (!META_BACK_TGT_QUARANTINE( mt ) ||
						    bc->candidates[j].sr_type == REP_RESULT) {
							continue;
						}

						if (mt->mt_isquarantined > LDAP_BACK_FQ_NO) {
							timeout_err = LDAP_UNAVAILABLE;
						} else {
							mt->mt_timeout_ops++;
							if ((mi->mi_max_timeout_ops > 0) &&
							    (mt->mt_timeout_ops > mi->mi_max_timeout_ops)) {
								timeout_err = LDAP_UNAVAILABLE;
								rs->sr_err = timeout_err;
								if (mt->mt_isquarantined == LDAP_BACK_FQ_NO)
									asyncmeta_quarantine(op, mi, rs, j);
							}
						}
					}
				}
			}
			rs->sr_err = timeout_err;
			rs->sr_text = timeout_text;
			if (!bc->op->o_abandon ) {
				asyncmeta_send_ldap_result( bc, bc->op, &bc->rs );
			}
			asyncmeta_clear_bm_context(bc);
		}

		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		if (mi->mi_idle_timeout) {
			for (j=0; j<mi->mi_ntargets; j++) {
				a_metasingleconn_t *msc = &mc->mc_conns[j];
				if ( msc->msc_active > 0 ) {
					continue;
				}
				if (mc->pending_ops > 0) {
					continue;
				}
				current_time = slap_get_time();
				if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout < current_time) {
					asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__);
				}
			}
		}
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
	}

	slap_sl_mem_setctx(ctx, oldctx);
	current_time = slap_get_time();
	Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] stop at [%ld] \n", rtask, current_time );
	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
	if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
		ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
	}
	rtask->interval.tv_sec = 1;
	rtask->interval.tv_usec = 0;
	ldap_pvt_runqueue_resched(&slapd_rq, rtask, 0);
	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
	return NULL;
}
Exemplo n.º 16
0
/*
 * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
 * return the LDAP DN to which it matches. The SASL regexp rules in the config
 * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
 * search with scope=base), just return the URI (or its searchbase). Otherwise
 * an internal search must be done, and if that search returns exactly one
 * entry, return the DN of that one entry.
 */
void slap_sasl2dn( Connection *conn,
	struct berval *saslname, struct berval *sasldn )
{
	int rc;
	Backend *be = NULL;
	struct berval dn = { 0, NULL };
	int scope = LDAP_SCOPE_BASE;
	Filter *filter = NULL;
	slap_callback cb = { slap_cb_null_response,
		slap_cb_null_sresult, sasl_sc_sasl2dn, slap_cb_null_sreference, NULL};
	Operation op = {0};
	struct berval regout = { 0, NULL };

#ifdef NEW_LOGGING
	LDAP_LOG( TRANSPORT, ENTRY, 
		"slap_sasl2dn: converting SASL name %s to DN.\n",
		saslname->bv_val, 0, 0 );
#else
	Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
		"converting SASL name %s to a DN\n",
		saslname->bv_val, 0,0 );
#endif

	sasldn->bv_val = NULL;
	sasldn->bv_len = 0;
	cb.sc_private = sasldn;

	/* Convert the SASL name into a minimal URI */
	if( !slap_sasl_regexp( saslname, &regout ) ) {
		goto FINISHED;
	}

	rc = slap_parseURI( &regout, &dn, &scope, &filter );
	if( regout.bv_val ) ch_free( regout.bv_val );
	if( rc != LDAP_SUCCESS ) {
		goto FINISHED;
	}

	/* Must do an internal search */
	be = select_backend( &dn, 0, 1 );

	/* Massive shortcut: search scope == base */
	if( scope == LDAP_SCOPE_BASE ) {
		*sasldn = dn;
		dn.bv_len = 0;
		dn.bv_val = NULL;
		goto FINISHED;
	}

#ifdef NEW_LOGGING
	LDAP_LOG( TRANSPORT, DETAIL1, 
		"slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
		dn.bv_val, scope, 0 );
#else
	Debug( LDAP_DEBUG_TRACE,
		"slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
		dn.bv_val, scope, 0 );
#endif

	if(( be == NULL ) || ( be->be_search == NULL)) {
		goto FINISHED;
	}

	op.o_tag = LDAP_REQ_SEARCH;
	op.o_protocol = LDAP_VERSION3;
	op.o_ndn = conn->c_ndn;
	op.o_callback = &cb;
	op.o_time = slap_get_time();
	op.o_do_not_cache = 1;
	op.o_is_auth_check = 1;
	op.o_threadctx = conn->c_sasl_bindop->o_threadctx;

	(*be->be_search)( be, conn, &op, NULL, &dn,
		scope, LDAP_DEREF_NEVER, 1, 0,
		filter, NULL, NULL, 1 );
	
FINISHED:
	if( sasldn->bv_len ) {
		conn->c_authz_backend = be;
	}
	if( dn.bv_len ) ch_free( dn.bv_val );
	if( filter ) filter_free( filter );

#ifdef NEW_LOGGING
	LDAP_LOG( TRANSPORT, ENTRY, 
		"slap_sasl2dn: Converted SASL name to %s\n",
		sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
#else
	Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
		sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
#endif

	return;
}
Exemplo n.º 17
0
/*
 * call from within ldap_back_db_open()
 */
int
ldap_back_monitor_db_open( BackendDB *be )
{
	ldapinfo_t		*li = (ldapinfo_t *) be->be_private;
	char			buf[ BACKMONITOR_BUFSIZE ];
	Entry			*e = NULL;
	monitor_callback_t	*cb = NULL;
	struct berval		suffix, *filter, *base;
	char			*ptr;
	time_t			now;
	char			timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
	struct berval 		timestamp;
	int			rc = 0;
	BackendInfo		*mi;
	monitor_extra_t		*mbe;

	if ( !SLAP_DBMONITORING( be ) ) {
		return 0;
	}

	/* check if monitor is configured and usable */
	mi = backend_info( "monitor" );
	if ( !mi || !mi->bi_extra ) {
		SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
		return 0;
 	}
 	mbe = mi->bi_extra;

	/* don't bother if monitor is not configured */
	if ( !mbe->is_configured() ) {
		static int warning = 0;

		if ( warning++ == 0 ) {
			Debug( LDAP_DEBUG_ANY, "ldap_back_monitor_db_open: "
				"monitoring disabled; "
				"configure monitor database to enable\n",
				0, 0, 0 );
		}

		return 0;
	}

	/* set up the fake subsystem that is used to create
	 * the volatile connection entries */
	li->li_monitor_info.lmi_mss.mss_name = "back-ldap";
	li->li_monitor_info.lmi_mss.mss_flags = MONITOR_F_VOLATILE_CH;
	li->li_monitor_info.lmi_mss.mss_create = ldap_back_monitor_conn_create;

	li->li_monitor_info.lmi_li = li;
	li->li_monitor_info.lmi_scope = LDAP_SCOPE_SUBORDINATE;
	base = &li->li_monitor_info.lmi_base;
	BER_BVSTR( base, "cn=databases,cn=monitor" );
	filter = &li->li_monitor_info.lmi_filter;
	BER_BVZERO( filter );

	suffix.bv_len = ldap_bv2escaped_filter_value_len( &be->be_nsuffix[ 0 ] );
	if ( suffix.bv_len == be->be_nsuffix[ 0 ].bv_len ) {
		suffix = be->be_nsuffix[ 0 ];

	} else {
		ldap_bv2escaped_filter_value( &be->be_nsuffix[ 0 ], &suffix );
	}
	
	filter->bv_len = STRLENOF( "(&" )
		+ li->li_monitor_info.lmi_more_filter.bv_len
		+ STRLENOF( "(monitoredInfo=" )
		+ strlen( be->bd_info->bi_type )
		+ STRLENOF( ")(!(monitorOverlay=" )
		+ strlen( be->bd_info->bi_type )
		+ STRLENOF( "))(namingContexts:distinguishedNameMatch:=" )
		+ suffix.bv_len + STRLENOF( "))" );
	ptr = filter->bv_val = ch_malloc( filter->bv_len + 1 );
	ptr = lutil_strcopy( ptr, "(&" );
	ptr = lutil_strncopy( ptr, li->li_monitor_info.lmi_more_filter.bv_val,
		li->li_monitor_info.lmi_more_filter.bv_len );
	ptr = lutil_strcopy( ptr, "(monitoredInfo=" );
	ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
	ptr = lutil_strcopy( ptr, ")(!(monitorOverlay=" );
	ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
	ptr = lutil_strcopy( ptr, "))(namingContexts:distinguishedNameMatch:=" );
	ptr = lutil_strncopy( ptr, suffix.bv_val, suffix.bv_len );
	ptr = lutil_strcopy( ptr, "))" );
	ptr[ 0 ] = '\0';
	assert( ptr == &filter->bv_val[ filter->bv_len ] );

	if ( suffix.bv_val != be->be_nsuffix[ 0 ].bv_val ) {
		ch_free( suffix.bv_val );
	}

	now = slap_get_time();
	timestamp.bv_val = timebuf;
	timestamp.bv_len = sizeof( timebuf );
	slap_timestamp( &now, &timestamp );

	/* caller (e.g. an overlay based on back-ldap) may want to use
	 * a different RDN... */
	if ( BER_BVISNULL( &li->li_monitor_info.lmi_rdn ) ) {
		ber_str2bv( "cn=Connections", 0, 1, &li->li_monitor_info.lmi_rdn );
	}

	ptr = ber_bvchr( &li->li_monitor_info.lmi_rdn, '=' );
	assert( ptr != NULL );
	ptr[ 0 ] = '\0';
	ptr++;

	snprintf( buf, sizeof( buf ),
		"dn: %s=%s\n"
		"objectClass: monitorContainer\n"
		"%s: %s\n"
		"creatorsName: %s\n"
		"createTimestamp: %s\n"
		"modifiersName: %s\n"
		"modifyTimestamp: %s\n",
		li->li_monitor_info.lmi_rdn.bv_val,
			ptr,
		li->li_monitor_info.lmi_rdn.bv_val,
			ptr,
		BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
		timestamp.bv_val,
		BER_BVISNULL( &be->be_rootdn ) ? SLAPD_ANONYMOUS : be->be_rootdn.bv_val,
		timestamp.bv_val );
	e = str2entry( buf );
	if ( e == NULL ) {
		rc = -1;
		goto cleanup;
	}

	ptr[ -1 ] = '=';

	/* add labeledURI and special, modifiable URI value */
	if ( li->li_uri != NULL ) {
		struct berval	bv;
		LDAPURLDesc	*ludlist = NULL;
		int		rc;

		rc = ldap_url_parselist_ext( &ludlist,
			li->li_uri, NULL,
			LDAP_PVT_URL_PARSE_NOEMPTY_HOST
				| LDAP_PVT_URL_PARSE_DEF_PORT );
		if ( rc != LDAP_URL_SUCCESS ) {
			Debug( LDAP_DEBUG_ANY,
				"ldap_back_monitor_db_open: "
				"unable to parse URI list (ignored)\n",
				0, 0, 0 );
		} else {
			for ( ; ludlist != NULL; ) {
				LDAPURLDesc	*next = ludlist->lud_next;

				bv.bv_val = ldap_url_desc2str( ludlist );
				assert( bv.bv_val != NULL );
				ldap_free_urldesc( ludlist );
				bv.bv_len = strlen( bv.bv_val );
				attr_merge_normalize_one( e, slap_schema.si_ad_labeledURI,
					&bv, NULL );
				ch_free( bv.bv_val );

				ludlist = next;
			}
		}
		
		ber_str2bv( li->li_uri, 0, 0, &bv );
		attr_merge_normalize_one( e, ad_olmDbURIList,
			&bv, NULL );
	}

	ber_dupbv( &li->li_monitor_info.lmi_nrdn, &e->e_nname );

	cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
	cb->mc_update = ldap_back_monitor_update;
	cb->mc_modify = ldap_back_monitor_modify;
	cb->mc_free = ldap_back_monitor_free;
	cb->mc_private = (void *)li;

	rc = mbe->register_entry_parent( e, cb,
		(monitor_subsys_t *)&li->li_monitor_info,
		MONITOR_F_VOLATILE_CH,
		base, LDAP_SCOPE_SUBORDINATE, filter );

cleanup:;
	if ( rc != 0 ) {
		if ( cb != NULL ) {
			ch_free( cb );
			cb = NULL;
		}

		if ( e != NULL ) {
			entry_free( e );
			e = NULL;
		}

		if ( !BER_BVISNULL( filter ) ) {
			ch_free( filter->bv_val );
			BER_BVZERO( filter );
		}
	}

	/* store for cleanup */
	li->li_monitor_info.lmi_cb = (void *)cb;

	if ( e != NULL ) {
		entry_free( e );
	}

	return rc;
}
Exemplo n.º 18
0
static
int slap_sasl_match(Connection *conn, struct berval *rule, struct berval *assertDN, struct berval *authc )
{
	struct berval searchbase = {0, NULL};
	int rc, scope;
	Backend *be;
	Filter *filter=NULL;
	regex_t reg;
	smatch_info sm;
	slap_callback cb = {
		slap_cb_null_response,
		slap_cb_null_sresult,
		sasl_sc_smatch,
		NULL
	};
	Operation op = {0};

#ifdef NEW_LOGGING
	LDAP_LOG( TRANSPORT, ENTRY, 
		"slap_sasl_match: comparing DN %s to rule %s\n", 
		assertDN->bv_val, rule->bv_val,0 );
#else
	Debug( LDAP_DEBUG_TRACE,
	   "===>slap_sasl_match: comparing DN %s to rule %s\n",
		assertDN->bv_val, rule->bv_val, 0 );
#endif

	rc = slap_parseURI( rule, &searchbase, &scope, &filter );
	if( rc != LDAP_SUCCESS ) goto CONCLUDED;

	/* Massive shortcut: search scope == base */
	if( scope == LDAP_SCOPE_BASE ) {
		rc = regcomp(&reg, searchbase.bv_val,
			REG_EXTENDED|REG_ICASE|REG_NOSUB);
		if ( rc == 0 ) {
			rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
			regfree( &reg );
		}
		if ( rc == 0 ) {
			rc = LDAP_SUCCESS;
		} else {
			rc = LDAP_INAPPROPRIATE_AUTH;
		}
		goto CONCLUDED;
	}

	/* Must run an internal search. */

#ifdef NEW_LOGGING
	LDAP_LOG( TRANSPORT, DETAIL1, 
		"slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
		searchbase.bv_val, scope,0 );
#else
	Debug( LDAP_DEBUG_TRACE,
	   "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
	   searchbase.bv_val, scope, 0 );
#endif

	be = select_backend( &searchbase, 0, 1 );
	if(( be == NULL ) || ( be->be_search == NULL)) {
		rc = LDAP_INAPPROPRIATE_AUTH;
		goto CONCLUDED;
	}

	sm.dn = assertDN;
	sm.match = 0;
	cb.sc_private = &sm;

	op.o_tag = LDAP_REQ_SEARCH;
	op.o_protocol = LDAP_VERSION3;
	op.o_ndn = *authc;
	op.o_callback = &cb;
	op.o_time = slap_get_time();
	op.o_do_not_cache = 1;
	op.o_is_auth_check = 1;
	op.o_threadctx = conn->c_sasl_bindop->o_threadctx;

	(*be->be_search)( be, conn, &op, /*base=*/NULL, &searchbase,
	   scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
	   /*attrs=*/NULL, /*attrsonly=*/0 );

	if (sm.match) {
		rc = LDAP_SUCCESS;
	} else {
		rc = LDAP_INAPPROPRIATE_AUTH;
	}

CONCLUDED:
	if( searchbase.bv_len ) ch_free( searchbase.bv_val );
	if( filter ) filter_free( filter );

#ifdef NEW_LOGGING
	LDAP_LOG( TRANSPORT, ENTRY, 
		"slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
#else
	Debug( LDAP_DEBUG_TRACE,
	   "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
#endif

	return( rc );
}
Exemplo n.º 19
0
static int
constraint_violation( constraint *c, struct berval *bv, Operation *op, SlapReply *rs)
{
	if ((!c) || (!bv)) return LDAP_SUCCESS;
	
	if ((c->re) &&
		(regexec(c->re, bv->bv_val, 0, NULL, 0) == REG_NOMATCH))
		return LDAP_CONSTRAINT_VIOLATION; /* regular expression violation */

	if ((c->size) && (bv->bv_len > c->size))
		return LDAP_CONSTRAINT_VIOLATION; /* size violation */

	if (c->lud) {
		Operation nop = *op;
		slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
		slap_callback cb;
		SlapReply nrs = { REP_RESULT };
		int i;
		int found;
		int rc;
		size_t len;
		struct berval filterstr;
		char *ptr;

		found = 0;

		nrs.sr_entry = NULL;
		nrs.sr_nentries = 0;

		cb.sc_next = NULL;
		cb.sc_response = constraint_uri_cb;
		cb.sc_cleanup = NULL;
		cb.sc_private = &found;

		nop.o_protocol = LDAP_VERSION3;
		nop.o_tag = LDAP_REQ_SEARCH;
		nop.o_time = slap_get_time();
		if (c->lud->lud_dn) {
			struct berval dn;

			ber_str2bv(c->lud->lud_dn, 0, 0, &dn);
			nop.o_req_dn = dn;
			nop.o_req_ndn = dn;
			nop.o_bd = select_backend(&nop.o_req_ndn, 1 );
			if (!nop.o_bd) {
				return LDAP_NO_SUCH_OBJECT; /* unexpected error */
			}
			if (!nop.o_bd->be_search) {
				return LDAP_OTHER; /* unexpected error */
			}
		} else {
			nop.o_req_dn = nop.o_bd->be_nsuffix[0];
			nop.o_req_ndn = nop.o_bd->be_nsuffix[0];
			nop.o_bd = on->on_info->oi_origdb;
		}
		nop.o_do_not_cache = 1;
		nop.o_callback = &cb;

		nop.ors_scope = c->lud->lud_scope;
		nop.ors_deref = LDAP_DEREF_NEVER;
		nop.ors_slimit = SLAP_NO_LIMIT;
		nop.ors_tlimit = SLAP_NO_LIMIT;
		nop.ors_limit = NULL;

		nop.ors_attrsonly = 0;
		nop.ors_attrs = slap_anlist_no_attrs;

		len = STRLENOF("(&(") + 
			  c->filter.bv_len +
			  STRLENOF(")(|");

		for (i = 0; c->attrs[i]; i++) {
			len += STRLENOF("(") +
				   c->attrs[i]->ad_cname.bv_len +
				   STRLENOF("=") + 
				   bv->bv_len +
				   STRLENOF(")");
		}

		len += STRLENOF("))");
		filterstr.bv_len = len;
		filterstr.bv_val = op->o_tmpalloc(len + 1, op->o_tmpmemctx);

		ptr = filterstr.bv_val +
			snprintf(filterstr.bv_val, len, "(&(%s)(|", c->lud->lud_filter);
		for (i = 0; c->attrs[i]; i++) {
			*ptr++ = '(';
			ptr = lutil_strcopy( ptr, c->attrs[i]->ad_cname.bv_val );
			*ptr++ = '=';
			ptr = lutil_strcopy( ptr, bv->bv_val );
			*ptr++ = ')';
		}
		*ptr++ = ')';
		*ptr++ = ')';
		*ptr++ = '\0';

		nop.ors_filterstr = filterstr;
		nop.ors_filter = str2filter_x(&nop, filterstr.bv_val);
		if ( nop.ors_filter == NULL ) {
			Debug( LDAP_DEBUG_ANY,
				"%s constraint_violation uri filter=\"%s\" invalid\n",
				op->o_log_prefix, filterstr.bv_val, 0 );
			rc = LDAP_OTHER;

		} else {
			Debug(LDAP_DEBUG_TRACE, 
				"==> constraint_violation uri filter = %s\n",
				filterstr.bv_val, 0, 0);

			rc = nop.o_bd->be_search( &nop, &nrs );
		
			Debug(LDAP_DEBUG_TRACE, 
				"==> constraint_violation uri rc = %d, found = %d\n",
				rc, found, 0);
		}
		op->o_tmpfree(filterstr.bv_val, op->o_tmpmemctx);

		if ((rc != LDAP_SUCCESS) && (rc != LDAP_NO_SUCH_OBJECT)) {
			return rc; /* unexpected error */
		}

		if (!found)
			return LDAP_CONSTRAINT_VIOLATION; /* constraint violation */
			
	}

	return LDAP_SUCCESS;
}
Exemplo n.º 20
0
/*
 * FIXME: error return must be handled in a cleaner way ...
 */
int
meta_back_op_result(
	metaconn_t		*mc,
	Operation		*op,
	SlapReply		*rs,
	int			candidate,
	ber_int_t		msgid,
	time_t			timeout,
	ldap_back_send_t	sendok )
{
	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;

	const char	*save_text = rs->sr_text,
			*save_matched = rs->sr_matched;
	BerVarray	save_ref = rs->sr_ref;
	LDAPControl	**save_ctrls = rs->sr_ctrls;
	void		*matched_ctx = NULL;

	char		*matched = NULL;
	char		*text = NULL;
	char		**refs = NULL;
	LDAPControl	**ctrls = NULL;

	assert( mc != NULL );

	rs->sr_text = NULL;
	rs->sr_matched = NULL;
	rs->sr_ref = NULL;
	rs->sr_ctrls = NULL;

	if ( candidate != META_TARGET_NONE ) {
		metatarget_t		*mt = mi->mi_targets[ candidate ];
		metasingleconn_t	*msc = &mc->mc_conns[ candidate ];

		if ( LDAP_ERR_OK( rs->sr_err ) ) {
			int		rc;
			struct timeval	tv;
			LDAPMessage	*res = NULL;
			time_t		stoptime = (time_t)(-1);
			int		timeout_err = op->o_protocol >= LDAP_VERSION3 ?
						LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
			const char	*timeout_text = "Operation timed out";

			/* if timeout is not specified, compute and use
			 * the one specific to the ongoing operation */
			if ( timeout == (time_t)(-1) ) {
				slap_op_t	opidx = slap_req2op( op->o_tag );

				if ( opidx == SLAP_OP_SEARCH ) {
					if ( op->ors_tlimit <= 0 ) {
						timeout = 0;

					} else {
						timeout = op->ors_tlimit;
						timeout_err = LDAP_TIMELIMIT_EXCEEDED;
						timeout_text = NULL;
					}

				} else {
					timeout = mt->mt_timeout[ opidx ];
				}
			}

			/* better than nothing :) */
			if ( timeout == 0 ) {
				if ( mi->mi_idle_timeout ) {
					timeout = mi->mi_idle_timeout;

				} else if ( mi->mi_conn_ttl ) {
					timeout = mi->mi_conn_ttl;
				}
			}

			if ( timeout ) {
				stoptime = op->o_time + timeout;
			}

			LDAP_BACK_TV_SET( &tv );

retry:;
			rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
			switch ( rc ) {
			case 0:
				if ( timeout && slap_get_time() > stoptime ) {
					(void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok );
					rs->sr_err = timeout_err;
					rs->sr_text = timeout_text;
					break;
				}

				LDAP_BACK_TV_SET( &tv );
				ldap_pvt_thread_yield();
				goto retry;

			case -1:
				ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
						&rs->sr_err );
				break;


			/* otherwise get the result; if it is not
			 * LDAP_SUCCESS, record it in the reply
			 * structure (this includes
			 * LDAP_COMPARE_{TRUE|FALSE}) */
			default:
				/* only touch when activity actually took place... */
				if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
					msc->msc_time = op->o_time;
				}

				rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
						&matched, &text, &refs, &ctrls, 1 );
				res = NULL;
				if ( rc == LDAP_SUCCESS ) {
					rs->sr_text = text;
				} 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 ( refs != NULL
					&& refs[ 0 ] != NULL
					&& refs[ 0 ][ 0 ] != '\0' )
				{
					if ( rs->sr_err != LDAP_REFERRAL ) {
						Debug( LDAP_DEBUG_ANY,
							"%s meta_back_op_result[%d]: "
							"got referrals with err=%d\n",
							op->o_log_prefix,
							candidate, rs->sr_err );

					} else {
						int	i;

						for ( i = 0; refs[ i ] != NULL; i++ )
							/* count */ ;
						rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
							op->o_tmpmemctx );
						for ( i = 0; refs[ i ] != NULL; i++ ) {
							ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
						}
						BER_BVZERO( &rs->sr_ref[ i ] );
					}

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

					rs->sr_err = LDAP_NO_SUCH_OBJECT;
				}

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

			assert( res == NULL );
		}

		/* if the error in the reply structure is not
		 * LDAP_SUCCESS, try to map it from client
		 * to server error */
		if ( !LDAP_ERR_OK( rs->sr_err ) ) {
			rs->sr_err = slap_map_api2result( rs );

			/* internal ops ( op->o_conn == NULL )
			 * must not reply to client */
			if ( op->o_conn && !op->o_do_not_cache && matched ) {

				/* record the (massaged) matched
				 * DN into the reply structure */
				rs->sr_matched = matched;
			}
		}

		if ( META_BACK_TGT_QUARANTINE( mt ) ) {
			meta_back_quarantine( op, rs, candidate );
		}

	} else {
		int	i,
			err = rs->sr_err;

		for ( i = 0; i < mi->mi_ntargets; i++ ) {
			metasingleconn_t	*msc = &mc->mc_conns[ i ];
			char			*xtext = NULL;
			char			*xmatched = NULL;

			if ( msc->msc_ld == NULL ) {
				continue;
			}

			rs->sr_err = LDAP_SUCCESS;

			ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				/*
				 * better check the type of error. In some cases
				 * (search ?) it might be better to return a
				 * success if at least one of the targets gave
				 * positive result ...
				 */
				ldap_get_option( msc->msc_ld,
						LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext );
				if ( xtext != NULL && xtext [ 0 ] == '\0' ) {
					ldap_memfree( xtext );
					xtext = NULL;
				}

				ldap_get_option( msc->msc_ld,
						LDAP_OPT_MATCHED_DN, &xmatched );
				if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) {
					ldap_memfree( xmatched );
					xmatched = NULL;
				}

				rs->sr_err = slap_map_api2result( rs );

				if ( LogTest( LDAP_DEBUG_ANY ) ) {
					char	buf[ SLAP_TEXT_BUFLEN ];

					snprintf( buf, sizeof( buf ),
						"meta_back_op_result[%d] "
						"err=%d text=\"%s\" matched=\"%s\"",
						i, rs->sr_err,
						( xtext ? xtext : "" ),
						( xmatched ? xmatched : "" ) );
					Debug( LDAP_DEBUG_ANY, "%s %s.\n",
						op->o_log_prefix, buf );
				}

				/*
				 * FIXME: need to rewrite "match" (need rwinfo)
				 */
				switch ( rs->sr_err ) {
				default:
					err = rs->sr_err;
					if ( xtext != NULL ) {
						if ( text ) {
							ldap_memfree( text );
						}
						text = xtext;
						xtext = NULL;
					}
					if ( xmatched != NULL ) {
						if ( matched ) {
							ldap_memfree( matched );
						}
						matched = xmatched;
						xmatched = NULL;
					}
					break;
				}

				if ( xtext ) {
					ldap_memfree( xtext );
				}

				if ( xmatched ) {
					ldap_memfree( xmatched );
				}
			}

			if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
				meta_back_quarantine( op, rs, i );
			}
		}

		if ( err != LDAP_SUCCESS ) {
			rs->sr_err = err;
		}
	}

	if ( matched != NULL ) {
		struct berval	dn, pdn;

		ber_str2bv( matched, 0, 0, &dn );
		if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
			ldap_memfree( matched );
			matched_ctx = op->o_tmpmemctx;
			matched = pdn.bv_val;
		}
		rs->sr_matched = matched;
	}

	if ( rs->sr_err == LDAP_UNAVAILABLE ) {
		if ( !( sendok & LDAP_BACK_RETRYING ) ) {
			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
				if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
				send_ldap_result( op, rs );
			}
		}

	} else if ( op->o_conn &&
		( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
			|| ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
	{
		send_ldap_result( op, rs );
	}
	if ( matched ) {
		op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
	}
	if ( text ) {
		ldap_memfree( text );
	}
	if ( rs->sr_ref ) {
		op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
		rs->sr_ref = NULL;
	}
	if ( refs ) {
		ber_memvfree( (void **)refs );
	}
	if ( ctrls ) {
		assert( rs->sr_ctrls != NULL );
		ldap_controls_free( ctrls );
	}

	rs->sr_text = save_text;
	rs->sr_matched = save_matched;
	rs->sr_ref = save_ref;
	rs->sr_ctrls = save_ctrls;

	return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
}
Exemplo n.º 21
0
void *
asyncmeta_op_handle_result(void *ctx, void *arg)
{
	a_metaconn_t *mc = arg;
	int		i, j, rc, ntargets;
	struct timeval	tv = {0};
	LDAPMessage     *msg;
	a_metasingleconn_t *msc;
	bm_context_t *bc;
	void *oldctx;

	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
	rc = ++mc->mc_active;
	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
	if (rc > 1)
		return NULL;

	ntargets = mc->mc_info->mi_ntargets;
	i = ntargets;
	oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);	/* get existing memctx */

again:
	for (j=0; j<ntargets; j++) {
		i++;
		if (i >= ntargets) i = 0;
		msc = &mc->mc_conns[i];
		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		if (!mc->mc_conns[i].msc_ldr ||
		    META_BACK_CONN_CREATING( &mc->mc_conns[i] ) ||
		    META_BACK_CONN_INVALID(&mc->mc_conns[i])) {
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			continue;
		}

		msc->msc_active++;
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );

		rc = ldap_result( mc->mc_conns[i].msc_ldr, LDAP_RES_ANY, LDAP_MSG_RECEIVED, &tv, &msg );
		if (rc < 1) {
			if (rc < 0) {
				ldap_get_option( mc->mc_conns[i].msc_ldr, LDAP_OPT_ERROR_NUMBER, &rc);
				META_BACK_CONN_INVALID_SET(&mc->mc_conns[i]);
				asyncmeta_op_read_error(mc, i, rc, ctx);
			}
			ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
			msc->msc_active--;
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			continue;
		}
		rc = ldap_msgtype( msg );
		if (rc == LDAP_RES_BIND) {
			if ( LogTest( asyncmeta_debug ) ) {
				char	time_buf[ SLAP_TEXT_BUFLEN ];
				asyncmeta_get_timestamp(time_buf);
				Debug( asyncmeta_debug, "[%s] asyncmeta_op_handle_result received bind msgid=%d msc: %p\n",
				      time_buf, ldap_msgid(msg), msc );
			}
			asyncmeta_handle_bind_result(msg, mc, i, ctx);
			mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
			ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
			msc->msc_result_time = slap_get_time();
			msc->msc_active--;
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			if (msg)
				ldap_msgfree(msg);

			continue;
		}
retry_bc:
		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		bc = asyncmeta_find_message(ldap_msgid(msg), mc, i);
/* The sender might not be yet done with the context. On error it might also remove it
 * so it's best to try and find it again after a wait */
		if (bc && bc->bc_active > 0) {
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			ldap_pvt_thread_yield();
			goto retry_bc;
		}
		if (bc) {
			bc->bc_active++;
		}

		msc->msc_result_time = slap_get_time();
		msc->msc_active--;
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
		if (!bc) {
			Debug( asyncmeta_debug,
				"asyncmeta_op_handle_result: Unable to find bc for msguid %d, msc: %p\n", ldap_msgid(msg), msc );
			ldap_msgfree(msg);
			continue;
		}

		/* set our memctx */
		bc->op->o_threadctx = ctx;
		bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
		slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
		if (bc->op->o_abandon) {
			ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
			asyncmeta_drop_bc( mc, bc);
			if ( bc->op->o_tag == LDAP_REQ_SEARCH ) {
				int j;
				for (j=0; j<ntargets; j++) {
					if (bc->candidates[j].sr_msgid >= 0) {
						a_metasingleconn_t *tmp_msc = &mc->mc_conns[j];
						tmp_msc->msc_active++;
						asyncmeta_back_cancel( mc, bc->op,
								       bc->candidates[ j ].sr_msgid, j );
						tmp_msc->msc_active--;
					}
				}
			}
			asyncmeta_clear_bm_context(bc);
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			if (msg)
				ldap_msgfree(msg);
			continue;
		}

		switch (rc) {
		case LDAP_RES_SEARCH_ENTRY:
		case LDAP_RES_SEARCH_REFERENCE:
		case LDAP_RES_SEARCH_RESULT:
		case LDAP_RES_INTERMEDIATE:
			asyncmeta_handle_search_msg(msg, mc, bc, i);
			mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
			msg = NULL;
			break;
		case LDAP_RES_ADD:
		case LDAP_RES_DELETE:
		case LDAP_RES_MODDN:
		case LDAP_RES_COMPARE:
		case LDAP_RES_MODIFY:
			rc = asyncmeta_handle_common_result(msg, mc, bc, i);
			mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
			break;
		default:
			{
			Debug( asyncmeta_debug,
				   "asyncmeta_op_handle_result: "
				   "unrecognized response message tag=%d\n",
				   rc );

			}
		}
		if (msg)
			ldap_msgfree(msg);
	}

	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
	rc = --mc->mc_active;
	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
	if (rc) {
		i++;
		goto again;
	}
	slap_sl_mem_setctx(ctx, oldctx);
	if (mc->mc_conns) {
		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		for (i=0; i<ntargets; i++) {
			if (!slapd_shutdown && !META_BACK_CONN_INVALID(msc)
			    && mc->mc_conns[i].msc_ldr && mc->mc_conns[i].conn) {
				connection_client_enable(mc->mc_conns[i].conn);
			}
		}
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
	}
	return NULL;
}
Exemplo n.º 22
0
static int
dds_op_modify( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
	dds_info_t	*di = (dds_info_t *)on->on_bi.bi_private;
	Modifications	*mod;
	Entry		*e = NULL;
	BackendInfo	*bi = op->o_bd->bd_info;
	int		was_dynamicObject = 0,
			is_dynamicObject = 0;
	struct berval	bv_entryTtl = BER_BVNULL;
	time_t		entryTtl = 0;
	char		textbuf[ SLAP_TEXT_BUFLEN ];

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

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

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

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

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

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

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

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

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

				break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

					}
					goto done;
				}

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

			default:
				LDAP_BUG();
				break;
			}

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

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

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

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

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

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

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

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

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

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

		*modp = tmpmod;

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

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

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

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

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

	return SLAP_CB_CONTINUE;
}
Exemplo n.º 23
0
void asyncmeta_set_msc_time(a_metasingleconn_t *msc)
{
	msc->msc_time = slap_get_time();
}
Exemplo n.º 24
0
static void *
slapd_daemon_task(
	void *ptr
)
{
	int l;
	time_t	last_idle_check = 0;
	struct timeval idle;
	time( &starttime );

#define SLAPD_IDLE_CHECK_LIMIT 4

	if ( global_idletimeout > 0 ) {
		last_idle_check = slap_get_time();
		/* Set the select timeout.
		 * Don't just truncate, preserve the fractions of
		 * seconds to prevent sleeping for zero time.
		 */
		idle.tv_sec = global_idletimeout/SLAPD_IDLE_CHECK_LIMIT;
		idle.tv_usec = global_idletimeout - idle.tv_sec * SLAPD_IDLE_CHECK_LIMIT;
		idle.tv_usec *= 1000000 / SLAPD_IDLE_CHECK_LIMIT;
	} else {
		idle.tv_sec = 0;
		idle.tv_usec = 0;
	}

	for ( l = 0; slap_listeners[l] != NULL; l++ ) {
		if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
			continue;
#ifdef LDAP_CONNECTIONLESS
		/* Since this is connectionless, the data port is the
		 * listening port. The listen() and accept() calls
		 * are unnecessary.
		 */
		if ( slap_listeners[l]->sl_is_udp ) {
			slapd_add( slap_listeners[l]->sl_sd );
			continue;
		}
#endif

		if ( listen( slap_listeners[l]->sl_sd, SLAPD_LISTEN ) == -1 ) {
			int err = sock_errno();

#ifdef LDAP_PF_INET6
			/* If error is EADDRINUSE, we are trying to listen to INADDR_ANY and
			 * we are already listening to in6addr_any, then we want to ignore
			 * this and continue.
			 */
			if ( err == EADDRINUSE ) {
				int i;
				struct sockaddr_in sa = slap_listeners[l]->sl_sa.sa_in_addr;
				struct sockaddr_in6 sa6;
				
				if ( sa.sin_family == AF_INET &&
				     sa.sin_addr.s_addr == htonl(INADDR_ANY) ) {
					for ( i = 0 ; i < l; i++ ) {
						sa6 = slap_listeners[i]->sl_sa.sa_in6_addr;
						if ( sa6.sin6_family == AF_INET6 &&
						     !memcmp( &sa6.sin6_addr, &in6addr_any, sizeof(struct in6_addr) ) )
							break;
					}

					if ( i < l ) {
						/* We are already listening to in6addr_any */
#ifdef NEW_LOGGING
						LDAP_LOG(CONNECTION, WARNING,
							   "slapd_daemon_task: Attempt to listen to 0.0.0.0 failed, already listening on ::, assuming IPv4 included\n", 0, 0, 0 );
#else
						Debug( LDAP_DEBUG_CONNS,
						       "daemon: Attempt to listen to 0.0.0.0 failed, already listening on ::, assuming IPv4 included\n",
						       0, 0, 0 );
#endif
						slapd_close( slap_listeners[l]->sl_sd );
						slap_listeners[l]->sl_sd = AC_SOCKET_INVALID;
						continue;
					}
				}
			}
#endif				
#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, ERR, 
				"slapd_daemon_task: listen( %s, 5 ) failed errno=%d (%s)\n",
				slap_listeners[l]->sl_url.bv_val, err, sock_errstr(err) );
#else
			Debug( LDAP_DEBUG_ANY,
				"daemon: listen(%s, 5) failed errno=%d (%s)\n",
					slap_listeners[l]->sl_url.bv_val, err,
					sock_errstr(err) );
#endif
			return( (void*)-1 );
		}

		slapd_add( slap_listeners[l]->sl_sd );
	}

#ifdef HAVE_NT_SERVICE_MANAGER
	if ( started_event != NULL ) {
		ldap_pvt_thread_cond_signal( &started_event );
	}
#endif
	/* initialization complete. Here comes the loop. */

	while ( !slapd_shutdown ) {
		ber_socket_t i;
		int ns;
		int at;
		ber_socket_t nfds;
#define SLAPD_EBADF_LIMIT 16
		int ebadf = 0;

		time_t	now;

		fd_set			readfds;
		fd_set			writefds;
		Sockaddr		from;

		struct timeval		tv;
		struct timeval		*tvp;

		now = slap_get_time();

		if( ( global_idletimeout > 0 ) &&
			difftime( last_idle_check +
			global_idletimeout/SLAPD_IDLE_CHECK_LIMIT, now ) < 0 ) {
			connections_timeout_idle( now );
			last_idle_check = now;
		}
		tv = idle;

#ifdef SIGHUP
		if( slapd_gentle_shutdown ) {
			ber_socket_t active;

			if( slapd_gentle_shutdown == 1 ) {
				Debug( LDAP_DEBUG_ANY, "slapd gentle shutdown\n", 0, 0, 0 );
				close_listeners( 1 );
				global_restrictops |= SLAP_RESTRICT_OP_WRITES;
				slapd_gentle_shutdown = 2;
			}

			ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
			active = slap_daemon.sd_nactives;
			ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
			if( active == 0 ) {
				slapd_shutdown = 2;
				break;
			}
		}
#endif

		FD_ZERO( &writefds );
		FD_ZERO( &readfds );

		at = 0;

		ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );

#ifdef FD_SET_MANUAL_COPY
		for( s = 0; s < nfds; s++ ) {
			if(FD_ISSET( &slap_sd_readers, s )) {
				FD_SET( s, &readfds );
			}
			if(FD_ISSET( &slap_sd_writers, s )) {
				FD_SET( s, &writefds );
			}
		}
#else
		AC_MEMCPY( &readfds, &slap_daemon.sd_readers, sizeof(fd_set) );
		AC_MEMCPY( &writefds, &slap_daemon.sd_writers, sizeof(fd_set) );
#endif
		assert(!FD_ISSET(wake_sds[0], &readfds));
		FD_SET( wake_sds[0], &readfds );

		for ( l = 0; slap_listeners[l] != NULL; l++ ) {
			if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
				continue;
			if ( slap_listeners[l]->sl_is_mute )
				FD_CLR( slap_listeners[l]->sl_sd, &readfds );
			else
			if (!FD_ISSET(slap_listeners[l]->sl_sd, &readfds))
			    FD_SET( slap_listeners[l]->sl_sd, &readfds );
		}

#ifndef HAVE_WINSOCK
		nfds = slap_daemon.sd_nfds;
#else
		nfds = dtblsize;
#endif
		if ( global_idletimeout && slap_daemon.sd_nactives )
			at = 1;

		ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );

		if ( !at )
			at = ldap_pvt_thread_pool_backload(&connection_pool);

#if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS )
		tvp = NULL;
#else
		tvp = at ? &tv : NULL;
#endif

		for ( l = 0; slap_listeners[l] != NULL; l++ ) {
			if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID ||
			    slap_listeners[l]->sl_is_mute )
				continue;

#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, DETAIL1, 
				"slapd_daemon_task: select: listen=%d "
				"active_threads=%d tvp=%s\n",
				slap_listeners[l]->sl_sd, at, tvp == NULL ? "NULL" : "idle" );
#else
			Debug( LDAP_DEBUG_CONNS,
				"daemon: select: listen=%d active_threads=%d tvp=%s\n",
					slap_listeners[l]->sl_sd, at,
					tvp == NULL ? "NULL" : "idle" );
#endif
		}

		switch(ns = select( nfds, &readfds,
#ifdef HAVE_WINSOCK
			/* don't pass empty fd_set */
			( writefds.fd_count > 0 ? &writefds : NULL ),
#else
			&writefds,
#endif
			NULL, tvp ))
		{
		case -1: {	/* failure - try again */
				int err = sock_errno();

				if( err == EBADF
#ifdef WSAENOTSOCK
					/* you'd think this would be EBADF */
					|| err == WSAENOTSOCK
#endif
				) {
					if (++ebadf < SLAPD_EBADF_LIMIT)
						continue;
				}

				if( err != EINTR ) {
#ifdef NEW_LOGGING
					LDAP_LOG( CONNECTION, INFO, 
						"slapd_daemon_task: select failed (%d): %s\n",
						err, sock_errstr(err), 0 );
#else
					Debug( LDAP_DEBUG_CONNS,
						"daemon: select failed (%d): %s\n",
						err, sock_errstr(err), 0 );
#endif
					slapd_shutdown = 2;
				}
			}
			continue;

		case 0:		/* timeout - let threads run */
			ebadf = 0;
#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, DETAIL2,
				   "slapd_daemon_task: select timeout - yielding\n", 0, 0, 0 );
#else
			Debug( LDAP_DEBUG_CONNS, "daemon: select timeout - yielding\n",
			    0, 0, 0 );
#endif
			ldap_pvt_thread_yield();
			continue;

		default:	/* something happened - deal with it */
			if( slapd_shutdown ) continue;

			ebadf = 0;
#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, DETAIL2, 
				   "slapd_daemon_task: activity on %d descriptors\n", ns, 0, 0 );
#else
			Debug( LDAP_DEBUG_CONNS, "daemon: activity on %d descriptors\n",
				ns, 0, 0 );
#endif
			/* FALL THRU */
		}

		if( FD_ISSET( wake_sds[0], &readfds ) ) {
			char c[BUFSIZ];
			tcp_read( wake_sds[0], c, sizeof(c) );
#if defined(NO_THREADS) || defined(HAVE_GNU_PTH)
			waking = 0;
#endif
			continue;
		}

		for ( l = 0; slap_listeners[l] != NULL; l++ ) {
			ber_socket_t s;
			socklen_t len = sizeof(from);
			long id;
			slap_ssf_t ssf = 0;
			char *authid = NULL;
#ifdef SLAPD_RLOOKUPS
			char hbuf[NI_MAXHOST];
#endif

			char	*dnsname = NULL;
			char	*peeraddr = NULL;
#ifdef LDAP_PF_LOCAL
			char	peername[MAXPATHLEN + sizeof("PATH=")];
#elif defined(LDAP_PF_INET6)
			char	peername[sizeof("IP=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535")];
#else
			char	peername[sizeof("IP=255.255.255.255:65336")];
#endif /* LDAP_PF_LOCAL */

			peername[0] = '\0';

			if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
				continue;

			if ( !FD_ISSET( slap_listeners[l]->sl_sd, &readfds ) )
				continue;

#ifdef LDAP_CONNECTIONLESS
			if ( slap_listeners[l]->sl_is_udp ) {
				/* The first time we receive a query, we set this
				 * up as a "connection". It remains open for the life
				 * of the slapd.
				 */
				if ( slap_listeners[l]->sl_is_udp < 2 ) {
				    id = connection_init(
					slap_listeners[l]->sl_sd,
				    	slap_listeners[l], "", "",
					2, ssf, authid );
				    slap_listeners[l]->sl_is_udp++;
				}
				continue;
			}
#endif

			/* Don't need to look at this in the data loops */
			FD_CLR( slap_listeners[l]->sl_sd, &readfds );
			FD_CLR( slap_listeners[l]->sl_sd, &writefds );

			s = accept( slap_listeners[l]->sl_sd,
				(struct sockaddr *) &from, &len );
			if ( s == AC_SOCKET_INVALID ) {
				int err = sock_errno();

				if(
#ifdef EMFILE
				    err == EMFILE ||
#endif
#ifdef ENFILE
				    err == ENFILE ||
#endif
				    0 )
				{
					ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
					emfile++;
					/* Stop listening until an existing session closes */
					slap_listeners[l]->sl_is_mute = 1;
					ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
				}

#ifdef NEW_LOGGING
				LDAP_LOG( CONNECTION, ERR, 
					"slapd_daemon_task: accept(%ld) failed errno=%d (%s)\n",
					(long)slap_listeners[l]->sl_sd, 
					err, sock_errstr(err) );
#else
				Debug( LDAP_DEBUG_ANY,
					"daemon: accept(%ld) failed errno=%d (%s)\n",
					(long) slap_listeners[l]->sl_sd, err,
					sock_errstr(err) );
#endif
				ldap_pvt_thread_yield();
				continue;
			}

#ifndef HAVE_WINSOCK
			/* make sure descriptor number isn't too great */
			if ( s >= dtblsize ) {
#ifdef NEW_LOGGING
				LDAP_LOG( CONNECTION, ERR, 
				   "slapd_daemon_task: %ld beyond descriptor table size %ld\n",
				   (long)s, (long)dtblsize, 0 );
#else
				Debug( LDAP_DEBUG_ANY,
					"daemon: %ld beyond descriptor table size %ld\n",
					(long) s, (long) dtblsize, 0 );
#endif

				slapd_close(s);
				ldap_pvt_thread_yield();
				continue;
			}
#endif

#ifdef LDAP_DEBUG
			ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );

			/* newly accepted stream should not be in any of the FD SETS */
			assert( !FD_ISSET( s, &slap_daemon.sd_actives) );
			assert( !FD_ISSET( s, &slap_daemon.sd_readers) );
			assert( !FD_ISSET( s, &slap_daemon.sd_writers) );

			ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
#endif

#if defined( SO_KEEPALIVE ) || defined( TCP_NODELAY )
#ifdef LDAP_PF_LOCAL
			/* for IPv4 and IPv6 sockets only */
			if ( from.sa_addr.sa_family != AF_LOCAL )
#endif /* LDAP_PF_LOCAL */
			{
				int rc;
				int tmp;
#ifdef SO_KEEPALIVE
				/* enable keep alives */
				tmp = 1;
				rc = setsockopt( s, SOL_SOCKET, SO_KEEPALIVE,
					(char *) &tmp, sizeof(tmp) );
				if ( rc == AC_SOCKET_ERROR ) {
					int err = sock_errno();
#ifdef NEW_LOGGING
					LDAP_LOG( CONNECTION, ERR, 
						"slapd_daemon_task: setsockopt( %ld, SO_KEEPALIVE)"
					   " failed errno=%d (%s)\n",
						(long)s, err, sock_errstr(err) );
#else
					Debug( LDAP_DEBUG_ANY,
						"slapd(%ld): setsockopt(SO_KEEPALIVE) failed "
						"errno=%d (%s)\n", (long) s, err, sock_errstr(err) );
#endif
				}
#endif
#ifdef TCP_NODELAY
				/* enable no delay */
				tmp = 1;
				rc = setsockopt( s, IPPROTO_TCP, TCP_NODELAY,
					(char *)&tmp, sizeof(tmp) );
				if ( rc == AC_SOCKET_ERROR ) {
					int err = sock_errno();
#ifdef NEW_LOGGING
					LDAP_LOG( CONNECTION, ERR, 
						"slapd_daemon_task: setsockopt( %ld, "
						"TCP_NODELAY) failed errno=%d (%s)\n",
						(long)s, err, sock_errstr(err) );
#else
					Debug( LDAP_DEBUG_ANY,
						"slapd(%ld): setsockopt(TCP_NODELAY) failed "
						"errno=%d (%s)\n", (long) s, err, sock_errstr(err) );
#endif
				}
#endif
			}
#endif

#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, DETAIL1, 
				"slapd_daemon_task: new connection on %ld\n", (long)s, 0, 0 );
#else
			Debug( LDAP_DEBUG_CONNS, "daemon: new connection on %ld\n",
				(long) s, 0, 0 );
#endif
			switch ( from.sa_addr.sa_family ) {
#  ifdef LDAP_PF_LOCAL
			case AF_LOCAL:
				sprintf( peername, "PATH=%s", from.sa_un_addr.sun_path );
				ssf = LDAP_PVT_SASL_LOCAL_SSF;
				{
					uid_t uid;
					gid_t gid;

					if( getpeereid( s, &uid, &gid ) == 0 ) {
						authid = ch_malloc(
							sizeof("uidnumber=4294967295+gidnumber=4294967295,"
								"cn=peercred,cn=external,cn=auth"));
						sprintf(authid, "uidnumber=%d+gidnumber=%d,"
							"cn=peercred,cn=external,cn=auth",
							(int) uid, (int) gid);
					}
				}
				dnsname = "local";
				break;
#endif /* LDAP_PF_LOCAL */

#  ifdef LDAP_PF_INET6
			case AF_INET6:
			if ( IN6_IS_ADDR_V4MAPPED(&from.sa_in6_addr.sin6_addr) ) {
				peeraddr = inet_ntoa( *((struct in_addr *)
							&from.sa_in6_addr.sin6_addr.s6_addr[12]) );
				sprintf( peername, "IP=%s:%d",
					 peeraddr != NULL ? peeraddr : SLAP_STRING_UNKNOWN,
					 (unsigned) ntohs( from.sa_in6_addr.sin6_port ) );
			} else {
				char addr[INET6_ADDRSTRLEN];

				peeraddr = (char *) inet_ntop( AF_INET6,
						      &from.sa_in6_addr.sin6_addr,
						      addr, sizeof addr );
				sprintf( peername, "IP=%s %d",
					 peeraddr != NULL ? peeraddr : SLAP_STRING_UNKNOWN,
					 (unsigned) ntohs( from.sa_in6_addr.sin6_port ) );
			}
			break;
#  endif /* LDAP_PF_INET6 */

			case AF_INET:
			peeraddr = inet_ntoa( from.sa_in_addr.sin_addr );
			sprintf( peername, "IP=%s:%d",
				peeraddr != NULL ? peeraddr : SLAP_STRING_UNKNOWN,
				(unsigned) ntohs( from.sa_in_addr.sin_port ) );
				break;

			default:
				slapd_close(s);
				continue;
			}

			if ( ( from.sa_addr.sa_family == AF_INET )
#ifdef LDAP_PF_INET6
				|| ( from.sa_addr.sa_family == AF_INET6 )
#endif
			) {
#ifdef SLAPD_RLOOKUPS
				if ( use_reverse_lookup ) {
					char *herr;
					if (ldap_pvt_get_hname( (const struct sockaddr *)&from, len, hbuf,
						sizeof(hbuf), &herr ) == 0) {
						ldap_pvt_str2lower( hbuf );
						dnsname = hbuf;
					}
				}
#else
				dnsname = NULL;
#endif /* SLAPD_RLOOKUPS */

#ifdef HAVE_TCPD
				if ( !hosts_ctl("slapd",
						dnsname != NULL ? dnsname : SLAP_STRING_UNKNOWN,
						peeraddr != NULL ? peeraddr : SLAP_STRING_UNKNOWN,
						SLAP_STRING_UNKNOWN ))
				{
					/* DENY ACCESS */
					Statslog( LDAP_DEBUG_STATS,
						"fd=%ld DENIED from %s (%s)\n",
						(long) s,
						dnsname != NULL ? dnsname : SLAP_STRING_UNKNOWN,
						peeraddr != NULL ? peeraddr : SLAP_STRING_UNKNOWN,
						0, 0 );
					slapd_close(s);
					continue;
				}
#endif /* HAVE_TCPD */
			}

			id = connection_init(s,
				slap_listeners[l],
				dnsname != NULL ? dnsname : SLAP_STRING_UNKNOWN,
				peername,
#ifdef HAVE_TLS
				slap_listeners[l]->sl_is_tls,
#else
				0,
#endif
				ssf,
				authid );

			if( authid ) ch_free(authid);

			if( id < 0 ) {
#ifdef NEW_LOGGING
				LDAP_LOG( CONNECTION, INFO, 
					"slapd_daemon_task: "
					"connection_init(%ld, %s, %s) "
					"failed.\n",
					(long)s, peername, 
					slap_listeners[l]->sl_name.bv_val );
#else
				Debug( LDAP_DEBUG_ANY,
					"daemon: connection_init(%ld, %s, %s) "
					"failed.\n",
					(long) s,
					peername,
					slap_listeners[l]->sl_name.bv_val );
#endif
				slapd_close(s);
				continue;
			}

			Statslog( LDAP_DEBUG_STATS,
				"conn=%ld fd=%ld ACCEPT from %s (%s)\n",
				id, (long) s,
				peername,
				slap_listeners[l]->sl_name.bv_val,
				0 );

			slapd_add( s );
			continue;
		}

#ifdef LDAP_DEBUG
#ifdef NEW_LOGGING
		LDAP_LOG( CONNECTION, DETAIL2,
			   "slapd_daemon_task: activity on ", 0, 0, 0 );
#else
		Debug( LDAP_DEBUG_CONNS, "daemon: activity on:", 0, 0, 0 );
#endif
#ifdef HAVE_WINSOCK
		for ( i = 0; i < readfds.fd_count; i++ ) {
#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, DETAIL2, 
				" %d%s", readfds.fd_array[i], "r", 0, 0 );
#else
			Debug( LDAP_DEBUG_CONNS, " %d%s",
				readfds.fd_array[i], "r", 0 );
#endif
		}
		for ( i = 0; i < writefds.fd_count; i++ ) {
#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, DETAIL2, 
				" %d%s", writefds.fd_array[i], "w" , 0 );
#else
			Debug( LDAP_DEBUG_CONNS, " %d%s",
				writefds.fd_array[i], "w", 0 );
#endif
		}

#else
		for ( i = 0; i < nfds; i++ ) {
			int	r, w;

			r = FD_ISSET( i, &readfds );
			w = FD_ISSET( i, &writefds );
			if ( r || w ) {
#ifdef NEW_LOGGING
				LDAP_LOG( CONNECTION, DETAIL2, 
					" %d%s%s", i, r ? "r" : "", w ? "w" : "" );
#else
				Debug( LDAP_DEBUG_CONNS, " %d%s%s", i,
				    r ? "r" : "", w ? "w" : "" );
#endif
			}
		}
#endif
#ifdef NEW_LOGGING
		LDAP_LOG( CONNECTION, DETAIL2, "\n", 0, 0, 0 );
#else
		Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
#endif

#endif

		/* loop through the writers */
#ifdef HAVE_WINSOCK
		for ( i = 0; i < writefds.fd_count; i++ )
#else
		for ( i = 0; i < nfds; i++ )
#endif
		{
			ber_socket_t wd;
#ifdef HAVE_WINSOCK
			wd = writefds.fd_array[i];
#else
			if( ! FD_ISSET( i, &writefds ) ) {
				continue;
			}
			wd = i;
#endif

#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, DETAIL2, 
				"slapd_daemon_task: write active on %d\n", wd, 0, 0 );
#else
			Debug( LDAP_DEBUG_CONNS,
				"daemon: write active on %d\n",
				wd, 0, 0 );
#endif
			/*
			 * NOTE: it is possible that the connection was closed
			 * and that the stream is now inactive.
			 * connection_write() must valid the stream is still
			 * active.
			 */

			if ( connection_write( wd ) < 0 ) {
				FD_CLR( (unsigned) wd, &readfds );
				slapd_close( wd );
			}
		}

#ifdef HAVE_WINSOCK
		for ( i = 0; i < readfds.fd_count; i++ )
#else
		for ( i = 0; i < nfds; i++ )
#endif
		{
			ber_socket_t rd;
#ifdef HAVE_WINSOCK
			rd = readfds.fd_array[i];
#else
			if( ! FD_ISSET( i, &readfds ) ) {
				continue;
			}
			rd = i;
#endif

#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, DETAIL2, 
				"slapd_daemon_task: read activity on %d\n", rd, 0, 0 );
#else
			Debug ( LDAP_DEBUG_CONNS,
				"daemon: read activity on %d\n", rd, 0, 0 );
#endif
			/*
			 * NOTE: it is possible that the connection was closed
			 * and that the stream is now inactive.
			 * connection_read() must valid the stream is still
			 * active.
			 */

			if ( connection_read( rd ) < 0 ) {
				slapd_close( rd );
			}
		}
		ldap_pvt_thread_yield();
	}

	if( slapd_shutdown == 1 ) {
#ifdef NEW_LOGGING
		LDAP_LOG( CONNECTION, CRIT,
		   "slapd_daemon_task: shutdown requested and initiated.\n", 0, 0, 0 );
#else
		Debug( LDAP_DEBUG_TRACE,
			"daemon: shutdown requested and initiated.\n",
			0, 0, 0 );
#endif

	} else if ( slapd_shutdown == 2 ) {
#ifdef HAVE_NT_SERVICE_MANAGER
#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, CRIT,
			   "slapd_daemon_task: shutdown initiated by Service Manager.\n",
			   0, 0, 0);
#else
			Debug( LDAP_DEBUG_TRACE,
			       "daemon: shutdown initiated by Service Manager.\n",
			       0, 0, 0);
#endif
#else /* !HAVE_NT_SERVICE_MANAGER */
#ifdef NEW_LOGGING
			LDAP_LOG( CONNECTION, CRIT,
			   "slapd_daemon_task: abnormal condition, "
			   "shutdown initiated.\n", 0, 0, 0 );
#else
			Debug( LDAP_DEBUG_TRACE,
			       "daemon: abnormal condition, shutdown initiated.\n",
			       0, 0, 0 );
#endif
#endif /* !HAVE_NT_SERVICE_MANAGER */
	} else {
#ifdef NEW_LOGGING
		LDAP_LOG( CONNECTION, CRIT,
		   "slapd_daemon_task: no active streams, shutdown initiated.\n", 
		   0, 0, 0 );
#else
		Debug( LDAP_DEBUG_TRACE,
		       "daemon: no active streams, shutdown initiated.\n",
		       0, 0, 0 );
#endif
	}

	if( slapd_gentle_shutdown != 2 ) {
		close_listeners ( 0 );
	}

	free ( slap_listeners );
	slap_listeners = NULL;

	if( !slapd_gentle_shutdown ) {
		connections_shutdown();
	}

#ifdef NEW_LOGGING
	LDAP_LOG( CONNECTION, CRIT, 
		"slapd_daemon_task: shutdown waiting for %d threads to terminate.\n",
		ldap_pvt_thread_pool_backload(&connection_pool), 0, 0 );
#else
	Debug( LDAP_DEBUG_ANY,
	    "slapd shutdown: waiting for %d threads to terminate\n",
	    ldap_pvt_thread_pool_backload(&connection_pool), 0, 0 );
#endif
	ldap_pvt_thread_pool_destroy(&connection_pool, 1);

	return NULL;
}
Exemplo n.º 25
0
meta_search_candidate_t
asyncmeta_dobind_result(
	a_metaconn_t		*mc,
	int			candidate,
	SlapReply		*bind_result,
	LDAPMessage		*res )
{
	a_metainfo_t		*mi = mc->mc_info;
	a_metatarget_t		*mt = mi->mi_targets[ candidate ];
	a_metasingleconn_t	*msc = &mc->mc_conns[ candidate ];

	meta_search_candidate_t	retcode = META_SEARCH_NOT_CANDIDATE;
	int			rc;

	assert( msc->msc_ldr != NULL );

	if ( mi->mi_idle_timeout != 0 ) {
		asyncmeta_set_msc_time(msc);
	}

	if ( LogTest( asyncmeta_debug ) ) {
		char	time_buf[ SLAP_TEXT_BUFLEN ];
		asyncmeta_get_timestamp(time_buf);
		Debug( asyncmeta_debug, "[%x] [%s] asyncmeta_dobind_result msc: %p, "
		       "msc->msc_binding_time: %x, msc->msc_flags:%x\n ",
		       (unsigned int)slap_get_time(), time_buf, msc,
		       (unsigned int)msc->msc_binding_time, msc->msc_mscflags );
	}
	/* FIXME: matched? referrals? response controls? */
	rc = ldap_parse_result( msc->msc_ldr, res,
				&(bind_result->sr_err),
				(char **)&(bind_result->sr_matched),
				(char **)&(bind_result->sr_text),
				NULL, NULL, 0 );

	if ( LogTest( asyncmeta_debug ) ) {
		char	time_buf[ SLAP_TEXT_BUFLEN ];
		asyncmeta_get_timestamp(time_buf);
		Debug( asyncmeta_debug,
		       "[%s] asyncmeta_dobind_result error=%d msc: %p\n",
		       time_buf,bind_result->sr_err, msc );
	}

	if ( rc != LDAP_SUCCESS ) {
		bind_result->sr_err = rc;
	}
	rc = slap_map_api2result( bind_result );

	LDAP_BACK_CONN_BINDING_CLEAR( msc );
	if ( rc != LDAP_SUCCESS ) {
		bind_result->sr_err = rc;
	} else {
		/* FIXME: check if bound as idassert authcDN! */
		if ( BER_BVISNULL( &msc->msc_bound_ndn )
			|| BER_BVISEMPTY( &msc->msc_bound_ndn ) )
		{
			LDAP_BACK_CONN_ISANON_SET( msc );
			if ( LogTest( asyncmeta_debug ) ) {
				char	time_buf[ SLAP_TEXT_BUFLEN ];
				asyncmeta_get_timestamp(time_buf);
				Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result anonymous msc: %p\n",
				      time_buf, msc );
			}

		} else {
			if ( META_BACK_TGT_SAVECRED( mt ) &&
				!BER_BVISNULL( &msc->msc_cred ) &&
				!BER_BVISEMPTY( &msc->msc_cred ) )
			{
				ldap_set_rebind_proc( msc->msc_ldr, mt->mt_rebind_f, msc );
			}
			if ( LogTest( asyncmeta_debug ) ) {
				char	time_buf[ SLAP_TEXT_BUFLEN ];
				asyncmeta_get_timestamp(time_buf);
				Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_result success msc: %p\n",
				      time_buf, msc );
			}
			LDAP_BACK_CONN_ISBOUND_SET( msc );
		}
		retcode = META_SEARCH_CANDIDATE;
	}
	return retcode;
}
Exemplo n.º 26
0
int
slapadd( int argc, char **argv )
{
	char *buf = NULL;
	const char *text;
	char textbuf[SLAP_TEXT_BUFLEN] = { '\0' };
	size_t textlen = sizeof textbuf;
	const char *progname = "slapadd";

	struct berval csn;
	struct berval maxcsn[ SLAP_SYNC_SID_MAX + 1 ];
	unsigned long sid;
	struct berval bvtext;
	Attribute *attr;
	Entry *ctxcsn_e;
	ID	ctxcsn_id, id;
	OperationBuffer opbuf;
	Operation *op;

	int match;
	int checkvals;
	int lineno, nextline;
	int lmax;
	int rc = EXIT_SUCCESS;
	int manage = 0;	

	/* default "000" */
	csnsid = 0;

	slap_tool_init( progname, SLAPADD, argc, argv );

	memset( &opbuf, 0, sizeof(opbuf) );
	op = &opbuf.ob_op;
	op->o_hdr = &opbuf.ob_hdr;

	if( !be->be_entry_open ||
		!be->be_entry_close ||
		!be->be_entry_put ||
		(update_ctxcsn &&
		 (!be->be_dn2id_get ||
		  !be->be_entry_get ||
		  !be->be_entry_modify)) )
	{
		fprintf( stderr, "%s: database doesn't support necessary operations.\n",
			progname );
		if ( dryrun ) {
			fprintf( stderr, "\t(dry) continuing...\n" );

		} else {
			exit( EXIT_FAILURE );
		}
	}

	checkvals = (slapMode & SLAP_TOOL_QUICK) ? 0 : 1;

	lmax = 0;
	nextline = 0;

	/* enforce schema checking unless not disabled */
	if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) {
		SLAP_DBFLAGS(be) &= ~(SLAP_DBFLAG_NO_SCHEMA_CHECK);
	}

	if( !dryrun && be->be_entry_open( be, 1 ) != 0 ) {
		fprintf( stderr, "%s: could not open database.\n",
			progname );
		exit( EXIT_FAILURE );
	}

	if ( update_ctxcsn ) {
		maxcsn[ 0 ].bv_val = maxcsnbuf;
		for ( sid = 1; sid <= SLAP_SYNC_SID_MAX; sid++ ) {
			maxcsn[ sid ].bv_val = maxcsn[ sid - 1 ].bv_val + LDAP_LUTIL_CSNSTR_BUFSIZE;
			maxcsn[ sid ].bv_len = 0;
		}
	}

	/* nextline is the line number of the end of the current entry */
	for( lineno=1; ldif_read_record( ldiffp, &nextline, &buf, &lmax );
		lineno=nextline+1 ) {
		Entry *e;

		if ( lineno < jumpline )
			continue;

		e = str2entry2( buf, checkvals );

		/*
		 * Initialize text buffer
		 */
		bvtext.bv_len = textlen;
		bvtext.bv_val = textbuf;
		bvtext.bv_val[0] = '\0';

		if( e == NULL ) {
			fprintf( stderr, "%s: could not parse entry (line=%d)\n",
				progname, lineno );
			rc = EXIT_FAILURE;
			if( continuemode ) continue;
			break;
		}

		/* make sure the DN is not empty */
		if( BER_BVISEMPTY( &e->e_nname ) &&
			!BER_BVISEMPTY( be->be_nsuffix )) {
			fprintf( stderr, "%s: empty dn=\"%s\" (line=%d)\n",
				progname, e->e_dn, lineno );
			rc = EXIT_FAILURE;
			entry_free( e );
			if( continuemode ) continue;
			break;
		}

		/* check backend */
		if( select_backend( &e->e_nname, nosubordinates )
			!= be )
		{
			fprintf( stderr, "%s: line %d: "
				"database (%s) not configured to hold \"%s\"\n",
				progname, lineno,
				be ? be->be_suffix[0].bv_val : "<none>",
				e->e_dn );
			fprintf( stderr, "%s: line %d: "
				"database (%s) not configured to hold \"%s\"\n",
				progname, lineno,
				be ? be->be_nsuffix[0].bv_val : "<none>",
				e->e_ndn );
			rc = EXIT_FAILURE;
			entry_free( e );
			if( continuemode ) continue;
			break;
		}

		{
			Attribute *oc = attr_find( e->e_attrs,
				slap_schema.si_ad_objectClass );

			if( oc == NULL ) {
				fprintf( stderr, "%s: dn=\"%s\" (line=%d): %s\n",
					progname, e->e_dn, lineno,
					"no objectClass attribute");
				rc = EXIT_FAILURE;
				entry_free( e );
				if( continuemode ) continue;
				break;
			}

			/* check schema */
			op->o_bd = be;

			if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) {
				rc = entry_schema_check( op, e, NULL, manage, 1,
					&text, textbuf, textlen );

				if( rc != LDAP_SUCCESS ) {
					fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n",
						progname, e->e_dn, lineno, rc, text );
					rc = EXIT_FAILURE;
					entry_free( e );
					if( continuemode ) continue;
					break;
				}
				textbuf[ 0 ] = '\0';
			}
		}

		if ( SLAP_LASTMOD(be) ) {
			time_t now = slap_get_time();
			char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
			struct berval vals[ 2 ];

			struct berval name, timestamp;

			struct berval nvals[ 2 ];
			struct berval nname;
			char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];

			vals[1].bv_len = 0;
			vals[1].bv_val = NULL;

			nvals[1].bv_len = 0;
			nvals[1].bv_val = NULL;

			csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), csnsid, 0 );
			csn.bv_val = csnbuf;

			timestamp.bv_val = timebuf;
			timestamp.bv_len = sizeof(timebuf);

			slap_timestamp( &now, &timestamp );

			if ( BER_BVISEMPTY( &be->be_rootndn ) ) {
				BER_BVSTR( &name, SLAPD_ANONYMOUS );
				nname = name;
			} else {
				name = be->be_rootdn;
				nname = be->be_rootndn;
			}

			if( attr_find( e->e_attrs, slap_schema.si_ad_entryUUID )
				== NULL )
			{
				vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
				vals[0].bv_val = uuidbuf;
				attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, vals, NULL );
			}

			if( attr_find( e->e_attrs, slap_schema.si_ad_creatorsName )
				== NULL )
			{
				vals[0] = name;
				nvals[0] = nname;
				attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals );
			}

			if( attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp )
				== NULL )
			{
				vals[0] = timestamp;
				attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL );
			}

			if( attr_find( e->e_attrs, slap_schema.si_ad_entryCSN )
				== NULL )
			{
				vals[0] = csn;
				attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL );
			}

			if( attr_find( e->e_attrs, slap_schema.si_ad_modifiersName )
				== NULL )
			{
				vals[0] = name;
				nvals[0] = nname;
				attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals );
			}

			if( attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp )
				== NULL )
			{
				vals[0] = timestamp;
				attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL );
			}

			if ( update_ctxcsn ) {
				int rc_sid;

				attr = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN );
				assert( attr != NULL );

				rc_sid = slap_parse_csn_sid( &attr->a_nvals[ 0 ] );
				if ( rc_sid < 0 ) {
					Debug( LDAP_DEBUG_ANY, "%s: could not "
						"extract SID from entryCSN=%s\n",
						progname, attr->a_nvals[ 0 ].bv_val, 0 );

				} else {
					assert( rc_sid <= SLAP_SYNC_SID_MAX );

					sid = (unsigned)rc_sid;
					if ( maxcsn[ sid ].bv_len != 0 ) {
						match = 0;
						value_match( &match, slap_schema.si_ad_entryCSN,
							slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
							SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
							&maxcsn[ sid ], &attr->a_nvals[0], &text );
					} else {
						match = -1;
					}
					if ( match < 0 ) {
						strcpy( maxcsn[ sid ].bv_val, attr->a_nvals[0].bv_val );
						maxcsn[ sid ].bv_len = attr->a_nvals[0].bv_len;
					}
				}
			}
		}

		if ( !dryrun ) {
			id = be->be_entry_put( be, e, &bvtext );
			if( id == NOID ) {
				fprintf( stderr, "%s: could not add entry dn=\"%s\" "
								 "(line=%d): %s\n", progname, e->e_dn,
								 lineno, bvtext.bv_val );
				rc = EXIT_FAILURE;
				entry_free( e );
				if( continuemode ) continue;
				break;
			}
			if ( verbose )
				fprintf( stderr, "added: \"%s\" (%08lx)\n",
					e->e_dn, (long) id );
		} else {
			if ( verbose )
				fprintf( stderr, "added: \"%s\"\n",
					e->e_dn );
		}

		entry_free( e );
	}

	bvtext.bv_len = textlen;
	bvtext.bv_val = textbuf;
	bvtext.bv_val[0] = '\0';

	if ( rc == EXIT_SUCCESS && update_ctxcsn && !dryrun && sid != SLAP_SYNC_SID_MAX + 1 ) {
		ctxcsn_id = be->be_dn2id_get( be, be->be_nsuffix );
		if ( ctxcsn_id == NOID ) {
			fprintf( stderr, "%s: context entry is missing\n", progname );
			rc = EXIT_FAILURE;
		} else {
			ctxcsn_e = be->be_entry_get( be, ctxcsn_id );
			if ( ctxcsn_e != NULL ) {
				Entry *e = entry_dup( ctxcsn_e );
				int change;
				attr = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN );
				if ( attr ) {
					int		i;

					change = 0;

					for ( i = 0; !BER_BVISNULL( &attr->a_nvals[ i ] ); i++ ) {
						int rc_sid;

						rc_sid = slap_parse_csn_sid( &attr->a_nvals[ i ] );
						if ( rc_sid < 0 ) {
							Debug( LDAP_DEBUG_ANY,
								"%s: unable to extract SID "
								"from #%d contextCSN=%s\n",
								progname, i,
								attr->a_nvals[ i ].bv_val );
							continue;
						}

						assert( rc_sid <= SLAP_SYNC_SID_MAX );

						sid = (unsigned)rc_sid;

						if ( maxcsn[ sid ].bv_len == 0 ) {
							match = -1;

						} else {
							value_match( &match, slap_schema.si_ad_entryCSN,
								slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
								SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
								&maxcsn[ sid ], &attr->a_nvals[i], &text );
						}

						if ( match > 0 ) {
							change = 1;
						} else {
							AC_MEMCPY( maxcsn[ sid ].bv_val,
								attr->a_nvals[ i ].bv_val,
								attr->a_nvals[ i ].bv_len );
							maxcsn[ sid ].bv_val[ attr->a_nvals[ i ].bv_len ] = '\0';
							maxcsn[ sid ].bv_len = attr->a_nvals[ i ].bv_len;
						}
					}

					if ( change ) {
						if ( attr->a_nvals != attr->a_vals ) {
							ber_bvarray_free( attr->a_nvals );
						}
						attr->a_nvals = NULL;
						ber_bvarray_free( attr->a_vals );
						attr->a_vals = NULL;
						attr->a_numvals = 0;
					}
				} else {
					change = 1;
				}

				if ( change ) {
					for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) {
						if ( maxcsn[ sid ].bv_len ) {
							attr_merge_one( e, slap_schema.si_ad_contextCSN,
								&maxcsn[ sid], NULL );
						}
					}

					ctxcsn_id = be->be_entry_modify( be, e, &bvtext );
					if( ctxcsn_id == NOID ) {
						fprintf( stderr, "%s: could not modify ctxcsn\n",
							progname);
						rc = EXIT_FAILURE;
					} else if ( verbose ) {
						fprintf( stderr, "modified: \"%s\" (%08lx)\n",
							e->e_dn, (long) ctxcsn_id );
					}
				}
				entry_free( e );
			}
		} 
	}

	ch_free( buf );

	if ( !dryrun ) {
		if( be->be_entry_close( be ) ) {
			rc = EXIT_FAILURE;
		}

		if( be->be_sync ) {
			be->be_sync( be );
		}
	}

	slap_tool_destroy();

	return rc;
}
Exemplo n.º 27
0
static int auditlog_response(Operation *op, SlapReply *rs) {
	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
	auditlog_data *ad = on->on_bi.bi_private;
	FILE *f;
	Attribute *a;
	Modifications *m;
	struct berval *b, *who = NULL, peername;
	char *what, *whatm, *suffix;
	time_t stamp;
	int i;

	if ( rs->sr_err != LDAP_SUCCESS ) return SLAP_CB_CONTINUE;

	if ( !ad->ad_logfile ) return SLAP_CB_CONTINUE;

/*
** add or modify: use modifiersName if present
**
*/
	switch(op->o_tag) {
		case LDAP_REQ_MODRDN:	what = "modrdn";	break;
		case LDAP_REQ_DELETE:	what = "delete";	break;
		case LDAP_REQ_ADD:
			what = "add";
			for(a = op->ora_e->e_attrs; a; a = a->a_next)
				if( a->a_desc == slap_schema.si_ad_modifiersName ) {
					who = &a->a_vals[0];
					break;
				}
			break;
		case LDAP_REQ_MODIFY:
			what = "modify";
			for(m = op->orm_modlist; m; m = m->sml_next)
				if( m->sml_desc == slap_schema.si_ad_modifiersName &&
					( m->sml_op == LDAP_MOD_ADD ||
					m->sml_op == LDAP_MOD_REPLACE )) {
					who = &m->sml_values[0];
					break;
				}
			break;
		default:
			return SLAP_CB_CONTINUE;
	}

	suffix = op->o_bd->be_suffix[0].bv_len ? op->o_bd->be_suffix[0].bv_val :
		"global";

/*
** note: this means requestor's dn when modifiersName is null
*/
	if ( !who )
		who = &op->o_dn;

	peername = op->o_conn->c_peer_name;
	ldap_pvt_thread_mutex_lock(&ad->ad_mutex);
	if((f = fopen(ad->ad_logfile, "a")) == NULL) {
		ldap_pvt_thread_mutex_unlock(&ad->ad_mutex);
		return SLAP_CB_CONTINUE;
	}

	stamp = slap_get_time();
	fprintf(f, "# %s %ld %s%s%s %s conn=%ld\n",
		what, (long)stamp, suffix, who ? " " : "", who ? who->bv_val : "",
		peername.bv_val ? peername.bv_val: "", op->o_conn->c_connid);

	if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) &&
		(!who || !dn_match( who, &op->o_conn->c_dn )))
		fprintf(f, "# realdn: %s\n", op->o_conn->c_dn.bv_val );

	fprintf(f, "dn: %s\nchangetype: %s\n",
		op->o_req_dn.bv_val, what);

	switch(op->o_tag) {
	  case LDAP_REQ_ADD:
		for(a = op->ora_e->e_attrs; a; a = a->a_next)
		  if((b = a->a_vals) != NULL)
			for(i = 0; b[i].bv_val; i++)
				fprint_ldif(f, a->a_desc->ad_cname.bv_val, b[i].bv_val, b[i].bv_len);
		break;

	  case LDAP_REQ_MODIFY:
		for(m = op->orm_modlist; m; m = m->sml_next) {
			switch(m->sml_op & LDAP_MOD_OP) {
				case LDAP_MOD_ADD:	 whatm = "add";		break;
				case LDAP_MOD_REPLACE:	 whatm = "replace";	break;
				case LDAP_MOD_DELETE:	 whatm = "delete";	break;
				case LDAP_MOD_INCREMENT: whatm = "increment";	break;
				default:
					fprintf(f, "# MOD_TYPE_UNKNOWN:%02x\n", m->sml_op & LDAP_MOD_OP);
					continue;
			}
			fprintf(f, "%s: %s\n", whatm, m->sml_desc->ad_cname.bv_val);
			if((b = m->sml_values) != NULL)
			  for(i = 0; b[i].bv_val; i++)
				fprint_ldif(f, m->sml_desc->ad_cname.bv_val, b[i].bv_val, b[i].bv_len);
			fprintf(f, "-\n");
		}
		break;

	  case LDAP_REQ_MODRDN:
		fprintf(f, "newrdn: %s\ndeleteoldrdn: %s\n",
			op->orr_newrdn.bv_val, op->orr_deleteoldrdn ? "1" : "0");
		if(op->orr_newSup) fprintf(f, "newsuperior: %s\n", op->orr_newSup->bv_val);
		break;

	  case LDAP_REQ_DELETE:
		/* nothing else needed */
		break;
	}

	fprintf(f, "# end %s %ld\n\n", what, (long)stamp);

	fclose(f);
	ldap_pvt_thread_mutex_unlock(&ad->ad_mutex);
	return SLAP_CB_CONTINUE;
}
Exemplo n.º 28
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->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 );
	}

	return rs->sr_err;
}
Exemplo n.º 29
0
int
mdb_search( Operation *op, SlapReply *rs )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
	ID		id, cursor, nsubs, ncand, cscope;
	ID		lastid = NOID;
	ID		candidates[MDB_IDL_UM_SIZE];
	ID		iscopes[MDB_IDL_DB_SIZE];
	ID2		*scopes;
	void	*stack;
	Entry		*e = NULL, *base = NULL;
	Entry		*matched = NULL;
	AttributeName	*attrs;
	slap_mask_t	mask;
	time_t		stoptime;
	int		manageDSAit;
	int		tentries = 0;
	IdScopes	isc;
	MDB_cursor	*mci, *mcd;
	ww_ctx wwctx;
	slap_callback cb = { 0 };

	mdb_op_info	opinfo = {{{0}}}, *moi = &opinfo;
	MDB_txn			*ltid = NULL;

	Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_search) "\n", 0, 0, 0);
	attrs = op->oq_search.rs_attrs;

	manageDSAit = get_manageDSAit( op );

	rs->sr_err = mdb_opinfo_get( op, mdb, 1, &moi );
	switch(rs->sr_err) {
	case 0:
		break;
	default:
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
		return rs->sr_err;
	}

	ltid = moi->moi_txn;

	rs->sr_err = mdb_cursor_open( ltid, mdb->mi_id2entry, &mci );
	if ( rs->sr_err ) {
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
		return rs->sr_err;
	}

	rs->sr_err = mdb_cursor_open( ltid, mdb->mi_dn2id, &mcd );
	if ( rs->sr_err ) {
		mdb_cursor_close( mci );
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
		return rs->sr_err;
	}

	scopes = scope_chunk_get( op );
	stack = search_stack( op );
	isc.mt = ltid;
	isc.mc = mcd;
	isc.scopes = scopes;
	isc.oscope = op->ors_scope;
	isc.sctmp = stack;

	if ( op->ors_deref & LDAP_DEREF_FINDING ) {
		MDB_IDL_ZERO(candidates);
	}
dn2entry_retry:
	/* get entry with reader lock */
	rs->sr_err = mdb_dn2entry( op, ltid, mcd, &op->o_req_ndn, &e, &nsubs, 1 );

	switch(rs->sr_err) {
	case MDB_NOTFOUND:
		matched = e;
		e = NULL;
		break;
	case 0:
		break;
	case LDAP_BUSY:
		send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" );
		goto done;
	default:
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
		goto done;
	}

	if ( op->ors_deref & LDAP_DEREF_FINDING ) {
		if ( matched && is_entry_alias( matched )) {
			struct berval stub;

			stub.bv_val = op->o_req_ndn.bv_val;
			stub.bv_len = op->o_req_ndn.bv_len - matched->e_nname.bv_len - 1;
			e = deref_base( op, rs, matched, &matched, ltid,
				candidates, NULL );
			if ( e ) {
				build_new_dn( &op->o_req_ndn, &e->e_nname, &stub,
					op->o_tmpmemctx );
				mdb_entry_return(op, e);
				matched = NULL;
				goto dn2entry_retry;
			}
		} else if ( e && is_entry_alias( e )) {
			e = deref_base( op, rs, e, &matched, ltid,
				candidates, NULL );
		}
	}

	if ( e == NULL ) {
		struct berval matched_dn = BER_BVNULL;

		if ( matched != NULL ) {
			BerVarray erefs = NULL;

			/* return referral only if "disclose"
			 * is granted on the object */
			if ( ! access_allowed( op, matched,
						slap_schema.si_ad_entry,
						NULL, ACL_DISCLOSE, NULL ) )
			{
				rs->sr_err = LDAP_NO_SUCH_OBJECT;

			} else {
				ber_dupbv( &matched_dn, &matched->e_name );

				erefs = is_entry_referral( matched )
					? get_entry_referrals( op, matched )
					: NULL;
				if ( rs->sr_err == MDB_NOTFOUND )
					rs->sr_err = LDAP_REFERRAL;
				rs->sr_matched = matched_dn.bv_val;
			}

			mdb_entry_return(op, matched);
			matched = NULL;

			if ( erefs ) {
				rs->sr_ref = referral_rewrite( erefs, &matched_dn,
					&op->o_req_dn, op->oq_search.rs_scope );
				ber_bvarray_free( erefs );
			}

		} else {
			rs->sr_ref = referral_rewrite( default_referral,
				NULL, &op->o_req_dn, op->oq_search.rs_scope );
			rs->sr_err = rs->sr_ref != NULL ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT;
		}

		send_ldap_result( op, rs );

		if ( rs->sr_ref ) {
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;
		}
		if ( !BER_BVISNULL( &matched_dn ) ) {
			ber_memfree( matched_dn.bv_val );
			rs->sr_matched = NULL;
		}
		goto done;
	}

	/* NOTE: __NEW__ "search" access is required
	 * on searchBase object */
	if ( ! access_allowed_mask( op, e, slap_schema.si_ad_entry,
				NULL, ACL_SEARCH, NULL, &mask ) )
	{
		if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
			rs->sr_err = LDAP_NO_SUCH_OBJECT;
		} else {
			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		}

		mdb_entry_return( op,e);
		send_ldap_result( op, rs );
		goto done;
	}

	if ( !manageDSAit && is_entry_referral( e ) ) {
		/* entry is a referral */
		struct berval matched_dn = BER_BVNULL;
		BerVarray erefs = NULL;
		
		ber_dupbv( &matched_dn, &e->e_name );
		erefs = get_entry_referrals( op, e );

		rs->sr_err = LDAP_REFERRAL;

		mdb_entry_return( op, e );
		e = NULL;

		if ( erefs ) {
			rs->sr_ref = referral_rewrite( erefs, &matched_dn,
				&op->o_req_dn, op->oq_search.rs_scope );
			ber_bvarray_free( erefs );

			if ( !rs->sr_ref ) {
				rs->sr_text = "bad_referral object";
			}
		}

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

		rs->sr_matched = matched_dn.bv_val;
		send_ldap_result( op, rs );

		ber_bvarray_free( rs->sr_ref );
		rs->sr_ref = NULL;
		ber_memfree( matched_dn.bv_val );
		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;
		mdb_entry_return( op,e);
		send_ldap_result( op, rs );
		goto done;
	}

	/* compute it anyway; root does not use it */
	stoptime = op->o_time + op->ors_tlimit;

	base = e;

	e = NULL;

	/* select candidates */
	if ( op->oq_search.rs_scope == LDAP_SCOPE_BASE ) {
		rs->sr_err = base_candidate( op->o_bd, base, candidates );
		scopes[0].mid = 0;
		ncand = 1;
	} else {
		if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) {
			size_t nkids;
			MDB_val key, data;
			key.mv_data = &base->e_id;
			key.mv_size = sizeof( ID );
			mdb_cursor_get( mcd, &key, &data, MDB_SET );
			mdb_cursor_count( mcd, &nkids );
			nsubs = nkids - 1;
		} else if ( !base->e_id ) {
			/* we don't maintain nsubs for entryID 0.
			 * just grab entry count from id2entry stat
			 */
			MDB_stat ms;
			mdb_stat( ltid, mdb->mi_id2entry, &ms );
			nsubs = ms.ms_entries;
		}
		MDB_IDL_ZERO( candidates );
		scopes[0].mid = 1;
		scopes[1].mid = base->e_id;
		scopes[1].mval.mv_data = NULL;
		rs->sr_err = search_candidates( op, rs, base,
			&isc, mci, candidates, stack );
		ncand = MDB_IDL_N( candidates );
		if ( !base->e_id || ncand == NOID ) {
			/* grab entry count from id2entry stat
			 */
			MDB_stat ms;
			mdb_stat( ltid, mdb->mi_id2entry, &ms );
			if ( !base->e_id )
				nsubs = ms.ms_entries;
			if ( ncand == NOID )
				ncand = ms.ms_entries;
		}
	}

	/* start cursor at beginning of candidates.
	 */
	cursor = 0;

	if ( candidates[0] == 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_search) ": no candidates\n",
			0, 0, 0 );

		goto nochange;
	}

	/* if not root and candidates exceed to-be-checked entries, abort */
	if ( op->ors_limit	/* isroot == FALSE */ &&
		op->ors_limit->lms_s_unchecked != -1 &&
		ncand > (unsigned) op->ors_limit->lms_s_unchecked )
	{
		rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
		send_ldap_result( op, rs );
		rs->sr_err = LDAP_SUCCESS;
		goto done;
	}

	if ( op->ors_limit == NULL	/* isroot == TRUE */ ||
		!op->ors_limit->lms_s_pr_hide )
	{
		tentries = ncand;
	}

	wwctx.flag = 0;
	/* If we're running in our own read txn */
	if (  moi == &opinfo ) {
		cb.sc_writewait = mdb_writewait;
		cb.sc_private = &wwctx;
		wwctx.txn = ltid;
		wwctx.mcd = NULL;
		cb.sc_next = op->o_callback;
		op->o_callback = &cb;
	}

	if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
		PagedResultsState *ps = op->o_pagedresults_state;
		/* deferred cookie parsing */
		rs->sr_err = parse_paged_cookie( op, rs );
		if ( rs->sr_err != LDAP_SUCCESS ) {
			send_ldap_result( op, rs );
			goto done;
		}

		cursor = (ID) ps->ps_cookie;
		if ( cursor && ps->ps_size == 0 ) {
			rs->sr_err = LDAP_SUCCESS;
			rs->sr_text = "search abandoned by pagedResult size=0";
			send_ldap_result( op, rs );
			goto done;
		}
		id = mdb_idl_first( candidates, &cursor );
		if ( id == NOID ) {
			Debug( LDAP_DEBUG_TRACE, 
				LDAP_XSTRING(mdb_search)
				": no paged results candidates\n",
				0, 0, 0 );
			send_paged_response( op, rs, &lastid, 0 );

			rs->sr_err = LDAP_OTHER;
			goto done;
		}
		if ( id == (ID)ps->ps_cookie )
			id = mdb_idl_next( candidates, &cursor );
		nsubs = ncand;	/* always bypass scope'd search */
		goto loop_begin;
	}
	if ( nsubs < ncand ) {
		int rc;
		/* Do scope-based search */

		/* if any alias scopes were set, save them */
		if (scopes[0].mid > 1) {
			cursor = 1;
			for (cscope = 1; cscope <= scopes[0].mid; cscope++) {
				/* Ignore the original base */
				if (scopes[cscope].mid == base->e_id)
					continue;
				iscopes[cursor++] = scopes[cscope].mid;
			}
			iscopes[0] = scopes[0].mid - 1;
		} else {
			iscopes[0] = 0;
		}

		wwctx.mcd = mcd;
		isc.id = base->e_id;
		isc.numrdns = 0;
		rc = mdb_dn2id_walk( op, &isc );
		if ( rc )
			id = NOID;
		else
			id = isc.id;
		cscope = 0;
	} else {
		id = mdb_idl_first( candidates, &cursor );
	}

	while (id != NOID)
	{
		int scopeok;
		MDB_val edata;

loop_begin:

		/* check for abandon */
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			send_ldap_result( op, rs );
			goto done;
		}

		/* mostly needed by internal searches,
		 * e.g. related to syncrepl, for whom
		 * abandon does not get set... */
		if ( slapd_shutdown ) {
			rs->sr_err = LDAP_UNAVAILABLE;
			send_ldap_disconnect( op, rs );
			goto done;
		}

		/* check time limit */
		if ( op->ors_tlimit != SLAP_NO_LIMIT
				&& slap_get_time() > stoptime )
		{
			rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
			rs->sr_ref = rs->sr_v2ref;
			send_ldap_result( op, rs );
			rs->sr_err = LDAP_SUCCESS;
			goto done;
		}


		if ( nsubs < ncand ) {
			unsigned i;
			/* Is this entry in the candidate list? */
			scopeok = 0;
			if (MDB_IDL_IS_RANGE( candidates )) {
				if ( id >= MDB_IDL_RANGE_FIRST( candidates ) &&
					id <= MDB_IDL_RANGE_LAST( candidates ))
					scopeok = 1;
			} else {
				i = mdb_idl_search( candidates, id );
				if ( candidates[i] == id )
					scopeok = 1;
			}
			if ( scopeok )
				goto scopeok;
			goto loop_continue;
		}

		/* Does this candidate actually satisfy the search scope?
		 */
		scopeok = 0;
		isc.numrdns = 0;
		switch( op->ors_scope ) {
		case LDAP_SCOPE_BASE:
			/* This is always true, yes? */
			if ( id == base->e_id ) scopeok = 1;
			break;

#ifdef LDAP_SCOPE_CHILDREN
		case LDAP_SCOPE_CHILDREN:
			if ( id == base->e_id ) break;
			/* Fall-thru */
#endif
		case LDAP_SCOPE_SUBTREE:
			if ( id == base->e_id ) {
				scopeok = 1;
				break;
			}
			/* Fall-thru */
		case LDAP_SCOPE_ONELEVEL:
			isc.id = id;
			isc.nscope = 0;
			rs->sr_err = mdb_idscopes( op, &isc );
			if ( rs->sr_err == MDB_SUCCESS ) {
				if ( isc.nscope )
					scopeok = 1;
			} else {
				if ( rs->sr_err == MDB_NOTFOUND )
					goto notfound;
			}
			break;
		}

		/* Not in scope, ignore it */
		if ( !scopeok )
		{
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_search)
				": %ld scope not okay\n",
				(long) id, 0, 0 );
			goto loop_continue;
		}

scopeok:
		if ( id == base->e_id ) {
			e = base;
		} else {

			/* get the entry */
			rs->sr_err = mdb_id2edata( op, mci, id, &edata );
			if ( rs->sr_err == MDB_NOTFOUND ) {
notfound:
				if( nsubs < ncand )
					goto loop_continue;

				if( !MDB_IDL_IS_RANGE(candidates) ) {
					/* only complain for non-range IDLs */
					Debug( LDAP_DEBUG_TRACE,
						LDAP_XSTRING(mdb_search)
						": candidate %ld not found\n",
						(long) id, 0, 0 );
				} else {
					/* get the next ID from the DB */
					rs->sr_err = mdb_get_nextid( mci, &cursor );
					if ( rs->sr_err == MDB_NOTFOUND ) {
						break;
					}
					if ( rs->sr_err ) {
						rs->sr_err = LDAP_OTHER;
						rs->sr_text = "internal error in get_nextid";
						send_ldap_result( op, rs );
						goto done;
					}
					cursor--;
				}

				goto loop_continue;
			} else if ( rs->sr_err ) {
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "internal error in mdb_id2edata";
				send_ldap_result( op, rs );
				goto done;
			}

			rs->sr_err = mdb_entry_decode( op, ltid, &edata, &e );
			if ( rs->sr_err ) {
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "internal error in mdb_entry_decode";
				send_ldap_result( op, rs );
				goto done;
			}
			e->e_id = id;
			e->e_name.bv_val = NULL;
			e->e_nname.bv_val = NULL;
		}

		if ( is_entry_subentry( e ) ) {
			if( op->oq_search.rs_scope != LDAP_SCOPE_BASE ) {
				if(!get_subentries_visibility( op )) {
					/* only subentries are visible */
					goto loop_continue;
				}

			} else if ( get_subentries( op ) &&
				!get_subentries_visibility( op ))
			{
				/* only subentries are visible */
				goto loop_continue;
			}

		} else if ( get_subentries_visibility( op )) {
			/* only subentries are visible */
			goto loop_continue;
		}

		/* aliases were already dereferenced in candidate list */
		if ( op->ors_deref & LDAP_DEREF_SEARCHING ) {
			/* but if the search base is an alias, and we didn't
			 * deref it when finding, return it.
			 */
			if ( is_entry_alias(e) &&
				((op->ors_deref & LDAP_DEREF_FINDING) || e != base ))
			{
				goto loop_continue;
			}
		}

		if ( !manageDSAit && is_entry_glue( e )) {
			goto loop_continue;
		}

		if (e != base) {
			struct berval pdn, pndn;
			char *d, *n;
			int i;

			/* child of base, just append RDNs to base->e_name */
			if ( nsubs < ncand || isc.scopes[isc.nscope].mid == base->e_id ) {
				pdn = base->e_name;
				pndn = base->e_nname;
			} else {
				mdb_id2name( op, ltid, &isc.mc, scopes[isc.nscope].mid, &pdn, &pndn );
			}
			e->e_name.bv_len = pdn.bv_len;
			e->e_nname.bv_len = pndn.bv_len;
			for (i=0; i<isc.numrdns; i++) {
				e->e_name.bv_len += isc.rdns[i].bv_len + 1;
				e->e_nname.bv_len += isc.nrdns[i].bv_len + 1;
			}
			e->e_name.bv_val = op->o_tmpalloc(e->e_name.bv_len + 1, op->o_tmpmemctx);
			e->e_nname.bv_val = op->o_tmpalloc(e->e_nname.bv_len + 1, op->o_tmpmemctx);
			d = e->e_name.bv_val;
			n = e->e_nname.bv_val;
			if (nsubs < ncand) {
				/* RDNs are in top-down order */
				for (i=isc.numrdns-1; i>=0; i--) {
					memcpy(d, isc.rdns[i].bv_val, isc.rdns[i].bv_len);
					d += isc.rdns[i].bv_len;
					*d++ = ',';
					memcpy(n, isc.nrdns[i].bv_val, isc.nrdns[i].bv_len);
					n += isc.nrdns[i].bv_len;
					*n++ = ',';
				}
			} else {
				/* RDNs are in bottom-up order */
				for (i=0; i<isc.numrdns; i++) {
					memcpy(d, isc.rdns[i].bv_val, isc.rdns[i].bv_len);
					d += isc.rdns[i].bv_len;
					*d++ = ',';
					memcpy(n, isc.nrdns[i].bv_val, isc.nrdns[i].bv_len);
					n += isc.nrdns[i].bv_len;
					*n++ = ',';
				}
			}

			if (pdn.bv_len) {
				memcpy(d, pdn.bv_val, pdn.bv_len+1);
				memcpy(n, pndn.bv_val, pndn.bv_len+1);
			} else {
				*--d = '\0';
				*--n = '\0';
				e->e_name.bv_len--;
				e->e_nname.bv_len--;
			}
			if (pndn.bv_val != base->e_nname.bv_val) {
				op->o_tmpfree(pndn.bv_val, op->o_tmpmemctx);
				op->o_tmpfree(pdn.bv_val, op->o_tmpmemctx);
			}
		}

		/*
		 * if it's a referral, add it to the list of referrals. only do
		 * this for non-base searches, and don't check the filter
		 * explicitly here since it's only a candidate anyway.
		 */
		if ( !manageDSAit && op->oq_search.rs_scope != LDAP_SCOPE_BASE
			&& is_entry_referral( e ) )
		{
			BerVarray erefs = get_entry_referrals( op, e );
			rs->sr_ref = referral_rewrite( erefs, &e->e_name, NULL,
				op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL
					? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );

			rs->sr_entry = e;
			rs->sr_flags = 0;

			send_search_reference( op, rs );

			if (e != base)
				mdb_entry_return( op, e );
			rs->sr_entry = NULL;
			e = NULL;

			ber_bvarray_free( rs->sr_ref );
			ber_bvarray_free( erefs );
			rs->sr_ref = NULL;

			if ( wwctx.flag ) {
				rs->sr_err = mdb_waitfixup( op, &wwctx, mci, mcd );
				if ( rs->sr_err ) {
					send_ldap_result( op, rs );
					goto done;
				}
			}

			goto loop_continue;
		}

		/* if it matches the filter and scope, send it */
		rs->sr_err = test_filter( op, e, op->oq_search.rs_filter );

		if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
			/* check size limit */
			if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
				if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) {
					mdb_entry_return( op, e );
					e = NULL;
					send_paged_response( op, rs, &lastid, tentries );
					goto done;
				}
				lastid = id;
			}

			if (e) {
				/* safe default */
				rs->sr_attrs = op->oq_search.rs_attrs;
				rs->sr_operational_attrs = NULL;
				rs->sr_ctrls = NULL;
				rs->sr_entry = e;
				RS_ASSERT( e->e_private != NULL );
				rs->sr_flags = 0;
				rs->sr_err = LDAP_SUCCESS;
				rs->sr_err = send_search_entry( op, rs );
				rs->sr_attrs = NULL;
				rs->sr_entry = NULL;
				if (e != base)
					mdb_entry_return( op, e );
				e = NULL;

				switch ( rs->sr_err ) {
				case LDAP_SUCCESS:	/* entry sent ok */
					break;
				default:		/* entry not sent */
					break;
				case LDAP_BUSY:
					send_ldap_result( op, rs );
					goto done;
				case LDAP_UNAVAILABLE:
				case LDAP_SIZELIMIT_EXCEEDED:
					if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
						rs->sr_ref = rs->sr_v2ref;
						send_ldap_result( op, rs );
						rs->sr_err = LDAP_SUCCESS;

					} else {
						rs->sr_err = LDAP_OTHER;
					}
					goto done;
				}
				if ( wwctx.flag ) {
					rs->sr_err = mdb_waitfixup( op, &wwctx, mci, mcd );
					if ( rs->sr_err ) {
						send_ldap_result( op, rs );
						goto done;
					}
				}
			}

		} else {
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_search)
				": %ld does not match filter\n",
				(long) id, 0, 0 );
		}

loop_continue:
		if( e != NULL ) {
			if ( e != base )
				mdb_entry_return( op, e );
			RS_ASSERT( rs->sr_entry == NULL );
			e = NULL;
			rs->sr_entry = NULL;
		}

		if ( nsubs < ncand ) {
			int rc = mdb_dn2id_walk( op, &isc );
			if (rc) {
				id = NOID;
				/* We got to the end of a subtree. If there are any
				 * alias scopes left, search them too.
				 */
				while (iscopes[0] && cscope < iscopes[0]) {
					cscope++;
					isc.id = iscopes[cscope];
					if ( base )
						mdb_entry_return( op, base );
					rs->sr_err = mdb_id2entry(op, mci, isc.id, &base);
					if ( !rs->sr_err ) {
						mdb_id2name( op, ltid, &isc.mc, isc.id, &base->e_name, &base->e_nname );
						isc.numrdns = 0;
						if (isc.oscope == LDAP_SCOPE_ONELEVEL)
							isc.oscope = LDAP_SCOPE_BASE;
						rc = mdb_dn2id_walk( op, &isc );
						if ( !rc ) {
							id = isc.id;
							break;
						}
					}
				}
			} else
				id = isc.id;
		} else {
			id = mdb_idl_next( candidates, &cursor );
		}
	}

nochange:
	rs->sr_ctrls = NULL;
	rs->sr_ref = rs->sr_v2ref;
	rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL;
	rs->sr_rspoid = NULL;
	if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
		send_paged_response( op, rs, NULL, 0 );
	} else {
		send_ldap_result( op, rs );
	}

	rs->sr_err = LDAP_SUCCESS;

done:
	if ( cb.sc_private ) {
		/* remove our writewait callback */
		slap_callback **scp = &op->o_callback;
		while ( *scp ) {
			if ( *scp == &cb ) {
				*scp = cb.sc_next;
				cb.sc_private = NULL;
				break;
			}
		}
	}
	mdb_cursor_close( mcd );
	mdb_cursor_close( mci );
	if ( moi == &opinfo ) {
		mdb_txn_reset( moi->moi_txn );
		LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
	} else {
		moi->moi_ref--;
	}
	if( rs->sr_v2ref ) {
		ber_bvarray_free( rs->sr_v2ref );
		rs->sr_v2ref = NULL;
	}
	if (base)
		mdb_entry_return( op, base );
	scope_chunk_ret( op, scopes );

	return rs->sr_err;
}
Exemplo n.º 30
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;
}