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