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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdlib.h> 29 #include <stdio.h> 30 #include <errno.h> 31 #include <string.h> 32 #include <synch.h> 33 #include <time.h> 34 #include <libintl.h> 35 #include <thread.h> 36 #include <syslog.h> 37 #include <sys/mman.h> 38 #include <nsswitch.h> 39 #include <nss_dbdefs.h> 40 #include "solaris-priv.h" 41 #include "solaris-int.h" 42 #include "ns_sldap.h" 43 #include "ns_internal.h" 44 #include "ns_cache_door.h" 45 #include "ldappr.h" 46 #include <sys/stat.h> 47 #include <fcntl.h> 48 #include <procfs.h> 49 #include <unistd.h> 50 51 extern unsigned int _sleep(unsigned int); 52 extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *, 53 LDAPControl **, LDAPControl **); 54 extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip); 55 56 static int openConnection(LDAP **, const char *, const ns_cred_t *, 57 int, ns_ldap_error_t **, int, int); 58 /* 59 * sessionLock, wait4session, sessionTid 60 * are variables to synchronize the creation/retrieval of a connection. 61 * MTperCon is a flag to enable/disable multiple threads sharing the same 62 * connection. 63 * sessionPoolLock is a mutex lock for the connection pool. 64 * sharedConnNumber is the number of sharable connections in the pool. 65 * sharedConnNumberLock is a mutex for sharedConnNumber. 66 */ 67 static mutex_t sessionLock = DEFAULTMUTEX; 68 static int wait4session = 0; 69 static thread_t sessionTid = 0; 70 int MTperConn = 1; 71 static rwlock_t sessionPoolLock = DEFAULTRWLOCK; 72 73 static Connection **sessionPool = NULL; 74 static int sessionPoolSize = 0; 75 static int sharedConnNumber = 0; 76 static mutex_t sharedConnNumberLock = DEFAULTMUTEX; 77 78 79 static mutex_t nscdLock = DEFAULTMUTEX; 80 static int nscdChecked = 0; 81 static pid_t checkedPid = -1; 82 static int isNscd = 0; 83 /* 84 * SSF values are for SASL integrity & privacy. 85 * JES DS5.2 does not support this feature but DS6 does. 86 * The values between 0 and 65535 can work with both server versions. 87 */ 88 #define MAX_SASL_SSF 65535 89 #define MIN_SASL_SSF 0 90 91 /* Number of hostnames to allocate memory for */ 92 #define NUMTOMALLOC 32 93 /* 94 * ns_mtckey is for sharing a ldap connection among multiple 95 * threads; created by ns_ldap_init() in ns_init.c 96 */ 97 extern thread_key_t ns_mtckey; 98 99 /* Per thread LDAP error resides in thread-specific data. */ 100 struct ldap_error { 101 int le_errno; 102 char *le_matched; 103 char *le_errmsg; 104 }; 105 106 /* destructor */ 107 void 108 ns_tsd_cleanup(void *key) { 109 struct ldap_error *le = (struct ldap_error *)key; 110 111 if (le == NULL) 112 return; 113 if (le->le_matched != NULL) { 114 ldap_memfree(le->le_matched); 115 } 116 if (le->le_errmsg != NULL) { 117 ldap_memfree(le->le_errmsg); 118 } 119 free(le); 120 } 121 122 /* Callback function for allocating a mutex */ 123 static void * 124 ns_mutex_alloc(void) 125 { 126 mutex_t *mutexp = NULL; 127 128 if ((mutexp = malloc(sizeof (mutex_t))) != NULL) { 129 if (mutex_init(mutexp, USYNC_THREAD, NULL) != 0) { 130 free(mutexp); 131 mutexp = NULL; 132 } 133 } 134 return (mutexp); 135 } 136 137 /* Callback function for freeing a mutex */ 138 static void 139 ns_mutex_free(void *mutexp) 140 { 141 (void) mutex_destroy((mutex_t *)mutexp); 142 free(mutexp); 143 } 144 145 /* 146 * Function for setting up thread-specific data 147 * where per thread LDAP error is stored 148 */ 149 static int 150 tsd_setup() 151 { 152 void *tsd; 153 int rc; 154 155 /* return success if TSD already set */ 156 rc = thr_getspecific(ns_mtckey, &tsd); 157 if (rc == 0 && tsd != NULL) 158 return (0); 159 160 /* allocate and set TSD */ 161 tsd = (void *) calloc(1, sizeof (struct ldap_error)); 162 if (tsd == NULL) 163 return (-1); 164 rc = thr_setspecific(ns_mtckey, tsd); 165 if (rc != 0) { /* must be ENOMEM */ 166 free(tsd); 167 return (-1); 168 } 169 return (0); 170 171 172 } 173 174 /* Callback function for setting the per thread LDAP error */ 175 /*ARGSUSED*/ 176 static void 177 set_ld_error(int err, char *matched, char *errmsg, void *dummy) 178 { 179 struct ldap_error *le; 180 181 if (thr_getspecific(ns_mtckey, (void **)&le) != 0) { 182 syslog(LOG_ERR, "set_ld_error: thr_getspecific failed. errno" 183 " %d", errno); 184 return; 185 } 186 le->le_errno = err; 187 if (le->le_matched != NULL) { 188 ldap_memfree(le->le_matched); 189 } 190 le->le_matched = matched; 191 if (le->le_errmsg != NULL) { 192 ldap_memfree(le->le_errmsg); 193 } 194 le->le_errmsg = errmsg; 195 } 196 197 int 198 /* check and allocate the thread-specific data for using a shared connection */ 199 __s_api_check_MTC_tsd() 200 { 201 if (tsd_setup() != 0) 202 return (NS_LDAP_MEMORY); 203 204 return (NS_LDAP_SUCCESS); 205 } 206 207 /* Callback function for getting the per thread LDAP error */ 208 /*ARGSUSED*/ 209 static int 210 get_ld_error(char **matched, char **errmsg, void *dummy) 211 { 212 struct ldap_error *le; 213 214 if (thr_getspecific(ns_mtckey, (void **)&le) != 0) { 215 syslog(LOG_ERR, "get_ld_error: thr_getspecific failed. errno" 216 " %d", errno); 217 return (errno); 218 } 219 if (matched != NULL) { 220 *matched = le->le_matched; 221 } 222 if (errmsg != NULL) { 223 *errmsg = le->le_errmsg; 224 } 225 return (le->le_errno); 226 } 227 228 /* Callback function for setting per thread errno */ 229 static void 230 set_errno(int err) 231 { 232 errno = err; 233 } 234 235 /* Callback function for getting per thread errno */ 236 static int 237 get_errno(void) 238 { 239 return (errno); 240 } 241 242 /* 243 * set up to allow multiple threads to use the same ldap connection 244 */ 245 static int 246 setup_mt_conn(LDAP *ld) 247 { 248 249 struct ldap_thread_fns tfns; 250 struct ldap_extra_thread_fns extrafns; 251 int rc; 252 253 /* 254 * Set the function pointers for dealing with mutexes 255 * and error information 256 */ 257 (void) memset(&tfns, '\0', sizeof (struct ldap_thread_fns)); 258 tfns.ltf_mutex_alloc = (void *(*)(void)) ns_mutex_alloc; 259 tfns.ltf_mutex_free = (void (*)(void *)) ns_mutex_free; 260 tfns.ltf_mutex_lock = (int (*)(void *)) mutex_lock; 261 tfns.ltf_mutex_unlock = (int (*)(void *)) mutex_unlock; 262 tfns.ltf_get_errno = get_errno; 263 tfns.ltf_set_errno = set_errno; 264 tfns.ltf_get_lderrno = get_ld_error; 265 tfns.ltf_set_lderrno = set_ld_error; 266 tfns.ltf_lderrno_arg = NULL; 267 268 /* 269 * Set up this session to use those function pointers 270 */ 271 rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS, 272 (void *) &tfns); 273 if (rc < 0) { 274 syslog(LOG_WARNING, "libsldap: ldap_set_option " 275 "(LDAP_OPT_THREAD_FN_PTRS)"); 276 return (-1); 277 } 278 279 /* 280 * Set the function pointers for working with semaphores 281 */ 282 (void) memset(&extrafns, '\0', 283 sizeof (struct ldap_extra_thread_fns)); 284 extrafns.ltf_threadid_fn = (void * (*)(void))thr_self; 285 extrafns.ltf_mutex_trylock = NULL; 286 extrafns.ltf_sema_alloc = NULL; 287 extrafns.ltf_sema_free = NULL; 288 extrafns.ltf_sema_wait = NULL; 289 extrafns.ltf_sema_post = NULL; 290 291 /* Set up this session to use those function pointers */ 292 rc = ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS, 293 (void *) &extrafns); 294 if (rc < 0) { 295 syslog(LOG_WARNING, "libsldap: ldap_set_option " 296 "(LDAP_OPT_EXTRA_THREAD_FN_PTRS)"); 297 return (-1); 298 } 299 300 return (0); 301 } 302 303 static void 304 ns_setup_mt_conn_and_tsd(LDAP *ld) { 305 thread_t t = thr_self(); 306 void *tsd; 307 /* set up to share this connection among threads */ 308 if (MTperConn == 1) { 309 if (tsd_setup() == -1) { 310 syslog(LOG_ERR, "tid= %d: unable " 311 "to set up TSD\n", t); 312 } else { 313 if (setup_mt_conn(ld) == -1) { 314 /* multiple threads per connection not supported */ 315 syslog(LOG_ERR, "tid= %d: multiple " 316 "threads per connection not " 317 "supported\n", t); 318 (void) thr_getspecific(ns_mtckey, &tsd); 319 ns_tsd_cleanup(tsd); 320 (void) thr_setspecific(ns_mtckey, NULL); 321 MTperConn = 0; 322 } 323 } 324 } 325 } 326 327 /* 328 * Check /proc/PID/psinfo to see if this process is nscd 329 * If it is, treat connection as NS_LDAP_KEEP_CONN, to reduce 330 * constant reconnects for many operations. 331 * A more complete solution is to develop true connection pooling. 332 * However, this is much better than a new connection for every request. 333 */ 334 static int 335 nscd_proc() 336 { 337 pid_t my_pid; 338 psinfo_t pinfo; 339 char fname[BUFSIZ]; 340 int ret; 341 int fd; 342 343 /* Don't bother checking if this process isn't root. */ 344 /* It can't be nscd */ 345 if (getuid() != 0) 346 return (0); 347 348 my_pid = getpid(); 349 if (nscdChecked && (my_pid == checkedPid)) { 350 return (isNscd); 351 } 352 (void) mutex_lock(&nscdLock); 353 if (nscdChecked && (my_pid == checkedPid)) { 354 (void) mutex_unlock(&nscdLock); 355 return (isNscd); 356 } 357 nscdChecked = 1; 358 checkedPid = my_pid; 359 isNscd = 0; 360 if (snprintf(fname, BUFSIZ, "/proc/%d/psinfo", my_pid) != 0) { 361 if ((fd = open(fname, O_RDONLY)) > 0) { 362 ret = read(fd, &pinfo, sizeof (psinfo_t)); 363 (void) close(fd); 364 if (ret == sizeof (psinfo_t) && 365 (strcmp(pinfo.pr_fname, "nscd") == 0)) { 366 /* process runs as root and is named nscd */ 367 /* that's good enough for now */ 368 isNscd = 1; 369 } 370 } 371 } 372 (void) mutex_unlock(&nscdLock); 373 return (isNscd); 374 } 375 376 /* 377 * This function requests a server from the cache manager through 378 * the door functionality 379 */ 380 381 static int 382 __s_api_requestServer(const char *request, const char *server, 383 ns_server_info_t *ret, ns_ldap_error_t **error, const char *addrType) 384 { 385 union { 386 ldap_data_t s_d; 387 char s_b[DOORBUFFERSIZE]; 388 } space; 389 ldap_data_t *sptr; 390 int ndata; 391 int adata; 392 char errstr[MAXERROR]; 393 const char *ireq; 394 char *rbuf, *ptr, *rest; 395 char *dptr; 396 char **mptr, **mptr1, **cptr, **cptr1; 397 int mcnt, ccnt; 398 char **servers; 399 int rc, len; 400 401 if (ret == NULL || error == NULL) { 402 return (NS_LDAP_OP_FAILED); 403 } 404 (void) memset(ret, 0, sizeof (ns_server_info_t)); 405 *error = NULL; 406 407 (void) memset(space.s_b, 0, DOORBUFFERSIZE); 408 409 if (request == NULL) 410 ireq = NS_CACHE_NEW; 411 else 412 ireq = request; 413 414 adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1); 415 if (server != NULL) { 416 adata += strlen(DOORLINESEP) + 1; 417 adata += strlen(server) + 1; 418 } 419 ndata = sizeof (space); 420 len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber); 421 space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER; 422 if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len) 423 return (NS_LDAP_MEMORY); 424 if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >= 425 len) 426 return (NS_LDAP_MEMORY); 427 if (server != NULL) { 428 if (strlcat(space.s_d.ldap_call.ldap_u.domainname, 429 DOORLINESEP, len) >= len) 430 return (NS_LDAP_MEMORY); 431 if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, 432 len) >= len) 433 return (NS_LDAP_MEMORY); 434 } 435 sptr = &space.s_d; 436 437 switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) { 438 case SUCCESS: 439 break; 440 /* this case is for when the $mgr is not running, but ldapclient */ 441 /* is trying to initialize things */ 442 case NOSERVER: 443 /* get first server from config list unavailable otherwise */ 444 servers = NULL; 445 rc = __s_api_getServers(&servers, error); 446 if (rc != NS_LDAP_SUCCESS) { 447 if (servers != NULL) { 448 __s_api_free2dArray(servers); 449 servers = NULL; 450 } 451 return (rc); 452 } 453 if (servers == NULL || servers[0] == NULL) { 454 __s_api_free2dArray(servers); 455 servers = NULL; 456 (void) sprintf(errstr, 457 gettext("No server found in configuration")); 458 MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT, 459 strdup(errstr), NULL); 460 return (NS_LDAP_CONFIG); 461 } 462 ret->server = strdup(servers[0]); 463 if (ret->server == NULL) { 464 __s_api_free2dArray(servers); 465 return (NS_LDAP_MEMORY); 466 } 467 ret->saslMechanisms = NULL; 468 ret->controls = NULL; 469 __s_api_free2dArray(servers); 470 servers = NULL; 471 return (NS_LDAP_SUCCESS); 472 case NOTFOUND: 473 default: 474 return (NS_LDAP_OP_FAILED); 475 } 476 477 /* copy info from door call return structure here */ 478 rbuf = space.s_d.ldap_ret.ldap_u.config; 479 480 /* Get the host */ 481 ptr = strtok_r(rbuf, DOORLINESEP, &rest); 482 if (ptr == NULL) { 483 (void) sprintf(errstr, gettext("No server returned from " 484 "ldap_cachemgr")); 485 MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR, 486 strdup(errstr), NULL); 487 return (NS_LDAP_OP_FAILED); 488 } 489 ret->server = strdup(ptr); 490 if (ret->server == NULL) { 491 return (NS_LDAP_MEMORY); 492 } 493 494 /* get the Supported Controls/SASL mechs */ 495 mptr = NULL; 496 mcnt = 0; 497 cptr = NULL; 498 ccnt = 0; 499 for (; ; ) { 500 ptr = strtok_r(NULL, DOORLINESEP, &rest); 501 if (ptr == NULL) 502 break; 503 if (strncasecmp(ptr, _SASLMECHANISM, 504 _SASLMECHANISM_LEN) == 0) { 505 dptr = strchr(ptr, '='); 506 if (dptr == NULL) 507 continue; 508 dptr++; 509 mptr1 = (char **)realloc((void *)mptr, 510 sizeof (char *) * (mcnt+2)); 511 if (mptr1 == NULL) { 512 __s_api_free2dArray(mptr); 513 if (sptr != &space.s_d) { 514 (void) munmap((char *)sptr, ndata); 515 } 516 __s_api_free2dArray(cptr); 517 free(ret->server); 518 ret->server = NULL; 519 return (NS_LDAP_MEMORY); 520 } 521 mptr = mptr1; 522 mptr[mcnt] = strdup(dptr); 523 if (mptr[mcnt] == NULL) { 524 if (sptr != &space.s_d) { 525 (void) munmap((char *)sptr, ndata); 526 } 527 __s_api_free2dArray(cptr); 528 cptr = NULL; 529 __s_api_free2dArray(mptr); 530 mptr = NULL; 531 free(ret->server); 532 ret->server = NULL; 533 return (NS_LDAP_MEMORY); 534 } 535 mcnt++; 536 mptr[mcnt] = NULL; 537 } 538 if (strncasecmp(ptr, _SUPPORTEDCONTROL, 539 _SUPPORTEDCONTROL_LEN) == 0) { 540 dptr = strchr(ptr, '='); 541 if (dptr == NULL) 542 continue; 543 dptr++; 544 cptr1 = (char **)realloc((void *)cptr, 545 sizeof (char *) * (ccnt+2)); 546 if (cptr1 == NULL) { 547 if (sptr != &space.s_d) { 548 (void) munmap((char *)sptr, ndata); 549 } 550 __s_api_free2dArray(cptr); 551 __s_api_free2dArray(mptr); 552 mptr = NULL; 553 free(ret->server); 554 ret->server = NULL; 555 return (NS_LDAP_MEMORY); 556 } 557 cptr = cptr1; 558 cptr[ccnt] = strdup(dptr); 559 if (cptr[ccnt] == NULL) { 560 if (sptr != &space.s_d) { 561 (void) munmap((char *)sptr, ndata); 562 } 563 __s_api_free2dArray(cptr); 564 cptr = NULL; 565 __s_api_free2dArray(mptr); 566 mptr = NULL; 567 free(ret->server); 568 ret->server = NULL; 569 return (NS_LDAP_MEMORY); 570 } 571 ccnt++; 572 cptr[ccnt] = NULL; 573 } 574 } 575 if (mptr != NULL) { 576 ret->saslMechanisms = mptr; 577 } 578 if (cptr != NULL) { 579 ret->controls = cptr; 580 } 581 582 583 /* clean up door call */ 584 if (sptr != &space.s_d) { 585 (void) munmap((char *)sptr, ndata); 586 } 587 *error = NULL; 588 589 return (NS_LDAP_SUCCESS); 590 } 591 592 593 /* 594 * printCred(): prints the credential structure 595 */ 596 static void 597 printCred(int pri, const ns_cred_t *cred) 598 { 599 thread_t t = thr_self(); 600 601 if (cred == NULL) { 602 syslog(LOG_ERR, "tid= %d: printCred: cred is NULL\n", t); 603 return; 604 } 605 606 syslog(pri, "tid= %d: AuthType=%d", t, cred->auth.type); 607 syslog(pri, "tid= %d: TlsType=%d", t, cred->auth.tlstype); 608 syslog(pri, "tid= %d: SaslMech=%d", t, cred->auth.saslmech); 609 syslog(pri, "tid= %d: SaslOpt=%d", t, cred->auth.saslopt); 610 if (cred->hostcertpath) 611 syslog(pri, "tid= %d: hostCertPath=%s\n", 612 t, cred->hostcertpath); 613 if (cred->cred.unix_cred.userID) 614 syslog(pri, "tid= %d: userID=%s\n", 615 t, cred->cred.unix_cred.userID); 616 #ifdef DEBUG 617 if (cred->cred.unix_cred.passwd) 618 syslog(pri, "tid= %d: passwd=%s\n", 619 t, cred->cred.unix_cred.passwd); 620 #endif 621 } 622 623 /* 624 * printConnection(): prints the connection structure 625 */ 626 static void 627 printConnection(int pri, Connection *con) 628 { 629 thread_t t = thr_self(); 630 631 if (con == NULL) 632 return; 633 634 syslog(pri, "tid= %d: connectionID=%d\n", t, con->connectionId); 635 syslog(pri, "tid= %d: shared=%d\n", t, con->shared); 636 syslog(pri, "tid= %d: usedBit=%d\n", t, con->usedBit); 637 syslog(pri, "tid= %d: threadID=%d\n", t, con->threadID); 638 if (con->serverAddr) { 639 syslog(pri, "tid= %d: serverAddr=%s\n", 640 t, con->serverAddr); 641 } 642 printCred(pri, con->auth); 643 } 644 645 646 647 /* 648 * addConnection(): set up a connection so that it can be shared 649 * among multiple threads and then insert the connection in the 650 * connection list. 651 * Returns: -1 = failure, new Connection ID = success 652 * 653 * This function could exit with sessionLock locked. It will be 654 * be unlocked in __s_api_getConnection() when it exits without getting a 655 * connection. 656 */ 657 static int 658 addConnection(Connection *con) 659 { 660 int i, noMTperC = 0; 661 thread_t t = thr_self(); 662 struct ldap_thread_fns tfns; 663 void *tsd; 664 665 if (!con) 666 return (-1); 667 668 syslog(LOG_DEBUG, "tid= %d: Adding connection (serverAddr=%s)", 669 t, con->serverAddr); 670 671 if (MTperConn == 1) { 672 /* 673 * Make sure ld has proper thread functions and tsd 674 * is set up. 675 */ 676 (void) memset(&tfns, 0, sizeof (struct ldap_thread_fns)); 677 /* 678 * ldap_init sets ltf_get_lderrno and ltf_set_lderrno to NULLs. 679 * It's supposed to be overwritten by ns_setup_mt_conn_and_tsd. 680 */ 681 if (ldap_get_option(con->ld, LDAP_OPT_THREAD_FN_PTRS, 682 (void *)&tfns) != 0 || 683 tfns.ltf_get_lderrno != get_ld_error || 684 tfns.ltf_set_lderrno != set_ld_error) { 685 MTperConn = 0; 686 noMTperC = 1; 687 } else { 688 if (thr_getspecific(ns_mtckey, &tsd) != 0 || 689 tsd == NULL) 690 noMTperC = 1; 691 } 692 693 } else { 694 noMTperC = 1; 695 } 696 697 (void) rw_wrlock(&sessionPoolLock); 698 if (sessionPool == NULL) { 699 sessionPoolSize = SESSION_CACHE_INC; 700 sessionPool = calloc(sessionPoolSize, 701 sizeof (struct connection **)); 702 if (!sessionPool) { 703 (void) rw_unlock(&sessionPoolLock); 704 return (-1); 705 } 706 707 syslog(LOG_DEBUG, "tid= %d: Initialized sessionPool", t); 708 } 709 for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i) 710 ; 711 if (i == sessionPoolSize) { 712 /* run out of array, need to increase sessionPool */ 713 Connection **cl; 714 cl = (Connection **) realloc(sessionPool, 715 (sessionPoolSize + SESSION_CACHE_INC) * 716 sizeof (Connection *)); 717 if (!cl) { 718 (void) rw_unlock(&sessionPoolLock); 719 return (-1); 720 } 721 (void) memset(cl + sessionPoolSize, 0, 722 SESSION_CACHE_INC * sizeof (struct connection *)); 723 sessionPool = cl; 724 sessionPoolSize += SESSION_CACHE_INC; 725 syslog(LOG_DEBUG, "tid: %d: Increased " 726 "sessionPoolSize to: %d\n", 727 t, sessionPoolSize); 728 } 729 sessionPool[i] = con; 730 if (noMTperC == 0) { 731 con->shared++; 732 con->pid = getpid(); 733 (void) mutex_lock(&sharedConnNumberLock); 734 sharedConnNumber++; 735 (void) mutex_unlock(&sharedConnNumberLock); 736 } else 737 con->usedBit = B_TRUE; 738 739 (void) rw_unlock(&sessionPoolLock); 740 741 con->connectionId = i + CONID_OFFSET; 742 743 syslog(LOG_DEBUG, "tid= %d: Connection added [%d]\n", 744 t, i); 745 printConnection(LOG_DEBUG, con); 746 747 /* 748 * A connection can be shared now, unlock 749 * the session mutex and let other 750 * threads try to use this connection or 751 * get their own. 752 */ 753 if (wait4session != 0 && sessionTid == thr_self()) { 754 wait4session = 0; 755 sessionTid = 0; 756 syslog(LOG_DEBUG, "tid= %d: unlocking sessionLock\n", t); 757 (void) mutex_unlock(&sessionLock); 758 } 759 760 return (i + CONID_OFFSET); 761 } 762 763 /* 764 * See if the specified session matches a currently available 765 */ 766 767 static int 768 findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID, 769 Connection **conp) 770 { 771 Connection *cp; 772 int id; 773 774 if ((conp == NULL) || (auth == NULL) || cID < CONID_OFFSET) 775 return (-1); 776 777 /* if a new connection is requested, no need to continue */ 778 if (flags & NS_LDAP_NEW_CONN) 779 return (-1); 780 781 *conp = NULL; 782 if (sessionPool == NULL) 783 return (-1); 784 id = cID - CONID_OFFSET; 785 if (id < 0 || id >= sessionPoolSize) 786 return (-1); 787 788 (void) rw_rdlock(&sessionPoolLock); 789 if (sessionPool[id] == NULL) { 790 (void) rw_unlock(&sessionPoolLock); 791 return (-1); 792 } 793 cp = sessionPool[id]; 794 795 /* 796 * Make sure the connection has the same type of authentication method 797 */ 798 if ((cp->usedBit) || 799 (cp->notAvail) || 800 (cp->auth->auth.type != auth->auth.type) || 801 (cp->auth->auth.tlstype != auth->auth.tlstype) || 802 (cp->auth->auth.saslmech != auth->auth.saslmech) || 803 (cp->auth->auth.saslopt != auth->auth.saslopt)) { 804 (void) rw_unlock(&sessionPoolLock); 805 return (-1); 806 } 807 if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) && 808 ((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) || 809 (cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) || 810 (cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) && 811 ((cp->auth->cred.unix_cred.userID == NULL) || 812 (strcasecmp(cp->auth->cred.unix_cred.userID, 813 auth->cred.unix_cred.userID) != 0))) { 814 (void) rw_unlock(&sessionPoolLock); 815 return (-1); 816 } 817 818 /* An existing connection is found but it needs to be reset */ 819 if (flags & NS_LDAP_NEW_CONN) { 820 (void) rw_unlock(&sessionPoolLock); 821 DropConnection(cID, 0); 822 return (-1); 823 } 824 /* found an available connection */ 825 cp->usedBit = B_TRUE; 826 (void) rw_unlock(&sessionPoolLock); 827 cp->threadID = thr_self(); 828 *conp = cp; 829 return (cID); 830 } 831 832 /* 833 * findConnection(): find an available connection from the list 834 * that matches the criteria specified in Connection structure. 835 * If serverAddr is NULL, then find a connection to any server 836 * as long as it matches the rest of the parameters. 837 * Returns: -1 = failure, the Connection ID found = success. 838 * 839 * This function could exit with sessionLock locked. It will be 840 * be unlocked in addConnection() when this thread adds the connection 841 * to the pool or in __s_api_getConnection() when it exits without getting a 842 * connection. 843 */ 844 #define TRY_TIMES 10 845 static int 846 findConnection(int flags, const char *serverAddr, 847 const ns_cred_t *auth, Connection **conp) 848 { 849 Connection *cp; 850 int i; 851 int rc; 852 int try; 853 #ifdef DEBUG 854 thread_t t = thr_self(); 855 #endif /* DEBUG */ 856 857 if (auth == NULL || conp == NULL) 858 return (-1); 859 *conp = NULL; 860 861 /* if a new connection is requested, no need to continue */ 862 if (flags & NS_LDAP_NEW_CONN) 863 return (-1); 864 865 #ifdef DEBUG 866 (void) fprintf(stderr, "tid= %d: Find connection\n", t); 867 (void) fprintf(stderr, "tid= %d: Looking for ....\n", t); 868 if (serverAddr && *serverAddr) 869 (void) fprintf(stderr, "tid= %d: serverAddr=%s\n", 870 t, serverAddr); 871 else 872 (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t); 873 printCred(stderr, auth); 874 fflush(stderr); 875 #endif /* DEBUG */ 876 877 /* 878 * If multiple threads per connection not supported, 879 * no sessionPool means no connection 880 */ 881 (void) rw_rdlock(&sessionPoolLock); 882 if (MTperConn == 0 && sessionPool == NULL) { 883 (void) rw_unlock(&sessionPoolLock); 884 return (-1); 885 } 886 887 /* 888 * If no sharable connections in cache, then serialize the opening 889 * of connections. Make sure only one is being opened 890 * at a time. Otherwise, we may end up with more 891 * connections than we want (if multiple threads get 892 * here at the same time) 893 */ 894 (void) mutex_lock(&sharedConnNumberLock); 895 if (sessionPool == NULL || (sharedConnNumber == 0 && MTperConn == 1)) { 896 (void) mutex_unlock(&sharedConnNumberLock); 897 (void) rw_unlock(&sessionPoolLock); 898 (void) mutex_lock(&sessionLock); 899 (void) mutex_lock(&sharedConnNumberLock); 900 if (sessionPool == NULL || (sharedConnNumber == 0 && 901 MTperConn == 1)) { 902 (void) mutex_unlock(&sharedConnNumberLock); 903 wait4session = 1; 904 sessionTid = thr_self(); 905 #ifdef DEBUG 906 (void) fprintf(stderr, "tid= %d: get " 907 "connection ... \n", t); 908 fflush(stderr); 909 #endif /* DEBUG */ 910 /* 911 * Exit with sessionLock locked. It will be 912 * be unlocked in addConnection() when this 913 * thread adds the connection to the pool or 914 * in __s_api_getConnection() when it exits 915 * without getting a connection. 916 */ 917 return (-1); 918 } 919 920 #ifdef DEBUG 921 (void) fprintf(stderr, "tid= %d: shareable connections " 922 "exist\n", t); 923 fflush(stderr); 924 #endif /* DEBUG */ 925 (void) mutex_unlock(&sharedConnNumberLock); 926 /* 927 * There are sharable connections, check to see if 928 * one can be shared. 929 */ 930 (void) mutex_unlock(&sessionLock); 931 (void) rw_rdlock(&sessionPoolLock); 932 } else 933 (void) mutex_unlock(&sharedConnNumberLock); 934 935 try = 0; 936 check_again: 937 938 for (i = 0; i < sessionPoolSize; ++i) { 939 if (sessionPool[i] == NULL) 940 continue; 941 cp = sessionPool[i]; 942 #ifdef DEBUG 943 (void) fprintf(stderr, "tid= %d: checking connection " 944 "[%d] ....\n", t, i); 945 printConnection(stderr, cp); 946 #endif /* DEBUG */ 947 if ((cp->usedBit) || (cp->notAvail) || 948 (cp->auth->auth.type != auth->auth.type) || 949 (cp->auth->auth.tlstype != auth->auth.tlstype) || 950 (cp->auth->auth.saslmech != auth->auth.saslmech) || 951 (cp->auth->auth.saslopt != auth->auth.saslopt) || 952 (serverAddr && *serverAddr && 953 (strcasecmp(serverAddr, cp->serverAddr) != 0))) 954 continue; 955 if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) && 956 ((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) || 957 (cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) || 958 (cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) && 959 ((cp->auth->cred.unix_cred.userID == NULL) || 960 (cp->auth->cred.unix_cred.passwd == NULL) || 961 ((strcasecmp(cp->auth->cred.unix_cred.userID, 962 auth->cred.unix_cred.userID) != 0)) || 963 ((strcmp(cp->auth->cred.unix_cred.passwd, 964 auth->cred.unix_cred.passwd) != 0)))) 965 continue; 966 /* found an available connection */ 967 if (MTperConn == 0) 968 cp->usedBit = B_TRUE; 969 else { 970 /* 971 * if connection was established in a different 972 * process, drop it and get a new one 973 */ 974 if (cp->pid != getpid()) { 975 (void) rw_unlock(&sessionPoolLock); 976 DropConnection(cp->connectionId, 977 NS_LDAP_NEW_CONN); 978 979 goto get_conn; 980 } 981 /* allocate TSD for per thread ldap error */ 982 rc = tsd_setup(); 983 984 /* if we got TSD, this connection is shared */ 985 if (rc != -1) 986 cp->shared++; 987 else if (cp->shared == 0) { 988 cp->usedBit = B_TRUE; 989 cp->threadID = thr_self(); 990 (void) rw_unlock(&sessionPoolLock); 991 return (-1); 992 } 993 } 994 (void) rw_unlock(&sessionPoolLock); 995 996 *conp = cp; 997 #ifdef DEBUG 998 (void) fprintf(stderr, "tid= %d: Connection found " 999 "cID=%d, shared =%d\n", t, i, cp->shared); 1000 fflush(stderr); 1001 #endif /* DEBUG */ 1002 return (i + CONID_OFFSET); 1003 } 1004 1005 get_conn: 1006 1007 (void) rw_unlock(&sessionPoolLock); 1008 1009 /* 1010 * If multiple threads per connection not supported, 1011 * we are done, just return -1 to tell the caller to 1012 * proceed with opening a connection 1013 */ 1014 if (MTperConn == 0) 1015 return (-1); 1016 1017 /* 1018 * No connection can be shared, test to see if 1019 * one is being opened. If trylock returns 1020 * EBUSY then it is, so wait until the opening 1021 * is done and try to see if the new connection 1022 * can be shared. 1023 */ 1024 rc = mutex_trylock(&sessionLock); 1025 if (rc == EBUSY) { 1026 (void) mutex_lock(&sessionLock); 1027 (void) mutex_unlock(&sessionLock); 1028 (void) rw_rdlock(&sessionPoolLock); 1029 #ifdef DEBUG 1030 (void) fprintf(stderr, "tid= %d: check session " 1031 "pool again\n", t); 1032 fflush(stderr); 1033 #endif /* DEBUG */ 1034 if (try < TRY_TIMES) { 1035 try++; 1036 goto check_again; 1037 } else { 1038 syslog(LOG_WARNING, "libsldap: mutex_trylock " 1039 "%d times. Stop.", TRY_TIMES); 1040 (void) rw_unlock(&sessionPoolLock); 1041 return (-1); 1042 } 1043 } else if (rc == 0) { 1044 /* 1045 * No connection can be shared, none being opened, 1046 * exit with sessionLock locked to open one. The 1047 * mutex will be unlocked in addConnection() when 1048 * this thread adds the new connection to the pool 1049 * or in __s_api_getConnection() when it exits 1050 * without getting a connection. 1051 */ 1052 wait4session = 1; 1053 sessionTid = thr_self(); 1054 #ifdef DEBUG 1055 (void) fprintf(stderr, "tid= %d: no connection found, " 1056 "none being opened, get connection ...\n", t); 1057 fflush(stderr); 1058 #endif /* DEBUG */ 1059 return (-1); 1060 } else { 1061 syslog(LOG_WARNING, "libsldap: mutex_trylock unexpected " 1062 "error %d", rc); 1063 return (-1); 1064 } 1065 } 1066 1067 /* 1068 * Free a Connection structure 1069 */ 1070 static void 1071 freeConnection(Connection *con) 1072 { 1073 if (con == NULL) 1074 return; 1075 if (con->serverAddr) 1076 free(con->serverAddr); 1077 if (con->auth) 1078 (void) __ns_ldap_freeCred(&(con->auth)); 1079 if (con->saslMechanisms) { 1080 __s_api_free2dArray(con->saslMechanisms); 1081 } 1082 if (con->controls) { 1083 __s_api_free2dArray(con->controls); 1084 } 1085 free(con); 1086 } 1087 1088 /* 1089 * Find a connection matching the passed in criteria. If an open 1090 * connection with that criteria exists use it, otherwise open a 1091 * new connection. 1092 * Success: returns the pointer to the Connection structure 1093 * Failure: returns NULL, error code and message should be in errorp 1094 */ 1095 1096 static int 1097 makeConnection(Connection **conp, const char *serverAddr, 1098 const ns_cred_t *auth, ConnectionID *cID, int timeoutSec, 1099 ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd, 1100 int nopasswd_acct_mgmt, int flags, char ***badsrvrs) 1101 { 1102 Connection *con = NULL; 1103 ConnectionID id; 1104 char errmsg[MAXERROR]; 1105 int rc, exit_rc = NS_LDAP_SUCCESS; 1106 ns_server_info_t sinfo; 1107 char *hReq, *host = NULL; 1108 LDAP *ld = NULL; 1109 int passwd_mgmt = 0; 1110 int totalbad = 0; /* Number of servers contacted unsuccessfully */ 1111 short memerr = 0; /* Variable for tracking memory allocation */ 1112 char *serverAddrType = NULL; 1113 1114 1115 if (conp == NULL || errorp == NULL || auth == NULL) 1116 return (NS_LDAP_INVALID_PARAM); 1117 *errorp = NULL; 1118 *conp = NULL; 1119 sinfo.server = NULL; 1120 sinfo.controls = NULL; 1121 sinfo.saslMechanisms = NULL; 1122 1123 if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) { 1124 /* connection found in cache */ 1125 #ifdef DEBUG 1126 (void) fprintf(stderr, "tid= %d: connection found in " 1127 "cache %d\n", thr_self(), id); 1128 fflush(stderr); 1129 #endif /* DEBUG */ 1130 *cID = id; 1131 *conp = con; 1132 return (NS_LDAP_SUCCESS); 1133 } 1134 1135 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) 1136 serverAddrType = NS_CACHE_ADDR_HOSTNAME; 1137 else 1138 serverAddrType = NS_CACHE_ADDR_IP; 1139 1140 if (serverAddr) { 1141 rc = __s_api_requestServer(NS_CACHE_NEW, serverAddr, 1142 &sinfo, errorp, serverAddrType); 1143 if (rc != NS_LDAP_SUCCESS || sinfo.server == NULL) { 1144 (void) snprintf(errmsg, sizeof (errmsg), 1145 gettext("makeConnection: unable to get " 1146 "server information for %s"), serverAddr); 1147 syslog(LOG_ERR, "libsldap: %s", errmsg); 1148 return (NS_LDAP_OP_FAILED); 1149 } 1150 rc = openConnection(&ld, sinfo.server, auth, timeoutSec, errorp, 1151 fail_if_new_pwd_reqd, passwd_mgmt); 1152 if (rc == NS_LDAP_SUCCESS || rc == 1153 NS_LDAP_SUCCESS_WITH_INFO) { 1154 exit_rc = rc; 1155 goto create_con; 1156 } else { 1157 return (rc); 1158 } 1159 } 1160 1161 /* No cached connection, create one */ 1162 for (; ; ) { 1163 if (host == NULL) 1164 hReq = NS_CACHE_NEW; 1165 else 1166 hReq = NS_CACHE_NEXT; 1167 rc = __s_api_requestServer(hReq, host, &sinfo, errorp, 1168 serverAddrType); 1169 if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) || 1170 (host && (strcasecmp(host, sinfo.server) == 0))) { 1171 /* Log the error */ 1172 if (*errorp) { 1173 (void) snprintf(errmsg, sizeof (errmsg), 1174 "%s: (%s)", gettext("makeConnection: " 1175 "unable to make LDAP connection, " 1176 "request for a server failed"), 1177 (*errorp)->message); 1178 syslog(LOG_ERR, "libsldap: %s", errmsg); 1179 } 1180 1181 if (sinfo.server) 1182 free(sinfo.server); 1183 __s_api_free2dArray(sinfo.saslMechanisms); 1184 __s_api_free2dArray(sinfo.controls); 1185 if (host) 1186 free(host); 1187 return (NS_LDAP_OP_FAILED); 1188 } 1189 if (host) 1190 free(host); 1191 host = strdup(sinfo.server); 1192 if (host == NULL) { 1193 free(sinfo.server); 1194 __s_api_free2dArray(sinfo.saslMechanisms); 1195 __s_api_free2dArray(sinfo.controls); 1196 return (NS_LDAP_MEMORY); 1197 } 1198 1199 /* check if server supports password management */ 1200 passwd_mgmt = __s_api_contain_passwd_control_oid( 1201 sinfo.controls); 1202 /* check if server supports password less account mgmt */ 1203 if (nopasswd_acct_mgmt && 1204 !__s_api_contain_account_usable_control_oid( 1205 sinfo.controls)) { 1206 syslog(LOG_WARNING, "libsldap: server %s does not " 1207 "provide account information without password", 1208 host); 1209 free(host); 1210 free(sinfo.server); 1211 __s_api_free2dArray(sinfo.saslMechanisms); 1212 __s_api_free2dArray(sinfo.controls); 1213 return (NS_LDAP_OP_FAILED); 1214 } 1215 /* make the connection */ 1216 rc = openConnection(&ld, host, auth, timeoutSec, errorp, 1217 fail_if_new_pwd_reqd, passwd_mgmt); 1218 /* if success, go to create connection structure */ 1219 if (rc == NS_LDAP_SUCCESS || 1220 rc == NS_LDAP_SUCCESS_WITH_INFO) { 1221 exit_rc = rc; 1222 break; 1223 } 1224 1225 /* 1226 * If not able to reach the server, inform the ldap 1227 * cache manager that the server should be removed 1228 * from its server list. Thus, the manager will not 1229 * return this server on the next get-server request 1230 * and will also reduce the server list refresh TTL, 1231 * so that it will find out sooner when the server 1232 * is up again. 1233 */ 1234 if (rc == NS_LDAP_INTERNAL && *errorp != NULL) { 1235 if ((*errorp)->status == LDAP_CONNECT_ERROR || 1236 (*errorp)->status == LDAP_SERVER_DOWN) { 1237 /* Reset memory allocation error */ 1238 memerr = 0; 1239 /* 1240 * We contacted a server that we could 1241 * not either authenticate to or contact. 1242 * If it is due to authentication, then 1243 * we need to try the server again. So, 1244 * do not remove the server yet, but 1245 * add it to the bad server list. 1246 * The caller routine will remove 1247 * the servers if: 1248 * a). A good server is found or 1249 * b). All the possible methods 1250 * are tried without finding 1251 * a good server 1252 */ 1253 if (*badsrvrs == NULL) { 1254 if (!(*badsrvrs = (char **)malloc 1255 (sizeof (char *) * NUMTOMALLOC))) { 1256 memerr = 1; 1257 } 1258 /* Allocate memory in chunks of NUMTOMALLOC */ 1259 } else if ((totalbad % NUMTOMALLOC) == 1260 NUMTOMALLOC - 1) { 1261 char **tmpptr; 1262 if (!(tmpptr = (char **)realloc(*badsrvrs, 1263 (sizeof (char *) * NUMTOMALLOC * 1264 ((totalbad/NUMTOMALLOC) + 2))))) { 1265 memerr = 1; 1266 } else { 1267 *badsrvrs = tmpptr; 1268 } 1269 } 1270 /* 1271 * Store host only if there were no unsuccessful 1272 * memory allocations above 1273 */ 1274 if (!memerr && 1275 !((*badsrvrs)[totalbad++] = strdup(host))) { 1276 memerr = 1; 1277 totalbad--; 1278 } 1279 (*badsrvrs)[totalbad] = NULL; 1280 } 1281 } 1282 1283 /* else, cleanup and go for the next server */ 1284 if (sinfo.server) { 1285 free(sinfo.server); 1286 sinfo.server = NULL; 1287 } 1288 __s_api_free2dArray(sinfo.saslMechanisms); 1289 sinfo.saslMechanisms = NULL; 1290 __s_api_free2dArray(sinfo.controls); 1291 sinfo.controls = NULL; 1292 /* Return if we had memory allocation errors */ 1293 if (memerr) 1294 return (NS_LDAP_MEMORY); 1295 if (*errorp) { 1296 /* 1297 * If openConnection() failed due to 1298 * password policy, or invalid credential, 1299 * keep *errorp and exit 1300 */ 1301 if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD || 1302 (*errorp)->status == LDAP_INVALID_CREDENTIALS) { 1303 free(host); 1304 return (rc); 1305 } else { 1306 (void) __ns_ldap_freeError(errorp); 1307 *errorp = NULL; 1308 } 1309 } 1310 } 1311 1312 create_con: 1313 /* we have created ld, setup con structure */ 1314 if (host) 1315 free(host); 1316 if ((con = calloc(1, sizeof (Connection))) == NULL) { 1317 if (sinfo.server) 1318 free(sinfo.server); 1319 __s_api_free2dArray(sinfo.saslMechanisms); 1320 __s_api_free2dArray(sinfo.controls); 1321 /* 1322 * If password control attached in **errorp, 1323 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 1324 * free the error structure 1325 */ 1326 if (*errorp) { 1327 (void) __ns_ldap_freeError(errorp); 1328 *errorp = NULL; 1329 } 1330 return (NS_LDAP_MEMORY); 1331 } 1332 1333 con->serverAddr = sinfo.server; 1334 con->saslMechanisms = sinfo.saslMechanisms; 1335 con->controls = sinfo.controls; 1336 1337 con->auth = __ns_ldap_dupAuth(auth); 1338 if (con->auth == NULL) { 1339 free(con); 1340 /* 1341 * If password control attached in **errorp, 1342 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 1343 * free the error structure 1344 */ 1345 if (*errorp) { 1346 (void) __ns_ldap_freeError(errorp); 1347 *errorp = NULL; 1348 } 1349 return (NS_LDAP_MEMORY); 1350 } 1351 1352 con->threadID = thr_self(); 1353 con->pid = getpid(); 1354 1355 con->ld = ld; 1356 if ((id = addConnection(con)) == -1) { 1357 freeConnection(con); 1358 /* 1359 * If password control attached in **errorp, 1360 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 1361 * free the error structure 1362 */ 1363 if (*errorp) { 1364 (void) __ns_ldap_freeError(errorp); 1365 *errorp = NULL; 1366 } 1367 return (NS_LDAP_MEMORY); 1368 } 1369 #ifdef DEBUG 1370 (void) fprintf(stderr, "tid= %d: connection added into " 1371 "cache %d\n", thr_self(), id); 1372 fflush(stderr); 1373 #endif /* DEBUG */ 1374 *cID = id; 1375 *conp = con; 1376 return (exit_rc); 1377 } 1378 1379 /* 1380 * Return the specified connection to the pool. If necessary 1381 * delete the connection. 1382 */ 1383 1384 static void 1385 _DropConnection(ConnectionID cID, int flag, int fini) 1386 { 1387 Connection *cp; 1388 int id; 1389 int use_lock = !fini; 1390 #ifdef DEBUG 1391 thread_t t = thr_self(); 1392 #endif /* DEBUG */ 1393 1394 id = cID - CONID_OFFSET; 1395 if (id < 0 || id >= sessionPoolSize) 1396 return; 1397 #ifdef DEBUG 1398 (void) fprintf(stderr, "tid= %d: " 1399 "Dropping connection cID=%d flag=0x%x, fini = %d\n", 1400 t, cID, flag, fini); 1401 fflush(stderr); 1402 #endif /* DEBUG */ 1403 if (use_lock) 1404 (void) rw_wrlock(&sessionPoolLock); 1405 1406 cp = sessionPool[id]; 1407 /* sanity check before removing */ 1408 if (!cp || (!fini && !cp->shared && (!cp->usedBit || 1409 cp->threadID != thr_self()))) { 1410 #ifdef DEBUG 1411 if (cp == NULL) 1412 (void) fprintf(stderr, "tid= %d: no " 1413 "need to remove (fini = %d, cp = %p)\n", t, 1414 fini, cp); 1415 else 1416 (void) fprintf(stderr, "tid= %d: no " 1417 "need to remove (fini = %d, cp = %p, shared = %d)\n", 1418 t, fini, cp, cp->shared); 1419 fflush(stderr); 1420 #endif /* DEBUG */ 1421 if (use_lock) 1422 (void) rw_unlock(&sessionPoolLock); 1423 return; 1424 } 1425 1426 if (!fini && 1427 ((flag & NS_LDAP_NEW_CONN) == 0) && !cp->notAvail && 1428 ((flag & NS_LDAP_KEEP_CONN) || 1429 (MTperConn == 0 && nscd_proc()) || 1430 MTperConn)) { 1431 #ifdef DEBUG 1432 (void) fprintf(stderr, "tid= %d: keep alive (fini = %d " 1433 "shared = %d)\n", t, fini, cp->shared); 1434 #endif /* DEBUG */ 1435 /* release Connection (keep alive) */ 1436 if (cp->shared) 1437 cp->shared--; 1438 cp->usedBit = B_FALSE; 1439 cp->threadID = 0; /* unmark the threadID */ 1440 if (use_lock) 1441 (void) rw_unlock(&sessionPoolLock); 1442 } else { 1443 /* delete Connection (disconnect) */ 1444 if (cp->shared > 0) { 1445 #ifdef DEBUG 1446 (void) fprintf(stderr, "tid= %d: Connection no " 1447 "longer available (fini = %d, shared = %d)\n", 1448 t, fini, cp->shared); 1449 fflush(stderr); 1450 #endif /* DEBUG */ 1451 cp->shared--; 1452 /* 1453 * Mark this connection not available and decrement 1454 * sharedConnNumber. There could be multiple threads 1455 * sharing this connection so decrement 1456 * sharedConnNumber only once per connection. 1457 */ 1458 if (cp->notAvail == 0) { 1459 cp->notAvail = 1; 1460 (void) mutex_lock(&sharedConnNumberLock); 1461 sharedConnNumber--; 1462 (void) mutex_unlock(&sharedConnNumberLock); 1463 } 1464 } 1465 1466 if (cp->shared <= 0) { 1467 #ifdef DEBUG 1468 (void) fprintf(stderr, "tid= %d: unbind " 1469 "(fini = %d, shared = %d)\n", 1470 t, fini, cp->shared); 1471 fflush(stderr); 1472 #endif /* DEBUG */ 1473 sessionPool[id] = NULL; 1474 (void) ldap_unbind(cp->ld); 1475 freeConnection(cp); 1476 } 1477 1478 if (use_lock) 1479 (void) rw_unlock(&sessionPoolLock); 1480 } 1481 1482 if (MTperConn) { 1483 void *tsd; 1484 (void) thr_getspecific(ns_mtckey, &tsd); 1485 if (tsd != NULL) { 1486 ns_tsd_cleanup(tsd); 1487 (void) thr_setspecific(ns_mtckey, NULL); 1488 } 1489 } 1490 } 1491 1492 void 1493 DropConnection(ConnectionID cID, int flag) 1494 { 1495 _DropConnection(cID, flag, 0); 1496 } 1497 1498 /* 1499 * This routine is called after a bind operation is 1500 * done in openConnection() to process the password 1501 * management information, if any. 1502 * 1503 * Input: 1504 * bind_type: "simple" or "sasl/DIGEST-MD5" 1505 * ldaprc : ldap rc from the ldap bind operation 1506 * controls : controls returned by the server 1507 * errmsg : error message from the server 1508 * fail_if_new_pwd_reqd: 1509 * flag indicating if connection should be open 1510 * when password needs to change immediately 1511 * passwd_mgmt: 1512 * flag indicating if server supports password 1513 * policy/management 1514 * 1515 * Output : ns_ldap_error structure, which may contain 1516 * password status and number of seconds until 1517 * expired 1518 * 1519 * return rc: 1520 * NS_LDAP_EXTERNAL: error, connection should not open 1521 * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached 1522 * NS_LDAP_SUCCESS: OK to open connection 1523 * 1524 */ 1525 1526 static int 1527 process_pwd_mgmt(char *bind_type, int ldaprc, 1528 LDAPControl **controls, 1529 char *errmsg, ns_ldap_error_t **errorp, 1530 int fail_if_new_pwd_reqd, 1531 int passwd_mgmt) 1532 { 1533 char errstr[MAXERROR]; 1534 LDAPControl **ctrl = NULL; 1535 int exit_rc; 1536 ns_ldap_passwd_status_t pwd_status = NS_PASSWD_GOOD; 1537 int sec_until_exp = 0; 1538 1539 /* 1540 * errmsg may be an empty string, 1541 * even if ldaprc is LDAP_SUCCESS, 1542 * free the empty string if that's the case 1543 */ 1544 if (errmsg && 1545 (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) { 1546 ldap_memfree(errmsg); 1547 errmsg = NULL; 1548 } 1549 1550 if (ldaprc != LDAP_SUCCESS) { 1551 /* 1552 * try to map ldap rc and error message to 1553 * a password status 1554 */ 1555 if (errmsg) { 1556 if (passwd_mgmt) 1557 pwd_status = 1558 __s_api_set_passwd_status( 1559 ldaprc, errmsg); 1560 ldap_memfree(errmsg); 1561 } 1562 1563 (void) snprintf(errstr, sizeof (errstr), 1564 gettext("openConnection: " 1565 "%s bind failed " 1566 "- %s"), bind_type, ldap_err2string(ldaprc)); 1567 1568 if (pwd_status != NS_PASSWD_GOOD) { 1569 MKERROR_PWD_MGMT(*errorp, 1570 ldaprc, strdup(errstr), 1571 pwd_status, 0, NULL); 1572 } else { 1573 MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr), 1574 NULL); 1575 } 1576 if (controls) 1577 ldap_controls_free(controls); 1578 1579 return (NS_LDAP_INTERNAL); 1580 } 1581 1582 /* 1583 * ldaprc is LDAP_SUCCESS, 1584 * process the password management controls, if any 1585 */ 1586 exit_rc = NS_LDAP_SUCCESS; 1587 if (controls && passwd_mgmt) { 1588 /* 1589 * The control with the OID 1590 * 2.16.840.1.113730.3.4.4 (or 1591 * LDAP_CONTROL_PWEXPIRED, as defined 1592 * in the ldap.h header file) is the 1593 * expired password control. 1594 * 1595 * This control is used if the server 1596 * is configured to require users to 1597 * change their passwords when first 1598 * logging in and whenever the 1599 * passwords are reset. 1600 * 1601 * If the user is logging in for the 1602 * first time or if the user's 1603 * password has been reset, the 1604 * server sends this control to 1605 * indicate that the client needs to 1606 * change the password immediately. 1607 * 1608 * At this point, the only operation 1609 * that the client can perform is to 1610 * change the user's password. If the 1611 * client requests any other LDAP 1612 * operation, the server sends back 1613 * an LDAP_UNWILLING_TO_PERFORM 1614 * result code with an expired 1615 * password control. 1616 * 1617 * The control with the OID 1618 * 2.16.840.1.113730.3.4.5 (or 1619 * LDAP_CONTROL_PWEXPIRING, as 1620 * defined in the ldap.h header file) 1621 * is the password expiration warning 1622 * control. 1623 * 1624 * This control is used if the server 1625 * is configured to expire user 1626 * passwords after a certain amount 1627 * of time. 1628 * 1629 * The server sends this control back 1630 * to the client if the client binds 1631 * using a password that will soon 1632 * expire. The ldctl_value field of 1633 * the LDAPControl structure 1634 * specifies the number of seconds 1635 * before the password will expire. 1636 */ 1637 for (ctrl = controls; *ctrl; ctrl++) { 1638 1639 if (strcmp((*ctrl)->ldctl_oid, 1640 LDAP_CONTROL_PWEXPIRED) == 0) { 1641 /* 1642 * if the caller wants this bind 1643 * to fail, set up the error info. 1644 * If call to this function is 1645 * for searching the LDAP directory, 1646 * e.g., __ns_ldap_list(), 1647 * there's really no sense to 1648 * let a connection open and 1649 * then fail immediately afterward 1650 * on the LDAP search operation with 1651 * the LDAP_UNWILLING_TO_PERFORM rc 1652 */ 1653 pwd_status = 1654 NS_PASSWD_CHANGE_NEEDED; 1655 if (fail_if_new_pwd_reqd) { 1656 (void) snprintf(errstr, 1657 sizeof (errstr), 1658 gettext( 1659 "openConnection: " 1660 "%s bind " 1661 "failed " 1662 "- password " 1663 "expired. It " 1664 " needs to change " 1665 "immediately!"), 1666 bind_type); 1667 MKERROR_PWD_MGMT(*errorp, 1668 LDAP_SUCCESS, 1669 strdup(errstr), 1670 pwd_status, 1671 0, 1672 NULL); 1673 exit_rc = NS_LDAP_INTERNAL; 1674 } else { 1675 MKERROR_PWD_MGMT(*errorp, 1676 LDAP_SUCCESS, 1677 NULL, 1678 pwd_status, 1679 0, 1680 NULL); 1681 exit_rc = 1682 NS_LDAP_SUCCESS_WITH_INFO; 1683 } 1684 break; 1685 } else if (strcmp((*ctrl)->ldctl_oid, 1686 LDAP_CONTROL_PWEXPIRING) == 0) { 1687 pwd_status = 1688 NS_PASSWD_ABOUT_TO_EXPIRE; 1689 if ((*ctrl)-> 1690 ldctl_value.bv_len > 0 && 1691 (*ctrl)-> 1692 ldctl_value.bv_val) 1693 sec_until_exp = 1694 atoi((*ctrl)-> 1695 ldctl_value.bv_val); 1696 MKERROR_PWD_MGMT(*errorp, 1697 LDAP_SUCCESS, 1698 NULL, 1699 pwd_status, 1700 sec_until_exp, 1701 NULL); 1702 exit_rc = 1703 NS_LDAP_SUCCESS_WITH_INFO; 1704 break; 1705 } 1706 } 1707 } 1708 1709 if (controls) 1710 ldap_controls_free(controls); 1711 1712 return (exit_rc); 1713 } 1714 1715 static int 1716 ldap_in_hosts_switch() 1717 { 1718 enum __nsw_parse_err pserr; 1719 struct __nsw_switchconfig *conf; 1720 struct __nsw_lookup *lkp; 1721 const char *name; 1722 int found = 0; 1723 1724 conf = __nsw_getconfig("hosts", &pserr); 1725 if (conf == NULL) { 1726 return (-1); 1727 } 1728 1729 /* check for skip and count other backends */ 1730 for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 1731 name = lkp->service_name; 1732 if (strcmp(name, "ldap") == 0) { 1733 found = 1; 1734 break; 1735 } 1736 } 1737 __nsw_freeconfig(conf); 1738 return (found); 1739 } 1740 1741 static int 1742 openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, 1743 int timeoutSec, ns_ldap_error_t **errorp, 1744 int fail_if_new_pwd_reqd, int passwd_mgmt) 1745 { 1746 LDAP *ld = NULL; 1747 char *binddn, *passwd; 1748 char *digest_md5_name; 1749 const char *s; 1750 int ldapVersion = LDAP_VERSION3; 1751 int derefOption = LDAP_DEREF_ALWAYS; 1752 int zero = 0; 1753 int rc; 1754 char errstr[MAXERROR]; 1755 int errnum = 0; 1756 LDAPMessage *resultMsg; 1757 int msgId; 1758 int useSSL = 0, port = 0; 1759 struct timeval tv; 1760 AuthType_t bindType; 1761 int timeoutMilliSec = timeoutSec * 1000; 1762 struct berval cred; 1763 char *sslServerAddr; 1764 char *s1; 1765 char *errmsg, *end = NULL; 1766 LDAPControl **controls; 1767 int pwd_rc, min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF; 1768 ns_sasl_cb_param_t sasl_param; 1769 1770 *errorp = NULL; 1771 *ldp = NULL; 1772 1773 switch (auth->auth.type) { 1774 case NS_LDAP_AUTH_NONE: 1775 case NS_LDAP_AUTH_SIMPLE: 1776 case NS_LDAP_AUTH_SASL: 1777 bindType = auth->auth.type; 1778 break; 1779 case NS_LDAP_AUTH_TLS: 1780 useSSL = 1; 1781 switch (auth->auth.tlstype) { 1782 case NS_LDAP_TLS_NONE: 1783 bindType = NS_LDAP_AUTH_NONE; 1784 break; 1785 case NS_LDAP_TLS_SIMPLE: 1786 bindType = NS_LDAP_AUTH_SIMPLE; 1787 break; 1788 case NS_LDAP_TLS_SASL: 1789 bindType = NS_LDAP_AUTH_SASL; 1790 break; 1791 default: 1792 (void) sprintf(errstr, 1793 gettext("openConnection: unsupported " 1794 "TLS authentication method " 1795 "(%d)"), auth->auth.tlstype); 1796 MKERROR(LOG_WARNING, *errorp, 1797 LDAP_AUTH_METHOD_NOT_SUPPORTED, 1798 strdup(errstr), NULL); 1799 return (NS_LDAP_INTERNAL); 1800 } 1801 break; 1802 default: 1803 (void) sprintf(errstr, 1804 gettext("openConnection: unsupported " 1805 "authentication method (%d)"), auth->auth.type); 1806 MKERROR(LOG_WARNING, *errorp, 1807 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 1808 NULL); 1809 return (NS_LDAP_INTERNAL); 1810 } 1811 1812 if (useSSL) { 1813 const char *hostcertpath; 1814 char *alloc_hcp = NULL; 1815 #ifdef DEBUG 1816 (void) fprintf(stderr, "tid= %d: +++TLS transport\n", 1817 thr_self()); 1818 #endif /* DEBUG */ 1819 1820 if (prldap_set_session_option(NULL, NULL, 1821 PRLDAP_OPT_IO_MAX_TIMEOUT, 1822 timeoutMilliSec) != LDAP_SUCCESS) { 1823 (void) snprintf(errstr, sizeof (errstr), 1824 gettext("openConnection: failed to initialize " 1825 "TLS security")); 1826 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 1827 strdup(errstr), NULL); 1828 return (NS_LDAP_INTERNAL); 1829 } 1830 1831 hostcertpath = auth->hostcertpath; 1832 if (hostcertpath == NULL) { 1833 alloc_hcp = __s_get_hostcertpath(); 1834 hostcertpath = alloc_hcp; 1835 } 1836 1837 if (hostcertpath == NULL) 1838 return (NS_LDAP_MEMORY); 1839 1840 if ((rc = ldapssl_client_init(hostcertpath, NULL)) < 0) { 1841 if (alloc_hcp) 1842 free(alloc_hcp); 1843 (void) snprintf(errstr, sizeof (errstr), 1844 gettext("openConnection: failed to initialize " 1845 "TLS security (%s)"), 1846 ldapssl_err2string(rc)); 1847 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 1848 strdup(errstr), NULL); 1849 return (NS_LDAP_INTERNAL); 1850 } 1851 if (alloc_hcp) 1852 free(alloc_hcp); 1853 1854 /* determine if the host name contains a port number */ 1855 s = strchr(serverAddr, ']'); /* skip over ipv6 addr */ 1856 if (s == NULL) 1857 s = serverAddr; 1858 s = strchr(s, ':'); 1859 if (s != NULL) { 1860 /* 1861 * If we do get a port number, we will try stripping 1862 * it. At present, referrals will always have a 1863 * port number. 1864 */ 1865 sslServerAddr = strdup(serverAddr); 1866 if (sslServerAddr == NULL) 1867 return (NS_LDAP_MEMORY); 1868 s1 = strrchr(sslServerAddr, ':'); 1869 if (s1 != NULL) 1870 *s1 = '\0'; 1871 (void) snprintf(errstr, sizeof (errstr), 1872 gettext("openConnection: cannot use tls with %s. " 1873 "Trying %s"), 1874 serverAddr, sslServerAddr); 1875 syslog(LOG_ERR, "libsldap: %s", errstr); 1876 } else 1877 sslServerAddr = (char *)serverAddr; 1878 1879 ld = ldapssl_init(sslServerAddr, LDAPS_PORT, 1); 1880 1881 if (sslServerAddr != serverAddr) 1882 free(sslServerAddr); 1883 1884 if (ld == NULL || 1885 ldapssl_install_gethostbyaddr(ld, "ldap") != 0) { 1886 (void) snprintf(errstr, sizeof (errstr), 1887 gettext("openConnection: failed to connect " 1888 "using TLS (%s)"), strerror(errno)); 1889 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 1890 strdup(errstr), NULL); 1891 return (NS_LDAP_INTERNAL); 1892 } 1893 } else { 1894 #ifdef DEBUG 1895 (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n", 1896 thr_self()); 1897 #endif /* DEBUG */ 1898 port = LDAP_PORT; 1899 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI && 1900 (end = strchr(serverAddr, ':')) != NULL) { 1901 /* 1902 * The IP is converted to hostname so it's a 1903 * hostname:port up to this point. 1904 * 1905 * libldap passes hostname:port to the sasl layer. 1906 * The ldap service principal is constructed as 1907 * ldap/hostname:port@REALM. Kerberos authentication 1908 * will fail. So it needs to be parsed to construct 1909 * a valid principal ldap/hostname@REALM. 1910 * 1911 * For useSSL case above, it already parses port so 1912 * no need to parse serverAddr 1913 */ 1914 *end = '\0'; 1915 port = atoi(end + 1); 1916 } 1917 1918 /* Warning message IF cannot connect to host(s) */ 1919 if ((ld = ldap_init((char *)serverAddr, port)) == NULL) { 1920 char *p = strerror(errno); 1921 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 1922 strdup(p), NULL); 1923 if (end) 1924 *end = ':'; 1925 return (NS_LDAP_INTERNAL); 1926 } else { 1927 if (end) 1928 *end = ':'; 1929 /* check and avoid gethostname recursion */ 1930 if (ldap_in_hosts_switch() > 0 && 1931 ! __s_api_isipv4((char *)serverAddr) && 1932 ! __s_api_isipv6((char *)serverAddr)) { 1933 /* host: ldap - found, attempt to recover */ 1934 if (ldap_set_option(ld, LDAP_X_OPT_DNS_SKIPDB, 1935 "ldap") != 0) { 1936 (void) snprintf(errstr, sizeof (errstr), 1937 gettext("openConnection: " 1938 "unrecoverable gethostname " 1939 "recursion detected " 1940 "in /etc/nsswitch.conf")); 1941 MKERROR(LOG_WARNING, *errorp, 1942 LDAP_CONNECT_ERROR, 1943 strdup(errstr), NULL); 1944 (void) ldap_unbind(ld); 1945 return (NS_LDAP_INTERNAL); 1946 } 1947 } 1948 } 1949 } 1950 1951 ns_setup_mt_conn_and_tsd(ld); 1952 (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); 1953 (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 1954 /* 1955 * set LDAP_OPT_REFERRALS to OFF. 1956 * This library will handle the referral itself 1957 * based on API flags or configuration file 1958 * specification. If this option is not set 1959 * to OFF, libldap will never pass the 1960 * referral info up to this library 1961 */ 1962 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 1963 (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 1964 (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 1965 /* setup TCP/IP connect timeout */ 1966 (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 1967 &timeoutMilliSec); 1968 /* retry if LDAP I/O was interrupted */ 1969 (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 1970 1971 switch (bindType) { 1972 case NS_LDAP_AUTH_NONE: 1973 #ifdef DEBUG 1974 (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n", 1975 thr_self()); 1976 #endif /* DEBUG */ 1977 break; 1978 case NS_LDAP_AUTH_SIMPLE: 1979 binddn = auth->cred.unix_cred.userID; 1980 passwd = auth->cred.unix_cred.passwd; 1981 if (passwd == NULL || *passwd == '\0' || 1982 binddn == NULL || *binddn == '\0') { 1983 (void) sprintf(errstr, gettext("openConnection: " 1984 "missing credentials for Simple bind")); 1985 MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS, 1986 strdup(errstr), NULL); 1987 (void) ldap_unbind(ld); 1988 return (NS_LDAP_INTERNAL); 1989 } 1990 1991 #ifdef DEBUG 1992 (void) fprintf(stderr, "tid= %d: +++Simple bind\n", 1993 thr_self()); 1994 #endif /* DEBUG */ 1995 msgId = ldap_simple_bind(ld, binddn, passwd); 1996 1997 if (msgId == -1) { 1998 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 1999 (void *)&errnum); 2000 (void) snprintf(errstr, sizeof (errstr), 2001 gettext("openConnection: simple bind failed " 2002 "- %s"), ldap_err2string(errnum)); 2003 (void) ldap_unbind(ld); 2004 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 2005 NULL); 2006 return (NS_LDAP_INTERNAL); 2007 } 2008 2009 tv.tv_sec = timeoutSec; 2010 tv.tv_usec = 0; 2011 rc = ldap_result(ld, msgId, 0, &tv, &resultMsg); 2012 2013 if ((rc == -1) || (rc == 0)) { 2014 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 2015 (void *)&errnum); 2016 (void) snprintf(errstr, sizeof (errstr), 2017 gettext("openConnection: simple bind failed " 2018 "- %s"), ldap_err2string(errnum)); 2019 (void) ldap_msgfree(resultMsg); 2020 (void) ldap_unbind(ld); 2021 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 2022 NULL); 2023 return (NS_LDAP_INTERNAL); 2024 } 2025 2026 /* 2027 * get ldaprc, controls, and error msg 2028 */ 2029 rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 2030 &errmsg, NULL, &controls, 1); 2031 2032 if (rc != LDAP_SUCCESS) { 2033 (void) snprintf(errstr, sizeof (errstr), 2034 gettext("openConnection: simple bind failed " 2035 "- unable to parse result")); 2036 (void) ldap_unbind(ld); 2037 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2038 strdup(errstr), NULL); 2039 return (NS_LDAP_INTERNAL); 2040 } 2041 2042 /* process the password management info, if any */ 2043 pwd_rc = process_pwd_mgmt("simple", 2044 errnum, controls, errmsg, 2045 errorp, 2046 fail_if_new_pwd_reqd, 2047 passwd_mgmt); 2048 2049 if (pwd_rc == NS_LDAP_INTERNAL) { 2050 (void) ldap_unbind(ld); 2051 return (pwd_rc); 2052 } 2053 2054 if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) { 2055 *ldp = ld; 2056 return (pwd_rc); 2057 } 2058 2059 break; 2060 case NS_LDAP_AUTH_SASL: 2061 if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE && 2062 auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 2063 (void) sprintf(errstr, 2064 gettext("openConnection: SASL options are " 2065 "not supported (%d) for non-GSSAPI sasl bind"), 2066 auth->auth.saslopt); 2067 MKERROR(LOG_WARNING, *errorp, 2068 LDAP_AUTH_METHOD_NOT_SUPPORTED, 2069 strdup(errstr), NULL); 2070 (void) ldap_unbind(ld); 2071 return (NS_LDAP_INTERNAL); 2072 } 2073 if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 2074 binddn = auth->cred.unix_cred.userID; 2075 passwd = auth->cred.unix_cred.passwd; 2076 if (passwd == NULL || *passwd == '\0' || 2077 binddn == NULL || *binddn == '\0') { 2078 (void) sprintf(errstr, 2079 gettext("openConnection: missing credentials " 2080 "for SASL bind")); 2081 MKERROR(LOG_WARNING, *errorp, 2082 LDAP_INVALID_CREDENTIALS, 2083 strdup(errstr), NULL); 2084 (void) ldap_unbind(ld); 2085 return (NS_LDAP_INTERNAL); 2086 } 2087 cred.bv_val = passwd; 2088 cred.bv_len = strlen(passwd); 2089 } 2090 2091 switch (auth->auth.saslmech) { 2092 case NS_LDAP_SASL_CRAM_MD5: 2093 /* 2094 * NOTE: if iDS changes to support cram_md5, 2095 * please add password management code here. 2096 * Since ldap_sasl_cram_md5_bind_s does not 2097 * return anything that could be used to 2098 * extract the ldap rc/errmsg/control to 2099 * determine if bind failed due to password 2100 * policy, a new cram_md5_bind API will need 2101 * to be introduced. See 2102 * ldap_x_sasl_digest_md5_bind() and case 2103 * NS_LDAP_SASL_DIGEST_MD5 below for details. 2104 */ 2105 if ((rc = ldap_sasl_cram_md5_bind_s(ld, binddn, 2106 &cred, NULL, NULL)) != LDAP_SUCCESS) { 2107 (void) ldap_get_option(ld, 2108 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 2109 (void) snprintf(errstr, sizeof (errstr), 2110 gettext("openConnection: " 2111 "sasl/CRAM-MD5 bind failed - %s"), 2112 ldap_err2string(errnum)); 2113 MKERROR(LOG_WARNING, *errorp, errnum, 2114 strdup(errstr), NULL); 2115 (void) ldap_unbind(ld); 2116 return (NS_LDAP_INTERNAL); 2117 } 2118 break; 2119 case NS_LDAP_SASL_DIGEST_MD5: 2120 digest_md5_name = malloc(strlen(binddn) + 5); 2121 /* 5 = strlen("dn: ") + 1 */ 2122 if (digest_md5_name == NULL) { 2123 (void) ldap_unbind(ld); 2124 return (NS_LDAP_MEMORY); 2125 } 2126 (void) strcpy(digest_md5_name, "dn: "); 2127 (void) strcat(digest_md5_name, binddn); 2128 2129 tv.tv_sec = timeoutSec; 2130 tv.tv_usec = 0; 2131 rc = ldap_x_sasl_digest_md5_bind(ld, 2132 digest_md5_name, &cred, NULL, NULL, 2133 &tv, &resultMsg); 2134 2135 if (resultMsg == NULL) { 2136 free(digest_md5_name); 2137 (void) ldap_get_option(ld, 2138 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 2139 (void) snprintf(errstr, sizeof (errstr), 2140 gettext("openConnection: " 2141 "DIGEST-MD5 bind failed - %s"), 2142 ldap_err2string(errnum)); 2143 (void) ldap_unbind(ld); 2144 MKERROR(LOG_WARNING, *errorp, errnum, 2145 strdup(errstr), NULL); 2146 return (NS_LDAP_INTERNAL); 2147 } 2148 2149 /* 2150 * get ldaprc, controls, and error msg 2151 */ 2152 rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 2153 &errmsg, NULL, &controls, 1); 2154 2155 if (rc != LDAP_SUCCESS) { 2156 free(digest_md5_name); 2157 (void) snprintf(errstr, sizeof (errstr), 2158 gettext("openConnection: " 2159 "DIGEST-MD5 bind failed " 2160 "- unable to parse result")); 2161 (void) ldap_unbind(ld); 2162 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2163 strdup(errstr), NULL); 2164 return (NS_LDAP_INTERNAL); 2165 } 2166 2167 /* process the password management info, if any */ 2168 pwd_rc = process_pwd_mgmt("sasl/DIGEST-MD5", 2169 errnum, controls, errmsg, 2170 errorp, 2171 fail_if_new_pwd_reqd, 2172 passwd_mgmt); 2173 2174 if (pwd_rc == NS_LDAP_INTERNAL) { 2175 free(digest_md5_name); 2176 (void) ldap_unbind(ld); 2177 return (pwd_rc); 2178 } 2179 2180 if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) { 2181 *ldp = ld; 2182 return (pwd_rc); 2183 } 2184 2185 free(digest_md5_name); 2186 break; 2187 case NS_LDAP_SASL_GSSAPI: 2188 if (sasl_gssapi_inited == 0) { 2189 rc = __s_api_sasl_gssapi_init(); 2190 if (rc != NS_LDAP_SUCCESS) { 2191 (void) snprintf(errstr, sizeof (errstr), 2192 gettext("openConnection: " 2193 "GSSAPI initialization " 2194 "failed")); 2195 (void) ldap_unbind(ld); 2196 MKERROR(LOG_WARNING, *errorp, rc, 2197 strdup(errstr), NULL); 2198 return (rc); 2199 } 2200 } 2201 (void) memset(&sasl_param, 0, 2202 sizeof (ns_sasl_cb_param_t)); 2203 sasl_param.authid = NULL; 2204 sasl_param.authzid = ""; 2205 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN, 2206 (void *)&min_ssf); 2207 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX, 2208 (void *)&max_ssf); 2209 2210 rc = ldap_sasl_interactive_bind_s( 2211 ld, NULL, "GSSAPI", 2212 NULL, NULL, LDAP_SASL_INTERACTIVE, 2213 __s_api_sasl_bind_callback, 2214 &sasl_param); 2215 2216 if (rc != LDAP_SUCCESS) { 2217 (void) snprintf(errstr, sizeof (errstr), 2218 gettext("openConnection: " 2219 "GSSAPI bind failed " 2220 "- %d %s"), rc, ldap_err2string(rc)); 2221 (void) ldap_unbind(ld); 2222 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2223 strdup(errstr), NULL); 2224 return (NS_LDAP_INTERNAL); 2225 } 2226 2227 break; 2228 default: 2229 (void) ldap_unbind(ld); 2230 (void) sprintf(errstr, 2231 gettext("openConnection: unsupported SASL " 2232 "mechanism (%d)"), auth->auth.saslmech); 2233 MKERROR(LOG_WARNING, *errorp, 2234 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 2235 NULL); 2236 return (NS_LDAP_INTERNAL); 2237 } 2238 } 2239 2240 *ldp = ld; 2241 return (NS_LDAP_SUCCESS); 2242 } 2243 2244 /* 2245 * FUNCTION: __s_api_getDefaultAuth 2246 * 2247 * Constructs a credential for authentication using the config module. 2248 * 2249 * RETURN VALUES: 2250 * 2251 * NS_LDAP_SUCCESS If successful 2252 * NS_LDAP_CONFIG If there are any config errors. 2253 * NS_LDAP_MEMORY Memory errors. 2254 * NS_LDAP_OP_FAILED If there are no more authentication methods so can 2255 * not build a new authp. 2256 * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the 2257 * necessary fields of a cred for a given auth method 2258 * are not provided. 2259 * INPUT: 2260 * 2261 * cLevel Currently requested credential level to be tried 2262 * 2263 * aMethod Currently requested authentication method to be tried 2264 * 2265 * OUTPUT: 2266 * 2267 * authp authentication method to use. 2268 */ 2269 static int 2270 __s_api_getDefaultAuth( 2271 int *cLevel, 2272 ns_auth_t *aMethod, 2273 ns_cred_t **authp) 2274 { 2275 void **paramVal = NULL; 2276 char *modparamVal = NULL; 2277 int getUid = 0; 2278 int getPasswd = 0; 2279 int getCertpath = 0; 2280 int rc = 0; 2281 ns_ldap_error_t *errorp = NULL; 2282 2283 #ifdef DEBUG 2284 (void) fprintf(stderr, "__s_api_getDefaultAuth START\n"); 2285 #endif 2286 2287 if (aMethod == NULL) { 2288 /* Require an Auth */ 2289 return (NS_LDAP_INVALID_PARAM); 2290 2291 } 2292 /* 2293 * credential level "self" can work with auth method sasl/GSSAPI only 2294 */ 2295 if (cLevel && *cLevel == NS_LDAP_CRED_SELF && 2296 aMethod->saslmech != NS_LDAP_SASL_GSSAPI) 2297 return (NS_LDAP_INVALID_PARAM); 2298 2299 *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t)); 2300 if ((*authp) == NULL) 2301 return (NS_LDAP_MEMORY); 2302 2303 (*authp)->auth = *aMethod; 2304 2305 switch (aMethod->type) { 2306 case NS_LDAP_AUTH_NONE: 2307 return (NS_LDAP_SUCCESS); 2308 case NS_LDAP_AUTH_SIMPLE: 2309 getUid++; 2310 getPasswd++; 2311 break; 2312 case NS_LDAP_AUTH_SASL: 2313 if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 2314 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) { 2315 getUid++; 2316 getPasswd++; 2317 } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) { 2318 (void) __ns_ldap_freeCred(authp); 2319 *authp = NULL; 2320 return (NS_LDAP_INVALID_PARAM); 2321 } 2322 break; 2323 case NS_LDAP_AUTH_TLS: 2324 if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) || 2325 ((aMethod->tlstype == NS_LDAP_TLS_SASL) && 2326 ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 2327 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) { 2328 getUid++; 2329 getPasswd++; 2330 getCertpath++; 2331 } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) { 2332 getCertpath++; 2333 } else { 2334 (void) __ns_ldap_freeCred(authp); 2335 *authp = NULL; 2336 return (NS_LDAP_INVALID_PARAM); 2337 } 2338 break; 2339 } 2340 2341 if (getUid) { 2342 paramVal = NULL; 2343 if ((rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P, 2344 ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 2345 (void) __ns_ldap_freeCred(authp); 2346 (void) __ns_ldap_freeError(&errorp); 2347 *authp = NULL; 2348 return (rc); 2349 } 2350 2351 if (paramVal == NULL || *paramVal == NULL) { 2352 (void) __ns_ldap_freeCred(authp); 2353 *authp = NULL; 2354 return (NS_LDAP_INVALID_PARAM); 2355 } 2356 2357 (*authp)->cred.unix_cred.userID = strdup((char *)*paramVal); 2358 (void) __ns_ldap_freeParam(¶mVal); 2359 if ((*authp)->cred.unix_cred.userID == NULL) { 2360 (void) __ns_ldap_freeCred(authp); 2361 *authp = NULL; 2362 return (NS_LDAP_MEMORY); 2363 } 2364 } 2365 if (getPasswd) { 2366 paramVal = NULL; 2367 if ((rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P, 2368 ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 2369 (void) __ns_ldap_freeCred(authp); 2370 (void) __ns_ldap_freeError(&errorp); 2371 *authp = NULL; 2372 return (rc); 2373 } 2374 2375 if (paramVal == NULL || *paramVal == NULL) { 2376 (void) __ns_ldap_freeCred(authp); 2377 *authp = NULL; 2378 return (NS_LDAP_INVALID_PARAM); 2379 } 2380 2381 modparamVal = dvalue((char *)*paramVal); 2382 (void) __ns_ldap_freeParam(¶mVal); 2383 if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) { 2384 (void) __ns_ldap_freeCred(authp); 2385 if (modparamVal != NULL) 2386 free(modparamVal); 2387 *authp = NULL; 2388 return (NS_LDAP_INVALID_PARAM); 2389 } 2390 2391 (*authp)->cred.unix_cred.passwd = modparamVal; 2392 } 2393 if (getCertpath) { 2394 paramVal = NULL; 2395 if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 2396 ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 2397 (void) __ns_ldap_freeCred(authp); 2398 (void) __ns_ldap_freeError(&errorp); 2399 *authp = NULL; 2400 return (rc); 2401 } 2402 2403 if (paramVal == NULL || *paramVal == NULL) { 2404 (void) __ns_ldap_freeCred(authp); 2405 *authp = NULL; 2406 return (NS_LDAP_INVALID_PARAM); 2407 } 2408 2409 (*authp)->hostcertpath = strdup((char *)*paramVal); 2410 (void) __ns_ldap_freeParam(¶mVal); 2411 if ((*authp)->hostcertpath == NULL) { 2412 (void) __ns_ldap_freeCred(authp); 2413 *authp = NULL; 2414 return (NS_LDAP_MEMORY); 2415 } 2416 } 2417 return (NS_LDAP_SUCCESS); 2418 } 2419 2420 /* 2421 * FUNCTION: __s_api_getConnection 2422 * 2423 * Bind to the specified server or one from the server 2424 * list and return the pointer. 2425 * 2426 * This function can rebind or not (NS_LDAP_HARD), it can require a 2427 * credential or bind anonymously 2428 * 2429 * This function follows the DUA configuration schema algorithm 2430 * 2431 * RETURN VALUES: 2432 * 2433 * NS_LDAP_SUCCESS A connection was made successfully. 2434 * NS_LDAP_SUCCESS_WITH_INFO 2435 * A connection was made successfully, but with 2436 * password management info in *errorp 2437 * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function. 2438 * NS_LDAP_CONFIG If there are any config errors. 2439 * NS_LDAP_MEMORY Memory errors. 2440 * NS_LDAP_INTERNAL If there was a ldap error. 2441 * 2442 * INPUT: 2443 * 2444 * server Bind to this LDAP server only 2445 * flags If NS_LDAP_HARD is set function will not return until it has 2446 * a connection unless there is a authentication problem. 2447 * If NS_LDAP_NEW_CONN is set the function must force a new 2448 * connection to be created 2449 * If NS_LDAP_KEEP_CONN is set the connection is to be kept open 2450 * auth Credentials for bind. This could be NULL in which case 2451 * a default cred built from the config module is used. 2452 * sessionId cookie that points to a previous session 2453 * fail_if_new_pwd_reqd 2454 * a flag indicating this function should fail if the passwd 2455 * in auth needs to change immediately 2456 * nopasswd_acct_mgmt 2457 * a flag indicating that makeConnection should check before 2458 * binding if server supports LDAP V3 password less 2459 * account management 2460 * 2461 * OUTPUT: 2462 * 2463 * session pointer to a session with connection information 2464 * errorp Set if there are any INTERNAL, or CONFIG error. 2465 */ 2466 int 2467 __s_api_getConnection( 2468 const char *server, 2469 const int flags, 2470 const ns_cred_t *cred, /* credentials for bind */ 2471 ConnectionID *sessionId, 2472 Connection **session, 2473 ns_ldap_error_t **errorp, 2474 int fail_if_new_pwd_reqd, 2475 int nopasswd_acct_mgmt) 2476 { 2477 char errmsg[MAXERROR]; 2478 ns_auth_t **aMethod = NULL; 2479 ns_auth_t **aNext = NULL; 2480 int **cLevel = NULL; 2481 int **cNext = NULL; 2482 int timeoutSec = NS_DEFAULT_BIND_TIMEOUT; 2483 int rc; 2484 Connection *con = NULL; 2485 int sec = 1; 2486 ns_cred_t *authp = NULL; 2487 ns_cred_t anon; 2488 int version = NS_LDAP_V2, self_gssapi_only = 0; 2489 void **paramVal = NULL; 2490 char **badSrvrs = NULL; /* List of problem hostnames */ 2491 2492 if ((session == NULL) || (sessionId == NULL)) { 2493 return (NS_LDAP_INVALID_PARAM); 2494 } 2495 *session = NULL; 2496 2497 /* if we already have a session id try to reuse connection */ 2498 if (*sessionId > 0) { 2499 rc = findConnectionById(flags, cred, *sessionId, &con); 2500 if (rc == *sessionId && con) { 2501 *session = con; 2502 return (NS_LDAP_SUCCESS); 2503 } 2504 *sessionId = 0; 2505 } 2506 2507 /* get profile version number */ 2508 if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, 2509 ¶mVal, errorp)) != NS_LDAP_SUCCESS) 2510 return (rc); 2511 if (paramVal == NULL) { 2512 (void) sprintf(errmsg, gettext("getConnection: no file " 2513 "version")); 2514 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg), 2515 NS_LDAP_CONFIG); 2516 return (NS_LDAP_CONFIG); 2517 } 2518 if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0) 2519 version = NS_LDAP_V1; 2520 (void) __ns_ldap_freeParam((void ***)¶mVal); 2521 2522 /* Get the bind timeout value */ 2523 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp); 2524 if (paramVal != NULL && *paramVal != NULL) { 2525 timeoutSec = **((int **)paramVal); 2526 (void) __ns_ldap_freeParam(¶mVal); 2527 } 2528 if (*errorp) 2529 (void) __ns_ldap_freeError(errorp); 2530 2531 if (cred == NULL) { 2532 /* Get the authentication method list */ 2533 if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, 2534 (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS) 2535 return (rc); 2536 if (aMethod == NULL) { 2537 aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *)); 2538 if (aMethod == NULL) 2539 return (NS_LDAP_MEMORY); 2540 aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t)); 2541 if (aMethod[0] == NULL) { 2542 free(aMethod); 2543 return (NS_LDAP_MEMORY); 2544 } 2545 if (version == NS_LDAP_V1) 2546 (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE; 2547 else { 2548 (aMethod[0])->type = NS_LDAP_AUTH_SASL; 2549 (aMethod[0])->saslmech = 2550 NS_LDAP_SASL_DIGEST_MD5; 2551 (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE; 2552 } 2553 } 2554 2555 /* Get the credential level list */ 2556 if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P, 2557 (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) { 2558 (void) __ns_ldap_freeParam((void ***)&aMethod); 2559 return (rc); 2560 } 2561 if (cLevel == NULL) { 2562 cLevel = (int **)calloc(2, sizeof (int *)); 2563 if (cLevel == NULL) 2564 return (NS_LDAP_MEMORY); 2565 cLevel[0] = (int *)calloc(1, sizeof (int)); 2566 if (cLevel[0] == NULL) 2567 return (NS_LDAP_MEMORY); 2568 if (version == NS_LDAP_V1) 2569 *(cLevel[0]) = NS_LDAP_CRED_PROXY; 2570 else 2571 *(cLevel[0]) = NS_LDAP_CRED_ANON; 2572 } 2573 } 2574 2575 /* setup the anon credential for anonymous connection */ 2576 (void) memset(&anon, 0, sizeof (ns_cred_t)); 2577 anon.auth.type = NS_LDAP_AUTH_NONE; 2578 2579 for (; ; ) { 2580 if (cred != NULL) { 2581 /* using specified auth method */ 2582 rc = makeConnection(&con, server, cred, 2583 sessionId, timeoutSec, errorp, 2584 fail_if_new_pwd_reqd, 2585 nopasswd_acct_mgmt, flags, &badSrvrs); 2586 if (rc == NS_LDAP_SUCCESS || 2587 rc == NS_LDAP_SUCCESS_WITH_INFO) { 2588 *session = con; 2589 break; 2590 } 2591 } else { 2592 self_gssapi_only = __s_api_self_gssapi_only_get(); 2593 /* for every cred level */ 2594 for (cNext = cLevel; *cNext != NULL; cNext++) { 2595 if (self_gssapi_only && 2596 **cNext != NS_LDAP_CRED_SELF) 2597 continue; 2598 if (**cNext == NS_LDAP_CRED_ANON) { 2599 /* 2600 * make connection anonymously 2601 * Free the down server list before 2602 * looping through 2603 */ 2604 if (badSrvrs && *badSrvrs) { 2605 __s_api_free2dArray(badSrvrs); 2606 badSrvrs = NULL; 2607 } 2608 rc = makeConnection(&con, server, &anon, 2609 sessionId, timeoutSec, errorp, 2610 fail_if_new_pwd_reqd, 2611 nopasswd_acct_mgmt, flags, 2612 &badSrvrs); 2613 if (rc == NS_LDAP_SUCCESS || 2614 rc == 2615 NS_LDAP_SUCCESS_WITH_INFO) { 2616 *session = con; 2617 goto done; 2618 } 2619 continue; 2620 } 2621 /* for each cred level */ 2622 for (aNext = aMethod; *aNext != NULL; aNext++) { 2623 if (self_gssapi_only && 2624 (*aNext)->saslmech != 2625 NS_LDAP_SASL_GSSAPI) 2626 continue; 2627 /* 2628 * self coexists with sasl/GSSAPI only 2629 * and non-self coexists with non-gssapi 2630 * only 2631 */ 2632 if ((**cNext == NS_LDAP_CRED_SELF && 2633 (*aNext)->saslmech != 2634 NS_LDAP_SASL_GSSAPI) || 2635 (**cNext != NS_LDAP_CRED_SELF && 2636 (*aNext)->saslmech == 2637 NS_LDAP_SASL_GSSAPI)) 2638 continue; 2639 /* make connection and authenticate */ 2640 /* with default credentials */ 2641 authp = NULL; 2642 rc = __s_api_getDefaultAuth(*cNext, 2643 *aNext, &authp); 2644 if (rc != NS_LDAP_SUCCESS) { 2645 continue; 2646 } 2647 /* 2648 * Free the down server list before 2649 * looping through 2650 */ 2651 if (badSrvrs && *badSrvrs) { 2652 __s_api_free2dArray(badSrvrs); 2653 badSrvrs = NULL; 2654 } 2655 rc = makeConnection(&con, server, authp, 2656 sessionId, timeoutSec, errorp, 2657 fail_if_new_pwd_reqd, 2658 nopasswd_acct_mgmt, flags, 2659 &badSrvrs); 2660 (void) __ns_ldap_freeCred(&authp); 2661 if (rc == NS_LDAP_SUCCESS || 2662 rc == 2663 NS_LDAP_SUCCESS_WITH_INFO) { 2664 *session = con; 2665 goto done; 2666 } 2667 } 2668 } 2669 } 2670 if (flags & NS_LDAP_HARD) { 2671 if (sec < LDAPMAXHARDLOOKUPTIME) 2672 sec *= 2; 2673 _sleep(sec); 2674 } else { 2675 break; 2676 } 2677 } 2678 2679 done: 2680 /* 2681 * If unable to get a connection, and this is 2682 * the thread opening the shared connection, 2683 * unlock the session mutex and let other 2684 * threads try to get their own connection. 2685 */ 2686 if (wait4session != 0 && sessionTid == thr_self()) { 2687 wait4session = 0; 2688 sessionTid = 0; 2689 #ifdef DEBUG 2690 (void) fprintf(stderr, "tid= %d: __s_api_getConnection: " 2691 "unlocking sessionLock \n", thr_self()); 2692 fflush(stderr); 2693 #endif /* DEBUG */ 2694 (void) mutex_unlock(&sessionLock); 2695 } 2696 if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) { 2697 /* 2698 * self_gssapi_only is true but no self/sasl/gssapi is 2699 * configured 2700 */ 2701 rc = NS_LDAP_CONFIG; 2702 } 2703 2704 (void) __ns_ldap_freeParam((void ***)&aMethod); 2705 (void) __ns_ldap_freeParam((void ***)&cLevel); 2706 2707 if (badSrvrs && *badSrvrs) { 2708 /* 2709 * At this point, either we have a successful 2710 * connection or exhausted all the possible auths. 2711 * and creds. Mark the problem servers as down 2712 * so that the problem servers are not contacted 2713 * again until the refresh_ttl expires. 2714 */ 2715 (void) __s_api_removeBadServers(badSrvrs); 2716 __s_api_free2dArray(badSrvrs); 2717 } 2718 return (rc); 2719 } 2720 2721 #pragma fini(_free_sessionPool) 2722 static void 2723 _free_sessionPool() 2724 { 2725 int id; 2726 2727 (void) rw_wrlock(&sessionPoolLock); 2728 if (sessionPool != NULL) { 2729 for (id = 0; id < sessionPoolSize; id++) 2730 _DropConnection(id + CONID_OFFSET, 0, 1); 2731 free(sessionPool); 2732 sessionPool = NULL; 2733 sessionPoolSize = 0; 2734 } 2735 (void) rw_unlock(&sessionPoolLock); 2736 } 2737