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.
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.
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]
23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
38 #include <nss_dbdefs.h>
39 #include "solaris-priv.h"
40 #include "solaris-int.h"
42 #include "ns_internal.h"
43 #include "ns_cache_door.h"
44 #include "ns_connmgmt.h"
51 #define USE_DEFAULT_PORT 0
53 static ns_ldap_return_code
performBind(const ns_cred_t
*,
59 static ns_ldap_return_code
createSession(const ns_cred_t
*,
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
);
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
,
77 static int openConnection(LDAP
**, const char *, const ns_cred_t
*,
78 int, ns_ldap_error_t
**, int, int, ns_conn_user_t
*, int);
80 _DropConnection(ConnectionID cID
, int flag
, int fini
);
82 static mutex_t sessionPoolLock
= DEFAULTMUTEX
;
84 static Connection
**sessionPool
= NULL
;
85 static int sessionPoolSize
= 0;
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.
92 #define MAX_SASL_SSF 65535
93 #define MIN_SASL_SSF 0
95 /* Number of hostnames to allocate memory for */
96 #define NUMTOMALLOC 32
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.
106 getFirstFromConfig(ns_server_info_t
*ret
, ns_ldap_error_t
**error
)
108 char **servers
= NULL
;
109 ns_ldap_return_code ret_code
;
110 char errstr
[MAXERROR
];
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
);
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
);
130 ret
->server
= strdup(servers
[0]);
131 if (ret
->server
== NULL
) {
132 __s_api_free2dArray(servers
);
133 return (NS_LDAP_MEMORY
);
136 ret
->saslMechanisms
= NULL
;
137 ret
->controls
= NULL
;
139 __s_api_free2dArray(servers
);
141 return (NS_LDAP_SUCCESS
);
144 /* very similar to __door_getldapconfig() in ns_config.c */
146 __door_getadmincred(char **buffer
, int *buflen
, ns_ldap_error_t
**error
)
148 return (__door_getconf(buffer
, buflen
, error
, GETADMINCRED
));
152 * This function requests Admin credentials from the cache manager through
153 * the door functionality
157 requestAdminCred(UnixCred_t
**cred
, ns_ldap_error_t
**error
)
164 ret
= __door_getadmincred(&buffer
, &buflen
, error
);
166 if (ret
!= NS_LDAP_SUCCESS
) {
167 if (*error
!= NULL
&& (*error
)->message
!= NULL
)
168 syslog(LOG_WARNING
, "libsldap: %s", (*error
)->message
);
172 /* now convert from door format */
173 ret
= SetDoorInfoToUnixCred(buffer
, error
, cred
);
180 * This function requests a server from the cache manager through
181 * the door functionality
185 __s_api_requestServer(const char *request
, const char *server
,
186 ns_server_info_t
*ret
, ns_ldap_error_t
**error
, const char *addrType
)
190 char s_b
[DOORBUFFERSIZE
];
195 char errstr
[MAXERROR
];
197 char *rbuf
, *ptr
, *rest
;
199 char **mptr
, **mptr1
, **cptr
, **cptr1
;
202 ns_ldap_return_code ret_code
;
204 if (ret
== NULL
|| error
== NULL
) {
205 return (NS_LDAP_OP_FAILED
);
207 (void) memset(ret
, 0, sizeof (ns_server_info_t
));
216 * In the 'Standalone' mode a server will be obtained
217 * from the local libsldap's list
219 if (__s_api_isStandalone()) {
220 if ((ret_code
= __s_api_findRootDSE(ireq
,
224 error
)) != NS_LDAP_SUCCESS
) {
226 * get first server from local list only once
229 if (strcmp(ireq
, NS_CACHE_NEW
) != 0)
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
);
240 ret_code
= getFirstFromConfig(ret
, error
);
241 if (ret_code
!= NS_LDAP_SUCCESS
) {
245 if (strcmp(addrType
, NS_CACHE_ADDR_HOSTNAME
) == 0) {
246 ret_code
= __s_api_ip2hostname(ret
->server
,
248 if (ret_code
!= NS_LDAP_SUCCESS
) {
249 (void) snprintf(errstr
,
251 gettext("The %s address "
252 "can not be resolved into "
253 "a host name. Returning "
254 "the address as it is."),
263 return (NS_LDAP_INTERNAL
);
268 return (NS_LDAP_SUCCESS
);
271 (void) memset(space
.s_b
, 0, DOORBUFFERSIZE
);
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;
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
) >=
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
,
292 return (NS_LDAP_MEMORY
);
296 switch (__ns_ldap_trydoorcall(&sptr
, &ndata
, &adata
)) {
297 case NS_CACHE_SUCCESS
:
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
) {
307 if (strcmp(addrType
, NS_CACHE_ADDR_HOSTNAME
) == 0) {
308 ret_code
= __s_api_ip2hostname(ret
->server
,
310 if (ret_code
!= NS_LDAP_SUCCESS
) {
311 (void) snprintf(errstr
,
313 gettext("The %s address "
314 "can not be resolved into "
315 "a host name. Returning "
316 "the address as it is."),
325 return (NS_LDAP_INTERNAL
);
328 return (NS_LDAP_SUCCESS
);
329 case NS_CACHE_NOTFOUND
:
331 return (NS_LDAP_OP_FAILED
);
334 /* copy info from door call return structure here */
335 rbuf
= space
.s_d
.ldap_ret
.ldap_u
.config
;
338 ptr
= strtok_r(rbuf
, DOORLINESEP
, &rest
);
340 (void) sprintf(errstr
, gettext("No server returned from "
342 MKERROR(LOG_WARNING
, *error
, NS_CONFIG_CACHEMGR
,
343 strdup(errstr
), NS_LDAP_MEMORY
);
344 return (NS_LDAP_OP_FAILED
);
346 ret
->server
= strdup(ptr
);
347 if (ret
->server
== NULL
) {
348 return (NS_LDAP_MEMORY
);
350 /* Get the host FQDN format */
351 if (strcmp(addrType
, NS_CACHE_ADDR_HOSTNAME
) == 0) {
352 ptr
= strtok_r(NULL
, DOORLINESEP
, &rest
);
354 (void) sprintf(errstr
, gettext("No server FQDN format "
355 "returned from ldap_cachemgr"));
356 MKERROR(LOG_WARNING
, *error
, NS_CONFIG_CACHEMGR
,
360 return (NS_LDAP_OP_FAILED
);
362 ret
->serverFQDN
= strdup(ptr
);
363 if (ret
->serverFQDN
== NULL
) {
366 return (NS_LDAP_MEMORY
);
370 /* get the Supported Controls/SASL mechs */
376 ptr
= strtok_r(NULL
, DOORLINESEP
, &rest
);
379 if (strncasecmp(ptr
, _SASLMECHANISM
,
380 _SASLMECHANISM_LEN
) == 0) {
381 dptr
= strchr(ptr
, '=');
385 mptr1
= reallocarray(mptr
, mcnt
+ 2,
388 __s_api_free2dArray(mptr
);
389 if (sptr
!= &space
.s_d
) {
390 (void) munmap((char *)sptr
, ndata
);
392 __s_api_free2dArray(cptr
);
393 __s_api_free_server_info(ret
);
394 return (NS_LDAP_MEMORY
);
397 mptr
[mcnt
] = strdup(dptr
);
398 if (mptr
[mcnt
] == NULL
) {
399 if (sptr
!= &space
.s_d
) {
400 (void) munmap((char *)sptr
, ndata
);
402 __s_api_free2dArray(cptr
);
404 __s_api_free2dArray(mptr
);
406 __s_api_free_server_info(ret
);
407 return (NS_LDAP_MEMORY
);
412 if (strncasecmp(ptr
, _SUPPORTEDCONTROL
,
413 _SUPPORTEDCONTROL_LEN
) == 0) {
414 dptr
= strchr(ptr
, '=');
418 cptr1
= reallocarray(cptr
, ccnt
+ 2,
421 if (sptr
!= &space
.s_d
) {
422 (void) munmap((char *)sptr
, ndata
);
424 __s_api_free2dArray(cptr
);
425 __s_api_free2dArray(mptr
);
427 __s_api_free_server_info(ret
);
428 return (NS_LDAP_MEMORY
);
431 cptr
[ccnt
] = strdup(dptr
);
432 if (cptr
[ccnt
] == NULL
) {
433 if (sptr
!= &space
.s_d
) {
434 (void) munmap((char *)sptr
, ndata
);
436 __s_api_free2dArray(cptr
);
438 __s_api_free2dArray(mptr
);
440 __s_api_free_server_info(ret
);
441 return (NS_LDAP_MEMORY
);
448 ret
->saslMechanisms
= mptr
;
451 ret
->controls
= cptr
;
455 /* clean up door call */
456 if (sptr
!= &space
.s_d
) {
457 (void) munmap((char *)sptr
, ndata
);
461 return (NS_LDAP_SUCCESS
);
467 * printCred(): prints the credential structure
470 printCred(FILE *fp
, const ns_cred_t
*cred
)
472 thread_t t
= thr_self();
475 (void) fprintf(fp
, "tid= %d: printCred: cred is NULL\n", t
);
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
);
495 * printConnection(): prints the connection structure
498 printConnection(FILE *fp
, Connection
*con
)
500 thread_t t
= thr_self();
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",
512 printCred(fp
, con
->auth
);
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
523 addConnection(Connection
*con
)
530 (void) fprintf(stderr
, "Adding connection thrid=%d\n", con
->threadID
);
532 (void) mutex_lock(&sessionPoolLock
);
533 if (sessionPool
== NULL
) {
534 sessionPoolSize
= SESSION_CACHE_INC
;
535 sessionPool
= calloc(sessionPoolSize
,
536 sizeof (Connection
*));
538 (void) mutex_unlock(&sessionPoolLock
);
542 (void) fprintf(stderr
, "Initialized sessionPool\n");
545 for (i
= 0; (i
< sessionPoolSize
) && (sessionPool
[i
] != NULL
); ++i
)
547 if (i
== sessionPoolSize
) {
548 /* run out of array, need to increase sessionPool */
550 cl
= reallocarray(sessionPool
,
551 sessionPoolSize
+ SESSION_CACHE_INC
,
552 sizeof (Connection
*));
554 (void) mutex_unlock(&sessionPoolLock
);
557 (void) memset(cl
+ sessionPoolSize
, 0,
558 SESSION_CACHE_INC
* sizeof (Connection
*));
560 sessionPoolSize
+= SESSION_CACHE_INC
;
562 (void) fprintf(stderr
, "Increased sessionPoolSize to: %d\n",
566 sessionPool
[i
] = con
;
567 con
->usedBit
= B_TRUE
;
568 (void) mutex_unlock(&sessionPoolLock
);
569 con
->connectionId
= i
+ CONID_OFFSET
;
571 (void) fprintf(stderr
, "Connection added [%d]\n", i
);
572 printConnection(stderr
, con
);
574 return (i
+ CONID_OFFSET
);
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.
585 findConnection(int flags
, const char *serverAddr
,
586 const ns_cred_t
*auth
, Connection
**conp
)
594 if (auth
== NULL
|| conp
== NULL
)
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.
603 if ((flags
& NS_LDAP_NEW_CONN
) || (!__s_api_nscd_proc() &&
604 !__s_api_peruser_proc() && !(flags
& NS_LDAP_KEEP_CONN
)))
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",
615 (void) fprintf(stderr
, "tid= %d: serverAddr=NULL\n", t
);
616 printCred(stderr
, auth
);
619 if (sessionPool
== NULL
)
621 (void) mutex_lock(&sessionPoolLock
);
622 for (i
= 0; i
< sessionPoolSize
; ++i
) {
623 if (sessionPool
[i
] == NULL
)
627 (void) fprintf(stderr
,
628 "tid: %d: checking connection [%d] ....\n", t
, i
);
629 printConnection(stderr
, cp
);
631 if ((cp
->usedBit
) || (serverAddr
&& *serverAddr
&&
632 (strcasecmp(serverAddr
, cp
->serverAddr
) != 0)))
635 if (__s_api_is_auth_matched(cp
->auth
, auth
) == B_FALSE
)
638 /* found an available connection */
639 cp
->usedBit
= B_TRUE
;
640 (void) mutex_unlock(&sessionPoolLock
);
641 cp
->threadID
= thr_self();
644 (void) fprintf(stderr
,
645 "tid %d: Connection found cID=%d\n", t
, i
);
648 return (i
+ CONID_OFFSET
);
650 (void) mutex_unlock(&sessionPoolLock
);
655 * Free a Connection structure
658 __s_api_freeConnection(Connection
*con
)
662 free(con
->serverAddr
);
664 (void) __ns_ldap_freeCred(&(con
->auth
));
665 if (con
->saslMechanisms
) {
666 __s_api_free2dArray(con
->saslMechanisms
);
669 __s_api_free2dArray(con
->controls
);
675 * Find a connection matching the passed in criteria. If an open
676 * connection with that criteria exists use it, otherwise open a
678 * Success: returns the pointer to the Connection structure
679 * Failure: returns NULL, error code and message should be in errorp
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
)
689 Connection
*con
= NULL
;
691 char errmsg
[MAXERROR
];
692 int rc
, exit_rc
= NS_LDAP_SUCCESS
;
693 ns_server_info_t sinfo
;
694 char *hReq
, *host
= NULL
;
697 int totalbad
= 0; /* Number of servers contacted unsuccessfully */
698 short memerr
= 0; /* Variable for tracking memory allocation */
699 char *serverAddrType
= NULL
, **bindHost
= NULL
;
702 if (conp
== NULL
|| errorp
== NULL
|| auth
== NULL
)
703 return (NS_LDAP_INVALID_PARAM
);
705 (void) __ns_ldap_freeError(errorp
);
707 (void) memset(&sinfo
, 0, sizeof (sinfo
));
709 if ((id
= findConnection(flags
, serverAddr
, auth
, &con
)) != -1) {
710 /* connection found in cache */
712 (void) fprintf(stderr
, "tid= %d: connection found in "
713 "cache %d\n", thr_self(), id
);
718 return (NS_LDAP_SUCCESS
);
721 if (auth
->auth
.saslmech
== NS_LDAP_SASL_GSSAPI
) {
722 serverAddrType
= NS_CACHE_ADDR_HOSTNAME
;
723 bindHost
= &sinfo
.serverFQDN
;
725 serverAddrType
= NS_CACHE_ADDR_IP
;
726 bindHost
= &sinfo
.server
;
730 if (__s_api_isInitializing()) {
732 * When obtaining the root DSE, connect to the server
733 * passed here through the serverAddr parameter
735 sinfo
.server
= strdup(serverAddr
);
736 if (sinfo
.server
== NULL
)
737 return (NS_LDAP_MEMORY
);
738 if (strcmp(serverAddrType
,
739 NS_CACHE_ADDR_HOSTNAME
) == 0) {
740 rc
= __s_api_ip2hostname(sinfo
.server
,
742 if (rc
!= NS_LDAP_SUCCESS
) {
743 (void) snprintf(errmsg
,
745 gettext("The %s address "
746 "can not be resolved into "
747 "a host name. Returning "
748 "the address as it is."),
755 __s_api_free_server_info(&sinfo
);
756 return (NS_LDAP_INTERNAL
);
761 * We're given the server address, just use it.
762 * In case of sasl/GSSAPI, serverAddr would need
763 * to be a FQDN. We assume this is the case for now.
765 * Only the server address fields of sinfo structure
766 * are filled in since these are the only relevant
767 * data that we have. Other fields of this structure
768 * (controls, saslMechanisms) are kept to NULL.
770 sinfo
.server
= strdup(serverAddr
);
771 if (sinfo
.server
== NULL
) {
772 return (NS_LDAP_MEMORY
);
774 if (auth
->auth
.saslmech
== NS_LDAP_SASL_GSSAPI
) {
775 sinfo
.serverFQDN
= strdup(serverAddr
);
776 if (sinfo
.serverFQDN
== NULL
) {
778 return (NS_LDAP_MEMORY
);
782 rc
= openConnection(&ld
, *bindHost
, auth
, timeoutSec
, errorp
,
783 fail_if_new_pwd_reqd
, passwd_mgmt
, conn_user
, flags
);
784 if (rc
== NS_LDAP_SUCCESS
|| rc
==
785 NS_LDAP_SUCCESS_WITH_INFO
) {
789 if (auth
->auth
.saslmech
== NS_LDAP_SASL_GSSAPI
) {
790 (void) snprintf(errmsg
, sizeof (errmsg
),
791 "%s %s", gettext("makeConnection: "
792 "failed to open connection using "
793 "sasl/GSSAPI to"), *bindHost
);
795 (void) snprintf(errmsg
, sizeof (errmsg
),
796 "%s %s", gettext("makeConnection: "
797 "failed to open connection to"),
800 syslog(LOG_ERR
, "libsldap: %s", errmsg
);
801 __s_api_free_server_info(&sinfo
);
806 /* No cached connection, create one */
811 hReq
= NS_CACHE_NEXT
;
812 rc
= __s_api_requestServer(hReq
, host
, &sinfo
, errorp
,
814 if ((rc
!= NS_LDAP_SUCCESS
) || (sinfo
.server
== NULL
) ||
815 (host
&& (strcasecmp(host
, sinfo
.server
) == 0))) {
818 (void) snprintf(errmsg
, sizeof (errmsg
),
819 "%s: (%s)", gettext("makeConnection: "
820 "unable to make LDAP connection, "
821 "request for a server failed"),
823 syslog(LOG_ERR
, "libsldap: %s", errmsg
);
826 __s_api_free_server_info(&sinfo
);
828 return (NS_LDAP_OP_FAILED
);
831 host
= strdup(sinfo
.server
);
833 __s_api_free_server_info(&sinfo
);
834 return (NS_LDAP_MEMORY
);
837 /* check if server supports password management */
838 passwd_mgmt
= __s_api_contain_passwd_control_oid(
840 /* check if server supports password less account mgmt */
841 if (nopasswd_acct_mgmt
&&
842 !__s_api_contain_account_usable_control_oid(
844 syslog(LOG_WARNING
, "libsldap: server %s does not "
845 "provide account information without password",
848 __s_api_free_server_info(&sinfo
);
849 return (NS_LDAP_OP_FAILED
);
851 /* make the connection */
852 rc
= openConnection(&ld
, *bindHost
, auth
, timeoutSec
, errorp
,
853 fail_if_new_pwd_reqd
, passwd_mgmt
, conn_user
, flags
);
854 /* if success, go to create connection structure */
855 if (rc
== NS_LDAP_SUCCESS
||
856 rc
== NS_LDAP_SUCCESS_WITH_INFO
) {
862 * If not able to reach the server, inform the ldap
863 * cache manager that the server should be removed
864 * from its server list. Thus, the manager will not
865 * return this server on the next get-server request
866 * and will also reduce the server list refresh TTL,
867 * so that it will find out sooner when the server
870 if (rc
== NS_LDAP_INTERNAL
&& *errorp
!= NULL
) {
871 if ((*errorp
)->status
== LDAP_CONNECT_ERROR
||
872 (*errorp
)->status
== LDAP_SERVER_DOWN
) {
873 /* Reset memory allocation error */
876 * We contacted a server that we could
877 * not either authenticate to or contact.
878 * If it is due to authentication, then
879 * we need to try the server again. So,
880 * do not remove the server yet, but
881 * add it to the bad server list.
882 * The caller routine will remove
884 * a). A good server is found or
885 * b). All the possible methods
886 * are tried without finding
889 if (*badsrvrs
== NULL
) {
890 if (!(*badsrvrs
= (char **)malloc
891 (sizeof (char *) * NUMTOMALLOC
))) {
894 /* Allocate memory in chunks of NUMTOMALLOC */
895 } else if ((totalbad
% NUMTOMALLOC
) ==
898 if (!(tmpptr
= (char **)realloc(
900 (sizeof (char *) * NUMTOMALLOC
*
901 ((totalbad
/NUMTOMALLOC
) + 2))))) {
908 * Store host only if there were no unsuccessful
909 * memory allocations above
912 !((*badsrvrs
)[totalbad
++] = strdup(host
))) {
916 (*badsrvrs
)[totalbad
] = NULL
;
920 /* else, cleanup and go for the next server */
921 __s_api_free_server_info(&sinfo
);
923 /* Return if we had memory allocation errors */
925 return (NS_LDAP_MEMORY
);
928 * If openConnection() failed due to
929 * password policy, or invalid credential,
930 * keep *errorp and exit
932 if ((*errorp
)->pwd_mgmt
.status
!= NS_PASSWD_GOOD
||
933 (*errorp
)->status
== LDAP_INVALID_CREDENTIALS
) {
937 (void) __ns_ldap_freeError(errorp
);
944 /* we have created ld, setup con structure */
946 if ((con
= calloc(1, sizeof (Connection
))) == NULL
) {
947 __s_api_free_server_info(&sinfo
);
949 * If password control attached in **errorp,
950 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
951 * free the error structure
954 (void) __ns_ldap_freeError(errorp
);
957 (void) ldap_unbind(ld
);
958 return (NS_LDAP_MEMORY
);
961 con
->serverAddr
= sinfo
.server
; /* Store original format */
962 if (sinfo
.serverFQDN
!= NULL
) {
963 free(sinfo
.serverFQDN
);
964 sinfo
.serverFQDN
= NULL
;
966 con
->saslMechanisms
= sinfo
.saslMechanisms
;
967 con
->controls
= sinfo
.controls
;
969 con
->auth
= __ns_ldap_dupAuth(auth
);
970 if (con
->auth
== NULL
) {
971 (void) ldap_unbind(ld
);
972 __s_api_freeConnection(con
);
974 * If password control attached in **errorp,
975 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
976 * free the error structure
979 (void) __ns_ldap_freeError(errorp
);
982 return (NS_LDAP_MEMORY
);
985 con
->threadID
= thr_self();
989 /* add MT connection to the MT connection pool */
990 if (conn_user
!= NULL
&& conn_user
->conn_mt
!= NULL
) {
991 if (__s_api_conn_mt_add(con
, conn_user
, errorp
) ==
996 (void) ldap_unbind(ld
);
997 __s_api_freeConnection(con
);
998 return ((*errorp
)->status
);
1002 /* MT connection not supported or not required case */
1003 if ((id
= addConnection(con
)) == -1) {
1004 (void) ldap_unbind(ld
);
1005 __s_api_freeConnection(con
);
1007 * If password control attached in **errorp,
1008 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1009 * free the error structure
1012 (void) __ns_ldap_freeError(errorp
);
1015 return (NS_LDAP_MEMORY
);
1018 (void) fprintf(stderr
, "tid= %d: connection added into "
1019 "cache %d\n", thr_self(), id
);
1028 * Return the specified connection to the pool. If necessary
1029 * delete the connection.
1033 _DropConnection(ConnectionID cID
, int flag
, int fini
)
1037 int use_mutex
= !fini
;
1038 struct timeval zerotime
;
1041 zerotime
.tv_sec
= zerotime
.tv_usec
= 0L;
1043 id
= cID
- CONID_OFFSET
;
1044 if (id
< 0 || id
>= sessionPoolSize
)
1047 (void) fprintf(stderr
,
1048 "tid %d: Dropping connection cID=%d flag=0x%x\n",
1049 thr_self(), cID
, flag
);
1053 (void) mutex_lock(&sessionPoolLock
);
1055 cp
= sessionPool
[id
];
1056 /* sanity check before removing */
1057 if (!cp
|| (!fini
&& (!cp
->usedBit
|| cp
->threadID
!= thr_self()))) {
1059 (void) mutex_unlock(&sessionPoolLock
);
1064 ((flag
& NS_LDAP_NEW_CONN
) == 0) &&
1065 ((flag
& NS_LDAP_KEEP_CONN
) || __s_api_nscd_proc() ||
1066 __s_api_peruser_proc())) {
1067 /* release Connection (keep alive) */
1068 cp
->usedBit
= B_FALSE
;
1069 cp
->threadID
= 0; /* unmark the threadID */
1071 * Do sanity cleanup of remaining results.
1073 while (ldap_result(cp
->ld
, LDAP_RES_ANY
, LDAP_MSG_ALL
,
1074 &zerotime
, &res
) > 0) {
1076 (void) ldap_msgfree(res
);
1079 (void) mutex_unlock(&sessionPoolLock
);
1081 /* delete Connection (disconnect) */
1082 sessionPool
[id
] = NULL
;
1084 (void) mutex_unlock(&sessionPoolLock
);
1085 (void) ldap_unbind(cp
->ld
);
1086 __s_api_freeConnection(cp
);
1091 DropConnection(ConnectionID cID
, int flag
)
1093 _DropConnection(cID
, flag
, 0);
1097 * This routine is called after a bind operation is
1098 * done in openConnection() to process the password
1099 * management information, if any.
1102 * bind_type: "simple" or "sasl/DIGEST-MD5"
1103 * ldaprc : ldap rc from the ldap bind operation
1104 * controls : controls returned by the server
1105 * errmsg : error message from the server
1106 * fail_if_new_pwd_reqd:
1107 * flag indicating if connection should be open
1108 * when password needs to change immediately
1110 * flag indicating if server supports password
1113 * Output : ns_ldap_error structure, which may contain
1114 * password status and number of seconds until
1118 * NS_LDAP_EXTERNAL: error, connection should not open
1119 * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached
1120 * NS_LDAP_SUCCESS: OK to open connection
1125 process_pwd_mgmt(char *bind_type
, int ldaprc
,
1126 LDAPControl
**controls
,
1127 char *errmsg
, ns_ldap_error_t
**errorp
,
1128 int fail_if_new_pwd_reqd
,
1131 char errstr
[MAXERROR
];
1132 LDAPControl
**ctrl
= NULL
;
1134 ns_ldap_passwd_status_t pwd_status
= NS_PASSWD_GOOD
;
1135 int sec_until_exp
= 0;
1138 * errmsg may be an empty string,
1139 * even if ldaprc is LDAP_SUCCESS,
1140 * free the empty string if that's the case
1143 (*errmsg
== '\0' || ldaprc
== LDAP_SUCCESS
)) {
1144 ldap_memfree(errmsg
);
1148 if (ldaprc
!= LDAP_SUCCESS
) {
1150 * try to map ldap rc and error message to
1156 __s_api_set_passwd_status(
1158 ldap_memfree(errmsg
);
1161 (void) snprintf(errstr
, sizeof (errstr
),
1162 gettext("openConnection: "
1164 "- %s"), bind_type
, ldap_err2string(ldaprc
));
1166 if (pwd_status
!= NS_PASSWD_GOOD
) {
1167 MKERROR_PWD_MGMT(*errorp
,
1168 ldaprc
, strdup(errstr
),
1171 MKERROR(LOG_ERR
, *errorp
, ldaprc
, strdup(errstr
),
1175 ldap_controls_free(controls
);
1177 return (NS_LDAP_INTERNAL
);
1181 * ldaprc is LDAP_SUCCESS,
1182 * process the password management controls, if any
1184 exit_rc
= NS_LDAP_SUCCESS
;
1185 if (controls
&& passwd_mgmt
) {
1187 * The control with the OID
1188 * 2.16.840.1.113730.3.4.4 (or
1189 * LDAP_CONTROL_PWEXPIRED, as defined
1190 * in the ldap.h header file) is the
1191 * expired password control.
1193 * This control is used if the server
1194 * is configured to require users to
1195 * change their passwords when first
1196 * logging in and whenever the
1197 * passwords are reset.
1199 * If the user is logging in for the
1200 * first time or if the user's
1201 * password has been reset, the
1202 * server sends this control to
1203 * indicate that the client needs to
1204 * change the password immediately.
1206 * At this point, the only operation
1207 * that the client can perform is to
1208 * change the user's password. If the
1209 * client requests any other LDAP
1210 * operation, the server sends back
1211 * an LDAP_UNWILLING_TO_PERFORM
1212 * result code with an expired
1215 * The control with the OID
1216 * 2.16.840.1.113730.3.4.5 (or
1217 * LDAP_CONTROL_PWEXPIRING, as
1218 * defined in the ldap.h header file)
1219 * is the password expiration warning
1222 * This control is used if the server
1223 * is configured to expire user
1224 * passwords after a certain amount
1227 * The server sends this control back
1228 * to the client if the client binds
1229 * using a password that will soon
1230 * expire. The ldctl_value field of
1231 * the LDAPControl structure
1232 * specifies the number of seconds
1233 * before the password will expire.
1235 for (ctrl
= controls
; *ctrl
; ctrl
++) {
1237 if (strcmp((*ctrl
)->ldctl_oid
,
1238 LDAP_CONTROL_PWEXPIRED
) == 0) {
1240 * if the caller wants this bind
1241 * to fail, set up the error info.
1242 * If call to this function is
1243 * for searching the LDAP directory,
1244 * e.g., __ns_ldap_list(),
1245 * there's really no sense to
1246 * let a connection open and
1247 * then fail immediately afterward
1248 * on the LDAP search operation with
1249 * the LDAP_UNWILLING_TO_PERFORM rc
1252 NS_PASSWD_CHANGE_NEEDED
;
1253 if (fail_if_new_pwd_reqd
) {
1254 (void) snprintf(errstr
,
1265 MKERROR_PWD_MGMT(*errorp
,
1271 exit_rc
= NS_LDAP_INTERNAL
;
1273 MKERROR_PWD_MGMT(*errorp
,
1280 NS_LDAP_SUCCESS_WITH_INFO
;
1283 } else if (strcmp((*ctrl
)->ldctl_oid
,
1284 LDAP_CONTROL_PWEXPIRING
) == 0) {
1286 NS_PASSWD_ABOUT_TO_EXPIRE
;
1288 ldctl_value
.bv_len
> 0 &&
1293 ldctl_value
.bv_val
);
1294 MKERROR_PWD_MGMT(*errorp
,
1301 NS_LDAP_SUCCESS_WITH_INFO
;
1308 ldap_controls_free(controls
);
1314 ldap_in_nss_switch(char *db
)
1316 enum __nsw_parse_err pserr
;
1317 struct __nsw_switchconfig
*conf
;
1318 struct __nsw_lookup
*lkp
;
1322 conf
= __nsw_getconfig(db
, &pserr
);
1327 /* check for skip and count other backends */
1328 for (lkp
= conf
->lookups
; lkp
!= NULL
; lkp
= lkp
->next
) {
1329 name
= lkp
->service_name
;
1330 if (strcmp(name
, "ldap") == 0) {
1335 (void) __nsw_freeconfig(conf
);
1340 openConnection(LDAP
**ldp
, const char *serverAddr
, const ns_cred_t
*auth
,
1341 int timeoutSec
, ns_ldap_error_t
**errorp
,
1342 int fail_if_new_pwd_reqd
, int passwd_mgmt
,
1343 ns_conn_user_t
*conn_user
, int flags
)
1346 int ldapVersion
= LDAP_VERSION3
;
1347 int derefOption
= LDAP_DEREF_ALWAYS
;
1349 int timeoutMilliSec
= timeoutSec
* 1000;
1350 uint16_t port
= USE_DEFAULT_PORT
;
1352 char errstr
[MAXERROR
];
1355 ns_ldap_return_code ret_code
= NS_LDAP_SUCCESS
;
1360 /* determine if the host name contains a port number */
1361 s
= strchr(serverAddr
, ']'); /* skip over ipv6 addr */
1362 s
= strchr(s
!= NULL
? s
: serverAddr
, ':');
1364 if (sscanf(s
+ 1, "%hu", &port
) != 1) {
1365 (void) snprintf(errstr
,
1367 gettext("openConnection: cannot "
1368 "convert %s into a valid "
1369 "port number for the "
1370 "%s server. A default value "
1374 syslog(LOG_ERR
, "libsldap: %s", errstr
);
1380 ret_code
= createSession(auth
,
1389 if (ret_code
!= NS_LDAP_SUCCESS
) {
1393 /* check to see if the underlying libsldap supports MT connection */
1394 if (conn_user
!= NULL
) {
1397 rc
= __s_api_check_libldap_MT_conn_support(conn_user
, ld
,
1399 if (rc
!= NS_LDAP_SUCCESS
) {
1400 (void) ldap_unbind(ld
);
1405 (void) ldap_set_option(ld
, LDAP_OPT_PROTOCOL_VERSION
, &ldapVersion
);
1406 (void) ldap_set_option(ld
, LDAP_OPT_DEREF
, &derefOption
);
1408 * This library will handle the referral itself based on API flags or
1409 * configuration file specification. The LDAP bind operation is an
1410 * exception where we rely on the LDAP library to follow the referal.
1412 * The LDAP follow referral option must be set to OFF for the libldap5
1413 * to pass the referral info up to this library. This option MUST be
1414 * set to OFF after we have performed a sucessful bind. If we are not
1415 * to follow referrals we MUST also set the LDAP follow referral option
1416 * to OFF before we perform an LDAP bind.
1418 ret_code
= __s_api_toFollowReferrals(flags
, &followRef
, errorp
);
1419 if (ret_code
!= NS_LDAP_SUCCESS
) {
1420 (void) ldap_unbind(ld
);
1425 (void) ldap_set_option(ld
, LDAP_OPT_REFERRALS
, LDAP_OPT_ON
);
1427 (void) ldap_set_option(ld
, LDAP_OPT_REFERRALS
, LDAP_OPT_OFF
);
1429 (void) ldap_set_option(ld
, LDAP_OPT_TIMELIMIT
, &zero
);
1430 (void) ldap_set_option(ld
, LDAP_OPT_SIZELIMIT
, &zero
);
1431 /* setup TCP/IP connect timeout */
1432 (void) ldap_set_option(ld
, LDAP_X_OPT_CONNECT_TIMEOUT
,
1434 /* retry if LDAP I/O was interrupted */
1435 (void) ldap_set_option(ld
, LDAP_OPT_RESTART
, LDAP_OPT_ON
);
1437 ret_code
= performBind(auth
,
1441 fail_if_new_pwd_reqd
,
1444 if (ret_code
== NS_LDAP_SUCCESS
||
1445 ret_code
== NS_LDAP_SUCCESS_WITH_INFO
) {
1447 * Turn off LDAP referral following so that this library can
1448 * process referrals.
1450 (void) ldap_set_option(ld
, LDAP_OPT_REFERRALS
, LDAP_OPT_OFF
);
1458 * FUNCTION: __s_api_getDefaultAuth
1460 * Constructs a credential for authentication using the config module.
1464 * NS_LDAP_SUCCESS If successful
1465 * NS_LDAP_CONFIG If there are any config errors.
1466 * NS_LDAP_MEMORY Memory errors.
1467 * NS_LDAP_OP_FAILED If there are no more authentication methods so can
1468 * not build a new authp.
1469 * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the
1470 * necessary fields of a cred for a given auth method
1474 * cLevel Currently requested credential level to be tried
1476 * aMethod Currently requested authentication method to be tried
1478 * getAdmin If non 0, get Admin -i.e., not proxyAgent- DN and password
1482 * authp authentication method to use.
1485 __s_api_getDefaultAuth(
1491 void **paramVal
= NULL
;
1492 char *modparamVal
= NULL
;
1495 int getCertpath
= 0;
1497 ns_ldap_error_t
*errorp
= NULL
;
1498 UnixCred_t
*AdminCred
= NULL
;
1501 (void) fprintf(stderr
, "__s_api_getDefaultAuth START\n");
1504 if (aMethod
== NULL
) {
1505 /* Require an Auth */
1506 return (NS_LDAP_INVALID_PARAM
);
1510 * credential level "self" can work with auth method sasl/GSSAPI only
1512 if (cLevel
&& *cLevel
== NS_LDAP_CRED_SELF
&&
1513 aMethod
->saslmech
!= NS_LDAP_SASL_GSSAPI
)
1514 return (NS_LDAP_INVALID_PARAM
);
1516 *authp
= (ns_cred_t
*)calloc(1, sizeof (ns_cred_t
));
1517 if ((*authp
) == NULL
)
1518 return (NS_LDAP_MEMORY
);
1520 (*authp
)->auth
= *aMethod
;
1522 switch (aMethod
->type
) {
1523 case NS_LDAP_AUTH_NONE
:
1524 return (NS_LDAP_SUCCESS
);
1525 case NS_LDAP_AUTH_SIMPLE
:
1529 case NS_LDAP_AUTH_SASL
:
1530 if ((aMethod
->saslmech
== NS_LDAP_SASL_DIGEST_MD5
) ||
1531 (aMethod
->saslmech
== NS_LDAP_SASL_CRAM_MD5
)) {
1534 } else if (aMethod
->saslmech
!= NS_LDAP_SASL_GSSAPI
) {
1535 (void) __ns_ldap_freeCred(authp
);
1536 return (NS_LDAP_INVALID_PARAM
);
1539 case NS_LDAP_AUTH_TLS
:
1540 if ((aMethod
->tlstype
== NS_LDAP_TLS_SIMPLE
) ||
1541 ((aMethod
->tlstype
== NS_LDAP_TLS_SASL
) &&
1542 ((aMethod
->saslmech
== NS_LDAP_SASL_DIGEST_MD5
) ||
1543 (aMethod
->saslmech
== NS_LDAP_SASL_CRAM_MD5
)))) {
1547 } else if (aMethod
->tlstype
== NS_LDAP_TLS_NONE
) {
1550 (void) __ns_ldap_freeCred(authp
);
1551 return (NS_LDAP_INVALID_PARAM
);
1560 * Assume AdminCred has been retrieved from
1561 * ldap_cachemgr already. It will not work
1562 * without userID or password. Flags getUid
1563 * and getPasswd should always be set
1566 AdminCred
= calloc(1, sizeof (UnixCred_t
));
1567 if (AdminCred
== NULL
) {
1568 (void) __ns_ldap_freeCred(authp
);
1569 return (NS_LDAP_MEMORY
);
1572 rc
= requestAdminCred(&AdminCred
, &errorp
);
1573 if (rc
!= NS_LDAP_SUCCESS
) {
1574 (void) __ns_ldap_freeCred(authp
);
1575 (void) __ns_ldap_freeUnixCred(&AdminCred
);
1576 (void) __ns_ldap_freeError(&errorp
);
1580 if (AdminCred
->userID
== NULL
) {
1581 (void) __ns_ldap_freeCred(authp
);
1582 (void) __ns_ldap_freeUnixCred(&AdminCred
);
1583 return (NS_LDAP_INVALID_PARAM
);
1585 (*authp
)->cred
.unix_cred
.userID
= AdminCred
->userID
;
1586 AdminCred
->userID
= NULL
;
1588 rc
= __ns_ldap_getParam(NS_LDAP_BINDDN_P
,
1589 ¶mVal
, &errorp
);
1590 if (rc
!= NS_LDAP_SUCCESS
) {
1591 (void) __ns_ldap_freeCred(authp
);
1592 (void) __ns_ldap_freeError(&errorp
);
1596 if (paramVal
== NULL
|| *paramVal
== NULL
) {
1597 (void) __ns_ldap_freeCred(authp
);
1598 return (NS_LDAP_INVALID_PARAM
);
1601 (*authp
)->cred
.unix_cred
.userID
=
1602 strdup((char *)*paramVal
);
1603 (void) __ns_ldap_freeParam(¶mVal
);
1605 if ((*authp
)->cred
.unix_cred
.userID
== NULL
) {
1606 (void) __ns_ldap_freeCred(authp
);
1607 (void) __ns_ldap_freeUnixCred(&AdminCred
);
1608 return (NS_LDAP_MEMORY
);
1615 * Assume AdminCred has been retrieved from
1616 * ldap_cachemgr already. It will not work
1617 * without the userID anyway because for
1618 * getting admin credential, flags getUid
1619 * and getPasswd should always be set
1622 if (AdminCred
== NULL
|| AdminCred
->passwd
== NULL
) {
1623 (void) __ns_ldap_freeCred(authp
);
1624 (void) __ns_ldap_freeUnixCred(&AdminCred
);
1625 return (NS_LDAP_INVALID_PARAM
);
1627 modparamVal
= dvalue(AdminCred
->passwd
);
1629 rc
= __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P
,
1630 ¶mVal
, &errorp
);
1631 if (rc
!= NS_LDAP_SUCCESS
) {
1632 (void) __ns_ldap_freeCred(authp
);
1633 (void) __ns_ldap_freeError(&errorp
);
1637 if (paramVal
== NULL
|| *paramVal
== NULL
) {
1638 (void) __ns_ldap_freeCred(authp
);
1639 return (NS_LDAP_INVALID_PARAM
);
1642 modparamVal
= dvalue((char *)*paramVal
);
1643 (void) __ns_ldap_freeParam(¶mVal
);
1646 if (modparamVal
== NULL
|| (strlen((char *)modparamVal
) == 0)) {
1647 (void) __ns_ldap_freeCred(authp
);
1648 (void) __ns_ldap_freeUnixCred(&AdminCred
);
1650 return (NS_LDAP_INVALID_PARAM
);
1653 (*authp
)->cred
.unix_cred
.passwd
= modparamVal
;
1657 if ((rc
= __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P
,
1658 ¶mVal
, &errorp
)) != NS_LDAP_SUCCESS
) {
1659 (void) __ns_ldap_freeCred(authp
);
1660 (void) __ns_ldap_freeUnixCred(&AdminCred
);
1661 (void) __ns_ldap_freeError(&errorp
);
1666 if (paramVal
== NULL
|| *paramVal
== NULL
) {
1667 (void) __ns_ldap_freeCred(authp
);
1668 (void) __ns_ldap_freeUnixCred(&AdminCred
);
1670 return (NS_LDAP_INVALID_PARAM
);
1673 (*authp
)->hostcertpath
= strdup((char *)*paramVal
);
1674 (void) __ns_ldap_freeParam(¶mVal
);
1675 if ((*authp
)->hostcertpath
== NULL
) {
1676 (void) __ns_ldap_freeCred(authp
);
1677 (void) __ns_ldap_freeUnixCred(&AdminCred
);
1679 return (NS_LDAP_MEMORY
);
1682 (void) __ns_ldap_freeUnixCred(&AdminCred
);
1683 return (NS_LDAP_SUCCESS
);
1687 * FUNCTION: getConnection
1689 * internal version of __s_api_getConnection()
1695 const ns_cred_t
*cred
, /* credentials for bind */
1696 ConnectionID
*sessionId
,
1697 Connection
**session
,
1698 ns_ldap_error_t
**errorp
,
1699 int fail_if_new_pwd_reqd
,
1700 int nopasswd_acct_mgmt
,
1701 ns_conn_user_t
*conn_user
)
1703 char errmsg
[MAXERROR
];
1704 ns_auth_t
**aMethod
= NULL
;
1705 ns_auth_t
**aNext
= NULL
;
1706 int **cLevel
= NULL
;
1708 int timeoutSec
= NS_DEFAULT_BIND_TIMEOUT
;
1710 Connection
*con
= NULL
;
1712 ns_cred_t
*authp
= NULL
;
1714 int version
= NS_LDAP_V2
, self_gssapi_only
= 0;
1715 void **paramVal
= NULL
;
1716 char **badSrvrs
= NULL
; /* List of problem hostnames */
1718 if ((session
== NULL
) || (sessionId
== NULL
)) {
1719 return (NS_LDAP_INVALID_PARAM
);
1723 /* reuse MT connection if needed and if available */
1724 if (conn_user
!= NULL
) {
1725 rc
= __s_api_conn_mt_get(server
, flags
, cred
, session
, errorp
,
1727 if (rc
!= NS_LDAP_NOTFOUND
)
1731 /* get profile version number */
1732 if ((rc
= __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P
,
1733 ¶mVal
, errorp
)) != NS_LDAP_SUCCESS
)
1735 if (paramVal
== NULL
) {
1736 (void) sprintf(errmsg
, gettext("getConnection: no file "
1738 MKERROR(LOG_WARNING
, *errorp
, NS_CONFIG_FILE
, strdup(errmsg
),
1740 return (NS_LDAP_CONFIG
);
1742 if (strcasecmp((char *)*paramVal
, NS_LDAP_VERSION_1
) == 0)
1743 version
= NS_LDAP_V1
;
1744 (void) __ns_ldap_freeParam((void ***)¶mVal
);
1746 /* Get the bind timeout value */
1747 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P
, ¶mVal
, errorp
);
1748 if (paramVal
!= NULL
&& *paramVal
!= NULL
) {
1749 timeoutSec
= **((int **)paramVal
);
1750 (void) __ns_ldap_freeParam(¶mVal
);
1753 (void) __ns_ldap_freeError(errorp
);
1756 /* Get the authentication method list */
1757 if ((rc
= __ns_ldap_getParam(NS_LDAP_AUTH_P
,
1758 (void ***)&aMethod
, errorp
)) != NS_LDAP_SUCCESS
)
1760 if (aMethod
== NULL
) {
1761 aMethod
= (ns_auth_t
**)calloc(2, sizeof (ns_auth_t
*));
1762 if (aMethod
== NULL
)
1763 return (NS_LDAP_MEMORY
);
1764 aMethod
[0] = (ns_auth_t
*)calloc(1, sizeof (ns_auth_t
));
1765 if (aMethod
[0] == NULL
) {
1767 return (NS_LDAP_MEMORY
);
1769 if (version
== NS_LDAP_V1
)
1770 (aMethod
[0])->type
= NS_LDAP_AUTH_SIMPLE
;
1772 (aMethod
[0])->type
= NS_LDAP_AUTH_SASL
;
1773 (aMethod
[0])->saslmech
=
1774 NS_LDAP_SASL_DIGEST_MD5
;
1775 (aMethod
[0])->saslopt
= NS_LDAP_SASLOPT_NONE
;
1779 /* Get the credential level list */
1780 if ((rc
= __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P
,
1781 (void ***)&cLevel
, errorp
)) != NS_LDAP_SUCCESS
) {
1782 (void) __ns_ldap_freeParam((void ***)&aMethod
);
1785 if (cLevel
== NULL
) {
1786 cLevel
= (int **)calloc(2, sizeof (int *));
1788 return (NS_LDAP_MEMORY
);
1789 cLevel
[0] = (int *)calloc(1, sizeof (int));
1790 if (cLevel
[0] == NULL
)
1791 return (NS_LDAP_MEMORY
);
1792 if (version
== NS_LDAP_V1
)
1793 *(cLevel
[0]) = NS_LDAP_CRED_PROXY
;
1795 *(cLevel
[0]) = NS_LDAP_CRED_ANON
;
1799 /* setup the anon credential for anonymous connection */
1800 (void) memset(&anon
, 0, sizeof (ns_cred_t
));
1801 anon
.auth
.type
= NS_LDAP_AUTH_NONE
;
1805 /* using specified auth method */
1806 rc
= makeConnection(&con
, server
, cred
,
1807 sessionId
, timeoutSec
, errorp
,
1808 fail_if_new_pwd_reqd
,
1809 nopasswd_acct_mgmt
, flags
, &badSrvrs
, conn_user
);
1810 /* not using bad server if credentials were supplied */
1811 if (badSrvrs
&& *badSrvrs
) {
1812 __s_api_free2dArray(badSrvrs
);
1815 if (rc
== NS_LDAP_SUCCESS
||
1816 rc
== NS_LDAP_SUCCESS_WITH_INFO
) {
1821 self_gssapi_only
= __s_api_self_gssapi_only_get();
1822 /* for every cred level */
1823 for (cNext
= cLevel
; *cNext
!= NULL
; cNext
++) {
1824 if (self_gssapi_only
&&
1825 **cNext
!= NS_LDAP_CRED_SELF
)
1827 if (**cNext
== NS_LDAP_CRED_ANON
) {
1829 * make connection anonymously
1830 * Free the down server list before
1833 if (badSrvrs
&& *badSrvrs
) {
1834 __s_api_free2dArray(badSrvrs
);
1837 rc
= makeConnection(&con
, server
, &anon
,
1838 sessionId
, timeoutSec
, errorp
,
1839 fail_if_new_pwd_reqd
,
1840 nopasswd_acct_mgmt
, flags
,
1841 &badSrvrs
, conn_user
);
1842 if (rc
== NS_LDAP_SUCCESS
||
1844 NS_LDAP_SUCCESS_WITH_INFO
) {
1850 /* for each cred level */
1851 for (aNext
= aMethod
; *aNext
!= NULL
; aNext
++) {
1852 if (self_gssapi_only
&&
1853 (*aNext
)->saslmech
!=
1854 NS_LDAP_SASL_GSSAPI
)
1857 * self coexists with sasl/GSSAPI only
1858 * and non-self coexists with non-gssapi
1861 if ((**cNext
== NS_LDAP_CRED_SELF
&&
1862 (*aNext
)->saslmech
!=
1863 NS_LDAP_SASL_GSSAPI
) ||
1864 (**cNext
!= NS_LDAP_CRED_SELF
&&
1865 (*aNext
)->saslmech
==
1866 NS_LDAP_SASL_GSSAPI
))
1868 /* make connection and authenticate */
1869 /* with default credentials */
1871 rc
= __s_api_getDefaultAuth(*cNext
,
1873 flags
& NS_LDAP_READ_SHADOW
);
1874 if (rc
!= NS_LDAP_SUCCESS
) {
1878 * Free the down server list before
1881 if (badSrvrs
&& *badSrvrs
) {
1882 __s_api_free2dArray(badSrvrs
);
1885 rc
= makeConnection(&con
, server
, authp
,
1886 sessionId
, timeoutSec
, errorp
,
1887 fail_if_new_pwd_reqd
,
1888 nopasswd_acct_mgmt
, flags
,
1889 &badSrvrs
, conn_user
);
1890 (void) __ns_ldap_freeCred(&authp
);
1891 if (rc
== NS_LDAP_SUCCESS
||
1893 NS_LDAP_SUCCESS_WITH_INFO
) {
1900 if (flags
& NS_LDAP_HARD
) {
1901 if (sec
< LDAPMAXHARDLOOKUPTIME
)
1910 if (self_gssapi_only
&& rc
== NS_LDAP_SUCCESS
&& *session
== NULL
) {
1912 * self_gssapi_only is true but no self/sasl/gssapi is
1915 rc
= NS_LDAP_CONFIG
;
1918 (void) __ns_ldap_freeParam((void ***)&aMethod
);
1919 (void) __ns_ldap_freeParam((void ***)&cLevel
);
1921 if (badSrvrs
&& *badSrvrs
) {
1923 * At this point, either we have a successful
1924 * connection or exhausted all the possible auths.
1925 * and creds. Mark the problem servers as down
1926 * so that the problem servers are not contacted
1927 * again until the refresh_ttl expires.
1929 (void) __s_api_removeBadServers(badSrvrs
);
1930 __s_api_free2dArray(badSrvrs
);
1936 * FUNCTION: __s_api_getConnection
1938 * Bind to the specified server or one from the server
1939 * list and return the pointer.
1941 * This function can rebind or not (NS_LDAP_HARD), it can require a
1942 * credential or bind anonymously
1944 * This function follows the DUA configuration schema algorithm
1948 * NS_LDAP_SUCCESS A connection was made successfully.
1949 * NS_LDAP_SUCCESS_WITH_INFO
1950 * A connection was made successfully, but with
1951 * password management info in *errorp
1952 * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function.
1953 * NS_LDAP_CONFIG If there are any config errors.
1954 * NS_LDAP_MEMORY Memory errors.
1955 * NS_LDAP_INTERNAL If there was a ldap error.
1959 * server Bind to this LDAP server only
1960 * flags If NS_LDAP_HARD is set function will not return until it has
1961 * a connection unless there is a authentication problem.
1962 * If NS_LDAP_NEW_CONN is set the function must force a new
1963 * connection to be created
1964 * If NS_LDAP_KEEP_CONN is set the connection is to be kept open
1965 * auth Credentials for bind. This could be NULL in which case
1966 * a default cred built from the config module is used.
1967 * sessionId cookie that points to a previous session
1968 * fail_if_new_pwd_reqd
1969 * a flag indicating this function should fail if the passwd
1970 * in auth needs to change immediately
1971 * nopasswd_acct_mgmt
1972 * a flag indicating that makeConnection should check before
1973 * binding if server supports LDAP V3 password less
1974 * account management
1978 * session pointer to a session with connection information
1979 * errorp Set if there are any INTERNAL, or CONFIG error.
1982 __s_api_getConnection(
1985 const ns_cred_t
*cred
, /* credentials for bind */
1986 ConnectionID
*sessionId
,
1987 Connection
**session
,
1988 ns_ldap_error_t
**errorp
,
1989 int fail_if_new_pwd_reqd
,
1990 int nopasswd_acct_mgmt
,
1991 ns_conn_user_t
*conn_user
)
1995 rc
= getConnection(server
, flags
, cred
, sessionId
, session
,
1996 errorp
, fail_if_new_pwd_reqd
, nopasswd_acct_mgmt
,
1999 if (rc
!= NS_LDAP_SUCCESS
&& rc
!= NS_LDAP_SUCCESS_WITH_INFO
) {
2000 if (conn_user
!= NULL
&& conn_user
->conn_mt
!= NULL
)
2001 __s_api_conn_mt_remove(conn_user
, rc
, errorp
);
2008 __s_api_free_sessionPool()
2012 (void) mutex_lock(&sessionPoolLock
);
2014 if (sessionPool
!= NULL
) {
2015 for (id
= 0; id
< sessionPoolSize
; id
++)
2016 _DropConnection(id
+ CONID_OFFSET
, 0, 1);
2019 sessionPoolSize
= 0;
2021 (void) mutex_unlock(&sessionPoolLock
);
2025 * This function initializes a TLS LDAP session. On success LDAP* is returned
2026 * (pointed by *ldp). Otherwise, the function returns an NS error code and
2027 * provide an additional info pointed by *errorp.
2031 createTLSSession(const ns_cred_t
*auth
, const char *serverAddr
,
2032 uint16_t port
, int timeoutMilliSec
,
2033 LDAP
**ldp
, ns_ldap_error_t
**errorp
)
2035 const char *hostcertpath
;
2036 char *alloc_hcp
= NULL
, errstr
[MAXERROR
];
2040 (void) fprintf(stderr
, "tid= %d: +++TLS transport\n",
2044 if (prldap_set_session_option(NULL
, NULL
,
2045 PRLDAP_OPT_IO_MAX_TIMEOUT
,
2046 timeoutMilliSec
) != LDAP_SUCCESS
) {
2047 (void) snprintf(errstr
, sizeof (errstr
),
2048 gettext("createTLSSession: failed to initialize "
2050 MKERROR(LOG_WARNING
, *errorp
, LDAP_CONNECT_ERROR
,
2051 strdup(errstr
), NS_LDAP_MEMORY
);
2052 return (NS_LDAP_INTERNAL
);
2055 hostcertpath
= auth
->hostcertpath
;
2056 if (hostcertpath
== NULL
) {
2057 alloc_hcp
= __s_get_hostcertpath();
2058 hostcertpath
= alloc_hcp
;
2061 if (hostcertpath
== NULL
)
2062 return (NS_LDAP_MEMORY
);
2064 if ((ldap_rc
= ldapssl_client_init(hostcertpath
, NULL
)) < 0) {
2065 if (alloc_hcp
!= NULL
) {
2068 (void) snprintf(errstr
, sizeof (errstr
),
2069 gettext("createTLSSession: failed to initialize "
2070 "TLS security (%s)"),
2071 ldapssl_err2string(ldap_rc
));
2072 MKERROR(LOG_WARNING
, *errorp
, LDAP_CONNECT_ERROR
,
2073 strdup(errstr
), NS_LDAP_MEMORY
);
2074 return (NS_LDAP_INTERNAL
);
2078 *ldp
= ldapssl_init(serverAddr
, port
, 1);
2081 ldapssl_install_gethostbyaddr(*ldp
, "ldap") != 0) {
2082 (void) snprintf(errstr
, sizeof (errstr
),
2083 gettext("createTLSSession: failed to connect "
2084 "using TLS (%s)"), strerror(errno
));
2085 MKERROR(LOG_WARNING
, *errorp
, LDAP_CONNECT_ERROR
,
2086 strdup(errstr
), NS_LDAP_MEMORY
);
2087 return (NS_LDAP_INTERNAL
);
2090 return (NS_LDAP_SUCCESS
);
2094 * Convert (resolve) hostname to IP address.
2098 * server - \[IPv6_address\][:port]
2099 * - IPv4_address[:port]
2102 * newaddr - Buffer to which this function writes resulting address,
2103 * including the port number, if specified in server argument.
2105 * newaddr_size - Size of the newaddr buffer.
2107 * errstr - Buffer to which error string is written if error occurs.
2109 * errstr_size - Size of the errstr buffer.
2113 * Returns 1 for success, 0 in case of error.
2115 * newaddr - See above (INPUT section).
2117 * errstr - See above (INPUT section).
2120 cvt_hostname2ip(char *server
, char *newaddr
, int newaddr_size
,
2121 char *errstr
, int errstr_size
)
2124 unsigned short port
= 0;
2126 char buffer
[NSS_BUFLEN_HOSTS
];
2127 struct hostent result
;
2129 /* Determine if the host name contains a port number. */
2131 /* Skip over IPv6 address. */
2132 s
= strchr(server
, ']');
2133 s
= strchr(s
!= NULL
? s
: server
, ':');
2135 if (sscanf(s
+ 1, "%hu", &port
) != 1) {
2136 /* Address misformatted. No port number after : */
2137 (void) snprintf(errstr
, errstr_size
, "%s",
2138 gettext("Invalid host:port format"));
2141 /* Cut off the :<port> part. */
2147 * Resolve hostname and fill in hostent structure.
2149 if (!__s_api_hostname2ip(server
, &result
, buffer
, NSS_BUFLEN_HOSTS
,
2152 * The only possible error here could be TRY_AGAIN if buffer was
2153 * not big enough. NSS_BUFLEN_HOSTS should have been enough
2156 (void) snprintf(errstr
, errstr_size
, "%s",
2157 gettext("Unable to resolve address."));
2164 * Convert the address to string.
2166 if (!inet_ntop(result
.h_addrtype
, result
.h_addr_list
[0], buffer
,
2167 NSS_BUFLEN_HOSTS
)) {
2168 /* There's not much we can do. */
2169 (void) snprintf(errstr
, errstr_size
, "%s",
2170 gettext("Unable to convert address to string."));
2174 /* Put together the address and the port */
2176 switch (result
.h_addrtype
) {
2178 (void) snprintf(newaddr
,
2180 1 + strlen(buffer
) + 1 + 1 + 5 + 1,
2187 (void) snprintf(newaddr
,
2189 strlen(buffer
) + 1 + 5 + 1,
2196 (void) strncpy(newaddr
, buffer
, newaddr_size
);
2204 * This finction initializes a none-TLS LDAP session. On success LDAP*
2205 * is returned (pointed by *ldp). Otherwise, the function returns
2206 * an NS error code and provides an additional info pointed by *errorp.
2210 createNonTLSSession(const char *serverAddr
,
2211 uint16_t port
, int gssapi
,
2212 LDAP
**ldp
, ns_ldap_error_t
**errorp
)
2214 char errstr
[MAXERROR
];
2217 /* [INET6_ADDRSTRLEN]:<port>\0 */
2218 char svraddr
[1+INET6_ADDRSTRLEN
+1+1+5+1];
2220 (void) fprintf(stderr
, "tid= %d: +++Unsecure transport\n",
2225 is_ip
= (__s_api_isipv4((char *)serverAddr
) ||
2226 __s_api_isipv6((char *)serverAddr
));
2230 * Let's try to resolve IP address of server.
2232 if (is_ip
== 0 && !gssapi
&& (ldap_in_nss_switch((char *)"hosts") > 0 ||
2233 ldap_in_nss_switch((char *)"ipnodes") > 0)) {
2234 addr
= strdup(serverAddr
);
2236 return (NS_LDAP_MEMORY
);
2238 if (cvt_hostname2ip(addr
, svraddr
, sizeof (svraddr
),
2239 errstr
, MAXERROR
) == 1) {
2240 serverAddr
= svraddr
;
2244 MKERROR(LOG_WARNING
, *errorp
, LDAP_CONNECT_ERROR
,
2245 strdup(errstr
), NS_LDAP_MEMORY
);
2246 return (NS_LDAP_INTERNAL
);
2250 /* Warning message IF cannot connect to host(s) */
2251 if ((*ldp
= ldap_init((char *)serverAddr
, port
)) == NULL
) {
2252 char *p
= strerror(errno
);
2253 MKERROR(LOG_WARNING
, *errorp
, LDAP_CONNECT_ERROR
,
2254 strdup(p
), NS_LDAP_MEMORY
);
2255 return (NS_LDAP_INTERNAL
);
2258 return (NS_LDAP_SUCCESS
);
2262 * This finction initializes an LDAP session.
2265 * auth - a structure specified an authenticastion method and credentials,
2266 * serverAddr - the address of a server to which a connection
2267 * will be established,
2268 * port - a port being listened by the server,
2269 * timeoutMilliSec - a timeout in milliseconds for the Bind operation.
2272 * ldp - a pointer to an LDAP structure which will be used
2273 * for all the subsequent operations against the server.
2274 * If an error occurs, the function returns an NS error code
2275 * and provides an additional info pointed by *errorp.
2279 createSession(const ns_cred_t
*auth
, const char *serverAddr
,
2280 uint16_t port
, int timeoutMilliSec
,
2281 LDAP
**ldp
, ns_ldap_error_t
**errorp
)
2283 int useSSL
= 0, gssapi
= 0;
2284 char errstr
[MAXERROR
];
2286 switch (auth
->auth
.type
) {
2287 case NS_LDAP_AUTH_NONE
:
2288 case NS_LDAP_AUTH_SIMPLE
:
2289 case NS_LDAP_AUTH_SASL
:
2291 case NS_LDAP_AUTH_TLS
:
2295 (void) sprintf(errstr
,
2296 gettext("openConnection: unsupported "
2297 "authentication method (%d)"), auth
->auth
.type
);
2298 MKERROR(LOG_WARNING
, *errorp
,
2299 LDAP_AUTH_METHOD_NOT_SUPPORTED
, strdup(errstr
),
2301 return (NS_LDAP_INTERNAL
);
2304 if (port
== USE_DEFAULT_PORT
) {
2305 port
= useSSL
? LDAPS_PORT
: LDAP_PORT
;
2308 if (auth
->auth
.type
== NS_LDAP_AUTH_SASL
&&
2309 auth
->auth
.saslmech
== NS_LDAP_SASL_GSSAPI
)
2313 return (createTLSSession(auth
, serverAddr
, port
,
2314 timeoutMilliSec
, ldp
, errorp
));
2316 return (createNonTLSSession(serverAddr
, port
, gssapi
,
2321 * This finction performs a non-SASL bind operation. If an error accures,
2322 * the function returns an NS error code and provides an additional info
2323 * pointed by *errorp.
2327 doSimpleBind(const ns_cred_t
*auth
,
2330 ns_ldap_error_t
**errorp
,
2331 int fail_if_new_pwd_reqd
,
2334 char *binddn
, *passwd
, errstr
[MAXERROR
], *errmsg
;
2335 int msgId
, errnum
= 0, ldap_rc
;
2336 ns_ldap_return_code ret_code
;
2337 LDAPMessage
*resultMsg
= NULL
;
2338 LDAPControl
**controls
;
2341 binddn
= auth
->cred
.unix_cred
.userID
;
2342 passwd
= auth
->cred
.unix_cred
.passwd
;
2343 if (passwd
== NULL
|| *passwd
== '\0' ||
2344 binddn
== NULL
|| *binddn
== '\0') {
2345 (void) sprintf(errstr
, gettext("openConnection: "
2346 "missing credentials for Simple bind"));
2347 MKERROR(LOG_WARNING
, *errorp
, LDAP_INVALID_CREDENTIALS
,
2348 strdup(errstr
), NS_LDAP_MEMORY
);
2349 (void) ldap_unbind(ld
);
2350 return (NS_LDAP_INTERNAL
);
2354 (void) fprintf(stderr
, "tid= %d: +++Simple bind\n",
2357 msgId
= ldap_simple_bind(ld
, binddn
, passwd
);
2360 (void) ldap_get_option(ld
, LDAP_OPT_ERROR_NUMBER
,
2362 (void) snprintf(errstr
, sizeof (errstr
),
2363 gettext("openConnection: simple bind failed "
2364 "- %s"), ldap_err2string(errnum
));
2365 (void) ldap_unbind(ld
);
2366 MKERROR(LOG_WARNING
, *errorp
, errnum
, strdup(errstr
),
2368 return (NS_LDAP_INTERNAL
);
2371 tv
.tv_sec
= timeoutSec
;
2373 ldap_rc
= ldap_result(ld
, msgId
, 0, &tv
, &resultMsg
);
2375 if ((ldap_rc
== -1) || (ldap_rc
== 0)) {
2376 (void) ldap_get_option(ld
, LDAP_OPT_ERROR_NUMBER
,
2378 (void) snprintf(errstr
, sizeof (errstr
),
2379 gettext("openConnection: simple bind failed "
2380 "- %s"), ldap_err2string(errnum
));
2381 (void) ldap_msgfree(resultMsg
);
2382 (void) ldap_unbind(ld
);
2383 MKERROR(LOG_WARNING
, *errorp
, errnum
, strdup(errstr
),
2385 return (NS_LDAP_INTERNAL
);
2389 * get ldaprc, controls, and error msg
2391 ldap_rc
= ldap_parse_result(ld
, resultMsg
, &errnum
, NULL
,
2392 &errmsg
, NULL
, &controls
, 1);
2394 if (ldap_rc
!= LDAP_SUCCESS
) {
2395 (void) snprintf(errstr
, sizeof (errstr
),
2396 gettext("openConnection: simple bind failed "
2397 "- unable to parse result"));
2398 (void) ldap_unbind(ld
);
2399 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
,
2400 strdup(errstr
), NS_LDAP_MEMORY
);
2401 return (NS_LDAP_INTERNAL
);
2404 /* process the password management info, if any */
2405 ret_code
= process_pwd_mgmt("simple",
2406 errnum
, controls
, errmsg
,
2408 fail_if_new_pwd_reqd
,
2411 if (ret_code
== NS_LDAP_INTERNAL
) {
2412 (void) ldap_unbind(ld
);
2419 * This finction performs a SASL bind operation. If an error accures,
2420 * the function returns an NS error code and provides an additional info
2421 * pointed by *errorp.
2425 doSASLBind(const ns_cred_t
*auth
,
2428 ns_ldap_error_t
**errorp
,
2429 int fail_if_new_pwd_reqd
,
2432 char *binddn
, *passwd
, *digest_md5_name
,
2433 errstr
[MAXERROR
], *errmsg
;
2435 int ldap_rc
, errnum
= 0;
2436 ns_ldap_return_code ret_code
;
2438 LDAPMessage
*resultMsg
;
2439 LDAPControl
**controls
;
2440 int min_ssf
= MIN_SASL_SSF
, max_ssf
= MAX_SASL_SSF
;
2441 ns_sasl_cb_param_t sasl_param
;
2443 if (auth
->auth
.saslopt
!= NS_LDAP_SASLOPT_NONE
&&
2444 auth
->auth
.saslmech
!= NS_LDAP_SASL_GSSAPI
) {
2445 (void) sprintf(errstr
,
2446 gettext("openConnection: SASL options are "
2447 "not supported (%d) for non-GSSAPI sasl bind"),
2448 auth
->auth
.saslopt
);
2449 MKERROR(LOG_WARNING
, *errorp
,
2450 LDAP_AUTH_METHOD_NOT_SUPPORTED
,
2451 strdup(errstr
), NS_LDAP_MEMORY
);
2452 (void) ldap_unbind(ld
);
2453 return (NS_LDAP_INTERNAL
);
2455 if (auth
->auth
.saslmech
!= NS_LDAP_SASL_GSSAPI
) {
2456 binddn
= auth
->cred
.unix_cred
.userID
;
2457 passwd
= auth
->cred
.unix_cred
.passwd
;
2458 if (passwd
== NULL
|| *passwd
== '\0' ||
2459 binddn
== NULL
|| *binddn
== '\0') {
2460 (void) sprintf(errstr
,
2461 gettext("openConnection: missing credentials "
2463 MKERROR(LOG_WARNING
, *errorp
,
2464 LDAP_INVALID_CREDENTIALS
,
2465 strdup(errstr
), NS_LDAP_MEMORY
);
2466 (void) ldap_unbind(ld
);
2467 return (NS_LDAP_INTERNAL
);
2469 cred
.bv_val
= passwd
;
2470 cred
.bv_len
= strlen(passwd
);
2473 ret_code
= NS_LDAP_SUCCESS
;
2475 switch (auth
->auth
.saslmech
) {
2476 case NS_LDAP_SASL_CRAM_MD5
:
2478 * NOTE: if iDS changes to support cram_md5,
2479 * please add password management code here.
2480 * Since ldap_sasl_cram_md5_bind_s does not
2481 * return anything that could be used to
2482 * extract the ldap rc/errmsg/control to
2483 * determine if bind failed due to password
2484 * policy, a new cram_md5_bind API will need
2485 * to be introduced. See
2486 * ldap_x_sasl_digest_md5_bind() and case
2487 * NS_LDAP_SASL_DIGEST_MD5 below for details.
2489 if ((ldap_rc
= ldap_sasl_cram_md5_bind_s(ld
, binddn
,
2490 &cred
, NULL
, NULL
)) != LDAP_SUCCESS
) {
2491 (void) ldap_get_option(ld
,
2492 LDAP_OPT_ERROR_NUMBER
, (void *)&errnum
);
2493 (void) snprintf(errstr
, sizeof (errstr
),
2494 gettext("openConnection: "
2495 "sasl/CRAM-MD5 bind failed - %s"),
2496 ldap_err2string(errnum
));
2497 MKERROR(LOG_WARNING
, *errorp
, errnum
,
2498 strdup(errstr
), NS_LDAP_MEMORY
);
2499 (void) ldap_unbind(ld
);
2500 return (NS_LDAP_INTERNAL
);
2503 case NS_LDAP_SASL_DIGEST_MD5
:
2504 digest_md5_name
= malloc(strlen(binddn
) + 5);
2505 /* 5 = strlen("dn: ") + 1 */
2506 if (digest_md5_name
== NULL
) {
2507 (void) ldap_unbind(ld
);
2508 return (NS_LDAP_MEMORY
);
2510 (void) strcpy(digest_md5_name
, "dn: ");
2511 (void) strcat(digest_md5_name
, binddn
);
2513 tv
.tv_sec
= timeoutSec
;
2515 ldap_rc
= ldap_x_sasl_digest_md5_bind(ld
,
2516 digest_md5_name
, &cred
, NULL
, NULL
,
2519 if (resultMsg
== NULL
) {
2520 free(digest_md5_name
);
2521 (void) ldap_get_option(ld
,
2522 LDAP_OPT_ERROR_NUMBER
, (void *)&errnum
);
2523 (void) snprintf(errstr
, sizeof (errstr
),
2524 gettext("openConnection: "
2525 "DIGEST-MD5 bind failed - %s"),
2526 ldap_err2string(errnum
));
2527 (void) ldap_unbind(ld
);
2528 MKERROR(LOG_WARNING
, *errorp
, errnum
,
2529 strdup(errstr
), NS_LDAP_MEMORY
);
2530 return (NS_LDAP_INTERNAL
);
2534 * get ldaprc, controls, and error msg
2536 ldap_rc
= ldap_parse_result(ld
, resultMsg
, &errnum
, NULL
,
2537 &errmsg
, NULL
, &controls
, 1);
2539 if (ldap_rc
!= LDAP_SUCCESS
) {
2540 free(digest_md5_name
);
2541 (void) snprintf(errstr
, sizeof (errstr
),
2542 gettext("openConnection: "
2543 "DIGEST-MD5 bind failed "
2544 "- unable to parse result"));
2545 (void) ldap_unbind(ld
);
2546 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
,
2547 strdup(errstr
), NS_LDAP_MEMORY
);
2548 return (NS_LDAP_INTERNAL
);
2551 /* process the password management info, if any */
2552 ret_code
= process_pwd_mgmt("sasl/DIGEST-MD5",
2553 errnum
, controls
, errmsg
,
2555 fail_if_new_pwd_reqd
,
2558 if (ret_code
== NS_LDAP_INTERNAL
) {
2559 (void) ldap_unbind(ld
);
2562 free(digest_md5_name
);
2564 case NS_LDAP_SASL_GSSAPI
:
2565 (void) memset(&sasl_param
, 0,
2566 sizeof (ns_sasl_cb_param_t
));
2567 sasl_param
.authid
= NULL
;
2568 sasl_param
.authzid
= "";
2569 (void) ldap_set_option(ld
, LDAP_OPT_X_SASL_SSF_MIN
,
2571 (void) ldap_set_option(ld
, LDAP_OPT_X_SASL_SSF_MAX
,
2574 ldap_rc
= ldap_sasl_interactive_bind_s(
2576 NULL
, NULL
, LDAP_SASL_INTERACTIVE
,
2577 __s_api_sasl_bind_callback
,
2580 if (ldap_rc
!= LDAP_SUCCESS
) {
2581 (void) snprintf(errstr
, sizeof (errstr
),
2582 gettext("openConnection: "
2583 "GSSAPI bind failed "
2586 ldap_err2string(ldap_rc
));
2587 (void) ldap_unbind(ld
);
2588 MKERROR(LOG_WARNING
, *errorp
, NS_LDAP_INTERNAL
,
2589 strdup(errstr
), NS_LDAP_MEMORY
);
2590 return (NS_LDAP_INTERNAL
);
2595 (void) ldap_unbind(ld
);
2596 (void) sprintf(errstr
,
2597 gettext("openConnection: unsupported SASL "
2598 "mechanism (%d)"), auth
->auth
.saslmech
);
2599 MKERROR(LOG_WARNING
, *errorp
,
2600 LDAP_AUTH_METHOD_NOT_SUPPORTED
, strdup(errstr
),
2602 return (NS_LDAP_INTERNAL
);
2609 * This function performs an LDAP Bind operation proceeding
2610 * from a type of the connection specified by auth->auth.type.
2613 * auth - a structure specified an authenticastion method and credentials,
2614 * ld - a pointer returned by the createSession() function,
2615 * timeoutSec - a timeout in seconds for the Bind operation,
2616 * fail_if_new_pwd_reqd - a flag indicating that the call should fail
2617 * if a new password is required,
2618 * passwd_mgmt - a flag indicating that the server supports
2619 * password management.
2622 * If an error accures, the function returns an NS error code
2623 * and provides an additional info pointed by *errorp.
2627 performBind(const ns_cred_t
*auth
,
2630 ns_ldap_error_t
**errorp
,
2631 int fail_if_new_pwd_reqd
,
2635 char errstr
[MAXERROR
];
2637 ns_ldap_return_code (*binder
)(const ns_cred_t
*auth
,
2640 ns_ldap_error_t
**errorp
,
2641 int fail_if_new_pwd_reqd
,
2642 int passwd_mgmt
) = NULL
;
2645 (void) sprintf(errstr
,
2646 "performBind: LDAP session "
2647 "is not initialized.");
2648 MKERROR(LOG_WARNING
, *errorp
,
2649 LDAP_AUTH_METHOD_NOT_SUPPORTED
,
2650 strdup(errstr
), NS_LDAP_MEMORY
);
2651 return (NS_LDAP_INTERNAL
);
2654 bindType
= auth
->auth
.type
== NS_LDAP_AUTH_TLS
?
2655 auth
->auth
.tlstype
: auth
->auth
.type
;
2658 case NS_LDAP_AUTH_NONE
:
2660 (void) fprintf(stderr
, "tid= %d: +++Anonymous bind\n",
2664 case NS_LDAP_AUTH_SIMPLE
:
2665 binder
= doSimpleBind
;
2667 case NS_LDAP_AUTH_SASL
:
2668 binder
= doSASLBind
;
2671 (void) sprintf(errstr
,
2672 gettext("openConnection: unsupported "
2673 "authentication method "
2675 MKERROR(LOG_WARNING
, *errorp
,
2676 LDAP_AUTH_METHOD_NOT_SUPPORTED
,
2677 strdup(errstr
), NS_LDAP_MEMORY
);
2678 (void) ldap_unbind(ld
);
2679 return (NS_LDAP_INTERNAL
);
2682 if (binder
!= NULL
) {
2683 return (*binder
)(auth
,
2687 fail_if_new_pwd_reqd
,
2691 return (NS_LDAP_SUCCESS
);