1/* $NetBSD$ */ 2 3/* OpenLDAP: pkg/ldap/servers/slapd/sasl.c,v 1.239.2.23 2010/04/15 18:41:32 quanah Exp */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2010 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 51static sasl_security_properties_t sasl_secprops; 52#elif defined( SLAP_BUILTIN_SASL ) 53/* 54 * built-in SASL implementation 55 * only supports EXTERNAL 56 */ 57typedef 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 66static struct berval ext_bv = BER_BVC( "EXTERNAL" ); 67 68char *slap_sasl_auxprops; 69 70#ifdef HAVE_CYRUS_SASL 71 72/* Just use our internal auxprop by default */ 73static int 74slap_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 91int 92slap_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 150static const char *slap_propnames[] = { 151 "*slapConn", "*slapAuthcDNlen", "*slapAuthcDN", 152 "*slapAuthzDNlen", "*slapAuthzDN", NULL }; 153 154static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL }; 155static 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 164typedef struct lookup_info { 165 int flags; 166 const struct propval *list; 167 sasl_server_params_t *sparams; 168} lookup_info; 169 170static slap_response sasl_ap_lookup; 171 172static struct berval sc_cleartext = BER_BVC("{CLEARTEXT}"); 173 174static int 175sasl_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 264static int 265#else 266static void 267#endif 268slap_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 423static int 424slap_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 531static 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 546static int 547slap_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 */ 569static int 570slap_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 681done: 682 AC_MEMCPY( out, in, inlen ); 683 out[inlen] = '\0'; 684 685 *out_len = inlen; 686 687 return SASL_OK; 688} 689 690static int 691slap_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 757ok: 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 772static int 773slap_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 833static struct berval sasl_pwscheme = BER_BVC("{SASL}"); 834 835static 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 886typedef struct slapd_map_data { 887 struct berval base; 888 struct berval filter; 889 AttributeName attrs[2]; 890 int scope; 891} slapd_map_data; 892 893static void * 894slapd_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 ); 976done: 977 ldap_free_urldesc( lud ); 978 return ret; 979} 980 981struct slapd_rw_info { 982 slapd_map_data *si_data; 983 struct berval si_val; 984}; 985 986static int 987slapd_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 1007static int 1008slapd_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 1087static int 1088slapd_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->filter.bv_val ); 1096 ch_free( md ); 1097 1098 return 0; 1099} 1100 1101static const rewrite_mapper slapd_mapper = { 1102 "slapd", 1103 slapd_rw_config, 1104 slapd_rw_apply, 1105 slapd_rw_destroy 1106}; 1107#endif 1108 1109int slap_sasl_init( void ) 1110{ 1111#ifdef HAVE_CYRUS_SASL 1112 int rc; 1113 static sasl_callback_t server_callbacks[] = { 1114 { SASL_CB_LOG, &slap_sasl_log, NULL }, 1115 { SASL_CB_GETOPT, &slap_sasl_getopt, NULL }, 1116 { SASL_CB_LIST_END, NULL, NULL } 1117 }; 1118#endif 1119 1120#ifdef ENABLE_REWRITE 1121 rewrite_mapper_register( &slapd_mapper ); 1122#endif 1123 1124#ifdef HAVE_CYRUS_SASL 1125#ifdef HAVE_SASL_VERSION 1126 /* stringify the version number, sasl.h doesn't do it for us */ 1127#define VSTR0(maj, min, pat) #maj "." #min "." #pat 1128#define VSTR(maj, min, pat) VSTR0(maj, min, pat) 1129#define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \ 1130 SASL_VERSION_STEP) 1131 1132 sasl_version( NULL, &rc ); 1133 if ( ((rc >> 16) != ((SASL_VERSION_MAJOR << 8)|SASL_VERSION_MINOR)) || 1134 (rc & 0xffff) < SASL_VERSION_STEP) 1135 { 1136 char version[sizeof("xxx.xxx.xxxxx")]; 1137 sprintf( version, "%u.%d.%d", (unsigned)rc >> 24, (rc >> 16) & 0xff, 1138 rc & 0xffff ); 1139 Debug( LDAP_DEBUG_ANY, "slap_sasl_init: SASL library version mismatch:" 1140 " expected %s, got %s\n", 1141 SASL_VERSION_STRING, version, 0 ); 1142 return -1; 1143 } 1144#endif 1145 1146 sasl_set_mutex( 1147 ldap_pvt_sasl_mutex_new, 1148 ldap_pvt_sasl_mutex_lock, 1149 ldap_pvt_sasl_mutex_unlock, 1150 ldap_pvt_sasl_mutex_dispose ); 1151 1152 generic_filter.f_desc = slap_schema.si_ad_objectClass; 1153 1154 rc = sasl_auxprop_add_plugin( "slapd", slap_auxprop_init ); 1155 if( rc != SASL_OK ) { 1156 Debug( LDAP_DEBUG_ANY, "slap_sasl_init: auxprop add plugin failed\n", 1157 0, 0, 0 ); 1158 return -1; 1159 } 1160 1161 /* should provide callbacks for logging */ 1162 /* server name should be configurable */ 1163 rc = sasl_server_init( server_callbacks, "slapd" ); 1164 1165 if( rc != SASL_OK ) { 1166 Debug( LDAP_DEBUG_ANY, "slap_sasl_init: server init failed\n", 1167 0, 0, 0 ); 1168 1169 return -1; 1170 } 1171 1172#ifdef SLAPD_SPASSWD 1173 lutil_passwd_add( &sasl_pwscheme, chk_sasl, NULL ); 1174#endif 1175 1176 Debug( LDAP_DEBUG_TRACE, "slap_sasl_init: initialized!\n", 1177 0, 0, 0 ); 1178 1179 /* default security properties */ 1180 memset( &sasl_secprops, '\0', sizeof(sasl_secprops) ); 1181 sasl_secprops.max_ssf = INT_MAX; 1182 sasl_secprops.maxbufsize = 65536; 1183 sasl_secprops.security_flags = SASL_SEC_NOPLAINTEXT|SASL_SEC_NOANONYMOUS; 1184#endif 1185 1186 return 0; 1187} 1188 1189int slap_sasl_destroy( void ) 1190{ 1191#ifdef HAVE_CYRUS_SASL 1192 sasl_done(); 1193#endif 1194 free( sasl_host ); 1195 sasl_host = NULL; 1196 1197 return 0; 1198} 1199 1200static char * 1201slap_sasl_peer2ipport( struct berval *peer ) 1202{ 1203 int isv6 = 0; 1204 char *ipport, *p, 1205 *addr = &peer->bv_val[ STRLENOF( "IP=" ) ]; 1206 ber_len_t plen = peer->bv_len - STRLENOF( "IP=" ); 1207 1208 /* IPv6? */ 1209 if ( addr[0] == '[' ) { 1210 isv6 = 1; 1211 plen--; 1212 } 1213 ipport = ch_strdup( &addr[isv6] ); 1214 1215 /* Convert IPv6/IPv4 addresses to address;port syntax. */ 1216 p = strrchr( ipport, ':' ); 1217 if ( p != NULL ) { 1218 *p = ';'; 1219 if ( isv6 ) { 1220 assert( p[-1] == ']' ); 1221 AC_MEMCPY( &p[-1], p, plen - ( p - ipport ) + 1 ); 1222 } 1223 1224 } else if ( isv6 ) { 1225 /* trim ']' */ 1226 plen--; 1227 assert( addr[plen] == ']' ); 1228 addr[plen] = '\0'; 1229 } 1230 1231 return ipport; 1232} 1233 1234int slap_sasl_open( Connection *conn, int reopen ) 1235{ 1236 int sc = LDAP_SUCCESS; 1237#ifdef HAVE_CYRUS_SASL 1238 int cb; 1239 1240 sasl_conn_t *ctx = NULL; 1241 sasl_callback_t *session_callbacks; 1242 char *ipremoteport = NULL, *iplocalport = NULL; 1243 1244 assert( conn->c_sasl_authctx == NULL ); 1245 1246 if ( !reopen ) { 1247 assert( conn->c_sasl_extra == NULL ); 1248 1249 session_callbacks = 1250 SLAP_CALLOC( 5, sizeof(sasl_callback_t)); 1251 if( session_callbacks == NULL ) { 1252 Debug( LDAP_DEBUG_ANY, 1253 "slap_sasl_open: SLAP_MALLOC failed", 0, 0, 0 ); 1254 return -1; 1255 } 1256 conn->c_sasl_extra = session_callbacks; 1257 1258 session_callbacks[cb=0].id = SASL_CB_LOG; 1259 session_callbacks[cb].proc = &slap_sasl_log; 1260 session_callbacks[cb++].context = conn; 1261 1262 session_callbacks[cb].id = SASL_CB_PROXY_POLICY; 1263 session_callbacks[cb].proc = &slap_sasl_authorize; 1264 session_callbacks[cb++].context = conn; 1265 1266 session_callbacks[cb].id = SASL_CB_CANON_USER; 1267 session_callbacks[cb].proc = &slap_sasl_canonicalize; 1268 session_callbacks[cb++].context = conn; 1269 1270 session_callbacks[cb].id = SASL_CB_LIST_END; 1271 session_callbacks[cb].proc = NULL; 1272 session_callbacks[cb++].context = NULL; 1273 } else { 1274 session_callbacks = conn->c_sasl_extra; 1275 } 1276 1277 conn->c_sasl_layers = 0; 1278 1279 /* create new SASL context */ 1280 if ( conn->c_sock_name.bv_len != 0 && 1281 strncmp( conn->c_sock_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 ) 1282 { 1283 iplocalport = slap_sasl_peer2ipport( &conn->c_sock_name ); 1284 } 1285 1286 if ( conn->c_peer_name.bv_len != 0 && 1287 strncmp( conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 ) 1288 { 1289 ipremoteport = slap_sasl_peer2ipport( &conn->c_peer_name ); 1290 } 1291 1292 sc = sasl_server_new( "ldap", sasl_host, global_realm, 1293 iplocalport, ipremoteport, session_callbacks, SASL_SUCCESS_DATA, &ctx ); 1294 if ( iplocalport != NULL ) { 1295 ch_free( iplocalport ); 1296 } 1297 if ( ipremoteport != NULL ) { 1298 ch_free( ipremoteport ); 1299 } 1300 1301 if( sc != SASL_OK ) { 1302 Debug( LDAP_DEBUG_ANY, "sasl_server_new failed: %d\n", 1303 sc, 0, 0 ); 1304 1305 return -1; 1306 } 1307 1308 conn->c_sasl_authctx = ctx; 1309 1310 if( sc == SASL_OK ) { 1311 sc = sasl_setprop( ctx, 1312 SASL_SEC_PROPS, &sasl_secprops ); 1313 1314 if( sc != SASL_OK ) { 1315 Debug( LDAP_DEBUG_ANY, "sasl_setprop failed: %d\n", 1316 sc, 0, 0 ); 1317 1318 slap_sasl_close( conn ); 1319 return -1; 1320 } 1321 } 1322 1323 sc = slap_sasl_err2ldap( sc ); 1324 1325#elif defined(SLAP_BUILTIN_SASL) 1326 /* built-in SASL implementation */ 1327 SASL_CTX *ctx = (SASL_CTX *) SLAP_MALLOC(sizeof(SASL_CTX)); 1328 if( ctx == NULL ) return -1; 1329 1330 ctx->sc_external_ssf = 0; 1331 BER_BVZERO( &ctx->sc_external_id ); 1332 1333 conn->c_sasl_authctx = ctx; 1334#endif 1335 1336 return sc; 1337} 1338 1339int slap_sasl_external( 1340 Connection *conn, 1341 slap_ssf_t ssf, 1342 struct berval *auth_id ) 1343{ 1344#ifdef HAVE_CYRUS_SASL 1345 int sc; 1346 sasl_conn_t *ctx = conn->c_sasl_authctx; 1347 sasl_ssf_t sasl_ssf = ssf; 1348 1349 if ( ctx == NULL ) { 1350 return LDAP_UNAVAILABLE; 1351 } 1352 1353 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf ); 1354 1355 if ( sc != SASL_OK ) { 1356 return LDAP_OTHER; 1357 } 1358 1359 sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL, 1360 auth_id ? auth_id->bv_val : NULL ); 1361 1362 if ( sc != SASL_OK ) { 1363 return LDAP_OTHER; 1364 } 1365#elif defined(SLAP_BUILTIN_SASL) 1366 /* built-in SASL implementation */ 1367 SASL_CTX *ctx = conn->c_sasl_authctx; 1368 if ( ctx == NULL ) return LDAP_UNAVAILABLE; 1369 1370 ctx->sc_external_ssf = ssf; 1371 if( auth_id ) { 1372 ctx->sc_external_id = *auth_id; 1373 BER_BVZERO( auth_id ); 1374 } else { 1375 BER_BVZERO( &ctx->sc_external_id ); 1376 } 1377#endif 1378 1379 return LDAP_SUCCESS; 1380} 1381 1382int slap_sasl_reset( Connection *conn ) 1383{ 1384 return LDAP_SUCCESS; 1385} 1386 1387char ** slap_sasl_mechs( Connection *conn ) 1388{ 1389 char **mechs = NULL; 1390 1391#ifdef HAVE_CYRUS_SASL 1392 sasl_conn_t *ctx = conn->c_sasl_authctx; 1393 1394 if( ctx == NULL ) ctx = conn->c_sasl_sockctx; 1395 1396 if( ctx != NULL ) { 1397 int sc; 1398 SASL_CONST char *mechstr; 1399 1400 sc = sasl_listmech( ctx, 1401 NULL, NULL, ",", NULL, 1402 &mechstr, NULL, NULL ); 1403 1404 if( sc != SASL_OK ) { 1405 Debug( LDAP_DEBUG_ANY, "slap_sasl_listmech failed: %d\n", 1406 sc, 0, 0 ); 1407 1408 return NULL; 1409 } 1410 1411 mechs = ldap_str2charray( mechstr, "," ); 1412 } 1413#elif defined(SLAP_BUILTIN_SASL) 1414 /* builtin SASL implementation */ 1415 SASL_CTX *ctx = conn->c_sasl_authctx; 1416 if ( ctx != NULL && ctx->sc_external_id.bv_val ) { 1417 /* should check ssf */ 1418 mechs = ldap_str2charray( "EXTERNAL", "," ); 1419 } 1420#endif 1421 1422 return mechs; 1423} 1424 1425int slap_sasl_close( Connection *conn ) 1426{ 1427#ifdef HAVE_CYRUS_SASL 1428 sasl_conn_t *ctx = conn->c_sasl_authctx; 1429 1430 if( ctx != NULL ) { 1431 sasl_dispose( &ctx ); 1432 } 1433 if ( conn->c_sasl_sockctx && 1434 conn->c_sasl_authctx != conn->c_sasl_sockctx ) 1435 { 1436 ctx = conn->c_sasl_sockctx; 1437 sasl_dispose( &ctx ); 1438 } 1439 1440 conn->c_sasl_authctx = NULL; 1441 conn->c_sasl_sockctx = NULL; 1442 conn->c_sasl_done = 0; 1443 1444 free( conn->c_sasl_extra ); 1445 conn->c_sasl_extra = NULL; 1446 1447#elif defined(SLAP_BUILTIN_SASL) 1448 SASL_CTX *ctx = conn->c_sasl_authctx; 1449 if( ctx ) { 1450 if( ctx->sc_external_id.bv_val ) { 1451 free( ctx->sc_external_id.bv_val ); 1452 BER_BVZERO( &ctx->sc_external_id ); 1453 } 1454 free( ctx ); 1455 conn->c_sasl_authctx = NULL; 1456 } 1457#endif 1458 1459 return LDAP_SUCCESS; 1460} 1461 1462int slap_sasl_bind( Operation *op, SlapReply *rs ) 1463{ 1464#ifdef HAVE_CYRUS_SASL 1465 sasl_conn_t *ctx = op->o_conn->c_sasl_authctx; 1466 struct berval response; 1467 unsigned reslen = 0; 1468 int sc; 1469 1470 Debug(LDAP_DEBUG_ARGS, 1471 "==> sasl_bind: dn=\"%s\" mech=%s datalen=%ld\n", 1472 op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", 1473 op->o_conn->c_sasl_bind_in_progress ? "<continuing>" : 1474 op->o_conn->c_sasl_bind_mech.bv_val, 1475 op->orb_cred.bv_len ); 1476 1477 if( ctx == NULL ) { 1478 send_ldap_error( op, rs, LDAP_UNAVAILABLE, 1479 "SASL unavailable on this session" ); 1480 return rs->sr_err; 1481 } 1482 1483#define START( ctx, mech, cred, clen, resp, rlen, err ) \ 1484 sasl_server_start( ctx, mech, cred, clen, resp, rlen ) 1485#define STEP( ctx, cred, clen, resp, rlen, err ) \ 1486 sasl_server_step( ctx, cred, clen, resp, rlen ) 1487 1488 if ( !op->o_conn->c_sasl_bind_in_progress ) { 1489 /* If we already authenticated once, must use a new context */ 1490 if ( op->o_conn->c_sasl_done ) { 1491 sasl_ssf_t ssf = 0; 1492 const char *authid = NULL; 1493 sasl_getprop( ctx, SASL_SSF_EXTERNAL, (void *)&ssf ); 1494 sasl_getprop( ctx, SASL_AUTH_EXTERNAL, (void *)&authid ); 1495 if ( authid ) authid = ch_strdup( authid ); 1496 if ( ctx != op->o_conn->c_sasl_sockctx ) { 1497 sasl_dispose( &ctx ); 1498 } 1499 op->o_conn->c_sasl_authctx = NULL; 1500 1501 slap_sasl_open( op->o_conn, 1 ); 1502 ctx = op->o_conn->c_sasl_authctx; 1503 if ( authid ) { 1504 sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf ); 1505 sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid ); 1506 ch_free( (char *)authid ); 1507 } 1508 } 1509 sc = START( ctx, 1510 op->o_conn->c_sasl_bind_mech.bv_val, 1511 op->orb_cred.bv_val, op->orb_cred.bv_len, 1512 (SASL_CONST char **)&response.bv_val, &reslen, &rs->sr_text ); 1513 1514 } else { 1515 sc = STEP( ctx, 1516 op->orb_cred.bv_val, op->orb_cred.bv_len, 1517 (SASL_CONST char **)&response.bv_val, &reslen, &rs->sr_text ); 1518 } 1519 1520 response.bv_len = reslen; 1521 1522 if ( sc == SASL_OK ) { 1523 sasl_ssf_t *ssf = NULL; 1524 1525 ber_dupbv_x( &op->orb_edn, &op->o_conn->c_sasl_dn, op->o_tmpmemctx ); 1526 BER_BVZERO( &op->o_conn->c_sasl_dn ); 1527 op->o_conn->c_sasl_done = 1; 1528 1529 rs->sr_err = LDAP_SUCCESS; 1530 1531 (void) sasl_getprop( ctx, SASL_SSF, (void *)&ssf ); 1532 op->orb_ssf = ssf ? *ssf : 0; 1533 1534 ctx = NULL; 1535 if( op->orb_ssf ) { 1536 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 1537 op->o_conn->c_sasl_layers++; 1538 1539 /* If there's an old layer, set sockctx to NULL to 1540 * tell connection_read() to wait for us to finish. 1541 * Otherwise there is a race condition: we have to 1542 * send the Bind response using the old security 1543 * context and then remove it before reading any 1544 * new messages. 1545 */ 1546 if ( op->o_conn->c_sasl_sockctx ) { 1547 ctx = op->o_conn->c_sasl_sockctx; 1548 op->o_conn->c_sasl_sockctx = NULL; 1549 } else { 1550 op->o_conn->c_sasl_sockctx = op->o_conn->c_sasl_authctx; 1551 } 1552 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 1553 } 1554 1555 /* Must send response using old security layer */ 1556 rs->sr_sasldata = (response.bv_len ? &response : NULL); 1557 send_ldap_sasl( op, rs ); 1558 1559 /* Now dispose of the old security layer. 1560 */ 1561 if ( ctx ) { 1562 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 1563 ldap_pvt_sasl_remove( op->o_conn->c_sb ); 1564 op->o_conn->c_sasl_sockctx = op->o_conn->c_sasl_authctx; 1565 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 1566 sasl_dispose( &ctx ); 1567 } 1568 } else if ( sc == SASL_CONTINUE ) { 1569 rs->sr_err = LDAP_SASL_BIND_IN_PROGRESS, 1570 rs->sr_text = sasl_errdetail( ctx ); 1571 rs->sr_sasldata = &response; 1572 send_ldap_sasl( op, rs ); 1573 1574 } else { 1575 BER_BVZERO( &op->o_conn->c_sasl_dn ); 1576 rs->sr_text = sasl_errdetail( ctx ); 1577 rs->sr_err = slap_sasl_err2ldap( sc ), 1578 send_ldap_result( op, rs ); 1579 } 1580 1581 Debug(LDAP_DEBUG_TRACE, "<== slap_sasl_bind: rc=%d\n", rs->sr_err, 0, 0); 1582 1583#elif defined(SLAP_BUILTIN_SASL) 1584 /* built-in SASL implementation */ 1585 SASL_CTX *ctx = op->o_conn->c_sasl_authctx; 1586 1587 if ( ctx == NULL ) { 1588 send_ldap_error( op, rs, LDAP_OTHER, 1589 "Internal SASL Error" ); 1590 1591 } else if ( bvmatch( &ext_bv, &op->o_conn->c_sasl_bind_mech ) ) { 1592 /* EXTERNAL */ 1593 1594 if( op->orb_cred.bv_len ) { 1595 rs->sr_text = "proxy authorization not support"; 1596 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1597 send_ldap_result( op, rs ); 1598 1599 } else { 1600 op->orb_edn = ctx->sc_external_id; 1601 rs->sr_err = LDAP_SUCCESS; 1602 rs->sr_sasldata = NULL; 1603 send_ldap_sasl( op, rs ); 1604 } 1605 1606 } else { 1607 send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED, 1608 "requested SASL mechanism not supported" ); 1609 } 1610#else 1611 send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED, 1612 "SASL not supported" ); 1613#endif 1614 1615 return rs->sr_err; 1616} 1617 1618char* slap_sasl_secprops( const char *in ) 1619{ 1620#ifdef HAVE_CYRUS_SASL 1621 int rc = ldap_pvt_sasl_secprops( in, &sasl_secprops ); 1622 1623 return rc == LDAP_SUCCESS ? NULL : "Invalid security properties"; 1624#else 1625 return "SASL not supported"; 1626#endif 1627} 1628 1629void slap_sasl_secprops_unparse( struct berval *bv ) 1630{ 1631#ifdef HAVE_CYRUS_SASL 1632 ldap_pvt_sasl_secprops_unparse( &sasl_secprops, bv ); 1633#endif 1634} 1635 1636#ifdef HAVE_CYRUS_SASL 1637int 1638slap_sasl_setpass( Operation *op, SlapReply *rs ) 1639{ 1640 struct berval id = BER_BVNULL; /* needs to come from connection */ 1641 struct berval new = BER_BVNULL; 1642 struct berval old = BER_BVNULL; 1643 1644 assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 ); 1645 1646 rs->sr_err = sasl_getprop( op->o_conn->c_sasl_authctx, SASL_USERNAME, 1647 (SASL_CONST void **)(char *)&id.bv_val ); 1648 1649 if( rs->sr_err != SASL_OK ) { 1650 rs->sr_text = "unable to retrieve SASL username"; 1651 rs->sr_err = LDAP_OTHER; 1652 goto done; 1653 } 1654 1655 Debug( LDAP_DEBUG_ARGS, "==> slap_sasl_setpass: \"%s\"\n", 1656 id.bv_val ? id.bv_val : "", 0, 0 ); 1657 1658 rs->sr_err = slap_passwd_parse( op->ore_reqdata, 1659 NULL, &old, &new, &rs->sr_text ); 1660 1661 if( rs->sr_err != LDAP_SUCCESS ) { 1662 goto done; 1663 } 1664 1665 if( new.bv_len == 0 ) { 1666 slap_passwd_generate(&new); 1667 1668 if( new.bv_len == 0 ) { 1669 rs->sr_text = "password generation failed."; 1670 rs->sr_err = LDAP_OTHER; 1671 goto done; 1672 } 1673 1674 rs->sr_rspdata = slap_passwd_return( &new ); 1675 } 1676 1677 rs->sr_err = sasl_setpass( op->o_conn->c_sasl_authctx, id.bv_val, 1678 new.bv_val, new.bv_len, old.bv_val, old.bv_len, 0 ); 1679 if( rs->sr_err != SASL_OK ) { 1680 rs->sr_text = sasl_errdetail( op->o_conn->c_sasl_authctx ); 1681 } 1682 switch(rs->sr_err) { 1683 case SASL_OK: 1684 rs->sr_err = LDAP_SUCCESS; 1685 break; 1686 1687 case SASL_NOCHANGE: 1688 case SASL_NOMECH: 1689 case SASL_DISABLED: 1690 case SASL_PWLOCK: 1691 case SASL_FAIL: 1692 case SASL_BADPARAM: 1693 default: 1694 rs->sr_err = LDAP_OTHER; 1695 } 1696 1697done: 1698 return rs->sr_err; 1699} 1700#endif /* HAVE_CYRUS_SASL */ 1701 1702/* Take any sort of identity string and return a DN with the "dn:" prefix. The 1703 * string returned in *dn is in its own allocated memory, and must be free'd 1704 * by the calling process. -Mark Adamson, Carnegie Mellon 1705 * 1706 * The "dn:" prefix is no longer used anywhere inside slapd. It is only used 1707 * on strings passed in directly from SASL. -Howard Chu, Symas Corp. 1708 */ 1709 1710#define SET_NONE 0 1711#define SET_DN 1 1712#define SET_U 2 1713 1714int slap_sasl_getdn( Connection *conn, Operation *op, struct berval *id, 1715 char *user_realm, struct berval *dn, int flags ) 1716{ 1717 int rc, is_dn = SET_NONE, do_norm = 1; 1718 struct berval dn2, *mech; 1719 1720 assert( conn != NULL ); 1721 assert( id != NULL ); 1722 1723 Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: conn %lu id=%s [len=%lu]\n", 1724 conn->c_connid, 1725 BER_BVISNULL( id ) ? "NULL" : ( BER_BVISEMPTY( id ) ? "<empty>" : id->bv_val ), 1726 BER_BVISNULL( id ) ? 0 : ( BER_BVISEMPTY( id ) ? 0 : 1727 (unsigned long) id->bv_len ) ); 1728 1729 if ( !op ) { 1730 op = conn->c_sasl_bindop; 1731 } 1732 assert( op != NULL ); 1733 1734 BER_BVZERO( dn ); 1735 1736 if ( !BER_BVISNULL( id ) ) { 1737 /* Blatantly anonymous ID */ 1738 static struct berval bv_anonymous = BER_BVC( "anonymous" ); 1739 1740 if ( ber_bvstrcasecmp( id, &bv_anonymous ) == 0 ) { 1741 return( LDAP_SUCCESS ); 1742 } 1743 1744 } else { 1745 /* FIXME: if empty, should we stop? */ 1746 BER_BVSTR( id, "" ); 1747 } 1748 1749 if ( !BER_BVISEMPTY( &conn->c_sasl_bind_mech ) ) { 1750 mech = &conn->c_sasl_bind_mech; 1751 } else { 1752 mech = &conn->c_authmech; 1753 } 1754 1755 /* An authcID needs to be converted to authzID form. Set the 1756 * values directly into *dn; they will be normalized later. (and 1757 * normalizing always makes a new copy.) An ID from a TLS certificate 1758 * is already normalized, so copy it and skip normalization. 1759 */ 1760 if( flags & SLAP_GETDN_AUTHCID ) { 1761 if( bvmatch( mech, &ext_bv )) { 1762 /* EXTERNAL DNs are already normalized */ 1763 assert( !BER_BVISNULL( id ) ); 1764 1765 do_norm = 0; 1766 is_dn = SET_DN; 1767 ber_dupbv_x( dn, id, op->o_tmpmemctx ); 1768 1769 } else { 1770 /* convert to u:<username> form */ 1771 is_dn = SET_U; 1772 *dn = *id; 1773 } 1774 } 1775 1776 if( is_dn == SET_NONE ) { 1777 if( !strncasecmp( id->bv_val, "u:", STRLENOF( "u:" ) ) ) { 1778 is_dn = SET_U; 1779 dn->bv_val = id->bv_val + STRLENOF( "u:" ); 1780 dn->bv_len = id->bv_len - STRLENOF( "u:" ); 1781 1782 } else if ( !strncasecmp( id->bv_val, "dn:", STRLENOF( "dn:" ) ) ) { 1783 is_dn = SET_DN; 1784 dn->bv_val = id->bv_val + STRLENOF( "dn:" ); 1785 dn->bv_len = id->bv_len - STRLENOF( "dn:" ); 1786 } 1787 } 1788 1789 /* No other possibilities from here */ 1790 if( is_dn == SET_NONE ) { 1791 BER_BVZERO( dn ); 1792 return( LDAP_INAPPROPRIATE_AUTH ); 1793 } 1794 1795 /* Username strings */ 1796 if( is_dn == SET_U ) { 1797 /* ITS#3419: values may need escape */ 1798 LDAPRDN DN[ 5 ]; 1799 LDAPAVA *RDNs[ 4 ][ 2 ]; 1800 LDAPAVA AVAs[ 4 ]; 1801 int irdn; 1802 1803 irdn = 0; 1804 DN[ irdn ] = RDNs[ irdn ]; 1805 RDNs[ irdn ][ 0 ] = &AVAs[ irdn ]; 1806 AVAs[ irdn ].la_attr = slap_schema.si_ad_uid->ad_cname; 1807 AVAs[ irdn ].la_value = *dn; 1808 AVAs[ irdn ].la_flags = LDAP_AVA_NULL; 1809 AVAs[ irdn ].la_private = NULL; 1810 RDNs[ irdn ][ 1 ] = NULL; 1811 1812 if ( user_realm && *user_realm ) { 1813 irdn++; 1814 DN[ irdn ] = RDNs[ irdn ]; 1815 RDNs[ irdn ][ 0 ] = &AVAs[ irdn ]; 1816 AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname; 1817 ber_str2bv( user_realm, 0, 0, &AVAs[ irdn ].la_value ); 1818 AVAs[ irdn ].la_flags = LDAP_AVA_NULL; 1819 AVAs[ irdn ].la_private = NULL; 1820 RDNs[ irdn ][ 1 ] = NULL; 1821 } 1822 1823 if ( !BER_BVISNULL( mech ) ) { 1824 irdn++; 1825 DN[ irdn ] = RDNs[ irdn ]; 1826 RDNs[ irdn ][ 0 ] = &AVAs[ irdn ]; 1827 AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname; 1828 AVAs[ irdn ].la_value = *mech; 1829 AVAs[ irdn ].la_flags = LDAP_AVA_NULL; 1830 AVAs[ irdn ].la_private = NULL; 1831 RDNs[ irdn ][ 1 ] = NULL; 1832 } 1833 1834 irdn++; 1835 DN[ irdn ] = RDNs[ irdn ]; 1836 RDNs[ irdn ][ 0 ] = &AVAs[ irdn ]; 1837 AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname; 1838 BER_BVSTR( &AVAs[ irdn ].la_value, "auth" ); 1839 AVAs[ irdn ].la_flags = LDAP_AVA_NULL; 1840 AVAs[ irdn ].la_private = NULL; 1841 RDNs[ irdn ][ 1 ] = NULL; 1842 1843 irdn++; 1844 DN[ irdn ] = NULL; 1845 1846 rc = ldap_dn2bv_x( DN, dn, LDAP_DN_FORMAT_LDAPV3, 1847 op->o_tmpmemctx ); 1848 if ( rc != LDAP_SUCCESS ) { 1849 BER_BVZERO( dn ); 1850 return rc; 1851 } 1852 1853 Debug( LDAP_DEBUG_TRACE, 1854 "slap_sasl_getdn: u:id converted to %s\n", 1855 dn->bv_val, 0, 0 ); 1856 1857 } else { 1858 1859 /* Dup the DN in any case, so we don't risk 1860 * leaks or dangling pointers later, 1861 * and the DN value is '\0' terminated */ 1862 ber_dupbv_x( &dn2, dn, op->o_tmpmemctx ); 1863 dn->bv_val = dn2.bv_val; 1864 } 1865 1866 /* All strings are in DN form now. Normalize if needed. */ 1867 if ( do_norm ) { 1868 rc = dnNormalize( 0, NULL, NULL, dn, &dn2, op->o_tmpmemctx ); 1869 1870 /* User DNs were constructed above and must be freed now */ 1871 slap_sl_free( dn->bv_val, op->o_tmpmemctx ); 1872 1873 if ( rc != LDAP_SUCCESS ) { 1874 BER_BVZERO( dn ); 1875 return rc; 1876 } 1877 *dn = dn2; 1878 } 1879 1880 /* Run thru regexp */ 1881 slap_sasl2dn( op, dn, &dn2, flags ); 1882 if( !BER_BVISNULL( &dn2 ) ) { 1883 slap_sl_free( dn->bv_val, op->o_tmpmemctx ); 1884 *dn = dn2; 1885 Debug( LDAP_DEBUG_TRACE, 1886 "slap_sasl_getdn: dn:id converted to %s\n", 1887 dn->bv_val, 0, 0 ); 1888 } 1889 1890 return( LDAP_SUCCESS ); 1891} 1892