sasl.c revision 1.1.1.6
1/* $NetBSD: sasl.c,v 1.1.1.6 2018/02/06 01:53:15 christos Exp $ */ 2 3/* $OpenLDAP$ */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2017 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 18#include <sys/cdefs.h> 19__RCSID("$NetBSD: sasl.c,v 1.1.1.6 2018/02/06 01:53:15 christos Exp $"); 20 21#include "portable.h" 22 23#include <stdio.h> 24#ifdef HAVE_LIMITS_H 25#include <limits.h> 26#endif 27 28#include <ac/stdlib.h> 29#include <ac/string.h> 30 31#include <lber.h> 32#include <ldap_log.h> 33 34#include "slap.h" 35 36#ifdef ENABLE_REWRITE 37#include <rewrite.h> 38#endif 39 40#ifdef HAVE_CYRUS_SASL 41# ifdef HAVE_SASL_SASL_H 42# include <sasl/sasl.h> 43# include <sasl/saslplug.h> 44# else 45# include <sasl.h> 46# include <saslplug.h> 47# endif 48 49# define SASL_CONST const 50 51#define SASL_VERSION_FULL ((SASL_VERSION_MAJOR << 16) |\ 52 (SASL_VERSION_MINOR << 8) | SASL_VERSION_STEP) 53 54#if SASL_VERSION_MINOR >= 0x020119 /* 2.1.25 */ 55typedef sasl_callback_ft slap_sasl_cb_ft; 56#else 57typedef int (*slap_sasl_cb_ft)(); 58#endif 59 60static sasl_security_properties_t sasl_secprops; 61#elif defined( SLAP_BUILTIN_SASL ) 62/* 63 * built-in SASL implementation 64 * only supports EXTERNAL 65 */ 66typedef struct sasl_ctx { 67 slap_ssf_t sc_external_ssf; 68 struct berval sc_external_id; 69} SASL_CTX; 70 71#endif 72 73#include <lutil.h> 74 75static struct berval ext_bv = BER_BVC( "EXTERNAL" ); 76 77char *slap_sasl_auxprops; 78 79#ifdef HAVE_CYRUS_SASL 80 81/* Just use our internal auxprop by default */ 82static int 83slap_sasl_getopt( 84 void *context, 85 const char *plugin_name, 86 const char *option, 87 const char **result, 88 unsigned *len) 89{ 90 if ( strcmp( option, "auxprop_plugin" )) { 91 return SASL_FAIL; 92 } 93 if ( slap_sasl_auxprops ) 94 *result = slap_sasl_auxprops; 95 else 96 *result = "slapd"; 97 return SASL_OK; 98} 99 100int 101slap_sasl_log( 102 void *context, 103 int priority, 104 const char *message) 105{ 106 Connection *conn = context; 107 int level; 108 const char * label; 109 110 if ( message == NULL ) { 111 return SASL_BADPARAM; 112 } 113 114 switch (priority) { 115 case SASL_LOG_NONE: 116 level = LDAP_DEBUG_NONE; 117 label = "None"; 118 break; 119 case SASL_LOG_ERR: 120 level = LDAP_DEBUG_ANY; 121 label = "Error"; 122 break; 123 case SASL_LOG_FAIL: 124 level = LDAP_DEBUG_ANY; 125 label = "Failure"; 126 break; 127 case SASL_LOG_WARN: 128 level = LDAP_DEBUG_TRACE; 129 label = "Warning"; 130 break; 131 case SASL_LOG_NOTE: 132 level = LDAP_DEBUG_TRACE; 133 label = "Notice"; 134 break; 135 case SASL_LOG_DEBUG: 136 level = LDAP_DEBUG_TRACE; 137 label = "Debug"; 138 break; 139 case SASL_LOG_TRACE: 140 level = LDAP_DEBUG_TRACE; 141 label = "Trace"; 142 break; 143 case SASL_LOG_PASS: 144 level = LDAP_DEBUG_TRACE; 145 label = "Password Trace"; 146 break; 147 default: 148 return SASL_BADPARAM; 149 } 150 151 Debug( level, "SASL [conn=%ld] %s: %s\n", 152 conn ? (long) conn->c_connid: -1L, 153 label, message ); 154 155 156 return SASL_OK; 157} 158 159static const char *slap_propnames[] = { 160 "*slapConn", "*slapAuthcDNlen", "*slapAuthcDN", 161 "*slapAuthzDNlen", "*slapAuthzDN", NULL }; 162 163static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL }; 164static struct berval generic_filterstr = BER_BVC("(objectclass=*)"); 165 166#define SLAP_SASL_PROP_CONN 0 167#define SLAP_SASL_PROP_AUTHCLEN 1 168#define SLAP_SASL_PROP_AUTHC 2 169#define SLAP_SASL_PROP_AUTHZLEN 3 170#define SLAP_SASL_PROP_AUTHZ 4 171#define SLAP_SASL_PROP_COUNT 5 /* Number of properties we used */ 172 173typedef struct lookup_info { 174 int flags; 175 const struct propval *list; 176 sasl_server_params_t *sparams; 177} lookup_info; 178 179static slap_response sasl_ap_lookup; 180 181static struct berval sc_cleartext = BER_BVC("{CLEARTEXT}"); 182 183static int 184sasl_ap_lookup( Operation *op, SlapReply *rs ) 185{ 186 BerVarray bv; 187 AttributeDescription *ad; 188 Attribute *a; 189 const char *text; 190 int rc, i; 191 lookup_info *sl = (lookup_info *)op->o_callback->sc_private; 192 193 if (rs->sr_type != REP_SEARCH) return 0; 194 195 for( i = 0; sl->list[i].name; i++ ) { 196 const char *name = sl->list[i].name; 197 198 if ( name[0] == '*' ) { 199 if ( sl->flags & SASL_AUXPROP_AUTHZID ) continue; 200 /* Skip our private properties */ 201 if ( !strcmp( name, slap_propnames[0] )) { 202 i += SLAP_SASL_PROP_COUNT - 1; 203 continue; 204 } 205 name++; 206 } else if ( !(sl->flags & SASL_AUXPROP_AUTHZID ) ) 207 continue; 208 209 if ( sl->list[i].values ) { 210 if ( !(sl->flags & SASL_AUXPROP_OVERRIDE) ) continue; 211 } 212 ad = NULL; 213 rc = slap_str2ad( name, &ad, &text ); 214 if ( rc != LDAP_SUCCESS ) { 215 Debug( LDAP_DEBUG_TRACE, 216 "slap_ap_lookup: str2ad(%s): %s\n", name, text, 0 ); 217 continue; 218 } 219 220 /* If it's the rootdn and a rootpw was present, we already set 221 * it so don't override it here. 222 */ 223 if ( ad == slap_schema.si_ad_userPassword && sl->list[i].values && 224 be_isroot_dn( op->o_bd, &op->o_req_ndn )) 225 continue; 226 227 a = attr_find( rs->sr_entry->e_attrs, ad ); 228 if ( !a ) continue; 229 if ( ! access_allowed( op, rs->sr_entry, ad, NULL, ACL_AUTH, NULL ) ) { 230 continue; 231 } 232 if ( sl->list[i].values && ( sl->flags & SASL_AUXPROP_OVERRIDE ) ) { 233 sl->sparams->utils->prop_erase( sl->sparams->propctx, 234 sl->list[i].name ); 235 } 236 for ( bv = a->a_vals; bv->bv_val; bv++ ) { 237 /* ITS#3846 don't give hashed passwords to SASL */ 238 if ( ad == slap_schema.si_ad_userPassword && 239 bv->bv_val[0] == '{' /*}*/ ) 240 { 241 if ( lutil_passwd_scheme( bv->bv_val ) ) { 242 /* If it's not a recognized scheme, just assume it's 243 * a cleartext password that happened to include brackets. 244 * 245 * If it's a recognized scheme, skip this value, unless the 246 * scheme is {CLEARTEXT}. In that case, skip over the 247 * scheme name and use the remainder. If there is nothing 248 * past the scheme name, skip this value. 249 */ 250#ifdef SLAPD_CLEARTEXT 251 if ( !strncasecmp( bv->bv_val, sc_cleartext.bv_val, 252 sc_cleartext.bv_len )) { 253 struct berval cbv; 254 cbv.bv_len = bv->bv_len - sc_cleartext.bv_len; 255 if ( cbv.bv_len > 0 ) { 256 cbv.bv_val = bv->bv_val + sc_cleartext.bv_len; 257 sl->sparams->utils->prop_set( sl->sparams->propctx, 258 sl->list[i].name, cbv.bv_val, cbv.bv_len ); 259 } 260 } 261#endif 262 continue; 263 } 264 } 265 sl->sparams->utils->prop_set( sl->sparams->propctx, 266 sl->list[i].name, bv->bv_val, bv->bv_len ); 267 } 268 } 269 return LDAP_SUCCESS; 270} 271 272#if SASL_VERSION_FULL >= 0x020118 273static int 274#else 275static void 276#endif 277slap_auxprop_lookup( 278 void *glob_context, 279 sasl_server_params_t *sparams, 280 unsigned flags, 281 const char *user, 282 unsigned ulen) 283{ 284 OperationBuffer opbuf = {{ NULL }}; 285 Operation *op = (Operation *)&opbuf; 286 int i, doit = 0; 287 Connection *conn = NULL; 288 lookup_info sl; 289 int rc = LDAP_SUCCESS; 290 291 sl.list = sparams->utils->prop_get( sparams->propctx ); 292 sl.sparams = sparams; 293 sl.flags = flags; 294 295 /* Find our DN and conn first */ 296 for( i = 0; sl.list[i].name; i++ ) { 297 if ( sl.list[i].name[0] == '*' ) { 298 if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) { 299 if ( sl.list[i].values && sl.list[i].values[0] ) 300 AC_MEMCPY( &conn, sl.list[i].values[0], sizeof( conn ) ); 301 continue; 302 } 303 if ( flags & SASL_AUXPROP_AUTHZID ) { 304 if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZLEN] )) { 305 if ( sl.list[i].values && sl.list[i].values[0] ) 306 AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0], 307 sizeof( op->o_req_ndn.bv_len ) ); 308 } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZ] )) { 309 if ( sl.list[i].values ) 310 op->o_req_ndn.bv_val = (char *)sl.list[i].values[0]; 311 break; 312 } 313 } 314 315 if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) { 316 if ( sl.list[i].values && sl.list[i].values[0] ) 317 AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0], 318 sizeof( op->o_req_ndn.bv_len ) ); 319 } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) { 320 if ( sl.list[i].values ) { 321 op->o_req_ndn.bv_val = (char *)sl.list[i].values[0]; 322 if ( !(flags & SASL_AUXPROP_AUTHZID) ) 323 break; 324 } 325 } 326 } 327 } 328 329 /* we don't know anything about this, ignore it */ 330 if ( !conn ) { 331 rc == LDAP_SUCCESS; 332 goto done; 333 } 334 335 /* Now see what else needs to be fetched */ 336 for( i = 0; sl.list[i].name; i++ ) { 337 const char *name = sl.list[i].name; 338 339 if ( name[0] == '*' ) { 340 if ( flags & SASL_AUXPROP_AUTHZID ) continue; 341 /* Skip our private properties */ 342 if ( !strcmp( name, slap_propnames[0] )) { 343 i += SLAP_SASL_PROP_COUNT - 1; 344 continue; 345 } 346 name++; 347 } else if ( !(flags & SASL_AUXPROP_AUTHZID ) ) 348 continue; 349 350 if ( sl.list[i].values ) { 351 if ( !(flags & SASL_AUXPROP_OVERRIDE) ) continue; 352 } 353 doit = 1; 354 break; 355 } 356 357 if (doit) { 358 slap_callback cb = { NULL, sasl_ap_lookup, NULL, NULL }; 359 360 cb.sc_private = &sl; 361 362 op->o_bd = select_backend( &op->o_req_ndn, 1 ); 363 364 if ( op->o_bd ) { 365 /* For rootdn, see if we can use the rootpw */ 366 if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) && 367 !BER_BVISEMPTY( &op->o_bd->be_rootpw )) { 368 struct berval cbv = BER_BVNULL; 369 370 /* If there's a recognized scheme, see if it's CLEARTEXT */ 371 if ( lutil_passwd_scheme( op->o_bd->be_rootpw.bv_val )) { 372 if ( !strncasecmp( op->o_bd->be_rootpw.bv_val, 373 sc_cleartext.bv_val, sc_cleartext.bv_len )) { 374 375 /* If it's CLEARTEXT, skip past scheme spec */ 376 cbv.bv_len = op->o_bd->be_rootpw.bv_len - 377 sc_cleartext.bv_len; 378 if ( cbv.bv_len ) { 379 cbv.bv_val = op->o_bd->be_rootpw.bv_val + 380 sc_cleartext.bv_len; 381 } 382 } 383 /* No scheme, use the whole value */ 384 } else { 385 cbv = op->o_bd->be_rootpw; 386 } 387 if ( !BER_BVISEMPTY( &cbv )) { 388 for( i = 0; sl.list[i].name; i++ ) { 389 const char *name = sl.list[i].name; 390 391 if ( name[0] == '*' ) { 392 if ( flags & SASL_AUXPROP_AUTHZID ) continue; 393 name++; 394 } else if ( !(flags & SASL_AUXPROP_AUTHZID ) ) 395 continue; 396 397 if ( !strcasecmp(name,"userPassword") ) { 398 sl.sparams->utils->prop_set( sl.sparams->propctx, 399 sl.list[i].name, cbv.bv_val, cbv.bv_len ); 400 break; 401 } 402 } 403 } 404 } 405 406 if ( op->o_bd->be_search ) { 407 SlapReply rs = {REP_RESULT}; 408 op->o_hdr = conn->c_sasl_bindop->o_hdr; 409 op->o_controls = opbuf.ob_controls; 410 op->o_tag = LDAP_REQ_SEARCH; 411 op->o_dn = conn->c_ndn; 412 op->o_ndn = conn->c_ndn; 413 op->o_callback = &cb; 414 slap_op_time( &op->o_time, &op->o_tincr ); 415 op->o_do_not_cache = 1; 416 op->o_is_auth_check = 1; 417 op->o_req_dn = op->o_req_ndn; 418 op->ors_scope = LDAP_SCOPE_BASE; 419 op->ors_deref = LDAP_DEREF_NEVER; 420 op->ors_tlimit = SLAP_NO_LIMIT; 421 op->ors_slimit = 1; 422 op->ors_filter = &generic_filter; 423 op->ors_filterstr = generic_filterstr; 424 op->o_authz = conn->c_authz; 425 /* FIXME: we want all attributes, right? */ 426 op->ors_attrs = NULL; 427 428 rc = op->o_bd->be_search( op, &rs ); 429 } 430 } 431 } 432done:; 433#if SASL_VERSION_FULL >= 0x020118 434 return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK; 435#endif 436} 437 438#if SASL_VERSION_FULL >= 0x020110 439static int 440slap_auxprop_store( 441 void *glob_context, 442 sasl_server_params_t *sparams, 443 struct propctx *prctx, 444 const char *user, 445 unsigned ulen) 446{ 447 Operation op = {0}; 448 Opheader oph; 449 SlapReply rs = {REP_RESULT}; 450 int rc, i; 451 unsigned j; 452 Connection *conn = NULL; 453 const struct propval *pr; 454 Modifications *modlist = NULL, **modtail = &modlist, *mod; 455 slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; 456 char textbuf[SLAP_TEXT_BUFLEN]; 457 const char *text; 458 size_t textlen = sizeof(textbuf); 459 460 /* just checking if we are enabled */ 461 if (!prctx) return SASL_OK; 462 463 if (!sparams || !user) return SASL_BADPARAM; 464 465 pr = sparams->utils->prop_get( sparams->propctx ); 466 467 /* Find our DN and conn first */ 468 for( i = 0; pr[i].name; i++ ) { 469 if ( pr[i].name[0] == '*' ) { 470 if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) { 471 if ( pr[i].values && pr[i].values[0] ) 472 AC_MEMCPY( &conn, pr[i].values[0], sizeof( conn ) ); 473 continue; 474 } 475 if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) { 476 if ( pr[i].values && pr[i].values[0] ) 477 AC_MEMCPY( &op.o_req_ndn.bv_len, pr[i].values[0], 478 sizeof( op.o_req_ndn.bv_len ) ); 479 } else if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) { 480 if ( pr[i].values ) 481 op.o_req_ndn.bv_val = (char *)pr[i].values[0]; 482 } 483 } 484 } 485 if (!conn || !op.o_req_ndn.bv_val) return SASL_BADPARAM; 486 487 op.o_bd = select_backend( &op.o_req_ndn, 1 ); 488 489 if ( !op.o_bd || !op.o_bd->be_modify ) return SASL_FAIL; 490 491 pr = sparams->utils->prop_get( prctx ); 492 if (!pr) return SASL_BADPARAM; 493 494 for (i=0; pr[i].name; i++); 495 if (!i) return SASL_BADPARAM; 496 497 for (i=0; pr[i].name; i++) { 498 mod = (Modifications *)ch_malloc( sizeof(Modifications) ); 499 mod->sml_op = LDAP_MOD_REPLACE; 500 mod->sml_flags = 0; 501 ber_str2bv( pr[i].name, 0, 0, &mod->sml_type ); 502 mod->sml_numvals = pr[i].nvalues; 503 mod->sml_values = (struct berval *)ch_malloc( (pr[i].nvalues + 1) * 504 sizeof(struct berval)); 505 for (j=0; j<pr[i].nvalues; j++) { 506 ber_str2bv( pr[i].values[j], 0, 1, &mod->sml_values[j]); 507 } 508 BER_BVZERO( &mod->sml_values[j] ); 509 mod->sml_nvalues = NULL; 510 mod->sml_desc = NULL; 511 *modtail = mod; 512 modtail = &mod->sml_next; 513 } 514 *modtail = NULL; 515 516 rc = slap_mods_check( &op, modlist, &text, textbuf, textlen, NULL ); 517 518 if ( rc == LDAP_SUCCESS ) { 519 rc = slap_mods_no_user_mod_check( &op, modlist, 520 &text, textbuf, textlen ); 521 522 if ( rc == LDAP_SUCCESS ) { 523 if ( conn->c_sasl_bindop ) { 524 op.o_hdr = conn->c_sasl_bindop->o_hdr; 525 } else { 526 op.o_hdr = &oph; 527 memset( &oph, 0, sizeof(oph) ); 528 operation_fake_init( conn, &op, ldap_pvt_thread_pool_context(), 0 ); 529 } 530 op.o_tag = LDAP_REQ_MODIFY; 531 op.o_ndn = op.o_req_ndn; 532 op.o_callback = &cb; 533 slap_op_time( &op.o_time, &op.o_tincr ); 534 op.o_do_not_cache = 1; 535 op.o_is_auth_check = 1; 536 op.o_req_dn = op.o_req_ndn; 537 op.orm_modlist = modlist; 538 539 rc = op.o_bd->be_modify( &op, &rs ); 540 } 541 } 542 slap_mods_free( modlist, 1 ); 543 return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK; 544} 545#endif /* SASL_VERSION_FULL >= 2.1.16 */ 546 547static sasl_auxprop_plug_t slap_auxprop_plugin = { 548 0, /* Features */ 549 0, /* spare */ 550 NULL, /* glob_context */ 551 NULL, /* auxprop_free */ 552 slap_auxprop_lookup, 553 "slapd", /* name */ 554#if SASL_VERSION_FULL >= 0x020110 555 slap_auxprop_store /* the declaration of this member changed 556 * in cyrus SASL from 2.1.15 to 2.1.16 */ 557#else 558 NULL 559#endif 560}; 561 562static int 563slap_auxprop_init( 564 const sasl_utils_t *utils, 565 int max_version, 566 int *out_version, 567 sasl_auxprop_plug_t **plug, 568 const char *plugname) 569{ 570 if ( !out_version || !plug ) return SASL_BADPARAM; 571 572 if ( max_version < SASL_AUXPROP_PLUG_VERSION ) return SASL_BADVERS; 573 574 *out_version = SASL_AUXPROP_PLUG_VERSION; 575 *plug = &slap_auxprop_plugin; 576 return SASL_OK; 577} 578 579/* Convert a SASL authcid or authzid into a DN. Store the DN in an 580 * auxiliary property, so that we can refer to it in sasl_authorize 581 * without interfering with anything else. Also, the SASL username 582 * buffer is constrained to 256 characters, and our DNs could be 583 * much longer (SLAP_LDAPDN_MAXLEN, currently set to 8192) 584 */ 585static int 586slap_sasl_canonicalize( 587 sasl_conn_t *sconn, 588 void *context, 589 const char *in, 590 unsigned inlen, 591 unsigned flags, 592 const char *user_realm, 593 char *out, 594 unsigned out_max, 595 unsigned *out_len) 596{ 597 Connection *conn = (Connection *)context; 598 struct propctx *props = sasl_auxprop_getctx( sconn ); 599 struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } }; 600 struct berval dn; 601 int rc, which; 602 const char *names[2]; 603 struct berval bvin; 604 605 *out_len = 0; 606 607 Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n", 608 conn ? (long) conn->c_connid : -1L, 609 (flags & SASL_CU_AUTHID) ? "authcid" : "authzid", 610 in ? in : "<empty>"); 611 612 /* If name is too big, just truncate. We don't care, we're 613 * using DNs, not the usernames. 614 */ 615 if ( inlen > out_max ) 616 inlen = out_max-1; 617 618 /* This is a Simple Bind using SPASSWD. That means the in-directory 619 * userPassword of the Binding user already points at SASL, so it 620 * cannot be used to actually satisfy a password comparison. Just 621 * ignore it, some other mech will process it. 622 */ 623 if ( !conn->c_sasl_bindop || 624 conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) goto done; 625 626 /* See if we need to add request, can only do it once */ 627 prop_getnames( props, slap_propnames, auxvals ); 628 if ( !auxvals[0].name ) 629 prop_request( props, slap_propnames ); 630 631 if ( flags & SASL_CU_AUTHID ) 632 which = SLAP_SASL_PROP_AUTHCLEN; 633 else 634 which = SLAP_SASL_PROP_AUTHZLEN; 635 636 /* Need to store the Connection for auxprop_lookup */ 637 if ( !auxvals[SLAP_SASL_PROP_CONN].values ) { 638 names[0] = slap_propnames[SLAP_SASL_PROP_CONN]; 639 names[1] = NULL; 640 prop_set( props, names[0], (char *)&conn, sizeof( conn ) ); 641 } 642 643 /* Already been here? */ 644 if ( auxvals[which].values ) 645 goto done; 646 647 /* Normally we require an authzID to have a u: or dn: prefix. 648 * However, SASL frequently gives us an authzID that is just 649 * an exact copy of the authcID, without a prefix. We need to 650 * detect and allow this condition. If SASL calls canonicalize 651 * with SASL_CU_AUTHID|SASL_CU_AUTHZID this is a no-brainer. 652 * But if it's broken into two calls, we need to remember the 653 * authcID so that we can compare the authzID later. We store 654 * the authcID temporarily in conn->c_sasl_dn. We necessarily 655 * finish Canonicalizing before Authorizing, so there is no 656 * conflict with slap_sasl_authorize's use of this temp var. 657 * 658 * The SASL EXTERNAL mech is backwards from all the other mechs, 659 * it does authzID before the authcID. If we see that authzID 660 * has already been done, don't do anything special with authcID. 661 */ 662 if ( flags == SASL_CU_AUTHID && !auxvals[SLAP_SASL_PROP_AUTHZ].values ) { 663 conn->c_sasl_dn.bv_val = (char *) in; 664 conn->c_sasl_dn.bv_len = 0; 665 } else if ( flags == SASL_CU_AUTHZID && conn->c_sasl_dn.bv_val ) { 666 rc = strcmp( in, conn->c_sasl_dn.bv_val ); 667 conn->c_sasl_dn.bv_val = NULL; 668 /* They were equal, no work needed */ 669 if ( !rc ) goto done; 670 } 671 672 bvin.bv_val = (char *)in; 673 bvin.bv_len = inlen; 674 rc = slap_sasl_getdn( conn, NULL, &bvin, (char *)user_realm, &dn, 675 (flags & SASL_CU_AUTHID) ? SLAP_GETDN_AUTHCID : SLAP_GETDN_AUTHZID ); 676 if ( rc != LDAP_SUCCESS ) { 677 sasl_seterror( sconn, 0, ldap_err2string( rc ) ); 678 return SASL_NOAUTHZ; 679 } 680 681 names[0] = slap_propnames[which]; 682 names[1] = NULL; 683 prop_set( props, names[0], (char *)&dn.bv_len, sizeof( dn.bv_len ) ); 684 685 which++; 686 names[0] = slap_propnames[which]; 687 prop_set( props, names[0], dn.bv_val, dn.bv_len ); 688 689 Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n", 690 conn ? (long) conn->c_connid : -1L, names[0]+1, 691 dn.bv_val ? dn.bv_val : "<EMPTY>" ); 692 693 /* Not needed any more, SASL has copied it */ 694 if ( conn && conn->c_sasl_bindop ) 695 conn->c_sasl_bindop->o_tmpfree( dn.bv_val, conn->c_sasl_bindop->o_tmpmemctx ); 696 697done: 698 AC_MEMCPY( out, in, inlen ); 699 out[inlen] = '\0'; 700 701 *out_len = inlen; 702 703 return SASL_OK; 704} 705 706static int 707slap_sasl_authorize( 708 sasl_conn_t *sconn, 709 void *context, 710 char *requested_user, 711 unsigned rlen, 712 char *auth_identity, 713 unsigned alen, 714 const char *def_realm, 715 unsigned urlen, 716 struct propctx *props) 717{ 718 Connection *conn = (Connection *)context; 719 /* actually: 720 * (SLAP_SASL_PROP_COUNT - 1) because we skip "conn", 721 * + 1 for NULL termination? 722 */ 723 struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } }; 724 struct berval authcDN, authzDN = BER_BVNULL; 725 int rc; 726 727 /* Simple Binds don't support proxy authorization, ignore it */ 728 if ( !conn->c_sasl_bindop || 729 conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) return SASL_OK; 730 731 Debug( LDAP_DEBUG_ARGS, "SASL proxy authorize [conn=%ld]: " 732 "authcid=\"%s\" authzid=\"%s\"\n", 733 conn ? (long) conn->c_connid : -1L, auth_identity, requested_user ); 734 if ( conn->c_sasl_dn.bv_val ) { 735 BER_BVZERO( &conn->c_sasl_dn ); 736 } 737 738 /* Skip SLAP_SASL_PROP_CONN */ 739 prop_getnames( props, slap_propnames+1, auxvals ); 740 741 /* Should not happen */ 742 if ( !auxvals[0].values ) { 743 sasl_seterror( sconn, 0, "invalid authcid" ); 744 return SASL_NOAUTHZ; 745 } 746 747 AC_MEMCPY( &authcDN.bv_len, auxvals[0].values[0], sizeof(authcDN.bv_len) ); 748 authcDN.bv_val = auxvals[1].values ? (char *)auxvals[1].values[0] : NULL; 749 conn->c_sasl_dn = authcDN; 750 751 /* Nothing to do if no authzID was given */ 752 if ( !auxvals[2].name || !auxvals[2].values ) { 753 goto ok; 754 } 755 756 AC_MEMCPY( &authzDN.bv_len, auxvals[2].values[0], sizeof(authzDN.bv_len) ); 757 authzDN.bv_val = auxvals[3].values ? (char *)auxvals[3].values[0] : NULL; 758 759 rc = slap_sasl_authorized( conn->c_sasl_bindop, &authcDN, &authzDN ); 760 if ( rc != LDAP_SUCCESS ) { 761 Debug( LDAP_DEBUG_TRACE, "SASL Proxy Authorize [conn=%ld]: " 762 "proxy authorization disallowed (%d)\n", 763 conn ? (long) conn->c_connid : -1L, rc, 0 ); 764 765 sasl_seterror( sconn, 0, "not authorized" ); 766 return SASL_NOAUTHZ; 767 } 768 769 /* FIXME: we need yet another dup because slap_sasl_getdn() 770 * is using the bind operation slab */ 771 ber_dupbv( &conn->c_sasl_authz_dn, &authzDN ); 772 773ok: 774 if (conn->c_sasl_bindop) { 775 Statslog( LDAP_DEBUG_STATS, 776 "%s BIND authcid=\"%s\" authzid=\"%s\"\n", 777 conn->c_sasl_bindop->o_log_prefix, 778 auth_identity, requested_user, 0, 0 ); 779 } 780 781 Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: " 782 " proxy authorization allowed authzDN=\"%s\"\n", 783 conn ? (long) conn->c_connid : -1L, 784 authzDN.bv_val ? authzDN.bv_val : "", 0 ); 785 return SASL_OK; 786} 787 788static int 789slap_sasl_err2ldap( int saslerr ) 790{ 791 int rc; 792 793 /* map SASL errors to LDAP resultCode returned by: 794 * sasl_server_new() 795 * SASL_OK, SASL_NOMEM 796 * sasl_server_step() 797 * SASL_OK, SASL_CONTINUE, SASL_TRANS, SASL_BADPARAM, SASL_BADPROT, 798 * ... 799 * sasl_server_start() 800 * + SASL_NOMECH 801 * sasl_setprop() 802 * SASL_OK, SASL_BADPARAM 803 */ 804 805 switch (saslerr) { 806 case SASL_OK: 807 rc = LDAP_SUCCESS; 808 break; 809 case SASL_CONTINUE: 810 rc = LDAP_SASL_BIND_IN_PROGRESS; 811 break; 812 case SASL_FAIL: 813 case SASL_NOMEM: 814 rc = LDAP_OTHER; 815 break; 816 case SASL_NOMECH: 817 rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; 818 break; 819 case SASL_BADAUTH: 820 case SASL_NOUSER: 821 case SASL_TRANS: 822 case SASL_EXPIRED: 823 rc = LDAP_INVALID_CREDENTIALS; 824 break; 825 case SASL_NOAUTHZ: 826 rc = LDAP_INSUFFICIENT_ACCESS; 827 break; 828 case SASL_TOOWEAK: 829 case SASL_ENCRYPT: 830 rc = LDAP_INAPPROPRIATE_AUTH; 831 break; 832 case SASL_UNAVAIL: 833 case SASL_TRYAGAIN: 834 rc = LDAP_UNAVAILABLE; 835 break; 836 case SASL_DISABLED: 837 rc = LDAP_UNWILLING_TO_PERFORM; 838 break; 839 default: 840 rc = LDAP_OTHER; 841 break; 842 } 843 844 return rc; 845} 846 847#ifdef SLAPD_SPASSWD 848 849static struct berval sasl_pwscheme = BER_BVC("{SASL}"); 850 851static int chk_sasl( 852 const struct berval *sc, 853 const struct berval * passwd, 854 const struct berval * cred, 855 const char **text ) 856{ 857 unsigned int i; 858 int rtn; 859 void *ctx, *sconn = NULL; 860 861 for( i=0; i<cred->bv_len; i++) { 862 if(cred->bv_val[i] == '\0') { 863 return LUTIL_PASSWD_ERR; /* NUL character in password */ 864 } 865 } 866 867 if( cred->bv_val[i] != '\0' ) { 868 return LUTIL_PASSWD_ERR; /* cred must behave like a string */ 869 } 870 871 for( i=0; i<passwd->bv_len; i++) { 872 if(passwd->bv_val[i] == '\0') { 873 return LUTIL_PASSWD_ERR; /* NUL character in password */ 874 } 875 } 876 877 if( passwd->bv_val[i] != '\0' ) { 878 return LUTIL_PASSWD_ERR; /* passwd must behave like a string */ 879 } 880 881 rtn = LUTIL_PASSWD_ERR; 882 883 ctx = ldap_pvt_thread_pool_context(); 884 ldap_pvt_thread_pool_getkey( ctx, (void *)slap_sasl_bind, &sconn, NULL ); 885 886 if( sconn != NULL ) { 887 int sc; 888 sc = sasl_checkpass( sconn, 889 passwd->bv_val, passwd->bv_len, 890 cred->bv_val, cred->bv_len ); 891 rtn = ( sc != SASL_OK ) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; 892 } 893 894 return rtn; 895} 896#endif /* SLAPD_SPASSWD */ 897 898#endif /* HAVE_CYRUS_SASL */ 899 900#ifdef ENABLE_REWRITE 901 902typedef struct slapd_map_data { 903 struct berval base; 904 struct berval filter; 905 AttributeName attrs[2]; 906 int scope; 907} slapd_map_data; 908 909static void * 910slapd_rw_config( const char *fname, int lineno, int argc, char **argv ) 911{ 912 slapd_map_data *ret = NULL; 913 LDAPURLDesc *lud = NULL; 914 char *uri; 915 AttributeDescription *ad = NULL; 916 int rc, flen = 0; 917 struct berval dn, ndn; 918 919 if ( argc != 1 ) { 920 Debug( LDAP_DEBUG_ANY, 921 "[%s:%d] slapd map needs URI\n", 922 fname, lineno, 0 ); 923 return NULL; 924 } 925 926 uri = argv[0]; 927 if ( strncasecmp( uri, "uri=", STRLENOF( "uri=" ) ) == 0 ) { 928 uri += STRLENOF( "uri=" ); 929 } 930 931 if ( ldap_url_parse( uri, &lud ) != LDAP_URL_SUCCESS ) { 932 Debug( LDAP_DEBUG_ANY, 933 "[%s:%d] illegal URI '%s'\n", 934 fname, lineno, uri ); 935 return NULL; 936 } 937 938 if ( strcasecmp( lud->lud_scheme, "ldap" )) { 939 Debug( LDAP_DEBUG_ANY, 940 "[%s:%d] illegal URI scheme '%s'\n", 941 fname, lineno, lud->lud_scheme ); 942 goto done; 943 } 944 945 if (( lud->lud_host && lud->lud_host[0] ) || lud->lud_exts 946 || !lud->lud_dn ) { 947 Debug( LDAP_DEBUG_ANY, 948 "[%s:%d] illegal URI '%s'\n", 949 fname, lineno, uri ); 950 goto done; 951 } 952 953 if ( lud->lud_attrs ) { 954 if ( lud->lud_attrs[1] ) { 955 Debug( LDAP_DEBUG_ANY, 956 "[%s:%d] only one attribute allowed in URI\n", 957 fname, lineno, 0 ); 958 goto done; 959 } 960 if ( strcasecmp( lud->lud_attrs[0], "dn" ) && 961 strcasecmp( lud->lud_attrs[0], "entryDN" )) { 962 const char *text; 963 rc = slap_str2ad( lud->lud_attrs[0], &ad, &text ); 964 if ( rc ) 965 goto done; 966 } 967 } 968 ber_str2bv( lud->lud_dn, 0, 0, &dn ); 969 if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL )) 970 goto done; 971 972 if ( lud->lud_filter ) { 973 flen = strlen( lud->lud_filter ) + 1; 974 } 975 ret = ch_malloc( sizeof( slapd_map_data ) + flen ); 976 ret->base = ndn; 977 if ( flen ) { 978 ret->filter.bv_val = (char *)(ret+1); 979 ret->filter.bv_len = flen - 1; 980 strcpy( ret->filter.bv_val, lud->lud_filter ); 981 } else { 982 BER_BVZERO( &ret->filter ); 983 } 984 ret->scope = lud->lud_scope; 985 if ( ad ) { 986 ret->attrs[0].an_name = ad->ad_cname; 987 } else { 988 BER_BVZERO( &ret->attrs[0].an_name ); 989 } 990 ret->attrs[0].an_desc = ad; 991 BER_BVZERO( &ret->attrs[1].an_name ); 992done: 993 ldap_free_urldesc( lud ); 994 return ret; 995} 996 997struct slapd_rw_info { 998 slapd_map_data *si_data; 999 struct berval si_val; 1000}; 1001 1002static int 1003slapd_rw_cb( Operation *op, SlapReply *rs ) 1004{ 1005 if ( rs->sr_type == REP_SEARCH ) { 1006 struct slapd_rw_info *si = op->o_callback->sc_private; 1007 1008 if ( si->si_data->attrs[0].an_desc ) { 1009 Attribute *a; 1010 1011 a = attr_find( rs->sr_entry->e_attrs, 1012 si->si_data->attrs[0].an_desc ); 1013 if ( a ) { 1014 ber_dupbv( &si->si_val, a->a_vals ); 1015 } 1016 } else { 1017 ber_dupbv( &si->si_val, &rs->sr_entry->e_name ); 1018 } 1019 } 1020 return LDAP_SUCCESS; 1021} 1022 1023static int 1024slapd_rw_apply( void *private, const char *filter, struct berval *val ) 1025{ 1026 slapd_map_data *sl = private; 1027 slap_callback cb = { NULL }; 1028 Connection conn = {0}; 1029 OperationBuffer opbuf; 1030 Operation *op; 1031 void *thrctx; 1032 SlapReply rs = {REP_RESULT}; 1033 struct slapd_rw_info si; 1034 char *ptr; 1035 int rc; 1036 1037 thrctx = ldap_pvt_thread_pool_context(); 1038 connection_fake_init2( &conn, &opbuf, thrctx, 0 ); 1039 op = &opbuf.ob_op; 1040 1041 op->o_tag = LDAP_REQ_SEARCH; 1042 op->o_req_dn = op->o_req_ndn = sl->base; 1043 op->o_bd = select_backend( &op->o_req_ndn, 1 ); 1044 if ( !op->o_bd ) { 1045 return REWRITE_ERR; 1046 } 1047 si.si_data = sl; 1048 BER_BVZERO( &si.si_val ); 1049 op->ors_scope = sl->scope; 1050 op->ors_deref = LDAP_DEREF_NEVER; 1051 op->ors_slimit = 1; 1052 op->ors_tlimit = SLAP_NO_LIMIT; 1053 if ( sl->attrs[0].an_desc ) { 1054 op->ors_attrs = sl->attrs; 1055 } else { 1056 op->ors_attrs = slap_anlist_no_attrs; 1057 } 1058 if ( filter ) { 1059 rc = strlen( filter ); 1060 } else { 1061 rc = 0; 1062 } 1063 rc += sl->filter.bv_len; 1064 ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( rc + 1, op->o_tmpmemctx ); 1065 if ( sl->filter.bv_len ) { 1066 ptr = lutil_strcopy( ptr, sl->filter.bv_val ); 1067 } else { 1068 *ptr = '\0'; 1069 } 1070 if ( filter ) { 1071 strcpy( ptr, filter ); 1072 } 1073 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val ); 1074 if ( !op->ors_filter ) { 1075 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 1076 return REWRITE_ERR; 1077 } 1078 1079 op->ors_attrsonly = 0; 1080 op->o_dn = op->o_bd->be_rootdn; 1081 op->o_ndn = op->o_bd->be_rootndn; 1082 op->o_do_not_cache = 1; 1083 1084 cb.sc_response = slapd_rw_cb; 1085 cb.sc_private = &si; 1086 op->o_callback = &cb; 1087 1088 rc = op->o_bd->be_search( op, &rs ); 1089 if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &si.si_val )) { 1090 *val = si.si_val; 1091 rc = REWRITE_SUCCESS; 1092 } else { 1093 if ( !BER_BVISNULL( &si.si_val )) { 1094 ch_free( si.si_val.bv_val ); 1095 } 1096 rc = REWRITE_ERR; 1097 } 1098 filter_free_x( op, op->ors_filter, 1 ); 1099 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 1100 return rc; 1101} 1102 1103static int 1104slapd_rw_destroy( void *private ) 1105{ 1106 slapd_map_data *md = private; 1107 1108 assert( private != NULL ); 1109 1110 ch_free( md->base.bv_val ); 1111 ch_free( md ); 1112 1113 return 0; 1114} 1115 1116static const rewrite_mapper slapd_mapper = { 1117 "slapd", 1118 slapd_rw_config, 1119 slapd_rw_apply, 1120 slapd_rw_destroy 1121}; 1122#endif 1123 1124int slap_sasl_init( void ) 1125{ 1126#ifdef HAVE_CYRUS_SASL 1127 int rc; 1128 static sasl_callback_t server_callbacks[] = { 1129 { SASL_CB_LOG, (slap_sasl_cb_ft)&slap_sasl_log, NULL }, 1130 { SASL_CB_GETOPT, (slap_sasl_cb_ft)&slap_sasl_getopt, NULL }, 1131 { SASL_CB_LIST_END, NULL, NULL } 1132 }; 1133#endif 1134 1135#ifdef ENABLE_REWRITE 1136 rewrite_mapper_register( &slapd_mapper ); 1137#endif 1138 1139#ifdef HAVE_CYRUS_SASL 1140#ifdef HAVE_SASL_VERSION 1141 /* stringify the version number, sasl.h doesn't do it for us */ 1142#define VSTR0(maj, min, pat) #maj "." #min "." #pat 1143#define VSTR(maj, min, pat) VSTR0(maj, min, pat) 1144#define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \ 1145 SASL_VERSION_STEP) 1146 1147 sasl_version( NULL, &rc ); 1148 if ( ((rc >> 16) != ((SASL_VERSION_MAJOR << 8)|SASL_VERSION_MINOR)) || 1149 (rc & 0xffff) < SASL_VERSION_STEP) 1150 { 1151 char version[sizeof("xxx.xxx.xxxxx")]; 1152 sprintf( version, "%u.%d.%d", (unsigned)rc >> 24, (rc >> 16) & 0xff, 1153 rc & 0xffff ); 1154 Debug( LDAP_DEBUG_ANY, "slap_sasl_init: SASL library version mismatch:" 1155 " expected %s, got %s\n", 1156 SASL_VERSION_STRING, version, 0 ); 1157 return -1; 1158 } 1159#endif 1160 1161 sasl_set_mutex( 1162 ldap_pvt_sasl_mutex_new, 1163 ldap_pvt_sasl_mutex_lock, 1164 ldap_pvt_sasl_mutex_unlock, 1165 ldap_pvt_sasl_mutex_dispose ); 1166 1167 generic_filter.f_desc = slap_schema.si_ad_objectClass; 1168 1169 rc = sasl_auxprop_add_plugin( "slapd", slap_auxprop_init ); 1170 if( rc != SASL_OK ) { 1171 Debug( LDAP_DEBUG_ANY, "slap_sasl_init: auxprop add plugin failed\n", 1172 0, 0, 0 ); 1173 return -1; 1174 } 1175 1176 /* should provide callbacks for logging */ 1177 /* server name should be configurable */ 1178 rc = sasl_server_init( server_callbacks, "slapd" ); 1179 1180 if( rc != SASL_OK ) { 1181 Debug( LDAP_DEBUG_ANY, "slap_sasl_init: server init failed\n", 1182 0, 0, 0 ); 1183 1184 return -1; 1185 } 1186 1187#ifdef SLAPD_SPASSWD 1188 lutil_passwd_add( &sasl_pwscheme, chk_sasl, NULL ); 1189#endif 1190 1191 Debug( LDAP_DEBUG_TRACE, "slap_sasl_init: initialized!\n", 1192 0, 0, 0 ); 1193 1194 /* default security properties */ 1195 memset( &sasl_secprops, '\0', sizeof(sasl_secprops) ); 1196 sasl_secprops.max_ssf = INT_MAX; 1197 sasl_secprops.maxbufsize = 65536; 1198 sasl_secprops.security_flags = SASL_SEC_NOPLAINTEXT|SASL_SEC_NOANONYMOUS; 1199#endif 1200 1201 return 0; 1202} 1203 1204int slap_sasl_destroy( void ) 1205{ 1206#ifdef HAVE_CYRUS_SASL 1207 sasl_done(); 1208#endif 1209 free( sasl_host ); 1210 sasl_host = NULL; 1211 1212 return 0; 1213} 1214 1215static char * 1216slap_sasl_peer2ipport( struct berval *peer ) 1217{ 1218 int isv6 = 0; 1219 char *ipport, *p, 1220 *addr = &peer->bv_val[ STRLENOF( "IP=" ) ]; 1221 ber_len_t plen = peer->bv_len - STRLENOF( "IP=" ); 1222 1223 /* IPv6? */ 1224 if ( addr[0] == '[' ) { 1225 isv6 = 1; 1226 plen--; 1227 } 1228 ipport = ch_strdup( &addr[isv6] ); 1229 1230 /* Convert IPv6/IPv4 addresses to address;port syntax. */ 1231 p = strrchr( ipport, ':' ); 1232 if ( p != NULL ) { 1233 *p = ';'; 1234 if ( isv6 ) { 1235 assert( p[-1] == ']' ); 1236 AC_MEMCPY( &p[-1], p, plen - ( p - ipport ) + 1 ); 1237 } 1238 1239 } else if ( isv6 ) { 1240 /* trim ']' */ 1241 plen--; 1242 assert( addr[plen] == ']' ); 1243 addr[plen] = '\0'; 1244 } 1245 1246 return ipport; 1247} 1248 1249int slap_sasl_open( Connection *conn, int reopen ) 1250{ 1251 int sc = LDAP_SUCCESS; 1252#ifdef HAVE_CYRUS_SASL 1253 int cb; 1254 1255 sasl_conn_t *ctx = NULL; 1256 sasl_callback_t *session_callbacks; 1257 char *ipremoteport = NULL, *iplocalport = NULL; 1258 1259 assert( conn->c_sasl_authctx == NULL ); 1260 1261 if ( !reopen ) { 1262 assert( conn->c_sasl_extra == NULL ); 1263 1264 session_callbacks = 1265 SLAP_CALLOC( 5, sizeof(sasl_callback_t)); 1266 if( session_callbacks == NULL ) { 1267 Debug( LDAP_DEBUG_ANY, 1268 "slap_sasl_open: SLAP_MALLOC failed", 0, 0, 0 ); 1269 return -1; 1270 } 1271 conn->c_sasl_extra = session_callbacks; 1272 1273 session_callbacks[cb=0].id = SASL_CB_LOG; 1274 session_callbacks[cb].proc = (slap_sasl_cb_ft)&slap_sasl_log; 1275 session_callbacks[cb++].context = conn; 1276 1277 session_callbacks[cb].id = SASL_CB_PROXY_POLICY; 1278 session_callbacks[cb].proc = (slap_sasl_cb_ft)&slap_sasl_authorize; 1279 session_callbacks[cb++].context = conn; 1280 1281 session_callbacks[cb].id = SASL_CB_CANON_USER; 1282 session_callbacks[cb].proc = (slap_sasl_cb_ft)&slap_sasl_canonicalize; 1283 session_callbacks[cb++].context = conn; 1284 1285 session_callbacks[cb].id = SASL_CB_LIST_END; 1286 session_callbacks[cb].proc = NULL; 1287 session_callbacks[cb++].context = NULL; 1288 } else { 1289 session_callbacks = conn->c_sasl_extra; 1290 } 1291 1292 conn->c_sasl_layers = 0; 1293 1294 /* create new SASL context */ 1295 if ( conn->c_sock_name.bv_len != 0 && 1296 strncmp( conn->c_sock_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 ) 1297 { 1298 iplocalport = slap_sasl_peer2ipport( &conn->c_sock_name ); 1299 } 1300 1301 if ( conn->c_peer_name.bv_len != 0 && 1302 strncmp( conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 ) 1303 { 1304 ipremoteport = slap_sasl_peer2ipport( &conn->c_peer_name ); 1305 } 1306 1307 sc = sasl_server_new( "ldap", sasl_host, global_realm, 1308 iplocalport, ipremoteport, session_callbacks, SASL_SUCCESS_DATA, &ctx ); 1309 if ( iplocalport != NULL ) { 1310 ch_free( iplocalport ); 1311 } 1312 if ( ipremoteport != NULL ) { 1313 ch_free( ipremoteport ); 1314 } 1315 1316 if( sc != SASL_OK ) { 1317 Debug( LDAP_DEBUG_ANY, "sasl_server_new failed: %d\n", 1318 sc, 0, 0 ); 1319 1320 return -1; 1321 } 1322 1323 conn->c_sasl_authctx = ctx; 1324 1325 if( sc == SASL_OK ) { 1326 sc = sasl_setprop( ctx, 1327 SASL_SEC_PROPS, &sasl_secprops ); 1328 1329 if( sc != SASL_OK ) { 1330 Debug( LDAP_DEBUG_ANY, "sasl_setprop failed: %d\n", 1331 sc, 0, 0 ); 1332 1333 slap_sasl_close( conn ); 1334 return -1; 1335 } 1336 } 1337 1338 sc = slap_sasl_err2ldap( sc ); 1339 1340#elif defined(SLAP_BUILTIN_SASL) 1341 /* built-in SASL implementation */ 1342 SASL_CTX *ctx = (SASL_CTX *) SLAP_MALLOC(sizeof(SASL_CTX)); 1343 if( ctx == NULL ) return -1; 1344 1345 ctx->sc_external_ssf = 0; 1346 BER_BVZERO( &ctx->sc_external_id ); 1347 1348 conn->c_sasl_authctx = ctx; 1349#endif 1350 1351 return sc; 1352} 1353 1354int slap_sasl_external( 1355 Connection *conn, 1356 slap_ssf_t ssf, 1357 struct berval *auth_id ) 1358{ 1359#ifdef HAVE_CYRUS_SASL 1360 int sc; 1361 sasl_conn_t *ctx = conn->c_sasl_authctx; 1362 sasl_ssf_t sasl_ssf = ssf; 1363 1364 if ( ctx == NULL ) { 1365 return LDAP_UNAVAILABLE; 1366 } 1367 1368 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf ); 1369 1370 if ( sc != SASL_OK ) { 1371 return LDAP_OTHER; 1372 } 1373 1374 sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL, 1375 auth_id ? auth_id->bv_val : NULL ); 1376 1377 if ( sc != SASL_OK ) { 1378 return LDAP_OTHER; 1379 } 1380#elif defined(SLAP_BUILTIN_SASL) 1381 /* built-in SASL implementation */ 1382 SASL_CTX *ctx = conn->c_sasl_authctx; 1383 if ( ctx == NULL ) return LDAP_UNAVAILABLE; 1384 1385 ctx->sc_external_ssf = ssf; 1386 if( auth_id ) { 1387 ctx->sc_external_id = *auth_id; 1388 BER_BVZERO( auth_id ); 1389 } else { 1390 BER_BVZERO( &ctx->sc_external_id ); 1391 } 1392#endif 1393 1394 return LDAP_SUCCESS; 1395} 1396 1397int slap_sasl_reset( Connection *conn ) 1398{ 1399 return LDAP_SUCCESS; 1400} 1401 1402char ** slap_sasl_mechs( Connection *conn ) 1403{ 1404 char **mechs = NULL; 1405 1406#ifdef HAVE_CYRUS_SASL 1407 sasl_conn_t *ctx = conn->c_sasl_authctx; 1408 1409 if( ctx == NULL ) ctx = conn->c_sasl_sockctx; 1410 1411 if( ctx != NULL ) { 1412 int sc; 1413 SASL_CONST char *mechstr; 1414 1415 sc = sasl_listmech( ctx, 1416 NULL, NULL, ",", NULL, 1417 &mechstr, NULL, NULL ); 1418 1419 if( sc != SASL_OK ) { 1420 Debug( LDAP_DEBUG_ANY, "slap_sasl_listmech failed: %d\n", 1421 sc, 0, 0 ); 1422 1423 return NULL; 1424 } 1425 1426 mechs = ldap_str2charray( mechstr, "," ); 1427 } 1428#elif defined(SLAP_BUILTIN_SASL) 1429 /* builtin SASL implementation */ 1430 SASL_CTX *ctx = conn->c_sasl_authctx; 1431 if ( ctx != NULL && ctx->sc_external_id.bv_val ) { 1432 /* should check ssf */ 1433 mechs = ldap_str2charray( "EXTERNAL", "," ); 1434 } 1435#endif 1436 1437 return mechs; 1438} 1439 1440int slap_sasl_close( Connection *conn ) 1441{ 1442#ifdef HAVE_CYRUS_SASL 1443 sasl_conn_t *ctx = conn->c_sasl_authctx; 1444 1445 if( ctx != NULL ) { 1446 sasl_dispose( &ctx ); 1447 } 1448 if ( conn->c_sasl_sockctx && 1449 conn->c_sasl_authctx != conn->c_sasl_sockctx ) 1450 { 1451 ctx = conn->c_sasl_sockctx; 1452 sasl_dispose( &ctx ); 1453 } 1454 1455 conn->c_sasl_authctx = NULL; 1456 conn->c_sasl_sockctx = NULL; 1457 conn->c_sasl_done = 0; 1458 1459 free( conn->c_sasl_extra ); 1460 conn->c_sasl_extra = NULL; 1461 1462#elif defined(SLAP_BUILTIN_SASL) 1463 SASL_CTX *ctx = conn->c_sasl_authctx; 1464 if( ctx ) { 1465 if( ctx->sc_external_id.bv_val ) { 1466 free( ctx->sc_external_id.bv_val ); 1467 BER_BVZERO( &ctx->sc_external_id ); 1468 } 1469 free( ctx ); 1470 conn->c_sasl_authctx = NULL; 1471 } 1472#endif 1473 1474 return LDAP_SUCCESS; 1475} 1476 1477int slap_sasl_bind( Operation *op, SlapReply *rs ) 1478{ 1479#ifdef HAVE_CYRUS_SASL 1480 sasl_conn_t *ctx = op->o_conn->c_sasl_authctx; 1481 struct berval response; 1482 unsigned reslen = 0; 1483 int sc; 1484 1485 Debug(LDAP_DEBUG_ARGS, 1486 "==> sasl_bind: dn=\"%s\" mech=%s datalen=%ld\n", 1487 op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", 1488 op->o_conn->c_sasl_bind_in_progress ? "<continuing>" : 1489 op->o_conn->c_sasl_bind_mech.bv_val, 1490 op->orb_cred.bv_len ); 1491 1492 if( ctx == NULL ) { 1493 send_ldap_error( op, rs, LDAP_UNAVAILABLE, 1494 "SASL unavailable on this session" ); 1495 return rs->sr_err; 1496 } 1497 1498#define START( ctx, mech, cred, clen, resp, rlen, err ) \ 1499 sasl_server_start( ctx, mech, cred, clen, resp, rlen ) 1500#define STEP( ctx, cred, clen, resp, rlen, err ) \ 1501 sasl_server_step( ctx, cred, clen, resp, rlen ) 1502 1503 if ( !op->o_conn->c_sasl_bind_in_progress ) { 1504 /* If we already authenticated once, must use a new context */ 1505 if ( op->o_conn->c_sasl_done ) { 1506 sasl_ssf_t *ssf = NULL; 1507 const char *authid = NULL; 1508 sasl_getprop( ctx, SASL_SSF_EXTERNAL, (void *)&ssf ); 1509 sasl_getprop( ctx, SASL_AUTH_EXTERNAL, (void *)&authid ); 1510 if ( authid ) authid = ch_strdup( authid ); 1511 if ( ctx != op->o_conn->c_sasl_sockctx ) { 1512 sasl_dispose( &ctx ); 1513 } 1514 op->o_conn->c_sasl_authctx = NULL; 1515 1516 slap_sasl_open( op->o_conn, 1 ); 1517 ctx = op->o_conn->c_sasl_authctx; 1518 if ( authid ) { 1519 sasl_setprop( ctx, SASL_SSF_EXTERNAL, ssf ); 1520 sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid ); 1521 ch_free( (char *)authid ); 1522 } 1523 } 1524 sc = START( ctx, 1525 op->o_conn->c_sasl_bind_mech.bv_val, 1526 op->orb_cred.bv_val, op->orb_cred.bv_len, 1527 (SASL_CONST char **)&response.bv_val, &reslen, &rs->sr_text ); 1528 1529 } else { 1530 sc = STEP( ctx, 1531 op->orb_cred.bv_val, op->orb_cred.bv_len, 1532 (SASL_CONST char **)&response.bv_val, &reslen, &rs->sr_text ); 1533 } 1534 1535 response.bv_len = reslen; 1536 1537 if ( sc == SASL_OK ) { 1538 sasl_ssf_t *ssf = NULL; 1539 1540 ber_dupbv_x( &op->orb_edn, &op->o_conn->c_sasl_dn, op->o_tmpmemctx ); 1541 BER_BVZERO( &op->o_conn->c_sasl_dn ); 1542 op->o_conn->c_sasl_done = 1; 1543 1544 rs->sr_err = LDAP_SUCCESS; 1545 1546 (void) sasl_getprop( ctx, SASL_SSF, (void *)&ssf ); 1547 op->orb_ssf = ssf ? *ssf : 0; 1548 1549 ctx = NULL; 1550 if( op->orb_ssf ) { 1551 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 1552 op->o_conn->c_sasl_layers++; 1553 1554 /* If there's an old layer, set sockctx to NULL to 1555 * tell connection_read() to wait for us to finish. 1556 * Otherwise there is a race condition: we have to 1557 * send the Bind response using the old security 1558 * context and then remove it before reading any 1559 * new messages. 1560 */ 1561 if ( op->o_conn->c_sasl_sockctx ) { 1562 ctx = op->o_conn->c_sasl_sockctx; 1563 op->o_conn->c_sasl_sockctx = NULL; 1564 } else { 1565 op->o_conn->c_sasl_sockctx = op->o_conn->c_sasl_authctx; 1566 } 1567 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 1568 } 1569 1570 /* Must send response using old security layer */ 1571 rs->sr_sasldata = (response.bv_len ? &response : NULL); 1572 send_ldap_sasl( op, rs ); 1573 1574 /* Now dispose of the old security layer. 1575 */ 1576 if ( ctx ) { 1577 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 1578 ldap_pvt_sasl_remove( op->o_conn->c_sb ); 1579 op->o_conn->c_sasl_sockctx = op->o_conn->c_sasl_authctx; 1580 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 1581 sasl_dispose( &ctx ); 1582 } 1583 } else if ( sc == SASL_CONTINUE ) { 1584 rs->sr_err = LDAP_SASL_BIND_IN_PROGRESS, 1585 rs->sr_text = sasl_errdetail( ctx ); 1586 rs->sr_sasldata = &response; 1587 send_ldap_sasl( op, rs ); 1588 1589 } else { 1590 BER_BVZERO( &op->o_conn->c_sasl_dn ); 1591 rs->sr_text = sasl_errdetail( ctx ); 1592 rs->sr_err = slap_sasl_err2ldap( sc ), 1593 send_ldap_result( op, rs ); 1594 } 1595 1596 Debug(LDAP_DEBUG_TRACE, "<== slap_sasl_bind: rc=%d\n", rs->sr_err, 0, 0); 1597 1598#elif defined(SLAP_BUILTIN_SASL) 1599 /* built-in SASL implementation */ 1600 SASL_CTX *ctx = op->o_conn->c_sasl_authctx; 1601 1602 if ( ctx == NULL ) { 1603 send_ldap_error( op, rs, LDAP_OTHER, 1604 "Internal SASL Error" ); 1605 1606 } else if ( bvmatch( &ext_bv, &op->o_conn->c_sasl_bind_mech ) ) { 1607 /* EXTERNAL */ 1608 1609 if( op->orb_cred.bv_len ) { 1610 rs->sr_text = "proxy authorization not supported"; 1611 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1612 send_ldap_result( op, rs ); 1613 1614 } else { 1615 op->orb_edn = ctx->sc_external_id; 1616 rs->sr_err = LDAP_SUCCESS; 1617 rs->sr_sasldata = NULL; 1618 send_ldap_sasl( op, rs ); 1619 } 1620 1621 } else { 1622 send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED, 1623 "requested SASL mechanism not supported" ); 1624 } 1625#else 1626 send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED, 1627 "SASL not supported" ); 1628#endif 1629 1630 return rs->sr_err; 1631} 1632 1633char* slap_sasl_secprops( const char *in ) 1634{ 1635#ifdef HAVE_CYRUS_SASL 1636 int rc = ldap_pvt_sasl_secprops( in, &sasl_secprops ); 1637 1638 return rc == LDAP_SUCCESS ? NULL : "Invalid security properties"; 1639#else 1640 return "SASL not supported"; 1641#endif 1642} 1643 1644void slap_sasl_secprops_unparse( struct berval *bv ) 1645{ 1646#ifdef HAVE_CYRUS_SASL 1647 ldap_pvt_sasl_secprops_unparse( &sasl_secprops, bv ); 1648#endif 1649} 1650 1651#ifdef HAVE_CYRUS_SASL 1652int 1653slap_sasl_setpass( Operation *op, SlapReply *rs ) 1654{ 1655 struct berval id = BER_BVNULL; /* needs to come from connection */ 1656 struct berval new = BER_BVNULL; 1657 struct berval old = BER_BVNULL; 1658 1659 assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 ); 1660 1661 rs->sr_err = sasl_getprop( op->o_conn->c_sasl_authctx, SASL_USERNAME, 1662 (SASL_CONST void **)(char *)&id.bv_val ); 1663 1664 if( rs->sr_err != SASL_OK ) { 1665 rs->sr_text = "unable to retrieve SASL username"; 1666 rs->sr_err = LDAP_OTHER; 1667 goto done; 1668 } 1669 1670 Debug( LDAP_DEBUG_ARGS, "==> slap_sasl_setpass: \"%s\"\n", 1671 id.bv_val ? id.bv_val : "", 0, 0 ); 1672 1673 rs->sr_err = slap_passwd_parse( op->ore_reqdata, 1674 NULL, &old, &new, &rs->sr_text ); 1675 1676 if( rs->sr_err != LDAP_SUCCESS ) { 1677 goto done; 1678 } 1679 1680 if( new.bv_len == 0 ) { 1681 slap_passwd_generate(&new); 1682 1683 if( new.bv_len == 0 ) { 1684 rs->sr_text = "password generation failed."; 1685 rs->sr_err = LDAP_OTHER; 1686 goto done; 1687 } 1688 1689 rs->sr_rspdata = slap_passwd_return( &new ); 1690 } 1691 1692 rs->sr_err = sasl_setpass( op->o_conn->c_sasl_authctx, id.bv_val, 1693 new.bv_val, new.bv_len, old.bv_val, old.bv_len, 0 ); 1694 if( rs->sr_err != SASL_OK ) { 1695 rs->sr_text = sasl_errdetail( op->o_conn->c_sasl_authctx ); 1696 } 1697 switch(rs->sr_err) { 1698 case SASL_OK: 1699 rs->sr_err = LDAP_SUCCESS; 1700 break; 1701 1702 case SASL_NOCHANGE: 1703 case SASL_NOMECH: 1704 case SASL_DISABLED: 1705 case SASL_PWLOCK: 1706 case SASL_FAIL: 1707 case SASL_BADPARAM: 1708 default: 1709 rs->sr_err = LDAP_OTHER; 1710 } 1711 1712done: 1713 return rs->sr_err; 1714} 1715#endif /* HAVE_CYRUS_SASL */ 1716 1717/* Take any sort of identity string and return a DN with the "dn:" prefix. The 1718 * string returned in *dn is in its own allocated memory, and must be free'd 1719 * by the calling process. -Mark Adamson, Carnegie Mellon 1720 * 1721 * The "dn:" prefix is no longer used anywhere inside slapd. It is only used 1722 * on strings passed in directly from SASL. -Howard Chu, Symas Corp. 1723 */ 1724 1725#define SET_NONE 0 1726#define SET_DN 1 1727#define SET_U 2 1728 1729int slap_sasl_getdn( Connection *conn, Operation *op, struct berval *id, 1730 char *user_realm, struct berval *dn, int flags ) 1731{ 1732 int rc, is_dn = SET_NONE, do_norm = 1; 1733 struct berval dn2, *mech; 1734 1735 assert( conn != NULL ); 1736 assert( id != NULL ); 1737 1738 Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: conn %lu id=%s [len=%lu]\n", 1739 conn->c_connid, 1740 BER_BVISNULL( id ) ? "NULL" : ( BER_BVISEMPTY( id ) ? "<empty>" : id->bv_val ), 1741 BER_BVISNULL( id ) ? 0 : ( BER_BVISEMPTY( id ) ? 0 : 1742 (unsigned long) id->bv_len ) ); 1743 1744 if ( !op ) { 1745 op = conn->c_sasl_bindop; 1746 } 1747 assert( op != NULL ); 1748 1749 BER_BVZERO( dn ); 1750 1751 if ( !BER_BVISNULL( id ) ) { 1752 /* Blatantly anonymous ID */ 1753 static struct berval bv_anonymous = BER_BVC( "anonymous" ); 1754 1755 if ( ber_bvstrcasecmp( id, &bv_anonymous ) == 0 ) { 1756 return( LDAP_SUCCESS ); 1757 } 1758 1759 } else { 1760 /* FIXME: if empty, should we stop? */ 1761 BER_BVSTR( id, "" ); 1762 } 1763 1764 if ( !BER_BVISEMPTY( &conn->c_sasl_bind_mech ) ) { 1765 mech = &conn->c_sasl_bind_mech; 1766 } else { 1767 mech = &conn->c_authmech; 1768 } 1769 1770 /* An authcID needs to be converted to authzID form. Set the 1771 * values directly into *dn; they will be normalized later. (and 1772 * normalizing always makes a new copy.) An ID from a TLS certificate 1773 * is already normalized, so copy it and skip normalization. 1774 */ 1775 if( flags & SLAP_GETDN_AUTHCID ) { 1776 if( bvmatch( mech, &ext_bv )) { 1777 /* EXTERNAL DNs are already normalized */ 1778 assert( !BER_BVISNULL( id ) ); 1779 1780 do_norm = 0; 1781 is_dn = SET_DN; 1782 ber_dupbv_x( dn, id, op->o_tmpmemctx ); 1783 1784 } else { 1785 /* convert to u:<username> form */ 1786 is_dn = SET_U; 1787 *dn = *id; 1788 } 1789 } 1790 1791 if( is_dn == SET_NONE ) { 1792 if( !strncasecmp( id->bv_val, "u:", STRLENOF( "u:" ) ) ) { 1793 is_dn = SET_U; 1794 dn->bv_val = id->bv_val + STRLENOF( "u:" ); 1795 dn->bv_len = id->bv_len - STRLENOF( "u:" ); 1796 1797 } else if ( !strncasecmp( id->bv_val, "dn:", STRLENOF( "dn:" ) ) ) { 1798 is_dn = SET_DN; 1799 dn->bv_val = id->bv_val + STRLENOF( "dn:" ); 1800 dn->bv_len = id->bv_len - STRLENOF( "dn:" ); 1801 } 1802 } 1803 1804 /* No other possibilities from here */ 1805 if( is_dn == SET_NONE ) { 1806 BER_BVZERO( dn ); 1807 return( LDAP_INAPPROPRIATE_AUTH ); 1808 } 1809 1810 /* Username strings */ 1811 if( is_dn == SET_U ) { 1812 /* ITS#3419: values may need escape */ 1813 LDAPRDN DN[ 5 ]; 1814 LDAPAVA *RDNs[ 4 ][ 2 ]; 1815 LDAPAVA AVAs[ 4 ]; 1816 int irdn; 1817 1818 irdn = 0; 1819 DN[ irdn ] = RDNs[ irdn ]; 1820 RDNs[ irdn ][ 0 ] = &AVAs[ irdn ]; 1821 AVAs[ irdn ].la_attr = slap_schema.si_ad_uid->ad_cname; 1822 AVAs[ irdn ].la_value = *dn; 1823 AVAs[ irdn ].la_flags = LDAP_AVA_NULL; 1824 AVAs[ irdn ].la_private = NULL; 1825 RDNs[ irdn ][ 1 ] = NULL; 1826 1827 if ( user_realm && *user_realm ) { 1828 irdn++; 1829 DN[ irdn ] = RDNs[ irdn ]; 1830 RDNs[ irdn ][ 0 ] = &AVAs[ irdn ]; 1831 AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname; 1832 ber_str2bv( user_realm, 0, 0, &AVAs[ irdn ].la_value ); 1833 AVAs[ irdn ].la_flags = LDAP_AVA_NULL; 1834 AVAs[ irdn ].la_private = NULL; 1835 RDNs[ irdn ][ 1 ] = NULL; 1836 } 1837 1838 if ( !BER_BVISNULL( mech ) ) { 1839 irdn++; 1840 DN[ irdn ] = RDNs[ irdn ]; 1841 RDNs[ irdn ][ 0 ] = &AVAs[ irdn ]; 1842 AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname; 1843 AVAs[ irdn ].la_value = *mech; 1844 AVAs[ irdn ].la_flags = LDAP_AVA_NULL; 1845 AVAs[ irdn ].la_private = NULL; 1846 RDNs[ irdn ][ 1 ] = NULL; 1847 } 1848 1849 irdn++; 1850 DN[ irdn ] = RDNs[ irdn ]; 1851 RDNs[ irdn ][ 0 ] = &AVAs[ irdn ]; 1852 AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname; 1853 BER_BVSTR( &AVAs[ irdn ].la_value, "auth" ); 1854 AVAs[ irdn ].la_flags = LDAP_AVA_NULL; 1855 AVAs[ irdn ].la_private = NULL; 1856 RDNs[ irdn ][ 1 ] = NULL; 1857 1858 irdn++; 1859 DN[ irdn ] = NULL; 1860 1861 rc = ldap_dn2bv_x( DN, dn, LDAP_DN_FORMAT_LDAPV3, 1862 op->o_tmpmemctx ); 1863 if ( rc != LDAP_SUCCESS ) { 1864 BER_BVZERO( dn ); 1865 return rc; 1866 } 1867 1868 Debug( LDAP_DEBUG_TRACE, 1869 "slap_sasl_getdn: u:id converted to %s\n", 1870 dn->bv_val, 0, 0 ); 1871 1872 } else { 1873 1874 /* Dup the DN in any case, so we don't risk 1875 * leaks or dangling pointers later, 1876 * and the DN value is '\0' terminated */ 1877 ber_dupbv_x( &dn2, dn, op->o_tmpmemctx ); 1878 dn->bv_val = dn2.bv_val; 1879 } 1880 1881 /* All strings are in DN form now. Normalize if needed. */ 1882 if ( do_norm ) { 1883 rc = dnNormalize( 0, NULL, NULL, dn, &dn2, op->o_tmpmemctx ); 1884 1885 /* User DNs were constructed above and must be freed now */ 1886 slap_sl_free( dn->bv_val, op->o_tmpmemctx ); 1887 1888 if ( rc != LDAP_SUCCESS ) { 1889 BER_BVZERO( dn ); 1890 return rc; 1891 } 1892 *dn = dn2; 1893 } 1894 1895 /* Run thru regexp */ 1896 slap_sasl2dn( op, dn, &dn2, flags ); 1897 if( !BER_BVISNULL( &dn2 ) ) { 1898 slap_sl_free( dn->bv_val, op->o_tmpmemctx ); 1899 *dn = dn2; 1900 Debug( LDAP_DEBUG_TRACE, 1901 "slap_sasl_getdn: dn:id converted to %s\n", 1902 dn->bv_val, 0, 0 ); 1903 } 1904 1905 return( LDAP_SUCCESS ); 1906} 1907