openldap/servers/slapd/back-bdb2/bind.c
Kurt Zeilenga 73276e84ae Import experimental referral implementation from OPENLDAP_DEVEL_REFERRALS.
Includes support for update referral for each replicated backend.
	Reworked replication test to use update referral.
Includes major rewrite of response encoding codes (result.c).
Includes reworked alias support and eliminates old suffix alias codes
(can be emulated using named alias).
Includes (untested) support for the Manage DSA IT control.
Works in LDAPv2 world.  Still testing in LDAPv3 world.
Added default referral (test009) test.
1999-07-16 02:45:46 +00:00

347 lines
7.3 KiB
C

/* bind.c - bdb2 backend bind and unbind routines */
#include "portable.h"
#include <stdio.h>
#include <ac/krb.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/unistd.h>
#include "slap.h"
#include "back-bdb2.h"
#include "proto-back-bdb2.h"
#include <lutil.h>
#ifdef HAVE_KERBEROS
extern int bdb2i_krbv4_ldap_auth();
#endif
static int
crypted_value_find(
struct berval **vals,
struct berval *v,
int syntax,
int normalize,
struct berval *cred
)
{
int i;
for ( i = 0; vals[i] != NULL; i++ ) {
if ( syntax != SYNTAX_BIN ) {
int result;
#ifdef SLAPD_CRYPT
ldap_pvt_thread_mutex_lock( &crypt_mutex );
#endif
result = lutil_passwd(
(char*) cred->bv_val,
(char*) vals[i]->bv_val,
NULL );
#ifdef SLAPD_CRYPT
ldap_pvt_thread_mutex_unlock( &crypt_mutex );
#endif
return result;
} else {
if ( value_cmp( vals[i], v, syntax, normalize ) == 0 ) {
return( 0 );
}
}
}
return( 1 );
}
static int
bdb2i_back_bind_internal(
BackendDB *be,
Connection *conn,
Operation *op,
char *dn,
int method,
char *mech,
struct berval *cred,
char** edn
)
{
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
Entry *e;
Attribute *a;
int rc;
Entry *matched;
#ifdef HAVE_KERBEROS
char krbname[MAX_K_NAME_SZ + 1];
AUTH_DAT ad;
#endif
Debug(LDAP_DEBUG_ARGS, "==> bdb2_back_bind: dn: %s\n", dn, 0, 0);
*edn = NULL;
/* get entry with reader lock */
if ( (e = bdb2i_dn2entry_r( be, dn, &matched )) == NULL ) {
char *matched_dn = NULL;
struct berval **refs = NULL;
if ( matched != NULL ) {
matched_dn = ch_strdup( matched->e_dn );
refs = is_entry_referral( matched )
? get_entry_referrals( be, conn, op, matched )
: NULL;
bdb2i_cache_return_entry_r( &li->li_cache, matched );
} else {
refs = default_referral;
}
/* allow noauth binds */
rc = 1;
if ( method == LDAP_AUTH_SIMPLE ) {
if( cred->bv_len == 0 ) {
/* SUCCESS */
send_ldap_result( conn, op, LDAP_SUCCESS,
NULL, NULL, NULL, NULL );
} else if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
*edn = ch_strdup( be_root_dn( be ) );
rc = 0;
} else {
send_ldap_result( conn, op, LDAP_REFERRAL,
matched_dn, NULL, refs, NULL );
}
} else if ( method == LDAP_AUTH_SASL ) {
if( mech != NULL && strcasecmp(mech,"DIGEST-MD5") == 0 ) {
/* insert DIGEST calls here */
send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
NULL, NULL, NULL, NULL );
} else {
send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED,
NULL, NULL, NULL, NULL );
}
} else {
send_ldap_result( conn, op, LDAP_REFERRAL,
matched_dn, NULL, refs, NULL );
rc = 1;
}
if ( matched != NULL ) {
ber_bvecfree( refs );
free( matched_dn );
}
return( rc );
}
*edn = ch_strdup( e->e_dn );
/* check for deleted */
if ( ! access_allowed( be, conn, op, e,
"entry", NULL, ACL_AUTH ) )
{
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL, NULL );
rc = 1;
goto return_results;
}
if ( is_entry_alias( e ) ) {
/* entry is a alias, don't allow bind */
Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
NULL, NULL, NULL, NULL );
rc = 1;
goto return_results;
}
if ( is_entry_referral( e ) ) {
/* entry is a referral, don't allow bind */
struct berval **refs = get_entry_referrals( be,
conn, op, e );
Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
0, 0 );
send_ldap_result( conn, op, LDAP_REFERRAL,
e->e_dn, NULL, refs, NULL );
ber_bvecfree( refs );
rc = 1;
goto return_results;
}
switch ( method ) {
case LDAP_AUTH_SIMPLE:
if ( cred->bv_len == 0 ) {
send_ldap_result( conn, op, LDAP_SUCCESS,
NULL, NULL, NULL, NULL );
/* stop front end from sending result */
rc = 1;
goto return_results;
}
/* check for root dn/passwd */
if ( be_isroot_pw( be, dn, cred ) ) {
/* front end will send result */
if( *edn != NULL ) free( *edn );
*edn = ch_strdup( be_root_dn( be ) );
rc = 0;
goto return_results;
}
if ( ! access_allowed( be, conn, op, e,
"userpassword", NULL, ACL_AUTH ) )
{
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL, NULL);
rc = 1;
goto return_results;
}
if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
NULL, NULL, NULL, NULL);
/* stop front end from sending result */
rc = 1;
goto return_results;
}
if ( crypted_value_find( a->a_vals, cred, a->a_syntax, 0, cred ) != 0 )
{
send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
NULL, NULL, NULL, NULL);
/* stop front end from sending result */
rc = 1;
goto return_results;
}
rc = 0;
break;
#ifdef HAVE_KERBEROS
case LDAP_AUTH_KRBV41:
if ( bdb2i_krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) {
send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
NULL, NULL, NULL, NULL);
rc = 1;
goto return_results;
}
if ( ! access_allowed( be, conn, op, e,
"krbname", NULL, ACL_AUTH ) )
{
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
NULL, NULL, NULL, NULL);
rc = 1;
goto return_results;
}
sprintf( krbname, "%s%s%s@%s", ad.pname, *ad.pinst ? "."
: "", ad.pinst, ad.prealm );
if ( (a = attr_find( e->e_attrs, "krbname" )) == NULL ) {
/*
* no krbName values present: check against DN
*/
if ( strcasecmp( dn, krbname ) == 0 ) {
rc = 0; /* XXX wild ass guess */
break;
}
send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
NULL, NULL, NULL, NULL);
rc = 1;
goto return_results;
} else { /* look for krbName match */
struct berval krbval;
krbval.bv_val = krbname;
krbval.bv_len = strlen( krbname );
if ( value_find( a->a_vals, &krbval, a->a_syntax, 3 ) != 0 ) {
send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
NULL, NULL, NULL, NULL);
rc = 1;
goto return_results;
}
}
rc = 0;
break;
case LDAP_AUTH_KRBV42:
send_ldap_result( conn, op, LDAP_SUCCESS,
NULL, NULL, NULL, NULL );
/* stop front end from sending result */
rc = 1;
goto return_results;
#endif
case LDAP_AUTH_SASL:
/* insert sasl code here */
default:
send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED,
NULL, "auth method not supported", NULL, NULL );
rc = 1;
goto return_results;
}
return_results:;
/* free entry and reader lock */
bdb2i_cache_return_entry_r( &li->li_cache, e );
/* front end with send result on success (rc==0) */
return( rc );
}
int
bdb2_back_bind(
BackendDB *be,
Connection *conn,
Operation *op,
char *dn,
int method,
char *mech,
struct berval *cred,
char** edn
)
{
DB_LOCK lock;
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
struct timeval time1;
int ret;
bdb2i_start_timing( be->bd_info, &time1 );
if ( bdb2i_enter_backend_r( &lock ) != 0 ) {
send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
NULL, NULL, NULL, NULL );
return( 1 );
}
ret = bdb2i_back_bind_internal( be, conn, op, dn, method, mech, cred, edn );
(void) bdb2i_leave_backend_r( lock );
bdb2i_stop_timing( be->bd_info, time1, "BIND", conn, op );
return( ret );
}