Beispiel #1
0
static int
ldap_back_monitor_update(
	Operation	*op,
	SlapReply	*rs,
	Entry		*e,
	void		*priv )
{
	ldapinfo_t		*li = (ldapinfo_t *)priv;

	Attribute		*a;

	/* update olmDbURIList */
	a = attr_find( e->e_attrs, ad_olmDbURIList );
	if ( a != NULL ) {
		struct berval	bv;

		assert( a->a_vals != NULL );
		assert( !BER_BVISNULL( &a->a_vals[ 0 ] ) );
		assert( BER_BVISNULL( &a->a_vals[ 1 ] ) );

		ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
		if ( li->li_uri ) {
			ber_str2bv( li->li_uri, 0, 0, &bv );
			if ( !bvmatch( &a->a_vals[ 0 ], &bv ) ) {
				ber_bvreplace( &a->a_vals[ 0 ], &bv );
			}
		}
		ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
	}

	return SLAP_CB_CONTINUE;
}
static int
bdb_monitor_update(
	Operation	*op,
	SlapReply	*rs,
	Entry		*e,
	void		*priv )
{
	struct bdb_info		*bdb = (struct bdb_info *) priv;
	Attribute		*a;

	char			buf[ BUFSIZ ];
	struct berval		bv;

	assert( ad_olmBDBEntryCache != NULL );

	a = attr_find( e->e_attrs, ad_olmBDBEntryCache );
	assert( a != NULL );
	bv.bv_val = buf;
	bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", bdb->bi_cache.c_cursize );
	ber_bvreplace( &a->a_vals[ 0 ], &bv );

	a = attr_find( e->e_attrs, ad_olmBDBDNCache );
	assert( a != NULL );
	bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", bdb->bi_cache.c_eiused );
	ber_bvreplace( &a->a_vals[ 0 ], &bv );

	a = attr_find( e->e_attrs, ad_olmBDBIDLCache );
	assert( a != NULL );
	bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", bdb->bi_idl_cache_size );
	ber_bvreplace( &a->a_vals[ 0 ], &bv );
	
#ifdef BDB_MONITOR_IDX
	bdb_monitor_idx_entry_add( bdb, e );
#endif /* BDB_MONITOR_IDX */

	return SLAP_CB_CONTINUE;
}
Beispiel #3
0
/*
 * handle the LDAP_RES_INTERMEDIATE response
 */
static int
ldap_sync_search_intermediate( ldap_sync_t *ls, LDAPMessage *res, int *refreshDone )
{
	int			rc;
	char			*retoid = NULL;
        struct berval		*retdata = NULL;
	BerElement		*ber = NULL;
	ber_len_t		len;
	ber_tag_t		syncinfo_tag;
	struct berval		cookie;
	int			refreshDeletes = 0;
	BerVarray		syncUUIDs = NULL;
	ldap_sync_refresh_t	phase;

#ifdef LDAP_SYNC_TRACE
	fprintf( stderr, "\tgot LDAP_RES_INTERMEDIATE\n" );
#endif /* LDAP_SYNC_TRACE */

	assert( ls != NULL );
	assert( res != NULL );
	assert( refreshDone != NULL );

	*refreshDone = 0;

	rc = ldap_parse_intermediate( ls->ls_ld, res,
		&retoid, &retdata, NULL, 0 );
#ifdef LDAP_SYNC_TRACE
	fprintf( stderr, "\t%sldap_parse_intermediate(%s) == %d\n",
		rc != LDAP_SUCCESS ? "!!! " : "",
		retoid == NULL ? "\"\"" : retoid,
		rc );
#endif /* LDAP_SYNC_TRACE */
	/* parsing must be successful, and yield the OID
	 * of the sync info intermediate response */
	if ( rc != LDAP_SUCCESS ) {
		goto done;
	}

	rc = LDAP_OTHER;

	if ( retoid == NULL || strcmp( retoid, LDAP_SYNC_INFO ) != 0 ) {
		goto done;
	}

	/* init ber using the value in the response */
	ber = ber_init( retdata );
	if ( ber == NULL ) {
		goto done;
	}

	syncinfo_tag = ber_peek_tag( ber, &len );
	switch ( syncinfo_tag ) {
	case LDAP_TAG_SYNC_NEW_COOKIE:
		if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
			goto done;
		}
		if ( cookie.bv_val != NULL ) {
			ber_bvreplace( &ls->ls_cookie, &cookie );
		}
#ifdef LDAP_SYNC_TRACE
		fprintf( stderr, "\t\tgot cookie=%s\n",
			cookie.bv_val ? cookie.bv_val : "(null)" );
#endif /* LDAP_SYNC_TRACE */
		break;

	case LDAP_TAG_SYNC_REFRESH_DELETE:
	case LDAP_TAG_SYNC_REFRESH_PRESENT:
		if ( syncinfo_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) {
#ifdef LDAP_SYNC_TRACE
			fprintf( stderr, "\t\tgot refreshDelete\n" );
#endif /* LDAP_SYNC_TRACE */
			switch ( ls->ls_refreshPhase ) {
			case LDAP_SYNC_CAPI_NONE:
			case LDAP_SYNC_CAPI_PRESENTS:
				ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
				break;

			default:
				/* TODO: impossible; handle */
				goto done;
			}

		} else {
#ifdef LDAP_SYNC_TRACE
			fprintf( stderr, "\t\tgot refreshPresent\n" );
#endif /* LDAP_SYNC_TRACE */
			switch ( ls->ls_refreshPhase ) {
			case LDAP_SYNC_CAPI_NONE:
				ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
				break;

			default:
				/* TODO: impossible; handle */
				goto done;
			}
		}

		if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) {
			goto done;
		}
		if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
			if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
				goto done;
			}
			if ( cookie.bv_val != NULL ) {
				ber_bvreplace( &ls->ls_cookie, &cookie );
			}
#ifdef LDAP_SYNC_TRACE
			fprintf( stderr, "\t\tgot cookie=%s\n",
				cookie.bv_val ? cookie.bv_val : "(null)" );
#endif /* LDAP_SYNC_TRACE */
		}

		*refreshDone = 1;
		if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDONE ) {
			if ( ber_scanf( ber, "b", refreshDone ) == LBER_ERROR ) {
				goto done;
			}
		}

