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