Newer
Older
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
#include "portable.h"
#include <stdio.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <ac/stdlib.h>
#include <ac/string.h>
#include <lber.h>
#include <ldap_log.h>
#ifdef ENABLE_REWRITE
#include <rewrite.h>
#endif
#ifdef HAVE_CYRUS_SASL
# ifdef HAVE_SASL_SASL_H
# include <sasl/sasl.h>
# include <sasl/saslplug.h>
#define SASL_VERSION_FULL ((SASL_VERSION_MAJOR << 16) |\
(SASL_VERSION_MINOR << 8) | SASL_VERSION_STEP)
static sasl_security_properties_t sasl_secprops;
#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
static struct berval ext_bv = BER_BVC( "EXTERNAL" );
/* Just use our internal auxprop by default */
static int
slap_sasl_getopt(
void *context,
const char *plugin_name,
const char *option,
const char **result,
unsigned *len)
{
if ( strcmp( option, "auxprop_plugin" )) {
return SASL_FAIL;
}
if ( slap_sasl_auxprops )
*result = slap_sasl_auxprops;
else
*result = "slapd";
return SASL_OK;
}
void *context,
int priority,
const char *message)
{
Connection *conn = context;
int level;
const char * label;
if ( message == NULL ) {
return SASL_BADPARAM;
}
switch (priority) {
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
case SASL_LOG_NONE:
level = LDAP_DEBUG_NONE;
label = "None";
break;
case SASL_LOG_ERR:
level = LDAP_DEBUG_ANY;
label = "Error";
break;
case SASL_LOG_FAIL:
level = LDAP_DEBUG_ANY;
label = "Failure";
break;
case SASL_LOG_WARN:
level = LDAP_DEBUG_TRACE;
label = "Warning";
break;
case SASL_LOG_NOTE:
level = LDAP_DEBUG_TRACE;
label = "Notice";
break;
case SASL_LOG_DEBUG:
level = LDAP_DEBUG_TRACE;
label = "Debug";
break;
case SASL_LOG_TRACE:
level = LDAP_DEBUG_TRACE;
label = "Trace";
break;
case SASL_LOG_PASS:
level = LDAP_DEBUG_TRACE;
label = "Password Trace";
break;
static const char *slap_propnames[] = {
"*slapConn", "*slapAuthcDNlen", "*slapAuthcDN",
"*slapAuthzDNlen", "*slapAuthzDN", NULL };
static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL };
static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
#define SLAP_SASL_PROP_CONN 0
#define SLAP_SASL_PROP_AUTHCLEN 1
#define SLAP_SASL_PROP_AUTHC 2
#define SLAP_SASL_PROP_AUTHZLEN 3
#define SLAP_SASL_PROP_AUTHZ 4
#define SLAP_SASL_PROP_COUNT 5 /* Number of properties we used */
typedef struct lookup_info {
int flags;
const struct propval *list;
sasl_server_params_t *sparams;
} 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 )
{
BerVarray bv;
AttributeDescription *ad;
Attribute *a;
const char *text;
int rc, i;
lookup_info *sl = (lookup_info *)op->o_callback->sc_private;
if (rs->sr_type != REP_SEARCH) return 0;
const char *name = sl->list[i].name;
if ( name[0] == '*' ) {
if ( sl->flags & SASL_AUXPROP_AUTHZID ) continue;
/* Skip our private properties */
if ( !strcmp( name, slap_propnames[0] )) {
i += SLAP_SASL_PROP_COUNT - 1;
name++;
} else if ( !(sl->flags & SASL_AUXPROP_AUTHZID ) )
continue;
if ( sl->list[i].values ) {
if ( !(sl->flags & SASL_AUXPROP_OVERRIDE) ) continue;
}
ad = NULL;
rc = slap_str2ad( name, &ad, &text );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE,
"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 ) ) {
continue;
}
if ( sl->list[i].values && ( sl->flags & SASL_AUXPROP_OVERRIDE ) ) {
sl->sparams->utils->prop_erase( sl->sparams->propctx,
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 ( !strncasecmp( bv->bv_val, sc_cleartext.bv_val,
sc_cleartext.bv_len )) {
struct berval cbv;
cbv.bv_len = bv->bv_len - sc_cleartext.bv_len;
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 );
}
}
return LDAP_SUCCESS;
}
#if SASL_VERSION_FULL >= 0x020118
static int
#else
static void
slap_auxprop_lookup(
void *glob_context,
sasl_server_params_t *sparams,
unsigned flags,
const char *user,
unsigned ulen)
{
OperationBuffer opbuf = {{ NULL }};
Connection *conn = NULL;
lookup_info sl;
sl.list = sparams->utils->prop_get( sparams->propctx );
sl.sparams = sparams;
sl.flags = flags;
/* Find our DN and conn first */
if ( sl.list[i].name[0] == '*' ) {
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 ) );
if ( flags & SASL_AUXPROP_AUTHZID ) {
if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZLEN] )) {
if ( sl.list[i].values && sl.list[i].values[0] )
AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0],
sizeof( op->o_req_ndn.bv_len ) );
} else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZ] )) {
if ( sl.list[i].values )
if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) {
if ( sl.list[i].values && sl.list[i].values[0] )
AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0],
sizeof( op->o_req_ndn.bv_len ) );
} else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) {
if ( sl.list[i].values ) {
if ( !(flags & SASL_AUXPROP_AUTHZID) )
break;
}
}
}
}
/* Now see what else needs to be fetched */
const char *name = sl.list[i].name;
if ( name[0] == '*' ) {
if ( flags & SASL_AUXPROP_AUTHZID ) continue;
/* Skip our private properties */
if ( !strcmp( name, slap_propnames[0] )) {
i += SLAP_SASL_PROP_COUNT - 1;
name++;
} else if ( !(flags & SASL_AUXPROP_AUTHZID ) )
continue;
if ( sl.list[i].values ) {
if ( !(flags & SASL_AUXPROP_OVERRIDE) ) continue;
}
doit = 1;
}
if (doit) {
slap_callback cb = { NULL, sasl_ap_lookup, NULL, NULL };
cb.sc_private = &sl;
/* 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 */
sc_cleartext.bv_len;
if ( cbv.bv_len ) {
sc_cleartext.bv_len;
}
}
/* No scheme, use the whole value */
} else {
}
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;
}
}
}
}
SlapReply rs = {REP_RESULT};
op->o_hdr = conn->c_sasl_bindop->o_hdr;
op->o_controls = opbuf.ob_controls;
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? */
}
}
#if SASL_VERSION_FULL >= 0x020118
return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK;
#endif
}
static int
slap_auxprop_store(
void *glob_context,
sasl_server_params_t *sparams,
struct propctx *prctx,
const char *user,
unsigned ulen)
{
Operation op = {0};
SlapReply rs = {REP_RESULT};
int rc, i;
unsigned j;
Connection *conn = NULL;
const struct propval *pr;
Modifications *modlist = NULL, **modtail = &modlist, *mod;
slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
char textbuf[SLAP_TEXT_BUFLEN];
const char *text;
size_t textlen = sizeof(textbuf);
/* just checking if we are enabled */
if (!prctx) return SASL_OK;
if (!sparams || !user) return SASL_BADPARAM;
pr = sparams->utils->prop_get( sparams->propctx );
/* 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[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[SLAP_SASL_PROP_AUTHCLEN] )) {
if ( pr[i].values && pr[i].values[0] )
AC_MEMCPY( &op.o_req_ndn.bv_len, pr[i].values[0],
sizeof( op.o_req_ndn.bv_len ) );
} else if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) {
if ( pr[i].values )
op.o_req_ndn.bv_val = (char *)pr[i].values[0];
}
}
}
if (!conn || !op.o_req_ndn.bv_val) return SASL_BADPARAM;
op.o_bd = select_backend( &op.o_req_ndn, 1 );
if ( !op.o_bd || !op.o_bd->be_modify ) return SASL_FAIL;
pr = sparams->utils->prop_get( prctx );
if (!pr) return SASL_BADPARAM;
for (i=0; pr[i].name; i++);
if (!i) return SASL_BADPARAM;
for (i=0; pr[i].name; i++) {
mod = (Modifications *)ch_malloc( sizeof(Modifications) );
mod->sml_op = LDAP_MOD_REPLACE;
mod->sml_flags = 0;
ber_str2bv( pr[i].name, 0, 0, &mod->sml_type );
mod->sml_values = (struct berval *)ch_malloc( (pr[i].nvalues + 1) *
sizeof(struct berval));
for (j=0; j<pr[i].nvalues; j++) {
ber_str2bv( pr[i].values[j], 0, 1, &mod->sml_values[j]);
}
mod->sml_nvalues = NULL;
mod->sml_desc = NULL;
*modtail = mod;
modtail = &mod->sml_next;
}
*modtail = NULL;
rc = slap_mods_check( &op, modlist, &text, textbuf, textlen, NULL );
if ( rc == LDAP_SUCCESS ) {
rc = slap_mods_no_user_mod_check( &op, modlist,
&text, textbuf, textlen );
Pierangelo Masarati
committed
if ( rc == LDAP_SUCCESS ) {
if ( conn->c_sasl_bindop ) {
op.o_hdr = conn->c_sasl_bindop->o_hdr;
} else {
op.o_hdr = &oph;
memset( &oph, 0, sizeof(oph) );
operation_fake_init( conn, &op, ldap_pvt_thread_pool_context(), 0 );
}
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 );
Pierangelo Masarati
committed
}
slap_mods_free( modlist, 1 );
Pierangelo Masarati
committed
return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK;
static sasl_auxprop_plug_t slap_auxprop_plugin = {
0, /* Features */
0, /* spare */
NULL, /* glob_context */
NULL, /* auxprop_free */
slap_auxprop_lookup,
"slapd", /* name */
slap_auxprop_store /* the declaration of this member changed
* in cyrus SASL from 2.1.15 to 2.1.16 */
};
static int
slap_auxprop_init(
const sasl_utils_t *utils,
int max_version,
int *out_version,
sasl_auxprop_plug_t **plug,
const char *plugname)
{
if ( !out_version || !plug ) return SASL_BADPARAM;
if ( max_version < SASL_AUXPROP_PLUG_VERSION ) return SASL_BADVERS;
*out_version = SASL_AUXPROP_PLUG_VERSION;
*plug = &slap_auxprop_plugin;
return SASL_OK;
}
/* Convert a SASL authcid or authzid into a DN. Store the DN in an
* 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 (SLAP_LDAPDN_MAXLEN, currently set to 8192)
static int
slap_sasl_canonicalize(
sasl_conn_t *sconn,
void *context,
const char *in,
unsigned inlen,
unsigned flags,
const char *user_realm,
char *out,
unsigned out_max,
unsigned *out_len)
{
Connection *conn = (Connection *)context;
struct propctx *props = sasl_auxprop_getctx( sconn );
struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } };
int rc, which;
const char *names[2];
Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n",
(flags & SASL_CU_AUTHID) ? "authcid" : "authzid",
in ? in : "<empty>");
/* If name is too big, just truncate. We don't care, we're
* using DNs, not the usernames.
*/
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 )
prop_request( props, slap_propnames );
if ( flags & SASL_CU_AUTHID )
else
/* Need to store the Connection for auxprop_lookup */
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 ) );
}
/* Already been here? */
if ( auxvals[which].values )
goto done;
/* Normally we require an authzID to have a u: or dn: prefix.
* However, SASL frequently gives us an authzID that is just
* an exact copy of the authcID, without a prefix. We need to
* detect and allow this condition. If SASL calls canonicalize
* with SASL_CU_AUTHID|SASL_CU_AUTHZID this is a no-brainer.
* But if it's broken into two calls, we need to remember the
* authcID so that we can compare the authzID later. We store
* the authcID temporarily in conn->c_sasl_dn. We necessarily
* finish Canonicalizing before Authorizing, so there is no
* conflict with slap_sasl_authorize's use of this temp var.
*
* The SASL EXTERNAL mech is backwards from all the other mechs,
* 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[SLAP_SASL_PROP_AUTHZ].values ) {
} else if ( flags == SASL_CU_AUTHZID && conn->c_sasl_dn.bv_val ) {
rc = strcmp( in, conn->c_sasl_dn.bv_val );
conn->c_sasl_dn.bv_val = NULL;
/* They were equal, no work needed */
if ( !rc ) goto done;
}
bvin.bv_val = (char *)in;
bvin.bv_len = inlen;
rc = slap_sasl_getdn( conn, NULL, &bvin, (char *)user_realm, &dn,
(flags & SASL_CU_AUTHID) ? SLAP_GETDN_AUTHCID : SLAP_GETDN_AUTHZID );
if ( rc != LDAP_SUCCESS ) {
sasl_seterror( sconn, 0, ldap_err2string( rc ) );
return SASL_NOAUTHZ;
names[0] = slap_propnames[which];
names[1] = NULL;
prop_set( props, names[0], (char *)&dn.bv_len, sizeof( dn.bv_len ) );
which++;
names[0] = slap_propnames[which];
prop_set( props, names[0], dn.bv_val, dn.bv_len );
Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n",
dn.bv_val ? dn.bv_val : "<EMPTY>" );
/* Not needed any more, SASL has copied it */
if ( conn && conn->c_sasl_bindop )
conn->c_sasl_bindop->o_tmpfree( dn.bv_val, conn->c_sasl_bindop->o_tmpmemctx );
done:
AC_MEMCPY( out, in, inlen );
out[inlen] = '\0';
*out_len = inlen;
static int
slap_sasl_authorize(
sasl_conn_t *sconn,
void *context,
char *requested_user,
char *auth_identity,
unsigned alen,
const char *def_realm,
unsigned urlen,
struct propctx *props)
{
Connection *conn = (Connection *)context;
/* 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 */
if ( !conn->c_sasl_bindop ||
conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) return SASL_OK;
Debug( LDAP_DEBUG_ARGS, "SASL proxy authorize [conn=%ld]: "
"authcid=\"%s\" authzid=\"%s\"\n",
conn ? (long) conn->c_connid : -1L, auth_identity, requested_user );
if ( conn->c_sasl_dn.bv_val ) {
/* Skip SLAP_SASL_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.bv_len, auxvals[0].values[0], sizeof(authcDN.bv_len) );
authcDN.bv_val = auxvals[1].values ? (char *)auxvals[1].values[0] : NULL;
conn->c_sasl_dn = authcDN;
/* Nothing to do if no authzID was given */
AC_MEMCPY( &authzDN.bv_len, auxvals[2].values[0], sizeof(authzDN.bv_len) );
authzDN.bv_val = auxvals[3].values ? (char *)auxvals[3].values[0] : NULL;
rc = slap_sasl_authorized( conn->c_sasl_bindop, &authcDN, &authzDN );
Debug( LDAP_DEBUG_TRACE, "SASL Proxy Authorize [conn=%ld]: "
"proxy authorization disallowed (%d)\n",
sasl_seterror( sconn, 0, "not authorized" );
return SASL_NOAUTHZ;
}
Pierangelo Masarati
committed
/* FIXME: we need yet another dup because slap_sasl_getdn()
* is using the bind operation slab */
Pierangelo Masarati
committed
if (conn->c_sasl_bindop) {
Statslog( LDAP_DEBUG_STATS,
"%s BIND authcid=\"%s\" authzid=\"%s\"\n",
conn->c_sasl_bindop->o_log_prefix,
auth_identity, requested_user, 0, 0 );
Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
" proxy authorization allowed authzDN=\"%s\"\n",
authzDN.bv_val ? authzDN.bv_val : "", 0 );
static int
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;
break;
case SASL_CONTINUE:
rc = LDAP_SASL_BIND_IN_PROGRESS;
break;
case SASL_FAIL:
case SASL_NOMEM:
rc = LDAP_OTHER;
break;
case SASL_NOMECH:
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:
rc = LDAP_INSUFFICIENT_ACCESS;
break;
case SASL_TOOWEAK:
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;
}
return rc;
}
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
#ifdef SLAPD_SPASSWD
static struct berval sasl_pwscheme = BER_BVC("{SASL}");
static int chk_sasl(
const struct berval *sc,
const struct berval * passwd,
const struct berval * cred,
const char **text )
{
unsigned int i;
int rtn;
void *ctx, *sconn = NULL;
for( i=0; i<cred->bv_len; i++) {
if(cred->bv_val[i] == '\0') {
return LUTIL_PASSWD_ERR; /* NUL character in password */
}
}
if( cred->bv_val[i] != '\0' ) {
return LUTIL_PASSWD_ERR; /* cred must behave like a string */
}
for( i=0; i<passwd->bv_len; i++) {
if(passwd->bv_val[i] == '\0') {
return LUTIL_PASSWD_ERR; /* NUL character in password */
}
}
if( passwd->bv_val[i] != '\0' ) {
return LUTIL_PASSWD_ERR; /* passwd must behave like a string */
}
rtn = LUTIL_PASSWD_ERR;
ctx = ldap_pvt_thread_pool_context();
Quanah Gibson-Mount
committed
ldap_pvt_thread_pool_getkey( ctx, (void *)slap_sasl_bind, &sconn, NULL );
if( sconn != NULL ) {
int sc;
sc = sasl_checkpass( sconn,
passwd->bv_val, passwd->bv_len,
cred->bv_val, cred->bv_len );
rtn = ( sc != SASL_OK ) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
}
return rtn;
}
#endif /* SLAPD_SPASSWD */
#endif /* HAVE_CYRUS_SASL */
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifdef ENABLE_REWRITE
typedef struct slapd_map_data {
struct berval base;
struct berval filter;
AttributeName attrs[2];
int scope;
} slapd_map_data;
static void *
slapd_rw_config( const char *fname, int lineno, int argc, char **argv )
{
slapd_map_data *ret = NULL;
LDAPURLDesc *lud = NULL;
char *uri;
AttributeDescription *ad = NULL;
int rc, flen = 0;
struct berval dn, ndn;
if ( argc != 1 ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] slapd map needs URI\n",
fname, lineno, 0 );
return NULL;
}
uri = argv[0];
if ( strncasecmp( uri, "uri=", STRLENOF( "uri=" ) ) == 0 ) {
uri += STRLENOF( "uri=" );
}
if ( ldap_url_parse( uri, &lud ) != LDAP_URL_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] illegal URI '%s'\n",
fname, lineno, uri );
return NULL;
}
if ( strcasecmp( lud->lud_scheme, "ldap" )) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] illegal URI scheme '%s'\n",
fname, lineno, lud->lud_scheme );
goto done;
}
if (( lud->lud_host && lud->lud_host[0] ) || lud->lud_exts
|| !lud->lud_dn ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] illegal URI '%s'\n",
fname, lineno, uri );
goto done;
}
if ( lud->lud_attrs ) {
if ( lud->lud_attrs[1] ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] only one attribute allowed in URI\n",
fname, lineno, 0 );
goto done;
}
if ( strcasecmp( lud->lud_attrs[0], "dn" ) &&
strcasecmp( lud->lud_attrs[0], "entryDN" )) {
const char *text;
rc = slap_str2ad( lud->lud_attrs[0], &ad, &text );
if ( rc )
goto done;
}
}
ber_str2bv( lud->lud_dn, 0, 0, &dn );
if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ))
goto done;
if ( lud->lud_filter ) {
flen = strlen( lud->lud_filter ) + 1;
}
ret = ch_malloc( sizeof( slapd_map_data ) + flen );
ret->base = ndn;
if ( flen ) {
ret->filter.bv_val = (char *)(ret+1);
ret->filter.bv_len = flen - 1;
strcpy( ret->filter.bv_val, lud->lud_filter );
} else {
BER_BVZERO( &ret->filter );
}
ret->scope = lud->lud_scope;
if ( ad ) {
ret->attrs[0].an_name = ad->ad_cname;
} else {
BER_BVZERO( &ret->attrs[0].an_name );
}
ret->attrs[0].an_desc = ad;
BER_BVZERO( &ret->attrs[1].an_name );
done:
ldap_free_urldesc( lud );
return ret;
}
struct slapd_rw_info {
slapd_map_data *si_data;
struct berval si_val;
};
static int
slapd_rw_cb( Operation *op, SlapReply *rs )
{
if ( rs->sr_type == REP_SEARCH ) {
struct slapd_rw_info *si = op->o_callback->sc_private;
if ( si->si_data->attrs[0].an_desc ) {
Attribute *a;
a = attr_find( rs->sr_entry->e_attrs,
si->si_data->attrs[0].an_desc );
if ( a ) {
ber_dupbv( &si->si_val, a->a_vals );
}
} else {
ber_dupbv( &si->si_val, &rs->sr_entry->e_name );
}