#ifdef LDAP_SYNC_TRACE
		fprintf( stderr, "\t\tgot refreshDone=%s\n",
			*refreshDone ? "TRUE" : "FALSE" );
#endif /* LDAP_SYNC_TRACE */

		if ( ber_scanf( ber, /*"{"*/ "}" ) == LBER_ERROR ) {
			goto done;
		}

		if ( *refreshDone ) {
			ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;
		}

		if ( ls->ls_intermediate ) {
			ls->ls_intermediate( ls, res, NULL, ls->ls_refreshPhase );
		}

		break;

	case LDAP_TAG_SYNC_ID_SET:
#ifdef LDAP_SYNC_TRACE
		fprintf( stderr, "\t\tgot syncIdSet\n" );
#endif /* LDAP_SYNC_TRACE */
		if ( ber_scanf( ber, "{" /*"}"*/ ) == LBER_ERROR ) {
			goto done;
		}
		if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
			if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
				goto done;
			}
			if ( cookie.bv_val != NULL ) {
				ber_bvreplace( &ls->ls_cookie, &cookie );
			}
#ifdef LDAP_SYNC_TRACE
			fprintf( stderr, "\t\tgot cookie=%s\n",
				cookie.bv_val ? cookie.bv_val : "(null)" );
#endif /* LDAP_SYNC_TRACE */
		}

		if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
			if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) {
				goto done;
			}
		}

		if ( ber_scanf( ber, /*"{"*/ "[W]}", &syncUUIDs ) == LBER_ERROR
			|| syncUUIDs == NULL )
		{
			goto done;
		}

		if ( refreshDeletes ) {
			phase = LDAP_SYNC_CAPI_DELETES_IDSET;

		} else {
			phase = LDAP_SYNC_CAPI_PRESENTS_IDSET;
		}

		/* FIXME: should touch ls->ls_refreshPhase? */
		if ( ls->ls_intermediate ) {
			ls->ls_intermediate( ls, res, syncUUIDs, phase );
		}

		ber_bvarray_free( syncUUIDs );
		break;

	default:
#ifdef LDAP_SYNC_TRACE
		fprintf( stderr, "\t\tunknown tag!\n" );
#endif /* LDAP_SYNC_TRACE */
		goto done;
	}

	rc = LDAP_SUCCESS;

done:;
	if ( ber != NULL ) {
		ber_free( ber, 1 );
	}

	if ( retoid != NULL ) {
		ldap_memfree( retoid );
	}

	if ( retdata != NULL ) {
		ber_bvfree( retdata );
	}

	return rc;
}
Beispiel #4
0
/*
 * handle the LDAP_RES_SEARCH_RESULT response
 */
static int
ldap_sync_search_result( ldap_sync_t *ls, LDAPMessage *res )
{
	int		err;
	char		*matched = NULL,
			*msg = NULL;
	LDAPControl	**ctrls = NULL;
	int		rc;
	int		refreshDeletes = -1;

#ifdef LDAP_SYNC_TRACE
	fprintf( stderr, "\tgot LDAP_RES_SEARCH_RESULT\n" );
#endif /* LDAP_SYNC_TRACE */

	assert( ls != NULL );
	assert( res != NULL );

	/* should not happen in refreshAndPersist... */
	rc = ldap_parse_result( ls->ls_ld,
		res, &err, &matched, &msg, NULL, &ctrls, 0 );
#ifdef LDAP_SYNC_TRACE
	fprintf( stderr,
		"\tldap_parse_result(%d, \"%s\", \"%s\") == %d\n",
		err,
		matched ? matched : "",
		msg ? msg : "",
		rc );
#endif /* LDAP_SYNC_TRACE */
	if ( rc == LDAP_SUCCESS ) {
		rc = err;
	}

	ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;

	switch ( rc ) {
	case LDAP_SUCCESS: {
		int		i;
		BerElement	*ber = NULL;
		ber_len_t	len;
		struct berval	cookie = { 0 };

		rc = LDAP_OTHER;

		/* deal with control; then fallthru to handler */
		if ( ctrls == NULL ) {
			goto done;
		}

		/* lookup the sync state control */
		for ( i = 0; ctrls[ i ] != NULL; i++ ) {
			if ( strcmp( ctrls[ i ]->ldctl_oid,
				LDAP_CONTROL_SYNC_DONE ) == 0 )
			{
				break;
			}
		}

		/* control must be present; there might be other... */
		if ( ctrls[ i ] == NULL ) {
			goto done;
		}

		/* extract data */
		ber = ber_init( &ctrls[ i ]->ldctl_value );
		if ( ber == NULL ) {
			goto done;
		}

		if ( ber_scanf( ber, "{" /*"}"*/) == LBER_ERROR ) {
			goto ber_done;
		}
		if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
			if ( ber_scanf( ber, "m", &cookie ) == LBER_ERROR ) {
				goto ber_done;
			}
			if ( cookie.bv_val != NULL ) {
				ber_bvreplace( &ls->ls_cookie, &cookie );
			}
#ifdef LDAP_SYNC_TRACE
			fprintf( stderr, "\t\tgot cookie=%s\n",
				cookie.bv_val ? cookie.bv_val : "(null)" );
#endif /* LDAP_SYNC_TRACE */
		}

		refreshDeletes = 0;
		if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) {
			if ( ber_scanf( ber, "b", &refreshDeletes ) == LBER_ERROR ) {
				goto ber_done;
			}
			if ( refreshDeletes ) {
				refreshDeletes = 1;
			}
		}

		if ( ber_scanf( ber, /*"{"*/ "}" ) != LBER_ERROR ) {
			rc = LDAP_SUCCESS;
		}

	ber_done:;
		ber_free( ber, 1 );
		if ( rc != LDAP_SUCCESS ) {
			break;
		}

#ifdef LDAP_SYNC_TRACE
		fprintf( stderr, "\t\tgot refreshDeletes=%s\n",
			refreshDeletes ? "TRUE" : "FALSE" );
#endif /* LDAP_SYNC_TRACE */

		/* FIXME: what should we do with the refreshDelete? */
		switch ( refreshDeletes ) {
		case 0:
			ls->ls_refreshPhase = LDAP_SYNC_CAPI_PRESENTS;
			break;

		default:
			ls->ls_refreshPhase = LDAP_SYNC_CAPI_DELETES;
			break;
		}

		} /* fallthru */

	case LDAP_SYNC_REFRESH_REQUIRED:
		/* TODO: check for Sync Done Control */
		/* FIXME: perhaps the handler should be called
		 * also in case of failure; we'll deal with this
		 * later when implementing refreshOnly */
		if ( ls->ls_search_result ) {
			err = ls->ls_search_result( ls, res, refreshDeletes );
		}
		break;
	}

