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