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