done:;
	if ( matched != NULL ) {
		ldap_memfree( matched );
	}

	if ( msg != NULL ) {
		ldap_memfree( msg );
	}

	if ( ctrls != NULL ) {
		ldap_controls_free( ctrls );
	}

	ls->ls_refreshPhase = LDAP_SYNC_CAPI_DONE;

	return rc;
}
Beispiel #5
0
/*
 * handle the LDAP_RES_SEARCH_ENTRY response
 */
static int
ldap_sync_search_entry( ldap_sync_t *ls, LDAPMessage *res )
{
	LDAPControl		**ctrls = NULL;
	int			rc = LDAP_OTHER,
				i;
	BerElement		*ber = NULL;
	struct berval		entryUUID = { 0 },
				cookie = { 0 };
	int			state = -1;
	ber_len_t		len;
	ldap_sync_refresh_t	phase;

#ifdef LDAP_SYNC_TRACE
	fprintf( stderr, "\tgot LDAP_RES_SEARCH_ENTRY\n" );
#endif /* LDAP_SYNC_TRACE */

	assert( ls != NULL );
	assert( res != NULL );

	phase = ls->ls_refreshPhase;

	/* OK */

	/* extract:
	 * - data
	 * - entryUUID
	 *
	 * check that:
	 * - Sync State Control is "add"
	 */

	/* the control MUST be present */

	/* extract controls */
	ldap_get_entry_controls( ls->ls_ld, res, &ctrls );
	if ( ctrls == NULL ) {
		goto done;
	}

	/* lookup the sync state control */
	for ( i = 0; ctrls[ i ] != NULL; i++ ) {
		if ( strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_SYNC_STATE ) == 0 ) {
			break;
		}
	}

	/* control must be present; there might be other... */
	if ( ctrls[ i ] == NULL ) {
		goto done;
	}

	/* extract data */
	ber = ber_init( &ctrls[ i ]->ldctl_value );
	if ( ber == NULL ) {
		goto done;
	}
	/* scan entryUUID in-place ("m") */
	if ( ber_scanf( ber, "{em" /*"}"*/, &state, &entryUUID ) == LBER_ERROR
		|| entryUUID.bv_len == 0 )
	{
		goto done;
	}

	if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
		/* scan cookie in-place ("m") */
		if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) == LBER_ERROR ) {
			goto done;
		}
		if ( cookie.bv_val != NULL ) {
			ber_bvreplace( &ls->ls_cookie, &cookie );
		}
#ifdef LDAP_SYNC_TRACE
		fprintf( stderr, "\t\tgot cookie=%s\n",
			cookie.bv_val ? cookie.bv_val : "(null)" );
#endif /* LDAP_SYNC_TRACE */
	}

	switch ( state ) {
	case LDAP_SYNC_PRESENT:
	case LDAP_SYNC_DELETE:
	case LDAP_SYNC_ADD:
	case LDAP_SYNC_MODIFY:
		/* NOTE: ldap_sync_refresh_t is defined
		 * as the corresponding LDAP_SYNC_*
		 * for the 4 above cases */
		phase = state;
#ifdef LDAP_SYNC_TRACE
		fprintf( stderr, "\t\tgot syncState=%s\n", ldap_sync_state2str( state ) );
#endif /* LDAP_SYNC_TRACE */
		break;

	default:
#ifdef LDAP_SYNC_TRACE
		fprintf( stderr, "\t\tgot unknown syncState=%d\n", state );
#endif /* LDAP_SYNC_TRACE */
		goto done;
	}

	rc = ls->ls_search_entry
		? ls->ls_search_entry( ls, res, &entryUUID, phase )
		: LDAP_SUCCESS;

