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