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