done:;
	if ( ber != NULL ) {
		ber_free( ber, 1 );
	}

	if ( ctrls != NULL ) {
		ldap_controls_free( ctrls );
	}

	return rc;
}
Beispiel #6
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;
}
Beispiel #7
0
int
entry_schema_check( 
	Operation *op,
	Entry *e,
	Attribute *oldattrs,
	int manage,
	int add,
	Attribute **socp,
	const char** text,
	char *textbuf, size_t textlen )
{
	Attribute	*a, *asc = NULL, *aoc = NULL;
	ObjectClass *sc, *oc, **socs = NULL;
	AttributeType *at;
	ContentRule *cr;
	int	rc, i;
	AttributeDescription *ad_structuralObjectClass
		= slap_schema.si_ad_structuralObjectClass;
	AttributeDescription *ad_objectClass
		= slap_schema.si_ad_objectClass;
	int extensible = 0;
	int subentry = is_entry_subentry( e );
	int collectiveSubentry = 0;

	if ( SLAP_NO_SCHEMA_CHECK( op->o_bd )) {
		return LDAP_SUCCESS;
	}

	if ( get_no_schema_check( op ) ) {
		return LDAP_SUCCESS;
	}

	if( subentry ) {
		collectiveSubentry = is_entry_collectiveAttributeSubentry( e );
	}

	*text = textbuf;

	/* misc attribute checks */
	for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
		const char *type = a->a_desc->ad_cname.bv_val;

		/* there should be at least one value */
		assert( a->a_vals != NULL );
		assert( a->a_vals[0].bv_val != NULL ); 

		if( a->a_desc->ad_type->sat_check ) {
			rc = (a->a_desc->ad_type->sat_check)(
				op->o_bd, e, a, text, textbuf, textlen );
			if( rc != LDAP_SUCCESS ) {
				return rc;
			}
		}

		if( a->a_desc == ad_structuralObjectClass )
			asc = a;
		else if ( a->a_desc == ad_objectClass )
			aoc = a;

		if( !collectiveSubentry && is_at_collective( a->a_desc->ad_type ) ) {
			snprintf( textbuf, textlen,
				"'%s' can only appear in collectiveAttributeSubentry",
				type );
			return LDAP_OBJECT_CLASS_VIOLATION;
		}

		/* if single value type, check for multiple values */
		if( is_at_single_value( a->a_desc->ad_type ) &&
			a->a_vals[1].bv_val != NULL )
		{
			Debug(LDAP_DEBUG_ANY,
			      "Entry (%s), attribute '%s' cannot have multiple values\n",
			      e->e_dn, type );

			return LDAP_CONSTRAINT_VIOLATION;
		}
	}

	/* check the object class attribute */
	if ( aoc == NULL ) {
		Debug( LDAP_DEBUG_ANY, "No objectClass for entry (%s)\n",
		    e->e_dn );

		*text = "no objectClass attribute";
		return LDAP_OBJECT_CLASS_VIOLATION;
	}

	assert( aoc->a_vals != NULL );
	assert( aoc->a_vals[0].bv_val != NULL );

	/* check the structural object class attribute */
	if ( asc == NULL && !add ) {
		Debug( LDAP_DEBUG_ANY,
			"No structuralObjectClass for entry (%s)\n",
		    e->e_dn );

		*text = "no structuralObjectClass operational attribute";
		return LDAP_OTHER;
	}

	rc = structural_class( aoc->a_vals, &oc, &socs, text, textbuf, textlen,
		op->o_tmpmemctx );
	if( rc != LDAP_SUCCESS ) {
		return rc;
	}

	if ( asc == NULL && add ) {
		attr_merge_one( e, ad_structuralObjectClass, &oc->soc_cname, NULL );
		asc = attr_find( e->e_attrs, ad_structuralObjectClass );
		sc = oc;
		goto got_soc;
	}

	assert( asc->a_vals != NULL );
	assert( asc->a_vals[0].bv_val != NULL );
	assert( asc->a_vals[1].bv_val == NULL );

	sc = oc_bvfind( &asc->a_vals[0] );
	if( sc == NULL ) {
		Debug(LDAP_DEBUG_ANY,
		      "entry_check_schema(%s): unrecognized structuralObjectClass '%s'\n",
		      e->e_dn, asc->a_vals[0].bv_val );

		rc = LDAP_OBJECT_CLASS_VIOLATION;
		goto done;
	}

	if( sc->soc_kind != LDAP_SCHEMA_STRUCTURAL ) {
		Debug(LDAP_DEBUG_ANY,
		      "entry_check_schema(%s): structuralObjectClass '%s' is not STRUCTURAL\n",
		      e->e_dn, asc->a_vals[0].bv_val );

		rc = LDAP_OTHER;
		goto done;
	}

