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