X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fsasl.c;h=484300bf6f36b8ce81345060d555cd2c57bc9b49;hb=4361a942abb69d6b3dbae637cddb4055080fe6fa;hp=10b17ca62f33e0d7d0ab3574b0c81660014ab697;hpb=8f58409749f270fb02ad5dd2b66159600e8eb272;p=openldap
diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c
index 10b17ca62f..484300bf6f 100644
--- a/servers/slapd/sasl.c
+++ b/servers/slapd/sasl.c
@@ -1,7 +1,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
- * Copyright 1998-2005 The OpenLDAP Foundation.
+ * Copyright 1998-2006 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -147,13 +147,13 @@ slap_sasl_log(
static const char *slap_propnames[] = {
"*slapConn", "*slapAuthcDN", "*slapAuthzDN", NULL };
-static Filter generic_filter = { LDAP_FILTER_PRESENT };
+static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL };
static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
-#define PROP_CONN 0
-#define PROP_AUTHC 1
-#define PROP_AUTHZ 2
-#define PROP_COUNT 3 /* Number of properties we used */
+#define SLAP_SASL_PROP_CONN 0
+#define SLAP_SASL_PROP_AUTHC 1
+#define SLAP_SASL_PROP_AUTHZ 2
+#define SLAP_SASL_PROP_COUNT 3 /* Number of properties we used */
typedef struct lookup_info {
int flags;
@@ -163,6 +163,8 @@ typedef struct lookup_info {
static slap_response sasl_ap_lookup;
+static struct berval sc_cleartext = BER_BVC("{CLEARTEXT}");
+
static int
sasl_ap_lookup( Operation *op, SlapReply *rs )
{
@@ -171,8 +173,7 @@ sasl_ap_lookup( Operation *op, SlapReply *rs )
Attribute *a;
const char *text;
int rc, i;
- slap_callback *tmp = op->o_callback;
- lookup_info *sl = tmp->sc_private;
+ lookup_info *sl = (lookup_info *)op->o_callback->sc_private;
if (rs->sr_type != REP_SEARCH) return 0;
@@ -183,7 +184,7 @@ sasl_ap_lookup( Operation *op, SlapReply *rs )
if ( sl->flags & SASL_AUXPROP_AUTHZID ) continue;
/* Skip our private properties */
if ( !strcmp( name, slap_propnames[0] )) {
- i += PROP_COUNT-1;
+ i += SLAP_SASL_PROP_COUNT - 1;
continue;
}
name++;
@@ -200,6 +201,14 @@ sasl_ap_lookup( Operation *op, SlapReply *rs )
"slap_ap_lookup: str2ad(%s): %s\n", name, text, 0 );
continue;
}
+
+ /* If it's the rootdn and a rootpw was present, we already set
+ * it so don't override it here.
+ */
+ if ( ad == slap_schema.si_ad_userPassword && sl->list[i].values &&
+ be_isroot_dn( op->o_bd, &op->o_req_ndn ))
+ continue;
+
a = attr_find( rs->sr_entry->e_attrs, ad );
if ( !a ) continue;
if ( ! access_allowed( op, rs->sr_entry, ad, NULL, ACL_AUTH, NULL ) ) {
@@ -210,6 +219,33 @@ sasl_ap_lookup( Operation *op, SlapReply *rs )
sl->list[i].name );
}
for ( bv = a->a_vals; bv->bv_val; bv++ ) {
+ /* ITS#3846 don't give hashed passwords to SASL */
+ if ( ad == slap_schema.si_ad_userPassword &&
+ bv->bv_val[0] == '{' /*}*/ )
+ {
+ if ( lutil_passwd_scheme( bv->bv_val ) ) {
+ /* If it's not a recognized scheme, just assume it's
+ * a cleartext password that happened to include brackets.
+ *
+ * If it's a recognized scheme, skip this value, unless the
+ * scheme is {CLEARTEXT}. In that case, skip over the
+ * scheme name and use the remainder. If there is nothing
+ * past the scheme name, skip this value.
+ */
+#ifdef SLAPD_CLEARTEXT
+ if ( !ber_bvstrcasecmp( bv, &sc_cleartext ) ) {
+ struct berval cbv;
+ cbv.bv_len = bv->bv_len - sc_cleartext.bv_len;
+ if ( cbv.bv_len > 0 ) {
+ cbv.bv_val = bv->bv_val + sc_cleartext.bv_len;
+ sl->sparams->utils->prop_set( sl->sparams->propctx,
+ sl->list[i].name, cbv.bv_val, cbv.bv_len );
+ }
+ }
+#endif
+ continue;
+ }
+ }
sl->sparams->utils->prop_set( sl->sparams->propctx,
sl->list[i].name, bv->bv_val, bv->bv_len );
}
@@ -237,19 +273,19 @@ slap_auxprop_lookup(
/* Find our DN and conn first */
for( i = 0; sl.list[i].name; i++ ) {
if ( sl.list[i].name[0] == '*' ) {
- if ( !strcmp( sl.list[i].name, slap_propnames[PROP_CONN] ) ) {
+ if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) {
if ( sl.list[i].values && sl.list[i].values[0] )
AC_MEMCPY( &conn, sl.list[i].values[0], sizeof( conn ) );
continue;
}
if ( (flags & SASL_AUXPROP_AUTHZID) &&
- !strcmp( sl.list[i].name, slap_propnames[PROP_AUTHZ] ) ) {
+ !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZ] ) ) {
if ( sl.list[i].values && sl.list[i].values[0] )
AC_MEMCPY( &op.o_req_ndn, sl.list[i].values[0], sizeof( struct berval ) );
break;
}
- if ( !strcmp( sl.list[i].name, slap_propnames[PROP_AUTHC] ) ) {
+ if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) {
if ( sl.list[i].values && sl.list[i].values[0] ) {
AC_MEMCPY( &op.o_req_ndn, sl.list[i].values[0], sizeof( struct berval ) );
if ( !(flags & SASL_AUXPROP_AUTHZID) )
@@ -267,7 +303,7 @@ slap_auxprop_lookup(
if ( flags & SASL_AUXPROP_AUTHZID ) continue;
/* Skip our private properties */
if ( !strcmp( name, slap_propnames[0] )) {
- i += PROP_COUNT-1;
+ i += SLAP_SASL_PROP_COUNT - 1;
continue;
}
name++;
@@ -288,26 +324,70 @@ slap_auxprop_lookup(
op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
- if ( op.o_bd && op.o_bd->be_search ) {
- SlapReply rs = {REP_RESULT};
- op.o_hdr = conn->c_sasl_bindop->o_hdr;
- op.o_tag = LDAP_REQ_SEARCH;
- 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_req_dn = op.o_req_ndn;
- op.ors_scope = LDAP_SCOPE_BASE;
- op.ors_deref = LDAP_DEREF_NEVER;
- op.ors_tlimit = SLAP_NO_LIMIT;
- op.ors_slimit = 1;
- op.ors_filter = &generic_filter;
- op.ors_filterstr = generic_filterstr;
- /* FIXME: we want all attributes, right? */
- op.ors_attrs = NULL;
-
- op.o_bd->be_search( &op, &rs );
+ if ( op.o_bd ) {
+ /* For rootdn, see if we can use the rootpw */
+ if ( be_isroot_dn( op.o_bd, &op.o_req_ndn ) &&
+ !BER_BVISEMPTY( &op.o_bd->be_rootpw )) {
+ struct berval cbv = BER_BVNULL;
+
+ /* If there's a recognized scheme, see if it's CLEARTEXT */
+ if ( lutil_passwd_scheme( op.o_bd->be_rootpw.bv_val )) {
+ if ( !strncasecmp( op.o_bd->be_rootpw.bv_val,
+ sc_cleartext.bv_val, sc_cleartext.bv_len )) {
+
+ /* If it's CLEARTEXT, skip past scheme spec */
+ cbv.bv_len = op.o_bd->be_rootpw.bv_len -
+ sc_cleartext.bv_len;
+ if ( cbv.bv_len ) {
+ cbv.bv_val = op.o_bd->be_rootpw.bv_val +
+ sc_cleartext.bv_len;
+ }
+ }
+ /* No scheme, use the whole value */
+ } else {
+ cbv = op.o_bd->be_rootpw;
+ }
+ if ( !BER_BVISEMPTY( &cbv )) {
+ for( i = 0; sl.list[i].name; i++ ) {
+ const char *name = sl.list[i].name;
+
+ if ( name[0] == '*' ) {
+ if ( flags & SASL_AUXPROP_AUTHZID ) continue;
+ name++;
+ } else if ( !(flags & SASL_AUXPROP_AUTHZID ) )
+ continue;
+
+ if ( !strcasecmp(name,"userPassword") ) {
+ sl.sparams->utils->prop_set( sl.sparams->propctx,
+ sl.list[i].name, cbv.bv_val, cbv.bv_len );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( op.o_bd->be_search ) {
+ SlapReply rs = {REP_RESULT};
+ op.o_hdr = conn->c_sasl_bindop->o_hdr;
+ op.o_tag = LDAP_REQ_SEARCH;
+ op.o_dn = conn->c_ndn;
+ op.o_ndn = conn->c_ndn;
+ op.o_callback = &cb;
+ slap_op_time( &op.o_time, &op.o_tincr );
+ op.o_do_not_cache = 1;
+ op.o_is_auth_check = 1;
+ op.o_req_dn = op.o_req_ndn;
+ op.ors_scope = LDAP_SCOPE_BASE;
+ op.ors_deref = LDAP_DEREF_NEVER;
+ op.ors_tlimit = SLAP_NO_LIMIT;
+ op.ors_slimit = 1;
+ op.ors_filter = &generic_filter;
+ op.ors_filterstr = generic_filterstr;
+ /* FIXME: we want all attributes, right? */
+ op.ors_attrs = NULL;
+
+ op.o_bd->be_search( &op, &rs );
+ }
}
}
}
@@ -342,12 +422,12 @@ slap_auxprop_store(
/* Find our DN and conn first */
for( i = 0; pr[i].name; i++ ) {
if ( pr[i].name[0] == '*' ) {
- if ( !strcmp( pr[i].name, slap_propnames[PROP_CONN] ) ) {
+ if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) {
if ( pr[i].values && pr[i].values[0] )
AC_MEMCPY( &conn, pr[i].values[0], sizeof( conn ) );
continue;
}
- if ( !strcmp( pr[i].name, slap_propnames[PROP_AUTHC] ) ) {
+ if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) {
if ( pr[i].values && pr[i].values[0] ) {
AC_MEMCPY( &op.o_req_ndn, pr[i].values[0], sizeof( struct berval ) );
}
@@ -391,25 +471,20 @@ slap_auxprop_store(
&text, textbuf, textlen );
if ( rc == LDAP_SUCCESS ) {
- rc = slap_mods_opattrs( &op, modlist, modtail,
- &text, textbuf, textlen, 1 );
-
- if ( rc == LDAP_SUCCESS ) {
- op.o_hdr = conn->c_sasl_bindop->o_hdr;
- op.o_tag = LDAP_REQ_MODIFY;
- op.o_ndn = op.o_req_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_req_dn = op.o_req_ndn;
- op.orm_modlist = modlist;
+ op.o_hdr = conn->c_sasl_bindop->o_hdr;
+ op.o_tag = LDAP_REQ_MODIFY;
+ op.o_ndn = op.o_req_ndn;
+ op.o_callback = &cb;
+ slap_op_time( &op.o_time, &op.o_tincr );
+ op.o_do_not_cache = 1;
+ op.o_is_auth_check = 1;
+ op.o_req_dn = op.o_req_ndn;
+ op.orm_modlist = modlist;
- rc = op.o_bd->be_modify( &op, &rs );
- }
+ rc = op.o_bd->be_modify( &op, &rs );
}
}
- slap_mods_free( modlist );
+ slap_mods_free( modlist, 1 );
return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK;
}
#endif /* SASL_VERSION_FULL >= 2.1.16 */
@@ -466,7 +541,7 @@ slap_sasl_canonicalize(
{
Connection *conn = (Connection *)context;
struct propctx *props = sasl_auxprop_getctx( sconn );
- struct propval auxvals[3];
+ struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } };
struct berval dn;
int rc, which;
const char *names[2];
@@ -499,13 +574,13 @@ slap_sasl_canonicalize(
prop_request( props, slap_propnames );
if ( flags & SASL_CU_AUTHID )
- which = PROP_AUTHC;
+ which = SLAP_SASL_PROP_AUTHC;
else
- which = PROP_AUTHZ;
+ which = SLAP_SASL_PROP_AUTHZ;
/* Need to store the Connection for auxprop_lookup */
- if ( !auxvals[PROP_CONN].values ) {
- names[0] = slap_propnames[PROP_CONN];
+ if ( !auxvals[SLAP_SASL_PROP_CONN].values ) {
+ names[0] = slap_propnames[SLAP_SASL_PROP_CONN];
names[1] = NULL;
prop_set( props, names[0], (char *)&conn, sizeof( conn ) );
}
@@ -529,7 +604,7 @@ slap_sasl_canonicalize(
* it does authzID before the authcID. If we see that authzID
* has already been done, don't do anything special with authcID.
*/
- if ( flags == SASL_CU_AUTHID && !auxvals[PROP_AUTHZ].values ) {
+ if ( flags == SASL_CU_AUTHID && !auxvals[SLAP_SASL_PROP_AUTHZ].values ) {
conn->c_sasl_dn.bv_val = (char *) in;
} else if ( flags == SASL_CU_AUTHZID && conn->c_sasl_dn.bv_val ) {
rc = strcmp( in, conn->c_sasl_dn.bv_val );
@@ -578,8 +653,12 @@ slap_sasl_authorize(
struct propctx *props)
{
Connection *conn = (Connection *)context;
- struct propval auxvals[3];
- struct berval authcDN, authzDN=BER_BVNULL;
+ /* actually:
+ * (SLAP_SASL_PROP_COUNT - 1) because we skip "conn",
+ * + 1 for NULL termination?
+ */
+ struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } };
+ struct berval authcDN, authzDN = BER_BVNULL;
int rc;
/* Simple Binds don't support proxy authorization, ignore it */
@@ -594,7 +673,7 @@ slap_sasl_authorize(
BER_BVZERO( &conn->c_sasl_dn );
}
- /* Skip PROP_CONN */
+ /* Skip SLAP_SASL_PROP_CONN */
prop_getnames( props, slap_propnames+1, auxvals );
/* Should not happen */
@@ -624,7 +703,17 @@ slap_sasl_authorize(
return SASL_NOAUTHZ;
}
- conn->c_sasl_authz_dn = authzDN;
+ /* FIXME: we need yet another dup because slap_sasl_getdn()
+ * is using the bind operation slab */
+ if ( conn->c_sasl_bindop ) {
+ ber_dupbv( &conn->c_sasl_authz_dn, &authzDN );
+ slap_sl_free( authzDN.bv_val,
+ conn->c_sasl_bindop->o_tmpmemctx );
+
+ } else {
+ conn->c_sasl_authz_dn = authzDN;
+ }
+
ok:
if (conn->c_sasl_bindop) {
Statslog( LDAP_DEBUG_STATS,
@@ -648,7 +737,7 @@ slap_sasl_authorize(
const char **user,
const char **errstr)
{
- struct berval authcDN, authzDN;
+ struct berval authcDN, authzDN = BER_BVNULL;
int rc;
Connection *conn = context;
char *realm;
@@ -702,7 +791,7 @@ slap_sasl_authorize(
return SASL_NOAUTHZ;
}
- rc = slap_sasl_authorized(conn->c_sasl_bindop, &authcDN, &authzDN );
+ rc = slap_sasl_authorized( conn->c_sasl_bindop, &authcDN, &authzDN );
if( rc ) {
Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
"proxy authorization disallowed (%d)\n",
@@ -712,7 +801,17 @@ slap_sasl_authorize(
ch_free( authzDN.bv_val );
return SASL_NOAUTHZ;
}
- conn->c_sasl_authz_dn = authzDN;
+
+ /* FIXME: we need yet another dup because slap_sasl_getdn()
+ * is using the bind operation slab */
+ if ( conn->c_sasl_bindop ) {
+ ber_dupbv( &conn->c_sasl_authz_dn, &authzDN );
+ slap_sl_free( authzDN.bv_val,
+ conn->c_sasl_bindop->o_tmpmemctx );
+
+ } else {
+ conn->c_sasl_authz_dn = authzDN;
+ }
ok:
Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
@@ -720,7 +819,7 @@ ok:
(long) (conn ? conn->c_connid : -1),
authzDN.bv_val ? authzDN.bv_val : "", 0 );
- if (conn->c_sasl_bindop) {
+ if ( conn->c_sasl_bindop ) {
Statslog( LDAP_DEBUG_STATS,
"conn=%lu op=%lu BIND authcid=\"%s\" authzid=\"%s\"\n",
conn->c_connid, conn->c_sasl_bindop->o_opid,
@@ -737,6 +836,18 @@ slap_sasl_err2ldap( int saslerr )
{
int rc;
+ /* map SASL errors to LDAP resultCode returned by:
+ * sasl_server_new()
+ * SASL_OK, SASL_NOMEM
+ * sasl_server_step()
+ * SASL_OK, SASL_CONTINUE, SASL_TRANS, SASL_BADPARAM, SASL_BADPROT,
+ * ...
+ * sasl_server_start()
+ * + SASL_NOMECH
+ * sasl_setprop()
+ * SASL_OK, SASL_BADPARAM
+ */
+
switch (saslerr) {
case SASL_OK:
rc = LDAP_SUCCESS;
@@ -745,8 +856,6 @@ slap_sasl_err2ldap( int saslerr )
rc = LDAP_SASL_BIND_IN_PROGRESS;
break;
case SASL_FAIL:
- rc = LDAP_OTHER;
- break;
case SASL_NOMEM:
rc = LDAP_OTHER;
break;
@@ -754,6 +863,9 @@ slap_sasl_err2ldap( int saslerr )
rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
break;
case SASL_BADAUTH:
+ case SASL_NOUSER:
+ case SASL_TRANS:
+ case SASL_EXPIRED:
rc = LDAP_INVALID_CREDENTIALS;
break;
case SASL_NOAUTHZ:
@@ -763,6 +875,13 @@ slap_sasl_err2ldap( int saslerr )
case SASL_ENCRYPT:
rc = LDAP_INAPPROPRIATE_AUTH;
break;
+ case SASL_UNAVAIL:
+ case SASL_TRYAGAIN:
+ rc = LDAP_UNAVAILABLE;
+ break;
+ case SASL_DISABLED:
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ break;
default:
rc = LDAP_OTHER;
break;
@@ -1331,6 +1450,9 @@ int slap_sasl_bind( Operation *op, SlapReply *rs )
}
} else if ( sc == SASL_CONTINUE ) {
rs->sr_err = LDAP_SASL_BIND_IN_PROGRESS,
+#if SASL_VERSION_MAJOR >= 2
+ rs->sr_text = sasl_errdetail( ctx );
+#endif
rs->sr_sasldata = &response;
send_ldap_sasl( op, rs );
@@ -1343,9 +1465,7 @@ int slap_sasl_bind( Operation *op, SlapReply *rs )
}
#if SASL_VERSION_MAJOR < 2
- if( response.bv_len ) {
- ch_free( response.bv_val );
- }
+ if( response.bv_len ) ch_free( response.bv_val );
#endif
Debug(LDAP_DEBUG_TRACE, "<== slap_sasl_bind: rc=%d\n", rs->sr_err, 0, 0);
@@ -1492,17 +1612,19 @@ int slap_sasl_getdn( Connection *conn, Operation *op, struct berval *id,
int rc, is_dn = SET_NONE, do_norm = 1;
struct berval dn2, *mech;
- assert( conn );
- assert( id );
+ assert( conn != NULL );
+ assert( id != NULL );
- Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: conn %d id=%s [len=%d]\n",
+ Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: conn %lu id=%s [len=%lu]\n",
conn->c_connid,
BER_BVISNULL( id ) ? "NULL" : ( BER_BVISEMPTY( id ) ? "" : id->bv_val ),
- BER_BVISNULL( id ) ? 0 : ( BER_BVISEMPTY( id ) ? 0 : id->bv_len ) );
+ BER_BVISNULL( id ) ? 0 : ( BER_BVISEMPTY( id ) ? 0 :
+ (unsigned long) id->bv_len ) );
if ( !op ) {
op = conn->c_sasl_bindop;
}
+ assert( op != NULL );
BER_BVZERO( dn );
@@ -1616,13 +1738,16 @@ int slap_sasl_getdn( Connection *conn, Operation *op, struct berval *id,
irdn++;
DN[ irdn ] = NULL;
- rc = ldap_dn2bv_x( DN, dn, LDAP_DN_FORMAT_LDAPV3, op->o_tmpmemctx );
+ rc = ldap_dn2bv_x( DN, dn, LDAP_DN_FORMAT_LDAPV3,
+ op->o_tmpmemctx );
if ( rc != LDAP_SUCCESS ) {
BER_BVZERO( dn );
return rc;
}
- Debug( LDAP_DEBUG_TRACE, "slap_sasl_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 );
} else {
@@ -1652,7 +1777,8 @@ int slap_sasl_getdn( Connection *conn, Operation *op, struct berval *id,
if( !BER_BVISNULL( &dn2 ) ) {
slap_sl_free( dn->bv_val, op->o_tmpmemctx );
*dn = dn2;
- Debug( LDAP_DEBUG_TRACE, "getdn: dn:id converted to %s\n",
+ Debug( LDAP_DEBUG_TRACE,
+ "slap_sasl_getdn: dn:id converted to %s\n",
dn->bv_val, 0, 0 );
}