got_soc:
	if( !manage && sc->soc_obsolete ) {
		Debug(LDAP_DEBUG_ANY,
		      "entry_check_schema(%s): structuralObjectClass '%s' is OBSOLETE\n",
		      e->e_dn, asc->a_vals[0].bv_val );

		rc = LDAP_OBJECT_CLASS_VIOLATION;
		goto done;
	}

	*text = textbuf;

	if ( oc == NULL ) {
		snprintf( textbuf, textlen, 
			"unrecognized objectClass '%s'",
			aoc->a_vals[0].bv_val );
		rc = LDAP_OBJECT_CLASS_VIOLATION;
		goto done;

	} else if ( sc != oc ) {
		if ( !manage && sc != slap_schema.si_oc_glue ) {
			snprintf( textbuf, textlen, 
				"structural object class modification "
				"from '%s' to '%s' not allowed",
				asc->a_vals[0].bv_val, oc->soc_cname.bv_val );
			rc = LDAP_NO_OBJECT_CLASS_MODS;
			goto done;
		}

		assert( asc->a_vals != NULL );
		assert( !BER_BVISNULL( &asc->a_vals[0] ) );
		assert( BER_BVISNULL( &asc->a_vals[1] ) );
		assert( asc->a_nvals == asc->a_vals );

		/* draft-zeilenga-ldap-relax: automatically modify
		 * structuralObjectClass if changed with relax */
		sc = oc;
		ber_bvreplace( &asc->a_vals[ 0 ], &sc->soc_cname );
		if ( socp ) {
			*socp = asc;
		}
	}

	/* naming check */
	if ( !is_entry_glue ( e ) ) {
		rc = entry_naming_check( e, manage, add, text, textbuf, textlen );
		if( rc != LDAP_SUCCESS ) {
			goto done;
		}
	} else {
		/* Glue Entry */
	}

	/* find the content rule for the structural class */
	cr = cr_find( sc->soc_oid );

	/* the cr must be same as the structural class */
	assert( !cr || !strcmp( cr->scr_oid, sc->soc_oid ) );

	/* check that the entry has required attrs of the content rule */
	if( cr ) {
		if( !manage && cr->scr_obsolete ) {
			Debug(LDAP_DEBUG_ANY,
			      "Entry (%s): content rule '%s' is obsolete\n",
			      e->e_dn, ldap_contentrule2name(&cr->scr_crule) );

			rc = LDAP_OBJECT_CLASS_VIOLATION;
			goto done;
		}

		if( cr->scr_required ) for( i=0; cr->scr_required[i]; i++ ) {
			at = cr->scr_required[i];

			for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
				if( a->a_desc->ad_type == at ) {
					break;
				}
			}

			/* not there => schema violation */
			if ( a == NULL ) {
				Debug(LDAP_DEBUG_ANY,
				      "Entry (%s): content rule '%s' requires attribute '%s'\n",
				      e->e_dn,
				      ldap_contentrule2name(&cr->scr_crule),
				      at->sat_cname.bv_val );

				rc = LDAP_OBJECT_CLASS_VIOLATION;
				goto done;
			}
		}

		if( cr->scr_precluded ) for( i=0; cr->scr_precluded[i]; i++ ) {
			at = cr->scr_precluded[i];

			for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
				if( a->a_desc->ad_type == at ) {
					break;
				}
			}

			/* there => schema violation */
			if ( a != NULL ) {
				Debug(LDAP_DEBUG_ANY,
				      "Entry (%s): content rule '%s' precluded attribute '%s'\n",
				      e->e_dn,
				      ldap_contentrule2name(&cr->scr_crule),
				      at->sat_cname.bv_val );

				rc = LDAP_OBJECT_CLASS_VIOLATION;
				goto done;
			}
		}
	}

	/* check that the entry has required attrs for each oc */
	for ( i = 0; socs[i]; i++ ) {
		oc = socs[i];
		if ( !manage && oc->soc_obsolete ) {
			/* disallow obsolete classes */
			Debug(LDAP_DEBUG_ANY,
			      "entry_check_schema(%s): objectClass '%s' is OBSOLETE\n",
			      e->e_dn, aoc->a_vals[i].bv_val );

			rc = LDAP_OBJECT_CLASS_VIOLATION;
			goto done;
		}

		if ( oc->soc_check ) {
			rc = (oc->soc_check)( op->o_bd, e, oc,
				text, textbuf, textlen );
			if( rc != LDAP_SUCCESS ) {
				goto done;
			}
		}

		if ( oc->soc_kind == LDAP_SCHEMA_ABSTRACT ) {
			/* object class is abstract */
			if ( oc != slap_schema.si_oc_top &&
				!is_object_subclass( oc, sc ))
			{
				int j;
				ObjectClass *xc = NULL;
				for( j=0; socs[j]; j++ ) {
					if( i != j ) {
						xc = socs[j];

						/* since we previous check against the
						 * structural object of this entry, the
						 * abstract class must be a (direct or indirect)
						 * superclass of one of the auxiliary classes of
						 * the entry.
						 */
						if ( xc->soc_kind == LDAP_SCHEMA_AUXILIARY &&
							is_object_subclass( oc, xc ) )
						{
							xc = NULL;
							break;
						}
					}
				}

				if( xc != NULL ) {
					Debug(LDAP_DEBUG_ANY,
					      "entry_check_schema(%s): instantiation of " "abstract objectClass '%s' not allowed\n",
					      e->e_dn, aoc->a_vals[i].bv_val );

					rc = LDAP_OBJECT_CLASS_VIOLATION;
					goto done;
				}
			}

		} else if ( oc->soc_kind != LDAP_SCHEMA_STRUCTURAL || oc == sc ) {
			char *s;

			if( oc->soc_kind == LDAP_SCHEMA_AUXILIARY ) {
				int k;

				if( cr ) {
					int j;

					k = -1;
					if( cr->scr_auxiliaries ) {
						for( j = 0; cr->scr_auxiliaries[j]; j++ ) {
							if( cr->scr_auxiliaries[j] == oc ) {
								k = 0;
								break;
							}
						}
					}
					if ( k ) {
						snprintf( textbuf, textlen, 
							"class '%s' not allowed by content rule '%s'",
							oc->soc_cname.bv_val,
							ldap_contentrule2name( &cr->scr_crule ) );
					}
				} else if ( global_disallows & SLAP_DISALLOW_AUX_WO_CR ) {
					k = -1;
					snprintf( textbuf, textlen, 
						"class '%s' not allowed by any content rule",
						oc->soc_cname.bv_val );
				} else {
					k = 0;	
				}

				if( k == -1 ) {
					Debug( LDAP_DEBUG_ANY,
						"Entry (%s): %s\n",
						e->e_dn, textbuf );

					rc = LDAP_OBJECT_CLASS_VIOLATION;
					goto done;
				}
			}

			s = oc_check_required( e, oc, &aoc->a_vals[i] );
			if (s != NULL) {
				Debug(LDAP_DEBUG_ANY,
				      "Entry (%s): object class '%s' requires attribute '%s'\n",
				      e->e_dn, aoc->a_vals[i].bv_val, s );

				rc = LDAP_OBJECT_CLASS_VIOLATION;
				goto done;
			}

			if( oc == slap_schema.si_oc_extensibleObject ) {
				extensible=1;
			}
		}
	}

	if( extensible ) {
		*text = NULL;
		rc = LDAP_SUCCESS;
		goto done;
	}

	/* check that each attr in the entry is allowed by some oc */
	for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
 		rc = LDAP_OBJECT_CLASS_VIOLATION;

		if( cr && cr->scr_required ) {
			for( i=0; cr->scr_required[i]; i++ ) {
				if( cr->scr_required[i] == a->a_desc->ad_type ) {
					rc = LDAP_SUCCESS;
					break;
				}
			}
		}

		if( rc != LDAP_SUCCESS && cr && cr->scr_allowed ) {
			for( i=0; cr->scr_allowed[i]; i++ ) {
				if( cr->scr_allowed[i] == a->a_desc->ad_type ) {
					rc = LDAP_SUCCESS;
					break;
				}
			}
		}

		if( rc != LDAP_SUCCESS ) 
		{
			rc = oc_check_allowed( a->a_desc->ad_type, socs, sc );
		}

		if ( rc != LDAP_SUCCESS ) {
			char *type = a->a_desc->ad_cname.bv_val;

			Debug(LDAP_DEBUG_ANY,
			      "Entry (%s), attribute '%s' not allowed\n",
			      e->e_dn, type );

			goto done;
		}
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

					target_entry_copy = entry_dup(target_entry);

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

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

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

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

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

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

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

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

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

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

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

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

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

						default:
							err = LDAP_OTHER;
							break;
						}

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

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

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

	if (target_entry_copy) {
		entry_free(target_entry_copy);
	}

	return SLAP_CB_CONTINUE;

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

	if (target_entry_copy) {
		entry_free(target_entry_copy);
	}

	op->o_bd->bd_info = (BackendInfo *)(on->on_info);
	if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
		msg = print_message( &rsv, m->sml_desc );
	}
	send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, msg );
	ch_free(msg);
	return (rs->sr_err);
}
Beispiel #9
0
int
meta_back_bind( Operation *op, SlapReply *rs )
{
	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
	metaconn_t	*mc = NULL;

	int		rc = LDAP_OTHER,
			i,
			gotit = 0,
			isroot = 0;

	SlapReply	*candidates;

	rs->sr_err = LDAP_SUCCESS;

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

	/* the test on the bind method should be superfluous */
	switch ( be_rootdn_bind( op, rs ) ) {
	case LDAP_SUCCESS:
		if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {
			/* frontend will return success */
			return rs->sr_err;
		}

		isroot = 1;
		/* fallthru */

	case SLAP_CB_CONTINUE:
		break;

	default:
		/* be_rootdn_bind() sent result */
		return rs->sr_err;
	}

	/* we need meta_back_getconn() not send result even on error,
	 * because we want to intercept the error and make it
	 * invalidCredentials */
	mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND );
	if ( !mc ) {
		if ( LogTest( LDAP_DEBUG_ANY ) ) {
			char	buf[ SLAP_TEXT_BUFLEN ];

			snprintf( buf, sizeof( buf ),
				"meta_back_bind: no target "
				"for dn \"%s\" (%d%s%s).",
				op->o_req_dn.bv_val, rs->sr_err,
				rs->sr_text ? ". " : "",
				rs->sr_text ? rs->sr_text : "" );
			Debug( LDAP_DEBUG_ANY,
				"%s %s\n",
				op->o_log_prefix, buf );
		}

		/* FIXME: there might be cases where we don't want
		 * to map the error onto invalidCredentials */
		switch ( rs->sr_err ) {
		case LDAP_NO_SUCH_OBJECT:
		case LDAP_UNWILLING_TO_PERFORM:
			rs->sr_err = LDAP_INVALID_CREDENTIALS;
			rs->sr_text = NULL;
			break;
		}
		send_ldap_result( op, rs );
		return rs->sr_err;
	}

	candidates = meta_back_candidates_get( op );

	/*
	 * Each target is scanned ...
	 */
	mc->mc_authz_target = META_BOUND_NONE;
	for ( i = 0; i < mi->mi_ntargets; i++ ) {
		metatarget_t	*mt = mi->mi_targets[ i ];
		int		lerr;

		/*
		 * Skip non-candidates
		 */
		if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
			continue;
		}

		if ( gotit == 0 ) {
			/* set rc to LDAP_SUCCESS only if at least
			 * one candidate has been tried */
			rc = LDAP_SUCCESS;
			gotit = 1;

		} else if ( !isroot ) {
			/*
			 * A bind operation is expected to have
			 * ONE CANDIDATE ONLY!
			 */
			Debug( LDAP_DEBUG_ANY,
				"### %s meta_back_bind: more than one"
				" candidate selected...\n",
				op->o_log_prefix );
		}

		if ( isroot ) {
			if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE
				|| BER_BVISNULL( &mt->mt_idassert_authcDN ) )
			{
				metasingleconn_t	*msc = &mc->mc_conns[ i ];

				/* skip the target if no pseudorootdn is provided */
				if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
					ch_free( msc->msc_bound_ndn.bv_val );
					BER_BVZERO( &msc->msc_bound_ndn );
				}

				if ( !BER_BVISNULL( &msc->msc_cred ) ) {
					/* destroy sensitive data */
					memset( msc->msc_cred.bv_val, 0,
						msc->msc_cred.bv_len );
					ch_free( msc->msc_cred.bv_val );
					BER_BVZERO( &msc->msc_cred );
				}

				continue;
			}


			(void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND, 1 );
			lerr = rs->sr_err;

		} else {
			lerr = meta_back_single_bind( op, rs, mc, i );
		}

		if ( lerr != LDAP_SUCCESS ) {
			rc = rs->sr_err = lerr;

			/* FIXME: in some cases (e.g. unavailable)
			 * do not assume it's not candidate; rather
			 * mark this as an error to be eventually
			 * reported to client */
			META_CANDIDATE_CLEAR( &candidates[ i ] );
			break;
		}
	}

	/* must re-insert if local DN changed as result of bind */
	if ( rc == LDAP_SUCCESS ) {
		if ( isroot ) {
			mc->mc_authz_target = META_BOUND_ALL;
		}

		if ( !LDAP_BACK_PCONN_ISPRIV( mc )
			&& !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) )
		{
			int		lerr;

			/* wait for all other ops to release the connection */
			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
			assert( mc->mc_refcnt == 1 );
#if META_BACK_PRINT_CONNTREE > 0
			meta_back_print_conntree( mi, ">>> meta_back_bind" );
#endif /* META_BACK_PRINT_CONNTREE */

			/* delete all cached connections with the current connection */
			if ( LDAP_BACK_SINGLECONN( mi ) ) {
				metaconn_t	*tmpmc;

				while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
				{
					assert( !LDAP_BACK_PCONN_ISPRIV( mc ) );
					Debug( LDAP_DEBUG_TRACE,
						"=>meta_back_bind: destroying conn %lu (refcnt=%u)\n",
						mc->mc_conn->c_connid, mc->mc_refcnt );

					if ( tmpmc->mc_refcnt != 0 ) {
						/* taint it */
						LDAP_BACK_CONN_TAINTED_SET( tmpmc );

					} else {
						/*
						 * Needs a test because the handler may be corrupted,
						 * and calling ldap_unbind on a corrupted header results
						 * in a segmentation fault
						 */
						meta_back_conn_free( tmpmc );
					}
				}
			}

			ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
			lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
				meta_back_conndn_cmp, meta_back_conndn_dup );
