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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
28 #define __STANDALONE_MODULE__
31 #include <sys/types.h>
45 #include <arpa/inet.h>
52 #include <nss_dbdefs.h>
55 #include "ns_cache_door.h"
56 #include "ns_internal.h"
57 #include "ns_connmgmt.h"
60 INFO_SERVER_JUST_INITED
= -1,
61 INFO_SERVER_UNKNOWN
= 0,
62 INFO_SERVER_CONNECTING
= 1,
64 INFO_SERVER_ERROR
= 3,
65 INFO_SERVER_REMOVED
= 4
66 } dir_server_status_t
;
73 typedef struct dir_server
{
77 dir_server_status_t status
;
79 dir_server_info_t info
;
82 typedef struct dir_server_list
{
83 dir_server_t
**nsServers
;
85 rwlock_t listDestroyLock
;
89 /* The local list of the directory servers' root DSEs. */
90 dir_server_list_t
*list
;
91 /* The flag indicating if libsldap is in the 'Standalone' mode. */
94 * The mutex ensuring that only one thread performs
95 * the initialization of the list.
97 mutex_t listReplaceLock
;
99 * A flag indicating that a particular thread is
100 * in the 'ldap_cachemgr' mode. It is stored by thread as
101 * a thread specific data.
105 * A thread specific key storing
106 * the the 'ldap_cachemgr' mode indicator.
108 thread_key_t standaloneInitKey
;
109 } dir_servers
= {NULL
, 0, DEFAULTMUTEX
, '1'};
111 typedef struct switchDatabase
{
116 static thread_key_t switchConfigKey
;
118 #pragma init(createStandaloneKey)
120 #define DONT_INCLUDE_ATTR_NAMES 0
121 #define INCLUDE_ATTR_NAMES 1
123 #define NOT_PROFILE 0
124 /* INET6_ADDRSTRLEN + ":" + <5-digit port> + some round-up */
125 #define MAX_HOSTADDR_LEN (INET6_ADDRSTRLEN + 6 + 12)
129 switch_conf_disposer(void *data
)
131 switch_database_t
*localData
= (switch_database_t
*)data
;
133 free(localData
->conf
);
138 * This function initializes an indication that a thread obtaining a root DSE
139 * will be switched to the 'ldap_cachemgr' mode. Within the thread libsldap
140 * will not invoke the __s_api_requestServer function. Instead, the library
141 * will establish a connection to the server specified by
142 * the __ns_ldap_getRootDSE function.
143 * Since ldap_cachmgr can obtain a DUAProfile and root DSEs at the same time
144 * and we do not want to affect a thread obtaining a DUAProfile,
145 * the 'ldap_cachemgr' mode is thread private.
146 * In addition, this function creates a key holding temporary configuration
147 * for the "hosts" and "ipnodes" databases which is used by the "SKIPDB"
148 * mechanism (__s_api_ip2hostname() & _s_api_hostname2ip()).
152 createStandaloneKey()
154 if (thr_keycreate(&dir_servers
.standaloneInitKey
, NULL
) != 0) {
155 syslog(LOG_ERR
, gettext("libsldap: unable to create a thread "
156 "key needed for sharing ldap connections"));
158 if (thr_keycreate(&switchConfigKey
, switch_conf_disposer
) != 0) {
159 syslog(LOG_ERR
, gettext("libsldap: unable to create a thread "
160 "key containing current nsswitch configuration"));
165 * This function sets the 'ldap_cachemgr' mode indication.
168 __s_api_setInitMode()
170 (void) thr_setspecific(dir_servers
.standaloneInitKey
,
171 (void *) &dir_servers
.initFlag
);
175 * This function unset the 'ldap_cachemgr' mode indication.
178 __s_api_unsetInitMode()
180 (void) thr_setspecific(dir_servers
.standaloneInitKey
, NULL
);
184 * This function checks if the 'ldap_cachemgr' mode indication is set.
187 __s_api_isInitializing() {
190 (void) thr_getspecific(dir_servers
.standaloneInitKey
, (void **) &flag
);
192 return (flag
!= NULL
&& *flag
== dir_servers
.initFlag
);
196 * This function checks if the process runs in the 'Standalone' mode.
197 * In this mode libsldap will check the local, process private list of root DSEs
198 * instead of requesting them via a door call to ldap_cachemgr.
201 __s_api_isStandalone()
205 (void) mutex_lock(&dir_servers
.listReplaceLock
);
206 mode
= dir_servers
.standalone
;
207 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
215 remove_ldap(char *dst
, char *src
, int dst_buf_len
)
219 if (strlen(src
) >= dst_buf_len
)
222 while (*src
!= '\0') {
223 /* Copy up to one space from source. */
226 while (isspace(*src
))
230 /* If not "ldap", just copy. */
231 if (strncmp(src
, "ldap", 4) != 0) {
232 while (!isspace(*src
)) {
234 /* At the end of string? */
235 if (dst
[i
-1] == '\0')
238 /* Copy up to one space from source. */
241 while (isspace(*src
))
244 /* Copy also the criteria section */
246 while (*src
!= ']') {
248 /* Shouln't happen if format is right */
249 if (dst
[i
-1] == '\0')
254 /* If next part is ldap, skip over it ... */
255 if (strncmp(src
, "ldap", 4) == 0) {
256 if (isspace(*(src
+4)) || *(src
+4) == '\0') {
258 while (isspace(*src
))
261 while (*src
++ != ']') {
263 * See comment above about
272 while (isspace(*src
))
285 get_db(const char *db_name
)
288 switch_database_t
*hostService
= NULL
;
289 FILE *fp
= fopen(__NSW_CONFIG_FILE
, "rF");
290 char *linep
, line
[NSS_BUFSIZ
];
293 syslog(LOG_WARNING
, gettext("libsldap: can not read %s"),
298 while ((linep
= fgets(line
, NSS_BUFSIZ
, fp
)) != NULL
) {
299 while (isspace(*linep
)) {
305 if (strncmp(linep
, db_name
, strlen(db_name
)) != 0) {
308 if ((linep
= strchr(linep
, ':')) != NULL
) {
309 if (linep
[strlen(linep
) - 1] == '\n') {
310 linep
[strlen(linep
) - 1] = '\0';
313 while (isspace(*++linep
))
316 if ((ptr
= strchr(linep
, '#')) != NULL
) {
317 while (--ptr
>= linep
&& isspace(*ptr
))
322 if (strlen(linep
) == 0) {
333 gettext("libsldap: the %s database "
334 "is missing from %s"),
340 (void) thr_getspecific(switchConfigKey
, (void **) &hostService
);
341 if (hostService
== NULL
) {
342 hostService
= calloc(1, sizeof (switch_database_t
));
343 if (hostService
== NULL
) {
346 (void) thr_setspecific(switchConfigKey
, hostService
);
350 * In a long-living process threads can perform several
351 * getXbyY requests. And the windows between those requests
352 * can be long. The nsswitch configuration can change from time
353 * to time. So instead of allocating/freeing memory every time
354 * the API is called, reallocate memory only when the current
355 * configuration for the database being used is longer than
358 if (strlen(linep
) >= hostService
->alloced
) {
359 ptr
= (char *)realloc((void *)hostService
->conf
,
362 free((void *)hostService
->conf
);
363 hostService
->conf
= NULL
;
364 hostService
->alloced
= 0;
367 bzero(ptr
, strlen(linep
) + 1);
368 hostService
->conf
= ptr
;
369 hostService
->alloced
= strlen(linep
) + 1;
372 if (remove_ldap(hostService
->conf
, linep
, hostService
->alloced
))
373 return (hostService
->conf
);
380 _initf_ipnodes(nss_db_params_t
*p
)
382 char *services
= get_db("ipnodes");
384 p
->name
= NSS_DBNAM_IPNODES
;
385 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
386 p
->default_config
= services
== NULL
? "" : services
;
391 _initf_hosts(nss_db_params_t
*p
)
393 char *services
= get_db("hosts");
395 p
->name
= NSS_DBNAM_HOSTS
;
396 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
397 p
->default_config
= services
== NULL
? "" : services
;
401 * This function is an analog of the standard gethostbyaddr_r()
402 * function with an exception that it removes the 'ldap' back-end
403 * (if any) from the host/ipnodes nsswitch's databases and then
404 * looks up using remaining back-ends.
408 _filter_gethostbyaddr_r(const char *addr
, int len
, int type
,
409 struct hostent
*result
, char *buffer
, int buflen
,
412 DEFINE_NSS_DB_ROOT(db_root_hosts
);
413 DEFINE_NSS_DB_ROOT(db_root_ipnodes
);
418 nss_db_root_t
*nss_db_root
;
423 str2ent
= str2hostent
;
424 nss_initf
= _initf_hosts
;
425 nss_db_root
= &db_root_hosts
;
426 dbop
= NSS_DBOP_HOSTS_BYADDR
;
429 str2ent
= str2hostent6
;
430 nss_initf
= _initf_ipnodes
;
431 nss_db_root
= &db_root_ipnodes
;
432 dbop
= NSS_DBOP_IPNODES_BYADDR
;
437 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2ent
);
439 arg
.key
.hostaddr
.addr
= addr
;
440 arg
.key
.hostaddr
.len
= len
;
441 arg
.key
.hostaddr
.type
= type
;
443 arg
.h_errno
= NETDB_SUCCESS
;
445 res
= nss_search(nss_db_root
, nss_initf
, dbop
, &arg
);
447 *h_errnop
= arg
.h_errno
;
448 return (struct hostent
*)NSS_XbyY_FINI(&arg
);
452 * This routine is an analog of gethostbyaddr_r().
453 * But in addition __s_api_hostname2ip() performs the "LDAP SKIPDB" activity
454 * prior to querying the name services.
455 * If the buffer is not big enough to accommodate a returning data,
456 * NULL is returned and h_errnop is set to TRY_AGAIN.
459 __s_api_hostname2ip(const char *name
,
460 struct hostent
*result
, char *buffer
, int buflen
,
463 DEFINE_NSS_DB_ROOT(db_root_ipnodes
);
464 DEFINE_NSS_DB_ROOT(db_root_hosts
);
468 struct in6_addr addr6
;
470 if (inet_pton(AF_INET
, name
, &addr
) > 0) {
471 if (buflen
< strlen(name
) + 1 +
472 sizeof (char *) * 2 + /* The h_aliases member */
473 sizeof (struct in_addr
) +
474 sizeof (struct in_addr
*) * 2) {
475 *h_errnop
= TRY_AGAIN
;
479 result
->h_addrtype
= AF_INET
;
480 result
->h_length
= sizeof (struct in_addr
);
481 (void) strncpy(buffer
, name
, buflen
);
483 result
->h_addr_list
= (char **)ROUND_UP(
484 buffer
+ strlen(name
) + 1,
486 result
->h_aliases
= (char **)ROUND_UP(result
->h_addr_list
,
488 result
->h_aliases
[0] = buffer
;
489 result
->h_aliases
[1] = NULL
;
491 buffer
+ buflen
- sizeof (struct in_addr
),
492 sizeof (struct in_addr
));
493 result
->h_addr_list
[0] = buffer
+ buflen
-
494 sizeof (struct in_addr
);
495 result
->h_addr_list
[1] = NULL
;
496 result
->h_aliases
= result
->h_addr_list
;
497 result
->h_name
= buffer
;
499 *h_errnop
= NETDB_SUCCESS
;
502 if (inet_pton(AF_INET6
, name
, &addr6
) > 0) {
503 if (buflen
< strlen(name
) + 1 +
504 sizeof (char *) * 2 + /* The h_aliases member */
505 sizeof (struct in6_addr
) +
506 sizeof (struct in6_addr
*) * 2) {
507 *h_errnop
= TRY_AGAIN
;
511 result
->h_addrtype
= AF_INET6
;
512 result
->h_length
= sizeof (struct in6_addr
);
513 (void) strncpy(buffer
, name
, buflen
);
515 result
->h_addr_list
= (char **)ROUND_UP(
516 buffer
+ strlen(name
) + 1,
518 result
->h_aliases
= (char **)ROUND_UP(result
->h_addr_list
,
520 result
->h_aliases
[0] = buffer
;
521 result
->h_aliases
[1] = NULL
;
523 buffer
+ buflen
- sizeof (struct in6_addr
),
524 sizeof (struct in6_addr
));
525 result
->h_addr_list
[0] = buffer
+ buflen
-
526 sizeof (struct in6_addr
);
527 result
->h_addr_list
[1] = NULL
;
528 result
->h_aliases
= result
->h_addr_list
;
529 result
->h_name
= buffer
;
531 *h_errnop
= NETDB_SUCCESS
;
535 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2hostent
);
539 arg
.h_errno
= NETDB_SUCCESS
;
541 res
= nss_search(&db_root_ipnodes
, _initf_ipnodes
,
542 NSS_DBOP_IPNODES_BYNAME
, &arg
);
543 if (res
== NSS_NOTFOUND
|| res
== NSS_UNAVAIL
) {
544 arg
.h_errno
= NETDB_SUCCESS
;
545 res
= nss_search(&db_root_hosts
, _initf_hosts
,
546 NSS_DBOP_HOSTS_BYNAME
, &arg
);
549 *h_errnop
= arg
.h_errno
;
550 return ((struct hostent
*)NSS_XbyY_FINI(&arg
));
554 * Convert an IP to a host name.
557 __s_api_ip2hostname(char *ipaddr
, char **hostname
) {
560 struct hostent
*hp
= NULL
, hostEnt
;
561 char buffer
[NSS_BUFLEN_HOSTS
];
562 int buflen
= NSS_BUFLEN_HOSTS
;
571 if (ipaddr
== NULL
|| hostname
== NULL
)
572 return (NS_LDAP_INVALID_PARAM
);
574 if ((addr
= strdup(ipaddr
)) == NULL
)
575 return (NS_LDAP_MEMORY
);
577 if (addr
[0] == '[') {
579 * Assume it's [ipv6]:port
583 if ((end
= strchr(addr
, ']')) != NULL
) {
586 if (*(end
+ 1) == ':')
591 return (NS_LDAP_INVALID_PARAM
);
593 } else if ((end
= strchr(addr
, ':')) != NULL
) {
594 /* assume it's ipv4:port */
604 if (inet_pton(AF_INET
, start
, &in
) == 1) {
606 hp
= _filter_gethostbyaddr_r((char *)&in
,
613 if (hp
&& hp
->h_name
) {
614 /* hostname + '\0' */
615 len
= strlen(hp
->h_name
) + 1;
618 len
+= strlen(port
) + 1;
619 if ((*hostname
= malloc(len
)) == NULL
) {
621 return (NS_LDAP_MEMORY
);
625 (void) snprintf(*hostname
, len
, "%s:%s",
628 (void) strlcpy(*hostname
, hp
->h_name
, len
);
631 return (NS_LDAP_SUCCESS
);
634 return (NS_LDAP_NOTFOUND
);
636 } else if (inet_pton(AF_INET6
, start
, &in6
) == 1) {
638 hp
= _filter_gethostbyaddr_r((char *)&in6
,
639 sizeof (in6
.s6_addr
),
645 if (hp
&& hp
->h_name
) {
646 /* hostname + '\0' */
647 len
= strlen(hp
->h_name
) + 1;
650 len
+= strlen(port
) + 1;
651 if ((*hostname
= malloc(len
)) == NULL
) {
653 return (NS_LDAP_MEMORY
);
657 (void) snprintf(*hostname
, len
, "%s:%s",
660 (void) strlcpy(*hostname
, hp
->h_name
, len
);
663 return (NS_LDAP_SUCCESS
);
666 return (NS_LDAP_NOTFOUND
);
676 return (NS_LDAP_SUCCESS
);
681 * This function obtains data returned by an LDAP search request and puts it
682 * in a string in the ldap_cachmgr(1) door call format.
685 * ld - a pointer to an LDAP structure used for a search operation,
686 * result_msg - a pointer to an LDAPMessage returned by the search,
687 * include_names - if set to INCLUDE_ATTR_NAMES, the output buffer will
688 * contain attribute names.
689 * Otherwise, only values will be return.
692 * a buffer containing server info in the following format:
693 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
694 * Should be free'ed by the caller.
698 convert_to_door_line(LDAP
* ld
,
699 LDAPMessage
*result_msg
,
704 uint32_t total_length
= 0, attr_len
= 0, i
;
708 int seen_objectclass
= 0, rewind
= 0;
711 return (NS_LDAP_INVALID_PARAM
);
715 if ((e
= ldap_first_entry(ld
, result_msg
)) == NULL
) {
716 return (NS_LDAP_NOTFOUND
);
719 /* calculate length of received data */
720 for (a
= ldap_first_attribute(ld
, e
, &ber
);
722 a
= ldap_next_attribute(ld
, e
, ber
)) {
724 if ((vals
= ldap_get_values(ld
, e
, a
)) != NULL
) {
725 for (i
= 0; vals
[i
] != NULL
; i
++) {
726 total_length
+= (include_names
?
729 strlen(DOORLINESEP
) +1;
731 ldap_value_free(vals
);
739 if (total_length
== 0) {
740 return (NS_LDAP_NOTFOUND
);
744 /* add 1 for the last '\0' */
745 *door_line
= (char *)malloc(total_length
+ 1);
746 if (*door_line
== NULL
) {
747 return (NS_LDAP_MEMORY
);
750 /* make it an empty string first */
752 a
= ldap_first_attribute(ld
, e
, &ber
);
756 * If we're processing DUAConfigProfile, we need to make
757 * sure we put objectclass attribute first.
758 * __s_api_create_config_door_str depends on that.
760 if (seen_objectclass
) {
761 if (strcasecmp(a
, "objectclass") == 0) {
762 /* Skip objectclass now. */
763 a
= ldap_next_attribute(ld
, e
, ber
);
767 if (strcasecmp(a
, "objectclass") == 0) {
768 seen_objectclass
= 1;
771 /* Skip all but objectclass first. */
772 a
= ldap_next_attribute(ld
, e
, ber
);
778 if ((vals
= ldap_get_values(ld
, e
, a
)) != NULL
) {
779 for (i
= 0; vals
[i
] != NULL
; i
++) {
781 attr_len
+= strlen(a
);
783 attr_len
+= strlen(vals
[i
]) +
784 strlen(DOORLINESEP
) + 2;
786 (void) snprintf(*door_line
+
793 (void) snprintf(*door_line
+
801 ldap_value_free(vals
);
810 a
= ldap_first_attribute(ld
, e
, &ber
);
813 a
= ldap_next_attribute(ld
, e
, ber
);
820 if (e
!= result_msg
) {
821 (void) ldap_msgfree(e
);
824 return (NS_LDAP_SUCCESS
);
828 * This function looks up the base DN of a directory serving
829 * a specified domain name.
832 * ld - a pointer to an LDAP structure used for the search operation,
833 * domain_name - the name of a domain.
836 * a buffer containing a directory's base DN found.
837 * Should be free'ed by the caller.
841 getDirBaseDN(LDAP
*ld
, const char *domain_name
, char **dir_base_dn
)
843 struct timeval tv
= {NS_DEFAULT_SEARCH_TIMEOUT
, 0};
844 char *attrs
[2], *DNlist
, *rest
, *ptr
;
845 char filter
[BUFSIZ
], *a
= NULL
;
847 LDAPMessage
*resultMsg
= NULL
;
848 ns_ldap_return_code ret_code
;
850 /* Get the whole list of naming contexts residing on the server */
851 attrs
[0] = "namingcontexts";
853 ldap_rc
= ldap_search_ext_s(ld
, "", LDAP_SCOPE_BASE
, "(objectclass=*)",
854 attrs
, 0, NULL
, NULL
, &tv
, 0, &resultMsg
);
856 /* If successful, the root DSE was found. */
860 * If the root DSE was not found, the server does
861 * not comply with the LDAP v3 protocol.
865 (void) ldap_msgfree(resultMsg
);
869 return (NS_LDAP_OP_FAILED
);
872 if ((ret_code
= convert_to_door_line(ld
,
874 DONT_INCLUDE_ATTR_NAMES
,
876 &DNlist
)) != NS_LDAP_SUCCESS
) {
878 (void) ldap_msgfree(resultMsg
);
885 (void) ldap_msgfree(resultMsg
);
889 if (DNlist
== NULL
||
890 (ptr
= strtok_r(DNlist
, DOORLINESEP
, &rest
)) == NULL
) {
891 return (NS_LDAP_NOTFOUND
);
896 * For each context try to find a NIS domain object
897 * which 'nisdomain' attribute's value matches the domain name
899 (void) snprintf(filter
,
901 "(&(objectclass=nisDomainObject)"
904 ldap_rc
= ldap_search_ext_s(ld
,
915 if (ldap_rc
!= LDAP_SUCCESS
) {
917 (void) ldap_msgfree(resultMsg
);
922 if ((a
= ldap_get_dn(ld
, resultMsg
)) != NULL
) {
923 *dir_base_dn
= strdup(a
);
927 (void) ldap_msgfree(resultMsg
);
933 return (NS_LDAP_MEMORY
);
939 (void) ldap_msgfree(resultMsg
);
942 } while (ptr
= strtok_r(NULL
, DOORLINESEP
, &rest
));
947 return (NS_LDAP_NOTFOUND
);
950 return (NS_LDAP_SUCCESS
);
954 * This function parses the results of a search operation
955 * requesting a DUAProfile.
958 * ld - a pointer to an LDAP structure used for the search operation,
959 * dir_base_dn - the name of a directory's base DN,
960 * profile_name - the name of a DUAProfile to be obtained.
963 * a buffer containing the DUAProfile in the following format:
964 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
965 * Should be free'ed by the caller.
969 getDUAProfile(LDAP
*ld
,
970 const char *dir_base_dn
,
971 const char *profile_name
,
974 char searchBaseDN
[BUFSIZ
], filter
[BUFSIZ
];
975 LDAPMessage
*resultMsg
= NULL
;
976 struct timeval tv
= {NS_DEFAULT_SEARCH_TIMEOUT
, 0};
978 ns_ldap_return_code ret_code
;
980 (void) snprintf(searchBaseDN
, BUFSIZ
, "ou=profile,%s", dir_base_dn
);
981 (void) snprintf(filter
,
984 _PROFILE1_OBJECTCLASS
,
985 _PROFILE2_OBJECTCLASS
,
987 ldap_rc
= ldap_search_ext_s(ld
,
1000 /* If successful, the DUA profile was found. */
1004 * If the root DSE was not found, the server does
1005 * not comply with the LDAP v3 protocol.
1009 (void) ldap_msgfree(resultMsg
);
1013 return (NS_LDAP_OP_FAILED
);
1016 ret_code
= convert_to_door_line(ld
,
1022 (void) ldap_msgfree(resultMsg
);
1029 * This function derives the directory's base DN from a provided domain name.
1032 * domain_name - the name of a domain to be converted into a base DN,
1033 * buffer - contains the derived base DN,
1034 * buf_len - the length of the buffer.
1037 * The function returns the address of the buffer or NULL.
1041 domainname2baseDN(char *domain_name
, char *buffer
, uint16_t buf_len
)
1046 if (!domain_name
|| !buffer
|| buf_len
== 0) {
1051 nextDC
= chr
= domain_name
;
1052 length
= strlen(domain_name
);
1053 for (i
= 0; i
< length
+ 1; ++i
, ++chr
) {
1054 /* Simply replace dots with "dc=" */
1055 if (*chr
!= '.' && *chr
!= '\0') {
1059 if (strlcat(buffer
, "dc=", buf_len
) >= buf_len
)
1061 if (strlcat(buffer
, nextDC
, buf_len
) >= buf_len
)
1065 * The end of the domain name
1066 * has not been reached yet
1068 if (strlcat(buffer
, ",", buf_len
) >= buf_len
)
1079 * This function obtains the directory's base DN and a DUAProfile
1080 * from a specified server.
1083 * server - a structure describing a server to connect to and
1084 * a DUAProfile to be obtained from the server,
1085 * cred - credentials to be used during establishing connections to
1089 * dua_profile - a buffer containing the DUAProfile in the following format:
1090 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1091 * dir_base_dn - a buffer containing the base DN,
1092 * errorp - an error object describing an error, if any.
1094 * All the output data structures should be free'ed by the caller.
1097 __ns_ldap_getConnectionInfoFromDUA(const ns_dir_server_t
*server
,
1098 const ns_cred_t
*cred
,
1101 ns_ldap_error_t
**errorp
)
1103 char serverAddr
[MAX_HOSTADDR_LEN
];
1104 char *dirBaseDN
= NULL
, *duaProfile
= NULL
;
1105 ns_cred_t default_cred
;
1106 ns_ldap_return_code ret_code
;
1108 ns_config_t
*config_struct
= __s_api_create_config();
1109 ConnectionID sessionId
= 0;
1110 Connection
*session
= NULL
;
1111 char errmsg
[MAXERROR
];
1112 char buffer
[NSS_BUFLEN_HOSTS
];
1113 ns_conn_user_t
*cu
= NULL
;
1115 if (errorp
== NULL
) {
1116 __s_api_destroy_config(config_struct
);
1117 return (NS_LDAP_INVALID_PARAM
);
1122 if (server
== NULL
) {
1123 __s_api_destroy_config(config_struct
);
1124 return (NS_LDAP_INVALID_PARAM
);
1127 if (config_struct
== NULL
) {
1128 return (NS_LDAP_MEMORY
);
1132 * If no credentials are specified, try to establish a connection
1136 default_cred
.cred
.unix_cred
.passwd
= NULL
;
1137 default_cred
.cred
.unix_cred
.userID
= NULL
;
1138 default_cred
.auth
.type
= NS_LDAP_AUTH_NONE
;
1141 /* Now create a default LDAP configuration */
1143 (void) strncpy(buffer
, server
->server
, sizeof (buffer
));
1144 if (__ns_ldap_setParamValue(config_struct
, NS_LDAP_SERVERS_P
, buffer
,
1145 errorp
) != NS_LDAP_SUCCESS
) {
1146 __s_api_destroy_config(config_struct
);
1147 return (NS_LDAP_CONFIG
);
1150 /* Put together the address and the port specified by the user app. */
1151 if (server
->port
> 0) {
1152 (void) snprintf(serverAddr
,
1153 sizeof (serverAddr
),
1158 (void) strncpy(serverAddr
, buffer
, sizeof (serverAddr
));
1162 * There is no default value for the 'Default Search Base DN' attribute.
1163 * Derive one from the domain name to make __s_api_crosscheck() happy.
1165 if (domainname2baseDN(server
->domainName
?
1166 server
->domainName
: config_struct
->domainName
,
1167 buffer
, NSS_BUFLEN_HOSTS
) == NULL
) {
1168 (void) snprintf(errmsg
,
1170 gettext("Can not convert %s into a base DN name"),
1171 server
->domainName
?
1172 server
->domainName
: config_struct
->domainName
);
1178 __s_api_destroy_config(config_struct
);
1179 return (NS_LDAP_INTERNAL
);
1181 if (__ns_ldap_setParamValue(config_struct
, NS_LDAP_SEARCH_BASEDN_P
,
1182 buffer
, errorp
) != NS_LDAP_SUCCESS
) {
1183 __s_api_destroy_config(config_struct
);
1184 return (NS_LDAP_CONFIG
);
1187 if (__s_api_crosscheck(config_struct
, errmsg
, B_FALSE
) != NS_SUCCESS
) {
1188 __s_api_destroy_config(config_struct
);
1189 return (NS_LDAP_CONFIG
);
1192 __s_api_init_config(config_struct
);
1194 __s_api_setInitMode();
1196 cu
= __s_api_conn_user_init(NS_CONN_USER_SEARCH
, NULL
, B_FALSE
);
1198 return (NS_LDAP_INTERNAL
);
1201 if ((ret_code
= __s_api_getConnection(serverAddr
,
1203 cred
? cred
: &default_cred
,
1209 cu
)) != NS_LDAP_SUCCESS
) {
1210 __s_api_conn_user_free(cu
);
1211 __s_api_unsetInitMode();
1215 __s_api_unsetInitMode();
1217 if ((ret_code
= getDirBaseDN(session
->ld
,
1218 server
->domainName
?
1219 server
->domainName
:
1220 config_struct
->domainName
,
1221 &dirBaseDN
)) != NS_LDAP_SUCCESS
) {
1222 (void) snprintf(errmsg
,
1224 gettext("Can not find the "
1225 "nisDomainObject for domain %s\n"),
1226 server
->domainName
?
1227 server
->domainName
: config_struct
->domainName
);
1233 __s_api_conn_user_free(cu
);
1234 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1239 * And here obtain a DUAProfile which will be used
1240 * as a real configuration.
1242 if ((ret_code
= getDUAProfile(session
->ld
,
1244 server
->profileName
?
1245 server
->profileName
: "default",
1246 &duaProfile
)) != NS_LDAP_SUCCESS
) {
1247 (void) snprintf(errmsg
,
1249 gettext("Can not find the "
1251 server
->profileName
?
1252 server
->profileName
: "default");
1258 __s_api_conn_user_free(cu
);
1259 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1264 *dir_base_dn
= dirBaseDN
;
1270 *dua_profile
= duaProfile
;
1275 __s_api_conn_user_free(cu
);
1276 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1278 return (NS_LDAP_SUCCESS
);
1282 * This function obtains the root DSE from a specified server.
1285 * server_addr - an adress of a server to be connected to.
1288 * root_dse - a buffer containing the root DSE in the following format:
1289 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1290 * For example: ( here | used as DOORLINESEP for visual purposes)
1291 * supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL
1292 * Should be free'ed by the caller.
1295 __ns_ldap_getRootDSE(const char *server_addr
,
1297 ns_ldap_error_t
**errorp
,
1300 char errmsg
[MAXERROR
];
1301 ns_ldap_return_code ret_code
;
1303 ConnectionID sessionId
= 0;
1304 Connection
*session
= NULL
;
1306 struct timeval tv
= {NS_DEFAULT_SEARCH_TIMEOUT
, 0};
1308 int ldap_rc
, ldaperrno
= 0;
1309 LDAPMessage
*resultMsg
= NULL
;
1310 void **paramVal
= NULL
;
1313 ns_conn_user_t
*cu
= NULL
;
1315 if (errorp
== NULL
) {
1316 return (NS_LDAP_INVALID_PARAM
);
1322 return (NS_LDAP_INVALID_PARAM
);
1326 return (NS_LDAP_INVALID_PARAM
);
1329 __s_api_setInitMode();
1331 cu
= __s_api_conn_user_init(NS_CONN_USER_SEARCH
, NULL
, B_FALSE
);
1333 return (NS_LDAP_INTERNAL
);
1337 * All the credentials will be taken from the current
1338 * libsldap configuration.
1340 if ((ret_code
= __s_api_getConnection(server_addr
,
1348 cu
)) != NS_LDAP_SUCCESS
) {
1349 /* Fallback to anonymous mode is disabled. Stop. */
1350 if (anon_fallback
== 0) {
1352 gettext("libsldap: can not get the root DSE from "
1353 " the %s server: %s. "
1354 "Falling back to anonymous disabled.\n"),
1356 errorp
&& *errorp
&& (*errorp
)->message
?
1357 (*errorp
)->message
: "");
1358 if (errorp
!= NULL
&& *errorp
!= NULL
) {
1359 (void) __ns_ldap_freeError(errorp
);
1361 __s_api_unsetInitMode();
1366 * Fallback to anonymous, non-SSL mode for backward
1367 * compatibility reasons. This mode should only be used when
1368 * this function (__ns_ldap_getRootDSE) is called from
1369 * ldap_cachemgr(1M).
1372 gettext("libsldap: Falling back to anonymous, non-SSL"
1373 " mode for __ns_ldap_getRootDSE. %s\n"),
1374 errorp
&& *errorp
&& (*errorp
)->message
?
1375 (*errorp
)->message
: "");
1377 /* Setup the anon credential for anonymous connection. */
1378 (void) memset(&anon
, 0, sizeof (ns_cred_t
));
1379 anon
.auth
.type
= NS_LDAP_AUTH_NONE
;
1381 if (*errorp
!= NULL
) {
1382 (void) __ns_ldap_freeError(errorp
);
1386 ret_code
= __s_api_getConnection(server_addr
,
1396 if (ret_code
!= NS_LDAP_SUCCESS
) {
1397 __s_api_conn_user_free(cu
);
1398 __s_api_unsetInitMode();
1403 __s_api_unsetInitMode();
1405 /* get search timeout value */
1406 (void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P
, ¶mVal
, errorp
);
1407 if (paramVal
!= NULL
&& *paramVal
!= NULL
) {
1408 tv
.tv_sec
= **((int **)paramVal
);
1409 (void) __ns_ldap_freeParam(¶mVal
);
1411 if (*errorp
!= NULL
) {
1412 (void) __ns_ldap_freeError(errorp
);
1415 /* Get root DSE from the server specified by the caller. */
1416 attrs
[0] = "supportedControl";
1417 attrs
[1] = "supportedsaslmechanisms";
1419 ldap_rc
= ldap_search_ext_s(session
->ld
,
1431 if (ldap_rc
!= LDAP_SUCCESS
) {
1433 * If the root DSE was not found, the server does
1434 * not comply with the LDAP v3 protocol.
1436 (void) ldap_get_option(session
->ld
,
1437 LDAP_OPT_ERROR_NUMBER
,
1439 (void) snprintf(errmsg
,
1441 gettext(ldap_err2string(ldaperrno
)));
1449 (void) ldap_msgfree(resultMsg
);
1453 __s_api_conn_user_free(cu
);
1454 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1455 return (NS_LDAP_OP_FAILED
);
1457 __s_api_conn_user_free(cu
);
1459 ret_code
= convert_to_door_line(session
->ld
,
1464 if (ret_code
== NS_LDAP_NOTFOUND
) {
1465 (void) snprintf(errmsg
,
1467 gettext("No root DSE data "
1468 "for server %s returned."),
1478 (void) ldap_msgfree(resultMsg
);
1482 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1488 * This function destroys the local list of root DSEs. The input parameter is
1489 * a pointer to the list to be erased.
1490 * The type of the pointer passed to this function should be
1491 * (dir_server_list_t *).
1495 disposeOfOldList(void *param
)
1497 dir_server_list_t
*old_list
= (dir_server_list_t
*)param
;
1500 (void) rw_wrlock(&old_list
->listDestroyLock
);
1501 /* Destroy the old list */
1502 while (old_list
->nsServers
[i
]) {
1503 free(old_list
->nsServers
[i
]->ip
);
1505 while (old_list
->nsServers
[i
]->controls
&&
1506 old_list
->nsServers
[i
]->controls
[j
]) {
1507 free(old_list
->nsServers
[i
]->controls
[j
]);
1510 free(old_list
->nsServers
[i
]->controls
);
1512 while (old_list
->nsServers
[i
]->saslMech
&&
1513 old_list
->nsServers
[i
]->saslMech
[j
]) {
1514 free(old_list
->nsServers
[i
]->saslMech
[j
]);
1517 free(old_list
->nsServers
[i
]->saslMech
);
1521 * All the structures pointed by old_list->nsServers were allocated
1522 * in one chunck. The nsServers[0] pointer points to the beginning
1525 free(old_list
->nsServers
[0]);
1526 free(old_list
->nsServers
);
1527 (void) rw_unlock(&old_list
->listDestroyLock
);
1528 (void) rwlock_destroy(&old_list
->listDestroyLock
);
1535 * This function cancels the Standalone mode and destroys the list of root DSEs.
1538 __ns_ldap_cancelStandalone(void)
1540 dir_server_list_t
*old_list
;
1542 (void) mutex_lock(&dir_servers
.listReplaceLock
);
1543 dir_servers
.standalone
= 0;
1544 if (!dir_servers
.list
) {
1545 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
1548 old_list
= dir_servers
.list
;
1549 dir_servers
.list
= NULL
;
1550 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
1552 (void) disposeOfOldList(old_list
);
1558 create_ns_servers_entry(void *param
)
1560 #define CHUNK_SIZE 16
1562 dir_server_t
*server
= (dir_server_t
*)param
;
1563 ns_ldap_return_code
*retCode
= calloc(1,
1564 sizeof (ns_ldap_return_code
));
1565 uint32_t sc_counter
= 0, sm_counter
= 0;
1566 uint32_t sc_mem_blocks
= 1, sm_mem_blocks
= 1;
1567 char *rootDSE
= NULL
, *attr
, *val
, *rest
, **ptr
;
1568 ns_ldap_error_t
*error
= NULL
;
1570 if (retCode
== NULL
) {
1575 * We call this function in non anon-fallback mode because we
1576 * want the whole procedure to fail as soon as possible to
1577 * indicate there are problems with connecting to the server.
1579 *retCode
= __ns_ldap_getRootDSE(server
->ip
,
1584 if (*retCode
== NS_LDAP_MEMORY
) {
1590 * If the root DSE can not be obtained, log an error and keep the
1593 if (*retCode
!= NS_LDAP_SUCCESS
) {
1594 server
->status
= INFO_SERVER_ERROR
;
1596 gettext("libsldap (\"standalone\" mode): "
1597 "can not obtain the root DSE from %s. %s"),
1599 error
&& error
->message
? error
->message
: "");
1601 (void) __ns_ldap_freeError(&error
);
1606 /* Get the first attribute of the root DSE. */
1607 attr
= strtok_r(rootDSE
, DOORLINESEP
, &rest
);
1610 server
->status
= INFO_SERVER_ERROR
;
1612 gettext("libsldap (\"standalone\" mode): "
1613 "the root DSE from %s is empty or corrupted."),
1615 *retCode
= NS_LDAP_INTERNAL
;
1619 server
->controls
= (char **)calloc(CHUNK_SIZE
, sizeof (char *));
1620 server
->saslMech
= (char **)calloc(CHUNK_SIZE
, sizeof (char *));
1621 if (server
->controls
== NULL
|| server
->saslMech
== NULL
) {
1628 if ((val
= strchr(attr
, '=')) == NULL
) {
1633 if (strncasecmp(attr
,
1635 _SASLMECHANISM_LEN
) == 0) {
1636 if (sm_counter
== CHUNK_SIZE
* sm_mem_blocks
- 1) {
1637 ptr
= (char **)realloc(server
->saslMech
,
1642 *retCode
= NS_LDAP_MEMORY
;
1653 server
->saslMech
= ptr
;
1655 server
->saslMech
[sm_counter
] = strdup(val
);
1656 if (server
->saslMech
[sm_counter
] == NULL
) {
1657 *retCode
= NS_LDAP_MEMORY
;
1663 if (strncasecmp(attr
,
1665 _SUPPORTEDCONTROL_LEN
) == 0) {
1666 if (sc_counter
== CHUNK_SIZE
* sc_mem_blocks
- 1) {
1667 ptr
= (char **)realloc(server
->controls
,
1672 *retCode
= NS_LDAP_MEMORY
;
1683 server
->controls
= ptr
;
1686 server
->controls
[sc_counter
] = strdup(val
);
1687 if (server
->controls
[sc_counter
] == NULL
) {
1688 *retCode
= NS_LDAP_MEMORY
;
1695 } while (attr
= strtok_r(NULL
, DOORLINESEP
, &rest
));
1699 if (*retCode
== NS_LDAP_MEMORY
) {
1704 server
->controls
[sc_counter
] = NULL
;
1705 server
->saslMech
[sm_counter
] = NULL
;
1707 server
->status
= INFO_SERVER_UP
;
1715 * This function creates a new local list of root DSEs from all the servers
1716 * mentioned in the DUAProfile (or local NS BEC) and returns
1717 * a pointer to the list.
1721 createDirServerList(dir_server_list_t
**new_list
,
1722 ns_ldap_error_t
**errorp
)
1725 ns_ldap_return_code retCode
= NS_LDAP_SUCCESS
;
1726 dir_server_t
*tmpSrvArray
;
1727 long srvListLength
, i
;
1728 thread_t
*thrPool
, thrID
;
1729 void *status
= NULL
;
1731 if (errorp
== NULL
) {
1732 return (NS_LDAP_INVALID_PARAM
);
1737 if (new_list
== NULL
) {
1738 return (NS_LDAP_INVALID_PARAM
);
1741 retCode
= __s_api_getServers(&serverList
, errorp
);
1742 if (retCode
!= NS_LDAP_SUCCESS
|| serverList
== NULL
) {
1746 for (i
= 0; serverList
[i
]; ++i
) {
1751 thrPool
= calloc(srvListLength
, sizeof (thread_t
));
1752 if (thrPool
== NULL
) {
1753 __s_api_free2dArray(serverList
);
1754 return (NS_LDAP_MEMORY
);
1757 *new_list
= (dir_server_list_t
*)calloc(1,
1758 sizeof (dir_server_list_t
));
1759 if (*new_list
== NULL
) {
1760 __s_api_free2dArray(serverList
);
1762 return (NS_LDAP_MEMORY
);
1764 (void) rwlock_init(&(*new_list
)->listDestroyLock
, USYNC_THREAD
, NULL
);
1766 (*new_list
)->nsServers
= (dir_server_t
**)calloc(srvListLength
+ 1,
1767 sizeof (dir_server_t
*));
1768 if ((*new_list
)->nsServers
== NULL
) {
1771 __s_api_free2dArray(serverList
);
1773 return (NS_LDAP_MEMORY
);
1777 * Allocate a set of dir_server_t structures as an array,
1778 * with one alloc call and then initialize the nsServers pointers
1779 * with the addresses of the array's members.
1781 tmpSrvArray
= (dir_server_t
*)calloc(srvListLength
,
1782 sizeof (dir_server_t
));
1783 for (i
= 0; i
< srvListLength
; ++i
) {
1784 (*new_list
)->nsServers
[i
] = &tmpSrvArray
[i
];
1786 (*new_list
)->nsServers
[i
]->info
= INFO_STATUS_NEW
;
1787 (void) mutex_init(&(*new_list
)->nsServers
[i
]->updateStatus
,
1791 (*new_list
)->nsServers
[i
]->ip
= strdup(serverList
[i
]);
1792 if ((*new_list
)->nsServers
[i
]->ip
== NULL
) {
1793 retCode
= NS_LDAP_MEMORY
;
1797 (*new_list
)->nsServers
[i
]->status
= INFO_SERVER_CONNECTING
;
1799 switch (thr_create(NULL
,
1801 create_ns_servers_entry
,
1802 (*new_list
)->nsServers
[i
],
1806 (*new_list
)->nsServers
[i
]->status
=
1810 (*new_list
)->nsServers
[i
]->status
=
1819 for (i
= 0; i
< srvListLength
; ++i
) {
1820 if (thrPool
[i
] != 0 &&
1821 thr_join(thrPool
[i
], NULL
, &status
) == 0) {
1822 if (status
== NULL
) {
1824 * Some memory allocation problems occured. Just
1825 * ignore the server and hope there will be some
1828 (*new_list
)->nsServers
[i
]->status
=
1835 __s_api_free2dArray(serverList
);
1838 if (retCode
== NS_LDAP_MEMORY
) {
1839 (void) disposeOfOldList(*new_list
);
1840 return (NS_LDAP_MEMORY
);
1843 return (NS_LDAP_SUCCESS
);
1847 * This functions replaces the local list of root DSEs with a new one and starts
1848 * a thread destroying the old list. There is no need for other threads to wait
1849 * until the old list will be destroyed.
1850 * Since it is possible that more than one thread can start creating the list,
1851 * this function should be protected by mutexes to be sure that only one thread
1852 * performs the initialization.
1856 initGlobalList(ns_ldap_error_t
**error
)
1858 dir_server_list_t
*new_list
, *old_list
;
1859 ns_ldap_return_code ret_code
;
1862 ret_code
= createDirServerList(&new_list
, error
);
1863 if (ret_code
!= NS_LDAP_SUCCESS
) {
1867 old_list
= dir_servers
.list
;
1868 dir_servers
.list
= new_list
;
1871 (void) thr_create(NULL
,
1879 return (NS_LDAP_SUCCESS
);
1886 } authArray
[] = {{"none", {NS_LDAP_AUTH_NONE
,
1889 NS_LDAP_SASLOPT_NONE
}},
1890 {"simple", {NS_LDAP_AUTH_SIMPLE
,
1893 NS_LDAP_SASLOPT_NONE
}},
1894 {"tls:simple", {NS_LDAP_AUTH_TLS
,
1897 NS_LDAP_SASLOPT_NONE
}},
1898 {"tls:sasl/CRAM-MD5", {NS_LDAP_AUTH_TLS
,
1900 NS_LDAP_SASL_CRAM_MD5
,
1901 NS_LDAP_SASLOPT_NONE
}},
1902 {"tls:sasl/DIGEST-MD5", {NS_LDAP_AUTH_TLS
,
1904 NS_LDAP_SASL_DIGEST_MD5
,
1905 NS_LDAP_SASLOPT_NONE
}},
1906 {"sasl/CRAM-MD5", {NS_LDAP_AUTH_SASL
,
1908 NS_LDAP_SASL_CRAM_MD5
,
1909 NS_LDAP_SASLOPT_NONE
}},
1910 {"sasl/DIGEST-MD5", {NS_LDAP_AUTH_SASL
,
1912 NS_LDAP_SASL_DIGEST_MD5
,
1913 NS_LDAP_SASLOPT_NONE
}},
1914 {"sasl/GSSAPI", {NS_LDAP_AUTH_SASL
,
1916 NS_LDAP_SASL_GSSAPI
,
1917 NS_LDAP_SASLOPT_PRIV
| NS_LDAP_SASLOPT_INT
}},
1918 {NULL
, {NS_LDAP_AUTH_NONE
,
1921 NS_LDAP_SASLOPT_NONE
}}};
1924 __ns_ldap_initAuth(const char *auth_mech
,
1926 ns_ldap_error_t
**errorp
)
1929 char errmsg
[MAXERROR
];
1931 if (auth_mech
== NULL
) {
1932 (void) snprintf(errmsg
,
1934 gettext("Invalid authentication method specified\n"));
1935 MKERROR(LOG_WARNING
,
1940 return (NS_LDAP_INTERNAL
);
1943 for (i
= 0; authArray
[i
].authMech
!= NULL
; ++i
) {
1944 if (strcasecmp(auth_mech
, authArray
[i
].authMech
) == 0) {
1945 *auth
= authArray
[i
].auth
;
1946 return (NS_LDAP_SUCCESS
);
1950 (void) snprintf(errmsg
,
1952 gettext("Invalid authentication method specified\n"));
1953 MKERROR(LOG_WARNING
,
1958 return (NS_LDAP_INTERNAL
);
1962 * This function "informs" libsldap that a client application has specified
1963 * a directory to use. The function obtains a DUAProfile, credentials,
1964 * and naming context. During all further operations on behalf
1965 * of the application requested a standalone schema libsldap will use
1966 * the information obtained by __ns_ldap_initStandalone() instead of
1967 * door_call(3C)ing ldap_cachemgr(1M).
1970 * sa_conf - a structure describing where and in which way to obtain all
1971 * the configuration describing how to communicate to
1972 * a choosen LDAP directory,
1973 * errorp - an error object describing an error occured.
1976 __ns_ldap_initStandalone(const ns_standalone_conf_t
*sa_conf
,
1977 ns_ldap_error_t
**errorp
) {
1979 ns_cred_t user_cred
= {{NS_LDAP_AUTH_NONE
,
1982 NS_LDAP_SASLOPT_NONE
},
1985 char *dua_profile
= NULL
;
1986 char errmsg
[MAXERROR
];
1990 if (sa_conf
->SA_BIND_DN
== NULL
&& sa_conf
->SA_BIND_PWD
!= NULL
||
1991 sa_conf
->SA_BIND_DN
!= NULL
&& sa_conf
->SA_BIND_PWD
== NULL
) {
1992 (void) snprintf(errmsg
,
1994 gettext("Bind DN and bind password"
1995 " must both be provided\n"));
1998 NS_CONFIG_NOTLOADED
,
2001 return (NS_LDAP_INTERNAL
);
2004 switch (sa_conf
->type
) {
2005 case NS_LDAP_SERVER
:
2006 if (sa_conf
->SA_BIND_DN
!= NULL
) {
2007 user_cred
.cred
.unix_cred
.userID
= sa_conf
->SA_BIND_DN
;
2008 user_cred
.auth
.type
= NS_LDAP_AUTH_SIMPLE
;
2011 if (sa_conf
->SA_BIND_PWD
!= NULL
) {
2012 user_cred
.cred
.unix_cred
.passwd
= sa_conf
->SA_BIND_PWD
;
2015 if (sa_conf
->SA_AUTH
!= NULL
) {
2016 user_cred
.auth
.type
= sa_conf
->SA_AUTH
->type
;
2017 user_cred
.auth
.tlstype
= sa_conf
->SA_AUTH
->tlstype
;
2018 user_cred
.auth
.saslmech
= sa_conf
->SA_AUTH
->saslmech
;
2019 user_cred
.auth
.saslopt
= sa_conf
->SA_AUTH
->saslopt
;
2022 if (sa_conf
->SA_CERT_PATH
!= NULL
) {
2023 user_cred
.hostcertpath
= sa_conf
->SA_CERT_PATH
;
2026 ret_code
= __ns_ldap_getConnectionInfoFromDUA(
2027 &sa_conf
->ds_profile
.server
,
2032 if (ret_code
!= NS_LDAP_SUCCESS
) {
2036 cfg
= __s_api_create_config_door_str(dua_profile
, errorp
);
2039 return (NS_LDAP_CONFIG
);
2042 if (sa_conf
->SA_CERT_PATH
!= NULL
) {
2044 ParamIndexType type
;
2046 switch (cfg
->version
) {
2048 certPathAttr
= "NS_LDAP_CERT_PATH";
2050 default: /* Version 2 */
2051 certPathAttr
= "NS_LDAP_HOST_CERTPATH";
2055 if (__s_api_get_versiontype(cfg
,
2058 (ret_code
= __ns_ldap_setParamValue(cfg
,
2060 sa_conf
->SA_CERT_PATH
,
2061 errorp
)) != NS_LDAP_SUCCESS
) {
2062 __s_api_destroy_config(cfg
);
2067 if (sa_conf
->SA_BIND_DN
!= NULL
&&
2068 sa_conf
->SA_BIND_PWD
!= NULL
) {
2071 authMethods
= __s_api_strValue(cfg
, NS_LDAP_AUTH_P
,
2073 if (authMethods
!= NULL
&&
2074 strstr(authMethods
, "sasl/GSSAPI") != NULL
) {
2076 * The received DUAProfile specifies
2077 * sasl/GSSAPI as an auth. mechanism.
2078 * The bind DN and password will be
2081 syslog(LOG_INFO
, gettext("sasl/GSSAPI will be "
2082 "used as an authentication method. "
2083 "The bind DN and password will "
2089 if (authMethods
!= NULL
)
2092 if (__ns_ldap_setParamValue(cfg
,
2094 sa_conf
->SA_BIND_DN
,
2095 errorp
) != NS_LDAP_SUCCESS
) {
2096 __s_api_destroy_config(cfg
);
2097 return (NS_LDAP_CONFIG
);
2100 if (__ns_ldap_setParamValue(cfg
,
2101 NS_LDAP_BINDPASSWD_P
,
2102 sa_conf
->SA_BIND_PWD
,
2103 errorp
) != NS_LDAP_SUCCESS
) {
2104 __s_api_destroy_config(cfg
);
2105 return (NS_LDAP_CONFIG
);
2110 default: /* NS_CACHEMGR */
2111 return (NS_LDAP_SUCCESS
);
2114 __s_api_init_config(cfg
);
2115 /* Connection management should use the new config now. */
2116 __s_api_reinit_conn_mgmt_new_config(cfg
);
2117 __ns_ldap_setServer(TRUE
);
2119 (void) mutex_lock(&dir_servers
.listReplaceLock
);
2120 if ((ret_code
= initGlobalList(errorp
)) != NS_SUCCESS
) {
2121 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2124 dir_servers
.standalone
= 1;
2125 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2127 return (NS_LDAP_SUCCESS
);
2132 * serverAddr is the address of a server and
2133 * request is one of the following:
2134 * NS_CACHE_NEW: get a new server address, addr is ignored.
2135 * NS_CACHE_NORESP: get the next one, remove addr from list.
2136 * NS_CACHE_NEXT: get the next one, keep addr on list.
2137 * NS_CACHE_WRITE: get a non-replica server, if possible, if not, same
2140 * NS_CACHE_ADDR_IP: return server address as is, this is default.
2141 * NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only
2142 * self credential case requires such format.
2146 * a structure of type ns_server_info_t containing the server address
2147 * or name, server controls and supported SASL mechanisms.
2148 * NOTE: Caller should allocate space for the structure and free
2149 * all the space allocated by the function for the information contained
2152 * error - an error object describing an error, if any.
2155 __s_api_findRootDSE(const char *request
,
2156 const char *serverAddr
,
2157 const char *addrType
,
2158 ns_server_info_t
*ret
,
2159 ns_ldap_error_t
**error
)
2161 dir_server_list_t
*current_list
= NULL
;
2162 ns_ldap_return_code ret_code
;
2164 int matched
= FALSE
;
2165 dir_server_t
*server
= NULL
;
2166 char errmsg
[MAXERROR
];
2168 (void) mutex_lock(&dir_servers
.listReplaceLock
);
2169 if (dir_servers
.list
== NULL
) {
2170 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2171 (void) snprintf(errmsg
,
2173 gettext("The list of root DSEs is empty: "
2174 "the Standalone mode was not properly initialized"));
2177 NS_CONFIG_NOTLOADED
,
2180 return (NS_LDAP_INTERNAL
);
2183 current_list
= dir_servers
.list
;
2184 (void) rw_rdlock(¤t_list
->listDestroyLock
);
2185 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2188 * The code below is mostly the clone of the
2189 * ldap_cachemgr::cachemgr_getldap.c::getldap_get_serverInfo() function.
2190 * Currently we have two different server lists: one is maintained
2191 * by libsldap ('standalone' mode), the other is in ldap_cachemgr
2192 * (a part of its standard functionality).
2196 * If NS_CACHE_NEW, or the server info is new,
2197 * starts from the beginning of the list.
2199 (void) mutex_lock(¤t_list
->nsServers
[0]->updateStatus
);
2200 if (strcmp(request
, NS_CACHE_NEW
) == 0 ||
2201 current_list
->nsServers
[0]->info
== INFO_STATUS_NEW
) {
2204 (void) mutex_unlock(¤t_list
->nsServers
[i
]->updateStatus
);
2206 for (i
= 0; current_list
->nsServers
[i
]; ++i
) {
2208 * Lock the updateStatus mutex to
2209 * make sure the server status stays the same
2210 * while the data is being processed.
2212 if (matched
== FALSE
&&
2213 strcmp(current_list
->nsServers
[i
]->ip
,
2216 if (strcmp(request
, NS_CACHE_NORESP
) == 0) {
2219 * if the server has already been removed,
2222 (void) mutex_lock(¤t_list
->
2223 nsServers
[i
]->updateStatus
);
2224 if (current_list
->nsServers
[i
]->status
==
2225 INFO_SERVER_REMOVED
) {
2226 (void) mutex_unlock(¤t_list
->
2231 (void) mutex_unlock(¤t_list
->
2236 * if the information is new,
2237 * give this server one more chance.
2239 (void) mutex_lock(¤t_list
->
2242 if (current_list
->nsServers
[i
]->info
==
2244 current_list
->nsServers
[i
]->status
==
2246 server
= current_list
->nsServers
[i
];
2247 (void) mutex_unlock(¤t_list
->
2253 * it is recommended that
2254 * before removing the
2255 * server from the list,
2256 * the server should be
2257 * contacted one more time
2258 * to make sure that it is
2259 * really unavailable.
2260 * For now, just trust the client
2261 * (i.e., the sldap library)
2262 * that it knows what it is
2263 * doing and would not try
2264 * to mess up the server
2267 current_list
->nsServers
[i
]->status
=
2268 INFO_SERVER_REMOVED
;
2269 (void) mutex_unlock(¤t_list
->
2276 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
2283 if (strcmp(request
, NS_CACHE_WRITE
) == 0) {
2285 * ldap_cachemgr checks here if the server
2286 * is not a non-replica server (a server
2287 * of type INFO_RW_WRITEABLE). But currently
2288 * it considers all the servers in its list
2291 (void) mutex_lock(¤t_list
->
2294 if (current_list
->nsServers
[i
]->status
==
2296 (void) mutex_unlock(¤t_list
->
2299 server
= current_list
->nsServers
[i
];
2303 (void) mutex_lock(¤t_list
->
2306 if (current_list
->nsServers
[i
]->status
==
2308 (void) mutex_unlock(¤t_list
->
2311 server
= current_list
->nsServers
[i
];
2316 (void) mutex_unlock(¤t_list
->
2322 if (server
== NULL
) {
2323 (void) rw_unlock(¤t_list
->listDestroyLock
);
2324 (void) snprintf(errmsg
,
2326 gettext("No servers are available"));
2329 NS_CONFIG_NOTLOADED
,
2332 return (NS_LDAP_NOTFOUND
);
2335 (void) mutex_lock(&server
->updateStatus
);
2336 server
->info
= INFO_STATUS_OLD
;
2337 (void) mutex_unlock(&server
->updateStatus
);
2340 (void) rw_unlock(¤t_list
->listDestroyLock
);
2341 return (NS_LDAP_SUCCESS
);
2344 if (strcmp(addrType
, NS_CACHE_ADDR_HOSTNAME
) == 0) {
2345 ret_code
= __s_api_ip2hostname(server
->ip
, &ret
->serverFQDN
);
2346 if (ret_code
!= NS_LDAP_SUCCESS
) {
2347 (void) snprintf(errmsg
,
2349 gettext("The %s address "
2350 "can not be resolved into "
2351 "a host name. Returning "
2352 "the address as it is."),
2356 NS_CONFIG_NOTLOADED
,
2359 return (NS_LDAP_INTERNAL
);
2363 ret
->server
= strdup(server
->ip
);
2365 ret
->controls
= __s_api_cp2dArray(server
->controls
);
2366 ret
->saslMechanisms
= __s_api_cp2dArray(server
->saslMech
);
2368 (void) rw_unlock(¤t_list
->listDestroyLock
);
2370 return (NS_LDAP_SUCCESS
);
2374 * This function iterates through the list of the configured LDAP servers
2375 * and "pings" those which are marked as removed or if any error occurred
2376 * during the previous receiving of the server's root DSE. If the
2377 * function is able to reach such a server and get its root DSE, it
2378 * marks the server as on-line. Otherwise, the server's status is set
2380 * For each server the function tries to connect to, it fires up
2381 * a separate thread and then waits until all the treads finish.
2382 * The function returns NS_LDAP_INTERNAL if the Standalone mode was not
2383 * initialized or was canceled prior to an invocation of
2384 * __ns_ldap_pingOfflineServers().
2387 __ns_ldap_pingOfflineServers(void)
2389 dir_server_list_t
*current_list
= NULL
;
2390 ns_ldap_return_code retCode
= NS_LDAP_SUCCESS
;
2391 long srvListLength
, i
= 0;
2392 thread_t
*thrPool
, thrID
;
2393 void *status
= NULL
;
2395 (void) mutex_lock(&dir_servers
.listReplaceLock
);
2396 if (dir_servers
.list
== NULL
) {
2397 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2398 return (NS_LDAP_INTERNAL
);
2401 current_list
= dir_servers
.list
;
2402 (void) rw_wrlock(¤t_list
->listDestroyLock
);
2403 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2405 while (current_list
->nsServers
[i
] != NULL
) {
2410 thrPool
= calloc(srvListLength
, sizeof (thread_t
));
2411 if (thrPool
== NULL
) {
2412 (void) rw_unlock(¤t_list
->listDestroyLock
);
2413 return (NS_LDAP_MEMORY
);
2416 for (i
= 0; i
< srvListLength
; ++i
) {
2417 if (current_list
->nsServers
[i
]->status
!= INFO_SERVER_REMOVED
&&
2418 current_list
->nsServers
[i
]->status
!= INFO_SERVER_ERROR
) {
2421 current_list
->nsServers
[i
]->status
= INFO_SERVER_CONNECTING
;
2422 current_list
->nsServers
[i
]->info
= INFO_STATUS_NEW
;
2424 __s_api_free2dArray(current_list
->nsServers
[i
]->controls
);
2425 current_list
->nsServers
[i
]->controls
= NULL
;
2426 __s_api_free2dArray(current_list
->nsServers
[i
]->saslMech
);
2427 current_list
->nsServers
[i
]->saslMech
= NULL
;
2429 switch (thr_create(NULL
,
2431 create_ns_servers_entry
,
2432 current_list
->nsServers
[i
],
2436 current_list
->nsServers
[i
]->status
= INFO_SERVER_ERROR
;
2439 current_list
->nsServers
[i
]->status
= INFO_SERVER_ERROR
;
2440 retCode
= NS_LDAP_MEMORY
;
2446 /* A memory allocation error has occured */
2451 for (i
= 0; i
< srvListLength
; ++i
) {
2452 if (thrPool
[i
] != 0 &&
2453 thr_join(thrPool
[i
], NULL
, &status
) == 0) {
2454 if (status
== NULL
) {
2455 current_list
->nsServers
[i
]->status
=
2457 retCode
= NS_LDAP_MEMORY
;
2463 (void) rw_unlock(¤t_list
->listDestroyLock
);