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