#if META_BACK_PRINT_CONNTREE > 0
			meta_back_print_conntree( mi, "<<< meta_back_bind" );
#endif /* META_BACK_PRINT_CONNTREE */
			if ( lerr == 0 ) {
#if 0
				/* NOTE: a connection cannot be privileged
				 * and be in the avl tree at the same time
				 */
				if ( isroot ) {
					LDAP_BACK_CONN_ISPRIV_SET( mc );
					LDAP_BACK_PCONN_SET( mc, op );
				}
#endif
				LDAP_BACK_CONN_CACHED_SET( mc );

			} else {
				LDAP_BACK_CONN_CACHED_CLEAR( mc );
			}
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
		}
	}

	if ( mc != NULL ) {
		meta_back_release_conn( mi, mc );
	}

	/*
	 * rc is LDAP_SUCCESS if at least one bind succeeded,
	 * err is the last error that occurred during a bind;
	 * if at least (and at most?) one bind succeeds, fine.
	 */
	if ( rc != LDAP_SUCCESS ) {

		/*
		 * deal with bind failure ...
		 */

		/*
		 * no target was found within the naming context,
		 * so bind must fail with invalid credentials
		 */
		if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
			rs->sr_err = LDAP_INVALID_CREDENTIALS;
		} else {
			rs->sr_err = slap_map_api2result( rs );
		}
		send_ldap_result( op, rs );
		return rs->sr_err;

	}

	return LDAP_SUCCESS;
}
Beispiel #10
0
/*
 * meta_back_single_bind
 *
 * attempts to perform a bind with creds
 */
