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
getFirstFromConfig(ns_server_info_t * ret,ns_ldap_error_t ** error)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
__door_getadmincred(char ** buffer,int * buflen,ns_ldap_error_t ** error)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
requestAdminCred(UnixCred_t ** cred,ns_ldap_error_t ** error)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
__s_api_requestServer(const char * request,const char * server,ns_server_info_t * ret,ns_ldap_error_t ** error,const char * addrType)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
printCred(FILE * fp,const ns_cred_t * cred)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
printConnection(FILE * fp,Connection * con)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
addConnection(Connection * con)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
findConnection(int flags,const char * serverAddr,const ns_cred_t * auth,Connection ** conp)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
__s_api_freeConnection(Connection * con)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
makeConnection(Connection ** conp,const char * serverAddr,const ns_cred_t * auth,ConnectionID * cID,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int nopasswd_acct_mgmt,int flags,char *** badsrvrs,ns_conn_user_t * conn_user)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
_DropConnection(ConnectionID cID,int flag,int fini)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
DropConnection(ConnectionID cID,int flag)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
process_pwd_mgmt(char * bind_type,int ldaprc,LDAPControl ** controls,char * errmsg,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt)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
ldap_in_nss_switch(char * db)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
openConnection(LDAP ** ldp,const char * serverAddr,const ns_cred_t * auth,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt,ns_conn_user_t * conn_user,int flags)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
__s_api_getDefaultAuth(int * cLevel,ns_auth_t * aMethod,ns_cred_t ** authp,int getAdmin)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
getConnection(const char * server,const int flags,const ns_cred_t * cred,ConnectionID * sessionId,Connection ** session,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int nopasswd_acct_mgmt,ns_conn_user_t * conn_user)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
__s_api_getConnection(const char * server,const int flags,const ns_cred_t * cred,ConnectionID * sessionId,Connection ** session,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int nopasswd_acct_mgmt,ns_conn_user_t * conn_user)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
__s_api_free_sessionPool()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
createTLSSession(const ns_cred_t * auth,const char * serverAddr,uint16_t port,int timeoutMilliSec,LDAP ** ldp,ns_ldap_error_t ** errorp)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
cvt_hostname2ip(char * server,char * newaddr,int newaddr_size,char * errstr,int errstr_size)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
createNonTLSSession(const char * serverAddr,uint16_t port,int gssapi,LDAP ** ldp,ns_ldap_error_t ** errorp)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
createSession(const ns_cred_t * auth,const char * serverAddr,uint16_t port,int timeoutMilliSec,LDAP ** ldp,ns_ldap_error_t ** errorp)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
doSimpleBind(const ns_cred_t * auth,LDAP * ld,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt)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
doSASLBind(const ns_cred_t * auth,LDAP * ld,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt)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
performBind(const ns_cred_t * auth,LDAP * ld,int timeoutSec,ns_ldap_error_t ** errorp,int fail_if_new_pwd_reqd,int passwd_mgmt)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