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