static int
meta_back_single_bind(
	Operation		*op,
	SlapReply		*rs,
	metaconn_t		*mc,
	int			candidate )
{
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
	metatarget_t		*mt = mi->mi_targets[ candidate ];
	struct berval		mdn = BER_BVNULL;
	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
	int			msgid;
	dncookie		dc;
	struct berval		save_o_dn;
	int			save_o_do_not_cache;
	LDAPControl		**ctrls = NULL;

	if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
		ch_free( msc->msc_bound_ndn.bv_val );
		BER_BVZERO( &msc->msc_bound_ndn );
	}

	if ( !BER_BVISNULL( &msc->msc_cred ) ) {
		/* destroy sensitive data */
		memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
		ch_free( msc->msc_cred.bv_val );
		BER_BVZERO( &msc->msc_cred );
	}

	/*
	 * Rewrite the bind dn if needed
	 */
	dc.target = mt;
	dc.conn = op->o_conn;
	dc.rs = rs;
	dc.ctx = "bindDN";

	if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
		rs->sr_text = "DN rewrite error";
		rs->sr_err = LDAP_OTHER;
		return rs->sr_err;
	}

	/* don't add proxyAuthz; set the bindDN */
	save_o_dn = op->o_dn;
	save_o_do_not_cache = op->o_do_not_cache;
	op->o_do_not_cache = 1;
	op->o_dn = op->o_req_dn;

	ctrls = op->o_ctrls;
	rs->sr_err = meta_back_controls_add( op, rs, mc, candidate, &ctrls );
	op->o_dn = save_o_dn;
	op->o_do_not_cache = save_o_do_not_cache;
	if ( rs->sr_err != LDAP_SUCCESS ) {
		goto return_results;
	}

	/* FIXME: this fixes the bind problem right now; we need
	 * to use the asynchronous version to get the "matched"
	 * and more in case of failure ... */
	/* FIXME: should we check if at least some of the op->o_ctrls
	 * can/should be passed? */
	for (;;) {
		rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
			LDAP_SASL_SIMPLE, &op->orb_cred,
			ctrls, NULL, &msgid );
		if ( rs->sr_err != LDAP_X_CONNECTING ) {
			break;
		}
		ldap_pvt_thread_yield();
	}

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

	meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND, 1 );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		goto return_results;
	}

	/* If defined, proxyAuthz will be used also when
	 * back-ldap is the authorizing backend; for this
	 * purpose, a successful bind is followed by a
	 * bind with the configured identity assertion */
	/* NOTE: use with care */
	if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
		meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR, 1 );
		if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) {
			goto return_results;
		}
		goto cache_refresh;
	}

	ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_ndn );
	LDAP_BACK_CONN_ISBOUND_SET( msc );
	mc->mc_authz_target = candidate;

	if ( META_BACK_TGT_SAVECRED( mt ) ) {
		if ( !BER_BVISNULL( &msc->msc_cred ) ) {
			memset( msc->msc_cred.bv_val, 0,
				msc->msc_cred.bv_len );
		}
		ber_bvreplace( &msc->msc_cred, &op->orb_cred );
		ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
	}

cache_refresh:;
	if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED
			&& !BER_BVISEMPTY( &op->o_req_ndn ) )
	{
		( void )meta_dncache_update_entry( &mi->mi_cache,
				&op->o_req_ndn, candidate );
	}

return_results:;
	if ( mdn.bv_val != op->o_req_dn.bv_val ) {
		free( mdn.bv_val );
	}

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

	return rs->sr_err;
}
Beispiel #11
0
static int
meta_back_proxy_authz_bind(
	metaconn_t *mc,
	int candidate,
	Operation *op,
	SlapReply *rs,
	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 ];
	struct berval		binddn = BER_BVC( "" ),
				cred = BER_BVC( "" );
	int			method = LDAP_AUTH_NONE,
				rc;

	rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, sendok, &binddn, &cred, &method );
	if ( rc == LDAP_SUCCESS && !LDAP_BACK_CONN_ISBOUND( msc ) ) {
		int	msgid;

		switch ( method ) {
		case LDAP_AUTH_NONE:
		case LDAP_AUTH_SIMPLE:

			if(!dolock) {
				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
			}

			for (;;) {
				rs->sr_err = ldap_sasl_bind( msc->msc_ld,
					binddn.bv_val, LDAP_SASL_SIMPLE,
					&cred, NULL, NULL, &msgid );
				if ( rs->sr_err != LDAP_X_CONNECTING ) {
					break;
				}
				ldap_pvt_thread_yield();
			}

			if(!dolock) {
				ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
			}

			rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
			if ( rc == LDAP_SUCCESS ) {
				/* set rebind stuff in case of successful proxyAuthz bind,
				 * so that referral chasing is attempted using the right
				 * identity */
				LDAP_BACK_CONN_ISBOUND_SET( msc );
				ber_bvreplace( &msc->msc_bound_ndn, &binddn );

				if ( META_BACK_TGT_SAVECRED( mt ) ) {
					if ( !BER_BVISNULL( &msc->msc_cred ) ) {
						memset( msc->msc_cred.bv_val, 0,
							msc->msc_cred.bv_len );
					}
					ber_bvreplace( &msc->msc_cred, &cred );
					ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
				}
			}
			break;

		default:
			LDAP_BUG();
			break;
		}
	}

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

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

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

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

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

	save_attrs = attrs_dup( e->e_attrs );

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

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

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

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

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

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

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

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

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

		BER_BVZERO( &ul );
	}

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

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

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

	return rs->sr_err;
}
Beispiel #13
0
/*
 * asyncmeta_dobind_init()
 *
 * initiates bind for a candidate target
 */
