Back to index

openldap  2.4.31
sasl.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 #include "portable.h"
00017 
00018 #include <stdio.h>
00019 #ifdef HAVE_LIMITS_H
00020 #include <limits.h>
00021 #endif
00022 
00023 #include <ac/stdlib.h>
00024 #include <ac/string.h>
00025 
00026 #include <lber.h>
00027 #include <ldap_log.h>
00028 
00029 #include "slap.h"
00030 
00031 #ifdef ENABLE_REWRITE
00032 #include <rewrite.h>
00033 #endif
00034 
00035 #ifdef HAVE_CYRUS_SASL
00036 # ifdef HAVE_SASL_SASL_H
00037 #  include <sasl/sasl.h>
00038 #  include <sasl/saslplug.h>
00039 # else
00040 #  include <sasl.h>
00041 #  include <saslplug.h>
00042 # endif
00043 
00044 # define      SASL_CONST const
00045 
00046 #define SASL_VERSION_FULL   ((SASL_VERSION_MAJOR << 16) |\
00047        (SASL_VERSION_MINOR << 8) | SASL_VERSION_STEP)
00048 
00049 static sasl_security_properties_t sasl_secprops;
00050 #elif defined( SLAP_BUILTIN_SASL )
00051 /*
00052  * built-in SASL implementation
00053  *     only supports EXTERNAL
00054  */
00055 typedef struct sasl_ctx {
00056        slap_ssf_t sc_external_ssf;
00057        struct berval sc_external_id;
00058 } SASL_CTX;
00059 
00060 #endif
00061 
00062 #include <lutil.h>
00063 
00064 static struct berval ext_bv = BER_BVC( "EXTERNAL" );
00065 
00066 char *slap_sasl_auxprops;
00067 
00068 #ifdef HAVE_CYRUS_SASL
00069 
00070 /* Just use our internal auxprop by default */
00071 static int
00072 slap_sasl_getopt(
00073        void *context,
00074        const char *plugin_name,
00075        const char *option,
00076        const char **result,
00077        unsigned *len)
00078 {
00079        if ( strcmp( option, "auxprop_plugin" )) {
00080               return SASL_FAIL;
00081        }
00082        if ( slap_sasl_auxprops )
00083               *result = slap_sasl_auxprops;
00084        else
00085               *result = "slapd";
00086        return SASL_OK;
00087 }
00088 
00089 int
00090 slap_sasl_log(
00091        void *context,
00092        int priority,
00093        const char *message) 
00094 {
00095        Connection *conn = context;
00096        int level;
00097        const char * label;
00098 
00099        if ( message == NULL ) {
00100               return SASL_BADPARAM;
00101        }
00102 
00103        switch (priority) {
00104        case SASL_LOG_NONE:
00105               level = LDAP_DEBUG_NONE;
00106               label = "None";
00107               break;
00108        case SASL_LOG_ERR:
00109               level = LDAP_DEBUG_ANY;
00110               label = "Error";
00111               break;
00112        case SASL_LOG_FAIL:
00113               level = LDAP_DEBUG_ANY;
00114               label = "Failure";
00115               break;
00116        case SASL_LOG_WARN:
00117               level = LDAP_DEBUG_TRACE;
00118               label = "Warning";
00119               break;
00120        case SASL_LOG_NOTE:
00121               level = LDAP_DEBUG_TRACE;
00122               label = "Notice";
00123               break;
00124        case SASL_LOG_DEBUG:
00125               level = LDAP_DEBUG_TRACE;
00126               label = "Debug";
00127               break;
00128        case SASL_LOG_TRACE:
00129               level = LDAP_DEBUG_TRACE;
00130               label = "Trace";
00131               break;
00132        case SASL_LOG_PASS:
00133               level = LDAP_DEBUG_TRACE;
00134               label = "Password Trace";
00135               break;
00136        default:
00137               return SASL_BADPARAM;
00138        }
00139 
00140        Debug( level, "SASL [conn=%ld] %s: %s\n",
00141               conn ? (long) conn->c_connid: -1L,
00142               label, message );
00143 
00144 
00145        return SASL_OK;
00146 }
00147 
00148 static const char *slap_propnames[] = {
00149        "*slapConn", "*slapAuthcDNlen", "*slapAuthcDN",
00150        "*slapAuthzDNlen", "*slapAuthzDN", NULL };
00151 
00152 static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL };
00153 static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
00154 
00155 #define       SLAP_SASL_PROP_CONN  0
00156 #define       SLAP_SASL_PROP_AUTHCLEN     1
00157 #define       SLAP_SASL_PROP_AUTHC 2
00158 #define       SLAP_SASL_PROP_AUTHZLEN     3
00159 #define       SLAP_SASL_PROP_AUTHZ 4
00160 #define       SLAP_SASL_PROP_COUNT 5      /* Number of properties we used */
00161 
00162 typedef struct lookup_info {
00163        int flags;
00164        const struct propval *list;
00165        sasl_server_params_t *sparams;
00166 } lookup_info;
00167 
00168 static slap_response sasl_ap_lookup;
00169 
00170 static struct berval sc_cleartext = BER_BVC("{CLEARTEXT}");
00171 
00172 static int
00173 sasl_ap_lookup( Operation *op, SlapReply *rs )
00174 {
00175        BerVarray bv;
00176        AttributeDescription *ad;
00177        Attribute *a;
00178        const char *text;
00179        int rc, i;
00180        lookup_info *sl = (lookup_info *)op->o_callback->sc_private;
00181 
00182        if (rs->sr_type != REP_SEARCH) return 0;
00183 
00184        for( i = 0; sl->list[i].name; i++ ) {
00185               const char *name = sl->list[i].name;
00186 
00187               if ( name[0] == '*' ) {
00188                      if ( sl->flags & SASL_AUXPROP_AUTHZID ) continue;
00189                      /* Skip our private properties */
00190                      if ( !strcmp( name, slap_propnames[0] )) {
00191                             i += SLAP_SASL_PROP_COUNT - 1;
00192                             continue;
00193                      }
00194                      name++;
00195               } else if ( !(sl->flags & SASL_AUXPROP_AUTHZID ) )
00196                      continue;
00197 
00198               if ( sl->list[i].values ) {
00199                      if ( !(sl->flags & SASL_AUXPROP_OVERRIDE) ) continue;
00200               }
00201               ad = NULL;
00202               rc = slap_str2ad( name, &ad, &text );
00203               if ( rc != LDAP_SUCCESS ) {
00204                      Debug( LDAP_DEBUG_TRACE,
00205                             "slap_ap_lookup: str2ad(%s): %s\n", name, text, 0 );
00206                      continue;
00207               }
00208 
00209               /* If it's the rootdn and a rootpw was present, we already set
00210                * it so don't override it here.
00211                */
00212               if ( ad == slap_schema.si_ad_userPassword && sl->list[i].values && 
00213                      be_isroot_dn( op->o_bd, &op->o_req_ndn ))
00214                      continue;
00215 
00216               a = attr_find( rs->sr_entry->e_attrs, ad );
00217               if ( !a ) continue;
00218               if ( ! access_allowed( op, rs->sr_entry, ad, NULL, ACL_AUTH, NULL ) ) {
00219                      continue;
00220               }
00221               if ( sl->list[i].values && ( sl->flags & SASL_AUXPROP_OVERRIDE ) ) {
00222                      sl->sparams->utils->prop_erase( sl->sparams->propctx,
00223                      sl->list[i].name );
00224               }
00225               for ( bv = a->a_vals; bv->bv_val; bv++ ) {
00226                      /* ITS#3846 don't give hashed passwords to SASL */
00227                      if ( ad == slap_schema.si_ad_userPassword &&
00228                             bv->bv_val[0] == '{' /*}*/ )
00229                      {
00230                             if ( lutil_passwd_scheme( bv->bv_val ) ) {
00231                                    /* If it's not a recognized scheme, just assume it's
00232                                     * a cleartext password that happened to include brackets.
00233                                     *
00234                                     * If it's a recognized scheme, skip this value, unless the
00235                                     * scheme is {CLEARTEXT}. In that case, skip over the
00236                                     * scheme name and use the remainder. If there is nothing
00237                                     * past the scheme name, skip this value.
00238                                     */
00239 #ifdef SLAPD_CLEARTEXT
00240                                    if ( !strncasecmp( bv->bv_val, sc_cleartext.bv_val,
00241                                           sc_cleartext.bv_len )) {
00242                                           struct berval cbv;
00243                                           cbv.bv_len = bv->bv_len - sc_cleartext.bv_len;
00244                                           if ( cbv.bv_len > 0 ) {
00245                                                  cbv.bv_val = bv->bv_val + sc_cleartext.bv_len;
00246                                                  sl->sparams->utils->prop_set( sl->sparams->propctx,
00247                                                         sl->list[i].name, cbv.bv_val, cbv.bv_len );
00248                                           }
00249                                    }
00250 #endif
00251                                    continue;
00252                             }
00253                      }
00254                      sl->sparams->utils->prop_set( sl->sparams->propctx,
00255                             sl->list[i].name, bv->bv_val, bv->bv_len );
00256               }
00257        }
00258        return LDAP_SUCCESS;
00259 }
00260 
00261 #if SASL_VERSION_FULL >= 0x020118
00262 static int
00263 #else
00264 static void
00265 #endif
00266 slap_auxprop_lookup(
00267        void *glob_context,
00268        sasl_server_params_t *sparams,
00269        unsigned flags,
00270        const char *user,
00271        unsigned ulen)
00272 {
00273        OperationBuffer opbuf = {{ NULL }};
00274        Operation *op = (Operation *)&opbuf;
00275        int i, doit = 0;
00276        Connection *conn = NULL;
00277        lookup_info sl;
00278        int rc = LDAP_SUCCESS;
00279 
00280        sl.list = sparams->utils->prop_get( sparams->propctx );
00281        sl.sparams = sparams;
00282        sl.flags = flags;
00283 
00284        /* Find our DN and conn first */
00285        for( i = 0; sl.list[i].name; i++ ) {
00286               if ( sl.list[i].name[0] == '*' ) {
00287                      if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) {
00288                             if ( sl.list[i].values && sl.list[i].values[0] )
00289                                    AC_MEMCPY( &conn, sl.list[i].values[0], sizeof( conn ) );
00290                             continue;
00291                      }
00292                      if ( flags & SASL_AUXPROP_AUTHZID ) {
00293                             if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZLEN] )) {
00294                                    if ( sl.list[i].values && sl.list[i].values[0] )
00295                                           AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0],
00296                                                  sizeof( op->o_req_ndn.bv_len ) );
00297                             } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZ] )) {
00298                                    if ( sl.list[i].values )
00299                                           op->o_req_ndn.bv_val = (char *)sl.list[i].values[0];
00300                                    break;
00301                             }
00302                      }
00303 
00304                      if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) {
00305                             if ( sl.list[i].values && sl.list[i].values[0] )
00306                                    AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0],
00307                                           sizeof( op->o_req_ndn.bv_len ) );
00308                      } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) {
00309                             if ( sl.list[i].values ) {
00310                                    op->o_req_ndn.bv_val = (char *)sl.list[i].values[0];
00311                                    if ( !(flags & SASL_AUXPROP_AUTHZID) )
00312                                           break;
00313                             }
00314                      }
00315               }
00316        }
00317 
00318        /* Now see what else needs to be fetched */
00319        for( i = 0; sl.list[i].name; i++ ) {
00320               const char *name = sl.list[i].name;
00321 
00322               if ( name[0] == '*' ) {
00323                      if ( flags & SASL_AUXPROP_AUTHZID ) continue;
00324                      /* Skip our private properties */
00325                      if ( !strcmp( name, slap_propnames[0] )) {
00326                             i += SLAP_SASL_PROP_COUNT - 1;
00327                             continue;
00328                      }
00329                      name++;
00330               } else if ( !(flags & SASL_AUXPROP_AUTHZID ) )
00331                      continue;
00332 
00333               if ( sl.list[i].values ) {
00334                      if ( !(flags & SASL_AUXPROP_OVERRIDE) ) continue;
00335               }
00336               doit = 1;
00337               break;
00338        }
00339 
00340        if (doit) {
00341               slap_callback cb = { NULL, sasl_ap_lookup, NULL, NULL };
00342 
00343               cb.sc_private = &sl;
00344 
00345               op->o_bd = select_backend( &op->o_req_ndn, 1 );
00346 
00347               if ( op->o_bd ) {
00348                      /* For rootdn, see if we can use the rootpw */
00349                      if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) &&
00350                             !BER_BVISEMPTY( &op->o_bd->be_rootpw )) {
00351                             struct berval cbv = BER_BVNULL;
00352 
00353                             /* If there's a recognized scheme, see if it's CLEARTEXT */
00354                             if ( lutil_passwd_scheme( op->o_bd->be_rootpw.bv_val )) {
00355                                    if ( !strncasecmp( op->o_bd->be_rootpw.bv_val,
00356                                           sc_cleartext.bv_val, sc_cleartext.bv_len )) {
00357 
00358                                           /* If it's CLEARTEXT, skip past scheme spec */
00359                                           cbv.bv_len = op->o_bd->be_rootpw.bv_len -
00360                                                  sc_cleartext.bv_len;
00361                                           if ( cbv.bv_len ) {
00362                                                  cbv.bv_val = op->o_bd->be_rootpw.bv_val +
00363                                                         sc_cleartext.bv_len;
00364                                           }
00365                                    }
00366                             /* No scheme, use the whole value */
00367                             } else {
00368                                    cbv = op->o_bd->be_rootpw;
00369                             }
00370                             if ( !BER_BVISEMPTY( &cbv )) {
00371                                    for( i = 0; sl.list[i].name; i++ ) {
00372                                           const char *name = sl.list[i].name;
00373 
00374                                           if ( name[0] == '*' ) {
00375                                                  if ( flags & SASL_AUXPROP_AUTHZID ) continue;
00376                                                         name++;
00377                                           } else if ( !(flags & SASL_AUXPROP_AUTHZID ) )
00378                                                  continue;
00379 
00380                                           if ( !strcasecmp(name,"userPassword") ) {
00381                                                  sl.sparams->utils->prop_set( sl.sparams->propctx,
00382                                                         sl.list[i].name, cbv.bv_val, cbv.bv_len );
00383                                                  break;
00384                                           }
00385                                    }
00386                             }
00387                      }
00388 
00389                      if ( op->o_bd->be_search ) {
00390                             SlapReply rs = {REP_RESULT};
00391                             op->o_hdr = conn->c_sasl_bindop->o_hdr;
00392                             op->o_controls = opbuf.ob_controls;
00393                             op->o_tag = LDAP_REQ_SEARCH;
00394                             op->o_dn = conn->c_ndn;
00395                             op->o_ndn = conn->c_ndn;
00396                             op->o_callback = &cb;
00397                             slap_op_time( &op->o_time, &op->o_tincr );
00398                             op->o_do_not_cache = 1;
00399                             op->o_is_auth_check = 1;
00400                             op->o_req_dn = op->o_req_ndn;
00401                             op->ors_scope = LDAP_SCOPE_BASE;
00402                             op->ors_deref = LDAP_DEREF_NEVER;
00403                             op->ors_tlimit = SLAP_NO_LIMIT;
00404                             op->ors_slimit = 1;
00405                             op->ors_filter = &generic_filter;
00406                             op->ors_filterstr = generic_filterstr;
00407                             op->o_authz = conn->c_authz;
00408                             /* FIXME: we want all attributes, right? */
00409                             op->ors_attrs = NULL;
00410 
00411                             rc = op->o_bd->be_search( op, &rs );
00412                      }
00413               }
00414        }
00415 #if SASL_VERSION_FULL >= 0x020118
00416        return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK;
00417 #endif
00418 }
00419 
00420 #if SASL_VERSION_FULL >= 0x020110
00421 static int
00422 slap_auxprop_store(
00423        void *glob_context,
00424        sasl_server_params_t *sparams,
00425        struct propctx *prctx,
00426        const char *user,
00427        unsigned ulen)
00428 {
00429        Operation op = {0};
00430        Opheader oph;
00431        SlapReply rs = {REP_RESULT};
00432        int rc, i;
00433        unsigned j;
00434        Connection *conn = NULL;
00435        const struct propval *pr;
00436        Modifications *modlist = NULL, **modtail = &modlist, *mod;
00437        slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
00438        char textbuf[SLAP_TEXT_BUFLEN];
00439        const char *text;
00440        size_t textlen = sizeof(textbuf);
00441 
00442        /* just checking if we are enabled */
00443        if (!prctx) return SASL_OK;
00444 
00445        if (!sparams || !user) return SASL_BADPARAM;
00446 
00447        pr = sparams->utils->prop_get( sparams->propctx );
00448 
00449        /* Find our DN and conn first */
00450        for( i = 0; pr[i].name; i++ ) {
00451               if ( pr[i].name[0] == '*' ) {
00452                      if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) {
00453                             if ( pr[i].values && pr[i].values[0] )
00454                                    AC_MEMCPY( &conn, pr[i].values[0], sizeof( conn ) );
00455                             continue;
00456                      }
00457                      if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) {
00458                             if ( pr[i].values && pr[i].values[0] )
00459                                    AC_MEMCPY( &op.o_req_ndn.bv_len, pr[i].values[0],
00460                                           sizeof( op.o_req_ndn.bv_len ) );
00461                      } else if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) {
00462                             if ( pr[i].values )
00463                                    op.o_req_ndn.bv_val = (char *)pr[i].values[0];
00464                      }
00465               }
00466        }
00467        if (!conn || !op.o_req_ndn.bv_val) return SASL_BADPARAM;
00468 
00469        op.o_bd = select_backend( &op.o_req_ndn, 1 );
00470 
00471        if ( !op.o_bd || !op.o_bd->be_modify ) return SASL_FAIL;
00472               
00473        pr = sparams->utils->prop_get( prctx );
00474        if (!pr) return SASL_BADPARAM;
00475 
00476        for (i=0; pr[i].name; i++);
00477        if (!i) return SASL_BADPARAM;
00478 
00479        for (i=0; pr[i].name; i++) {
00480               mod = (Modifications *)ch_malloc( sizeof(Modifications) );
00481               mod->sml_op = LDAP_MOD_REPLACE;
00482               mod->sml_flags = 0;
00483               ber_str2bv( pr[i].name, 0, 0, &mod->sml_type );
00484               mod->sml_numvals = pr[i].nvalues;
00485               mod->sml_values = (struct berval *)ch_malloc( (pr[i].nvalues + 1) *
00486                      sizeof(struct berval));
00487               for (j=0; j<pr[i].nvalues; j++) {
00488                      ber_str2bv( pr[i].values[j], 0, 1, &mod->sml_values[j]);
00489               }
00490               BER_BVZERO( &mod->sml_values[j] );
00491               mod->sml_nvalues = NULL;
00492               mod->sml_desc = NULL;
00493               *modtail = mod;
00494               modtail = &mod->sml_next;
00495        }
00496        *modtail = NULL;
00497 
00498        rc = slap_mods_check( &op, modlist, &text, textbuf, textlen, NULL );
00499 
00500        if ( rc == LDAP_SUCCESS ) {
00501               rc = slap_mods_no_user_mod_check( &op, modlist,
00502                      &text, textbuf, textlen );
00503 
00504               if ( rc == LDAP_SUCCESS ) {
00505                      if ( conn->c_sasl_bindop ) {
00506                             op.o_hdr = conn->c_sasl_bindop->o_hdr;
00507                      } else {
00508                             op.o_hdr = &oph;
00509                             memset( &oph, 0, sizeof(oph) );
00510                             operation_fake_init( conn, &op, ldap_pvt_thread_pool_context(), 0 );
00511                      }
00512                      op.o_tag = LDAP_REQ_MODIFY;
00513                      op.o_ndn = op.o_req_ndn;
00514                      op.o_callback = &cb;
00515                      slap_op_time( &op.o_time, &op.o_tincr );
00516                      op.o_do_not_cache = 1;
00517                      op.o_is_auth_check = 1;
00518                      op.o_req_dn = op.o_req_ndn;
00519                      op.orm_modlist = modlist;
00520 
00521                      rc = op.o_bd->be_modify( &op, &rs );
00522               }
00523        }
00524        slap_mods_free( modlist, 1 );
00525        return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK;
00526 }
00527 #endif /* SASL_VERSION_FULL >= 2.1.16 */
00528 
00529 static sasl_auxprop_plug_t slap_auxprop_plugin = {
00530        0,     /* Features */
00531        0,     /* spare */
00532        NULL,  /* glob_context */
00533        NULL,  /* auxprop_free */
00534        slap_auxprop_lookup,
00535        "slapd",      /* name */
00536 #if SASL_VERSION_FULL >= 0x020110
00537        slap_auxprop_store   /* the declaration of this member changed
00538                              * in cyrus SASL from 2.1.15 to 2.1.16 */
00539 #else
00540        NULL
00541 #endif
00542 };
00543 
00544 static int
00545 slap_auxprop_init(
00546        const sasl_utils_t *utils,
00547        int max_version,
00548        int *out_version,
00549        sasl_auxprop_plug_t **plug,
00550        const char *plugname)
00551 {
00552        if ( !out_version || !plug ) return SASL_BADPARAM;
00553 
00554        if ( max_version < SASL_AUXPROP_PLUG_VERSION ) return SASL_BADVERS;
00555 
00556        *out_version = SASL_AUXPROP_PLUG_VERSION;
00557        *plug = &slap_auxprop_plugin;
00558        return SASL_OK;
00559 }
00560 
00561 /* Convert a SASL authcid or authzid into a DN. Store the DN in an
00562  * auxiliary property, so that we can refer to it in sasl_authorize
00563  * without interfering with anything else. Also, the SASL username
00564  * buffer is constrained to 256 characters, and our DNs could be
00565  * much longer (SLAP_LDAPDN_MAXLEN, currently set to 8192)
00566  */
00567 static int
00568 slap_sasl_canonicalize(
00569        sasl_conn_t *sconn,
00570        void *context,
00571        const char *in,
00572        unsigned inlen,
00573        unsigned flags,
00574        const char *user_realm,
00575        char *out,
00576        unsigned out_max,
00577        unsigned *out_len)
00578 {
00579        Connection *conn = (Connection *)context;
00580        struct propctx *props = sasl_auxprop_getctx( sconn );
00581        struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } };
00582        struct berval dn;
00583        int rc, which;
00584        const char *names[2];
00585        struct berval bvin;
00586 
00587        *out_len = 0;
00588 
00589        Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n",
00590               conn ? (long) conn->c_connid : -1L,
00591               (flags & SASL_CU_AUTHID) ? "authcid" : "authzid",
00592               in ? in : "<empty>");
00593 
00594        /* If name is too big, just truncate. We don't care, we're
00595         * using DNs, not the usernames.
00596         */
00597        if ( inlen > out_max )
00598               inlen = out_max-1;
00599 
00600        /* This is a Simple Bind using SPASSWD. That means the in-directory
00601         * userPassword of the Binding user already points at SASL, so it
00602         * cannot be used to actually satisfy a password comparison. Just
00603         * ignore it, some other mech will process it.
00604         */
00605        if ( !conn->c_sasl_bindop ||
00606               conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) goto done;
00607 
00608        /* See if we need to add request, can only do it once */
00609        prop_getnames( props, slap_propnames, auxvals );
00610        if ( !auxvals[0].name )
00611               prop_request( props, slap_propnames );
00612 
00613        if ( flags & SASL_CU_AUTHID )
00614               which = SLAP_SASL_PROP_AUTHCLEN;
00615        else
00616               which = SLAP_SASL_PROP_AUTHZLEN;
00617 
00618        /* Need to store the Connection for auxprop_lookup */
00619        if ( !auxvals[SLAP_SASL_PROP_CONN].values ) {
00620               names[0] = slap_propnames[SLAP_SASL_PROP_CONN];
00621               names[1] = NULL;
00622               prop_set( props, names[0], (char *)&conn, sizeof( conn ) );
00623        }
00624               
00625        /* Already been here? */
00626        if ( auxvals[which].values )
00627               goto done;
00628 
00629        /* Normally we require an authzID to have a u: or dn: prefix.
00630         * However, SASL frequently gives us an authzID that is just
00631         * an exact copy of the authcID, without a prefix. We need to
00632         * detect and allow this condition. If SASL calls canonicalize
00633         * with SASL_CU_AUTHID|SASL_CU_AUTHZID this is a no-brainer.
00634         * But if it's broken into two calls, we need to remember the
00635         * authcID so that we can compare the authzID later. We store
00636         * the authcID temporarily in conn->c_sasl_dn. We necessarily
00637         * finish Canonicalizing before Authorizing, so there is no
00638         * conflict with slap_sasl_authorize's use of this temp var.
00639         *
00640         * The SASL EXTERNAL mech is backwards from all the other mechs,
00641         * it does authzID before the authcID. If we see that authzID
00642         * has already been done, don't do anything special with authcID.
00643         */
00644        if ( flags == SASL_CU_AUTHID && !auxvals[SLAP_SASL_PROP_AUTHZ].values ) {
00645               conn->c_sasl_dn.bv_val = (char *) in;
00646               conn->c_sasl_dn.bv_len = 0;
00647        } else if ( flags == SASL_CU_AUTHZID && conn->c_sasl_dn.bv_val ) {
00648               rc = strcmp( in, conn->c_sasl_dn.bv_val );
00649               conn->c_sasl_dn.bv_val = NULL;
00650               /* They were equal, no work needed */
00651               if ( !rc ) goto done;
00652        }
00653 
00654        bvin.bv_val = (char *)in;
00655        bvin.bv_len = inlen;
00656        rc = slap_sasl_getdn( conn, NULL, &bvin, (char *)user_realm, &dn,
00657               (flags & SASL_CU_AUTHID) ? SLAP_GETDN_AUTHCID : SLAP_GETDN_AUTHZID );
00658        if ( rc != LDAP_SUCCESS ) {
00659               sasl_seterror( sconn, 0, ldap_err2string( rc ) );
00660               return SASL_NOAUTHZ;
00661        }
00662 
00663        names[0] = slap_propnames[which];
00664        names[1] = NULL;
00665        prop_set( props, names[0], (char *)&dn.bv_len, sizeof( dn.bv_len ) );
00666 
00667        which++;
00668        names[0] = slap_propnames[which];
00669        prop_set( props, names[0], dn.bv_val, dn.bv_len );
00670 
00671        Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n",
00672               conn ? (long) conn->c_connid : -1L, names[0]+1,
00673               dn.bv_val ? dn.bv_val : "<EMPTY>" );
00674 
00675        /* Not needed any more, SASL has copied it */
00676        if ( conn && conn->c_sasl_bindop )
00677               conn->c_sasl_bindop->o_tmpfree( dn.bv_val, conn->c_sasl_bindop->o_tmpmemctx );
00678 
00679 done:
00680        AC_MEMCPY( out, in, inlen );
00681        out[inlen] = '\0';
00682 
00683        *out_len = inlen;
00684 
00685        return SASL_OK;
00686 }
00687 
00688 static int
00689 slap_sasl_authorize(
00690        sasl_conn_t *sconn,
00691        void *context,
00692        char *requested_user,
00693        unsigned rlen,
00694        char *auth_identity,
00695        unsigned alen,
00696        const char *def_realm,
00697        unsigned urlen,
00698        struct propctx *props)
00699 {
00700        Connection *conn = (Connection *)context;
00701        /* actually:
00702         *     (SLAP_SASL_PROP_COUNT - 1)  because we skip "conn",
00703         *     + 1                         for NULL termination?
00704         */
00705        struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } };
00706        struct berval authcDN, authzDN = BER_BVNULL;
00707        int rc;
00708 
00709        /* Simple Binds don't support proxy authorization, ignore it */
00710        if ( !conn->c_sasl_bindop ||
00711               conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) return SASL_OK;
00712 
00713        Debug( LDAP_DEBUG_ARGS, "SASL proxy authorize [conn=%ld]: "
00714               "authcid=\"%s\" authzid=\"%s\"\n",
00715               conn ? (long) conn->c_connid : -1L, auth_identity, requested_user );
00716        if ( conn->c_sasl_dn.bv_val ) {
00717               BER_BVZERO( &conn->c_sasl_dn );
00718        }
00719 
00720        /* Skip SLAP_SASL_PROP_CONN */
00721        prop_getnames( props, slap_propnames+1, auxvals );
00722        
00723        /* Should not happen */
00724        if ( !auxvals[0].values ) {
00725               sasl_seterror( sconn, 0, "invalid authcid" );
00726               return SASL_NOAUTHZ;
00727        }
00728 
00729        AC_MEMCPY( &authcDN.bv_len, auxvals[0].values[0], sizeof(authcDN.bv_len) );
00730        authcDN.bv_val = auxvals[1].values ? (char *)auxvals[1].values[0] : NULL;
00731        conn->c_sasl_dn = authcDN;
00732 
00733        /* Nothing to do if no authzID was given */
00734        if ( !auxvals[2].name || !auxvals[2].values ) {
00735               goto ok;
00736        }
00737        
00738        AC_MEMCPY( &authzDN.bv_len, auxvals[2].values[0], sizeof(authzDN.bv_len) );
00739        authzDN.bv_val = auxvals[3].values ? (char *)auxvals[3].values[0] : NULL;
00740 
00741        rc = slap_sasl_authorized( conn->c_sasl_bindop, &authcDN, &authzDN );
00742        if ( rc != LDAP_SUCCESS ) {
00743               Debug( LDAP_DEBUG_TRACE, "SASL Proxy Authorize [conn=%ld]: "
00744                      "proxy authorization disallowed (%d)\n",
00745                      conn ? (long) conn->c_connid : -1L, rc, 0 );
00746 
00747               sasl_seterror( sconn, 0, "not authorized" );
00748               return SASL_NOAUTHZ;
00749        }
00750 
00751        /* FIXME: we need yet another dup because slap_sasl_getdn()
00752         * is using the bind operation slab */
00753        ber_dupbv( &conn->c_sasl_authz_dn, &authzDN );
00754 
00755 ok:
00756        if (conn->c_sasl_bindop) {
00757               Statslog( LDAP_DEBUG_STATS,
00758                      "%s BIND authcid=\"%s\" authzid=\"%s\"\n",
00759                      conn->c_sasl_bindop->o_log_prefix, 
00760                      auth_identity, requested_user, 0, 0 );
00761        }
00762 
00763        Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
00764               " proxy authorization allowed authzDN=\"%s\"\n",
00765               conn ? (long) conn->c_connid : -1L, 
00766               authzDN.bv_val ? authzDN.bv_val : "", 0 );
00767        return SASL_OK;
00768 } 
00769 
00770 static int
00771 slap_sasl_err2ldap( int saslerr )
00772 {
00773        int rc;
00774 
00775        /* map SASL errors to LDAP resultCode returned by:
00776         *     sasl_server_new()
00777         *            SASL_OK, SASL_NOMEM
00778         *     sasl_server_step()
00779         *            SASL_OK, SASL_CONTINUE, SASL_TRANS, SASL_BADPARAM, SASL_BADPROT,
00780         *      ...
00781         *     sasl_server_start()
00782         *      + SASL_NOMECH
00783         *     sasl_setprop()
00784         *            SASL_OK, SASL_BADPARAM
00785         */
00786 
00787        switch (saslerr) {
00788               case SASL_OK:
00789                      rc = LDAP_SUCCESS;
00790                      break;
00791               case SASL_CONTINUE:
00792                      rc = LDAP_SASL_BIND_IN_PROGRESS;
00793                      break;
00794               case SASL_FAIL:
00795               case SASL_NOMEM:
00796                      rc = LDAP_OTHER;
00797                      break;
00798               case SASL_NOMECH:
00799                      rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
00800                      break;
00801               case SASL_BADAUTH:
00802               case SASL_NOUSER:
00803               case SASL_TRANS:
00804               case SASL_EXPIRED:
00805                      rc = LDAP_INVALID_CREDENTIALS;
00806                      break;
00807               case SASL_NOAUTHZ:
00808                      rc = LDAP_INSUFFICIENT_ACCESS;
00809                      break;
00810               case SASL_TOOWEAK:
00811               case SASL_ENCRYPT:
00812                      rc = LDAP_INAPPROPRIATE_AUTH;
00813                      break;
00814               case SASL_UNAVAIL:
00815               case SASL_TRYAGAIN:
00816                      rc = LDAP_UNAVAILABLE;
00817                      break;
00818               case SASL_DISABLED:
00819                      rc = LDAP_UNWILLING_TO_PERFORM;
00820                      break;
00821               default:
00822                      rc = LDAP_OTHER;
00823                      break;
00824        }
00825 
00826        return rc;
00827 }
00828 
00829 #ifdef SLAPD_SPASSWD
00830 
00831 static struct berval sasl_pwscheme = BER_BVC("{SASL}");
00832 
00833 static int chk_sasl(
00834        const struct berval *sc,
00835        const struct berval * passwd,
00836        const struct berval * cred,
00837        const char **text )
00838 {
00839        unsigned int i;
00840        int rtn;
00841        void *ctx, *sconn = NULL;
00842 
00843        for( i=0; i<cred->bv_len; i++) {
00844               if(cred->bv_val[i] == '\0') {
00845                      return LUTIL_PASSWD_ERR;    /* NUL character in password */
00846               }
00847        }
00848 
00849        if( cred->bv_val[i] != '\0' ) {
00850               return LUTIL_PASSWD_ERR;    /* cred must behave like a string */
00851        }
00852 
00853        for( i=0; i<passwd->bv_len; i++) {
00854               if(passwd->bv_val[i] == '\0') {
00855                      return LUTIL_PASSWD_ERR;    /* NUL character in password */
00856               }
00857        }
00858 
00859        if( passwd->bv_val[i] != '\0' ) {
00860               return LUTIL_PASSWD_ERR;    /* passwd must behave like a string */
00861        }
00862 
00863        rtn = LUTIL_PASSWD_ERR;
00864 
00865        ctx = ldap_pvt_thread_pool_context();
00866        ldap_pvt_thread_pool_getkey( ctx, (void *)slap_sasl_bind, &sconn, NULL );
00867 
00868        if( sconn != NULL ) {
00869               int sc;
00870               sc = sasl_checkpass( sconn,
00871                      passwd->bv_val, passwd->bv_len,
00872                      cred->bv_val, cred->bv_len );
00873               rtn = ( sc != SASL_OK ) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
00874        }
00875 
00876        return rtn;
00877 }
00878 #endif /* SLAPD_SPASSWD */
00879 
00880 #endif /* HAVE_CYRUS_SASL */
00881 
00882 #ifdef ENABLE_REWRITE
00883 
00884 typedef struct slapd_map_data {
00885        struct berval base;
00886        struct berval filter;
00887        AttributeName attrs[2];
00888        int scope;
00889 } slapd_map_data;
00890 
00891 static void *
00892 slapd_rw_config( const char *fname, int lineno, int argc, char **argv )
00893 {
00894        slapd_map_data *ret = NULL;
00895        LDAPURLDesc *lud = NULL;
00896        char *uri;
00897        AttributeDescription *ad = NULL;
00898        int rc, flen = 0;
00899        struct berval dn, ndn;
00900 
00901        if ( argc != 1 ) {
00902               Debug( LDAP_DEBUG_ANY,
00903                      "[%s:%d] slapd map needs URI\n",
00904                      fname, lineno, 0 );
00905         return NULL;
00906        }
00907 
00908        uri = argv[0];
00909        if ( strncasecmp( uri, "uri=", STRLENOF( "uri=" ) ) == 0 ) {
00910               uri += STRLENOF( "uri=" );
00911        }
00912 
00913        if ( ldap_url_parse( uri, &lud ) != LDAP_URL_SUCCESS ) {
00914               Debug( LDAP_DEBUG_ANY,
00915                      "[%s:%d] illegal URI '%s'\n",
00916                      fname, lineno, uri );
00917         return NULL;
00918        }
00919 
00920        if ( strcasecmp( lud->lud_scheme, "ldap" )) {
00921               Debug( LDAP_DEBUG_ANY,
00922                      "[%s:%d] illegal URI scheme '%s'\n",
00923                      fname, lineno, lud->lud_scheme );
00924               goto done;
00925        }
00926 
00927        if (( lud->lud_host && lud->lud_host[0] ) || lud->lud_exts
00928               || !lud->lud_dn ) {
00929               Debug( LDAP_DEBUG_ANY,
00930                      "[%s:%d] illegal URI '%s'\n",
00931                      fname, lineno, uri );
00932               goto done;
00933        }
00934 
00935        if ( lud->lud_attrs ) {
00936               if ( lud->lud_attrs[1] ) {
00937                      Debug( LDAP_DEBUG_ANY,
00938                             "[%s:%d] only one attribute allowed in URI\n",
00939                             fname, lineno, 0 );
00940                      goto done;
00941               }
00942               if ( strcasecmp( lud->lud_attrs[0], "dn" ) &&
00943                      strcasecmp( lud->lud_attrs[0], "entryDN" )) {
00944                      const char *text;
00945                      rc = slap_str2ad( lud->lud_attrs[0], &ad, &text );
00946                      if ( rc )
00947                             goto done;
00948               }
00949        }
00950        ber_str2bv( lud->lud_dn, 0, 0, &dn );
00951        if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ))
00952               goto done;
00953 
00954        if ( lud->lud_filter ) {
00955               flen = strlen( lud->lud_filter ) + 1;
00956        }
00957        ret = ch_malloc( sizeof( slapd_map_data ) + flen );
00958        ret->base = ndn;
00959        if ( flen ) {
00960               ret->filter.bv_val = (char *)(ret+1);
00961               ret->filter.bv_len = flen - 1;
00962               strcpy( ret->filter.bv_val, lud->lud_filter );
00963        } else {
00964               BER_BVZERO( &ret->filter );
00965        }
00966        ret->scope = lud->lud_scope;
00967        if ( ad ) {
00968               ret->attrs[0].an_name = ad->ad_cname;
00969        } else {
00970               BER_BVZERO( &ret->attrs[0].an_name );
00971        }
00972        ret->attrs[0].an_desc = ad;
00973        BER_BVZERO( &ret->attrs[1].an_name );
00974 done:
00975        ldap_free_urldesc( lud );
00976        return ret;
00977 }
00978 
00979 struct slapd_rw_info {
00980        slapd_map_data *si_data;
00981        struct berval si_val;
00982 };
00983 
00984 static int
00985 slapd_rw_cb( Operation *op, SlapReply *rs )
00986 {
00987        if ( rs->sr_type == REP_SEARCH ) {
00988               struct slapd_rw_info *si = op->o_callback->sc_private;
00989 
00990               if ( si->si_data->attrs[0].an_desc ) {
00991                      Attribute *a;
00992 
00993                      a = attr_find( rs->sr_entry->e_attrs,
00994                             si->si_data->attrs[0].an_desc );
00995                      if ( a ) {
00996                             ber_dupbv( &si->si_val, a->a_vals );
00997                      }
00998               } else {
00999                      ber_dupbv( &si->si_val, &rs->sr_entry->e_name );
01000               }
01001        }
01002        return LDAP_SUCCESS;
01003 }
01004 
01005 static int
01006 slapd_rw_apply( void *private, const char *filter, struct berval *val )
01007 {
01008        slapd_map_data *sl = private;
01009        slap_callback cb = { NULL };
01010        Connection conn = {0};
01011        OperationBuffer opbuf;
01012        Operation *op;
01013        void *thrctx;
01014        SlapReply rs = {REP_RESULT};
01015        struct slapd_rw_info si;
01016        char *ptr;
01017        int rc;
01018 
01019        thrctx = ldap_pvt_thread_pool_context();
01020        connection_fake_init2( &conn, &opbuf, thrctx, 0 );
01021        op = &opbuf.ob_op;
01022 
01023        op->o_tag = LDAP_REQ_SEARCH;
01024        op->o_req_dn = op->o_req_ndn = sl->base;
01025        op->o_bd = select_backend( &op->o_req_ndn, 1 );
01026        if ( !op->o_bd ) {
01027               return REWRITE_ERR;
01028        }
01029        si.si_data = sl;
01030        BER_BVZERO( &si.si_val );
01031        op->ors_scope = sl->scope;
01032        op->ors_deref = LDAP_DEREF_NEVER;
01033        op->ors_slimit = 1;
01034        op->ors_tlimit = SLAP_NO_LIMIT;
01035        if ( sl->attrs[0].an_desc ) {
01036               op->ors_attrs = sl->attrs;
01037        } else {
01038               op->ors_attrs = slap_anlist_no_attrs;
01039        }
01040        if ( filter ) {
01041               rc = strlen( filter );
01042        } else {
01043               rc = 0;
01044        }
01045        rc += sl->filter.bv_len;
01046        ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( rc + 1, op->o_tmpmemctx );
01047        if ( sl->filter.bv_len ) {
01048               ptr = lutil_strcopy( ptr, sl->filter.bv_val );
01049        } else {
01050               *ptr = '\0';
01051        }
01052        if ( filter ) {
01053               strcpy( ptr, filter );
01054        }
01055        op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
01056        if ( !op->ors_filter ) {
01057               op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
01058               return REWRITE_ERR;
01059        }
01060 
01061        op->ors_attrsonly = 0;
01062        op->o_dn = op->o_bd->be_rootdn;
01063        op->o_ndn = op->o_bd->be_rootndn;
01064        op->o_do_not_cache = 1;
01065 
01066        cb.sc_response = slapd_rw_cb;
01067        cb.sc_private = &si;
01068        op->o_callback = &cb;
01069 
01070        rc = op->o_bd->be_search( op, &rs );
01071        if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &si.si_val )) {
01072               *val = si.si_val;
01073               rc = REWRITE_SUCCESS;
01074        } else {
01075               if ( !BER_BVISNULL( &si.si_val )) {
01076                      ch_free( si.si_val.bv_val );
01077               }
01078               rc = REWRITE_ERR;
01079        }
01080        filter_free_x( op, op->ors_filter, 1 );
01081        op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
01082        return rc;
01083 }
01084 
01085 static int
01086 slapd_rw_destroy( void *private )
01087 {
01088        slapd_map_data *md = private;
01089 
01090        assert( private != NULL );
01091 
01092        ch_free( md->base.bv_val );
01093        ch_free( md->filter.bv_val );
01094        ch_free( md );
01095 
01096        return 0;
01097 }
01098 
01099 static const rewrite_mapper slapd_mapper = {
01100        "slapd",
01101        slapd_rw_config,
01102        slapd_rw_apply,
01103        slapd_rw_destroy
01104 };
01105 #endif
01106 
01107 int slap_sasl_init( void )
01108 {
01109 #ifdef HAVE_CYRUS_SASL
01110        int rc;
01111        static sasl_callback_t server_callbacks[] = {
01112               { SASL_CB_LOG, &slap_sasl_log, NULL },
01113               { SASL_CB_GETOPT, &slap_sasl_getopt, NULL },
01114               { SASL_CB_LIST_END, NULL, NULL }
01115        };
01116 #endif
01117 
01118 #ifdef ENABLE_REWRITE
01119        rewrite_mapper_register( &slapd_mapper );
01120 #endif
01121 
01122 #ifdef HAVE_CYRUS_SASL
01123 #ifdef HAVE_SASL_VERSION
01124        /* stringify the version number, sasl.h doesn't do it for us */
01125 #define       VSTR0(maj, min, pat) #maj "." #min "." #pat
01126 #define       VSTR(maj, min, pat)  VSTR0(maj, min, pat)
01127 #define       SASL_VERSION_STRING  VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
01128                             SASL_VERSION_STEP)
01129 
01130        sasl_version( NULL, &rc );
01131        if ( ((rc >> 16) != ((SASL_VERSION_MAJOR << 8)|SASL_VERSION_MINOR)) ||
01132               (rc & 0xffff) < SASL_VERSION_STEP)
01133        {
01134               char version[sizeof("xxx.xxx.xxxxx")];
01135               sprintf( version, "%u.%d.%d", (unsigned)rc >> 24, (rc >> 16) & 0xff,
01136                      rc & 0xffff );
01137               Debug( LDAP_DEBUG_ANY, "slap_sasl_init: SASL library version mismatch:"
01138                      " expected %s, got %s\n",
01139                      SASL_VERSION_STRING, version, 0 );
01140               return -1;
01141        }
01142 #endif
01143 
01144        sasl_set_mutex(
01145               ldap_pvt_sasl_mutex_new,
01146               ldap_pvt_sasl_mutex_lock,
01147               ldap_pvt_sasl_mutex_unlock,
01148               ldap_pvt_sasl_mutex_dispose );
01149 
01150        generic_filter.f_desc = slap_schema.si_ad_objectClass;
01151 
01152        rc = sasl_auxprop_add_plugin( "slapd", slap_auxprop_init );
01153        if( rc != SASL_OK ) {
01154               Debug( LDAP_DEBUG_ANY, "slap_sasl_init: auxprop add plugin failed\n",
01155                      0, 0, 0 );
01156               return -1;
01157        }
01158 
01159        /* should provide callbacks for logging */
01160        /* server name should be configurable */
01161        rc = sasl_server_init( server_callbacks, "slapd" );
01162 
01163        if( rc != SASL_OK ) {
01164               Debug( LDAP_DEBUG_ANY, "slap_sasl_init: server init failed\n",
01165                      0, 0, 0 );
01166 
01167               return -1;
01168        }
01169 
01170 #ifdef SLAPD_SPASSWD
01171        lutil_passwd_add( &sasl_pwscheme, chk_sasl, NULL );
01172 #endif
01173 
01174        Debug( LDAP_DEBUG_TRACE, "slap_sasl_init: initialized!\n",
01175               0, 0, 0 );
01176 
01177        /* default security properties */
01178        memset( &sasl_secprops, '\0', sizeof(sasl_secprops) );
01179        sasl_secprops.max_ssf = INT_MAX;
01180        sasl_secprops.maxbufsize = 65536;
01181        sasl_secprops.security_flags = SASL_SEC_NOPLAINTEXT|SASL_SEC_NOANONYMOUS;
01182 #endif
01183 
01184        return 0;
01185 }
01186 
01187 int slap_sasl_destroy( void )
01188 {
01189 #ifdef HAVE_CYRUS_SASL
01190        sasl_done();
01191 #endif
01192        free( sasl_host );
01193        sasl_host = NULL;
01194 
01195        return 0;
01196 }
01197 
01198 static char *
01199 slap_sasl_peer2ipport( struct berval *peer )
01200 {
01201        int           isv6 = 0;
01202        char          *ipport, *p,
01203                      *addr = &peer->bv_val[ STRLENOF( "IP=" ) ];
01204        ber_len_t     plen = peer->bv_len - STRLENOF( "IP=" );
01205 
01206        /* IPv6? */
01207        if ( addr[0] == '[' ) {
01208               isv6 = 1;
01209               plen--;
01210        }
01211        ipport = ch_strdup( &addr[isv6] );
01212 
01213        /* Convert IPv6/IPv4 addresses to address;port syntax. */
01214        p = strrchr( ipport, ':' );
01215        if ( p != NULL ) {
01216               *p = ';';
01217               if ( isv6 ) {
01218                      assert( p[-1] == ']' );
01219                      AC_MEMCPY( &p[-1], p, plen - ( p - ipport ) + 1 );
01220               }
01221 
01222        } else if ( isv6 ) {
01223               /* trim ']' */
01224               plen--;
01225               assert( addr[plen] == ']' );
01226               addr[plen] = '\0';
01227        }
01228 
01229        return ipport;
01230 }
01231 
01232 int slap_sasl_open( Connection *conn, int reopen )
01233 {
01234        int sc = LDAP_SUCCESS;
01235 #ifdef HAVE_CYRUS_SASL
01236        int cb;
01237 
01238        sasl_conn_t *ctx = NULL;
01239        sasl_callback_t *session_callbacks;
01240        char *ipremoteport = NULL, *iplocalport = NULL;
01241 
01242        assert( conn->c_sasl_authctx == NULL );
01243 
01244        if ( !reopen ) {
01245               assert( conn->c_sasl_extra == NULL );
01246 
01247               session_callbacks =
01248                      SLAP_CALLOC( 5, sizeof(sasl_callback_t));
01249               if( session_callbacks == NULL ) {
01250                      Debug( LDAP_DEBUG_ANY, 
01251                             "slap_sasl_open: SLAP_MALLOC failed", 0, 0, 0 );
01252                      return -1;
01253               }
01254               conn->c_sasl_extra = session_callbacks;
01255 
01256               session_callbacks[cb=0].id = SASL_CB_LOG;
01257               session_callbacks[cb].proc = &slap_sasl_log;
01258               session_callbacks[cb++].context = conn;
01259 
01260               session_callbacks[cb].id = SASL_CB_PROXY_POLICY;
01261               session_callbacks[cb].proc = &slap_sasl_authorize;
01262               session_callbacks[cb++].context = conn;
01263 
01264               session_callbacks[cb].id = SASL_CB_CANON_USER;
01265               session_callbacks[cb].proc = &slap_sasl_canonicalize;
01266               session_callbacks[cb++].context = conn;
01267 
01268               session_callbacks[cb].id = SASL_CB_LIST_END;
01269               session_callbacks[cb].proc = NULL;
01270               session_callbacks[cb++].context = NULL;
01271        } else {
01272               session_callbacks = conn->c_sasl_extra;
01273        }
01274 
01275        conn->c_sasl_layers = 0;
01276 
01277        /* create new SASL context */
01278        if ( conn->c_sock_name.bv_len != 0 &&
01279               strncmp( conn->c_sock_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 )
01280        {
01281               iplocalport = slap_sasl_peer2ipport( &conn->c_sock_name );
01282        }
01283 
01284        if ( conn->c_peer_name.bv_len != 0 &&
01285               strncmp( conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 )
01286        {
01287               ipremoteport = slap_sasl_peer2ipport( &conn->c_peer_name );
01288        }
01289 
01290        sc = sasl_server_new( "ldap", sasl_host, global_realm,
01291               iplocalport, ipremoteport, session_callbacks, SASL_SUCCESS_DATA, &ctx );
01292        if ( iplocalport != NULL ) {
01293               ch_free( iplocalport );
01294        }
01295        if ( ipremoteport != NULL ) {
01296               ch_free( ipremoteport );
01297        }
01298 
01299        if( sc != SASL_OK ) {
01300               Debug( LDAP_DEBUG_ANY, "sasl_server_new failed: %d\n",
01301                      sc, 0, 0 );
01302 
01303               return -1;
01304        }
01305 
01306        conn->c_sasl_authctx = ctx;
01307 
01308        if( sc == SASL_OK ) {
01309               sc = sasl_setprop( ctx,
01310                      SASL_SEC_PROPS, &sasl_secprops );
01311 
01312               if( sc != SASL_OK ) {
01313                      Debug( LDAP_DEBUG_ANY, "sasl_setprop failed: %d\n",
01314                             sc, 0, 0 );
01315 
01316                      slap_sasl_close( conn );
01317                      return -1;
01318               }
01319        }
01320 
01321        sc = slap_sasl_err2ldap( sc );
01322 
01323 #elif defined(SLAP_BUILTIN_SASL)
01324        /* built-in SASL implementation */
01325        SASL_CTX *ctx = (SASL_CTX *) SLAP_MALLOC(sizeof(SASL_CTX));
01326        if( ctx == NULL ) return -1;
01327 
01328        ctx->sc_external_ssf = 0;
01329        BER_BVZERO( &ctx->sc_external_id );
01330 
01331        conn->c_sasl_authctx = ctx;
01332 #endif
01333 
01334        return sc;
01335 }
01336 
01337 int slap_sasl_external(
01338        Connection *conn,
01339        slap_ssf_t ssf,
01340        struct berval *auth_id )
01341 {
01342 #ifdef HAVE_CYRUS_SASL
01343        int sc;
01344        sasl_conn_t *ctx = conn->c_sasl_authctx;
01345        sasl_ssf_t sasl_ssf = ssf;
01346 
01347        if ( ctx == NULL ) {
01348               return LDAP_UNAVAILABLE;
01349        }
01350 
01351        sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf );
01352 
01353        if ( sc != SASL_OK ) {
01354               return LDAP_OTHER;
01355        }
01356 
01357        sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL,
01358               auth_id ? auth_id->bv_val : NULL );
01359 
01360        if ( sc != SASL_OK ) {
01361               return LDAP_OTHER;
01362        }
01363 #elif defined(SLAP_BUILTIN_SASL)
01364        /* built-in SASL implementation */
01365        SASL_CTX *ctx = conn->c_sasl_authctx;
01366        if ( ctx == NULL ) return LDAP_UNAVAILABLE;
01367 
01368        ctx->sc_external_ssf = ssf;
01369        if( auth_id ) {
01370               ctx->sc_external_id = *auth_id;
01371               BER_BVZERO( auth_id );
01372        } else {
01373               BER_BVZERO( &ctx->sc_external_id );
01374        }
01375 #endif
01376 
01377        return LDAP_SUCCESS;
01378 }
01379 
01380 int slap_sasl_reset( Connection *conn )
01381 {
01382        return LDAP_SUCCESS;
01383 }
01384 
01385 char ** slap_sasl_mechs( Connection *conn )
01386 {
01387        char **mechs = NULL;
01388 
01389 #ifdef HAVE_CYRUS_SASL
01390        sasl_conn_t *ctx = conn->c_sasl_authctx;
01391 
01392        if( ctx == NULL ) ctx = conn->c_sasl_sockctx;
01393 
01394        if( ctx != NULL ) {
01395               int sc;
01396               SASL_CONST char *mechstr;
01397 
01398               sc = sasl_listmech( ctx,
01399                      NULL, NULL, ",", NULL,
01400                      &mechstr, NULL, NULL );
01401 
01402               if( sc != SASL_OK ) {
01403                      Debug( LDAP_DEBUG_ANY, "slap_sasl_listmech failed: %d\n",
01404                             sc, 0, 0 );
01405 
01406                      return NULL;
01407               }
01408 
01409               mechs = ldap_str2charray( mechstr, "," );
01410        }
01411 #elif defined(SLAP_BUILTIN_SASL)
01412        /* builtin SASL implementation */
01413        SASL_CTX *ctx = conn->c_sasl_authctx;
01414        if ( ctx != NULL && ctx->sc_external_id.bv_val ) {
01415               /* should check ssf */
01416               mechs = ldap_str2charray( "EXTERNAL", "," );
01417        }
01418 #endif
01419 
01420        return mechs;
01421 }
01422 
01423 int slap_sasl_close( Connection *conn )
01424 {
01425 #ifdef HAVE_CYRUS_SASL
01426        sasl_conn_t *ctx = conn->c_sasl_authctx;
01427 
01428        if( ctx != NULL ) {
01429               sasl_dispose( &ctx );
01430        }
01431        if ( conn->c_sasl_sockctx &&
01432               conn->c_sasl_authctx != conn->c_sasl_sockctx )
01433        {
01434               ctx = conn->c_sasl_sockctx;
01435               sasl_dispose( &ctx );
01436        }
01437 
01438        conn->c_sasl_authctx = NULL;
01439        conn->c_sasl_sockctx = NULL;
01440        conn->c_sasl_done = 0;
01441 
01442        free( conn->c_sasl_extra );
01443        conn->c_sasl_extra = NULL;
01444 
01445 #elif defined(SLAP_BUILTIN_SASL)
01446        SASL_CTX *ctx = conn->c_sasl_authctx;
01447        if( ctx ) {
01448               if( ctx->sc_external_id.bv_val ) {
01449                      free( ctx->sc_external_id.bv_val );
01450                      BER_BVZERO( &ctx->sc_external_id );
01451               }
01452               free( ctx );
01453               conn->c_sasl_authctx = NULL;
01454        }
01455 #endif
01456 
01457        return LDAP_SUCCESS;
01458 }
01459 
01460 int slap_sasl_bind( Operation *op, SlapReply *rs )
01461 {
01462 #ifdef HAVE_CYRUS_SASL
01463        sasl_conn_t *ctx = op->o_conn->c_sasl_authctx;
01464        struct berval response;
01465        unsigned reslen = 0;
01466        int sc;
01467 
01468        Debug(LDAP_DEBUG_ARGS,
01469               "==> sasl_bind: dn=\"%s\" mech=%s datalen=%ld\n",
01470               op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "",
01471               op->o_conn->c_sasl_bind_in_progress ? "<continuing>" : 
01472               op->o_conn->c_sasl_bind_mech.bv_val,
01473               op->orb_cred.bv_len );
01474 
01475        if( ctx == NULL ) {
01476               send_ldap_error( op, rs, LDAP_UNAVAILABLE,
01477                      "SASL unavailable on this session" );
01478               return rs->sr_err;
01479        }
01480 
01481 #define       START( ctx, mech, cred, clen, resp, rlen, err ) \
01482        sasl_server_start( ctx, mech, cred, clen, resp, rlen )
01483 #define       STEP( ctx, cred, clen, resp, rlen, err ) \
01484        sasl_server_step( ctx, cred, clen, resp, rlen )
01485 
01486        if ( !op->o_conn->c_sasl_bind_in_progress ) {
01487               /* If we already authenticated once, must use a new context */
01488               if ( op->o_conn->c_sasl_done ) {
01489                      sasl_ssf_t ssf = 0;
01490                      const char *authid = NULL;
01491                      sasl_getprop( ctx, SASL_SSF_EXTERNAL, (void *)&ssf );
01492                      sasl_getprop( ctx, SASL_AUTH_EXTERNAL, (void *)&authid );
01493                      if ( authid ) authid = ch_strdup( authid );
01494                      if ( ctx != op->o_conn->c_sasl_sockctx ) {
01495                             sasl_dispose( &ctx );
01496                      }
01497                      op->o_conn->c_sasl_authctx = NULL;
01498                             
01499                      slap_sasl_open( op->o_conn, 1 );
01500                      ctx = op->o_conn->c_sasl_authctx;
01501                      if ( authid ) {
01502                             sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf );
01503                             sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid );
01504                             ch_free( (char *)authid );
01505                      }
01506               }
01507               sc = START( ctx,
01508                      op->o_conn->c_sasl_bind_mech.bv_val,
01509                      op->orb_cred.bv_val, op->orb_cred.bv_len,
01510                      (SASL_CONST char **)&response.bv_val, &reslen, &rs->sr_text );
01511 
01512        } else {
01513               sc = STEP( ctx,
01514                      op->orb_cred.bv_val, op->orb_cred.bv_len,
01515                      (SASL_CONST char **)&response.bv_val, &reslen, &rs->sr_text );
01516        }
01517 
01518        response.bv_len = reslen;
01519 
01520        if ( sc == SASL_OK ) {
01521               sasl_ssf_t *ssf = NULL;
01522 
01523               ber_dupbv_x( &op->orb_edn, &op->o_conn->c_sasl_dn, op->o_tmpmemctx );
01524               BER_BVZERO( &op->o_conn->c_sasl_dn );
01525               op->o_conn->c_sasl_done = 1;
01526 
01527               rs->sr_err = LDAP_SUCCESS;
01528 
01529               (void) sasl_getprop( ctx, SASL_SSF, (void *)&ssf );
01530               op->orb_ssf = ssf ? *ssf : 0;
01531 
01532               ctx = NULL;
01533               if( op->orb_ssf ) {
01534                      ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
01535                      op->o_conn->c_sasl_layers++;
01536 
01537                      /* If there's an old layer, set sockctx to NULL to
01538                       * tell connection_read() to wait for us to finish.
01539                       * Otherwise there is a race condition: we have to
01540                       * send the Bind response using the old security
01541                       * context and then remove it before reading any
01542                       * new messages.
01543                       */
01544                      if ( op->o_conn->c_sasl_sockctx ) {
01545                             ctx = op->o_conn->c_sasl_sockctx;
01546                             op->o_conn->c_sasl_sockctx = NULL;
01547                      } else {
01548                             op->o_conn->c_sasl_sockctx = op->o_conn->c_sasl_authctx;
01549                      }
01550                      ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
01551               }
01552 
01553               /* Must send response using old security layer */
01554               rs->sr_sasldata = (response.bv_len ? &response : NULL);
01555               send_ldap_sasl( op, rs );
01556               
01557               /* Now dispose of the old security layer.
01558                */
01559               if ( ctx ) {
01560                      ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
01561                      ldap_pvt_sasl_remove( op->o_conn->c_sb );
01562                      op->o_conn->c_sasl_sockctx = op->o_conn->c_sasl_authctx;
01563                      ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
01564                      sasl_dispose( &ctx );
01565               }
01566        } else if ( sc == SASL_CONTINUE ) {
01567               rs->sr_err = LDAP_SASL_BIND_IN_PROGRESS,
01568               rs->sr_text = sasl_errdetail( ctx );
01569               rs->sr_sasldata = &response;
01570               send_ldap_sasl( op, rs );
01571 
01572        } else {
01573               BER_BVZERO( &op->o_conn->c_sasl_dn );
01574               rs->sr_text = sasl_errdetail( ctx );
01575               rs->sr_err = slap_sasl_err2ldap( sc ),
01576               send_ldap_result( op, rs );
01577        }
01578 
01579        Debug(LDAP_DEBUG_TRACE, "<== slap_sasl_bind: rc=%d\n", rs->sr_err, 0, 0);
01580 
01581 #elif defined(SLAP_BUILTIN_SASL)
01582        /* built-in SASL implementation */
01583        SASL_CTX *ctx = op->o_conn->c_sasl_authctx;
01584 
01585        if ( ctx == NULL ) {
01586               send_ldap_error( op, rs, LDAP_OTHER,
01587                      "Internal SASL Error" );
01588 
01589        } else if ( bvmatch( &ext_bv, &op->o_conn->c_sasl_bind_mech ) ) {
01590               /* EXTERNAL */
01591 
01592               if( op->orb_cred.bv_len ) {
01593                      rs->sr_text = "proxy authorization not supported";
01594                      rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01595                      send_ldap_result( op, rs );
01596 
01597               } else {
01598                      op->orb_edn = ctx->sc_external_id;
01599                      rs->sr_err = LDAP_SUCCESS;
01600                      rs->sr_sasldata = NULL;
01601                      send_ldap_sasl( op, rs );
01602               }
01603 
01604        } else {
01605               send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED,
01606                      "requested SASL mechanism not supported" );
01607        }
01608 #else
01609        send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED,
01610               "SASL not supported" );
01611 #endif
01612 
01613        return rs->sr_err;
01614 }
01615 
01616 char* slap_sasl_secprops( const char *in )
01617 {
01618 #ifdef HAVE_CYRUS_SASL
01619        int rc = ldap_pvt_sasl_secprops( in, &sasl_secprops );
01620 
01621        return rc == LDAP_SUCCESS ? NULL : "Invalid security properties";
01622 #else
01623        return "SASL not supported";
01624 #endif
01625 }
01626 
01627 void slap_sasl_secprops_unparse( struct berval *bv )
01628 {
01629 #ifdef HAVE_CYRUS_SASL
01630        ldap_pvt_sasl_secprops_unparse( &sasl_secprops, bv );
01631 #endif
01632 }
01633 
01634 #ifdef HAVE_CYRUS_SASL
01635 int
01636 slap_sasl_setpass( Operation *op, SlapReply *rs )
01637 {
01638        struct berval id = BER_BVNULL;     /* needs to come from connection */
01639        struct berval new = BER_BVNULL;
01640        struct berval old = BER_BVNULL;
01641 
01642        assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 );
01643 
01644        rs->sr_err = sasl_getprop( op->o_conn->c_sasl_authctx, SASL_USERNAME,
01645               (SASL_CONST void **)(char *)&id.bv_val );
01646 
01647        if( rs->sr_err != SASL_OK ) {
01648               rs->sr_text = "unable to retrieve SASL username";
01649               rs->sr_err = LDAP_OTHER;
01650               goto done;
01651        }
01652 
01653        Debug( LDAP_DEBUG_ARGS, "==> slap_sasl_setpass: \"%s\"\n",
01654               id.bv_val ? id.bv_val : "", 0, 0 );
01655 
01656        rs->sr_err = slap_passwd_parse( op->ore_reqdata,
01657               NULL, &old, &new, &rs->sr_text );
01658 
01659        if( rs->sr_err != LDAP_SUCCESS ) {
01660               goto done;
01661        }
01662 
01663        if( new.bv_len == 0 ) {
01664               slap_passwd_generate(&new);
01665 
01666               if( new.bv_len == 0 ) {
01667                      rs->sr_text = "password generation failed.";
01668                      rs->sr_err = LDAP_OTHER;
01669                      goto done;
01670               }
01671               
01672               rs->sr_rspdata = slap_passwd_return( &new );
01673        }
01674 
01675        rs->sr_err = sasl_setpass( op->o_conn->c_sasl_authctx, id.bv_val,
01676               new.bv_val, new.bv_len, old.bv_val, old.bv_len, 0 );
01677        if( rs->sr_err != SASL_OK ) {
01678               rs->sr_text = sasl_errdetail( op->o_conn->c_sasl_authctx );
01679        }
01680        switch(rs->sr_err) {
01681               case SASL_OK:
01682                      rs->sr_err = LDAP_SUCCESS;
01683                      break;
01684 
01685               case SASL_NOCHANGE:
01686               case SASL_NOMECH:
01687               case SASL_DISABLED:
01688               case SASL_PWLOCK:
01689               case SASL_FAIL:
01690               case SASL_BADPARAM:
01691               default:
01692                      rs->sr_err = LDAP_OTHER;
01693        }
01694 
01695 done:
01696        return rs->sr_err;
01697 }
01698 #endif /* HAVE_CYRUS_SASL */
01699 
01700 /* Take any sort of identity string and return a DN with the "dn:" prefix. The
01701  * string returned in *dn is in its own allocated memory, and must be free'd 
01702  * by the calling process.  -Mark Adamson, Carnegie Mellon
01703  *
01704  * The "dn:" prefix is no longer used anywhere inside slapd. It is only used
01705  * on strings passed in directly from SASL.  -Howard Chu, Symas Corp.
01706  */
01707 
01708 #define SET_NONE     0
01709 #define       SET_DN        1
01710 #define       SET_U         2
01711 
01712 int slap_sasl_getdn( Connection *conn, Operation *op, struct berval *id,
01713        char *user_realm, struct berval *dn, int flags )
01714 {
01715        int rc, is_dn = SET_NONE, do_norm = 1;
01716        struct berval dn2, *mech;
01717 
01718        assert( conn != NULL );
01719        assert( id != NULL );
01720 
01721        Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: conn %lu id=%s [len=%lu]\n", 
01722               conn->c_connid,
01723               BER_BVISNULL( id ) ? "NULL" : ( BER_BVISEMPTY( id ) ? "<empty>" : id->bv_val ),
01724               BER_BVISNULL( id ) ? 0 : ( BER_BVISEMPTY( id ) ? 0 :
01725                                          (unsigned long) id->bv_len ) );
01726 
01727        if ( !op ) {
01728               op = conn->c_sasl_bindop;
01729        }
01730        assert( op != NULL );
01731 
01732        BER_BVZERO( dn );
01733 
01734        if ( !BER_BVISNULL( id ) ) {
01735               /* Blatantly anonymous ID */
01736               static struct berval bv_anonymous = BER_BVC( "anonymous" );
01737 
01738               if ( ber_bvstrcasecmp( id, &bv_anonymous ) == 0 ) {
01739                      return( LDAP_SUCCESS );
01740               }
01741 
01742        } else {
01743               /* FIXME: if empty, should we stop? */
01744               BER_BVSTR( id, "" );
01745        }
01746 
01747        if ( !BER_BVISEMPTY( &conn->c_sasl_bind_mech ) ) {
01748               mech = &conn->c_sasl_bind_mech;
01749        } else {
01750               mech = &conn->c_authmech;
01751        }
01752 
01753        /* An authcID needs to be converted to authzID form. Set the
01754         * values directly into *dn; they will be normalized later. (and
01755         * normalizing always makes a new copy.) An ID from a TLS certificate
01756         * is already normalized, so copy it and skip normalization.
01757         */
01758        if( flags & SLAP_GETDN_AUTHCID ) {
01759               if( bvmatch( mech, &ext_bv )) {
01760                      /* EXTERNAL DNs are already normalized */
01761                      assert( !BER_BVISNULL( id ) );
01762 
01763                      do_norm = 0;
01764                      is_dn = SET_DN;
01765                      ber_dupbv_x( dn, id, op->o_tmpmemctx );
01766 
01767               } else {
01768                      /* convert to u:<username> form */
01769                      is_dn = SET_U;
01770                      *dn = *id;
01771               }
01772        }
01773 
01774        if( is_dn == SET_NONE ) {
01775               if( !strncasecmp( id->bv_val, "u:", STRLENOF( "u:" ) ) ) {
01776                      is_dn = SET_U;
01777                      dn->bv_val = id->bv_val + STRLENOF( "u:" );
01778                      dn->bv_len = id->bv_len - STRLENOF( "u:" );
01779 
01780               } else if ( !strncasecmp( id->bv_val, "dn:", STRLENOF( "dn:" ) ) ) {
01781                      is_dn = SET_DN;
01782                      dn->bv_val = id->bv_val + STRLENOF( "dn:" );
01783                      dn->bv_len = id->bv_len - STRLENOF( "dn:" );
01784               }
01785        }
01786 
01787        /* No other possibilities from here */
01788        if( is_dn == SET_NONE ) {
01789               BER_BVZERO( dn );
01790               return( LDAP_INAPPROPRIATE_AUTH );
01791        }
01792 
01793        /* Username strings */
01794        if( is_dn == SET_U ) {
01795               /* ITS#3419: values may need escape */
01796               LDAPRDN              DN[ 5 ];
01797               LDAPAVA       *RDNs[ 4 ][ 2 ];
01798               LDAPAVA       AVAs[ 4 ];
01799               int           irdn;
01800 
01801               irdn = 0;
01802               DN[ irdn ] = RDNs[ irdn ];
01803               RDNs[ irdn ][ 0 ] = &AVAs[ irdn ];
01804               AVAs[ irdn ].la_attr = slap_schema.si_ad_uid->ad_cname;
01805               AVAs[ irdn ].la_value = *dn;
01806               AVAs[ irdn ].la_flags = LDAP_AVA_NULL;
01807               AVAs[ irdn ].la_private = NULL;
01808               RDNs[ irdn ][ 1 ] = NULL;
01809 
01810               if ( user_realm && *user_realm ) {
01811                      irdn++;
01812                      DN[ irdn ] = RDNs[ irdn ];
01813                      RDNs[ irdn ][ 0 ] = &AVAs[ irdn ];
01814                      AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname;
01815                      ber_str2bv( user_realm, 0, 0, &AVAs[ irdn ].la_value );
01816                      AVAs[ irdn ].la_flags = LDAP_AVA_NULL;
01817                      AVAs[ irdn ].la_private = NULL;
01818                      RDNs[ irdn ][ 1 ] = NULL;
01819               }
01820 
01821               if ( !BER_BVISNULL( mech ) ) {
01822                      irdn++;
01823                      DN[ irdn ] = RDNs[ irdn ];
01824                      RDNs[ irdn ][ 0 ] = &AVAs[ irdn ];
01825                      AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname;
01826                      AVAs[ irdn ].la_value = *mech;
01827                      AVAs[ irdn ].la_flags = LDAP_AVA_NULL;
01828                      AVAs[ irdn ].la_private = NULL;
01829                      RDNs[ irdn ][ 1 ] = NULL;
01830               }
01831 
01832               irdn++;
01833               DN[ irdn ] = RDNs[ irdn ];
01834               RDNs[ irdn ][ 0 ] = &AVAs[ irdn ];
01835               AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname;
01836               BER_BVSTR( &AVAs[ irdn ].la_value, "auth" );
01837               AVAs[ irdn ].la_flags = LDAP_AVA_NULL;
01838               AVAs[ irdn ].la_private = NULL;
01839               RDNs[ irdn ][ 1 ] = NULL;
01840 
01841               irdn++;
01842               DN[ irdn ] = NULL;
01843 
01844               rc = ldap_dn2bv_x( DN, dn, LDAP_DN_FORMAT_LDAPV3,
01845                             op->o_tmpmemctx );
01846               if ( rc != LDAP_SUCCESS ) {
01847                      BER_BVZERO( dn );
01848                      return rc;
01849               }
01850 
01851               Debug( LDAP_DEBUG_TRACE,
01852                      "slap_sasl_getdn: u:id converted to %s\n",
01853                      dn->bv_val, 0, 0 );
01854 
01855        } else {
01856               
01857               /* Dup the DN in any case, so we don't risk 
01858                * leaks or dangling pointers later,
01859                * and the DN value is '\0' terminated */
01860               ber_dupbv_x( &dn2, dn, op->o_tmpmemctx );
01861               dn->bv_val = dn2.bv_val;
01862        }
01863 
01864        /* All strings are in DN form now. Normalize if needed. */
01865        if ( do_norm ) {
01866               rc = dnNormalize( 0, NULL, NULL, dn, &dn2, op->o_tmpmemctx );
01867 
01868               /* User DNs were constructed above and must be freed now */
01869               slap_sl_free( dn->bv_val, op->o_tmpmemctx );
01870 
01871               if ( rc != LDAP_SUCCESS ) {
01872                      BER_BVZERO( dn );
01873                      return rc;
01874               }
01875               *dn = dn2;
01876        }
01877 
01878        /* Run thru regexp */
01879        slap_sasl2dn( op, dn, &dn2, flags );
01880        if( !BER_BVISNULL( &dn2 ) ) {
01881               slap_sl_free( dn->bv_val, op->o_tmpmemctx );
01882               *dn = dn2;
01883               Debug( LDAP_DEBUG_TRACE,
01884                      "slap_sasl_getdn: dn:id converted to %s\n",
01885                      dn->bv_val, 0, 0 );
01886        }
01887 
01888        return( LDAP_SUCCESS );
01889 }