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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 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 *, int); 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), NS_LDAP_MEMORY); 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\n", t, cred->auth.type); 480 (void) fprintf(fp, "tid= %d: TlsType=%d\n", t, cred->auth.tlstype); 481 (void) fprintf(fp, "tid= %d: SaslMech=%d\n", t, cred->auth.saslmech); 482 (void) fprintf(fp, "tid= %d: SaslOpt=%d\n", 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 if (*errorp) 706 (void) __ns_ldap_freeError(errorp); 707 *conp = NULL; 708 (void) memset(&sinfo, 0, sizeof (sinfo)); 709 710 if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) { 711 /* connection found in cache */ 712 #ifdef DEBUG 713 (void) fprintf(stderr, "tid= %d: connection found in " 714 "cache %d\n", thr_self(), id); 715 fflush(stderr); 716 #endif /* DEBUG */ 717 *cID = id; 718 *conp = con; 719 return (NS_LDAP_SUCCESS); 720 } 721 722 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 723 serverAddrType = NS_CACHE_ADDR_HOSTNAME; 724 bindHost = &sinfo.serverFQDN; 725 } else { 726 serverAddrType = NS_CACHE_ADDR_IP; 727 bindHost = &sinfo.server; 728 } 729 730 if (serverAddr) { 731 if (__s_api_isInitializing()) { 732 /* 733 * When obtaining the root DSE, connect to the server 734 * passed here through the serverAddr parameter 735 */ 736 sinfo.server = strdup(serverAddr); 737 if (sinfo.server == NULL) 738 return (NS_LDAP_MEMORY); 739 if (strcmp(serverAddrType, 740 NS_CACHE_ADDR_HOSTNAME) == 0) { 741 rc = __s_api_ip2hostname(sinfo.server, 742 &sinfo.serverFQDN); 743 if (rc != NS_LDAP_SUCCESS) { 744 (void) snprintf(errmsg, 745 sizeof (errmsg), 746 gettext("The %s address " 747 "can not be resolved into " 748 "a host name. Returning " 749 "the address as it is."), 750 serverAddr); 751 MKERROR(LOG_ERR, 752 *errorp, 753 NS_CONFIG_NOTLOADED, 754 strdup(errmsg), 755 NS_LDAP_MEMORY); 756 __s_api_free_server_info(&sinfo); 757 return (NS_LDAP_INTERNAL); 758 } 759 } 760 } else { 761 /* 762 * We're given the server address, just use it. 763 * In case of sasl/GSSAPI, serverAddr would need 764 * to be a FQDN. We assume this is the case for now. 765 * 766 * Only the server address fields of sinfo structure 767 * are filled in since these are the only relevant 768 * data that we have. Other fields of this structure 769 * (controls, saslMechanisms) are kept to NULL. 770 */ 771 sinfo.server = strdup(serverAddr); 772 if (sinfo.server == NULL) { 773 return (NS_LDAP_MEMORY); 774 } 775 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 776 sinfo.serverFQDN = strdup(serverAddr); 777 if (sinfo.serverFQDN == NULL) { 778 free(sinfo.server); 779 return (NS_LDAP_MEMORY); 780 } 781 } 782 } 783 rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp, 784 fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags); 785 if (rc == NS_LDAP_SUCCESS || rc == 786 NS_LDAP_SUCCESS_WITH_INFO) { 787 exit_rc = rc; 788 goto create_con; 789 } else { 790 if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) { 791 (void) snprintf(errmsg, sizeof (errmsg), 792 "%s %s", gettext("makeConnection: " 793 "failed to open connection using " 794 "sasl/GSSAPI to"), *bindHost); 795 } else { 796 (void) snprintf(errmsg, sizeof (errmsg), 797 "%s %s", gettext("makeConnection: " 798 "failed to open connection to"), 799 *bindHost); 800 } 801 syslog(LOG_ERR, "libsldap: %s", errmsg); 802 __s_api_free_server_info(&sinfo); 803 return (rc); 804 } 805 } 806 807 /* No cached connection, create one */ 808 for (; ; ) { 809 if (host == NULL) 810 hReq = NS_CACHE_NEW; 811 else 812 hReq = NS_CACHE_NEXT; 813 rc = __s_api_requestServer(hReq, host, &sinfo, errorp, 814 serverAddrType); 815 if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) || 816 (host && (strcasecmp(host, sinfo.server) == 0))) { 817 /* Log the error */ 818 if (*errorp) { 819 (void) snprintf(errmsg, sizeof (errmsg), 820 "%s: (%s)", gettext("makeConnection: " 821 "unable to make LDAP connection, " 822 "request for a server failed"), 823 (*errorp)->message); 824 syslog(LOG_ERR, "libsldap: %s", errmsg); 825 } 826 827 __s_api_free_server_info(&sinfo); 828 if (host) 829 free(host); 830 return (NS_LDAP_OP_FAILED); 831 } 832 if (host) 833 free(host); 834 host = strdup(sinfo.server); 835 if (host == NULL) { 836 __s_api_free_server_info(&sinfo); 837 return (NS_LDAP_MEMORY); 838 } 839 840 /* check if server supports password management */ 841 passwd_mgmt = __s_api_contain_passwd_control_oid( 842 sinfo.controls); 843 /* check if server supports password less account mgmt */ 844 if (nopasswd_acct_mgmt && 845 !__s_api_contain_account_usable_control_oid( 846 sinfo.controls)) { 847 syslog(LOG_WARNING, "libsldap: server %s does not " 848 "provide account information without password", 849 host); 850 free(host); 851 __s_api_free_server_info(&sinfo); 852 return (NS_LDAP_OP_FAILED); 853 } 854 /* make the connection */ 855 rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp, 856 fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags); 857 /* if success, go to create connection structure */ 858 if (rc == NS_LDAP_SUCCESS || 859 rc == NS_LDAP_SUCCESS_WITH_INFO) { 860 exit_rc = rc; 861 break; 862 } 863 864 /* 865 * If not able to reach the server, inform the ldap 866 * cache manager that the server should be removed 867 * from its server list. Thus, the manager will not 868 * return this server on the next get-server request 869 * and will also reduce the server list refresh TTL, 870 * so that it will find out sooner when the server 871 * is up again. 872 */ 873 if (rc == NS_LDAP_INTERNAL && *errorp != NULL) { 874 if ((*errorp)->status == LDAP_CONNECT_ERROR || 875 (*errorp)->status == LDAP_SERVER_DOWN) { 876 /* Reset memory allocation error */ 877 memerr = 0; 878 /* 879 * We contacted a server that we could 880 * not either authenticate to or contact. 881 * If it is due to authentication, then 882 * we need to try the server again. So, 883 * do not remove the server yet, but 884 * add it to the bad server list. 885 * The caller routine will remove 886 * the servers if: 887 * a). A good server is found or 888 * b). All the possible methods 889 * are tried without finding 890 * a good server 891 */ 892 if (*badsrvrs == NULL) { 893 if (!(*badsrvrs = (char **)malloc 894 (sizeof (char *) * NUMTOMALLOC))) { 895 memerr = 1; 896 } 897 /* Allocate memory in chunks of NUMTOMALLOC */ 898 } else if ((totalbad % NUMTOMALLOC) == 899 NUMTOMALLOC - 1) { 900 char **tmpptr; 901 if (!(tmpptr = (char **)realloc( 902 *badsrvrs, 903 (sizeof (char *) * NUMTOMALLOC * 904 ((totalbad/NUMTOMALLOC) + 2))))) { 905 memerr = 1; 906 } else { 907 *badsrvrs = tmpptr; 908 } 909 } 910 /* 911 * Store host only if there were no unsuccessful 912 * memory allocations above 913 */ 914 if (!memerr && 915 !((*badsrvrs)[totalbad++] = strdup(host))) { 916 memerr = 1; 917 totalbad--; 918 } 919 (*badsrvrs)[totalbad] = NULL; 920 } 921 } 922 923 /* else, cleanup and go for the next server */ 924 __s_api_free_server_info(&sinfo); 925 926 /* Return if we had memory allocation errors */ 927 if (memerr) 928 return (NS_LDAP_MEMORY); 929 if (*errorp) { 930 /* 931 * If openConnection() failed due to 932 * password policy, or invalid credential, 933 * keep *errorp and exit 934 */ 935 if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD || 936 (*errorp)->status == LDAP_INVALID_CREDENTIALS) { 937 free(host); 938 return (rc); 939 } else { 940 (void) __ns_ldap_freeError(errorp); 941 *errorp = NULL; 942 } 943 } 944 } 945 946 create_con: 947 /* we have created ld, setup con structure */ 948 if (host) 949 free(host); 950 if ((con = calloc(1, sizeof (Connection))) == NULL) { 951 __s_api_free_server_info(&sinfo); 952 /* 953 * If password control attached in **errorp, 954 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 955 * free the error structure 956 */ 957 if (*errorp) { 958 (void) __ns_ldap_freeError(errorp); 959 *errorp = NULL; 960 } 961 (void) ldap_unbind(ld); 962 return (NS_LDAP_MEMORY); 963 } 964 965 con->serverAddr = sinfo.server; /* Store original format */ 966 if (sinfo.serverFQDN != NULL) { 967 free(sinfo.serverFQDN); 968 sinfo.serverFQDN = NULL; 969 } 970 con->saslMechanisms = sinfo.saslMechanisms; 971 con->controls = sinfo.controls; 972 973 con->auth = __ns_ldap_dupAuth(auth); 974 if (con->auth == NULL) { 975 (void) ldap_unbind(ld); 976 __s_api_freeConnection(con); 977 /* 978 * If password control attached in **errorp, 979 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 980 * free the error structure 981 */ 982 if (*errorp) { 983 (void) __ns_ldap_freeError(errorp); 984 *errorp = NULL; 985 } 986 return (NS_LDAP_MEMORY); 987 } 988 989 con->threadID = thr_self(); 990 con->pid = getpid(); 991 992 con->ld = ld; 993 /* add MT connection to the MT connection pool */ 994 if (conn_user != NULL && conn_user->conn_mt != NULL) { 995 if (__s_api_conn_mt_add(con, conn_user, errorp) == 996 NS_LDAP_SUCCESS) { 997 *conp = con; 998 return (exit_rc); 999 } else { 1000 (void) ldap_unbind(ld); 1001 __s_api_freeConnection(con); 1002 return ((*errorp)->status); 1003 } 1004 } 1005 1006 /* MT connection not supported or not required case */ 1007 if ((id = addConnection(con)) == -1) { 1008 (void) ldap_unbind(ld); 1009 __s_api_freeConnection(con); 1010 /* 1011 * If password control attached in **errorp, 1012 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 1013 * free the error structure 1014 */ 1015 if (*errorp) { 1016 (void) __ns_ldap_freeError(errorp); 1017 *errorp = NULL; 1018 } 1019 return (NS_LDAP_MEMORY); 1020 } 1021 #ifdef DEBUG 1022 (void) fprintf(stderr, "tid= %d: connection added into " 1023 "cache %d\n", thr_self(), id); 1024 fflush(stderr); 1025 #endif /* DEBUG */ 1026 *cID = id; 1027 *conp = con; 1028 return (exit_rc); 1029 } 1030 1031 /* 1032 * Return the specified connection to the pool. If necessary 1033 * delete the connection. 1034 */ 1035 1036 static void 1037 _DropConnection(ConnectionID cID, int flag, int fini) 1038 { 1039 Connection *cp; 1040 int id; 1041 int use_mutex = !fini; 1042 struct timeval zerotime; 1043 LDAPMessage *res; 1044 1045 zerotime.tv_sec = zerotime.tv_usec = 0L; 1046 1047 id = cID - CONID_OFFSET; 1048 if (id < 0 || id >= sessionPoolSize) 1049 return; 1050 #ifdef DEBUG 1051 (void) fprintf(stderr, 1052 "tid %d: Dropping connection cID=%d flag=0x%x\n", 1053 thr_self(), cID, flag); 1054 fflush(stderr); 1055 #endif /* DEBUG */ 1056 if (use_mutex) 1057 (void) mutex_lock(&sessionPoolLock); 1058 1059 cp = sessionPool[id]; 1060 /* sanity check before removing */ 1061 if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) { 1062 if (use_mutex) 1063 (void) mutex_unlock(&sessionPoolLock); 1064 return; 1065 } 1066 1067 if (!fini && 1068 ((flag & NS_LDAP_NEW_CONN) == 0) && 1069 ((flag & NS_LDAP_KEEP_CONN) || __s_api_nscd_proc() || 1070 __s_api_peruser_proc())) { 1071 /* release Connection (keep alive) */ 1072 cp->usedBit = B_FALSE; 1073 cp->threadID = 0; /* unmark the threadID */ 1074 /* 1075 * Do sanity cleanup of remaining results. 1076 */ 1077 while (ldap_result(cp->ld, LDAP_RES_ANY, LDAP_MSG_ALL, 1078 &zerotime, &res) > 0) { 1079 if (res != NULL) 1080 (void) ldap_msgfree(res); 1081 } 1082 if (use_mutex) 1083 (void) mutex_unlock(&sessionPoolLock); 1084 } else { 1085 /* delete Connection (disconnect) */ 1086 sessionPool[id] = NULL; 1087 if (use_mutex) 1088 (void) mutex_unlock(&sessionPoolLock); 1089 (void) ldap_unbind(cp->ld); 1090 __s_api_freeConnection(cp); 1091 } 1092 } 1093 1094 void 1095 DropConnection(ConnectionID cID, int flag) 1096 { 1097 _DropConnection(cID, flag, 0); 1098 } 1099 1100 /* 1101 * This routine is called after a bind operation is 1102 * done in openConnection() to process the password 1103 * management information, if any. 1104 * 1105 * Input: 1106 * bind_type: "simple" or "sasl/DIGEST-MD5" 1107 * ldaprc : ldap rc from the ldap bind operation 1108 * controls : controls returned by the server 1109 * errmsg : error message from the server 1110 * fail_if_new_pwd_reqd: 1111 * flag indicating if connection should be open 1112 * when password needs to change immediately 1113 * passwd_mgmt: 1114 * flag indicating if server supports password 1115 * policy/management 1116 * 1117 * Output : ns_ldap_error structure, which may contain 1118 * password status and number of seconds until 1119 * expired 1120 * 1121 * return rc: 1122 * NS_LDAP_EXTERNAL: error, connection should not open 1123 * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached 1124 * NS_LDAP_SUCCESS: OK to open connection 1125 * 1126 */ 1127 1128 static int 1129 process_pwd_mgmt(char *bind_type, int ldaprc, 1130 LDAPControl **controls, 1131 char *errmsg, ns_ldap_error_t **errorp, 1132 int fail_if_new_pwd_reqd, 1133 int passwd_mgmt) 1134 { 1135 char errstr[MAXERROR]; 1136 LDAPControl **ctrl = NULL; 1137 int exit_rc; 1138 ns_ldap_passwd_status_t pwd_status = NS_PASSWD_GOOD; 1139 int sec_until_exp = 0; 1140 1141 /* 1142 * errmsg may be an empty string, 1143 * even if ldaprc is LDAP_SUCCESS, 1144 * free the empty string if that's the case 1145 */ 1146 if (errmsg && 1147 (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) { 1148 ldap_memfree(errmsg); 1149 errmsg = NULL; 1150 } 1151 1152 if (ldaprc != LDAP_SUCCESS) { 1153 /* 1154 * try to map ldap rc and error message to 1155 * a password status 1156 */ 1157 if (errmsg) { 1158 if (passwd_mgmt) 1159 pwd_status = 1160 __s_api_set_passwd_status( 1161 ldaprc, errmsg); 1162 ldap_memfree(errmsg); 1163 } 1164 1165 (void) snprintf(errstr, sizeof (errstr), 1166 gettext("openConnection: " 1167 "%s bind failed " 1168 "- %s"), bind_type, ldap_err2string(ldaprc)); 1169 1170 if (pwd_status != NS_PASSWD_GOOD) { 1171 MKERROR_PWD_MGMT(*errorp, 1172 ldaprc, strdup(errstr), 1173 pwd_status, 0, NS_LDAP_MEMORY); 1174 } else { 1175 MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr), 1176 NS_LDAP_MEMORY); 1177 } 1178 if (controls) 1179 ldap_controls_free(controls); 1180 1181 return (NS_LDAP_INTERNAL); 1182 } 1183 1184 /* 1185 * ldaprc is LDAP_SUCCESS, 1186 * process the password management controls, if any 1187 */ 1188 exit_rc = NS_LDAP_SUCCESS; 1189 if (controls && passwd_mgmt) { 1190 /* 1191 * The control with the OID 1192 * 2.16.840.1.113730.3.4.4 (or 1193 * LDAP_CONTROL_PWEXPIRED, as defined 1194 * in the ldap.h header file) is the 1195 * expired password control. 1196 * 1197 * This control is used if the server 1198 * is configured to require users to 1199 * change their passwords when first 1200 * logging in and whenever the 1201 * passwords are reset. 1202 * 1203 * If the user is logging in for the 1204 * first time or if the user's 1205 * password has been reset, the 1206 * server sends this control to 1207 * indicate that the client needs to 1208 * change the password immediately. 1209 * 1210 * At this point, the only operation 1211 * that the client can perform is to 1212 * change the user's password. If the 1213 * client requests any other LDAP 1214 * operation, the server sends back 1215 * an LDAP_UNWILLING_TO_PERFORM 1216 * result code with an expired 1217 * password control. 1218 * 1219 * The control with the OID 1220 * 2.16.840.1.113730.3.4.5 (or 1221 * LDAP_CONTROL_PWEXPIRING, as 1222 * defined in the ldap.h header file) 1223 * is the password expiration warning 1224 * control. 1225 * 1226 * This control is used if the server 1227 * is configured to expire user 1228 * passwords after a certain amount 1229 * of time. 1230 * 1231 * The server sends this control back 1232 * to the client if the client binds 1233 * using a password that will soon 1234 * expire. The ldctl_value field of 1235 * the LDAPControl structure 1236 * specifies the number of seconds 1237 * before the password will expire. 1238 */ 1239 for (ctrl = controls; *ctrl; ctrl++) { 1240 1241 if (strcmp((*ctrl)->ldctl_oid, 1242 LDAP_CONTROL_PWEXPIRED) == 0) { 1243 /* 1244 * if the caller wants this bind 1245 * to fail, set up the error info. 1246 * If call to this function is 1247 * for searching the LDAP directory, 1248 * e.g., __ns_ldap_list(), 1249 * there's really no sense to 1250 * let a connection open and 1251 * then fail immediately afterward 1252 * on the LDAP search operation with 1253 * the LDAP_UNWILLING_TO_PERFORM rc 1254 */ 1255 pwd_status = 1256 NS_PASSWD_CHANGE_NEEDED; 1257 if (fail_if_new_pwd_reqd) { 1258 (void) snprintf(errstr, 1259 sizeof (errstr), 1260 gettext( 1261 "openConnection: " 1262 "%s bind " 1263 "failed " 1264 "- password " 1265 "expired. It " 1266 " needs to change " 1267 "immediately!"), 1268 bind_type); 1269 MKERROR_PWD_MGMT(*errorp, 1270 LDAP_SUCCESS, 1271 strdup(errstr), 1272 pwd_status, 1273 0, 1274 NS_LDAP_MEMORY); 1275 exit_rc = NS_LDAP_INTERNAL; 1276 } else { 1277 MKERROR_PWD_MGMT(*errorp, 1278 LDAP_SUCCESS, 1279 NULL, 1280 pwd_status, 1281 0, 1282 NS_LDAP_MEMORY); 1283 exit_rc = 1284 NS_LDAP_SUCCESS_WITH_INFO; 1285 } 1286 break; 1287 } else if (strcmp((*ctrl)->ldctl_oid, 1288 LDAP_CONTROL_PWEXPIRING) == 0) { 1289 pwd_status = 1290 NS_PASSWD_ABOUT_TO_EXPIRE; 1291 if ((*ctrl)-> 1292 ldctl_value.bv_len > 0 && 1293 (*ctrl)-> 1294 ldctl_value.bv_val) 1295 sec_until_exp = 1296 atoi((*ctrl)-> 1297 ldctl_value.bv_val); 1298 MKERROR_PWD_MGMT(*errorp, 1299 LDAP_SUCCESS, 1300 NULL, 1301 pwd_status, 1302 sec_until_exp, 1303 NS_LDAP_MEMORY); 1304 exit_rc = 1305 NS_LDAP_SUCCESS_WITH_INFO; 1306 break; 1307 } 1308 } 1309 } 1310 1311 if (controls) 1312 ldap_controls_free(controls); 1313 1314 return (exit_rc); 1315 } 1316 1317 static int 1318 ldap_in_nss_switch(char *db) 1319 { 1320 enum __nsw_parse_err pserr; 1321 struct __nsw_switchconfig *conf; 1322 struct __nsw_lookup *lkp; 1323 const char *name; 1324 int found = 0; 1325 1326 conf = __nsw_getconfig(db, &pserr); 1327 if (conf == NULL) { 1328 return (-1); 1329 } 1330 1331 /* check for skip and count other backends */ 1332 for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 1333 name = lkp->service_name; 1334 if (strcmp(name, "ldap") == 0) { 1335 found = 1; 1336 break; 1337 } 1338 } 1339 (void) __nsw_freeconfig(conf); 1340 return (found); 1341 } 1342 1343 static int 1344 openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth, 1345 int timeoutSec, ns_ldap_error_t **errorp, 1346 int fail_if_new_pwd_reqd, int passwd_mgmt, 1347 ns_conn_user_t *conn_user, int flags) 1348 { 1349 LDAP *ld = NULL; 1350 int ldapVersion = LDAP_VERSION3; 1351 int derefOption = LDAP_DEREF_ALWAYS; 1352 int zero = 0; 1353 int timeoutMilliSec = timeoutSec * 1000; 1354 uint16_t port = USE_DEFAULT_PORT; 1355 char *s; 1356 char errstr[MAXERROR]; 1357 int followRef; 1358 1359 ns_ldap_return_code ret_code = NS_LDAP_SUCCESS; 1360 1361 *errorp = NULL; 1362 *ldp = NULL; 1363 1364 /* determine if the host name contains a port number */ 1365 s = strchr(serverAddr, ']'); /* skip over ipv6 addr */ 1366 s = strchr(s != NULL ? s : serverAddr, ':'); 1367 if (s != NULL) { 1368 if (sscanf(s + 1, "%hu", &port) != 1) { 1369 (void) snprintf(errstr, 1370 sizeof (errstr), 1371 gettext("openConnection: cannot " 1372 "convert %s into a valid " 1373 "port number for the " 1374 "%s server. A default value " 1375 "will be used."), 1376 s, 1377 serverAddr); 1378 syslog(LOG_ERR, "libsldap: %s", errstr); 1379 } else { 1380 *s = '\0'; 1381 } 1382 } 1383 1384 ret_code = createSession(auth, 1385 serverAddr, 1386 port, 1387 timeoutMilliSec, 1388 &ld, 1389 errorp); 1390 if (s != NULL) { 1391 *s = ':'; 1392 } 1393 if (ret_code != NS_LDAP_SUCCESS) { 1394 return (ret_code); 1395 } 1396 1397 /* check to see if the underlying libsldap supports MT connection */ 1398 if (conn_user != NULL) { 1399 int rc; 1400 1401 rc = __s_api_check_libldap_MT_conn_support(conn_user, ld, 1402 errorp); 1403 if (rc != NS_LDAP_SUCCESS) { 1404 (void) ldap_unbind(ld); 1405 return (rc); 1406 } 1407 } 1408 1409 (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); 1410 (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 1411 /* 1412 * This library will handle the referral itself based on API flags or 1413 * configuration file specification. The LDAP bind operation is an 1414 * exception where we rely on the LDAP library to follow the referal. 1415 * 1416 * The LDAP follow referral option must be set to OFF for the libldap5 1417 * to pass the referral info up to this library. This option MUST be 1418 * set to OFF after we have performed a sucessful bind. If we are not 1419 * to follow referrals we MUST also set the LDAP follow referral option 1420 * to OFF before we perform an LDAP bind. 1421 */ 1422 ret_code = __s_api_toFollowReferrals(flags, &followRef, errorp); 1423 if (ret_code != NS_LDAP_SUCCESS) { 1424 (void) ldap_unbind(ld); 1425 return (ret_code); 1426 } 1427 1428 if (followRef) 1429 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 1430 else 1431 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 1432 1433 (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 1434 (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 1435 /* setup TCP/IP connect timeout */ 1436 (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 1437 &timeoutMilliSec); 1438 /* retry if LDAP I/O was interrupted */ 1439 (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 1440 1441 ret_code = performBind(auth, 1442 ld, 1443 timeoutSec, 1444 errorp, 1445 fail_if_new_pwd_reqd, 1446 passwd_mgmt); 1447 1448 if (ret_code == NS_LDAP_SUCCESS || 1449 ret_code == NS_LDAP_SUCCESS_WITH_INFO) { 1450 /* 1451 * Turn off LDAP referral following so that this library can 1452 * process referrals. 1453 */ 1454 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 1455 *ldp = ld; 1456 } 1457 1458 return (ret_code); 1459 } 1460 1461 /* 1462 * FUNCTION: __s_api_getDefaultAuth 1463 * 1464 * Constructs a credential for authentication using the config module. 1465 * 1466 * RETURN VALUES: 1467 * 1468 * NS_LDAP_SUCCESS If successful 1469 * NS_LDAP_CONFIG If there are any config errors. 1470 * NS_LDAP_MEMORY Memory errors. 1471 * NS_LDAP_OP_FAILED If there are no more authentication methods so can 1472 * not build a new authp. 1473 * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the 1474 * necessary fields of a cred for a given auth method 1475 * are not provided. 1476 * INPUT: 1477 * 1478 * cLevel Currently requested credential level to be tried 1479 * 1480 * aMethod Currently requested authentication method to be tried 1481 * 1482 * getAdmin If non 0, get Admin -i.e., not proxyAgent- DN and password 1483 * 1484 * OUTPUT: 1485 * 1486 * authp authentication method to use. 1487 */ 1488 static int 1489 __s_api_getDefaultAuth( 1490 int *cLevel, 1491 ns_auth_t *aMethod, 1492 ns_cred_t **authp, 1493 int getAdmin) 1494 { 1495 void **paramVal = NULL; 1496 char *modparamVal = NULL; 1497 int getUid = 0; 1498 int getPasswd = 0; 1499 int getCertpath = 0; 1500 int rc = 0; 1501 ns_ldap_error_t *errorp = NULL; 1502 UnixCred_t *AdminCred = NULL; 1503 1504 #ifdef DEBUG 1505 (void) fprintf(stderr, "__s_api_getDefaultAuth START\n"); 1506 #endif 1507 1508 if (aMethod == NULL) { 1509 /* Require an Auth */ 1510 return (NS_LDAP_INVALID_PARAM); 1511 1512 } 1513 /* 1514 * credential level "self" can work with auth method sasl/GSSAPI only 1515 */ 1516 if (cLevel && *cLevel == NS_LDAP_CRED_SELF && 1517 aMethod->saslmech != NS_LDAP_SASL_GSSAPI) 1518 return (NS_LDAP_INVALID_PARAM); 1519 1520 *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t)); 1521 if ((*authp) == NULL) 1522 return (NS_LDAP_MEMORY); 1523 1524 (*authp)->auth = *aMethod; 1525 1526 switch (aMethod->type) { 1527 case NS_LDAP_AUTH_NONE: 1528 return (NS_LDAP_SUCCESS); 1529 case NS_LDAP_AUTH_SIMPLE: 1530 getUid++; 1531 getPasswd++; 1532 break; 1533 case NS_LDAP_AUTH_SASL: 1534 if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 1535 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) { 1536 getUid++; 1537 getPasswd++; 1538 } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) { 1539 (void) __ns_ldap_freeCred(authp); 1540 return (NS_LDAP_INVALID_PARAM); 1541 } 1542 break; 1543 case NS_LDAP_AUTH_TLS: 1544 if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) || 1545 ((aMethod->tlstype == NS_LDAP_TLS_SASL) && 1546 ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 1547 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) { 1548 getUid++; 1549 getPasswd++; 1550 getCertpath++; 1551 } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) { 1552 getCertpath++; 1553 } else { 1554 (void) __ns_ldap_freeCred(authp); 1555 return (NS_LDAP_INVALID_PARAM); 1556 } 1557 break; 1558 } 1559 1560 if (getUid) { 1561 paramVal = NULL; 1562 if (getAdmin) { 1563 /* 1564 * Assume AdminCred has been retrieved from 1565 * ldap_cachemgr already. It will not work 1566 * without userID or password. Flags getUid 1567 * and getPasswd should always be set 1568 * together. 1569 */ 1570 AdminCred = calloc(1, sizeof (UnixCred_t)); 1571 if (AdminCred == NULL) { 1572 (void) __ns_ldap_freeCred(authp); 1573 return (NS_LDAP_MEMORY); 1574 } 1575 1576 rc = requestAdminCred(&AdminCred, &errorp); 1577 if (rc != NS_LDAP_SUCCESS) { 1578 (void) __ns_ldap_freeCred(authp); 1579 (void) __ns_ldap_freeUnixCred(&AdminCred); 1580 (void) __ns_ldap_freeError(&errorp); 1581 return (rc); 1582 } 1583 1584 if (AdminCred->userID == NULL) { 1585 (void) __ns_ldap_freeCred(authp); 1586 (void) __ns_ldap_freeUnixCred(&AdminCred); 1587 return (NS_LDAP_INVALID_PARAM); 1588 } 1589 (*authp)->cred.unix_cred.userID = AdminCred->userID; 1590 AdminCred->userID = NULL; 1591 } else { 1592 rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P, 1593 ¶mVal, &errorp); 1594 if (rc != NS_LDAP_SUCCESS) { 1595 (void) __ns_ldap_freeCred(authp); 1596 (void) __ns_ldap_freeError(&errorp); 1597 return (rc); 1598 } 1599 1600 if (paramVal == NULL || *paramVal == NULL) { 1601 (void) __ns_ldap_freeCred(authp); 1602 return (NS_LDAP_INVALID_PARAM); 1603 } 1604 1605 (*authp)->cred.unix_cred.userID = 1606 strdup((char *)*paramVal); 1607 (void) __ns_ldap_freeParam(¶mVal); 1608 } 1609 if ((*authp)->cred.unix_cred.userID == NULL) { 1610 (void) __ns_ldap_freeCred(authp); 1611 (void) __ns_ldap_freeUnixCred(&AdminCred); 1612 return (NS_LDAP_MEMORY); 1613 } 1614 } 1615 if (getPasswd) { 1616 paramVal = NULL; 1617 if (getAdmin) { 1618 /* 1619 * Assume AdminCred has been retrieved from 1620 * ldap_cachemgr already. It will not work 1621 * without the userID anyway because for 1622 * getting admin credential, flags getUid 1623 * and getPasswd should always be set 1624 * together. 1625 */ 1626 if (AdminCred == NULL || AdminCred->passwd == NULL) { 1627 (void) __ns_ldap_freeCred(authp); 1628 (void) __ns_ldap_freeUnixCred(&AdminCred); 1629 return (NS_LDAP_INVALID_PARAM); 1630 } 1631 modparamVal = dvalue(AdminCred->passwd); 1632 } else { 1633 rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P, 1634 ¶mVal, &errorp); 1635 if (rc != NS_LDAP_SUCCESS) { 1636 (void) __ns_ldap_freeCred(authp); 1637 (void) __ns_ldap_freeError(&errorp); 1638 return (rc); 1639 } 1640 1641 if (paramVal == NULL || *paramVal == NULL) { 1642 (void) __ns_ldap_freeCred(authp); 1643 return (NS_LDAP_INVALID_PARAM); 1644 } 1645 1646 modparamVal = dvalue((char *)*paramVal); 1647 (void) __ns_ldap_freeParam(¶mVal); 1648 } 1649 1650 if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) { 1651 (void) __ns_ldap_freeCred(authp); 1652 (void) __ns_ldap_freeUnixCred(&AdminCred); 1653 if (modparamVal != NULL) 1654 free(modparamVal); 1655 return (NS_LDAP_INVALID_PARAM); 1656 } 1657 1658 (*authp)->cred.unix_cred.passwd = modparamVal; 1659 } 1660 if (getCertpath) { 1661 paramVal = NULL; 1662 if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 1663 ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 1664 (void) __ns_ldap_freeCred(authp); 1665 (void) __ns_ldap_freeUnixCred(&AdminCred); 1666 (void) __ns_ldap_freeError(&errorp); 1667 *authp = NULL; 1668 return (rc); 1669 } 1670 1671 if (paramVal == NULL || *paramVal == NULL) { 1672 (void) __ns_ldap_freeCred(authp); 1673 (void) __ns_ldap_freeUnixCred(&AdminCred); 1674 *authp = NULL; 1675 return (NS_LDAP_INVALID_PARAM); 1676 } 1677 1678 (*authp)->hostcertpath = strdup((char *)*paramVal); 1679 (void) __ns_ldap_freeParam(¶mVal); 1680 if ((*authp)->hostcertpath == NULL) { 1681 (void) __ns_ldap_freeCred(authp); 1682 (void) __ns_ldap_freeUnixCred(&AdminCred); 1683 *authp = NULL; 1684 return (NS_LDAP_MEMORY); 1685 } 1686 } 1687 (void) __ns_ldap_freeUnixCred(&AdminCred); 1688 return (NS_LDAP_SUCCESS); 1689 } 1690 1691 /* 1692 * FUNCTION: getConnection 1693 * 1694 * internal version of __s_api_getConnection() 1695 */ 1696 static int 1697 getConnection( 1698 const char *server, 1699 const int flags, 1700 const ns_cred_t *cred, /* credentials for bind */ 1701 ConnectionID *sessionId, 1702 Connection **session, 1703 ns_ldap_error_t **errorp, 1704 int fail_if_new_pwd_reqd, 1705 int nopasswd_acct_mgmt, 1706 ns_conn_user_t *conn_user) 1707 { 1708 char errmsg[MAXERROR]; 1709 ns_auth_t **aMethod = NULL; 1710 ns_auth_t **aNext = NULL; 1711 int **cLevel = NULL; 1712 int **cNext = NULL; 1713 int timeoutSec = NS_DEFAULT_BIND_TIMEOUT; 1714 int rc; 1715 Connection *con = NULL; 1716 int sec = 1; 1717 ns_cred_t *authp = NULL; 1718 ns_cred_t anon; 1719 int version = NS_LDAP_V2, self_gssapi_only = 0; 1720 void **paramVal = NULL; 1721 char **badSrvrs = NULL; /* List of problem hostnames */ 1722 1723 if ((session == NULL) || (sessionId == NULL)) { 1724 return (NS_LDAP_INVALID_PARAM); 1725 } 1726 *session = NULL; 1727 1728 /* reuse MT connection if needed and if available */ 1729 if (conn_user != NULL) { 1730 rc = __s_api_conn_mt_get(server, flags, cred, session, errorp, 1731 conn_user); 1732 if (rc != NS_LDAP_NOTFOUND) 1733 return (rc); 1734 } 1735 1736 /* get profile version number */ 1737 if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, 1738 ¶mVal, errorp)) != NS_LDAP_SUCCESS) 1739 return (rc); 1740 if (paramVal == NULL) { 1741 (void) sprintf(errmsg, gettext("getConnection: no file " 1742 "version")); 1743 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg), 1744 NS_LDAP_CONFIG); 1745 return (NS_LDAP_CONFIG); 1746 } 1747 if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0) 1748 version = NS_LDAP_V1; 1749 (void) __ns_ldap_freeParam((void ***)¶mVal); 1750 1751 /* Get the bind timeout value */ 1752 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp); 1753 if (paramVal != NULL && *paramVal != NULL) { 1754 timeoutSec = **((int **)paramVal); 1755 (void) __ns_ldap_freeParam(¶mVal); 1756 } 1757 if (*errorp) 1758 (void) __ns_ldap_freeError(errorp); 1759 1760 if (cred == NULL) { 1761 /* Get the authentication method list */ 1762 if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, 1763 (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS) 1764 return (rc); 1765 if (aMethod == NULL) { 1766 aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *)); 1767 if (aMethod == NULL) 1768 return (NS_LDAP_MEMORY); 1769 aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t)); 1770 if (aMethod[0] == NULL) { 1771 free(aMethod); 1772 return (NS_LDAP_MEMORY); 1773 } 1774 if (version == NS_LDAP_V1) 1775 (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE; 1776 else { 1777 (aMethod[0])->type = NS_LDAP_AUTH_SASL; 1778 (aMethod[0])->saslmech = 1779 NS_LDAP_SASL_DIGEST_MD5; 1780 (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE; 1781 } 1782 } 1783 1784 /* Get the credential level list */ 1785 if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P, 1786 (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) { 1787 (void) __ns_ldap_freeParam((void ***)&aMethod); 1788 return (rc); 1789 } 1790 if (cLevel == NULL) { 1791 cLevel = (int **)calloc(2, sizeof (int *)); 1792 if (cLevel == NULL) 1793 return (NS_LDAP_MEMORY); 1794 cLevel[0] = (int *)calloc(1, sizeof (int)); 1795 if (cLevel[0] == NULL) 1796 return (NS_LDAP_MEMORY); 1797 if (version == NS_LDAP_V1) 1798 *(cLevel[0]) = NS_LDAP_CRED_PROXY; 1799 else 1800 *(cLevel[0]) = NS_LDAP_CRED_ANON; 1801 } 1802 } 1803 1804 /* setup the anon credential for anonymous connection */ 1805 (void) memset(&anon, 0, sizeof (ns_cred_t)); 1806 anon.auth.type = NS_LDAP_AUTH_NONE; 1807 1808 for (;;) { 1809 if (cred != NULL) { 1810 /* using specified auth method */ 1811 rc = makeConnection(&con, server, cred, 1812 sessionId, timeoutSec, errorp, 1813 fail_if_new_pwd_reqd, 1814 nopasswd_acct_mgmt, flags, &badSrvrs, conn_user); 1815 /* not using bad server if credentials were supplied */ 1816 if (badSrvrs && *badSrvrs) { 1817 __s_api_free2dArray(badSrvrs); 1818 badSrvrs = NULL; 1819 } 1820 if (rc == NS_LDAP_SUCCESS || 1821 rc == NS_LDAP_SUCCESS_WITH_INFO) { 1822 *session = con; 1823 break; 1824 } 1825 } else { 1826 self_gssapi_only = __s_api_self_gssapi_only_get(); 1827 /* for every cred level */ 1828 for (cNext = cLevel; *cNext != NULL; cNext++) { 1829 if (self_gssapi_only && 1830 **cNext != NS_LDAP_CRED_SELF) 1831 continue; 1832 if (**cNext == NS_LDAP_CRED_ANON) { 1833 /* 1834 * make connection anonymously 1835 * Free the down server list before 1836 * looping through 1837 */ 1838 if (badSrvrs && *badSrvrs) { 1839 __s_api_free2dArray(badSrvrs); 1840 badSrvrs = NULL; 1841 } 1842 rc = makeConnection(&con, server, &anon, 1843 sessionId, timeoutSec, errorp, 1844 fail_if_new_pwd_reqd, 1845 nopasswd_acct_mgmt, flags, 1846 &badSrvrs, conn_user); 1847 if (rc == NS_LDAP_SUCCESS || 1848 rc == 1849 NS_LDAP_SUCCESS_WITH_INFO) { 1850 *session = con; 1851 goto done; 1852 } 1853 continue; 1854 } 1855 /* for each cred level */ 1856 for (aNext = aMethod; *aNext != NULL; aNext++) { 1857 if (self_gssapi_only && 1858 (*aNext)->saslmech != 1859 NS_LDAP_SASL_GSSAPI) 1860 continue; 1861 /* 1862 * self coexists with sasl/GSSAPI only 1863 * and non-self coexists with non-gssapi 1864 * only 1865 */ 1866 if ((**cNext == NS_LDAP_CRED_SELF && 1867 (*aNext)->saslmech != 1868 NS_LDAP_SASL_GSSAPI) || 1869 (**cNext != NS_LDAP_CRED_SELF && 1870 (*aNext)->saslmech == 1871 NS_LDAP_SASL_GSSAPI)) 1872 continue; 1873 /* make connection and authenticate */ 1874 /* with default credentials */ 1875 authp = NULL; 1876 rc = __s_api_getDefaultAuth(*cNext, 1877 *aNext, &authp, 1878 flags & NS_LDAP_READ_SHADOW); 1879 if (rc != NS_LDAP_SUCCESS) { 1880 continue; 1881 } 1882 /* 1883 * Free the down server list before 1884 * looping through 1885 */ 1886 if (badSrvrs && *badSrvrs) { 1887 __s_api_free2dArray(badSrvrs); 1888 badSrvrs = NULL; 1889 } 1890 rc = makeConnection(&con, server, authp, 1891 sessionId, timeoutSec, errorp, 1892 fail_if_new_pwd_reqd, 1893 nopasswd_acct_mgmt, flags, 1894 &badSrvrs, conn_user); 1895 (void) __ns_ldap_freeCred(&authp); 1896 if (rc == NS_LDAP_SUCCESS || 1897 rc == 1898 NS_LDAP_SUCCESS_WITH_INFO) { 1899 *session = con; 1900 goto done; 1901 } 1902 } 1903 } 1904 } 1905 if (flags & NS_LDAP_HARD) { 1906 if (sec < LDAPMAXHARDLOOKUPTIME) 1907 sec *= 2; 1908 (void) sleep(sec); 1909 } else { 1910 break; 1911 } 1912 } 1913 1914 done: 1915 if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) { 1916 /* 1917 * self_gssapi_only is true but no self/sasl/gssapi is 1918 * configured 1919 */ 1920 rc = NS_LDAP_CONFIG; 1921 } 1922 1923 (void) __ns_ldap_freeParam((void ***)&aMethod); 1924 (void) __ns_ldap_freeParam((void ***)&cLevel); 1925 1926 if (badSrvrs && *badSrvrs) { 1927 /* 1928 * At this point, either we have a successful 1929 * connection or exhausted all the possible auths. 1930 * and creds. Mark the problem servers as down 1931 * so that the problem servers are not contacted 1932 * again until the refresh_ttl expires. 1933 */ 1934 (void) __s_api_removeBadServers(badSrvrs); 1935 __s_api_free2dArray(badSrvrs); 1936 } 1937 return (rc); 1938 } 1939 1940 /* 1941 * FUNCTION: __s_api_getConnection 1942 * 1943 * Bind to the specified server or one from the server 1944 * list and return the pointer. 1945 * 1946 * This function can rebind or not (NS_LDAP_HARD), it can require a 1947 * credential or bind anonymously 1948 * 1949 * This function follows the DUA configuration schema algorithm 1950 * 1951 * RETURN VALUES: 1952 * 1953 * NS_LDAP_SUCCESS A connection was made successfully. 1954 * NS_LDAP_SUCCESS_WITH_INFO 1955 * A connection was made successfully, but with 1956 * password management info in *errorp 1957 * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function. 1958 * NS_LDAP_CONFIG If there are any config errors. 1959 * NS_LDAP_MEMORY Memory errors. 1960 * NS_LDAP_INTERNAL If there was a ldap error. 1961 * 1962 * INPUT: 1963 * 1964 * server Bind to this LDAP server only 1965 * flags If NS_LDAP_HARD is set function will not return until it has 1966 * a connection unless there is a authentication problem. 1967 * If NS_LDAP_NEW_CONN is set the function must force a new 1968 * connection to be created 1969 * If NS_LDAP_KEEP_CONN is set the connection is to be kept open 1970 * auth Credentials for bind. This could be NULL in which case 1971 * a default cred built from the config module is used. 1972 * sessionId cookie that points to a previous session 1973 * fail_if_new_pwd_reqd 1974 * a flag indicating this function should fail if the passwd 1975 * in auth needs to change immediately 1976 * nopasswd_acct_mgmt 1977 * a flag indicating that makeConnection should check before 1978 * binding if server supports LDAP V3 password less 1979 * account management 1980 * 1981 * OUTPUT: 1982 * 1983 * session pointer to a session with connection information 1984 * errorp Set if there are any INTERNAL, or CONFIG error. 1985 */ 1986 int 1987 __s_api_getConnection( 1988 const char *server, 1989 const int flags, 1990 const ns_cred_t *cred, /* credentials for bind */ 1991 ConnectionID *sessionId, 1992 Connection **session, 1993 ns_ldap_error_t **errorp, 1994 int fail_if_new_pwd_reqd, 1995 int nopasswd_acct_mgmt, 1996 ns_conn_user_t *conn_user) 1997 { 1998 int rc; 1999 2000 rc = getConnection(server, flags, cred, sessionId, session, 2001 errorp, fail_if_new_pwd_reqd, nopasswd_acct_mgmt, 2002 conn_user); 2003 2004 if (rc != NS_LDAP_SUCCESS && rc != NS_LDAP_SUCCESS_WITH_INFO) { 2005 if (conn_user != NULL && conn_user->conn_mt != NULL) 2006 __s_api_conn_mt_remove(conn_user, rc, errorp); 2007 } 2008 2009 return (rc); 2010 } 2011 2012 void 2013 __s_api_free_sessionPool() 2014 { 2015 int id; 2016 2017 (void) mutex_lock(&sessionPoolLock); 2018 2019 if (sessionPool != NULL) { 2020 for (id = 0; id < sessionPoolSize; id++) 2021 _DropConnection(id + CONID_OFFSET, 0, 1); 2022 free(sessionPool); 2023 sessionPool = NULL; 2024 sessionPoolSize = 0; 2025 } 2026 (void) mutex_unlock(&sessionPoolLock); 2027 } 2028 2029 /* 2030 * This function initializes a TLS LDAP session. On success LDAP* is returned 2031 * (pointed by *ldp). Otherwise, the function returns an NS error code and 2032 * provide an additional info pointed by *errorp. 2033 */ 2034 static 2035 ns_ldap_return_code 2036 createTLSSession(const ns_cred_t *auth, const char *serverAddr, 2037 uint16_t port, int timeoutMilliSec, 2038 LDAP **ldp, ns_ldap_error_t **errorp) 2039 { 2040 const char *hostcertpath; 2041 char *alloc_hcp = NULL, errstr[MAXERROR]; 2042 int ldap_rc; 2043 2044 #ifdef DEBUG 2045 (void) fprintf(stderr, "tid= %d: +++TLS transport\n", 2046 thr_self()); 2047 #endif /* DEBUG */ 2048 2049 if (prldap_set_session_option(NULL, NULL, 2050 PRLDAP_OPT_IO_MAX_TIMEOUT, 2051 timeoutMilliSec) != LDAP_SUCCESS) { 2052 (void) snprintf(errstr, sizeof (errstr), 2053 gettext("createTLSSession: failed to initialize " 2054 "TLS security")); 2055 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2056 strdup(errstr), NS_LDAP_MEMORY); 2057 return (NS_LDAP_INTERNAL); 2058 } 2059 2060 hostcertpath = auth->hostcertpath; 2061 if (hostcertpath == NULL) { 2062 alloc_hcp = __s_get_hostcertpath(); 2063 hostcertpath = alloc_hcp; 2064 } 2065 2066 if (hostcertpath == NULL) 2067 return (NS_LDAP_MEMORY); 2068 2069 if ((ldap_rc = ldapssl_client_init(hostcertpath, NULL)) < 0) { 2070 if (alloc_hcp != NULL) { 2071 free(alloc_hcp); 2072 } 2073 (void) snprintf(errstr, sizeof (errstr), 2074 gettext("createTLSSession: failed to initialize " 2075 "TLS security (%s)"), 2076 ldapssl_err2string(ldap_rc)); 2077 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2078 strdup(errstr), NS_LDAP_MEMORY); 2079 return (NS_LDAP_INTERNAL); 2080 } 2081 if (alloc_hcp) 2082 free(alloc_hcp); 2083 2084 *ldp = ldapssl_init(serverAddr, port, 1); 2085 2086 if (*ldp == NULL || 2087 ldapssl_install_gethostbyaddr(*ldp, "ldap") != 0) { 2088 (void) snprintf(errstr, sizeof (errstr), 2089 gettext("createTLSSession: failed to connect " 2090 "using TLS (%s)"), strerror(errno)); 2091 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2092 strdup(errstr), NS_LDAP_MEMORY); 2093 return (NS_LDAP_INTERNAL); 2094 } 2095 2096 return (NS_LDAP_SUCCESS); 2097 } 2098 2099 /* 2100 * Convert (resolve) hostname to IP address. 2101 * 2102 * INPUT: 2103 * 2104 * server - \[IPv6_address\][:port] 2105 * - IPv4_address[:port] 2106 * - hostname[:port] 2107 * 2108 * newaddr - Buffer to which this function writes resulting address, 2109 * including the port number, if specified in server argument. 2110 * 2111 * newaddr_size - Size of the newaddr buffer. 2112 * 2113 * errstr - Buffer to which error string is written if error occurs. 2114 * 2115 * errstr_size - Size of the errstr buffer. 2116 * 2117 * OUTPUT: 2118 * 2119 * Returns 1 for success, 0 in case of error. 2120 * 2121 * newaddr - See above (INPUT section). 2122 * 2123 * errstr - See above (INPUT section). 2124 */ 2125 static int 2126 cvt_hostname2ip(char *server, char *newaddr, int newaddr_size, 2127 char *errstr, int errstr_size) 2128 { 2129 char *s; 2130 unsigned short port = 0; 2131 int err; 2132 char buffer[NSS_BUFLEN_HOSTS]; 2133 struct hostent result; 2134 2135 /* Determine if the host name contains a port number. */ 2136 2137 /* Skip over IPv6 address. */ 2138 s = strchr(server, ']'); 2139 s = strchr(s != NULL ? s : server, ':'); 2140 if (s != NULL) { 2141 if (sscanf(s + 1, "%hu", &port) != 1) { 2142 /* Address misformatted. No port number after : */ 2143 (void) snprintf(errstr, errstr_size, "%s", 2144 gettext("Invalid host:port format")); 2145 return (0); 2146 } else 2147 /* Cut off the :<port> part. */ 2148 *s = '\0'; 2149 } 2150 2151 buffer[0] = '\0'; 2152 /* 2153 * Resolve hostname and fill in hostent structure. 2154 */ 2155 if (!__s_api_hostname2ip(server, &result, buffer, NSS_BUFLEN_HOSTS, 2156 &err)) { 2157 /* 2158 * The only possible error here could be TRY_AGAIN if buffer was 2159 * not big enough. NSS_BUFLEN_HOSTS should have been enough 2160 * though. 2161 */ 2162 (void) snprintf(errstr, errstr_size, "%s", 2163 gettext("Unable to resolve address.")); 2164 return (0); 2165 } 2166 2167 2168 buffer[0] = '\0'; 2169 /* 2170 * Convert the address to string. 2171 */ 2172 if (!inet_ntop(result.h_addrtype, result.h_addr_list[0], buffer, 2173 NSS_BUFLEN_HOSTS)) { 2174 /* There's not much we can do. */ 2175 (void) snprintf(errstr, errstr_size, "%s", 2176 gettext("Unable to convert address to string.")); 2177 return (0); 2178 } 2179 2180 /* Put together the address and the port */ 2181 if (port > 0) { 2182 switch (result.h_addrtype) { 2183 case AF_INET6: 2184 (void) snprintf(newaddr, 2185 /* [IP]:<port>\0 */ 2186 1 + strlen(buffer) + 1 + 1 + 5 + 1, 2187 "[%s]:%hu", 2188 buffer, 2189 port); 2190 break; 2191 /* AF_INET */ 2192 default : 2193 (void) snprintf(newaddr, 2194 /* IP:<port>\0 */ 2195 strlen(buffer) + 1 + 5 + 1, 2196 "%s:%hu", 2197 buffer, 2198 port); 2199 break; 2200 } 2201 } else { 2202 (void) strncpy(newaddr, buffer, newaddr_size); 2203 } 2204 2205 return (1); 2206 } 2207 2208 2209 /* 2210 * This finction initializes a none-TLS LDAP session. On success LDAP* 2211 * is returned (pointed by *ldp). Otherwise, the function returns 2212 * an NS error code and provides an additional info pointed by *errorp. 2213 */ 2214 static 2215 ns_ldap_return_code 2216 createNonTLSSession(const char *serverAddr, 2217 uint16_t port, int gssapi, 2218 LDAP **ldp, ns_ldap_error_t **errorp) 2219 { 2220 char errstr[MAXERROR]; 2221 char *addr; 2222 int is_ip = 0; 2223 /* [INET6_ADDRSTRLEN]:<port>\0 */ 2224 char svraddr[1+INET6_ADDRSTRLEN+1+1+5+1]; 2225 #ifdef DEBUG 2226 (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n", 2227 thr_self()); 2228 #endif /* DEBUG */ 2229 2230 if (gssapi == 0) { 2231 is_ip = (__s_api_isipv4((char *)serverAddr) || 2232 __s_api_isipv6((char *)serverAddr)); 2233 } 2234 2235 /* 2236 * Let's try to resolve IP address of server. 2237 */ 2238 if (is_ip == 0 && !gssapi && (ldap_in_nss_switch((char *)"hosts") > 0 || 2239 ldap_in_nss_switch((char *)"ipnodes") > 0)) { 2240 addr = strdup(serverAddr); 2241 if (addr == NULL) 2242 return (NS_LDAP_MEMORY); 2243 svraddr[0] = '\0'; 2244 if (cvt_hostname2ip(addr, svraddr, sizeof (svraddr), 2245 errstr, MAXERROR) == 1) { 2246 serverAddr = svraddr; 2247 free(addr); 2248 } else { 2249 free(addr); 2250 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2251 strdup(errstr), NS_LDAP_MEMORY); 2252 return (NS_LDAP_INTERNAL); 2253 } 2254 } 2255 2256 /* Warning message IF cannot connect to host(s) */ 2257 if ((*ldp = ldap_init((char *)serverAddr, port)) == NULL) { 2258 char *p = strerror(errno); 2259 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2260 strdup(p), NS_LDAP_MEMORY); 2261 return (NS_LDAP_INTERNAL); 2262 } 2263 2264 return (NS_LDAP_SUCCESS); 2265 } 2266 2267 /* 2268 * This finction initializes an LDAP session. 2269 * 2270 * INPUT: 2271 * auth - a structure specified an authenticastion method and credentials, 2272 * serverAddr - the address of a server to which a connection 2273 * will be established, 2274 * port - a port being listened by the server, 2275 * timeoutMilliSec - a timeout in milliseconds for the Bind operation. 2276 * 2277 * OUTPUT: 2278 * ldp - a pointer to an LDAP structure which will be used 2279 * for all the subsequent operations against the server. 2280 * If an error occurs, the function returns an NS error code 2281 * and provides an additional info pointed by *errorp. 2282 */ 2283 static 2284 ns_ldap_return_code 2285 createSession(const ns_cred_t *auth, const char *serverAddr, 2286 uint16_t port, int timeoutMilliSec, 2287 LDAP **ldp, ns_ldap_error_t **errorp) 2288 { 2289 int useSSL = 0, gssapi = 0; 2290 char errstr[MAXERROR]; 2291 2292 switch (auth->auth.type) { 2293 case NS_LDAP_AUTH_NONE: 2294 case NS_LDAP_AUTH_SIMPLE: 2295 case NS_LDAP_AUTH_SASL: 2296 break; 2297 case NS_LDAP_AUTH_TLS: 2298 useSSL = 1; 2299 break; 2300 default: 2301 (void) sprintf(errstr, 2302 gettext("openConnection: unsupported " 2303 "authentication method (%d)"), auth->auth.type); 2304 MKERROR(LOG_WARNING, *errorp, 2305 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 2306 NS_LDAP_MEMORY); 2307 return (NS_LDAP_INTERNAL); 2308 } 2309 2310 if (port == USE_DEFAULT_PORT) { 2311 port = useSSL ? LDAPS_PORT : LDAP_PORT; 2312 } 2313 2314 if (auth->auth.type == NS_LDAP_AUTH_SASL && 2315 auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) 2316 gssapi = 1; 2317 2318 if (useSSL) 2319 return (createTLSSession(auth, serverAddr, port, 2320 timeoutMilliSec, ldp, errorp)); 2321 else 2322 return (createNonTLSSession(serverAddr, port, gssapi, 2323 ldp, errorp)); 2324 } 2325 2326 /* 2327 * This finction performs a non-SASL bind operation. If an error accures, 2328 * the function returns an NS error code and provides an additional info 2329 * pointed by *errorp. 2330 */ 2331 static 2332 ns_ldap_return_code 2333 doSimpleBind(const ns_cred_t *auth, 2334 LDAP *ld, 2335 int timeoutSec, 2336 ns_ldap_error_t **errorp, 2337 int fail_if_new_pwd_reqd, 2338 int passwd_mgmt) 2339 { 2340 char *binddn, *passwd, errstr[MAXERROR], *errmsg; 2341 int msgId, errnum = 0, ldap_rc; 2342 ns_ldap_return_code ret_code; 2343 LDAPMessage *resultMsg = NULL; 2344 LDAPControl **controls; 2345 struct timeval tv; 2346 2347 binddn = auth->cred.unix_cred.userID; 2348 passwd = auth->cred.unix_cred.passwd; 2349 if (passwd == NULL || *passwd == '\0' || 2350 binddn == NULL || *binddn == '\0') { 2351 (void) sprintf(errstr, gettext("openConnection: " 2352 "missing credentials for Simple bind")); 2353 MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS, 2354 strdup(errstr), NS_LDAP_MEMORY); 2355 (void) ldap_unbind(ld); 2356 return (NS_LDAP_INTERNAL); 2357 } 2358 2359 #ifdef DEBUG 2360 (void) fprintf(stderr, "tid= %d: +++Simple bind\n", 2361 thr_self()); 2362 #endif /* DEBUG */ 2363 msgId = ldap_simple_bind(ld, binddn, passwd); 2364 2365 if (msgId == -1) { 2366 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 2367 (void *)&errnum); 2368 (void) snprintf(errstr, sizeof (errstr), 2369 gettext("openConnection: simple bind failed " 2370 "- %s"), ldap_err2string(errnum)); 2371 (void) ldap_unbind(ld); 2372 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 2373 NS_LDAP_MEMORY); 2374 return (NS_LDAP_INTERNAL); 2375 } 2376 2377 tv.tv_sec = timeoutSec; 2378 tv.tv_usec = 0; 2379 ldap_rc = ldap_result(ld, msgId, 0, &tv, &resultMsg); 2380 2381 if ((ldap_rc == -1) || (ldap_rc == 0)) { 2382 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 2383 (void *)&errnum); 2384 (void) snprintf(errstr, sizeof (errstr), 2385 gettext("openConnection: simple bind failed " 2386 "- %s"), ldap_err2string(errnum)); 2387 (void) ldap_msgfree(resultMsg); 2388 (void) ldap_unbind(ld); 2389 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 2390 NS_LDAP_MEMORY); 2391 return (NS_LDAP_INTERNAL); 2392 } 2393 2394 /* 2395 * get ldaprc, controls, and error msg 2396 */ 2397 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 2398 &errmsg, NULL, &controls, 1); 2399 2400 if (ldap_rc != LDAP_SUCCESS) { 2401 (void) snprintf(errstr, sizeof (errstr), 2402 gettext("openConnection: simple bind failed " 2403 "- unable to parse result")); 2404 (void) ldap_unbind(ld); 2405 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2406 strdup(errstr), NS_LDAP_MEMORY); 2407 return (NS_LDAP_INTERNAL); 2408 } 2409 2410 /* process the password management info, if any */ 2411 ret_code = process_pwd_mgmt("simple", 2412 errnum, controls, errmsg, 2413 errorp, 2414 fail_if_new_pwd_reqd, 2415 passwd_mgmt); 2416 2417 if (ret_code == NS_LDAP_INTERNAL) { 2418 (void) ldap_unbind(ld); 2419 } 2420 2421 return (ret_code); 2422 } 2423 2424 /* 2425 * This finction performs a SASL bind operation. If an error accures, 2426 * the function returns an NS error code and provides an additional info 2427 * pointed by *errorp. 2428 */ 2429 static 2430 ns_ldap_return_code 2431 doSASLBind(const ns_cred_t *auth, 2432 LDAP *ld, 2433 int timeoutSec, 2434 ns_ldap_error_t **errorp, 2435 int fail_if_new_pwd_reqd, 2436 int passwd_mgmt) 2437 { 2438 char *binddn, *passwd, *digest_md5_name, 2439 errstr[MAXERROR], *errmsg; 2440 struct berval cred; 2441 int ldap_rc, errnum = 0; 2442 ns_ldap_return_code ret_code; 2443 struct timeval tv; 2444 LDAPMessage *resultMsg; 2445 LDAPControl **controls; 2446 int min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF; 2447 ns_sasl_cb_param_t sasl_param; 2448 2449 if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE && 2450 auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 2451 (void) sprintf(errstr, 2452 gettext("openConnection: SASL options are " 2453 "not supported (%d) for non-GSSAPI sasl bind"), 2454 auth->auth.saslopt); 2455 MKERROR(LOG_WARNING, *errorp, 2456 LDAP_AUTH_METHOD_NOT_SUPPORTED, 2457 strdup(errstr), NS_LDAP_MEMORY); 2458 (void) ldap_unbind(ld); 2459 return (NS_LDAP_INTERNAL); 2460 } 2461 if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 2462 binddn = auth->cred.unix_cred.userID; 2463 passwd = auth->cred.unix_cred.passwd; 2464 if (passwd == NULL || *passwd == '\0' || 2465 binddn == NULL || *binddn == '\0') { 2466 (void) sprintf(errstr, 2467 gettext("openConnection: missing credentials " 2468 "for SASL bind")); 2469 MKERROR(LOG_WARNING, *errorp, 2470 LDAP_INVALID_CREDENTIALS, 2471 strdup(errstr), NS_LDAP_MEMORY); 2472 (void) ldap_unbind(ld); 2473 return (NS_LDAP_INTERNAL); 2474 } 2475 cred.bv_val = passwd; 2476 cred.bv_len = strlen(passwd); 2477 } 2478 2479 ret_code = NS_LDAP_SUCCESS; 2480 2481 switch (auth->auth.saslmech) { 2482 case NS_LDAP_SASL_CRAM_MD5: 2483 /* 2484 * NOTE: if iDS changes to support cram_md5, 2485 * please add password management code here. 2486 * Since ldap_sasl_cram_md5_bind_s does not 2487 * return anything that could be used to 2488 * extract the ldap rc/errmsg/control to 2489 * determine if bind failed due to password 2490 * policy, a new cram_md5_bind API will need 2491 * to be introduced. See 2492 * ldap_x_sasl_digest_md5_bind() and case 2493 * NS_LDAP_SASL_DIGEST_MD5 below for details. 2494 */ 2495 if ((ldap_rc = ldap_sasl_cram_md5_bind_s(ld, binddn, 2496 &cred, NULL, NULL)) != LDAP_SUCCESS) { 2497 (void) ldap_get_option(ld, 2498 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 2499 (void) snprintf(errstr, sizeof (errstr), 2500 gettext("openConnection: " 2501 "sasl/CRAM-MD5 bind failed - %s"), 2502 ldap_err2string(errnum)); 2503 MKERROR(LOG_WARNING, *errorp, errnum, 2504 strdup(errstr), NS_LDAP_MEMORY); 2505 (void) ldap_unbind(ld); 2506 return (NS_LDAP_INTERNAL); 2507 } 2508 break; 2509 case NS_LDAP_SASL_DIGEST_MD5: 2510 digest_md5_name = malloc(strlen(binddn) + 5); 2511 /* 5 = strlen("dn: ") + 1 */ 2512 if (digest_md5_name == NULL) { 2513 (void) ldap_unbind(ld); 2514 return (NS_LDAP_MEMORY); 2515 } 2516 (void) strcpy(digest_md5_name, "dn: "); 2517 (void) strcat(digest_md5_name, binddn); 2518 2519 tv.tv_sec = timeoutSec; 2520 tv.tv_usec = 0; 2521 ldap_rc = ldap_x_sasl_digest_md5_bind(ld, 2522 digest_md5_name, &cred, NULL, NULL, 2523 &tv, &resultMsg); 2524 2525 if (resultMsg == NULL) { 2526 free(digest_md5_name); 2527 (void) ldap_get_option(ld, 2528 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 2529 (void) snprintf(errstr, sizeof (errstr), 2530 gettext("openConnection: " 2531 "DIGEST-MD5 bind failed - %s"), 2532 ldap_err2string(errnum)); 2533 (void) ldap_unbind(ld); 2534 MKERROR(LOG_WARNING, *errorp, errnum, 2535 strdup(errstr), NS_LDAP_MEMORY); 2536 return (NS_LDAP_INTERNAL); 2537 } 2538 2539 /* 2540 * get ldaprc, controls, and error msg 2541 */ 2542 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 2543 &errmsg, NULL, &controls, 1); 2544 2545 if (ldap_rc != LDAP_SUCCESS) { 2546 free(digest_md5_name); 2547 (void) snprintf(errstr, sizeof (errstr), 2548 gettext("openConnection: " 2549 "DIGEST-MD5 bind failed " 2550 "- unable to parse result")); 2551 (void) ldap_unbind(ld); 2552 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2553 strdup(errstr), NS_LDAP_MEMORY); 2554 return (NS_LDAP_INTERNAL); 2555 } 2556 2557 /* process the password management info, if any */ 2558 ret_code = process_pwd_mgmt("sasl/DIGEST-MD5", 2559 errnum, controls, errmsg, 2560 errorp, 2561 fail_if_new_pwd_reqd, 2562 passwd_mgmt); 2563 2564 if (ret_code == NS_LDAP_INTERNAL) { 2565 (void) ldap_unbind(ld); 2566 } 2567 2568 free(digest_md5_name); 2569 break; 2570 case NS_LDAP_SASL_GSSAPI: 2571 (void) memset(&sasl_param, 0, 2572 sizeof (ns_sasl_cb_param_t)); 2573 sasl_param.authid = NULL; 2574 sasl_param.authzid = ""; 2575 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN, 2576 (void *)&min_ssf); 2577 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX, 2578 (void *)&max_ssf); 2579 2580 ldap_rc = ldap_sasl_interactive_bind_s( 2581 ld, NULL, "GSSAPI", 2582 NULL, NULL, LDAP_SASL_INTERACTIVE, 2583 __s_api_sasl_bind_callback, 2584 &sasl_param); 2585 2586 if (ldap_rc != LDAP_SUCCESS) { 2587 (void) snprintf(errstr, sizeof (errstr), 2588 gettext("openConnection: " 2589 "GSSAPI bind failed " 2590 "- %d %s"), 2591 ldap_rc, 2592 ldap_err2string(ldap_rc)); 2593 (void) ldap_unbind(ld); 2594 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2595 strdup(errstr), NS_LDAP_MEMORY); 2596 return (NS_LDAP_INTERNAL); 2597 } 2598 2599 break; 2600 default: 2601 (void) ldap_unbind(ld); 2602 (void) sprintf(errstr, 2603 gettext("openConnection: unsupported SASL " 2604 "mechanism (%d)"), auth->auth.saslmech); 2605 MKERROR(LOG_WARNING, *errorp, 2606 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 2607 NS_LDAP_MEMORY); 2608 return (NS_LDAP_INTERNAL); 2609 } 2610 2611 return (ret_code); 2612 } 2613 2614 /* 2615 * This function performs an LDAP Bind operation proceeding 2616 * from a type of the connection specified by auth->auth.type. 2617 * 2618 * INPUT: 2619 * auth - a structure specified an authenticastion method and credentials, 2620 * ld - a pointer returned by the createSession() function, 2621 * timeoutSec - a timeout in seconds for the Bind operation, 2622 * fail_if_new_pwd_reqd - a flag indicating that the call should fail 2623 * if a new password is required, 2624 * passwd_mgmt - a flag indicating that the server supports 2625 * password management. 2626 * 2627 * OUTPUT: 2628 * If an error accures, the function returns an NS error code 2629 * and provides an additional info pointed by *errorp. 2630 */ 2631 static 2632 ns_ldap_return_code 2633 performBind(const ns_cred_t *auth, 2634 LDAP *ld, 2635 int timeoutSec, 2636 ns_ldap_error_t **errorp, 2637 int fail_if_new_pwd_reqd, 2638 int passwd_mgmt) 2639 { 2640 int bindType; 2641 char errstr[MAXERROR]; 2642 2643 ns_ldap_return_code (*binder)(const ns_cred_t *auth, 2644 LDAP *ld, 2645 int timeoutSec, 2646 ns_ldap_error_t **errorp, 2647 int fail_if_new_pwd_reqd, 2648 int passwd_mgmt) = NULL; 2649 2650 if (!ld) { 2651 (void) sprintf(errstr, 2652 "performBind: LDAP session " 2653 "is not initialized."); 2654 MKERROR(LOG_WARNING, *errorp, 2655 LDAP_AUTH_METHOD_NOT_SUPPORTED, 2656 strdup(errstr), NS_LDAP_MEMORY); 2657 return (NS_LDAP_INTERNAL); 2658 } 2659 2660 bindType = auth->auth.type == NS_LDAP_AUTH_TLS ? 2661 auth->auth.tlstype : auth->auth.type; 2662 2663 switch (bindType) { 2664 case NS_LDAP_AUTH_NONE: 2665 #ifdef DEBUG 2666 (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n", 2667 thr_self()); 2668 #endif /* DEBUG */ 2669 break; 2670 case NS_LDAP_AUTH_SIMPLE: 2671 binder = doSimpleBind; 2672 break; 2673 case NS_LDAP_AUTH_SASL: 2674 binder = doSASLBind; 2675 break; 2676 default: 2677 (void) sprintf(errstr, 2678 gettext("openConnection: unsupported " 2679 "authentication method " 2680 "(%d)"), bindType); 2681 MKERROR(LOG_WARNING, *errorp, 2682 LDAP_AUTH_METHOD_NOT_SUPPORTED, 2683 strdup(errstr), NS_LDAP_MEMORY); 2684 (void) ldap_unbind(ld); 2685 return (NS_LDAP_INTERNAL); 2686 } 2687 2688 if (binder != NULL) { 2689 return (*binder)(auth, 2690 ld, 2691 timeoutSec, 2692 errorp, 2693 fail_if_new_pwd_reqd, 2694 passwd_mgmt); 2695 } 2696 2697 return (NS_LDAP_SUCCESS); 2698 } 2699