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 "ns_sldap.h" 42 #include "ns_internal.h" 43 #include "ns_cache_door.h" 44 #include <sys/stat.h> 45 #include <fcntl.h> 46 #include <procfs.h> 47 #include <unistd.h> 48 49 extern unsigned int _sleep(unsigned int); 50 extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *, 51 LDAPControl **, LDAPControl **); 52 extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip); 53 54 static int openConnection(LDAP **, const char *, const ns_cred_t *, 55 int, ns_ldap_error_t **, int, int); 56 57 static mutex_t sessionPoolLock = DEFAULTMUTEX; 58 59 static Connection **sessionPool = NULL; 60 static int sessionPoolSize = 0; 61 62 63 static mutex_t nscdLock = DEFAULTMUTEX; 64 static int nscdChecked = 0; 65 static pid_t checkedPid = -1; 66 static int isNscd = 0; 67 68 /* Number of hostnames to allocate memory for */ 69 #define NUMTOMALLOC 32 70 71 72 /* 73 * Check /proc/PID/psinfo to see if this process is nscd 74 * If it is, treat connection as NS_LDAP_KEEP_CONN, to reduce 75 * constant reconnects for many operations. 76 * A more complete solution is to develop true connection pooling. 77 * However, this is much better than a new connection for every request. 78 */ 79 static int 80 nscd_proc() 81 { 82 pid_t my_pid; 83 psinfo_t pinfo; 84 char fname[BUFSIZ]; 85 int ret; 86 int fd; 87 88 /* Don't bother checking if this process isn't root. */ 89 /* It can't be nscd */ 90 if (getuid() != 0) 91 return (0); 92 93 my_pid = getpid(); 94 if (nscdChecked && (my_pid == checkedPid)) { 95 return (isNscd); 96 } 97 (void) mutex_lock(&nscdLock); 98 if (nscdChecked && (my_pid == checkedPid)) { 99 (void) mutex_unlock(&nscdLock); 100 return (isNscd); 101 } 102 nscdChecked = 1; 103 checkedPid = my_pid; 104 isNscd = 0; 105 if (snprintf(fname, BUFSIZ, "/proc/%d/psinfo", my_pid) != 0) { 106 if ((fd = open(fname, O_RDONLY)) > 0) { 107 ret = read(fd, &pinfo, sizeof (psinfo_t)); 108 (void) close(fd); 109 if (ret == sizeof (psinfo_t) && 110 (strcmp(pinfo.pr_fname, "nscd") == 0)) { 111 /* process runs as root and is named nscd */ 112 /* that's good enough for now */ 113 isNscd = 1; 114 } 115 } 116 } 117 (void) mutex_unlock(&nscdLock); 118 return (isNscd); 119 } 120 121 /* 122 * This function requests a server from the cache manager through 123 * the door functionality 124 */ 125 126 static int 127 __s_api_requestServer(const char *request, const char *server, 128 ns_server_info_t *ret, ns_ldap_error_t **error) 129 { 130 union { 131 ldap_data_t s_d; 132 char s_b[DOORBUFFERSIZE]; 133 } space; 134 ldap_data_t *sptr; 135 int ndata; 136 int adata; 137 char errstr[MAXERROR]; 138 const char *ireq; 139 char *rbuf, *ptr, *rest; 140 char *dptr; 141 char **mptr, **mptr1, **cptr, **cptr1; 142 int mcnt, ccnt; 143 char **servers; 144 int rc; 145 146 if (ret == NULL || error == NULL) { 147 return (NS_LDAP_OP_FAILED); 148 } 149 (void) memset(ret, 0, sizeof (ns_server_info_t)); 150 *error = NULL; 151 152 (void) memset(space.s_b, 0, DOORBUFFERSIZE); 153 154 if (request == NULL) 155 ireq = NS_CACHE_NEW; 156 else 157 ireq = request; 158 159 adata = (sizeof (ldap_call_t) + strlen(ireq) +1); 160 if (server != NULL) { 161 adata += strlen(DOORLINESEP) + 1; 162 adata += strlen(server) + 1; 163 } 164 ndata = sizeof (space); 165 space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER; 166 (void) strcpy(space.s_d.ldap_call.ldap_u.domainname, ireq); 167 if (server != NULL) { 168 (void) strcat(space.s_d.ldap_call.ldap_u.domainname, 169 DOORLINESEP); 170 (void) strcat(space.s_d.ldap_call.ldap_u.domainname, server); 171 } 172 sptr = &space.s_d; 173 174 switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) { 175 case SUCCESS: 176 break; 177 /* this case is for when the $mgr is not running, but ldapclient */ 178 /* is trying to initialize things */ 179 case NOSERVER: 180 /* get first server from config list unavailable otherwise */ 181 servers = NULL; 182 rc = __s_api_getServers(&servers, error); 183 if (rc != NS_LDAP_SUCCESS) { 184 if (servers != NULL) { 185 __s_api_free2dArray(servers); 186 servers = NULL; 187 } 188 return (rc); 189 } 190 if (servers == NULL || servers[0] == NULL) { 191 __s_api_free2dArray(servers); 192 servers = NULL; 193 (void) sprintf(errstr, 194 gettext("No server found in configuration")); 195 MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT, 196 strdup(errstr), NULL); 197 return (NS_LDAP_CONFIG); 198 } 199 ret->server = strdup(servers[0]); 200 if (ret->server == NULL) { 201 __s_api_free2dArray(servers); 202 return (NS_LDAP_MEMORY); 203 } 204 ret->saslMechanisms = NULL; 205 ret->controls = NULL; 206 __s_api_free2dArray(servers); 207 servers = NULL; 208 return (NS_LDAP_SUCCESS); 209 case NOTFOUND: 210 default: 211 return (NS_LDAP_OP_FAILED); 212 } 213 214 /* copy info from door call return structure here */ 215 rbuf = space.s_d.ldap_ret.ldap_u.config; 216 217 /* Get the host */ 218 ptr = strtok_r(rbuf, DOORLINESEP, &rest); 219 if (ptr == NULL) { 220 (void) sprintf(errstr, gettext("No server returned from " 221 "ldap_cachemgr")); 222 MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR, 223 strdup(errstr), NULL); 224 return (NS_LDAP_OP_FAILED); 225 } 226 ret->server = strdup(ptr); 227 if (ret->server == NULL) { 228 return (NS_LDAP_MEMORY); 229 } 230 231 /* get the Supported Controls/SASL mechs */ 232 mptr = NULL; 233 mcnt = 0; 234 cptr = NULL; 235 ccnt = 0; 236 for (; ; ) { 237 ptr = strtok_r(NULL, DOORLINESEP, &rest); 238 if (ptr == NULL) 239 break; 240 if (strncasecmp(ptr, _SASLMECHANISM, 241 _SASLMECHANISM_LEN) == 0) { 242 dptr = strchr(ptr, '='); 243 if (dptr == NULL) 244 continue; 245 dptr++; 246 mptr1 = (char **)realloc((void *)mptr, 247 sizeof (char *) * (mcnt+2)); 248 if (mptr1 == NULL) { 249 __s_api_free2dArray(mptr); 250 if (sptr != &space.s_d) { 251 (void) munmap((char *)sptr, ndata); 252 } 253 __s_api_free2dArray(cptr); 254 free(ret->server); 255 ret->server = NULL; 256 return (NS_LDAP_MEMORY); 257 } 258 mptr = mptr1; 259 mptr[mcnt] = strdup(dptr); 260 if (mptr[mcnt] == NULL) { 261 if (sptr != &space.s_d) { 262 (void) munmap((char *)sptr, ndata); 263 } 264 __s_api_free2dArray(cptr); 265 cptr = NULL; 266 __s_api_free2dArray(mptr); 267 mptr = NULL; 268 free(ret->server); 269 ret->server = NULL; 270 return (NS_LDAP_MEMORY); 271 } 272 mcnt++; 273 mptr[mcnt] = NULL; 274 } 275 if (strncasecmp(ptr, _SUPPORTEDCONTROL, 276 _SUPPORTEDCONTROL_LEN) == 0) { 277 dptr = strchr(ptr, '='); 278 if (dptr == NULL) 279 continue; 280 dptr++; 281 cptr1 = (char **)realloc((void *)cptr, 282 sizeof (char *) * (ccnt+2)); 283 if (cptr1 == NULL) { 284 if (sptr != &space.s_d) { 285 (void) munmap((char *)sptr, ndata); 286 } 287 __s_api_free2dArray(cptr); 288 __s_api_free2dArray(mptr); 289 mptr = NULL; 290 free(ret->server); 291 ret->server = NULL; 292 return (NS_LDAP_MEMORY); 293 } 294 cptr = cptr1; 295 cptr[ccnt] = strdup(dptr); 296 if (cptr[ccnt] == NULL) { 297 if (sptr != &space.s_d) { 298 (void) munmap((char *)sptr, ndata); 299 } 300 __s_api_free2dArray(cptr); 301 cptr = NULL; 302 __s_api_free2dArray(mptr); 303 mptr = NULL; 304 free(ret->server); 305 ret->server = NULL; 306 return (NS_LDAP_MEMORY); 307 } 308 ccnt++; 309 cptr[ccnt] = NULL; 310 } 311 } 312 if (mptr != NULL) { 313 ret->saslMechanisms = mptr; 314 } 315 if (cptr != NULL) { 316 ret->controls = cptr; 317 } 318 319 320 /* clean up door call */ 321 if (sptr != &space.s_d) { 322 (void) munmap((char *)sptr, ndata); 323 } 324 *error = NULL; 325 326 return (NS_LDAP_SUCCESS); 327 } 328 329 #ifdef DEBUG 330 331 /* 332 * printCred(): prints the credential structure 333 */ 334 static void 335 printCred(FILE *fp, const ns_cred_t *cred) 336 { 337 if (fp == NULL) { 338 (void) fprintf(fp, "printCred: fp is NULL\n"); 339 return; 340 } 341 if (cred == NULL) { 342 (void) fprintf(fp, "printCred: cred is NULL\n"); 343 return; 344 } 345 346 (void) fprintf(fp, "AuthType=%d\n", cred->auth.type); 347 (void) fprintf(fp, "TlsType=%d\n", cred->auth.tlstype); 348 (void) fprintf(fp, "SaslMech=%d\n", cred->auth.saslmech); 349 (void) fprintf(fp, "SaslOpt=%d\n", cred->auth.saslopt); 350 if (cred->hostcertpath) 351 (void) fprintf(fp, "hostCertPath=%s\n", cred->hostcertpath); 352 if (cred->cred.unix_cred.userID) 353 (void) fprintf(fp, "userID=%s\n", cred->cred.unix_cred.userID); 354 if (cred->cred.unix_cred.passwd) 355 (void) fprintf(fp, "passwd=%s\n", cred->cred.unix_cred.passwd); 356 } 357 358 /* 359 * printConnection(): prints the connection structure 360 */ 361 static void 362 printConnection(FILE *fp, Connection *con) 363 { 364 if (fp == NULL || con == NULL) 365 return; 366 367 (void) fprintf(fp, "connectionID=%d\n", con->connectionId); 368 (void) fprintf(fp, "usedBit=%d\n", con->usedBit); 369 (void) fprintf(fp, "threadID=%d\n", con->threadID); 370 if (con->serverAddr) { 371 (void) fprintf(fp, "serverAddr=%s\n", con->serverAddr); 372 } 373 printCred(fp, con->auth); 374 (void) fprintf(fp, "-----------------------------------------------\n"); 375 fflush(fp); 376 } 377 378 #endif /* DEBUG */ 379 380 381 /* 382 * addConnection(): inserts a connection in the connection list. 383 * It will also sets use bit and the thread Id for the thread 384 * using the connection for the first time. 385 * Returns: -1 = failure, new Connection ID = success 386 */ 387 static int 388 addConnection(Connection *con) 389 { 390 int i; 391 392 if (!con) 393 return (-1); 394 #ifdef DEBUG 395 (void) fprintf(stderr, "Adding connection thrid=%d\n", con->threadID); 396 #endif /* DEBUG */ 397 (void) mutex_lock(&sessionPoolLock); 398 if (sessionPool == NULL) { 399 sessionPoolSize = SESSION_CACHE_INC; 400 sessionPool = calloc(sessionPoolSize, 401 sizeof (struct connection **)); 402 if (!sessionPool) { 403 (void) mutex_unlock(&sessionPoolLock); 404 return (-1); 405 } 406 #ifdef DEBUG 407 (void) fprintf(stderr, "Initialized sessionPool\n"); 408 #endif /* DEBUG */ 409 } 410 for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i) 411 ; 412 if (i == sessionPoolSize) { 413 /* run out of array, need to increase sessionPool */ 414 Connection **cl; 415 cl = (Connection **) realloc(sessionPool, 416 (sessionPoolSize + SESSION_CACHE_INC) * 417 sizeof (Connection *)); 418 if (!cl) { 419 (void) mutex_unlock(&sessionPoolLock); 420 return (-1); 421 } 422 (void) memset(cl + sessionPoolSize, 0, 423 SESSION_CACHE_INC * sizeof (struct connection *)); 424 sessionPool = cl; 425 sessionPoolSize += SESSION_CACHE_INC; 426 #ifdef DEBUG 427 (void) fprintf(stderr, "Increased sessionPoolSize to: %d\n", 428 sessionPoolSize); 429 #endif /* DEBUG */ 430 } 431 sessionPool[i] = con; 432 con->usedBit = B_TRUE; 433 (void) mutex_unlock(&sessionPoolLock); 434 con->connectionId = i + CONID_OFFSET; 435 #ifdef DEBUG 436 (void) fprintf(stderr, "Connection added [%d]\n", i); 437 printConnection(stderr, con); 438 #endif /* DEBUG */ 439 return (i + CONID_OFFSET); 440 } 441 442 /* 443 * See if the specified session matches a currently available 444 */ 445 446 static int 447 findConnectionById(int flags, const ns_cred_t *auth, ConnectionID cID, 448 Connection **conp) 449 { 450 Connection *cp; 451 int id; 452 453 if ((conp == NULL) || (auth == NULL) || cID < CONID_OFFSET) 454 return (-1); 455 *conp = NULL; 456 if (sessionPool == NULL) 457 return (-1); 458 id = cID - CONID_OFFSET; 459 if (id < 0 || id >= sessionPoolSize) 460 return (-1); 461 462 (void) mutex_lock(&sessionPoolLock); 463 if (sessionPool[id] == NULL) { 464 (void) mutex_unlock(&sessionPoolLock); 465 return (-1); 466 } 467 cp = sessionPool[id]; 468 469 /* 470 * Make sure the connection has the same type of authentication method 471 */ 472 if ((cp->usedBit) || 473 (cp->auth->auth.type != auth->auth.type) || 474 (cp->auth->auth.tlstype != auth->auth.tlstype) || 475 (cp->auth->auth.saslmech != auth->auth.saslmech) || 476 (cp->auth->auth.saslopt != auth->auth.saslopt)) { 477 (void) mutex_unlock(&sessionPoolLock); 478 return (-1); 479 } 480 if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) && 481 ((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) || 482 (cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) || 483 (cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) && 484 ((cp->auth->cred.unix_cred.userID == NULL) || 485 (strcasecmp(cp->auth->cred.unix_cred.userID, 486 auth->cred.unix_cred.userID) != 0))) { 487 (void) mutex_unlock(&sessionPoolLock); 488 return (-1); 489 } 490 /* An existing connection is found but it needs to be reset */ 491 if (flags & NS_LDAP_NEW_CONN) { 492 (void) mutex_unlock(&sessionPoolLock); 493 DropConnection(cID, 0); 494 return (-1); 495 } 496 /* found an available connection */ 497 cp->usedBit = B_TRUE; 498 (void) mutex_unlock(&sessionPoolLock); 499 cp->threadID = thr_self(); 500 *conp = cp; 501 return (cID); 502 } 503 504 /* 505 * findConnection(): find an available connection from the list 506 * that matches the criteria specified in Connection structure. 507 * If serverAddr is NULL, then find a connection to any server 508 * as long as it matches the rest of the parameters. 509 * Returns: -1 = failure, the Connection ID found = success. 510 */ 511 static int 512 findConnection(const char *serverAddr, const ns_cred_t *auth, Connection **conp) 513 { 514 Connection *cp; 515 int i; 516 517 if (auth == NULL || conp == NULL) 518 return (-1); 519 *conp = NULL; 520 521 #ifdef DEBUG 522 (void) fprintf(stderr, "Find connection\n"); 523 (void) fprintf(stderr, "Looking for ....\n"); 524 if (serverAddr && *serverAddr) 525 (void) fprintf(stderr, "serverAddr=%s\n", serverAddr); 526 else 527 (void) fprintf(stderr, "serverAddr=NULL\n"); 528 printCred(stderr, auth); 529 fflush(stderr); 530 #endif /* DEBUG */ 531 if (sessionPool == NULL) 532 return (-1); 533 (void) mutex_lock(&sessionPoolLock); 534 for (i = 0; i < sessionPoolSize; ++i) { 535 if (sessionPool[i] == NULL) 536 continue; 537 cp = sessionPool[i]; 538 #ifdef DEBUG 539 (void) fprintf(stderr, "checking connection [%d] ....\n", i); 540 printConnection(stderr, cp); 541 #endif /* DEBUG */ 542 if ((cp->usedBit) || 543 (cp->auth->auth.type != auth->auth.type) || 544 (cp->auth->auth.tlstype != auth->auth.tlstype) || 545 (cp->auth->auth.saslmech != auth->auth.saslmech) || 546 (cp->auth->auth.saslopt != auth->auth.saslopt) || 547 (serverAddr && *serverAddr && 548 (strcasecmp(serverAddr, cp->serverAddr) != 0))) 549 continue; 550 if ((((cp->auth->auth.type == NS_LDAP_AUTH_SASL) && 551 ((cp->auth->auth.saslmech == NS_LDAP_SASL_CRAM_MD5) || 552 (cp->auth->auth.saslmech == NS_LDAP_SASL_DIGEST_MD5))) || 553 (cp->auth->auth.type == NS_LDAP_AUTH_SIMPLE)) && 554 ((cp->auth->cred.unix_cred.userID == NULL) || 555 (cp->auth->cred.unix_cred.passwd == NULL) || 556 ((strcasecmp(cp->auth->cred.unix_cred.userID, 557 auth->cred.unix_cred.userID) != 0)) || 558 ((strcmp(cp->auth->cred.unix_cred.passwd, 559 auth->cred.unix_cred.passwd) != 0)))) 560 continue; 561 /* found an available connection */ 562 cp->usedBit = B_TRUE; 563 (void) mutex_unlock(&sessionPoolLock); 564 cp->threadID = thr_self(); 565 *conp = cp; 566 #ifdef DEBUG 567 (void) fprintf(stderr, "Connection found cID=%d\n", i); 568 fflush(stderr); 569 #endif /* DEBUG */ 570 return (i + CONID_OFFSET); 571 } 572 (void) mutex_unlock(&sessionPoolLock); 573 return (-1); 574 } 575 576 /* 577 * Free a Connection structure 578 */ 579 static void 580 freeConnection(Connection *con) 581 { 582 if (con == NULL) 583 return; 584 if (con->serverAddr) 585 free(con->serverAddr); 586 if (con->auth) 587 (void) __ns_ldap_freeCred(&(con->auth)); 588 if (con->saslMechanisms) { 589 __s_api_free2dArray(con->saslMechanisms); 590 } 591 if (con->controls) { 592 __s_api_free2dArray(con->controls); 593 } 594 free(con); 595 } 596 597 /* 598 * Find a connection matching the passed in criteria. If an open 599 * connection with that criteria exists use it, otherwise open a 600 * new connection. 601 * Success: returns the pointer to the Connection structure 602 * Failure: returns NULL, error code and message should be in errorp 603 */ 604 605 static int 606 makeConnection(Connection **conp, const char *serverAddr, 607 const ns_cred_t *auth, ConnectionID *cID, int timeoutSec, 608 ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd, 609 int nopasswd_acct_mgmt, char ***badsrvrs) 610 { 611 Connection *con = NULL; 612 ConnectionID id; 613 char errmsg[MAXERROR]; 614 int rc, exit_rc = NS_LDAP_SUCCESS; 615 ns_server_info_t sinfo; 616 char *hReq, *host = NULL; 617 LDAP *ld = NULL; 618 int passwd_mgmt = 0; 619 int totalbad = 0; /* Number of servers contacted unsuccessfully */ 620 short memerr = 0; /* Variable for tracking memory allocation errors */ 621 622 if (conp == NULL || errorp == NULL || auth == NULL) 623 return (NS_LDAP_INVALID_PARAM); 624 *errorp = NULL; 625 *conp = NULL; 626 sinfo.server = NULL; 627 sinfo.controls = NULL; 628 sinfo.saslMechanisms = NULL; 629 630 if ((id = findConnection(serverAddr, auth, &con)) != -1) { 631 /* connection found in cache */ 632 #ifdef DEBUG 633 (void) fprintf(stderr, "connection found in cache %d\n", id); 634 fflush(stderr); 635 #endif /* DEBUG */ 636 *cID = id; 637 *conp = con; 638 return (NS_LDAP_SUCCESS); 639 } 640 641 if (serverAddr) { 642 rc = openConnection(&ld, serverAddr, auth, timeoutSec, errorp, 643 fail_if_new_pwd_reqd, passwd_mgmt); 644 if (rc == NS_LDAP_SUCCESS || rc == 645 NS_LDAP_SUCCESS_WITH_INFO) { 646 exit_rc = rc; 647 rc = __s_api_requestServer(NS_CACHE_NEW, serverAddr, 648 &sinfo, errorp); 649 if (rc != NS_LDAP_SUCCESS || sinfo.server == NULL) { 650 (void) snprintf(errmsg, sizeof (errmsg), 651 gettext("makeConnection: unable to get " 652 "server information for %s"), serverAddr); 653 syslog(LOG_ERR, "libsldap: %s", errmsg); 654 return (NS_LDAP_OP_FAILED); 655 } 656 goto create_con; 657 } else { 658 return (rc); 659 } 660 } 661 662 /* No cached connection, create one */ 663 for (; ; ) { 664 if (host == NULL) 665 hReq = NS_CACHE_NEW; 666 else 667 hReq = NS_CACHE_NEXT; 668 rc = __s_api_requestServer(hReq, host, &sinfo, errorp); 669 if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) || 670 (host && (strcasecmp(host, sinfo.server) == 0))) { 671 /* Log the error */ 672 if (*errorp) { 673 (void) snprintf(errmsg, sizeof (errmsg), 674 "%s: (%s)", gettext("makeConnection: " 675 "unable to make LDAP connection, " 676 "request for a server failed"), 677 (*errorp)->message); 678 syslog(LOG_ERR, "libsldap: %s", errmsg); 679 } 680 681 if (sinfo.server) 682 free(sinfo.server); 683 __s_api_free2dArray(sinfo.saslMechanisms); 684 __s_api_free2dArray(sinfo.controls); 685 if (host) 686 free(host); 687 return (NS_LDAP_OP_FAILED); 688 } 689 if (host) 690 free(host); 691 host = strdup(sinfo.server); 692 if (host == NULL) { 693 free(sinfo.server); 694 __s_api_free2dArray(sinfo.saslMechanisms); 695 __s_api_free2dArray(sinfo.controls); 696 return (NS_LDAP_MEMORY); 697 } 698 699 /* check if server supports password management */ 700 passwd_mgmt = __s_api_contain_passwd_control_oid( 701 sinfo.controls); 702 /* check if server supports password less account mgmt */ 703 if (nopasswd_acct_mgmt && 704 !__s_api_contain_account_usable_control_oid( 705 sinfo.controls)) { 706 syslog(LOG_WARNING, "libsldap: server %s does not " 707 "provide account information without password", 708 host); 709 free(host); 710 free(sinfo.server); 711 __s_api_free2dArray(sinfo.saslMechanisms); 712 __s_api_free2dArray(sinfo.controls); 713 return (NS_LDAP_OP_FAILED); 714 } 715 /* make the connection */ 716 rc = openConnection(&ld, host, auth, timeoutSec, errorp, 717 fail_if_new_pwd_reqd, passwd_mgmt); 718 /* if success, go to create connection structure */ 719 if (rc == NS_LDAP_SUCCESS || 720 rc == NS_LDAP_SUCCESS_WITH_INFO) { 721 exit_rc = rc; 722 break; 723 } 724 725 /* 726 * If not able to reach the server, inform the ldap 727 * cache manager that the server should be removed 728 * from its server list. Thus, the manager will not 729 * return this server on the next get-server request 730 * and will also reduce the server list refresh TTL, 731 * so that it will find out sooner when the server 732 * is up again. 733 */ 734 if (rc == NS_LDAP_INTERNAL && *errorp != NULL) { 735 if ((*errorp)->status == LDAP_CONNECT_ERROR || 736 (*errorp)->status == LDAP_SERVER_DOWN) { 737 /* Reset memory allocation error */ 738 memerr = 0; 739 /* 740 * We contacted a server that we could 741 * not either authenticate to or contact. 742 * If it is due to authentication, then 743 * we need to try the server again. So, 744 * do not remove the server yet, but 745 * add it to the bad server list. 746 * The caller routine will remove 747 * the servers if: 748 * a). A good server is found or 749 * b). All the possible methods 750 * are tried without finding 751 * a good server 752 */ 753 if (*badsrvrs == NULL) { 754 if (!(*badsrvrs = (char **)malloc 755 (sizeof (char *) * NUMTOMALLOC))) { 756 memerr = 1; 757 } 758 /* Allocate memory in chunks of NUMTOMALLOC */ 759 } else if ((totalbad % NUMTOMALLOC) == 760 NUMTOMALLOC - 1) { 761 char **tmpptr; 762 if (!(tmpptr = (char **)realloc(*badsrvrs, 763 (sizeof (char *) * NUMTOMALLOC * 764 ((totalbad/NUMTOMALLOC) + 2))))) { 765 memerr = 1; 766 } else { 767 *badsrvrs = tmpptr; 768 } 769 } 770 /* 771 * Store host only if there were no unsuccessful 772 * memory allocations above 773 */ 774 if (!memerr && 775 !((*badsrvrs)[totalbad++] = strdup(host))) { 776 memerr = 1; 777 totalbad--; 778 } 779 (*badsrvrs)[totalbad] = NULL; 780 } 781 } 782 783 /* else, cleanup and go for the next server */ 784 if (sinfo.server) { 785 free(sinfo.server); 786 sinfo.server = NULL; 787 } 788 __s_api_free2dArray(sinfo.saslMechanisms); 789 sinfo.saslMechanisms = NULL; 790 __s_api_free2dArray(sinfo.controls); 791 sinfo.controls = NULL; 792 /* Return if we had memory allocation errors */ 793 if (memerr) 794 return (NS_LDAP_MEMORY); 795 if (*errorp) { 796 /* 797 * If openConnection() failed due to 798 * password policy, or invalid credential, 799 * keep *errorp and exit 800 */ 801 if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD || 802 (*errorp)->status == LDAP_INVALID_CREDENTIALS) { 803 free(host); 804 return (rc); 805 } else { 806 (void) __ns_ldap_freeError(errorp); 807 *errorp = NULL; 808 } 809 } 810 } 811 812 create_con: 813 /* we have created ld, setup con structure */ 814 if (host) 815 free(host); 816 if ((con = calloc(1, sizeof (Connection))) == NULL) { 817 if (sinfo.server) 818 free(sinfo.server); 819 __s_api_free2dArray(sinfo.saslMechanisms); 820 __s_api_free2dArray(sinfo.controls); 821 /* 822 * If password control attached in **errorp, 823 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 824 * free the error structure 825 */ 826 if (*errorp) { 827 (void) __ns_ldap_freeError(errorp); 828 *errorp = NULL; 829 } 830 return (NS_LDAP_MEMORY); 831 } 832 833 con->serverAddr = sinfo.server; 834 con->saslMechanisms = sinfo.saslMechanisms; 835 con->controls = sinfo.controls; 836 837 con->auth = __ns_ldap_dupAuth(auth); 838 if (con->auth == NULL) { 839 free(con); 840 /* 841 * If password control attached in **errorp, 842 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 843 * free the error structure 844 */ 845 if (*errorp) { 846 (void) __ns_ldap_freeError(errorp); 847 *errorp = NULL; 848 } 849 return (NS_LDAP_MEMORY); 850 } 851 852 con->threadID = thr_self(); 853 con->ld = ld; 854 if ((id = addConnection(con)) == -1) { 855 freeConnection(con); 856 /* 857 * If password control attached in **errorp, 858 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 859 * free the error structure 860 */ 861 if (*errorp) { 862 (void) __ns_ldap_freeError(errorp); 863 *errorp = NULL; 864 } 865 return (NS_LDAP_MEMORY); 866 } 867 #ifdef DEBUG 868 (void) fprintf(stderr, "connection added into cache %d\n", id); 869 fflush(stderr); 870 #endif /* DEBUG */ 871 *cID = id; 872 *conp = con; 873 return (exit_rc); 874 } 875 876 /* 877 * Return the specified connection to the pool. If necessary 878 * delete the connection. 879 */ 880 881 static void 882 _DropConnection(ConnectionID cID, int flag, int fini) 883 { 884 Connection *cp; 885 int id; 886 int use_mutex = !fini; 887 888 id = cID - CONID_OFFSET; 889 if (id < 0 || id >= sessionPoolSize) 890 return; 891 #ifdef DEBUG 892 (void) fprintf(stderr, 893 "Dropping connection cID=%d flag=0x%x\n", cID, flag); 894 fflush(stderr); 895 #endif /* DEBUG */ 896 if (use_mutex) 897 (void) mutex_lock(&sessionPoolLock); 898 899 cp = sessionPool[id]; 900 /* sanity check before removing */ 901 if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) { 902 if (use_mutex) 903 (void) mutex_unlock(&sessionPoolLock); 904 return; 905 } 906 907 if (!fini && 908 ((flag & NS_LDAP_NEW_CONN) == 0) && 909 ((flag & NS_LDAP_KEEP_CONN) || nscd_proc())) { 910 /* release Connection (keep alive) */ 911 cp->usedBit = B_FALSE; 912 cp->threadID = 0; /* unmark the threadID */ 913 if (use_mutex) 914 (void) mutex_unlock(&sessionPoolLock); 915 } else { 916 /* delete Connection (disconnect) */ 917 sessionPool[id] = NULL; 918 if (use_mutex) 919 (void) mutex_unlock(&sessionPoolLock); 920 (void) ldap_unbind(cp->ld); 921 freeConnection(cp); 922 } 923 } 924 925 void 926 DropConnection(ConnectionID cID, int flag) 927 { 928 _DropConnection(cID, flag, 0); 929 } 930 931 /* 932 * This routine is called after a bind operation is 933 * done in openConnection() to process the password 934 * management information, if any. 935 * 936 * Input: 937 * bind_type: "simple" or "sasl/DIGEST-MD5" 938 * ldaprc : ldap rc from the ldap bind operation 939 * controls : controls returned by the server 940 * errmsg : error message from the server 941 * fail_if_new_pwd_reqd: 942 * flag indicating if connection should be open 943 * when password needs to change immediately 944 * passwd_mgmt: 945 * flag indicating if server supports password 946 * policy/management 947 * 948 * Output : ns_ldap_error structure, which may contain 949 * password status and number of seconds until 950 * expired 951 * 952 * return rc: 953 * NS_LDAP_EXTERNAL: error, connection should not open 954 * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached 955 * NS_LDAP_SUCCESS: OK to open connection 956 * 957 */ 958 959 static int 960 process_pwd_mgmt(char *bind_type, int ldaprc, 961 LDAPControl **controls, 962 char *errmsg, ns_ldap_error_t **errorp, 963 int fail_if_new_pwd_reqd, 964 int passwd_mgmt) 965 { 966 char errstr[MAXERROR]; 967 LDAPControl **ctrl = NULL; 968 int exit_rc; 969 ns_ldap_passwd_status_t pwd_status = NS_PASSWD_GOOD; 970 int sec_until_exp = 0; 971 972 /* 973 * errmsg may be an empty string, 974 * even if ldaprc is LDAP_SUCCESS, 975 * free the empty string if that's the case 976 */ 977 if (errmsg && 978 (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) { 979 ldap_memfree(errmsg); 980 errmsg = NULL; 981 } 982 983 if (ldaprc != LDAP_SUCCESS) { 984 /* 985 * try to map ldap rc and error message to 986 * a password status 987 */ 988 if (errmsg) { 989 if (passwd_mgmt) 990 pwd_status = 991 __s_api_set_passwd_status( 992 ldaprc, errmsg); 993 ldap_memfree(errmsg); 994 } 995 996 (void) snprintf(errstr, sizeof (errstr), 997 gettext("openConnection: " 998 "%s bind failed " 999 "- %s"), bind_type, ldap_err2string(ldaprc)); 1000 1001 if (pwd_status != NS_PASSWD_GOOD) { 1002 MKERROR_PWD_MGMT(*errorp, 1003 ldaprc, strdup(errstr), 1004 pwd_status, 0, NULL); 1005 } else { 1006 MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr), 1007 NULL); 1008 } 1009 if (controls) 1010 ldap_controls_free(controls); 1011 1012 return (NS_LDAP_INTERNAL); 1013 } 1014 1015 /* 1016 * ldaprc is LDAP_SUCCESS, 1017 * process the password management controls, if any 1018 */ 1019 exit_rc = NS_LDAP_SUCCESS; 1020 if (controls && passwd_mgmt) { 1021 /* 1022 * The control with the OID 1023 * 2.16.840.1.113730.3.4.4 (or 1024 * LDAP_CONTROL_PWEXPIRED, as defined 1025 * in the ldap.h header file) is the 1026 * expired password control. 1027 * 1028 * This control is used if the server 1029 * is configured to require users to 1030 * change their passwords when first 1031 * logging in and whenever the 1032 * passwords are reset. 1033 * 1034 * If the user is logging in for the 1035 * first time or if the user's 1036 * password has been reset, the 1037 * server sends this control to 1038 * indicate that the client needs to 1039 * change the password immediately. 1040 * 1041 * At this point, the only operation 1042 * that the client can perform is to 1043 * change the user's password. If the 1044 * client requests any other LDAP 1045 * operation, the server sends back 1046 * an LDAP_UNWILLING_TO_PERFORM 1047 * result code with an expired 1048 * password control. 1049 * 1050 * The control with the OID 1051 * 2.16.840.1.113730.3.4.5 (or 1052 * LDAP_CONTROL_PWEXPIRING, as 1053 * defined in the ldap.h header file) 1054 * is the password expiration warning 1055 * control. 1056 * 1057 * This control is used if the server 1058 * is configured to expire user 1059 * passwords after a certain amount 1060 * of time. 1061 * 1062 * The server sends this control back 1063 * to the client if the client binds 1064 * using a password that will soon 1065 * expire. The ldctl_value field of 1066 * the LDAPControl structure 1067 * specifies the number of seconds 1068 * before the password will expire. 1069 */ 1070 for (ctrl = controls; *ctrl; ctrl++) { 1071 1072 if (strcmp((*ctrl)->ldctl_oid, 1073 LDAP_CONTROL_PWEXPIRED) == 0) { 1074 /* 1075 * if the caller wants this bind 1076 * to fail, set up the error info. 1077 * If call to this function is 1078 * for searching the LDAP directory, 1079 * e.g., __ns_ldap_list(), 1080 * there's really no sense to 1081 * let a connection open and 1082 * then fail immediately afterward 1083 * on the LDAP search operation with 1084 * the LDAP_UNWILLING_TO_PERFORM rc 1085 */ 1086 pwd_status = 1087 NS_PASSWD_CHANGE_NEEDED; 1088 if (fail_if_new_pwd_reqd) { 1089 (void) snprintf(errstr, 1090 sizeof (errstr), 1091 gettext( 1092 "openConnection: " 1093 "%s bind " 1094 "failed " 1095 "- password " 1096 "expired. It " 1097 " needs to change " 1098 "immediately!"), 1099 bind_type); 1100 MKERROR_PWD_MGMT(*errorp, 1101 LDAP_SUCCESS, 1102 strdup(errstr), 1103 pwd_status, 1104 0, 1105 NULL); 1106 exit_rc = NS_LDAP_INTERNAL; 1107 } else { 1108 MKERROR_PWD_MGMT(*errorp, 1109 LDAP_SUCCESS, 1110 NULL, 1111 pwd_status, 1112 0, 1113 NULL); 1114 exit_rc = 1115 NS_LDAP_SUCCESS_WITH_INFO; 1116 } 1117 break; 1118 } else if (strcmp((*ctrl)->ldctl_oid, 1119 LDAP_CONTROL_PWEXPIRING) == 0) { 1120 pwd_status = 1121 NS_PASSWD_ABOUT_TO_EXPIRE; 1122 if ((*ctrl)-> 1123 ldctl_value.bv_len > 0 && 1124 (*ctrl)-> 1125 ldctl_value.bv_val) 1126 sec_until_exp = 1127 atoi((*ctrl)-> 1128 ldctl_value.bv_val); 1129 MKERROR_PWD_MGMT(*errorp, 1130 LDAP_SUCCESS, 1131 NULL, 1132 pwd_status, 1133 sec_until_exp, 1134 NULL); 1135 exit_rc = 1136 NS_LDAP_SUCCESS_WITH_INFO; 1137 break; 1138 } 1139 } 1140 } 1141 1142 if (controls) 1143 ldap_controls_free(controls); 1144 1145 return (exit_rc); 1146 } 1147 1148 static int 1149 ldap_in_hosts_switch() 1150 { 1151 enum __nsw_parse_err pserr; 1152 struct __nsw_switchconfig *conf; 1153 struct __nsw_lookup *lkp; 1154 const char *name; 1155 int found = 0; 1156 1157 conf = __nsw_getconfig("hosts", &pserr); 1158 if (conf == NULL) { 1159 return (-1); 1160 } 1161 1162 /* check for skip and count other backends */ 1163 for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 1164 name = lkp->service_name; 1165 if (strcmp(name, "ldap") == 0) { 1166 found = 1; 1167 break; 1168 } 1169 } 1170 __nsw_freeconfig(conf); 1171 return (found); 1172 } 1173 1174 static int 1175 openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, 1176 int timeoutSec, ns_ldap_error_t **errorp, 1177 int fail_if_new_pwd_reqd, int passwd_mgmt) 1178 { 1179 LDAP *ld = NULL; 1180 char *binddn, *passwd; 1181 char *digest_md5_name; 1182 const char *s; 1183 int ldapVersion = LDAP_VERSION3; 1184 int derefOption = LDAP_DEREF_ALWAYS; 1185 int zero = 0; 1186 int rc; 1187 char errstr[MAXERROR]; 1188 int errnum = 0; 1189 LDAPMessage *resultMsg; 1190 int msgId; 1191 int useSSL = 0; 1192 struct timeval tv; 1193 AuthType_t bindType; 1194 int timeoutMilliSec = timeoutSec * 1000; 1195 struct berval cred; 1196 char *sslServerAddr; 1197 char *s1; 1198 char *errmsg; 1199 LDAPControl **controls; 1200 int pwd_rc; 1201 1202 *errorp = NULL; 1203 *ldp = NULL; 1204 1205 switch (auth->auth.type) { 1206 case NS_LDAP_AUTH_NONE: 1207 case NS_LDAP_AUTH_SIMPLE: 1208 case NS_LDAP_AUTH_SASL: 1209 bindType = auth->auth.type; 1210 break; 1211 case NS_LDAP_AUTH_TLS: 1212 useSSL = 1; 1213 switch (auth->auth.tlstype) { 1214 case NS_LDAP_TLS_NONE: 1215 bindType = NS_LDAP_AUTH_NONE; 1216 break; 1217 case NS_LDAP_TLS_SIMPLE: 1218 bindType = NS_LDAP_AUTH_SIMPLE; 1219 break; 1220 case NS_LDAP_TLS_SASL: 1221 bindType = NS_LDAP_AUTH_SASL; 1222 break; 1223 default: 1224 (void) sprintf(errstr, 1225 gettext("openConnection: unsupported " 1226 "TLS authentication method " 1227 "(%d)"), auth->auth.tlstype); 1228 MKERROR(LOG_WARNING, *errorp, 1229 LDAP_AUTH_METHOD_NOT_SUPPORTED, 1230 strdup(errstr), NULL); 1231 return (NS_LDAP_INTERNAL); 1232 } 1233 break; 1234 default: 1235 (void) sprintf(errstr, 1236 gettext("openConnection: unsupported " 1237 "authentication method (%d)"), auth->auth.type); 1238 MKERROR(LOG_WARNING, *errorp, 1239 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 1240 NULL); 1241 return (NS_LDAP_INTERNAL); 1242 } 1243 1244 if (useSSL) { 1245 const char *hostcertpath; 1246 char *alloc_hcp = NULL; 1247 #ifdef DEBUG 1248 (void) fprintf(stderr, "+++TLS transport\n"); 1249 #endif /* DEBUG */ 1250 hostcertpath = auth->hostcertpath; 1251 if (hostcertpath == NULL) { 1252 alloc_hcp = __s_get_hostcertpath(); 1253 hostcertpath = alloc_hcp; 1254 } 1255 1256 if (hostcertpath == NULL) 1257 return (NS_LDAP_MEMORY); 1258 1259 if ((rc = ldapssl_client_init(hostcertpath, NULL)) < 0) { 1260 if (alloc_hcp) 1261 free(alloc_hcp); 1262 (void) snprintf(errstr, sizeof (errstr), 1263 gettext("openConnection: failed to initialize " 1264 "TLS security (%s)"), 1265 ldapssl_err2string(rc)); 1266 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 1267 strdup(errstr), NULL); 1268 return (NS_LDAP_INTERNAL); 1269 } 1270 if (alloc_hcp) 1271 free(alloc_hcp); 1272 1273 /* determine if the host name contains a port number */ 1274 s = strchr(serverAddr, ']'); /* skip over ipv6 addr */ 1275 if (s == NULL) 1276 s = serverAddr; 1277 s = strchr(s, ':'); 1278 if (s != NULL) { 1279 /* 1280 * If we do get a port number, we will try stripping 1281 * it. At present, referrals will always have a 1282 * port number. 1283 */ 1284 sslServerAddr = strdup(serverAddr); 1285 if (sslServerAddr == NULL) 1286 return (NS_LDAP_MEMORY); 1287 s1 = strrchr(sslServerAddr, ':'); 1288 if (s1 != NULL) 1289 *s1 = '\0'; 1290 (void) snprintf(errstr, sizeof (errstr), 1291 gettext("openConnection: cannot use tls with %s. " 1292 "Trying %s"), 1293 serverAddr, sslServerAddr); 1294 syslog(LOG_ERR, "libsldap: %s", errstr); 1295 } else 1296 sslServerAddr = (char *)serverAddr; 1297 1298 ld = ldapssl_init(sslServerAddr, LDAPS_PORT, 1); 1299 1300 if (sslServerAddr != serverAddr) 1301 free(sslServerAddr); 1302 1303 if (ld == NULL || 1304 ldapssl_install_gethostbyaddr(ld, "ldap") != 0) { 1305 (void) snprintf(errstr, sizeof (errstr), 1306 gettext("openConnection: failed to connect " 1307 "using TLS (%s)"), strerror(errno)); 1308 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 1309 strdup(errstr), NULL); 1310 return (NS_LDAP_INTERNAL); 1311 } 1312 } else { 1313 #ifdef DEBUG 1314 (void) fprintf(stderr, "+++Unsecure transport\n"); 1315 #endif /* DEBUG */ 1316 /* Warning message IF cannot connect to host(s) */ 1317 if ((ld = ldap_init((char *)serverAddr, LDAP_PORT)) == NULL) { 1318 char *p = strerror(errno); 1319 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 1320 strdup(p), NULL); 1321 return (NS_LDAP_INTERNAL); 1322 } else { 1323 /* check and avoid gethostname recursion */ 1324 if (ldap_in_hosts_switch() > 0 && 1325 ! __s_api_isipv4((char *)serverAddr) && 1326 ! __s_api_isipv6((char *)serverAddr)) { 1327 /* host: ldap - found, attempt to recover */ 1328 if (ldap_set_option(ld, LDAP_X_OPT_DNS_SKIPDB, 1329 "ldap") != 0) { 1330 (void) snprintf(errstr, sizeof (errstr), 1331 gettext("openConnection: " 1332 "unrecoverable gethostname " 1333 "recursion detected " 1334 "in /etc/nsswitch.conf")); 1335 MKERROR(LOG_WARNING, *errorp, 1336 LDAP_CONNECT_ERROR, 1337 strdup(errstr), NULL); 1338 (void) ldap_unbind(ld); 1339 return (NS_LDAP_INTERNAL); 1340 } 1341 } 1342 } 1343 } 1344 1345 (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); 1346 (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 1347 /* 1348 * set LDAP_OPT_REFERRALS to OFF. 1349 * This library will handle the referral itself 1350 * based on API flags or configuration file 1351 * specification. If this option is not set 1352 * to OFF, libldap will never pass the 1353 * referral info up to this library 1354 */ 1355 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 1356 (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 1357 (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 1358 /* setup TCP/IP connect timeout */ 1359 (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 1360 &timeoutMilliSec); 1361 /* retry if LDAP I/O was interrupted */ 1362 (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 1363 1364 switch (bindType) { 1365 case NS_LDAP_AUTH_NONE: 1366 #ifdef DEBUG 1367 (void) fprintf(stderr, "+++Anonymous bind\n"); 1368 #endif /* DEBUG */ 1369 break; 1370 case NS_LDAP_AUTH_SIMPLE: 1371 binddn = auth->cred.unix_cred.userID; 1372 passwd = auth->cred.unix_cred.passwd; 1373 if (passwd == NULL || *passwd == '\0' || 1374 binddn == NULL || *binddn == '\0') { 1375 (void) sprintf(errstr, gettext("openConnection: " 1376 "missing credentials for Simple bind")); 1377 MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS, 1378 strdup(errstr), NULL); 1379 (void) ldap_unbind(ld); 1380 return (NS_LDAP_INTERNAL); 1381 } 1382 1383 #ifdef DEBUG 1384 (void) fprintf(stderr, "+++Simple bind\n"); 1385 #endif /* DEBUG */ 1386 msgId = ldap_simple_bind(ld, binddn, passwd); 1387 1388 if (msgId == -1) { 1389 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 1390 (void *)&errnum); 1391 (void) snprintf(errstr, sizeof (errstr), 1392 gettext("openConnection: simple bind failed " 1393 "- %s"), ldap_err2string(errnum)); 1394 (void) ldap_unbind(ld); 1395 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 1396 NULL); 1397 return (NS_LDAP_INTERNAL); 1398 } 1399 1400 tv.tv_sec = timeoutSec; 1401 tv.tv_usec = 0; 1402 rc = ldap_result(ld, msgId, 0, &tv, &resultMsg); 1403 1404 if ((rc == -1) || (rc == 0)) { 1405 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 1406 (void *)&errnum); 1407 (void) snprintf(errstr, sizeof (errstr), 1408 gettext("openConnection: simple bind failed " 1409 "- %s"), ldap_err2string(errnum)); 1410 (void) ldap_msgfree(resultMsg); 1411 (void) ldap_unbind(ld); 1412 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 1413 NULL); 1414 return (NS_LDAP_INTERNAL); 1415 } 1416 1417 /* 1418 * get ldaprc, controls, and error msg 1419 */ 1420 rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 1421 &errmsg, NULL, &controls, 1); 1422 1423 if (rc != LDAP_SUCCESS) { 1424 (void) snprintf(errstr, sizeof (errstr), 1425 gettext("openConnection: simple bind failed " 1426 "- unable to parse result")); 1427 (void) ldap_unbind(ld); 1428 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 1429 strdup(errstr), NULL); 1430 return (NS_LDAP_INTERNAL); 1431 } 1432 1433 /* process the password management info, if any */ 1434 pwd_rc = process_pwd_mgmt("simple", 1435 errnum, controls, errmsg, 1436 errorp, 1437 fail_if_new_pwd_reqd, 1438 passwd_mgmt); 1439 1440 if (pwd_rc == NS_LDAP_INTERNAL) { 1441 (void) ldap_unbind(ld); 1442 return (pwd_rc); 1443 } 1444 1445 if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) { 1446 *ldp = ld; 1447 return (pwd_rc); 1448 } 1449 1450 break; 1451 case NS_LDAP_AUTH_SASL: 1452 /* We don't support any sasl options yet */ 1453 if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE) { 1454 (void) sprintf(errstr, 1455 gettext("openConnection: SASL options are " 1456 "not supported (%d)"), auth->auth.saslopt); 1457 MKERROR(LOG_WARNING, *errorp, 1458 LDAP_AUTH_METHOD_NOT_SUPPORTED, 1459 strdup(errstr), NULL); 1460 (void) ldap_unbind(ld); 1461 return (NS_LDAP_INTERNAL); 1462 } 1463 binddn = auth->cred.unix_cred.userID; 1464 passwd = auth->cred.unix_cred.passwd; 1465 if (passwd == NULL || *passwd == '\0' || 1466 binddn == NULL || *binddn == '\0') { 1467 (void) sprintf(errstr, 1468 gettext("openConnection: missing credentials " 1469 "for SASL bind")); 1470 MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS, 1471 strdup(errstr), NULL); 1472 (void) ldap_unbind(ld); 1473 return (NS_LDAP_INTERNAL); 1474 } 1475 cred.bv_val = passwd; 1476 cred.bv_len = strlen(passwd); 1477 1478 switch (auth->auth.saslmech) { 1479 case NS_LDAP_SASL_CRAM_MD5: 1480 /* 1481 * NOTE: if iDS changes to support cram_md5, 1482 * please add password management code here. 1483 * Since ldap_sasl_cram_md5_bind_s does not 1484 * return anything that could be used to 1485 * extract the ldap rc/errmsg/control to 1486 * determine if bind failed due to password 1487 * policy, a new cram_md5_bind API will need 1488 * to be introduced. See 1489 * ldap_x_sasl_digest_md5_bind() and case 1490 * NS_LDAP_SASL_DIGEST_MD5 below for details. 1491 */ 1492 if ((rc = ldap_sasl_cram_md5_bind_s(ld, binddn, 1493 &cred, NULL, NULL)) != LDAP_SUCCESS) { 1494 (void) ldap_get_option(ld, 1495 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 1496 (void) snprintf(errstr, sizeof (errstr), 1497 gettext("openConnection: " 1498 "sasl/CRAM-MD5 bind failed - %s"), 1499 ldap_err2string(errnum)); 1500 MKERROR(LOG_WARNING, *errorp, errnum, 1501 strdup(errstr), NULL); 1502 (void) ldap_unbind(ld); 1503 return (NS_LDAP_INTERNAL); 1504 } 1505 break; 1506 case NS_LDAP_SASL_DIGEST_MD5: 1507 digest_md5_name = malloc(strlen(binddn) + 5); 1508 /* 5 = strlen("dn: ") + 1 */ 1509 if (digest_md5_name == NULL) { 1510 (void) ldap_unbind(ld); 1511 return (NS_LDAP_MEMORY); 1512 } 1513 (void) strcpy(digest_md5_name, "dn: "); 1514 (void) strcat(digest_md5_name, binddn); 1515 1516 tv.tv_sec = timeoutSec; 1517 tv.tv_usec = 0; 1518 rc = ldap_x_sasl_digest_md5_bind(ld, 1519 digest_md5_name, &cred, NULL, NULL, 1520 &tv, &resultMsg); 1521 1522 if (resultMsg == NULL) { 1523 free(digest_md5_name); 1524 (void) ldap_get_option(ld, 1525 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 1526 (void) snprintf(errstr, sizeof (errstr), 1527 gettext("openConnection: " 1528 "DIGEST-MD5 bind failed - %s"), 1529 ldap_err2string(errnum)); 1530 (void) ldap_unbind(ld); 1531 MKERROR(LOG_WARNING, *errorp, errnum, 1532 strdup(errstr), NULL); 1533 return (NS_LDAP_INTERNAL); 1534 } 1535 1536 /* 1537 * get ldaprc, controls, and error msg 1538 */ 1539 rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 1540 &errmsg, NULL, &controls, 1); 1541 1542 if (rc != LDAP_SUCCESS) { 1543 free(digest_md5_name); 1544 (void) snprintf(errstr, sizeof (errstr), 1545 gettext("openConnection: " 1546 "DIGEST-MD5 bind failed " 1547 "- unable to parse result")); 1548 (void) ldap_unbind(ld); 1549 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 1550 strdup(errstr), NULL); 1551 return (NS_LDAP_INTERNAL); 1552 } 1553 1554 /* process the password management info, if any */ 1555 pwd_rc = process_pwd_mgmt("sasl/DIGEST-MD5", 1556 errnum, controls, errmsg, 1557 errorp, 1558 fail_if_new_pwd_reqd, 1559 passwd_mgmt); 1560 1561 if (pwd_rc == NS_LDAP_INTERNAL) { 1562 free(digest_md5_name); 1563 (void) ldap_unbind(ld); 1564 return (pwd_rc); 1565 } 1566 1567 if (pwd_rc == NS_LDAP_SUCCESS_WITH_INFO) { 1568 *ldp = ld; 1569 return (pwd_rc); 1570 } 1571 1572 free(digest_md5_name); 1573 break; 1574 default: 1575 (void) ldap_unbind(ld); 1576 (void) sprintf(errstr, 1577 gettext("openConnection: unsupported SASL " 1578 "mechanism (%d)"), auth->auth.saslmech); 1579 MKERROR(LOG_WARNING, *errorp, 1580 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 1581 NULL); 1582 return (NS_LDAP_INTERNAL); 1583 } 1584 } 1585 1586 *ldp = ld; 1587 return (NS_LDAP_SUCCESS); 1588 } 1589 1590 /* 1591 * FUNCTION: __s_api_getDefaultAuth 1592 * 1593 * Constructs a credential for authentication using the config module. 1594 * 1595 * RETURN VALUES: 1596 * 1597 * NS_LDAP_SUCCESS If successful 1598 * NS_LDAP_CONFIG If there are any config errors. 1599 * NS_LDAP_MEMORY Memory errors. 1600 * NS_LDAP_OP_FAILED If there are no more authentication methods so can 1601 * not build a new authp. 1602 * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the 1603 * necessary fields of a cred for a given auth method 1604 * are not provided. 1605 * INPUT: 1606 * 1607 * cLevel Currently requested credential level to be tried 1608 * 1609 * aMethod Currently requested authentication method to be tried 1610 * 1611 * OUTPUT: 1612 * 1613 * authp authentication method to use. 1614 */ 1615 static int 1616 __s_api_getDefaultAuth( 1617 int *cLevel, 1618 ns_auth_t *aMethod, 1619 ns_cred_t **authp) 1620 { 1621 void **paramVal = NULL; 1622 char *modparamVal = NULL; 1623 int getUid = 0; 1624 int getPasswd = 0; 1625 int getCertpath = 0; 1626 int rc = 0; 1627 ns_ldap_error_t *errorp = NULL; 1628 1629 #ifdef DEBUG 1630 (void) fprintf(stderr, "__s_api_getDefaultAuth START\n"); 1631 #endif 1632 1633 if (aMethod == NULL) { 1634 /* Require an Auth */ 1635 return (NS_LDAP_INVALID_PARAM); 1636 1637 } 1638 1639 /* 1640 * Do not differentiate between (proxy/self) at this time, but 1641 * reject self credential levels at this time 1642 */ 1643 if (cLevel && *cLevel == NS_LDAP_CRED_SELF) 1644 return (NS_LDAP_INVALID_PARAM); 1645 1646 *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t)); 1647 if ((*authp) == NULL) 1648 return (NS_LDAP_MEMORY); 1649 1650 (*authp)->auth = *aMethod; 1651 1652 switch (aMethod->type) { 1653 case NS_LDAP_AUTH_NONE: 1654 return (NS_LDAP_SUCCESS); 1655 case NS_LDAP_AUTH_SIMPLE: 1656 getUid++; 1657 getPasswd++; 1658 break; 1659 case NS_LDAP_AUTH_SASL: 1660 if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 1661 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) { 1662 getUid++; 1663 getPasswd++; 1664 } else { 1665 (void) __ns_ldap_freeCred(authp); 1666 *authp = NULL; 1667 return (NS_LDAP_INVALID_PARAM); 1668 } 1669 break; 1670 case NS_LDAP_AUTH_TLS: 1671 if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) || 1672 ((aMethod->tlstype == NS_LDAP_TLS_SASL) && 1673 ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 1674 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) { 1675 getUid++; 1676 getPasswd++; 1677 getCertpath++; 1678 } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) { 1679 getCertpath++; 1680 } else { 1681 (void) __ns_ldap_freeCred(authp); 1682 *authp = NULL; 1683 return (NS_LDAP_INVALID_PARAM); 1684 } 1685 break; 1686 } 1687 1688 if (getUid) { 1689 paramVal = NULL; 1690 if ((rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P, 1691 ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 1692 (void) __ns_ldap_freeCred(authp); 1693 (void) __ns_ldap_freeError(&errorp); 1694 *authp = NULL; 1695 return (rc); 1696 } 1697 1698 if (paramVal == NULL || *paramVal == NULL) { 1699 (void) __ns_ldap_freeCred(authp); 1700 *authp = NULL; 1701 return (NS_LDAP_INVALID_PARAM); 1702 } 1703 1704 (*authp)->cred.unix_cred.userID = strdup((char *)*paramVal); 1705 (void) __ns_ldap_freeParam(¶mVal); 1706 if ((*authp)->cred.unix_cred.userID == NULL) { 1707 (void) __ns_ldap_freeCred(authp); 1708 *authp = NULL; 1709 return (NS_LDAP_MEMORY); 1710 } 1711 } 1712 if (getPasswd) { 1713 paramVal = NULL; 1714 if ((rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P, 1715 ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 1716 (void) __ns_ldap_freeCred(authp); 1717 (void) __ns_ldap_freeError(&errorp); 1718 *authp = NULL; 1719 return (rc); 1720 } 1721 1722 if (paramVal == NULL || *paramVal == NULL) { 1723 (void) __ns_ldap_freeCred(authp); 1724 *authp = NULL; 1725 return (NS_LDAP_INVALID_PARAM); 1726 } 1727 1728 modparamVal = dvalue((char *)*paramVal); 1729 (void) __ns_ldap_freeParam(¶mVal); 1730 if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) { 1731 (void) __ns_ldap_freeCred(authp); 1732 if (modparamVal != NULL) 1733 free(modparamVal); 1734 *authp = NULL; 1735 return (NS_LDAP_INVALID_PARAM); 1736 } 1737 1738 (*authp)->cred.unix_cred.passwd = modparamVal; 1739 } 1740 if (getCertpath) { 1741 paramVal = NULL; 1742 if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 1743 ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 1744 (void) __ns_ldap_freeCred(authp); 1745 (void) __ns_ldap_freeError(&errorp); 1746 *authp = NULL; 1747 return (rc); 1748 } 1749 1750 if (paramVal == NULL || *paramVal == NULL) { 1751 (void) __ns_ldap_freeCred(authp); 1752 *authp = NULL; 1753 return (NS_LDAP_INVALID_PARAM); 1754 } 1755 1756 (*authp)->hostcertpath = strdup((char *)*paramVal); 1757 (void) __ns_ldap_freeParam(¶mVal); 1758 if ((*authp)->hostcertpath == NULL) { 1759 (void) __ns_ldap_freeCred(authp); 1760 *authp = NULL; 1761 return (NS_LDAP_MEMORY); 1762 } 1763 } 1764 return (NS_LDAP_SUCCESS); 1765 } 1766 1767 /* 1768 * FUNCTION: __s_api_getConnection 1769 * 1770 * Bind to the specified server or one from the server 1771 * list and return the pointer. 1772 * 1773 * This function can rebind or not (NS_LDAP_HARD), it can require a 1774 * credential or bind anonymously 1775 * 1776 * This function follows the DUA configuration schema algorithm 1777 * 1778 * RETURN VALUES: 1779 * 1780 * NS_LDAP_SUCCESS A connection was made successfully. 1781 * NS_LDAP_SUCCESS_WITH_INFO 1782 * A connection was made successfully, but with 1783 * password management info in *errorp 1784 * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function. 1785 * NS_LDAP_CONFIG If there are any config errors. 1786 * NS_LDAP_MEMORY Memory errors. 1787 * NS_LDAP_INTERNAL If there was a ldap error. 1788 * 1789 * INPUT: 1790 * 1791 * server Bind to this LDAP server only 1792 * flags If NS_LDAP_HARD is set function will not return until it has 1793 * a connection unless there is a authentication problem. 1794 * If NS_LDAP_NEW_CONN is set the function must force a new 1795 * connection to be created 1796 * If NS_LDAP_KEEP_CONN is set the connection is to be kept open 1797 * auth Credentials for bind. This could be NULL in which case 1798 * a default cred built from the config module is used. 1799 * sessionId cookie that points to a previous session 1800 * fail_if_new_pwd_reqd 1801 * a flag indicating this function should fail if the passwd 1802 * in auth needs to change immediately 1803 * nopasswd_acct_mgmt 1804 * a flag indicating that makeConnection should check before 1805 * binding if server supports LDAP V3 password less 1806 * account management 1807 * 1808 * OUTPUT: 1809 * 1810 * session pointer to a session with connection information 1811 * errorp Set if there are any INTERNAL, or CONFIG error. 1812 */ 1813 int 1814 __s_api_getConnection( 1815 const char *server, 1816 const int flags, 1817 const ns_cred_t *cred, /* credentials for bind */ 1818 ConnectionID *sessionId, 1819 Connection **session, 1820 ns_ldap_error_t **errorp, 1821 int fail_if_new_pwd_reqd, 1822 int nopasswd_acct_mgmt) 1823 { 1824 char errmsg[MAXERROR]; 1825 ns_auth_t **aMethod = NULL; 1826 ns_auth_t **aNext = NULL; 1827 int **cLevel = NULL; 1828 int **cNext = NULL; 1829 int timeoutSec = NS_DEFAULT_BIND_TIMEOUT; 1830 int rc; 1831 Connection *con = NULL; 1832 int sec = 1; 1833 ns_cred_t *authp = NULL; 1834 ns_cred_t anon; 1835 int version = NS_LDAP_V2; 1836 void **paramVal = NULL; 1837 char **badSrvrs = NULL; /* List of problem hostnames */ 1838 1839 if ((session == NULL) || (sessionId == NULL)) { 1840 return (NS_LDAP_INVALID_PARAM); 1841 } 1842 *session = NULL; 1843 1844 /* if we already have a session id try to reuse connection */ 1845 if (*sessionId > 0) { 1846 rc = findConnectionById(flags, cred, *sessionId, &con); 1847 if (rc == *sessionId && con) { 1848 *session = con; 1849 return (NS_LDAP_SUCCESS); 1850 } 1851 *sessionId = 0; 1852 } 1853 1854 /* get profile version number */ 1855 if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, 1856 ¶mVal, errorp)) != NS_LDAP_SUCCESS) 1857 return (rc); 1858 if (paramVal == NULL) { 1859 (void) sprintf(errmsg, gettext("getConnection: no file " 1860 "version")); 1861 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg), 1862 NS_LDAP_CONFIG); 1863 return (NS_LDAP_CONFIG); 1864 } 1865 if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0) 1866 version = NS_LDAP_V1; 1867 (void) __ns_ldap_freeParam((void ***)¶mVal); 1868 1869 /* Get the bind timeout value */ 1870 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp); 1871 if (paramVal != NULL && *paramVal != NULL) { 1872 timeoutSec = **((int **)paramVal); 1873 (void) __ns_ldap_freeParam(¶mVal); 1874 } 1875 if (*errorp) 1876 (void) __ns_ldap_freeError(errorp); 1877 1878 if (cred == NULL) { 1879 /* Get the authentication method list */ 1880 if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, 1881 (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS) 1882 return (rc); 1883 if (aMethod == NULL) { 1884 aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *)); 1885 if (aMethod == NULL) 1886 return (NS_LDAP_MEMORY); 1887 aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t)); 1888 if (aMethod[0] == NULL) { 1889 free(aMethod); 1890 return (NS_LDAP_MEMORY); 1891 } 1892 if (version == NS_LDAP_V1) 1893 (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE; 1894 else { 1895 (aMethod[0])->type = NS_LDAP_AUTH_SASL; 1896 (aMethod[0])->saslmech = 1897 NS_LDAP_SASL_DIGEST_MD5; 1898 (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE; 1899 } 1900 } 1901 1902 /* Get the credential level list */ 1903 if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P, 1904 (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) { 1905 (void) __ns_ldap_freeParam((void ***)&aMethod); 1906 return (rc); 1907 } 1908 if (cLevel == NULL) { 1909 cLevel = (int **)calloc(2, sizeof (int *)); 1910 if (cLevel == NULL) 1911 return (NS_LDAP_MEMORY); 1912 cLevel[0] = (int *)calloc(1, sizeof (int)); 1913 if (cLevel[0] == NULL) 1914 return (NS_LDAP_MEMORY); 1915 if (version == NS_LDAP_V1) 1916 *(cLevel[0]) = NS_LDAP_CRED_PROXY; 1917 else 1918 *(cLevel[0]) = NS_LDAP_CRED_ANON; 1919 } 1920 } 1921 1922 /* setup the anon credential for anonymous connection */ 1923 (void) memset(&anon, 0, sizeof (ns_cred_t)); 1924 anon.auth.type = NS_LDAP_AUTH_NONE; 1925 1926 for (; ; ) { 1927 if (cred != NULL) { 1928 /* using specified auth method */ 1929 rc = makeConnection(&con, server, cred, 1930 sessionId, timeoutSec, errorp, 1931 fail_if_new_pwd_reqd, nopasswd_acct_mgmt, 1932 &badSrvrs); 1933 if (rc == NS_LDAP_SUCCESS || 1934 rc == NS_LDAP_SUCCESS_WITH_INFO) { 1935 *session = con; 1936 break; 1937 } 1938 } else { 1939 /* for every cred level */ 1940 for (cNext = cLevel; *cNext != NULL; cNext++) { 1941 if (**cNext == NS_LDAP_CRED_ANON) { 1942 /* 1943 * make connection anonymously 1944 * Free the down server list before 1945 * looping through 1946 */ 1947 if (badSrvrs && *badSrvrs) { 1948 __s_api_free2dArray(badSrvrs); 1949 badSrvrs = NULL; 1950 } 1951 rc = makeConnection(&con, server, &anon, 1952 sessionId, timeoutSec, errorp, 1953 fail_if_new_pwd_reqd, 1954 nopasswd_acct_mgmt, &badSrvrs); 1955 if (rc == NS_LDAP_SUCCESS || 1956 rc == 1957 NS_LDAP_SUCCESS_WITH_INFO) { 1958 *session = con; 1959 goto done; 1960 } 1961 continue; 1962 } 1963 /* for each cred level */ 1964 for (aNext = aMethod; *aNext != NULL; aNext++) { 1965 /* make connection and authenticate */ 1966 /* with default credentials */ 1967 authp = NULL; 1968 rc = __s_api_getDefaultAuth(*cNext, 1969 *aNext, &authp); 1970 if (rc != NS_LDAP_SUCCESS) { 1971 continue; 1972 } 1973 /* 1974 * Free the down server list before 1975 * looping through 1976 */ 1977 if (badSrvrs && *badSrvrs) { 1978 __s_api_free2dArray(badSrvrs); 1979 badSrvrs = NULL; 1980 } 1981 rc = makeConnection(&con, server, authp, 1982 sessionId, timeoutSec, errorp, 1983 fail_if_new_pwd_reqd, 1984 nopasswd_acct_mgmt, &badSrvrs); 1985 (void) __ns_ldap_freeCred(&authp); 1986 if (rc == NS_LDAP_SUCCESS || 1987 rc == 1988 NS_LDAP_SUCCESS_WITH_INFO) { 1989 *session = con; 1990 goto done; 1991 } 1992 } 1993 } 1994 } 1995 if (flags & NS_LDAP_HARD) { 1996 if (sec < LDAPMAXHARDLOOKUPTIME) 1997 sec *= 2; 1998 _sleep(sec); 1999 } else { 2000 break; 2001 } 2002 } 2003 2004 done: 2005 (void) __ns_ldap_freeParam((void ***)&aMethod); 2006 (void) __ns_ldap_freeParam((void ***)&cLevel); 2007 2008 if (badSrvrs && *badSrvrs) { 2009 /* 2010 * At this point, either we have a successful 2011 * connection or exhausted all the possible auths. 2012 * and creds. Mark the problem servers as down 2013 * so that the problem servers are not contacted 2014 * again until the refresh_ttl expires. 2015 */ 2016 (void) __s_api_removeBadServers(badSrvrs); 2017 __s_api_free2dArray(badSrvrs); 2018 } 2019 return (rc); 2020 } 2021 2022 #pragma fini(_free_sessionPool) 2023 static void 2024 _free_sessionPool() 2025 { 2026 int id; 2027 2028 (void) mutex_lock(&sessionPoolLock); 2029 if (sessionPool != NULL) { 2030 for (id = 0; id < sessionPoolSize; id++) 2031 _DropConnection(id + CONID_OFFSET, 0, 1); 2032 free(sessionPool); 2033 sessionPool = NULL; 2034 sessionPoolSize = 0; 2035 } 2036 (void) mutex_unlock(&sessionPoolLock); 2037 } 2038