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 */ 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 *, int); 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, flags); 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, flags); 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 (void) __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, int flags) 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 int followRef; 1356 1357 ns_ldap_return_code ret_code = NS_LDAP_SUCCESS; 1358 1359 *errorp = NULL; 1360 *ldp = NULL; 1361 1362 /* determine if the host name contains a port number */ 1363 s = strchr(serverAddr, ']'); /* skip over ipv6 addr */ 1364 s = strchr(s != NULL ? s : serverAddr, ':'); 1365 if (s != NULL) { 1366 if (sscanf(s + 1, "%hu", &port) != 1) { 1367 (void) snprintf(errstr, 1368 sizeof (errstr), 1369 gettext("openConnection: cannot " 1370 "convert %s into a valid " 1371 "port number for the " 1372 "%s server. A default value " 1373 "will be used."), 1374 s, 1375 serverAddr); 1376 syslog(LOG_ERR, "libsldap: %s", errstr); 1377 } else { 1378 *s = '\0'; 1379 } 1380 } 1381 1382 ret_code = createSession(auth, 1383 serverAddr, 1384 port, 1385 timeoutMilliSec, 1386 &ld, 1387 errorp); 1388 if (s != NULL) { 1389 *s = ':'; 1390 } 1391 if (ret_code != NS_LDAP_SUCCESS) { 1392 return (ret_code); 1393 } 1394 1395 /* check to see if the underlying libsldap supports MT connection */ 1396 if (conn_user != NULL) { 1397 int rc; 1398 1399 rc = __s_api_check_libldap_MT_conn_support(conn_user, ld, 1400 errorp); 1401 if (rc != NS_LDAP_SUCCESS) { 1402 (void) ldap_unbind(ld); 1403 return (rc); 1404 } 1405 } 1406 1407 (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion); 1408 (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 1409 /* 1410 * This library will handle the referral itself based on API flags or 1411 * configuration file specification. The LDAP bind operation is an 1412 * exception where we rely on the LDAP library to follow the referal. 1413 * 1414 * The LDAP follow referral option must be set to OFF for the libldap5 1415 * to pass the referral info up to this library. This option MUST be 1416 * set to OFF after we have performed a sucessful bind. If we are not 1417 * to follow referrals we MUST also set the LDAP follow referral option 1418 * to OFF before we perform an LDAP bind. 1419 */ 1420 ret_code = __s_api_toFollowReferrals(flags, &followRef, errorp); 1421 if (ret_code != NS_LDAP_SUCCESS) { 1422 (void) ldap_unbind(ld); 1423 return (ret_code); 1424 } 1425 1426 if (followRef) 1427 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 1428 else 1429 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 1430 1431 (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 1432 (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 1433 /* setup TCP/IP connect timeout */ 1434 (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 1435 &timeoutMilliSec); 1436 /* retry if LDAP I/O was interrupted */ 1437 (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 1438 1439 ret_code = performBind(auth, 1440 ld, 1441 timeoutSec, 1442 errorp, 1443 fail_if_new_pwd_reqd, 1444 passwd_mgmt); 1445 1446 if (ret_code == NS_LDAP_SUCCESS || 1447 ret_code == NS_LDAP_SUCCESS_WITH_INFO) { 1448 /* 1449 * Turn off LDAP referral following so that this library can 1450 * process referrals. 1451 */ 1452 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 1453 *ldp = ld; 1454 } 1455 1456 return (ret_code); 1457 } 1458 1459 /* 1460 * FUNCTION: __s_api_getDefaultAuth 1461 * 1462 * Constructs a credential for authentication using the config module. 1463 * 1464 * RETURN VALUES: 1465 * 1466 * NS_LDAP_SUCCESS If successful 1467 * NS_LDAP_CONFIG If there are any config errors. 1468 * NS_LDAP_MEMORY Memory errors. 1469 * NS_LDAP_OP_FAILED If there are no more authentication methods so can 1470 * not build a new authp. 1471 * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the 1472 * necessary fields of a cred for a given auth method 1473 * are not provided. 1474 * INPUT: 1475 * 1476 * cLevel Currently requested credential level to be tried 1477 * 1478 * aMethod Currently requested authentication method to be tried 1479 * 1480 * getAdmin If non 0, get Admin -i.e., not proxyAgent- DN and password 1481 * 1482 * OUTPUT: 1483 * 1484 * authp authentication method to use. 1485 */ 1486 static int 1487 __s_api_getDefaultAuth( 1488 int *cLevel, 1489 ns_auth_t *aMethod, 1490 ns_cred_t **authp, 1491 int getAdmin) 1492 { 1493 void **paramVal = NULL; 1494 char *modparamVal = NULL; 1495 int getUid = 0; 1496 int getPasswd = 0; 1497 int getCertpath = 0; 1498 int rc = 0; 1499 ns_ldap_error_t *errorp = NULL; 1500 UnixCred_t *AdminCred = NULL; 1501 1502 #ifdef DEBUG 1503 (void) fprintf(stderr, "__s_api_getDefaultAuth START\n"); 1504 #endif 1505 1506 if (aMethod == NULL) { 1507 /* Require an Auth */ 1508 return (NS_LDAP_INVALID_PARAM); 1509 1510 } 1511 /* 1512 * credential level "self" can work with auth method sasl/GSSAPI only 1513 */ 1514 if (cLevel && *cLevel == NS_LDAP_CRED_SELF && 1515 aMethod->saslmech != NS_LDAP_SASL_GSSAPI) 1516 return (NS_LDAP_INVALID_PARAM); 1517 1518 *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t)); 1519 if ((*authp) == NULL) 1520 return (NS_LDAP_MEMORY); 1521 1522 (*authp)->auth = *aMethod; 1523 1524 switch (aMethod->type) { 1525 case NS_LDAP_AUTH_NONE: 1526 return (NS_LDAP_SUCCESS); 1527 case NS_LDAP_AUTH_SIMPLE: 1528 getUid++; 1529 getPasswd++; 1530 break; 1531 case NS_LDAP_AUTH_SASL: 1532 if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 1533 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) { 1534 getUid++; 1535 getPasswd++; 1536 } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) { 1537 (void) __ns_ldap_freeCred(authp); 1538 return (NS_LDAP_INVALID_PARAM); 1539 } 1540 break; 1541 case NS_LDAP_AUTH_TLS: 1542 if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) || 1543 ((aMethod->tlstype == NS_LDAP_TLS_SASL) && 1544 ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) || 1545 (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) { 1546 getUid++; 1547 getPasswd++; 1548 getCertpath++; 1549 } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) { 1550 getCertpath++; 1551 } else { 1552 (void) __ns_ldap_freeCred(authp); 1553 return (NS_LDAP_INVALID_PARAM); 1554 } 1555 break; 1556 } 1557 1558 if (getUid) { 1559 paramVal = NULL; 1560 if (getAdmin) { 1561 /* 1562 * Assume AdminCred has been retrieved from 1563 * ldap_cachemgr already. It will not work 1564 * without userID or password. Flags getUid 1565 * and getPasswd should always be set 1566 * together. 1567 */ 1568 AdminCred = calloc(1, sizeof (UnixCred_t)); 1569 if (AdminCred == NULL) { 1570 (void) __ns_ldap_freeCred(authp); 1571 return (NS_LDAP_MEMORY); 1572 } 1573 1574 rc = requestAdminCred(&AdminCred, &errorp); 1575 if (rc != NS_LDAP_SUCCESS) { 1576 (void) __ns_ldap_freeCred(authp); 1577 (void) __ns_ldap_freeUnixCred(&AdminCred); 1578 (void) __ns_ldap_freeError(&errorp); 1579 return (rc); 1580 } 1581 1582 if (AdminCred->userID == NULL) { 1583 (void) __ns_ldap_freeCred(authp); 1584 (void) __ns_ldap_freeUnixCred(&AdminCred); 1585 return (NS_LDAP_INVALID_PARAM); 1586 } 1587 (*authp)->cred.unix_cred.userID = AdminCred->userID; 1588 AdminCred->userID = NULL; 1589 } else { 1590 rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P, 1591 ¶mVal, &errorp); 1592 if (rc != NS_LDAP_SUCCESS) { 1593 (void) __ns_ldap_freeCred(authp); 1594 (void) __ns_ldap_freeError(&errorp); 1595 return (rc); 1596 } 1597 1598 if (paramVal == NULL || *paramVal == NULL) { 1599 (void) __ns_ldap_freeCred(authp); 1600 return (NS_LDAP_INVALID_PARAM); 1601 } 1602 1603 (*authp)->cred.unix_cred.userID = 1604 strdup((char *)*paramVal); 1605 (void) __ns_ldap_freeParam(¶mVal); 1606 } 1607 if ((*authp)->cred.unix_cred.userID == NULL) { 1608 (void) __ns_ldap_freeCred(authp); 1609 (void) __ns_ldap_freeUnixCred(&AdminCred); 1610 return (NS_LDAP_MEMORY); 1611 } 1612 } 1613 if (getPasswd) { 1614 paramVal = NULL; 1615 if (getAdmin) { 1616 /* 1617 * Assume AdminCred has been retrieved from 1618 * ldap_cachemgr already. It will not work 1619 * without the userID anyway because for 1620 * getting admin credential, flags getUid 1621 * and getPasswd should always be set 1622 * together. 1623 */ 1624 if (AdminCred == NULL || AdminCred->passwd == NULL) { 1625 (void) __ns_ldap_freeCred(authp); 1626 (void) __ns_ldap_freeUnixCred(&AdminCred); 1627 return (NS_LDAP_INVALID_PARAM); 1628 } 1629 modparamVal = dvalue(AdminCred->passwd); 1630 } else { 1631 rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P, 1632 ¶mVal, &errorp); 1633 if (rc != NS_LDAP_SUCCESS) { 1634 (void) __ns_ldap_freeCred(authp); 1635 (void) __ns_ldap_freeError(&errorp); 1636 return (rc); 1637 } 1638 1639 if (paramVal == NULL || *paramVal == NULL) { 1640 (void) __ns_ldap_freeCred(authp); 1641 return (NS_LDAP_INVALID_PARAM); 1642 } 1643 1644 modparamVal = dvalue((char *)*paramVal); 1645 (void) __ns_ldap_freeParam(¶mVal); 1646 } 1647 1648 if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) { 1649 (void) __ns_ldap_freeCred(authp); 1650 (void) __ns_ldap_freeUnixCred(&AdminCred); 1651 if (modparamVal != NULL) 1652 free(modparamVal); 1653 return (NS_LDAP_INVALID_PARAM); 1654 } 1655 1656 (*authp)->cred.unix_cred.passwd = modparamVal; 1657 } 1658 if (getCertpath) { 1659 paramVal = NULL; 1660 if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 1661 ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { 1662 (void) __ns_ldap_freeCred(authp); 1663 (void) __ns_ldap_freeUnixCred(&AdminCred); 1664 (void) __ns_ldap_freeError(&errorp); 1665 *authp = NULL; 1666 return (rc); 1667 } 1668 1669 if (paramVal == NULL || *paramVal == NULL) { 1670 (void) __ns_ldap_freeCred(authp); 1671 (void) __ns_ldap_freeUnixCred(&AdminCred); 1672 *authp = NULL; 1673 return (NS_LDAP_INVALID_PARAM); 1674 } 1675 1676 (*authp)->hostcertpath = strdup((char *)*paramVal); 1677 (void) __ns_ldap_freeParam(¶mVal); 1678 if ((*authp)->hostcertpath == NULL) { 1679 (void) __ns_ldap_freeCred(authp); 1680 (void) __ns_ldap_freeUnixCred(&AdminCred); 1681 *authp = NULL; 1682 return (NS_LDAP_MEMORY); 1683 } 1684 } 1685 (void) __ns_ldap_freeUnixCred(&AdminCred); 1686 return (NS_LDAP_SUCCESS); 1687 } 1688 1689 /* 1690 * FUNCTION: getConnection 1691 * 1692 * internal version of __s_api_getConnection() 1693 */ 1694 static int 1695 getConnection( 1696 const char *server, 1697 const int flags, 1698 const ns_cred_t *cred, /* credentials for bind */ 1699 ConnectionID *sessionId, 1700 Connection **session, 1701 ns_ldap_error_t **errorp, 1702 int fail_if_new_pwd_reqd, 1703 int nopasswd_acct_mgmt, 1704 ns_conn_user_t *conn_user) 1705 { 1706 char errmsg[MAXERROR]; 1707 ns_auth_t **aMethod = NULL; 1708 ns_auth_t **aNext = NULL; 1709 int **cLevel = NULL; 1710 int **cNext = NULL; 1711 int timeoutSec = NS_DEFAULT_BIND_TIMEOUT; 1712 int rc; 1713 Connection *con = NULL; 1714 int sec = 1; 1715 ns_cred_t *authp = NULL; 1716 ns_cred_t anon; 1717 int version = NS_LDAP_V2, self_gssapi_only = 0; 1718 void **paramVal = NULL; 1719 char **badSrvrs = NULL; /* List of problem hostnames */ 1720 1721 if ((session == NULL) || (sessionId == NULL)) { 1722 return (NS_LDAP_INVALID_PARAM); 1723 } 1724 *session = NULL; 1725 1726 /* reuse MT connection if needed and if available */ 1727 if (conn_user != NULL) { 1728 rc = __s_api_conn_mt_get(server, flags, cred, session, errorp, 1729 conn_user); 1730 if (rc != NS_LDAP_NOTFOUND) 1731 return (rc); 1732 } 1733 1734 /* get profile version number */ 1735 if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, 1736 ¶mVal, errorp)) != NS_LDAP_SUCCESS) 1737 return (rc); 1738 if (paramVal == NULL) { 1739 (void) sprintf(errmsg, gettext("getConnection: no file " 1740 "version")); 1741 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg), 1742 NS_LDAP_CONFIG); 1743 return (NS_LDAP_CONFIG); 1744 } 1745 if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0) 1746 version = NS_LDAP_V1; 1747 (void) __ns_ldap_freeParam((void ***)¶mVal); 1748 1749 /* Get the bind timeout value */ 1750 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp); 1751 if (paramVal != NULL && *paramVal != NULL) { 1752 timeoutSec = **((int **)paramVal); 1753 (void) __ns_ldap_freeParam(¶mVal); 1754 } 1755 if (*errorp) 1756 (void) __ns_ldap_freeError(errorp); 1757 1758 if (cred == NULL) { 1759 /* Get the authentication method list */ 1760 if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, 1761 (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS) 1762 return (rc); 1763 if (aMethod == NULL) { 1764 aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *)); 1765 if (aMethod == NULL) 1766 return (NS_LDAP_MEMORY); 1767 aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t)); 1768 if (aMethod[0] == NULL) { 1769 free(aMethod); 1770 return (NS_LDAP_MEMORY); 1771 } 1772 if (version == NS_LDAP_V1) 1773 (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE; 1774 else { 1775 (aMethod[0])->type = NS_LDAP_AUTH_SASL; 1776 (aMethod[0])->saslmech = 1777 NS_LDAP_SASL_DIGEST_MD5; 1778 (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE; 1779 } 1780 } 1781 1782 /* Get the credential level list */ 1783 if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P, 1784 (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) { 1785 (void) __ns_ldap_freeParam((void ***)&aMethod); 1786 return (rc); 1787 } 1788 if (cLevel == NULL) { 1789 cLevel = (int **)calloc(2, sizeof (int *)); 1790 if (cLevel == NULL) 1791 return (NS_LDAP_MEMORY); 1792 cLevel[0] = (int *)calloc(1, sizeof (int)); 1793 if (cLevel[0] == NULL) 1794 return (NS_LDAP_MEMORY); 1795 if (version == NS_LDAP_V1) 1796 *(cLevel[0]) = NS_LDAP_CRED_PROXY; 1797 else 1798 *(cLevel[0]) = NS_LDAP_CRED_ANON; 1799 } 1800 } 1801 1802 /* setup the anon credential for anonymous connection */ 1803 (void) memset(&anon, 0, sizeof (ns_cred_t)); 1804 anon.auth.type = NS_LDAP_AUTH_NONE; 1805 1806 for (;;) { 1807 if (cred != NULL) { 1808 /* using specified auth method */ 1809 rc = makeConnection(&con, server, cred, 1810 sessionId, timeoutSec, errorp, 1811 fail_if_new_pwd_reqd, 1812 nopasswd_acct_mgmt, flags, &badSrvrs, conn_user); 1813 /* not using bad server if credentials were supplied */ 1814 if (badSrvrs && *badSrvrs) { 1815 __s_api_free2dArray(badSrvrs); 1816 badSrvrs = NULL; 1817 } 1818 if (rc == NS_LDAP_SUCCESS || 1819 rc == NS_LDAP_SUCCESS_WITH_INFO) { 1820 *session = con; 1821 break; 1822 } 1823 } else { 1824 self_gssapi_only = __s_api_self_gssapi_only_get(); 1825 /* for every cred level */ 1826 for (cNext = cLevel; *cNext != NULL; cNext++) { 1827 if (self_gssapi_only && 1828 **cNext != NS_LDAP_CRED_SELF) 1829 continue; 1830 if (**cNext == NS_LDAP_CRED_ANON) { 1831 /* 1832 * make connection anonymously 1833 * Free the down server list before 1834 * looping through 1835 */ 1836 if (badSrvrs && *badSrvrs) { 1837 __s_api_free2dArray(badSrvrs); 1838 badSrvrs = NULL; 1839 } 1840 rc = makeConnection(&con, server, &anon, 1841 sessionId, timeoutSec, errorp, 1842 fail_if_new_pwd_reqd, 1843 nopasswd_acct_mgmt, flags, 1844 &badSrvrs, conn_user); 1845 if (rc == NS_LDAP_SUCCESS || 1846 rc == 1847 NS_LDAP_SUCCESS_WITH_INFO) { 1848 *session = con; 1849 goto done; 1850 } 1851 continue; 1852 } 1853 /* for each cred level */ 1854 for (aNext = aMethod; *aNext != NULL; aNext++) { 1855 if (self_gssapi_only && 1856 (*aNext)->saslmech != 1857 NS_LDAP_SASL_GSSAPI) 1858 continue; 1859 /* 1860 * self coexists with sasl/GSSAPI only 1861 * and non-self coexists with non-gssapi 1862 * only 1863 */ 1864 if ((**cNext == NS_LDAP_CRED_SELF && 1865 (*aNext)->saslmech != 1866 NS_LDAP_SASL_GSSAPI) || 1867 (**cNext != NS_LDAP_CRED_SELF && 1868 (*aNext)->saslmech == 1869 NS_LDAP_SASL_GSSAPI)) 1870 continue; 1871 /* make connection and authenticate */ 1872 /* with default credentials */ 1873 authp = NULL; 1874 rc = __s_api_getDefaultAuth(*cNext, 1875 *aNext, &authp, 1876 flags & NS_LDAP_READ_SHADOW); 1877 if (rc != NS_LDAP_SUCCESS) { 1878 continue; 1879 } 1880 /* 1881 * Free the down server list before 1882 * looping through 1883 */ 1884 if (badSrvrs && *badSrvrs) { 1885 __s_api_free2dArray(badSrvrs); 1886 badSrvrs = NULL; 1887 } 1888 rc = makeConnection(&con, server, authp, 1889 sessionId, timeoutSec, errorp, 1890 fail_if_new_pwd_reqd, 1891 nopasswd_acct_mgmt, flags, 1892 &badSrvrs, conn_user); 1893 (void) __ns_ldap_freeCred(&authp); 1894 if (rc == NS_LDAP_SUCCESS || 1895 rc == 1896 NS_LDAP_SUCCESS_WITH_INFO) { 1897 *session = con; 1898 goto done; 1899 } 1900 } 1901 } 1902 } 1903 if (flags & NS_LDAP_HARD) { 1904 if (sec < LDAPMAXHARDLOOKUPTIME) 1905 sec *= 2; 1906 (void) sleep(sec); 1907 } else { 1908 break; 1909 } 1910 } 1911 1912 done: 1913 if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) { 1914 /* 1915 * self_gssapi_only is true but no self/sasl/gssapi is 1916 * configured 1917 */ 1918 rc = NS_LDAP_CONFIG; 1919 } 1920 1921 (void) __ns_ldap_freeParam((void ***)&aMethod); 1922 (void) __ns_ldap_freeParam((void ***)&cLevel); 1923 1924 if (badSrvrs && *badSrvrs) { 1925 /* 1926 * At this point, either we have a successful 1927 * connection or exhausted all the possible auths. 1928 * and creds. Mark the problem servers as down 1929 * so that the problem servers are not contacted 1930 * again until the refresh_ttl expires. 1931 */ 1932 (void) __s_api_removeBadServers(badSrvrs); 1933 __s_api_free2dArray(badSrvrs); 1934 } 1935 return (rc); 1936 } 1937 1938 /* 1939 * FUNCTION: __s_api_getConnection 1940 * 1941 * Bind to the specified server or one from the server 1942 * list and return the pointer. 1943 * 1944 * This function can rebind or not (NS_LDAP_HARD), it can require a 1945 * credential or bind anonymously 1946 * 1947 * This function follows the DUA configuration schema algorithm 1948 * 1949 * RETURN VALUES: 1950 * 1951 * NS_LDAP_SUCCESS A connection was made successfully. 1952 * NS_LDAP_SUCCESS_WITH_INFO 1953 * A connection was made successfully, but with 1954 * password management info in *errorp 1955 * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function. 1956 * NS_LDAP_CONFIG If there are any config errors. 1957 * NS_LDAP_MEMORY Memory errors. 1958 * NS_LDAP_INTERNAL If there was a ldap error. 1959 * 1960 * INPUT: 1961 * 1962 * server Bind to this LDAP server only 1963 * flags If NS_LDAP_HARD is set function will not return until it has 1964 * a connection unless there is a authentication problem. 1965 * If NS_LDAP_NEW_CONN is set the function must force a new 1966 * connection to be created 1967 * If NS_LDAP_KEEP_CONN is set the connection is to be kept open 1968 * auth Credentials for bind. This could be NULL in which case 1969 * a default cred built from the config module is used. 1970 * sessionId cookie that points to a previous session 1971 * fail_if_new_pwd_reqd 1972 * a flag indicating this function should fail if the passwd 1973 * in auth needs to change immediately 1974 * nopasswd_acct_mgmt 1975 * a flag indicating that makeConnection should check before 1976 * binding if server supports LDAP V3 password less 1977 * account management 1978 * 1979 * OUTPUT: 1980 * 1981 * session pointer to a session with connection information 1982 * errorp Set if there are any INTERNAL, or CONFIG error. 1983 */ 1984 int 1985 __s_api_getConnection( 1986 const char *server, 1987 const int flags, 1988 const ns_cred_t *cred, /* credentials for bind */ 1989 ConnectionID *sessionId, 1990 Connection **session, 1991 ns_ldap_error_t **errorp, 1992 int fail_if_new_pwd_reqd, 1993 int nopasswd_acct_mgmt, 1994 ns_conn_user_t *conn_user) 1995 { 1996 int rc; 1997 1998 rc = getConnection(server, flags, cred, sessionId, session, 1999 errorp, fail_if_new_pwd_reqd, nopasswd_acct_mgmt, 2000 conn_user); 2001 2002 if (rc != NS_LDAP_SUCCESS && rc != NS_LDAP_SUCCESS_WITH_INFO) { 2003 if (conn_user != NULL && conn_user->conn_mt != NULL) 2004 __s_api_conn_mt_remove(conn_user, rc, errorp); 2005 } 2006 2007 return (rc); 2008 } 2009 2010 void 2011 __s_api_free_sessionPool() 2012 { 2013 int id; 2014 2015 (void) mutex_lock(&sessionPoolLock); 2016 2017 if (sessionPool != NULL) { 2018 for (id = 0; id < sessionPoolSize; id++) 2019 _DropConnection(id + CONID_OFFSET, 0, 1); 2020 free(sessionPool); 2021 sessionPool = NULL; 2022 sessionPoolSize = 0; 2023 } 2024 (void) mutex_unlock(&sessionPoolLock); 2025 } 2026 2027 /* 2028 * This function initializes a TLS LDAP session. On success LDAP* is returned 2029 * (pointed by *ldp). Otherwise, the function returns an NS error code and 2030 * provide an additional info pointed by *errorp. 2031 */ 2032 static 2033 ns_ldap_return_code 2034 createTLSSession(const ns_cred_t *auth, const char *serverAddr, 2035 uint16_t port, int timeoutMilliSec, 2036 LDAP **ldp, ns_ldap_error_t **errorp) 2037 { 2038 const char *hostcertpath; 2039 char *alloc_hcp = NULL, errstr[MAXERROR]; 2040 int ldap_rc; 2041 2042 #ifdef DEBUG 2043 (void) fprintf(stderr, "tid= %d: +++TLS transport\n", 2044 thr_self()); 2045 #endif /* DEBUG */ 2046 2047 if (prldap_set_session_option(NULL, NULL, 2048 PRLDAP_OPT_IO_MAX_TIMEOUT, 2049 timeoutMilliSec) != LDAP_SUCCESS) { 2050 (void) snprintf(errstr, sizeof (errstr), 2051 gettext("createTLSSession: failed to initialize " 2052 "TLS security")); 2053 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2054 strdup(errstr), NS_LDAP_MEMORY); 2055 return (NS_LDAP_INTERNAL); 2056 } 2057 2058 hostcertpath = auth->hostcertpath; 2059 if (hostcertpath == NULL) { 2060 alloc_hcp = __s_get_hostcertpath(); 2061 hostcertpath = alloc_hcp; 2062 } 2063 2064 if (hostcertpath == NULL) 2065 return (NS_LDAP_MEMORY); 2066 2067 if ((ldap_rc = ldapssl_client_init(hostcertpath, NULL)) < 0) { 2068 if (alloc_hcp != NULL) { 2069 free(alloc_hcp); 2070 } 2071 (void) snprintf(errstr, sizeof (errstr), 2072 gettext("createTLSSession: failed to initialize " 2073 "TLS security (%s)"), 2074 ldapssl_err2string(ldap_rc)); 2075 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2076 strdup(errstr), NS_LDAP_MEMORY); 2077 return (NS_LDAP_INTERNAL); 2078 } 2079 if (alloc_hcp) 2080 free(alloc_hcp); 2081 2082 *ldp = ldapssl_init(serverAddr, port, 1); 2083 2084 if (*ldp == NULL || 2085 ldapssl_install_gethostbyaddr(*ldp, "ldap") != 0) { 2086 (void) snprintf(errstr, sizeof (errstr), 2087 gettext("createTLSSession: failed to connect " 2088 "using TLS (%s)"), strerror(errno)); 2089 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2090 strdup(errstr), NS_LDAP_MEMORY); 2091 return (NS_LDAP_INTERNAL); 2092 } 2093 2094 return (NS_LDAP_SUCCESS); 2095 } 2096 2097 /* 2098 * Convert (resolve) hostname to IP address. 2099 * 2100 * INPUT: 2101 * 2102 * server - \[IPv6_address\][:port] 2103 * - IPv4_address[:port] 2104 * - hostname[:port] 2105 * 2106 * newaddr - Buffer to which this function writes resulting address, 2107 * including the port number, if specified in server argument. 2108 * 2109 * newaddr_size - Size of the newaddr buffer. 2110 * 2111 * errstr - Buffer to which error string is written if error occurs. 2112 * 2113 * errstr_size - Size of the errstr buffer. 2114 * 2115 * OUTPUT: 2116 * 2117 * Returns 1 for success, 0 in case of error. 2118 * 2119 * newaddr - See above (INPUT section). 2120 * 2121 * errstr - See above (INPUT section). 2122 */ 2123 static int 2124 cvt_hostname2ip(char *server, char *newaddr, int newaddr_size, 2125 char *errstr, int errstr_size) 2126 { 2127 char *s; 2128 unsigned short port = 0; 2129 int err; 2130 char buffer[NSS_BUFLEN_HOSTS]; 2131 struct hostent result; 2132 2133 /* Determine if the host name contains a port number. */ 2134 2135 /* Skip over IPv6 address. */ 2136 s = strchr(server, ']'); 2137 s = strchr(s != NULL ? s : server, ':'); 2138 if (s != NULL) { 2139 if (sscanf(s + 1, "%hu", &port) != 1) { 2140 /* Address misformatted. No port number after : */ 2141 (void) snprintf(errstr, errstr_size, "%s", 2142 gettext("Invalid host:port format")); 2143 return (0); 2144 } else 2145 /* Cut off the :<port> part. */ 2146 *s = '\0'; 2147 } 2148 2149 buffer[0] = '\0'; 2150 /* 2151 * Resolve hostname and fill in hostent structure. 2152 */ 2153 if (!__s_api_hostname2ip(server, &result, buffer, NSS_BUFLEN_HOSTS, 2154 &err)) { 2155 /* 2156 * The only possible error here could be TRY_AGAIN if buffer was 2157 * not big enough. NSS_BUFLEN_HOSTS should have been enough 2158 * though. 2159 */ 2160 (void) snprintf(errstr, errstr_size, "%s", 2161 gettext("Unable to resolve address.")); 2162 return (0); 2163 } 2164 2165 2166 buffer[0] = '\0'; 2167 /* 2168 * Convert the address to string. 2169 */ 2170 if (!inet_ntop(result.h_addrtype, result.h_addr_list[0], buffer, 2171 NSS_BUFLEN_HOSTS)) { 2172 /* There's not much we can do. */ 2173 (void) snprintf(errstr, errstr_size, "%s", 2174 gettext("Unable to convert address to string.")); 2175 return (0); 2176 } 2177 2178 /* Put together the address and the port */ 2179 if (port > 0) { 2180 switch (result.h_addrtype) { 2181 case AF_INET6: 2182 (void) snprintf(newaddr, 2183 /* [IP]:<port>\0 */ 2184 1 + strlen(buffer) + 1 + 1 + 5 + 1, 2185 "[%s]:%hu", 2186 buffer, 2187 port); 2188 break; 2189 /* AF_INET */ 2190 default : 2191 (void) snprintf(newaddr, 2192 /* IP:<port>\0 */ 2193 strlen(buffer) + 1 + 5 + 1, 2194 "%s:%hu", 2195 buffer, 2196 port); 2197 break; 2198 } 2199 } else { 2200 (void) strncpy(newaddr, buffer, newaddr_size); 2201 } 2202 2203 return (1); 2204 } 2205 2206 2207 /* 2208 * This finction initializes a none-TLS LDAP session. On success LDAP* 2209 * is returned (pointed by *ldp). Otherwise, the function returns 2210 * an NS error code and provides an additional info pointed by *errorp. 2211 */ 2212 static 2213 ns_ldap_return_code 2214 createNonTLSSession(const char *serverAddr, 2215 uint16_t port, int gssapi, 2216 LDAP **ldp, ns_ldap_error_t **errorp) 2217 { 2218 char errstr[MAXERROR]; 2219 char *addr; 2220 int is_ip = 0; 2221 /* [INET6_ADDRSTRLEN]:<port>\0 */ 2222 char svraddr[1+INET6_ADDRSTRLEN+1+1+5+1]; 2223 #ifdef DEBUG 2224 (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n", 2225 thr_self()); 2226 #endif /* DEBUG */ 2227 2228 if (gssapi == 0) { 2229 is_ip = (__s_api_isipv4((char *)serverAddr) || 2230 __s_api_isipv6((char *)serverAddr)); 2231 } 2232 2233 /* 2234 * Let's try to resolve IP address of server. 2235 */ 2236 if (is_ip == 0 && !gssapi && (ldap_in_nss_switch((char *)"hosts") > 0 || 2237 ldap_in_nss_switch((char *)"ipnodes") > 0)) { 2238 addr = strdup(serverAddr); 2239 if (addr == NULL) 2240 return (NS_LDAP_MEMORY); 2241 svraddr[0] = '\0'; 2242 if (cvt_hostname2ip(addr, svraddr, sizeof (svraddr), 2243 errstr, MAXERROR) == 1) { 2244 serverAddr = svraddr; 2245 free(addr); 2246 } else { 2247 free(addr); 2248 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2249 strdup(errstr), NS_LDAP_MEMORY); 2250 return (NS_LDAP_INTERNAL); 2251 } 2252 } 2253 2254 /* Warning message IF cannot connect to host(s) */ 2255 if ((*ldp = ldap_init((char *)serverAddr, port)) == NULL) { 2256 char *p = strerror(errno); 2257 MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR, 2258 strdup(p), NS_LDAP_MEMORY); 2259 return (NS_LDAP_INTERNAL); 2260 } 2261 2262 return (NS_LDAP_SUCCESS); 2263 } 2264 2265 /* 2266 * This finction initializes an LDAP session. 2267 * 2268 * INPUT: 2269 * auth - a structure specified an authenticastion method and credentials, 2270 * serverAddr - the address of a server to which a connection 2271 * will be established, 2272 * port - a port being listened by the server, 2273 * timeoutMilliSec - a timeout in milliseconds for the Bind operation. 2274 * 2275 * OUTPUT: 2276 * ldp - a pointer to an LDAP structure which will be used 2277 * for all the subsequent operations against the server. 2278 * If an error occurs, the function returns an NS error code 2279 * and provides an additional info pointed by *errorp. 2280 */ 2281 static 2282 ns_ldap_return_code 2283 createSession(const ns_cred_t *auth, const char *serverAddr, 2284 uint16_t port, int timeoutMilliSec, 2285 LDAP **ldp, ns_ldap_error_t **errorp) 2286 { 2287 int useSSL = 0, gssapi = 0; 2288 char errstr[MAXERROR]; 2289 2290 switch (auth->auth.type) { 2291 case NS_LDAP_AUTH_NONE: 2292 case NS_LDAP_AUTH_SIMPLE: 2293 case NS_LDAP_AUTH_SASL: 2294 break; 2295 case NS_LDAP_AUTH_TLS: 2296 useSSL = 1; 2297 break; 2298 default: 2299 (void) sprintf(errstr, 2300 gettext("openConnection: unsupported " 2301 "authentication method (%d)"), auth->auth.type); 2302 MKERROR(LOG_WARNING, *errorp, 2303 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 2304 NS_LDAP_MEMORY); 2305 return (NS_LDAP_INTERNAL); 2306 } 2307 2308 if (port == USE_DEFAULT_PORT) { 2309 port = useSSL ? LDAPS_PORT : LDAP_PORT; 2310 } 2311 2312 if (auth->auth.type == NS_LDAP_AUTH_SASL && 2313 auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) 2314 gssapi = 1; 2315 2316 if (useSSL) 2317 return (createTLSSession(auth, serverAddr, port, 2318 timeoutMilliSec, ldp, errorp)); 2319 else 2320 return (createNonTLSSession(serverAddr, port, gssapi, 2321 ldp, errorp)); 2322 } 2323 2324 /* 2325 * This finction performs a non-SASL bind operation. If an error accures, 2326 * the function returns an NS error code and provides an additional info 2327 * pointed by *errorp. 2328 */ 2329 static 2330 ns_ldap_return_code 2331 doSimpleBind(const ns_cred_t *auth, 2332 LDAP *ld, 2333 int timeoutSec, 2334 ns_ldap_error_t **errorp, 2335 int fail_if_new_pwd_reqd, 2336 int passwd_mgmt) 2337 { 2338 char *binddn, *passwd, errstr[MAXERROR], *errmsg; 2339 int msgId, errnum = 0, ldap_rc; 2340 ns_ldap_return_code ret_code; 2341 LDAPMessage *resultMsg = NULL; 2342 LDAPControl **controls; 2343 struct timeval tv; 2344 2345 binddn = auth->cred.unix_cred.userID; 2346 passwd = auth->cred.unix_cred.passwd; 2347 if (passwd == NULL || *passwd == '\0' || 2348 binddn == NULL || *binddn == '\0') { 2349 (void) sprintf(errstr, gettext("openConnection: " 2350 "missing credentials for Simple bind")); 2351 MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS, 2352 strdup(errstr), NS_LDAP_MEMORY); 2353 (void) ldap_unbind(ld); 2354 return (NS_LDAP_INTERNAL); 2355 } 2356 2357 #ifdef DEBUG 2358 (void) fprintf(stderr, "tid= %d: +++Simple bind\n", 2359 thr_self()); 2360 #endif /* DEBUG */ 2361 msgId = ldap_simple_bind(ld, binddn, passwd); 2362 2363 if (msgId == -1) { 2364 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 2365 (void *)&errnum); 2366 (void) snprintf(errstr, sizeof (errstr), 2367 gettext("openConnection: simple bind failed " 2368 "- %s"), ldap_err2string(errnum)); 2369 (void) ldap_unbind(ld); 2370 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 2371 NS_LDAP_MEMORY); 2372 return (NS_LDAP_INTERNAL); 2373 } 2374 2375 tv.tv_sec = timeoutSec; 2376 tv.tv_usec = 0; 2377 ldap_rc = ldap_result(ld, msgId, 0, &tv, &resultMsg); 2378 2379 if ((ldap_rc == -1) || (ldap_rc == 0)) { 2380 (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 2381 (void *)&errnum); 2382 (void) snprintf(errstr, sizeof (errstr), 2383 gettext("openConnection: simple bind failed " 2384 "- %s"), ldap_err2string(errnum)); 2385 (void) ldap_msgfree(resultMsg); 2386 (void) ldap_unbind(ld); 2387 MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr), 2388 NS_LDAP_MEMORY); 2389 return (NS_LDAP_INTERNAL); 2390 } 2391 2392 /* 2393 * get ldaprc, controls, and error msg 2394 */ 2395 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 2396 &errmsg, NULL, &controls, 1); 2397 2398 if (ldap_rc != LDAP_SUCCESS) { 2399 (void) snprintf(errstr, sizeof (errstr), 2400 gettext("openConnection: simple bind failed " 2401 "- unable to parse result")); 2402 (void) ldap_unbind(ld); 2403 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2404 strdup(errstr), NS_LDAP_MEMORY); 2405 return (NS_LDAP_INTERNAL); 2406 } 2407 2408 /* process the password management info, if any */ 2409 ret_code = process_pwd_mgmt("simple", 2410 errnum, controls, errmsg, 2411 errorp, 2412 fail_if_new_pwd_reqd, 2413 passwd_mgmt); 2414 2415 if (ret_code == NS_LDAP_INTERNAL) { 2416 (void) ldap_unbind(ld); 2417 } 2418 2419 return (ret_code); 2420 } 2421 2422 /* 2423 * This finction performs a SASL bind operation. If an error accures, 2424 * the function returns an NS error code and provides an additional info 2425 * pointed by *errorp. 2426 */ 2427 static 2428 ns_ldap_return_code 2429 doSASLBind(const ns_cred_t *auth, 2430 LDAP *ld, 2431 int timeoutSec, 2432 ns_ldap_error_t **errorp, 2433 int fail_if_new_pwd_reqd, 2434 int passwd_mgmt) 2435 { 2436 char *binddn, *passwd, *digest_md5_name, 2437 errstr[MAXERROR], *errmsg; 2438 struct berval cred; 2439 int ldap_rc, errnum = 0; 2440 ns_ldap_return_code ret_code; 2441 struct timeval tv; 2442 LDAPMessage *resultMsg; 2443 LDAPControl **controls; 2444 int min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF; 2445 ns_sasl_cb_param_t sasl_param; 2446 2447 if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE && 2448 auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 2449 (void) sprintf(errstr, 2450 gettext("openConnection: SASL options are " 2451 "not supported (%d) for non-GSSAPI sasl bind"), 2452 auth->auth.saslopt); 2453 MKERROR(LOG_WARNING, *errorp, 2454 LDAP_AUTH_METHOD_NOT_SUPPORTED, 2455 strdup(errstr), NS_LDAP_MEMORY); 2456 (void) ldap_unbind(ld); 2457 return (NS_LDAP_INTERNAL); 2458 } 2459 if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 2460 binddn = auth->cred.unix_cred.userID; 2461 passwd = auth->cred.unix_cred.passwd; 2462 if (passwd == NULL || *passwd == '\0' || 2463 binddn == NULL || *binddn == '\0') { 2464 (void) sprintf(errstr, 2465 gettext("openConnection: missing credentials " 2466 "for SASL bind")); 2467 MKERROR(LOG_WARNING, *errorp, 2468 LDAP_INVALID_CREDENTIALS, 2469 strdup(errstr), NS_LDAP_MEMORY); 2470 (void) ldap_unbind(ld); 2471 return (NS_LDAP_INTERNAL); 2472 } 2473 cred.bv_val = passwd; 2474 cred.bv_len = strlen(passwd); 2475 } 2476 2477 ret_code = NS_LDAP_SUCCESS; 2478 2479 switch (auth->auth.saslmech) { 2480 case NS_LDAP_SASL_CRAM_MD5: 2481 /* 2482 * NOTE: if iDS changes to support cram_md5, 2483 * please add password management code here. 2484 * Since ldap_sasl_cram_md5_bind_s does not 2485 * return anything that could be used to 2486 * extract the ldap rc/errmsg/control to 2487 * determine if bind failed due to password 2488 * policy, a new cram_md5_bind API will need 2489 * to be introduced. See 2490 * ldap_x_sasl_digest_md5_bind() and case 2491 * NS_LDAP_SASL_DIGEST_MD5 below for details. 2492 */ 2493 if ((ldap_rc = ldap_sasl_cram_md5_bind_s(ld, binddn, 2494 &cred, NULL, NULL)) != LDAP_SUCCESS) { 2495 (void) ldap_get_option(ld, 2496 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 2497 (void) snprintf(errstr, sizeof (errstr), 2498 gettext("openConnection: " 2499 "sasl/CRAM-MD5 bind failed - %s"), 2500 ldap_err2string(errnum)); 2501 MKERROR(LOG_WARNING, *errorp, errnum, 2502 strdup(errstr), NS_LDAP_MEMORY); 2503 (void) ldap_unbind(ld); 2504 return (NS_LDAP_INTERNAL); 2505 } 2506 break; 2507 case NS_LDAP_SASL_DIGEST_MD5: 2508 digest_md5_name = malloc(strlen(binddn) + 5); 2509 /* 5 = strlen("dn: ") + 1 */ 2510 if (digest_md5_name == NULL) { 2511 (void) ldap_unbind(ld); 2512 return (NS_LDAP_MEMORY); 2513 } 2514 (void) strcpy(digest_md5_name, "dn: "); 2515 (void) strcat(digest_md5_name, binddn); 2516 2517 tv.tv_sec = timeoutSec; 2518 tv.tv_usec = 0; 2519 ldap_rc = ldap_x_sasl_digest_md5_bind(ld, 2520 digest_md5_name, &cred, NULL, NULL, 2521 &tv, &resultMsg); 2522 2523 if (resultMsg == NULL) { 2524 free(digest_md5_name); 2525 (void) ldap_get_option(ld, 2526 LDAP_OPT_ERROR_NUMBER, (void *)&errnum); 2527 (void) snprintf(errstr, sizeof (errstr), 2528 gettext("openConnection: " 2529 "DIGEST-MD5 bind failed - %s"), 2530 ldap_err2string(errnum)); 2531 (void) ldap_unbind(ld); 2532 MKERROR(LOG_WARNING, *errorp, errnum, 2533 strdup(errstr), NS_LDAP_MEMORY); 2534 return (NS_LDAP_INTERNAL); 2535 } 2536 2537 /* 2538 * get ldaprc, controls, and error msg 2539 */ 2540 ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL, 2541 &errmsg, NULL, &controls, 1); 2542 2543 if (ldap_rc != LDAP_SUCCESS) { 2544 free(digest_md5_name); 2545 (void) snprintf(errstr, sizeof (errstr), 2546 gettext("openConnection: " 2547 "DIGEST-MD5 bind failed " 2548 "- unable to parse result")); 2549 (void) ldap_unbind(ld); 2550 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2551 strdup(errstr), NS_LDAP_MEMORY); 2552 return (NS_LDAP_INTERNAL); 2553 } 2554 2555 /* process the password management info, if any */ 2556 ret_code = process_pwd_mgmt("sasl/DIGEST-MD5", 2557 errnum, controls, errmsg, 2558 errorp, 2559 fail_if_new_pwd_reqd, 2560 passwd_mgmt); 2561 2562 if (ret_code == NS_LDAP_INTERNAL) { 2563 (void) ldap_unbind(ld); 2564 } 2565 2566 free(digest_md5_name); 2567 break; 2568 case NS_LDAP_SASL_GSSAPI: 2569 (void) memset(&sasl_param, 0, 2570 sizeof (ns_sasl_cb_param_t)); 2571 sasl_param.authid = NULL; 2572 sasl_param.authzid = ""; 2573 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN, 2574 (void *)&min_ssf); 2575 (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX, 2576 (void *)&max_ssf); 2577 2578 ldap_rc = ldap_sasl_interactive_bind_s( 2579 ld, NULL, "GSSAPI", 2580 NULL, NULL, LDAP_SASL_INTERACTIVE, 2581 __s_api_sasl_bind_callback, 2582 &sasl_param); 2583 2584 if (ldap_rc != LDAP_SUCCESS) { 2585 (void) snprintf(errstr, sizeof (errstr), 2586 gettext("openConnection: " 2587 "GSSAPI bind failed " 2588 "- %d %s"), 2589 ldap_rc, 2590 ldap_err2string(ldap_rc)); 2591 (void) ldap_unbind(ld); 2592 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2593 strdup(errstr), NS_LDAP_MEMORY); 2594 return (NS_LDAP_INTERNAL); 2595 } 2596 2597 break; 2598 default: 2599 (void) ldap_unbind(ld); 2600 (void) sprintf(errstr, 2601 gettext("openConnection: unsupported SASL " 2602 "mechanism (%d)"), auth->auth.saslmech); 2603 MKERROR(LOG_WARNING, *errorp, 2604 LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr), 2605 NS_LDAP_MEMORY); 2606 return (NS_LDAP_INTERNAL); 2607 } 2608 2609 return (ret_code); 2610 } 2611 2612 /* 2613 * This function performs an LDAP Bind operation proceeding 2614 * from a type of the connection specified by auth->auth.type. 2615 * 2616 * INPUT: 2617 * auth - a structure specified an authenticastion method and credentials, 2618 * ld - a pointer returned by the createSession() function, 2619 * timeoutSec - a timeout in seconds for the Bind operation, 2620 * fail_if_new_pwd_reqd - a flag indicating that the call should fail 2621 * if a new password is required, 2622 * passwd_mgmt - a flag indicating that the server supports 2623 * password management. 2624 * 2625 * OUTPUT: 2626 * If an error accures, the function returns an NS error code 2627 * and provides an additional info pointed by *errorp. 2628 */ 2629 static 2630 ns_ldap_return_code 2631 performBind(const ns_cred_t *auth, 2632 LDAP *ld, 2633 int timeoutSec, 2634 ns_ldap_error_t **errorp, 2635 int fail_if_new_pwd_reqd, 2636 int passwd_mgmt) 2637 { 2638 int bindType; 2639 char errstr[MAXERROR]; 2640 2641 ns_ldap_return_code (*binder)(const ns_cred_t *auth, 2642 LDAP *ld, 2643 int timeoutSec, 2644 ns_ldap_error_t **errorp, 2645 int fail_if_new_pwd_reqd, 2646 int passwd_mgmt) = NULL; 2647 2648 if (!ld) { 2649 (void) sprintf(errstr, 2650 "performBind: LDAP session " 2651 "is not initialized."); 2652 MKERROR(LOG_WARNING, *errorp, 2653 LDAP_AUTH_METHOD_NOT_SUPPORTED, 2654 strdup(errstr), NS_LDAP_MEMORY); 2655 return (NS_LDAP_INTERNAL); 2656 } 2657 2658 bindType = auth->auth.type == NS_LDAP_AUTH_TLS ? 2659 auth->auth.tlstype : auth->auth.type; 2660 2661 switch (bindType) { 2662 case NS_LDAP_AUTH_NONE: 2663 #ifdef DEBUG 2664 (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n", 2665 thr_self()); 2666 #endif /* DEBUG */ 2667 break; 2668 case NS_LDAP_AUTH_SIMPLE: 2669 binder = doSimpleBind; 2670 break; 2671 case NS_LDAP_AUTH_SASL: 2672 binder = doSASLBind; 2673 break; 2674 default: 2675 (void) sprintf(errstr, 2676 gettext("openConnection: unsupported " 2677 "authentication method " 2678 "(%d)"), bindType); 2679 MKERROR(LOG_WARNING, *errorp, 2680 LDAP_AUTH_METHOD_NOT_SUPPORTED, 2681 strdup(errstr), NS_LDAP_MEMORY); 2682 (void) ldap_unbind(ld); 2683 return (NS_LDAP_INTERNAL); 2684 } 2685 2686 if (binder != NULL) { 2687 return (*binder)(auth, 2688 ld, 2689 timeoutSec, 2690 errorp, 2691 fail_if_new_pwd_reqd, 2692 passwd_mgmt); 2693 } 2694 2695 return (NS_LDAP_SUCCESS); 2696 } 2697