meta_search_candidate_t
asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn_t *mc, int candidate)
{
	SlapReply		*candidates = bc->candidates;
	a_metainfo_t		*mi = ( a_metainfo_t * )mc->mc_info;
	a_metatarget_t		*mt = mi->mi_targets[ candidate ];
	a_metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
	ber_socket_t s;
	struct berval		binddn = msc->msc_bound_ndn,
				cred = msc->msc_cred;
	int			method;

	int			rc;
	ber_int_t	msgid;

	meta_search_candidate_t	retcode;

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

	if ( mc->mc_authz_target == META_BOUND_ALL ) {
		return META_SEARCH_CANDIDATE;
	}

	retcode = META_SEARCH_BINDING;
	if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
		/* already bound (or anonymous) */

#ifdef DEBUG_205
		char	buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
		int	bound = 0;

		if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
			bound = 1;
		}

		snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
			(void *)mc, (void *)msc->msc_ld,
			bound ? " bound" : " anonymous",
			bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
		Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_dobind_init[%d]%s\n",
			op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */

		retcode = META_SEARCH_CANDIDATE;

	} else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
		/* another thread is binding the target for this conn; wait */

#ifdef DEBUG_205
		char	buf[ SLAP_TEXT_BUFLEN ] = { '\0' };

		snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
			(void *)mc, (void *)msc->msc_ld );
		Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_dobind_init[%d]%s\n",
			op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */

		candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
		retcode = META_SEARCH_NEED_BIND;

	} else {
		/* we'll need to bind the target for this conn */

#ifdef DEBUG_205
		char buf[ SLAP_TEXT_BUFLEN ];

		snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
			(void *)mc, (void *)msc->msc_ld );
		Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_dobind_init[%d]%s\n",
			op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */

		if ( msc->msc_ld == NULL ) {
			/* for some reason (e.g. because formerly in "binding"
			 * state, with eventual connection expiration or invalidation)
			 * it was not initialized as expected */

			Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p ld=NULL\n",
				op->o_log_prefix, candidate, (void *)mc );

			rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
				LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
			switch ( rc ) {
			case LDAP_SUCCESS:
				assert( msc->msc_ld != NULL );
				break;

			case LDAP_SERVER_DOWN:
			case LDAP_UNAVAILABLE:
				goto down;

			default:
				goto other;
			}
		}

		LDAP_BACK_CONN_BINDING_SET( msc );
	}

	if ( retcode != META_SEARCH_BINDING ) {
		return retcode;
	}

	if ( op->o_conn != NULL &&
		!op->o_do_not_cache &&
		( BER_BVISNULL( &msc->msc_bound_ndn ) ||
			BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
			( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
	{
		rc = asyncmeta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
		switch ( rc ) {
		case LDAP_SUCCESS:
			break;
		case LDAP_UNAVAILABLE:
			goto down;
		default:
			goto other;
		}

		/* NOTE: we copy things here, even if bind didn't succeed yet,
		 * because the connection is not shared until bind is over */
		if ( !BER_BVISNULL( &binddn ) ) {
			ldap_pvt_thread_mutex_lock(&mc->mc_om_mutex);

			ber_bvreplace( &msc->msc_bound_ndn, &binddn );
			if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
				if ( !BER_BVISNULL( &msc->msc_cred ) ) {
					memset( msc->msc_cred.bv_val, 0,
						msc->msc_cred.bv_len );
				}
				ber_bvreplace( &msc->msc_cred, &cred );
			}
			ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
		}
		if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
			/* apparently, idassert was configured with SASL bind,
			 * so bind occurred inside meta_back_proxy_authz_cred() */
			LDAP_BACK_CONN_BINDING_CLEAR( msc );
			return META_SEARCH_CANDIDATE;
		}

		/* paranoid */
		switch ( method ) {
		case LDAP_AUTH_NONE:
		case LDAP_AUTH_SIMPLE:
			/* do a simple bind with binddn, cred */
			break;

		default:
			assert( 0 );
			break;
		}
	}

	assert( msc->msc_ld != NULL );

	if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) {
		/* bind anonymously? */
		Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: "
			"non-empty dn with empty cred; binding anonymously\n",
			op->o_log_prefix, candidate, (void *)mc );
		cred = slap_empty_bv;

	} else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) {
		/* error */
		Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: "
			"empty dn with non-empty cred: error\n",
			op->o_log_prefix, candidate, (void *)mc );
		rc = LDAP_OTHER;
		goto other;
	}
retry_bind:
	rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
			NULL, NULL, &msgid );
	ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rc );

	if (rc == LDAP_SERVER_DOWN ) {
		goto down;
	}
	candidates[ candidate ].sr_msgid = msgid;
	asyncmeta_set_msc_time(msc);
#ifdef DEBUG_205
	{
		char buf[ SLAP_TEXT_BUFLEN ];

		snprintf( buf, sizeof( buf ), "asyncmeta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
			candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
		Debug( LDAP_DEBUG_ANY, "### %s %s\n",
			op->o_log_prefix, buf, 0 );
	}
#endif /* DEBUG_205 */

	switch ( rc ) {
	case LDAP_SUCCESS:
		assert( msgid >= 0 );
		META_BINDING_SET( &candidates[ candidate ] );
		rs->sr_err = LDAP_SUCCESS;
		return META_SEARCH_BINDING;

	case LDAP_X_CONNECTING:
		/* must retry, same conn */
		candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
		LDAP_BACK_CONN_BINDING_CLEAR( msc );
		goto retry_bind;

	case LDAP_SERVER_DOWN:
down:;
		retcode = META_SEARCH_ERR;
		rs->sr_err = LDAP_UNAVAILABLE;
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
		break;

		/* fall thru */

	default:
other:;
		rs->sr_err = rc;
		rc = slap_map_api2result( rs );
		candidates[ candidate ].sr_err = rc;
		if ( META_BACK_ONERR_STOP( mi ) ) {
			retcode = META_SEARCH_ERR;

		} else {
			retcode = META_SEARCH_NOT_CANDIDATE;
		}
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
		break;
	}

	return retcode;
}