/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2003 The OpenLDAP Foundation.
+ * Copyright 1998-2004 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
# define SASL_CONST
# endif
+#define SASL_VERSION_FULL ((SASL_VERSION_MAJOR << 16) |\
+ (SASL_VERSION_MINOR << 8) | SASL_VERSION_STEP)
+
static sasl_security_properties_t sasl_secprops;
-#endif /* HAVE_CYRUS_SASL */
+#elif defined( SLAP_BUILTIN_SASL )
+/*
+ * built-in SASL implementation
+ * only supports EXTERNAL
+ */
+typedef struct sasl_ctx {
+ slap_ssf_t sc_external_ssf;
+ struct berval sc_external_id;
+} SASL_CTX;
+
+#endif
#include "ldap_pvt.h"
#include "lber_pvt.h"
#include <lutil.h>
+static struct berval ext_bv = BER_BVC( "EXTERNAL" );
+
int slap_sasl_config( int cargc, char **cargv, char *line,
const char *fname, int lineno )
{
sasl_server_params_t *sparams;
} lookup_info;
-static slap_response sasl_ap_lookup, sasl_ap_store, sasl_cb_checkpass;
+static slap_response sasl_ap_lookup, sasl_cb_checkpass;
static int
sasl_ap_lookup( Operation *op, SlapReply *rs )
unsigned ulen)
{
Operation op = {0};
- int rc, i, doit=0;
+ int i, doit = 0;
Connection *conn = NULL;
lookup_info sl;
}
if (doit) {
- slap_callback cb = { sasl_ap_lookup, NULL };
+ slap_callback cb = { NULL, sasl_ap_lookup, NULL, NULL };
cb.sc_private = &sl;
}
}
-static int
-sasl_ap_store( Operation *op, SlapReply *rs )
-{
- return 0;
-}
-
+#if SASL_VERSION_FULL >= 0x020110
static int
slap_auxprop_store(
void *glob_context,
Connection *conn = NULL;
const struct propval *pr;
Modifications *modlist = NULL, **modtail = &modlist, *mod;
- slap_callback cb = { sasl_ap_store, NULL };
+ slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
char textbuf[SLAP_TEXT_BUFLEN];
const char *text;
size_t textlen = sizeof(textbuf);
slap_mods_free( modlist );
return rc ? SASL_FAIL : SASL_OK;
}
+#endif /* SASL_VERSION_FULL >= 2.1.16 */
static sasl_auxprop_plug_t slap_auxprop_plugin = {
0, /* Features */
NULL, /* auxprop_free */
slap_auxprop_lookup,
"slapd", /* name */
+#if SASL_VERSION_FULL >= 0x020110
slap_auxprop_store /* the declaration of this member changed
* in cyrus SASL from 2.1.15 to 2.1.16 */
+#else
+ NULL
+#endif
};
static int
sasl_auxprop_plug_t **plug,
const char *plugname)
{
- if ( !out_version | !plug ) return SASL_BADPARAM;
+ if ( !out_version || !plug ) return SASL_BADPARAM;
if ( max_version < SASL_AUXPROP_PLUG_VERSION ) return SASL_BADVERS;
a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_userPassword );
if ( !a ) return 0;
if ( ! access_allowed( op, rs->sr_entry, slap_schema.si_ad_userPassword,
- NULL, ACL_AUTH, NULL ) ) return 0;
+ NULL, ACL_AUTH, NULL ) )
+ {
+ return 0;
+ }
for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) {
if ( !lutil_passwd( bv, &ci->cred, NULL, &rs->sr_text ) ) {
op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
if ( op.o_bd && op.o_bd->be_search ) {
- slap_callback cb = { sasl_cb_checkpass, NULL };
+ slap_callback cb = { NULL, sasl_cb_checkpass, NULL, NULL };
SlapReply rs = {REP_RESULT};
ci.cred.bv_val = (char *)pass;
* auxiliary property, so that we can refer to it in sasl_authorize
* without interfering with anything else. Also, the SASL username
* buffer is constrained to 256 characters, and our DNs could be
- * much longer (totally arbitrary length)...
+ * much longer (SLAP_LDAPDN_MAXLEN, currently set to 8192)
*/
static int
slap_sasl_canonicalize(
if ( inlen > out_max )
inlen = out_max-1;
+ /* This is a Simple Bind using SPASSWD. That means the in-directory
+ * userPassword of the Binding user already points at SASL, so it
+ * cannot be used to actually satisfy a password comparison. Just
+ * ignore it, some other mech will process it.
+ */
+ if ( !conn->c_sasl_bindop ||
+ conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) goto done;
+
/* See if we need to add request, can only do it once */
prop_getnames( props, slap_propnames, auxvals );
if ( !auxvals[0].name )
struct berval authcDN, authzDN;
int rc;
+ /* Simple Binds don't support proxy authorization, ignore it */
+ if ( !conn->c_sasl_bindop ||
+ conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) return SASL_OK;
+
#ifdef NEW_LOGGING
LDAP_LOG( TRANSPORT, ENTRY,
"slap_sasl_authorize: conn %d authcid=\"%s\" authzid=\"%s\"\n",
/* Skip PROP_CONN */
prop_getnames( props, slap_propnames+1, auxvals );
+ /* Should not happen */
+ if ( !auxvals[0].values ) {
+ sasl_seterror( sconn, 0, "invalid authcid" );
+ return SASL_NOAUTHZ;
+ }
+
AC_MEMCPY( &authcDN, auxvals[0].values[0], sizeof(authcDN) );
/* Nothing to do if no authzID was given */
sasl_version( NULL, &rc );
if ( ((rc >> 16) != ((SASL_VERSION_MAJOR << 8)|SASL_VERSION_MINOR)) ||
- (rc & 0xffff) < SASL_VERSION_STEP) {
+ (rc & 0xffff) < SASL_VERSION_STEP)
+ {
char version[sizeof("xxx.xxx.xxxxx")];
sprintf( version, "%u.%d.%d", (unsigned)rc >> 24, (rc >> 16) & 0xff,
rc & 0xffff );
0, 0, 0 );
#endif
-
/* default security properties */
memset( &sasl_secprops, '\0', sizeof(sasl_secprops) );
sasl_secprops.max_ssf = INT_MAX;
int slap_sasl_open( Connection *conn, int reopen )
{
- int cb, sc = LDAP_SUCCESS;
-#if SASL_VERSION_MAJOR >= 2
- char *ipremoteport = NULL, *iplocalport = NULL;
-#endif
-
+ int sc = LDAP_SUCCESS;
#ifdef HAVE_CYRUS_SASL
+ int cb;
+
sasl_conn_t *ctx = NULL;
sasl_callback_t *session_callbacks;
+#if SASL_VERSION_MAJOR >= 2
+ char *ipremoteport = NULL, *iplocalport = NULL;
+#endif
+
assert( conn->c_sasl_authctx == NULL );
if ( !reopen ) {
}
sc = slap_sasl_err2ldap( sc );
+
+#elif defined(SLAP_BUILTIN_SASL)
+ /* built-in SASL implementation */
+ SASL_CTX *ctx = (SASL_CTX *) SLAP_MALLOC(sizeof(SASL_CTX));
+ if( ctx == NULL ) return -1;
+
+ ctx->sc_external_ssf = 0;
+ ctx->sc_external_id.bv_len = 0;
+ ctx->sc_external_id.bv_val = NULL;
+
+ conn->c_sasl_authctx = ctx;
#endif
+
return sc;
}
int slap_sasl_external(
Connection *conn,
slap_ssf_t ssf,
- const char *auth_id )
+ struct berval *auth_id )
{
#if SASL_VERSION_MAJOR >= 2
int sc;
return LDAP_OTHER;
}
- sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL, auth_id );
+ sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL,
+ auth_id ? auth_id->bv_val : NULL );
if ( sc != SASL_OK ) {
return LDAP_OTHER;
memset( &extprops, '\0', sizeof(extprops) );
extprops.ssf = ssf;
- extprops.auth_id = (char *) auth_id;
+ extprops.auth_id = auth_id ? auth_id->bv_val : NULL;
sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
(void *) &extprops );
if ( sc != SASL_OK ) {
return LDAP_OTHER;
}
+#elif defined(SLAP_BUILTIN_SASL)
+ /* built-in SASL implementation */
+ SASL_CTX *ctx = conn->c_sasl_authctx;
+ if ( ctx == NULL ) return LDAP_UNAVAILABLE;
+
+ ctx->sc_external_ssf = ssf;
+ if( auth_id ) {
+ ctx->sc_external_id = *auth_id;
+ auth_id->bv_len = 0;
+ auth_id->bv_val = NULL;
+ } else {
+ ctx->sc_external_id.bv_len = 0;
+ ctx->sc_external_id.bv_val = NULL;
+ }
#endif
return LDAP_SUCCESS;
ch_free( mechstr );
#endif
}
+#elif defined(SLAP_BUILTIN_SASL)
+ /* builtin SASL implementation */
+ SASL_CTX *ctx = conn->c_sasl_authctx;
+ if ( ctx != NULL && ctx->sc_external_id.bv_val ) {
+ /* should check ssf */
+ mechs = ldap_str2charray( "EXTERNAL", "," );
+ }
#endif
return mechs;
if( ctx != NULL ) {
sasl_dispose( &ctx );
}
- if ( conn->c_sasl_sockctx && conn->c_sasl_authctx != conn->c_sasl_sockctx ) {
+ if ( conn->c_sasl_sockctx &&
+ conn->c_sasl_authctx != conn->c_sasl_sockctx )
+ {
ctx = conn->c_sasl_sockctx;
sasl_dispose( &ctx );
}
free( conn->c_sasl_extra );
conn->c_sasl_extra = NULL;
+
+#elif defined(SLAP_BUILTIN_SASL)
+ SASL_CTX *ctx = conn->c_sasl_authctx;
+ if( ctx ) {
+ if( ctx->sc_external_id.bv_val ) {
+ free( ctx->sc_external_id.bv_val );
+ ctx->sc_external_id.bv_val = NULL;
+ }
+ free( ctx );
+ conn->c_sasl_authctx = NULL;
+ }
#endif
return LDAP_SUCCESS;
op->orb_cred.bv_len );
#endif
-
if( ctx == NULL ) {
send_ldap_error( op, rs, LDAP_UNAVAILABLE,
"SASL unavailable on this session" );
Debug(LDAP_DEBUG_TRACE, "<== slap_sasl_bind: rc=%d\n", rs->sr_err, 0, 0);
#endif
+#elif defined(SLAP_BUILTIN_SASL)
+ /* built-in SASL implementation */
+ SASL_CTX *ctx = op->o_conn->c_sasl_authctx;
+
+ if ( ctx == NULL ) {
+ send_ldap_error( op, rs, LDAP_OTHER,
+ "Internal SASL Error" );
+
+ } else if ( bvmatch( &ext_bv, &op->o_conn->c_sasl_bind_mech ) ) {
+ /* EXTERNAL */
+
+ if( op->orb_cred.bv_len ) {
+ rs->sr_text = "proxy authorization not support";
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ send_ldap_result( op, rs );
+ } else {
+ op->orb_edn = ctx->sc_external_id;
+ rs->sr_err = LDAP_SUCCESS;
+ rs->sr_sasldata = NULL;
+ send_ldap_sasl( op, rs );
+ }
+
+ } else {
+ send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED,
+ "requested SASL mechanism not supported" );
+ }
#else
- send_ldap_error( op, rs, LDAP_UNAVAILABLE,
+ send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED,
"SASL not supported" );
#endif
#define SET_DN 1
#define SET_U 2
-static struct berval ext_bv = BER_BVC( "EXTERNAL" );
-
int slap_sasl_getdn( Connection *conn, Operation *op, char *id, int len,
char *user_realm, struct berval *dn, int flags )
{
- char *c1;
int rc, is_dn = SET_NONE, do_norm = 1;
- struct berval dn2;
+ struct berval dn2, *mech;
+
+ assert( conn );
#ifdef NEW_LOGGING
LDAP_LOG( TRANSPORT, ENTRY,
"slap_sasl_getdn: conn %d id=%s [len=%d]\n",
- conn ? conn->c_connid : -1, id ? (*id ? id : "<empty>") : "NULL", len );
+ conn->c_connid, id ? (*id ? id : "<empty>") : "NULL", len );
#else
Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: id=%s [len=%d]\n",
id ? ( *id ? id : "<empty>" ) : "NULL", len, 0 );
len = 0;
}
+ if ( conn->c_sasl_bind_mech.bv_len ) {
+ mech = &conn->c_sasl_bind_mech;
+ } else {
+ mech = &conn->c_authmech;
+ }
+
/* An authcID needs to be converted to authzID form. Set the
* values directly into *dn; they will be normalized later. (and
* normalizing always makes a new copy.) An ID from a TLS certificate
* is already normalized, so copy it and skip normalization.
*/
if( flags & SLAP_GETDN_AUTHCID ) {
- if( conn->c_sasl_bind_mech.bv_len == ext_bv.bv_len &&
- strcasecmp( ext_bv.bv_val, conn->c_sasl_bind_mech.bv_val ) == 0 )
- {
+ if( bvmatch( mech, &ext_bv )) {
/* EXTERNAL DNs are already normalized */
do_norm = 0;
is_dn = SET_DN;
/* Username strings */
if( is_dn == SET_U ) {
- char *p, *realm;
+ char *p;
+ struct berval realm = { 0, NULL }, c1 = *dn;
+
len = dn->bv_len + sizeof("uid=")-1 + sizeof(",cn=auth")-1;
- /* username may have embedded realm name */
- if( ( realm = strchr( dn->bv_val, '@') ) ) {
- *realm++ = '\0';
- len += sizeof(",cn=")-2;
- } else if( user_realm && *user_realm ) {
- len += strlen( user_realm ) + sizeof(",cn=")-1;
+ if( user_realm && *user_realm ) {
+ realm.bv_val = user_realm;
+ realm.bv_len = strlen( user_realm );
+ len += realm.bv_len + sizeof(",cn=") - 1;
}
- if( conn->c_sasl_bind_mech.bv_len ) {
- len += conn->c_sasl_bind_mech.bv_len + sizeof(",cn=")-1;
+ if( mech->bv_len ) {
+ len += mech->bv_len + sizeof(",cn=")-1;
}
/* Build the new dn */
- c1 = dn->bv_val;
dn->bv_val = sl_malloc( len+1, op->o_tmpmemctx );
if( dn->bv_val == NULL ) {
#ifdef NEW_LOGGING
return LDAP_OTHER;
}
p = lutil_strcopy( dn->bv_val, "uid=" );
- p = lutil_strncopy( p, c1, dn->bv_len );
+ p = lutil_strncopy( p, c1.bv_val, c1.bv_len );
- if( realm ) {
- int rlen = dn->bv_len - ( realm - c1 );
- p = lutil_strcopy( p, ",cn=" );
- p = lutil_strncopy( p, realm, rlen );
- realm[-1] = '@';
- } else if( user_realm && *user_realm ) {
+ if( realm.bv_len ) {
p = lutil_strcopy( p, ",cn=" );
- p = lutil_strcopy( p, user_realm );
+ p = lutil_strncopy( p, realm.bv_val, realm.bv_len );
}
- if( conn->c_sasl_bind_mech.bv_len ) {
+ if( mech->bv_len ) {
p = lutil_strcopy( p, ",cn=" );
- p = lutil_strcopy( p, conn->c_sasl_bind_mech.bv_val );
+ p = lutil_strcopy( p, mech->bv_val );
}
p = lutil_strcopy( p, ",cn=auth" );
dn->bv_len = p - dn->bv_val;
LDAP_LOG( TRANSPORT, ENTRY,
"slap_sasl_getdn: u:id converted to %s.\n", dn->bv_val, 0, 0 );
#else
- Debug( LDAP_DEBUG_TRACE, "getdn: u:id converted to %s\n", dn->bv_val,0,0 );
+ Debug( LDAP_DEBUG_TRACE, "slap_sasl_getdn: u:id converted to %s\n", dn->bv_val,0,0 );
#endif
} else {
}
/* Run thru regexp */
- slap_sasl2dn( op, dn, &dn2 );
+ slap_sasl2dn( op, dn, &dn2, flags );
if( dn2.bv_val ) {
sl_free( dn->bv_val, op->o_tmpmemctx );
*dn = dn2;