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