1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <alloca.h> 26 #include <string.h> 27 #include <strings.h> 28 #include <lber.h> 29 #include <sasl/sasl.h> 30 #include <string.h> 31 #include <ctype.h> 32 #include <synch.h> 33 #include <atomic.h> 34 #include <errno.h> 35 #include <assert.h> 36 #include <limits.h> 37 #include <syslog.h> 38 #include <sys/u8_textprep.h> 39 #include <sys/varargs.h> 40 #include "libadutils.h" 41 #include "adutils_impl.h" 42 43 /* List of DSs, needed by the idle connection reaper thread */ 44 static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER; 45 static adutils_host_t *host_head = NULL; 46 47 /* 48 * List of query state structs -- needed so we can "route" LDAP results 49 * to the right context if multiple threads should be using the same 50 * connection concurrently 51 */ 52 static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER; 53 static adutils_query_state_t *qstatehead = NULL; 54 55 static char *adutils_sid_ber2str(BerValue *bvalues); 56 static void adutils_lookup_batch_unlock(adutils_query_state_t **state); 57 static void delete_ds(adutils_ad_t *ad, const char *host, int port); 58 59 int ad_debug[AD_DEBUG_MAX+1] = {0}; 60 61 typedef struct binary_attrs { 62 const char *name; 63 char *(*ber2str)(BerValue *bvalues); 64 } binary_attrs_t; 65 66 static binary_attrs_t binattrs[] = { 67 {"objectSID", adutils_sid_ber2str}, 68 {NULL, NULL} 69 }; 70 71 72 adutils_logger logger = syslog; 73 74 75 void 76 adutils_set_logger(adutils_logger funct) 77 { 78 logger = funct; 79 } 80 81 82 /* 83 * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com" 84 */ 85 static 86 char * 87 adutils_dns2dn(const char *dns) 88 { 89 int num_parts; 90 91 return (ldap_dns_to_dn((char *)dns, &num_parts)); 92 } 93 94 95 /* 96 * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 97 * attributes (CN, etc...). 98 */ 99 char * 100 adutils_dn2dns(const char *dn) 101 { 102 return (DN_to_DNS(dn)); 103 } 104 105 106 /* 107 * Convert a binary SID in a BerValue to a adutils_sid_t 108 */ 109 int 110 adutils_getsid(BerValue *bval, adutils_sid_t *sidp) 111 { 112 int i, j; 113 uchar_t *v; 114 uint32_t a; 115 116 /* 117 * The binary format of a SID is as follows: 118 * 119 * byte #0: version, always 0x01 120 * byte #1: RID count, always <= 0x0f 121 * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 122 * 123 * followed by RID count RIDs, each a little-endian, unsigned 124 * 32-bit int. 125 */ 126 /* 127 * Sanity checks: must have at least one RID, version must be 128 * 0x01, and the length must be 8 + rid count * 4 129 */ 130 if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && 131 bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { 132 v = (uchar_t *)bval->bv_val; 133 sidp->version = v[0]; 134 sidp->sub_authority_count = v[1]; 135 sidp->authority = 136 /* big endian -- so start from the left */ 137 ((u_longlong_t)v[2] << 40) | 138 ((u_longlong_t)v[3] << 32) | 139 ((u_longlong_t)v[4] << 24) | 140 ((u_longlong_t)v[5] << 16) | 141 ((u_longlong_t)v[6] << 8) | 142 (u_longlong_t)v[7]; 143 for (i = 0; i < sidp->sub_authority_count; i++) { 144 j = 8 + (i * 4); 145 /* little endian -- so start from the right */ 146 a = (v[j + 3] << 24) | (v[j + 2] << 16) | 147 (v[j + 1] << 8) | (v[j]); 148 sidp->sub_authorities[i] = a; 149 } 150 return (0); 151 } 152 return (-1); 153 } 154 155 /* 156 * Convert a adutils_sid_t to S-1-... 157 */ 158 char * 159 adutils_sid2txt(adutils_sid_t *sidp) 160 { 161 int rlen, i, len; 162 char *str, *cp; 163 164 if (sidp->version != 1) 165 return (NULL); 166 167 len = sizeof ("S-1-") - 1; 168 169 /* 170 * We could optimize like so, but, why? 171 * if (sidp->authority < 10) 172 * len += 2; 173 * else if (sidp->authority < 100) 174 * len += 3; 175 * else 176 * len += snprintf(NULL, 0"%llu", sidp->authority); 177 */ 178 len += snprintf(NULL, 0, "%llu", sidp->authority); 179 180 /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 181 len += 1 + (sidp->sub_authority_count + 1) * 10; 182 183 if ((cp = str = malloc(len)) == NULL) 184 return (NULL); 185 186 rlen = snprintf(str, len, "S-1-%llu", sidp->authority); 187 188 cp += rlen; 189 len -= rlen; 190 191 for (i = 0; i < sidp->sub_authority_count; i++) { 192 assert(len > 0); 193 rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]); 194 cp += rlen; 195 len -= rlen; 196 assert(len >= 0); 197 } 198 199 return (str); 200 } 201 202 /* 203 * Convert a adutils_sid_t to on-the-wire encoding 204 */ 205 static 206 int 207 sid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen) 208 { 209 uchar_t *p; 210 int i; 211 uint64_t a; 212 uint32_t r; 213 214 if (sid->version != 1 || 215 binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4)) 216 return (-1); 217 218 p = binsid; 219 *p++ = 0x01; /* version */ 220 /* sub authority count */ 221 *p++ = sid->sub_authority_count; 222 /* Authority */ 223 a = sid->authority; 224 /* big-endian -- start from left */ 225 *p++ = (a >> 40) & 0xFF; 226 *p++ = (a >> 32) & 0xFF; 227 *p++ = (a >> 24) & 0xFF; 228 *p++ = (a >> 16) & 0xFF; 229 *p++ = (a >> 8) & 0xFF; 230 *p++ = a & 0xFF; 231 232 /* sub-authorities */ 233 for (i = 0; i < sid->sub_authority_count; i++) { 234 r = sid->sub_authorities[i]; 235 /* little-endian -- start from right */ 236 *p++ = (r & 0x000000FF); 237 *p++ = (r & 0x0000FF00) >> 8; 238 *p++ = (r & 0x00FF0000) >> 16; 239 *p++ = (r & 0xFF000000) >> 24; 240 } 241 242 return (0); 243 } 244 245 /* 246 * Convert a stringified SID (S-1-...) into a hex-encoded version of the 247 * on-the-wire encoding, but with each pair of hex digits pre-pended 248 * with a '\', so we can pass this to libldap. 249 */ 250 int 251 adutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid, 252 char *hexbinsid, int hexbinsidlen) 253 { 254 adutils_sid_t sid = { 0 }; 255 int i, j; 256 const char *cp; 257 char *ecp; 258 u_longlong_t a; 259 unsigned long r; 260 uchar_t *binsid, b, hb; 261 262 /* Only version 1 SIDs please */ 263 if (strncmp(txt, "S-1-", strlen("S-1-")) != 0) 264 return (-1); 265 266 if (strlen(txt) < (strlen("S-1-") + 1)) 267 return (-1); 268 269 /* count '-'s */ 270 for (j = 0, cp = strchr(txt, '-'); 271 cp != NULL && *cp != '\0'; 272 j++, cp = strchr(cp + 1, '-')) { 273 /* can't end on a '-' */ 274 if (*(cp + 1) == '\0') 275 return (-1); 276 } 277 278 /* Adjust count for version and authority */ 279 j -= 2; 280 281 /* we know the version number and RID count */ 282 sid.version = 1; 283 sid.sub_authority_count = (rid != NULL) ? j + 1 : j; 284 285 /* must have at least one RID, but not too many */ 286 if (sid.sub_authority_count < 1 || 287 sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES) 288 return (-1); 289 290 /* check that we only have digits and '-' */ 291 if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1)) 292 return (-1); 293 294 cp = txt + strlen("S-1-"); 295 296 /* 64-bit safe parsing of unsigned 48-bit authority value */ 297 errno = 0; 298 a = strtoull(cp, &ecp, 10); 299 300 /* errors parsing the authority or too many bits */ 301 if (cp == ecp || (a == 0 && errno == EINVAL) || 302 (a == ULLONG_MAX && errno == ERANGE) || 303 (a & 0x0000ffffffffffffULL) != a) 304 return (-1); 305 306 cp = ecp; 307 308 sid.authority = (uint64_t)a; 309 310 for (i = 0; i < j; i++) { 311 if (*cp++ != '-') 312 return (-1); 313 /* 64-bit safe parsing of unsigned 32-bit RID */ 314 errno = 0; 315 r = strtoul(cp, &ecp, 10); 316 /* errors parsing the RID or too many bits */ 317 if (cp == ecp || (r == 0 && errno == EINVAL) || 318 (r == ULONG_MAX && errno == ERANGE) || 319 (r & 0xffffffffUL) != r) 320 return (-1); 321 sid.sub_authorities[i] = (uint32_t)r; 322 cp = ecp; 323 } 324 325 /* check that all of the string SID has been consumed */ 326 if (*cp != '\0') 327 return (-1); 328 329 if (rid != NULL) 330 sid.sub_authorities[j] = *rid; 331 332 j = 1 + 1 + 6 + sid.sub_authority_count * 4; 333 334 if (hexbinsidlen < (j * 3)) 335 return (-2); 336 337 /* binary encode the SID */ 338 binsid = (uchar_t *)alloca(j); 339 (void) sid2binsid(&sid, binsid, j); 340 341 /* hex encode, with a backslash before each byte */ 342 for (ecp = hexbinsid, i = 0; i < j; i++) { 343 b = binsid[i]; 344 *ecp++ = '\\'; 345 hb = (b >> 4) & 0xF; 346 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 347 hb = b & 0xF; 348 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 349 } 350 *ecp = '\0'; 351 352 return (0); 353 } 354 355 static 356 char * 357 convert_bval2sid(BerValue *bval, uint32_t *rid) 358 { 359 adutils_sid_t sid; 360 361 if (adutils_getsid(bval, &sid) < 0) 362 return (NULL); 363 364 /* 365 * If desired and if the SID is what should be a domain/computer 366 * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 367 * save the last RID and truncate the SID 368 */ 369 if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5) 370 *rid = sid.sub_authorities[--sid.sub_authority_count]; 371 return (adutils_sid2txt(&sid)); 372 } 373 374 375 /* 376 * Return a NUL-terminated stringified SID from the value of an 377 * objectSid attribute and put the last RID in *rid. 378 */ 379 char * 380 adutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid) 381 { 382 char *sid; 383 384 if (bval == NULL) 385 return (NULL); 386 /* objectSid is single valued */ 387 if ((sid = convert_bval2sid(bval, rid)) == NULL) 388 return (NULL); 389 return (sid); 390 } 391 392 static 393 char * 394 adutils_sid_ber2str(BerValue *bval) 395 { 396 return (adutils_bv_objsid2sidstr(bval, NULL)); 397 } 398 399 400 /* 401 * Extract an int from the Ber value 402 * Return B_TRUE if a valid integer was found, B_FALSE if not. 403 */ 404 boolean_t 405 adutils_bv_uint(BerValue *bval, unsigned int *result) 406 { 407 char buf[40]; /* big enough for any int */ 408 unsigned int tmp; 409 char *p; 410 411 *result = 0; /* for error cases */ 412 413 if (bval == NULL || bval->bv_val == NULL) 414 return (B_FALSE); 415 if (bval->bv_len >= sizeof (buf)) 416 return (B_FALSE); 417 418 (void) memcpy(buf, bval->bv_val, bval->bv_len); 419 buf[bval->bv_len] = '\0'; 420 421 tmp = strtoul(buf, &p, 10); 422 423 /* Junk after the number? */ 424 if (*p != '\0') 425 return (B_FALSE); 426 427 *result = tmp; 428 429 return (B_TRUE); 430 } 431 432 /* Return a NUL-terminated string from the Ber value */ 433 char * 434 adutils_bv_str(BerValue *bval) 435 { 436 char *s; 437 438 if (bval == NULL || bval->bv_val == NULL) 439 return (NULL); 440 if ((s = malloc(bval->bv_len + 1)) == NULL) 441 return (NULL); 442 (void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len, 443 bval->bv_val); 444 return (s); 445 } 446 447 /*ARGSUSED*/ 448 int 449 saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) 450 { 451 sasl_interact_t *interact; 452 453 if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) 454 return (LDAP_PARAM_ERROR); 455 456 /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 457 for (interact = prompts; interact->id != SASL_CB_LIST_END; 458 interact++) { 459 interact->result = NULL; 460 interact->len = 0; 461 } 462 return (LDAP_SUCCESS); 463 } 464 465 466 #define ADCONN_TIME 300 467 468 /* 469 * Idle connection reaping side of connection management 470 */ 471 void 472 adutils_reap_idle_connections() 473 { 474 adutils_host_t *adh; 475 time_t now; 476 477 (void) pthread_mutex_lock(&adhostlock); 478 now = time(NULL); 479 for (adh = host_head; adh != NULL; adh = adh->next) { 480 (void) pthread_mutex_lock(&adh->lock); 481 if (adh->ref == 0 && adh->idletime != 0 && 482 adh->idletime + ADCONN_TIME < now) { 483 if (adh->ld) { 484 (void) ldap_unbind(adh->ld); 485 adh->ld = NULL; 486 adh->idletime = 0; 487 adh->ref = 0; 488 } 489 } 490 (void) pthread_mutex_unlock(&adh->lock); 491 } 492 (void) pthread_mutex_unlock(&adhostlock); 493 } 494 495 496 adutils_rc 497 adutils_ad_alloc(adutils_ad_t **new_ad, const char *domain_name, 498 adutils_ad_partition_t part) 499 { 500 adutils_ad_t *ad; 501 502 *new_ad = NULL; 503 504 if ((ad = calloc(1, sizeof (*ad))) == NULL) 505 return (ADUTILS_ERR_MEMORY); 506 ad->ref = 1; 507 ad->partition = part; 508 509 /* domain_name is required iff we are talking directly to a DC */ 510 if (part == ADUTILS_AD_DATA) { 511 assert(domain_name != NULL); 512 assert(*domain_name != '\0'); 513 514 ad->basedn = adutils_dns2dn(domain_name); 515 } else { 516 assert(domain_name == NULL); 517 ad->basedn = strdup(""); 518 } 519 if (ad->basedn == NULL) 520 goto err; 521 522 if (pthread_mutex_init(&ad->lock, NULL) != 0) 523 goto err; 524 *new_ad = ad; 525 return (ADUTILS_SUCCESS); 526 527 err: 528 free(ad->basedn); 529 free(ad); 530 return (ADUTILS_ERR_MEMORY); 531 } 532 533 void 534 adutils_ad_free(adutils_ad_t **ad) 535 { 536 adutils_host_t *p; 537 adutils_host_t *prev; 538 539 if (ad == NULL || *ad == NULL) 540 return; 541 542 (void) pthread_mutex_lock(&(*ad)->lock); 543 544 if (atomic_dec_32_nv(&(*ad)->ref) > 0) { 545 (void) pthread_mutex_unlock(&(*ad)->lock); 546 *ad = NULL; 547 return; 548 } 549 550 (void) pthread_mutex_lock(&adhostlock); 551 prev = NULL; 552 p = host_head; 553 while (p != NULL) { 554 if (p->owner != (*ad)) { 555 prev = p; 556 p = p->next; 557 continue; 558 } else { 559 delete_ds((*ad), p->host, p->port); 560 if (prev == NULL) 561 p = host_head; 562 else 563 p = prev->next; 564 } 565 } 566 (void) pthread_mutex_unlock(&adhostlock); 567 568 (void) pthread_mutex_unlock(&(*ad)->lock); 569 (void) pthread_mutex_destroy(&(*ad)->lock); 570 571 if ((*ad)->known_domains) 572 free((*ad)->known_domains); 573 free((*ad)->basedn); 574 free(*ad); 575 576 *ad = NULL; 577 } 578 579 static 580 int 581 open_conn(adutils_host_t *adh, int timeoutsecs) 582 { 583 int zero = 0; 584 int ldversion, rc; 585 int timeoutms = timeoutsecs * 1000; 586 587 if (adh == NULL) 588 return (0); 589 590 (void) pthread_mutex_lock(&adh->lock); 591 592 if (!adh->dead && adh->ld != NULL) 593 /* done! */ 594 goto out; 595 596 if (adh->ld != NULL) { 597 (void) ldap_unbind(adh->ld); 598 adh->ld = NULL; 599 } 600 adh->num_requests = 0; 601 602 atomic_inc_64(&adh->generation); 603 604 /* Open and bind an LDAP connection */ 605 adh->ld = ldap_init(adh->host, adh->port); 606 if (adh->ld == NULL) { 607 logger(LOG_INFO, "ldap_init() to server " 608 "%s port %d failed. (%s)", adh->host, 609 adh->port, strerror(errno)); 610 goto out; 611 } 612 ldversion = LDAP_VERSION3; 613 (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion); 614 (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 615 (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero); 616 (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); 617 (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms); 618 (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 619 620 rc = adutils_set_thread_functions(adh->ld); 621 if (rc != LDAP_SUCCESS) { 622 /* Error has already been logged */ 623 (void) ldap_unbind(adh->ld); 624 adh->ld = NULL; 625 goto out; 626 } 627 628 rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */, 629 adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback, 630 NULL); 631 632 if (rc != LDAP_SUCCESS) { 633 (void) ldap_unbind(adh->ld); 634 adh->ld = NULL; 635 logger(LOG_INFO, "ldap_sasl_interactive_bind_s() to server " 636 "%s port %d failed. (%s)", adh->host, adh->port, 637 ldap_err2string(rc)); 638 goto out; 639 } 640 641 logger(LOG_DEBUG, "Using server %s:%d", 642 adh->host, adh->port); 643 644 out: 645 if (adh->ld != NULL) { 646 atomic_inc_32(&adh->ref); 647 adh->idletime = time(NULL); 648 adh->dead = 0; 649 (void) pthread_mutex_unlock(&adh->lock); 650 return (1); 651 } 652 653 (void) pthread_mutex_unlock(&adh->lock); 654 return (0); 655 } 656 657 658 /* 659 * Connection management: find an open connection or open one 660 */ 661 static 662 adutils_host_t * 663 get_conn(adutils_ad_t *ad) 664 { 665 adutils_host_t *adh = NULL; 666 int tries; 667 int dscount = 0; 668 int timeoutsecs = ADUTILS_LDAP_OPEN_TIMEOUT; 669 670 retry: 671 (void) pthread_mutex_lock(&adhostlock); 672 673 if (host_head == NULL) { 674 (void) pthread_mutex_unlock(&adhostlock); 675 goto out; 676 } 677 678 if (dscount == 0) { 679 /* 680 * First try: count the number of DSes. 681 * 682 * Integer overflow is not an issue -- we can't have so many 683 * DSes because they won't fit even DNS over TCP, and SMF 684 * shouldn't let you set so many. 685 */ 686 for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) { 687 if (adh->owner == ad) 688 dscount++; 689 } 690 691 if (dscount == 0) { 692 (void) pthread_mutex_unlock(&adhostlock); 693 goto out; 694 } 695 696 tries = dscount * 3; /* three tries per-ds */ 697 698 /* 699 * Begin round-robin at the next DS in the list after the last 700 * one that we had a connection to, else start with the first 701 * DS in the list. 702 */ 703 adh = ad->last_adh; 704 } 705 706 /* 707 * Round-robin -- pick the next one on the list; if the list 708 * changes on us, no big deal, we'll just potentially go 709 * around the wrong number of times. 710 */ 711 for (;;) { 712 if (adh != NULL && adh->owner == ad && adh->ld != NULL && 713 !adh->dead) 714 break; 715 if (adh == NULL || (adh = adh->next) == NULL) 716 adh = host_head; 717 if (adh->owner == ad) 718 break; 719 } 720 721 ad->last_adh = adh; 722 (void) pthread_mutex_unlock(&adhostlock); 723 724 /* Found suitable DS, open it if not already opened */ 725 if (open_conn(adh, timeoutsecs)) 726 return (adh); 727 728 tries--; 729 if ((tries % dscount) == 0) 730 timeoutsecs *= 2; 731 if (tries > 0) 732 goto retry; 733 734 out: 735 logger(LOG_NOTICE, "Couldn't open an LDAP connection to any global " 736 "catalog server!"); 737 return (NULL); 738 } 739 740 static 741 void 742 release_conn(adutils_host_t *adh) 743 { 744 int delete = 0; 745 746 (void) pthread_mutex_lock(&adh->lock); 747 if (atomic_dec_32_nv(&adh->ref) == 0) { 748 if (adh->owner == NULL) 749 delete = 1; 750 adh->idletime = time(NULL); 751 } 752 (void) pthread_mutex_unlock(&adh->lock); 753 754 /* Free this host if its owner no longer exists. */ 755 if (delete) { 756 (void) pthread_mutex_lock(&adhostlock); 757 delete_ds(NULL, adh->host, adh->port); 758 (void) pthread_mutex_unlock(&adhostlock); 759 } 760 } 761 762 /* 763 * Create a adutils_host_t, populate it and add it to the list of hosts. 764 */ 765 adutils_rc 766 adutils_add_ds(adutils_ad_t *ad, const char *host, int port) 767 { 768 adutils_host_t *p; 769 adutils_host_t *new = NULL; 770 int ret; 771 adutils_rc rc; 772 773 (void) pthread_mutex_lock(&adhostlock); 774 for (p = host_head; p != NULL; p = p->next) { 775 if (p->owner != ad) 776 continue; 777 778 if (strcmp(host, p->host) == 0 && p->port == port) { 779 /* already added */ 780 rc = ADUTILS_SUCCESS; 781 goto err; 782 } 783 } 784 785 rc = ADUTILS_ERR_MEMORY; 786 787 /* add new entry */ 788 new = (adutils_host_t *)calloc(1, sizeof (*new)); 789 if (new == NULL) 790 goto err; 791 new->owner = ad; 792 new->port = port; 793 new->dead = 0; 794 new->max_requests = 80; 795 new->num_requests = 0; 796 if ((new->host = strdup(host)) == NULL) 797 goto err; 798 new->saslflags = LDAP_SASL_INTERACTIVE; 799 new->saslmech = "GSSAPI"; 800 801 if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) { 802 free(new->host); 803 new->host = NULL; 804 errno = ret; 805 rc = ADUTILS_ERR_INTERNAL; 806 goto err; 807 } 808 809 /* link in */ 810 rc = ADUTILS_SUCCESS; 811 new->next = host_head; 812 host_head = new; 813 814 err: 815 (void) pthread_mutex_unlock(&adhostlock); 816 817 if (rc != 0 && new != NULL) { 818 if (new->host != NULL) { 819 (void) pthread_mutex_destroy(&new->lock); 820 free(new->host); 821 } 822 free(new); 823 } 824 825 return (rc); 826 } 827 828 /* 829 * Free a DS configuration. 830 * Caller must lock the adhostlock mutex 831 */ 832 static 833 void 834 delete_ds(adutils_ad_t *ad, const char *host, int port) 835 { 836 adutils_host_t **p, *q; 837 838 for (p = &host_head; *p != NULL; p = &((*p)->next)) { 839 if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 || 840 (*p)->port != port) 841 continue; 842 /* found */ 843 844 (void) pthread_mutex_lock(&((*p)->lock)); 845 if ((*p)->ref > 0) { 846 /* 847 * Still in use. Set its owner to NULL so 848 * that it can be freed when its ref count 849 * becomes 0. 850 */ 851 (*p)->owner = NULL; 852 (void) pthread_mutex_unlock(&((*p)->lock)); 853 break; 854 } 855 (void) pthread_mutex_unlock(&((*p)->lock)); 856 857 q = *p; 858 *p = (*p)->next; 859 860 (void) pthread_mutex_destroy(&q->lock); 861 862 if (q->ld) 863 (void) ldap_unbind(q->ld); 864 if (q->host) 865 free(q->host); 866 free(q); 867 break; 868 } 869 870 } 871 /* 872 * Add known domain name and domain SID to AD configuration. 873 */ 874 875 adutils_rc 876 adutils_add_domain(adutils_ad_t *ad, const char *domain, const char *sid) 877 { 878 struct known_domain *new; 879 int num = ad->num_known_domains; 880 881 ad->num_known_domains++; 882 new = realloc(ad->known_domains, 883 sizeof (struct known_domain) * ad->num_known_domains); 884 if (new != NULL) { 885 ad->known_domains = new; 886 (void) strlcpy(ad->known_domains[num].name, domain, 887 sizeof (ad->known_domains[num].name)); 888 (void) strlcpy(ad->known_domains[num].sid, sid, 889 sizeof (ad->known_domains[num].sid)); 890 return (ADUTILS_SUCCESS); 891 } else { 892 if (ad->known_domains != NULL) { 893 free(ad->known_domains); 894 ad->known_domains = NULL; 895 } 896 ad->num_known_domains = 0; 897 return (ADUTILS_ERR_MEMORY); 898 } 899 } 900 901 902 /* 903 * Check that this AD supports this domain. 904 * If there are no known domains assume that the 905 * domain is supported by this AD. 906 * 907 * Returns 1 if this domain is supported by this AD 908 * else returns 0; 909 */ 910 911 int 912 adutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain) 913 { 914 adutils_ad_t *ad = qs->qadh->owner; 915 int i; 916 917 for (i = 0; i < ad->num_known_domains; i++) { 918 if (domain_eq(domain, ad->known_domains[i].name)) 919 return (1); 920 } 921 922 return ((i == 0) ? 1 : 0); 923 } 924 925 926 /* 927 * Check that this AD supports the SID prefix. 928 * The SID prefix should match the domain SID. 929 * If there are no known domains assume that the 930 * SID prefix is supported by this AD. 931 * 932 * Returns 1 if this sid prefix is supported by this AD 933 * else returns 0; 934 */ 935 936 int 937 adutils_lookup_check_sid_prefix(adutils_query_state_t *qs, const char *sid) 938 { 939 adutils_ad_t *ad = qs->qadh->owner; 940 int i; 941 942 943 for (i = 0; i < ad->num_known_domains; i++) { 944 if (strcmp(sid, ad->known_domains[i].sid) == 0) 945 return (1); 946 } 947 948 return ((i == 0) ? 1 : 0); 949 } 950 951 952 adutils_rc 953 adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries, 954 adutils_ldap_res_search_cb ldap_res_search_cb, 955 void *ldap_res_search_argp, 956 adutils_query_state_t **state) 957 { 958 adutils_query_state_t *new_state; 959 adutils_host_t *adh = NULL; 960 961 if (ad == NULL) 962 return (ADUTILS_ERR_INTERNAL); 963 964 *state = NULL; 965 adh = get_conn(ad); 966 if (adh == NULL) 967 return (ADUTILS_ERR_RETRIABLE_NET_ERR); 968 969 new_state = calloc(1, sizeof (adutils_query_state_t) + 970 (nqueries - 1) * sizeof (adutils_q_t)); 971 if (new_state == NULL) 972 return (ADUTILS_ERR_MEMORY); 973 974 new_state->ref_cnt = 1; 975 new_state->qadh = adh; 976 new_state->qsize = nqueries; 977 new_state->qadh_gen = adh->generation; 978 new_state->qcount = 0; 979 new_state->ldap_res_search_cb = ldap_res_search_cb; 980 new_state->ldap_res_search_argp = ldap_res_search_argp; 981 (void) pthread_cond_init(&new_state->cv, NULL); 982 983 (void) pthread_mutex_lock(&qstatelock); 984 new_state->next = qstatehead; 985 qstatehead = new_state; 986 (void) pthread_mutex_unlock(&qstatelock); 987 *state = new_state; 988 989 return (ADUTILS_SUCCESS); 990 } 991 992 /* 993 * Find the adutils_query_state_t to which a given LDAP result msgid on a 994 * given connection belongs. This routine increaments the reference count 995 * so that the object can not be freed. adutils_lookup_batch_unlock() 996 * must be called to decreament the reference count. 997 */ 998 static 999 int 1000 msgid2query(adutils_host_t *adh, int msgid, 1001 adutils_query_state_t **state, int *qid) 1002 { 1003 adutils_query_state_t *p; 1004 int i; 1005 int ret; 1006 1007 (void) pthread_mutex_lock(&qstatelock); 1008 for (p = qstatehead; p != NULL; p = p->next) { 1009 if (p->qadh != adh || adh->generation != p->qadh_gen) 1010 continue; 1011 for (i = 0; i < p->qcount; i++) { 1012 if ((p->queries[i]).msgid == msgid) { 1013 if (!p->qdead) { 1014 p->ref_cnt++; 1015 *state = p; 1016 *qid = i; 1017 ret = 1; 1018 } else 1019 ret = 0; 1020 (void) pthread_mutex_unlock(&qstatelock); 1021 return (ret); 1022 } 1023 } 1024 } 1025 (void) pthread_mutex_unlock(&qstatelock); 1026 return (0); 1027 } 1028 1029 static 1030 int 1031 check_for_binary_attrs(const char *attr) 1032 { 1033 int i; 1034 for (i = 0; binattrs[i].name != NULL; i++) { 1035 if (strcasecmp(binattrs[i].name, attr) == 0) 1036 return (i); 1037 } 1038 return (-1); 1039 } 1040 1041 static 1042 void 1043 free_entry(adutils_entry_t *entry) 1044 { 1045 int i, j; 1046 adutils_attr_t *ap; 1047 1048 if (entry == NULL) 1049 return; 1050 if (entry->attr_nvpairs == NULL) { 1051 free(entry); 1052 return; 1053 } 1054 for (i = 0; i < entry->num_nvpairs; i++) { 1055 ap = &entry->attr_nvpairs[i]; 1056 if (ap->attr_name == NULL) { 1057 ldap_value_free(ap->attr_values); 1058 continue; 1059 } 1060 if (check_for_binary_attrs(ap->attr_name) >= 0) { 1061 free(ap->attr_name); 1062 if (ap->attr_values == NULL) 1063 continue; 1064 for (j = 0; j < ap->num_values; j++) 1065 free(ap->attr_values[j]); 1066 free(ap->attr_values); 1067 } else if (strcasecmp(ap->attr_name, "dn") == 0) { 1068 free(ap->attr_name); 1069 ldap_memfree(ap->attr_values[0]); 1070 free(ap->attr_values); 1071 } else { 1072 free(ap->attr_name); 1073 ldap_value_free(ap->attr_values); 1074 } 1075 } 1076 free(entry->attr_nvpairs); 1077 free(entry); 1078 } 1079 1080 void 1081 adutils_freeresult(adutils_result_t **result) 1082 { 1083 adutils_entry_t *e, *next; 1084 1085 if (result == NULL || *result == NULL) 1086 return; 1087 if ((*result)->entries == NULL) { 1088 free(*result); 1089 *result = NULL; 1090 return; 1091 } 1092 for (e = (*result)->entries; e != NULL; e = next) { 1093 next = e->next; 1094 free_entry(e); 1095 } 1096 free(*result); 1097 *result = NULL; 1098 } 1099 1100 const adutils_entry_t * 1101 adutils_getfirstentry(adutils_result_t *result) 1102 { 1103 if (result != NULL) 1104 return (result->entries); 1105 return (NULL); 1106 } 1107 1108 1109 char ** 1110 adutils_getattr(const adutils_entry_t *entry, const char *attrname) 1111 { 1112 int i; 1113 adutils_attr_t *ap; 1114 1115 if (entry == NULL || entry->attr_nvpairs == NULL) 1116 return (NULL); 1117 for (i = 0; i < entry->num_nvpairs; i++) { 1118 ap = &entry->attr_nvpairs[i]; 1119 if (ap->attr_name != NULL && 1120 strcasecmp(ap->attr_name, attrname) == 0) 1121 return (ap->attr_values); 1122 } 1123 return (NULL); 1124 } 1125 1126 1127 /* 1128 * Queue LDAP result for the given query. 1129 * 1130 * Return values: 1131 * 0 success 1132 * -1 ignore result 1133 * -2 error 1134 */ 1135 static 1136 int 1137 make_entry(adutils_q_t *q, adutils_host_t *adh, LDAPMessage *search_res, 1138 adutils_entry_t **entry) 1139 { 1140 BerElement *ber = NULL; 1141 BerValue **bvalues = NULL; 1142 char **strvalues; 1143 char *attr = NULL, *dn = NULL, *domain = NULL; 1144 adutils_entry_t *ep; 1145 adutils_attr_t *ap; 1146 int i, j, b, ret = -2; 1147 1148 *entry = NULL; 1149 1150 /* Check that this is the domain that we were looking for */ 1151 if ((dn = ldap_get_dn(adh->ld, search_res)) == NULL) 1152 return (-2); 1153 if ((domain = adutils_dn2dns(dn)) == NULL) { 1154 ldap_memfree(dn); 1155 return (-2); 1156 } 1157 if (q->edomain != NULL) { 1158 if (!domain_eq(q->edomain, domain)) { 1159 ldap_memfree(dn); 1160 free(domain); 1161 return (-1); 1162 } 1163 } 1164 free(domain); 1165 1166 /* Allocate memory for the entry */ 1167 if ((ep = calloc(1, sizeof (*ep))) == NULL) 1168 goto out; 1169 1170 /* For 'dn' */ 1171 ep->num_nvpairs = 1; 1172 1173 /* Count the number of name-value pairs for this entry */ 1174 for (attr = ldap_first_attribute(adh->ld, search_res, &ber); 1175 attr != NULL; 1176 attr = ldap_next_attribute(adh->ld, search_res, ber)) { 1177 ep->num_nvpairs++; 1178 ldap_memfree(attr); 1179 } 1180 ber_free(ber, 0); 1181 ber = NULL; 1182 1183 /* Allocate array for the attribute name-value pairs */ 1184 ep->attr_nvpairs = calloc(ep->num_nvpairs, sizeof (*ep->attr_nvpairs)); 1185 if (ep->attr_nvpairs == NULL) { 1186 ep->num_nvpairs = 0; 1187 goto out; 1188 } 1189 1190 /* For dn */ 1191 ap = &ep->attr_nvpairs[0]; 1192 if ((ap->attr_name = strdup("dn")) == NULL) 1193 goto out; 1194 ap->num_values = 1; 1195 ap->attr_values = calloc(ap->num_values, sizeof (*ap->attr_values)); 1196 if (ap->attr_values == NULL) { 1197 ap->num_values = 0; 1198 goto out; 1199 } 1200 ap->attr_values[0] = dn; 1201 dn = NULL; 1202 1203 for (attr = ldap_first_attribute(adh->ld, search_res, &ber), i = 1; 1204 attr != NULL; 1205 ldap_memfree(attr), i++, 1206 attr = ldap_next_attribute(adh->ld, search_res, ber)) { 1207 ap = &ep->attr_nvpairs[i]; 1208 if ((ap->attr_name = strdup(attr)) == NULL) 1209 goto out; 1210 1211 if ((b = check_for_binary_attrs(attr)) >= 0) { 1212 bvalues = 1213 ldap_get_values_len(adh->ld, search_res, attr); 1214 if (bvalues == NULL) 1215 continue; 1216 ap->num_values = ldap_count_values_len(bvalues); 1217 if (ap->num_values == 0) { 1218 ldap_value_free_len(bvalues); 1219 bvalues = NULL; 1220 continue; 1221 } 1222 ap->attr_values = calloc(ap->num_values, 1223 sizeof (*ap->attr_values)); 1224 if (ap->attr_values == NULL) { 1225 ap->num_values = 0; 1226 goto out; 1227 } 1228 for (j = 0; j < ap->num_values; j++) { 1229 ap->attr_values[j] = 1230 binattrs[b].ber2str(bvalues[j]); 1231 if (ap->attr_values[j] == NULL) 1232 goto out; 1233 } 1234 ldap_value_free_len(bvalues); 1235 bvalues = NULL; 1236 continue; 1237 } 1238 1239 strvalues = ldap_get_values(adh->ld, search_res, attr); 1240 if (strvalues == NULL) 1241 continue; 1242 ap->num_values = ldap_count_values(strvalues); 1243 if (ap->num_values == 0) { 1244 ldap_value_free(strvalues); 1245 continue; 1246 } 1247 ap->attr_values = strvalues; 1248 } 1249 1250 ret = 0; 1251 out: 1252 ldap_memfree(attr); 1253 ldap_memfree(dn); 1254 ber_free(ber, 0); 1255 ldap_value_free_len(bvalues); 1256 if (ret < 0) 1257 free_entry(ep); 1258 else 1259 *entry = ep; 1260 return (ret); 1261 } 1262 1263 /* 1264 * Put the search result onto the given adutils_q_t. 1265 * Returns: 0 success 1266 * < 0 error 1267 */ 1268 static 1269 int 1270 add_entry(adutils_host_t *adh, adutils_q_t *q, LDAPMessage *search_res) 1271 { 1272 int ret = -1; 1273 adutils_entry_t *entry = NULL; 1274 adutils_result_t *res; 1275 1276 ret = make_entry(q, adh, search_res, &entry); 1277 if (ret < -1) { 1278 *q->rc = ADUTILS_ERR_MEMORY; 1279 goto out; 1280 } else if (ret == -1) { 1281 /* ignore result */ 1282 goto out; 1283 } 1284 if (*q->result == NULL) { 1285 res = calloc(1, sizeof (*res)); 1286 if (res == NULL) { 1287 *q->rc = ADUTILS_ERR_MEMORY; 1288 goto out; 1289 } 1290 res->num_entries = 1; 1291 res->entries = entry; 1292 *q->result = res; 1293 } else { 1294 res = *q->result; 1295 entry->next = res->entries; 1296 res->entries = entry; 1297 res->num_entries++; 1298 } 1299 *q->rc = ADUTILS_SUCCESS; 1300 entry = NULL; 1301 ret = 0; 1302 1303 out: 1304 free_entry(entry); 1305 return (ret); 1306 } 1307 1308 /* 1309 * Try to get a result; if there is one, find the corresponding 1310 * adutils_q_t and process the result. 1311 * 1312 * Returns: 0 success 1313 * -1 error 1314 */ 1315 static 1316 int 1317 get_adobject_batch(adutils_host_t *adh, struct timeval *timeout) 1318 { 1319 adutils_query_state_t *query_state; 1320 LDAPMessage *res = NULL; 1321 int rc, ret, msgid, qid; 1322 adutils_q_t *que; 1323 int num; 1324 1325 (void) pthread_mutex_lock(&adh->lock); 1326 if (adh->dead || adh->num_requests == 0) { 1327 ret = (adh->dead) ? -1 : -2; 1328 (void) pthread_mutex_unlock(&adh->lock); 1329 return (ret); 1330 } 1331 1332 /* Get one result */ 1333 rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, timeout, &res); 1334 if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) || 1335 rc < 0) 1336 adh->dead = 1; 1337 1338 if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0) 1339 adh->num_requests--; 1340 if (adh->dead) { 1341 num = adh->num_requests; 1342 (void) pthread_mutex_unlock(&adh->lock); 1343 logger(LOG_DEBUG, 1344 "AD ldap_result error - %d queued requests", num); 1345 return (-1); 1346 } 1347 1348 switch (rc) { 1349 case LDAP_RES_SEARCH_RESULT: 1350 msgid = ldap_msgid(res); 1351 if (msgid2query(adh, msgid, &query_state, &qid)) { 1352 if (query_state->ldap_res_search_cb != NULL) { 1353 /* 1354 * We use the caller-provided callback 1355 * to process the result. 1356 */ 1357 query_state->ldap_res_search_cb( 1358 adh->ld, &res, rc, qid, 1359 query_state->ldap_res_search_argp); 1360 (void) pthread_mutex_unlock(&adh->lock); 1361 } else { 1362 /* 1363 * No callback. We fallback to our 1364 * default behaviour. All the entries 1365 * gotten from this search have been 1366 * added to the result list during 1367 * LDAP_RES_SEARCH_ENTRY (see below). 1368 * Here we set the return status to 1369 * notfound if the result is still empty. 1370 */ 1371 (void) pthread_mutex_unlock(&adh->lock); 1372 que = &(query_state->queries[qid]); 1373 if (*que->result == NULL) 1374 *que->rc = ADUTILS_ERR_NOTFOUND; 1375 } 1376 atomic_dec_32(&query_state->qinflight); 1377 adutils_lookup_batch_unlock(&query_state); 1378 } else { 1379 num = adh->num_requests; 1380 (void) pthread_mutex_unlock(&adh->lock); 1381 logger(LOG_DEBUG, 1382 "AD cannot find message ID (%d) " 1383 "- %d queued requests", 1384 msgid, num); 1385 } 1386 (void) ldap_msgfree(res); 1387 ret = 0; 1388 break; 1389 1390 case LDAP_RES_SEARCH_ENTRY: 1391 msgid = ldap_msgid(res); 1392 if (msgid2query(adh, msgid, &query_state, &qid)) { 1393 if (query_state->ldap_res_search_cb != NULL) { 1394 /* 1395 * We use the caller-provided callback 1396 * to process the entry. 1397 */ 1398 query_state->ldap_res_search_cb( 1399 adh->ld, &res, rc, qid, 1400 query_state->ldap_res_search_argp); 1401 (void) pthread_mutex_unlock(&adh->lock); 1402 } else { 1403 /* 1404 * No callback. We fallback to our 1405 * default behaviour. This entry 1406 * will be added to the result list. 1407 */ 1408 que = &(query_state->queries[qid]); 1409 rc = add_entry(adh, que, res); 1410 (void) pthread_mutex_unlock(&adh->lock); 1411 if (rc < 0) { 1412 logger(LOG_DEBUG, 1413 "Failed to queue entry by " 1414 "message ID (%d) " 1415 "- %d queued requests", 1416 msgid, num); 1417 } 1418 } 1419 adutils_lookup_batch_unlock(&query_state); 1420 } else { 1421 num = adh->num_requests; 1422 (void) pthread_mutex_unlock(&adh->lock); 1423 logger(LOG_DEBUG, 1424 "AD cannot find message ID (%d) " 1425 "- %d queued requests", 1426 msgid, num); 1427 } 1428 (void) ldap_msgfree(res); 1429 ret = 0; 1430 break; 1431 1432 case LDAP_RES_SEARCH_REFERENCE: 1433 /* 1434 * We have no need for these at the moment. Eventually, 1435 * when we query things that we can't expect to find in 1436 * the Global Catalog then we'll need to learn to follow 1437 * references. 1438 */ 1439 (void) pthread_mutex_unlock(&adh->lock); 1440 (void) ldap_msgfree(res); 1441 ret = 0; 1442 break; 1443 1444 default: 1445 /* timeout or error; treat the same */ 1446 (void) pthread_mutex_unlock(&adh->lock); 1447 ret = -1; 1448 break; 1449 } 1450 1451 return (ret); 1452 } 1453 1454 /* 1455 * This routine decreament the reference count of the 1456 * adutils_query_state_t 1457 */ 1458 static void 1459 adutils_lookup_batch_unlock(adutils_query_state_t **state) 1460 { 1461 /* 1462 * Decrement reference count with qstatelock locked 1463 */ 1464 (void) pthread_mutex_lock(&qstatelock); 1465 (*state)->ref_cnt--; 1466 /* 1467 * If there are no references wakup the allocating thread 1468 */ 1469 if ((*state)->ref_cnt <= 1) 1470 (void) pthread_cond_signal(&(*state)->cv); 1471 (void) pthread_mutex_unlock(&qstatelock); 1472 *state = NULL; 1473 } 1474 1475 /* 1476 * This routine frees the adutils_query_state_t structure 1477 * If the reference count is greater than 1 it waits 1478 * for the other threads to finish using it. 1479 */ 1480 void 1481 adutils_lookup_batch_release(adutils_query_state_t **state) 1482 { 1483 adutils_query_state_t **p; 1484 int i; 1485 1486 if (state == NULL || *state == NULL) 1487 return; 1488 1489 /* 1490 * Set state to dead to stop further operations. 1491 * Wait for reference count with qstatelock locked 1492 * to get to one. 1493 */ 1494 (void) pthread_mutex_lock(&qstatelock); 1495 (*state)->qdead = 1; 1496 while ((*state)->ref_cnt > 1) { 1497 (void) pthread_cond_wait(&(*state)->cv, &qstatelock); 1498 } 1499 1500 /* Remove this state struct from the list of state structs */ 1501 for (p = &qstatehead; *p != NULL; p = &(*p)->next) { 1502 if (*p == (*state)) { 1503 *p = (*state)->next; 1504 break; 1505 } 1506 } 1507 (void) pthread_mutex_unlock(&qstatelock); 1508 (void) pthread_cond_destroy(&(*state)->cv); 1509 release_conn((*state)->qadh); 1510 1511 /* Clear results for queries that failed */ 1512 for (i = 0; i < (*state)->qcount; i++) { 1513 if (*(*state)->queries[i].rc != ADUTILS_SUCCESS) { 1514 adutils_freeresult((*state)->queries[i].result); 1515 } 1516 } 1517 free(*state); 1518 *state = NULL; 1519 } 1520 1521 1522 /* 1523 * This routine waits for other threads using the 1524 * adutils_query_state_t structure to finish. 1525 * If the reference count is greater than 1 it waits 1526 * for the other threads to finish using it. 1527 */ 1528 static 1529 void 1530 adutils_lookup_batch_wait(adutils_query_state_t *state) 1531 { 1532 /* 1533 * Set state to dead to stop further operation. 1534 * stating. 1535 * Wait for reference count to get to one 1536 * with qstatelock locked. 1537 */ 1538 (void) pthread_mutex_lock(&qstatelock); 1539 state->qdead = 1; 1540 while (state->ref_cnt > 1) { 1541 (void) pthread_cond_wait(&state->cv, &qstatelock); 1542 } 1543 (void) pthread_mutex_unlock(&qstatelock); 1544 } 1545 1546 /* 1547 * Process active queries in the AD lookup batch and then finalize the 1548 * result. 1549 */ 1550 adutils_rc 1551 adutils_lookup_batch_end(adutils_query_state_t **state) 1552 { 1553 int rc = LDAP_SUCCESS; 1554 adutils_rc ad_rc = ADUTILS_SUCCESS; 1555 struct timeval tv; 1556 1557 tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 1558 tv.tv_usec = 0; 1559 1560 /* Process results until done or until timeout, if given */ 1561 while ((*state)->qinflight > 0) { 1562 if ((rc = get_adobject_batch((*state)->qadh, 1563 &tv)) != 0) 1564 break; 1565 } 1566 (*state)->qdead = 1; 1567 /* Wait for other threads processing search result to finish */ 1568 adutils_lookup_batch_wait(*state); 1569 if (rc == -1 || (*state)->qinflight != 0) 1570 ad_rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 1571 adutils_lookup_batch_release(state); 1572 return (ad_rc); 1573 } 1574 1575 /* 1576 * Send one prepared search, queue up msgid, process what results are 1577 * available 1578 */ 1579 adutils_rc 1580 adutils_lookup_batch_add(adutils_query_state_t *state, 1581 const char *filter, const char * const *attrs, const char *edomain, 1582 adutils_result_t **result, adutils_rc *rc) 1583 { 1584 adutils_rc retcode = ADUTILS_SUCCESS; 1585 int lrc, qid; 1586 int num; 1587 int dead; 1588 struct timeval tv; 1589 adutils_q_t *q; 1590 1591 qid = atomic_inc_32_nv(&state->qcount) - 1; 1592 q = &(state->queries[qid]); 1593 1594 assert(qid < state->qsize); 1595 1596 /* 1597 * Remember the expected domain so we can check the results 1598 * against it 1599 */ 1600 q->edomain = edomain; 1601 1602 /* Remember where to put the results */ 1603 q->result = result; 1604 q->rc = rc; 1605 1606 /* 1607 * Provide sane defaults for the results in case we never hear 1608 * back from the DS before closing the connection. 1609 */ 1610 *rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 1611 if (result != NULL) 1612 *result = NULL; 1613 1614 /* Check the number of queued requests first */ 1615 tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 1616 tv.tv_usec = 0; 1617 while (!state->qadh->dead && 1618 state->qadh->num_requests > state->qadh->max_requests) { 1619 if (get_adobject_batch(state->qadh, &tv) != 0) 1620 break; 1621 } 1622 1623 /* Send this lookup, don't wait for a result here */ 1624 lrc = LDAP_SUCCESS; 1625 (void) pthread_mutex_lock(&state->qadh->lock); 1626 1627 if (!state->qadh->dead) { 1628 state->qadh->idletime = time(NULL); 1629 1630 lrc = ldap_search_ext(state->qadh->ld, 1631 state->qadh->owner->basedn, 1632 LDAP_SCOPE_SUBTREE, filter, (char **)attrs, 1633 0, NULL, NULL, NULL, -1, &q->msgid); 1634 1635 if (lrc == LDAP_SUCCESS) { 1636 state->qadh->num_requests++; 1637 } else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE || 1638 lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN || 1639 lrc == LDAP_UNWILLING_TO_PERFORM) { 1640 retcode = ADUTILS_ERR_RETRIABLE_NET_ERR; 1641 state->qadh->dead = 1; 1642 } else { 1643 retcode = ADUTILS_ERR_OTHER; 1644 state->qadh->dead = 1; 1645 } 1646 } 1647 dead = state->qadh->dead; 1648 num = state->qadh->num_requests; 1649 (void) pthread_mutex_unlock(&state->qadh->lock); 1650 1651 if (dead) { 1652 if (lrc != LDAP_SUCCESS) 1653 logger(LOG_DEBUG, 1654 "AD ldap_search_ext error (%s) " 1655 "- %d queued requests", 1656 ldap_err2string(lrc), num); 1657 return (retcode); 1658 } 1659 1660 atomic_inc_32(&state->qinflight); 1661 1662 /* 1663 * Reap as many requests as we can _without_ waiting to prevent 1664 * any possible TCP socket buffer starvation deadlocks. 1665 */ 1666 (void) memset(&tv, 0, sizeof (tv)); 1667 while (get_adobject_batch(state->qadh, &tv) == 0) 1668 ; 1669 1670 return (ADUTILS_SUCCESS); 1671 } 1672 1673 /* 1674 * Single AD lookup request implemented on top of the batch API. 1675 */ 1676 adutils_rc 1677 adutils_lookup(adutils_ad_t *ad, const char *filter, const char **attrs, 1678 const char *domain, adutils_result_t **result) 1679 { 1680 adutils_rc rc, brc; 1681 adutils_query_state_t *qs; 1682 1683 rc = adutils_lookup_batch_start(ad, 1, NULL, NULL, &qs); 1684 if (rc != ADUTILS_SUCCESS) 1685 return (rc); 1686 1687 rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc); 1688 if (rc != ADUTILS_SUCCESS) { 1689 adutils_lookup_batch_release(&qs); 1690 return (rc); 1691 } 1692 1693 rc = adutils_lookup_batch_end(&qs); 1694 if (rc != ADUTILS_SUCCESS) 1695 return (rc); 1696 return (brc); 1697 } 1698 1699 boolean_t 1700 domain_eq(const char *a, const char *b) 1701 { 1702 int err; 1703 1704 return (u8_strcmp(a, b, 0, U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) 1705 == 0 && err == 0); 1706 } 1707 1708 void 1709 adutils_set_debug(enum ad_debug item, int value) 1710 { 1711 if (item >= 0 && item <= AD_DEBUG_MAX) 1712 ad_debug[item] = value; 1713 } 1714