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
;
438 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2ent
);
440 arg
.key
.hostaddr
.addr
= addr
;
441 arg
.key
.hostaddr
.len
= len
;
442 arg
.key
.hostaddr
.type
= type
;
444 arg
.h_errno
= NETDB_SUCCESS
;
446 res
= nss_search(nss_db_root
, nss_initf
, dbop
, &arg
);
448 *h_errnop
= arg
.h_errno
;
449 return (struct hostent
*)NSS_XbyY_FINI(&arg
);
453 * This routine is an analog of gethostbyaddr_r().
454 * But in addition __s_api_hostname2ip() performs the "LDAP SKIPDB" activity
455 * prior to querying the name services.
456 * If the buffer is not big enough to accommodate a returning data,
457 * NULL is returned and h_errnop is set to TRY_AGAIN.
460 __s_api_hostname2ip(const char *name
,
461 struct hostent
*result
, char *buffer
, int buflen
,
464 DEFINE_NSS_DB_ROOT(db_root_ipnodes
);
465 DEFINE_NSS_DB_ROOT(db_root_hosts
);
469 struct in6_addr addr6
;
471 if (inet_pton(AF_INET
, name
, &addr
) > 0) {
472 if (buflen
< strlen(name
) + 1 +
473 sizeof (char *) * 2 + /* The h_aliases member */
474 sizeof (struct in_addr
) +
475 sizeof (struct in_addr
*) * 2) {
476 *h_errnop
= TRY_AGAIN
;
480 result
->h_addrtype
= AF_INET
;
481 result
->h_length
= sizeof (struct in_addr
);
482 (void) strncpy(buffer
, name
, buflen
);
484 result
->h_addr_list
= (char **)ROUND_UP(
485 buffer
+ strlen(name
) + 1,
487 result
->h_aliases
= (char **)ROUND_UP(result
->h_addr_list
,
489 result
->h_aliases
[0] = buffer
;
490 result
->h_aliases
[1] = NULL
;
492 buffer
+ buflen
- sizeof (struct in_addr
),
493 sizeof (struct in_addr
));
494 result
->h_addr_list
[0] = buffer
+ buflen
-
495 sizeof (struct in_addr
);
496 result
->h_addr_list
[1] = NULL
;
497 result
->h_aliases
= result
->h_addr_list
;
498 result
->h_name
= buffer
;
500 *h_errnop
= NETDB_SUCCESS
;
503 if (inet_pton(AF_INET6
, name
, &addr6
) > 0) {
504 if (buflen
< strlen(name
) + 1 +
505 sizeof (char *) * 2 + /* The h_aliases member */
506 sizeof (struct in6_addr
) +
507 sizeof (struct in6_addr
*) * 2) {
508 *h_errnop
= TRY_AGAIN
;
512 result
->h_addrtype
= AF_INET6
;
513 result
->h_length
= sizeof (struct in6_addr
);
514 (void) strncpy(buffer
, name
, buflen
);
516 result
->h_addr_list
= (char **)ROUND_UP(
517 buffer
+ strlen(name
) + 1,
519 result
->h_aliases
= (char **)ROUND_UP(result
->h_addr_list
,
521 result
->h_aliases
[0] = buffer
;
522 result
->h_aliases
[1] = NULL
;
524 buffer
+ buflen
- sizeof (struct in6_addr
),
525 sizeof (struct in6_addr
));
526 result
->h_addr_list
[0] = buffer
+ buflen
-
527 sizeof (struct in6_addr
);
528 result
->h_addr_list
[1] = NULL
;
529 result
->h_aliases
= result
->h_addr_list
;
530 result
->h_name
= buffer
;
532 *h_errnop
= NETDB_SUCCESS
;
536 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2hostent
);
540 arg
.h_errno
= NETDB_SUCCESS
;
542 res
= nss_search(&db_root_ipnodes
, _initf_ipnodes
,
543 NSS_DBOP_IPNODES_BYNAME
, &arg
);
544 if (res
== NSS_NOTFOUND
|| res
== NSS_UNAVAIL
) {
545 arg
.h_errno
= NETDB_SUCCESS
;
546 res
= nss_search(&db_root_hosts
, _initf_hosts
,
547 NSS_DBOP_HOSTS_BYNAME
, &arg
);
550 *h_errnop
= arg
.h_errno
;
551 return ((struct hostent
*)NSS_XbyY_FINI(&arg
));
555 * Convert an IP to a host name.
558 __s_api_ip2hostname(char *ipaddr
, char **hostname
) {
561 struct hostent
*hp
= NULL
, hostEnt
;
562 char buffer
[NSS_BUFLEN_HOSTS
];
563 int buflen
= NSS_BUFLEN_HOSTS
;
572 if (ipaddr
== NULL
|| hostname
== NULL
)
573 return (NS_LDAP_INVALID_PARAM
);
575 if ((addr
= strdup(ipaddr
)) == NULL
)
576 return (NS_LDAP_MEMORY
);
578 if (addr
[0] == '[') {
580 * Assume it's [ipv6]:port
584 if ((end
= strchr(addr
, ']')) != NULL
) {
587 if (*(end
+ 1) == ':')
592 return (NS_LDAP_INVALID_PARAM
);
594 } else if ((end
= strchr(addr
, ':')) != NULL
) {
595 /* assume it's ipv4:port */
605 if (inet_pton(AF_INET
, start
, &in
) == 1) {
607 hp
= _filter_gethostbyaddr_r((char *)&in
,
614 if (hp
&& hp
->h_name
) {
615 /* hostname + '\0' */
616 len
= strlen(hp
->h_name
) + 1;
619 len
+= strlen(port
) + 1;
620 if ((*hostname
= malloc(len
)) == NULL
) {
622 return (NS_LDAP_MEMORY
);
626 (void) snprintf(*hostname
, len
, "%s:%s",
629 (void) strlcpy(*hostname
, hp
->h_name
, len
);
632 return (NS_LDAP_SUCCESS
);
635 return (NS_LDAP_NOTFOUND
);
637 } else if (inet_pton(AF_INET6
, start
, &in6
) == 1) {
639 hp
= _filter_gethostbyaddr_r((char *)&in6
,
640 sizeof (in6
.s6_addr
),
646 if (hp
&& hp
->h_name
) {
647 /* hostname + '\0' */
648 len
= strlen(hp
->h_name
) + 1;
651 len
+= strlen(port
) + 1;
652 if ((*hostname
= malloc(len
)) == NULL
) {
654 return (NS_LDAP_MEMORY
);
658 (void) snprintf(*hostname
, len
, "%s:%s",
661 (void) strlcpy(*hostname
, hp
->h_name
, len
);
664 return (NS_LDAP_SUCCESS
);
667 return (NS_LDAP_NOTFOUND
);
677 return (NS_LDAP_SUCCESS
);
682 * This function obtains data returned by an LDAP search request and puts it
683 * in a string in the ldap_cachmgr(1) door call format.
686 * ld - a pointer to an LDAP structure used for a search operation,
687 * result_msg - a pointer to an LDAPMessage returned by the search,
688 * include_names - if set to INCLUDE_ATTR_NAMES, the output buffer will
689 * contain attribute names.
690 * Otherwise, only values will be return.
693 * a buffer containing server info in the following format:
694 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
695 * Should be free'ed by the caller.
699 convert_to_door_line(LDAP
* ld
,
700 LDAPMessage
*result_msg
,
705 uint32_t total_length
= 0, attr_len
= 0, i
;
709 int seen_objectclass
= 0, rewind
= 0;
712 return (NS_LDAP_INVALID_PARAM
);
716 if ((e
= ldap_first_entry(ld
, result_msg
)) == NULL
) {
717 return (NS_LDAP_NOTFOUND
);
720 /* calculate length of received data */
721 for (a
= ldap_first_attribute(ld
, e
, &ber
);
723 a
= ldap_next_attribute(ld
, e
, ber
)) {
725 if ((vals
= ldap_get_values(ld
, e
, a
)) != NULL
) {
726 for (i
= 0; vals
[i
] != NULL
; i
++) {
727 total_length
+= (include_names
?
730 strlen(DOORLINESEP
) +1;
732 ldap_value_free(vals
);
740 if (total_length
== 0) {
741 return (NS_LDAP_NOTFOUND
);
745 /* add 1 for the last '\0' */
746 *door_line
= (char *)malloc(total_length
+ 1);
747 if (*door_line
== NULL
) {
748 return (NS_LDAP_MEMORY
);
751 /* make it an empty string first */
753 a
= ldap_first_attribute(ld
, e
, &ber
);
757 * If we're processing DUAConfigProfile, we need to make
758 * sure we put objectclass attribute first.
759 * __s_api_create_config_door_str depends on that.
761 if (seen_objectclass
) {
762 if (strcasecmp(a
, "objectclass") == 0) {
763 /* Skip objectclass now. */
764 a
= ldap_next_attribute(ld
, e
, ber
);
768 if (strcasecmp(a
, "objectclass") == 0) {
769 seen_objectclass
= 1;
772 /* Skip all but objectclass first. */
773 a
= ldap_next_attribute(ld
, e
, ber
);
779 if ((vals
= ldap_get_values(ld
, e
, a
)) != NULL
) {
780 for (i
= 0; vals
[i
] != NULL
; i
++) {
782 attr_len
+= strlen(a
);
784 attr_len
+= strlen(vals
[i
]) +
785 strlen(DOORLINESEP
) + 2;
787 (void) snprintf(*door_line
+
794 (void) snprintf(*door_line
+
802 ldap_value_free(vals
);
811 a
= ldap_first_attribute(ld
, e
, &ber
);
814 a
= ldap_next_attribute(ld
, e
, ber
);
821 if (e
!= result_msg
) {
822 (void) ldap_msgfree(e
);
825 return (NS_LDAP_SUCCESS
);
829 * This function looks up the base DN of a directory serving
830 * a specified domain name.
833 * ld - a pointer to an LDAP structure used for the search operation,
834 * domain_name - the name of a domain.
837 * a buffer containing a directory's base DN found.
838 * Should be free'ed by the caller.
842 getDirBaseDN(LDAP
*ld
, const char *domain_name
, char **dir_base_dn
)
844 struct timeval tv
= {NS_DEFAULT_SEARCH_TIMEOUT
, 0};
845 char *attrs
[2], *DNlist
, *rest
, *ptr
;
846 char filter
[BUFSIZ
], *a
= NULL
;
848 LDAPMessage
*resultMsg
= NULL
;
849 ns_ldap_return_code ret_code
;
851 /* Get the whole list of naming contexts residing on the server */
852 attrs
[0] = "namingcontexts";
854 ldap_rc
= ldap_search_ext_s(ld
, "", LDAP_SCOPE_BASE
, "(objectclass=*)",
855 attrs
, 0, NULL
, NULL
, &tv
, 0, &resultMsg
);
857 /* If successful, the root DSE was found. */
861 * If the root DSE was not found, the server does
862 * not comply with the LDAP v3 protocol.
866 (void) ldap_msgfree(resultMsg
);
870 return (NS_LDAP_OP_FAILED
);
873 if ((ret_code
= convert_to_door_line(ld
,
875 DONT_INCLUDE_ATTR_NAMES
,
877 &DNlist
)) != NS_LDAP_SUCCESS
) {
879 (void) ldap_msgfree(resultMsg
);
886 (void) ldap_msgfree(resultMsg
);
890 if (DNlist
== NULL
||
891 (ptr
= strtok_r(DNlist
, DOORLINESEP
, &rest
)) == NULL
) {
892 return (NS_LDAP_NOTFOUND
);
897 * For each context try to find a NIS domain object
898 * which 'nisdomain' attribute's value matches the domain name
900 (void) snprintf(filter
,
902 "(&(objectclass=nisDomainObject)"
905 ldap_rc
= ldap_search_ext_s(ld
,
916 if (ldap_rc
!= LDAP_SUCCESS
) {
918 (void) ldap_msgfree(resultMsg
);
923 if ((a
= ldap_get_dn(ld
, resultMsg
)) != NULL
) {
924 *dir_base_dn
= strdup(a
);
928 (void) ldap_msgfree(resultMsg
);
934 return (NS_LDAP_MEMORY
);
940 (void) ldap_msgfree(resultMsg
);
943 } while (ptr
= strtok_r(NULL
, DOORLINESEP
, &rest
));
948 return (NS_LDAP_NOTFOUND
);
951 return (NS_LDAP_SUCCESS
);
955 * This function parses the results of a search operation
956 * requesting a DUAProfile.
959 * ld - a pointer to an LDAP structure used for the search operation,
960 * dir_base_dn - the name of a directory's base DN,
961 * profile_name - the name of a DUAProfile to be obtained.
964 * a buffer containing the DUAProfile in the following format:
965 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
966 * Should be free'ed by the caller.
970 getDUAProfile(LDAP
*ld
,
971 const char *dir_base_dn
,
972 const char *profile_name
,
975 char searchBaseDN
[BUFSIZ
], filter
[BUFSIZ
];
976 LDAPMessage
*resultMsg
= NULL
;
977 struct timeval tv
= {NS_DEFAULT_SEARCH_TIMEOUT
, 0};
979 ns_ldap_return_code ret_code
;
981 (void) snprintf(searchBaseDN
, BUFSIZ
, "ou=profile,%s", dir_base_dn
);
982 (void) snprintf(filter
,
985 _PROFILE1_OBJECTCLASS
,
986 _PROFILE2_OBJECTCLASS
,
988 ldap_rc
= ldap_search_ext_s(ld
,
1001 /* If successful, the DUA profile was found. */
1005 * If the root DSE was not found, the server does
1006 * not comply with the LDAP v3 protocol.
1010 (void) ldap_msgfree(resultMsg
);
1014 return (NS_LDAP_OP_FAILED
);
1017 ret_code
= convert_to_door_line(ld
,
1023 (void) ldap_msgfree(resultMsg
);
1030 * This function derives the directory's base DN from a provided domain name.
1033 * domain_name - the name of a domain to be converted into a base DN,
1034 * buffer - contains the derived base DN,
1035 * buf_len - the length of the buffer.
1038 * The function returns the address of the buffer or NULL.
1042 domainname2baseDN(char *domain_name
, char *buffer
, uint16_t buf_len
)
1047 if (!domain_name
|| !buffer
|| buf_len
== 0) {
1052 nextDC
= chr
= domain_name
;
1053 length
= strlen(domain_name
);
1054 for (i
= 0; i
< length
+ 1; ++i
, ++chr
) {
1055 /* Simply replace dots with "dc=" */
1056 if (*chr
!= '.' && *chr
!= '\0') {
1060 if (strlcat(buffer
, "dc=", buf_len
) >= buf_len
)
1062 if (strlcat(buffer
, nextDC
, buf_len
) >= buf_len
)
1066 * The end of the domain name
1067 * has not been reached yet
1069 if (strlcat(buffer
, ",", buf_len
) >= buf_len
)
1080 * This function obtains the directory's base DN and a DUAProfile
1081 * from a specified server.
1084 * server - a structure describing a server to connect to and
1085 * a DUAProfile to be obtained from the server,
1086 * cred - credentials to be used during establishing connections to
1090 * dua_profile - a buffer containing the DUAProfile in the following format:
1091 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1092 * dir_base_dn - a buffer containing the base DN,
1093 * errorp - an error object describing an error, if any.
1095 * All the output data structures should be free'ed by the caller.
1098 __ns_ldap_getConnectionInfoFromDUA(const ns_dir_server_t
*server
,
1099 const ns_cred_t
*cred
,
1102 ns_ldap_error_t
**errorp
)
1104 char serverAddr
[MAX_HOSTADDR_LEN
];
1105 char *dirBaseDN
= NULL
, *duaProfile
= NULL
;
1106 ns_cred_t default_cred
;
1107 ns_ldap_return_code ret_code
;
1109 ns_config_t
*config_struct
= __s_api_create_config();
1110 ConnectionID sessionId
= 0;
1111 Connection
*session
= NULL
;
1112 char errmsg
[MAXERROR
];
1113 char buffer
[NSS_BUFLEN_HOSTS
];
1114 ns_conn_user_t
*cu
= NULL
;
1116 if (errorp
== NULL
) {
1117 __s_api_destroy_config(config_struct
);
1118 return (NS_LDAP_INVALID_PARAM
);
1123 if (server
== NULL
) {
1124 __s_api_destroy_config(config_struct
);
1125 return (NS_LDAP_INVALID_PARAM
);
1128 if (config_struct
== NULL
) {
1129 return (NS_LDAP_MEMORY
);
1133 * If no credentials are specified, try to establish a connection
1137 default_cred
.cred
.unix_cred
.passwd
= NULL
;
1138 default_cred
.cred
.unix_cred
.userID
= NULL
;
1139 default_cred
.auth
.type
= NS_LDAP_AUTH_NONE
;
1142 /* Now create a default LDAP configuration */
1144 (void) strncpy(buffer
, server
->server
, sizeof (buffer
));
1145 if (__ns_ldap_setParamValue(config_struct
, NS_LDAP_SERVERS_P
, buffer
,
1146 errorp
) != NS_LDAP_SUCCESS
) {
1147 __s_api_destroy_config(config_struct
);
1148 return (NS_LDAP_CONFIG
);
1151 /* Put together the address and the port specified by the user app. */
1152 if (server
->port
> 0) {
1153 (void) snprintf(serverAddr
,
1154 sizeof (serverAddr
),
1159 (void) strncpy(serverAddr
, buffer
, sizeof (serverAddr
));
1163 * There is no default value for the 'Default Search Base DN' attribute.
1164 * Derive one from the domain name to make __s_api_crosscheck() happy.
1166 if (domainname2baseDN(server
->domainName
?
1167 server
->domainName
: config_struct
->domainName
,
1168 buffer
, NSS_BUFLEN_HOSTS
) == NULL
) {
1169 (void) snprintf(errmsg
,
1171 gettext("Can not convert %s into a base DN name"),
1172 server
->domainName
?
1173 server
->domainName
: config_struct
->domainName
);
1179 __s_api_destroy_config(config_struct
);
1180 return (NS_LDAP_INTERNAL
);
1182 if (__ns_ldap_setParamValue(config_struct
, NS_LDAP_SEARCH_BASEDN_P
,
1183 buffer
, errorp
) != NS_LDAP_SUCCESS
) {
1184 __s_api_destroy_config(config_struct
);
1185 return (NS_LDAP_CONFIG
);
1188 if (__s_api_crosscheck(config_struct
, errmsg
, B_FALSE
) != NS_SUCCESS
) {
1189 __s_api_destroy_config(config_struct
);
1190 return (NS_LDAP_CONFIG
);
1193 __s_api_init_config(config_struct
);
1195 __s_api_setInitMode();
1197 cu
= __s_api_conn_user_init(NS_CONN_USER_SEARCH
, NULL
, B_FALSE
);
1199 return (NS_LDAP_INTERNAL
);
1202 if ((ret_code
= __s_api_getConnection(serverAddr
,
1204 cred
? cred
: &default_cred
,
1210 cu
)) != NS_LDAP_SUCCESS
) {
1211 __s_api_conn_user_free(cu
);
1212 __s_api_unsetInitMode();
1216 __s_api_unsetInitMode();
1218 if ((ret_code
= getDirBaseDN(session
->ld
,
1219 server
->domainName
?
1220 server
->domainName
:
1221 config_struct
->domainName
,
1222 &dirBaseDN
)) != NS_LDAP_SUCCESS
) {
1223 (void) snprintf(errmsg
,
1225 gettext("Can not find the "
1226 "nisDomainObject for domain %s\n"),
1227 server
->domainName
?
1228 server
->domainName
: config_struct
->domainName
);
1234 __s_api_conn_user_free(cu
);
1235 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1240 * And here obtain a DUAProfile which will be used
1241 * as a real configuration.
1243 if ((ret_code
= getDUAProfile(session
->ld
,
1245 server
->profileName
?
1246 server
->profileName
: "default",
1247 &duaProfile
)) != NS_LDAP_SUCCESS
) {
1248 (void) snprintf(errmsg
,
1250 gettext("Can not find the "
1252 server
->profileName
?
1253 server
->profileName
: "default");
1259 __s_api_conn_user_free(cu
);
1260 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1265 *dir_base_dn
= dirBaseDN
;
1271 *dua_profile
= duaProfile
;
1276 __s_api_conn_user_free(cu
);
1277 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1279 return (NS_LDAP_SUCCESS
);
1283 * This function obtains the root DSE from a specified server.
1286 * server_addr - an adress of a server to be connected to.
1289 * root_dse - a buffer containing the root DSE in the following format:
1290 * [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1291 * For example: ( here | used as DOORLINESEP for visual purposes)
1292 * supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL
1293 * Should be free'ed by the caller.
1296 __ns_ldap_getRootDSE(const char *server_addr
,
1298 ns_ldap_error_t
**errorp
,
1301 char errmsg
[MAXERROR
];
1302 ns_ldap_return_code ret_code
;
1304 ConnectionID sessionId
= 0;
1305 Connection
*session
= NULL
;
1307 struct timeval tv
= {NS_DEFAULT_SEARCH_TIMEOUT
, 0};
1309 int ldap_rc
, ldaperrno
= 0;
1310 LDAPMessage
*resultMsg
= NULL
;
1311 void **paramVal
= NULL
;
1314 ns_conn_user_t
*cu
= NULL
;
1316 if (errorp
== NULL
) {
1317 return (NS_LDAP_INVALID_PARAM
);
1323 return (NS_LDAP_INVALID_PARAM
);
1327 return (NS_LDAP_INVALID_PARAM
);
1330 __s_api_setInitMode();
1332 cu
= __s_api_conn_user_init(NS_CONN_USER_SEARCH
, NULL
, B_FALSE
);
1334 return (NS_LDAP_INTERNAL
);
1338 * All the credentials will be taken from the current
1339 * libsldap configuration.
1341 if ((ret_code
= __s_api_getConnection(server_addr
,
1349 cu
)) != NS_LDAP_SUCCESS
) {
1350 /* Fallback to anonymous mode is disabled. Stop. */
1351 if (anon_fallback
== 0) {
1353 gettext("libsldap: can not get the root DSE from "
1354 " the %s server: %s. "
1355 "Falling back to anonymous disabled.\n"),
1357 errorp
&& *errorp
&& (*errorp
)->message
?
1358 (*errorp
)->message
: "");
1359 if (errorp
!= NULL
&& *errorp
!= NULL
) {
1360 (void) __ns_ldap_freeError(errorp
);
1362 __s_api_unsetInitMode();
1367 * Fallback to anonymous, non-SSL mode for backward
1368 * compatibility reasons. This mode should only be used when
1369 * this function (__ns_ldap_getRootDSE) is called from
1373 gettext("libsldap: Falling back to anonymous, non-SSL"
1374 " mode for __ns_ldap_getRootDSE. %s\n"),
1375 errorp
&& *errorp
&& (*errorp
)->message
?
1376 (*errorp
)->message
: "");
1378 /* Setup the anon credential for anonymous connection. */
1379 (void) memset(&anon
, 0, sizeof (ns_cred_t
));
1380 anon
.auth
.type
= NS_LDAP_AUTH_NONE
;
1382 if (*errorp
!= NULL
) {
1383 (void) __ns_ldap_freeError(errorp
);
1387 ret_code
= __s_api_getConnection(server_addr
,
1397 if (ret_code
!= NS_LDAP_SUCCESS
) {
1398 __s_api_conn_user_free(cu
);
1399 __s_api_unsetInitMode();
1404 __s_api_unsetInitMode();
1406 /* get search timeout value */
1407 (void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P
, ¶mVal
, errorp
);
1408 if (paramVal
!= NULL
&& *paramVal
!= NULL
) {
1409 tv
.tv_sec
= **((int **)paramVal
);
1410 (void) __ns_ldap_freeParam(¶mVal
);
1412 if (*errorp
!= NULL
) {
1413 (void) __ns_ldap_freeError(errorp
);
1416 /* Get root DSE from the server specified by the caller. */
1417 attrs
[0] = "supportedControl";
1418 attrs
[1] = "supportedsaslmechanisms";
1420 ldap_rc
= ldap_search_ext_s(session
->ld
,
1432 if (ldap_rc
!= LDAP_SUCCESS
) {
1434 * If the root DSE was not found, the server does
1435 * not comply with the LDAP v3 protocol.
1437 (void) ldap_get_option(session
->ld
,
1438 LDAP_OPT_ERROR_NUMBER
,
1440 (void) snprintf(errmsg
,
1442 gettext(ldap_err2string(ldaperrno
)));
1450 (void) ldap_msgfree(resultMsg
);
1454 __s_api_conn_user_free(cu
);
1455 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1456 return (NS_LDAP_OP_FAILED
);
1458 __s_api_conn_user_free(cu
);
1460 ret_code
= convert_to_door_line(session
->ld
,
1465 if (ret_code
== NS_LDAP_NOTFOUND
) {
1466 (void) snprintf(errmsg
,
1468 gettext("No root DSE data "
1469 "for server %s returned."),
1479 (void) ldap_msgfree(resultMsg
);
1483 DropConnection(sessionId
, NS_LDAP_NEW_CONN
);
1489 * This function destroys the local list of root DSEs. The input parameter is
1490 * a pointer to the list to be erased.
1491 * The type of the pointer passed to this function should be
1492 * (dir_server_list_t *).
1496 disposeOfOldList(void *param
)
1498 dir_server_list_t
*old_list
= (dir_server_list_t
*)param
;
1501 (void) rw_wrlock(&old_list
->listDestroyLock
);
1502 /* Destroy the old list */
1503 while (old_list
->nsServers
[i
]) {
1504 free(old_list
->nsServers
[i
]->ip
);
1506 while (old_list
->nsServers
[i
]->controls
&&
1507 old_list
->nsServers
[i
]->controls
[j
]) {
1508 free(old_list
->nsServers
[i
]->controls
[j
]);
1511 free(old_list
->nsServers
[i
]->controls
);
1513 while (old_list
->nsServers
[i
]->saslMech
&&
1514 old_list
->nsServers
[i
]->saslMech
[j
]) {
1515 free(old_list
->nsServers
[i
]->saslMech
[j
]);
1518 free(old_list
->nsServers
[i
]->saslMech
);
1522 * All the structures pointed by old_list->nsServers were allocated
1523 * in one chunck. The nsServers[0] pointer points to the beginning
1526 free(old_list
->nsServers
[0]);
1527 free(old_list
->nsServers
);
1528 (void) rw_unlock(&old_list
->listDestroyLock
);
1529 (void) rwlock_destroy(&old_list
->listDestroyLock
);
1536 * This function cancels the Standalone mode and destroys the list of root DSEs.
1539 __ns_ldap_cancelStandalone(void)
1541 dir_server_list_t
*old_list
;
1543 (void) mutex_lock(&dir_servers
.listReplaceLock
);
1544 dir_servers
.standalone
= 0;
1545 if (!dir_servers
.list
) {
1546 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
1549 old_list
= dir_servers
.list
;
1550 dir_servers
.list
= NULL
;
1551 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
1553 (void) disposeOfOldList(old_list
);
1559 create_ns_servers_entry(void *param
)
1561 #define CHUNK_SIZE 16
1563 dir_server_t
*server
= (dir_server_t
*)param
;
1564 ns_ldap_return_code
*retCode
= calloc(1,
1565 sizeof (ns_ldap_return_code
));
1566 uint32_t sc_counter
= 0, sm_counter
= 0;
1567 uint32_t sc_mem_blocks
= 1, sm_mem_blocks
= 1;
1568 char *rootDSE
= NULL
, *attr
, *val
, *rest
, **ptr
;
1569 ns_ldap_error_t
*error
= NULL
;
1571 if (retCode
== NULL
) {
1576 * We call this function in non anon-fallback mode because we
1577 * want the whole procedure to fail as soon as possible to
1578 * indicate there are problems with connecting to the server.
1580 *retCode
= __ns_ldap_getRootDSE(server
->ip
,
1585 if (*retCode
== NS_LDAP_MEMORY
) {
1591 * If the root DSE can not be obtained, log an error and keep the
1594 if (*retCode
!= NS_LDAP_SUCCESS
) {
1595 server
->status
= INFO_SERVER_ERROR
;
1597 gettext("libsldap (\"standalone\" mode): "
1598 "can not obtain the root DSE from %s. %s"),
1600 error
&& error
->message
? error
->message
: "");
1602 (void) __ns_ldap_freeError(&error
);
1607 /* Get the first attribute of the root DSE. */
1608 attr
= strtok_r(rootDSE
, DOORLINESEP
, &rest
);
1611 server
->status
= INFO_SERVER_ERROR
;
1613 gettext("libsldap (\"standalone\" mode): "
1614 "the root DSE from %s is empty or corrupted."),
1616 *retCode
= NS_LDAP_INTERNAL
;
1620 server
->controls
= (char **)calloc(CHUNK_SIZE
, sizeof (char *));
1621 server
->saslMech
= (char **)calloc(CHUNK_SIZE
, sizeof (char *));
1622 if (server
->controls
== NULL
|| server
->saslMech
== NULL
) {
1629 if ((val
= strchr(attr
, '=')) == NULL
) {
1634 if (strncasecmp(attr
,
1636 _SASLMECHANISM_LEN
) == 0) {
1637 if (sm_counter
== CHUNK_SIZE
* sm_mem_blocks
- 1) {
1638 ptr
= (char **)reallocarray(server
->saslMech
,
1639 CHUNK_SIZE
* ++sm_mem_blocks
,
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 **)reallocarray(server
->controls
,
1668 CHUNK_SIZE
* ++sc_mem_blocks
,
1671 *retCode
= NS_LDAP_MEMORY
;
1682 server
->controls
= ptr
;
1685 server
->controls
[sc_counter
] = strdup(val
);
1686 if (server
->controls
[sc_counter
] == NULL
) {
1687 *retCode
= NS_LDAP_MEMORY
;
1694 } while (attr
= strtok_r(NULL
, DOORLINESEP
, &rest
));
1698 if (*retCode
== NS_LDAP_MEMORY
) {
1703 server
->controls
[sc_counter
] = NULL
;
1704 server
->saslMech
[sm_counter
] = NULL
;
1706 server
->status
= INFO_SERVER_UP
;
1714 * This function creates a new local list of root DSEs from all the servers
1715 * mentioned in the DUAProfile (or local NS BEC) and returns
1716 * a pointer to the list.
1720 createDirServerList(dir_server_list_t
**new_list
,
1721 ns_ldap_error_t
**errorp
)
1724 ns_ldap_return_code retCode
= NS_LDAP_SUCCESS
;
1725 dir_server_t
*tmpSrvArray
;
1726 long srvListLength
, i
;
1727 thread_t
*thrPool
, thrID
;
1728 void *status
= NULL
;
1730 if (errorp
== NULL
) {
1731 return (NS_LDAP_INVALID_PARAM
);
1736 if (new_list
== NULL
) {
1737 return (NS_LDAP_INVALID_PARAM
);
1740 retCode
= __s_api_getServers(&serverList
, errorp
);
1741 if (retCode
!= NS_LDAP_SUCCESS
|| serverList
== NULL
) {
1745 for (i
= 0; serverList
[i
]; ++i
) {
1750 thrPool
= calloc(srvListLength
, sizeof (thread_t
));
1751 if (thrPool
== NULL
) {
1752 __s_api_free2dArray(serverList
);
1753 return (NS_LDAP_MEMORY
);
1756 *new_list
= (dir_server_list_t
*)calloc(1,
1757 sizeof (dir_server_list_t
));
1758 if (*new_list
== NULL
) {
1759 __s_api_free2dArray(serverList
);
1761 return (NS_LDAP_MEMORY
);
1763 (void) rwlock_init(&(*new_list
)->listDestroyLock
, USYNC_THREAD
, NULL
);
1765 (*new_list
)->nsServers
= (dir_server_t
**)calloc(srvListLength
+ 1,
1766 sizeof (dir_server_t
*));
1767 if ((*new_list
)->nsServers
== NULL
) {
1770 __s_api_free2dArray(serverList
);
1772 return (NS_LDAP_MEMORY
);
1776 * Allocate a set of dir_server_t structures as an array,
1777 * with one alloc call and then initialize the nsServers pointers
1778 * with the addresses of the array's members.
1780 tmpSrvArray
= (dir_server_t
*)calloc(srvListLength
,
1781 sizeof (dir_server_t
));
1782 for (i
= 0; i
< srvListLength
; ++i
) {
1783 (*new_list
)->nsServers
[i
] = &tmpSrvArray
[i
];
1785 (*new_list
)->nsServers
[i
]->info
= INFO_STATUS_NEW
;
1786 (void) mutex_init(&(*new_list
)->nsServers
[i
]->updateStatus
,
1790 (*new_list
)->nsServers
[i
]->ip
= strdup(serverList
[i
]);
1791 if ((*new_list
)->nsServers
[i
]->ip
== NULL
) {
1792 retCode
= NS_LDAP_MEMORY
;
1796 (*new_list
)->nsServers
[i
]->status
= INFO_SERVER_CONNECTING
;
1798 switch (thr_create(NULL
,
1800 create_ns_servers_entry
,
1801 (*new_list
)->nsServers
[i
],
1805 (*new_list
)->nsServers
[i
]->status
=
1809 (*new_list
)->nsServers
[i
]->status
=
1818 for (i
= 0; i
< srvListLength
; ++i
) {
1819 if (thrPool
[i
] != 0 &&
1820 thr_join(thrPool
[i
], NULL
, &status
) == 0) {
1821 if (status
== NULL
) {
1823 * Some memory allocation problems occured. Just
1824 * ignore the server and hope there will be some
1827 (*new_list
)->nsServers
[i
]->status
=
1834 __s_api_free2dArray(serverList
);
1837 if (retCode
== NS_LDAP_MEMORY
) {
1838 (void) disposeOfOldList(*new_list
);
1839 return (NS_LDAP_MEMORY
);
1842 return (NS_LDAP_SUCCESS
);
1846 * This functions replaces the local list of root DSEs with a new one and starts
1847 * a thread destroying the old list. There is no need for other threads to wait
1848 * until the old list will be destroyed.
1849 * Since it is possible that more than one thread can start creating the list,
1850 * this function should be protected by mutexes to be sure that only one thread
1851 * performs the initialization.
1855 initGlobalList(ns_ldap_error_t
**error
)
1857 dir_server_list_t
*new_list
, *old_list
;
1858 ns_ldap_return_code ret_code
;
1861 ret_code
= createDirServerList(&new_list
, error
);
1862 if (ret_code
!= NS_LDAP_SUCCESS
) {
1866 old_list
= dir_servers
.list
;
1867 dir_servers
.list
= new_list
;
1870 (void) thr_create(NULL
,
1878 return (NS_LDAP_SUCCESS
);
1885 } authArray
[] = {{"none", {NS_LDAP_AUTH_NONE
,
1888 NS_LDAP_SASLOPT_NONE
}},
1889 {"simple", {NS_LDAP_AUTH_SIMPLE
,
1892 NS_LDAP_SASLOPT_NONE
}},
1893 {"tls:simple", {NS_LDAP_AUTH_TLS
,
1896 NS_LDAP_SASLOPT_NONE
}},
1897 {"tls:sasl/CRAM-MD5", {NS_LDAP_AUTH_TLS
,
1899 NS_LDAP_SASL_CRAM_MD5
,
1900 NS_LDAP_SASLOPT_NONE
}},
1901 {"tls:sasl/DIGEST-MD5", {NS_LDAP_AUTH_TLS
,
1903 NS_LDAP_SASL_DIGEST_MD5
,
1904 NS_LDAP_SASLOPT_NONE
}},
1905 {"sasl/CRAM-MD5", {NS_LDAP_AUTH_SASL
,
1907 NS_LDAP_SASL_CRAM_MD5
,
1908 NS_LDAP_SASLOPT_NONE
}},
1909 {"sasl/DIGEST-MD5", {NS_LDAP_AUTH_SASL
,
1911 NS_LDAP_SASL_DIGEST_MD5
,
1912 NS_LDAP_SASLOPT_NONE
}},
1913 {"sasl/GSSAPI", {NS_LDAP_AUTH_SASL
,
1915 NS_LDAP_SASL_GSSAPI
,
1916 NS_LDAP_SASLOPT_PRIV
| NS_LDAP_SASLOPT_INT
}},
1917 {NULL
, {NS_LDAP_AUTH_NONE
,
1920 NS_LDAP_SASLOPT_NONE
}}};
1923 __ns_ldap_initAuth(const char *auth_mech
,
1925 ns_ldap_error_t
**errorp
)
1928 char errmsg
[MAXERROR
];
1930 if (auth_mech
== NULL
) {
1931 (void) snprintf(errmsg
,
1933 gettext("Invalid authentication method specified\n"));
1934 MKERROR(LOG_WARNING
,
1939 return (NS_LDAP_INTERNAL
);
1942 for (i
= 0; authArray
[i
].authMech
!= NULL
; ++i
) {
1943 if (strcasecmp(auth_mech
, authArray
[i
].authMech
) == 0) {
1944 *auth
= authArray
[i
].auth
;
1945 return (NS_LDAP_SUCCESS
);
1949 (void) snprintf(errmsg
,
1951 gettext("Invalid authentication method specified\n"));
1952 MKERROR(LOG_WARNING
,
1957 return (NS_LDAP_INTERNAL
);
1961 * This function "informs" libsldap that a client application has specified
1962 * a directory to use. The function obtains a DUAProfile, credentials,
1963 * and naming context. During all further operations on behalf
1964 * of the application requested a standalone schema libsldap will use
1965 * the information obtained by __ns_ldap_initStandalone() instead of
1966 * door_call(3C)ing ldap_cachemgr(8).
1969 * sa_conf - a structure describing where and in which way to obtain all
1970 * the configuration describing how to communicate to
1971 * a choosen LDAP directory,
1972 * errorp - an error object describing an error occured.
1975 __ns_ldap_initStandalone(const ns_standalone_conf_t
*sa_conf
,
1976 ns_ldap_error_t
**errorp
) {
1978 ns_cred_t user_cred
= {{NS_LDAP_AUTH_NONE
,
1981 NS_LDAP_SASLOPT_NONE
},
1984 char *dua_profile
= NULL
;
1985 char errmsg
[MAXERROR
];
1989 if (sa_conf
->SA_BIND_DN
== NULL
&& sa_conf
->SA_BIND_PWD
!= NULL
||
1990 sa_conf
->SA_BIND_DN
!= NULL
&& sa_conf
->SA_BIND_PWD
== NULL
) {
1991 (void) snprintf(errmsg
,
1993 gettext("Bind DN and bind password"
1994 " must both be provided\n"));
1997 NS_CONFIG_NOTLOADED
,
2000 return (NS_LDAP_INTERNAL
);
2003 switch (sa_conf
->type
) {
2004 case NS_LDAP_SERVER
:
2005 if (sa_conf
->SA_BIND_DN
!= NULL
) {
2006 user_cred
.cred
.unix_cred
.userID
= sa_conf
->SA_BIND_DN
;
2007 user_cred
.auth
.type
= NS_LDAP_AUTH_SIMPLE
;
2010 if (sa_conf
->SA_BIND_PWD
!= NULL
) {
2011 user_cred
.cred
.unix_cred
.passwd
= sa_conf
->SA_BIND_PWD
;
2014 if (sa_conf
->SA_AUTH
!= NULL
) {
2015 user_cred
.auth
.type
= sa_conf
->SA_AUTH
->type
;
2016 user_cred
.auth
.tlstype
= sa_conf
->SA_AUTH
->tlstype
;
2017 user_cred
.auth
.saslmech
= sa_conf
->SA_AUTH
->saslmech
;
2018 user_cred
.auth
.saslopt
= sa_conf
->SA_AUTH
->saslopt
;
2021 if (sa_conf
->SA_CERT_PATH
!= NULL
) {
2022 user_cred
.hostcertpath
= sa_conf
->SA_CERT_PATH
;
2025 ret_code
= __ns_ldap_getConnectionInfoFromDUA(
2026 &sa_conf
->ds_profile
.server
,
2031 if (ret_code
!= NS_LDAP_SUCCESS
) {
2035 cfg
= __s_api_create_config_door_str(dua_profile
, errorp
);
2038 return (NS_LDAP_CONFIG
);
2041 if (sa_conf
->SA_CERT_PATH
!= NULL
) {
2043 ParamIndexType type
;
2045 switch (cfg
->version
) {
2047 certPathAttr
= "NS_LDAP_CERT_PATH";
2049 default: /* Version 2 */
2050 certPathAttr
= "NS_LDAP_HOST_CERTPATH";
2054 if (__s_api_get_versiontype(cfg
,
2057 (ret_code
= __ns_ldap_setParamValue(cfg
,
2059 sa_conf
->SA_CERT_PATH
,
2060 errorp
)) != NS_LDAP_SUCCESS
) {
2061 __s_api_destroy_config(cfg
);
2066 if (sa_conf
->SA_BIND_DN
!= NULL
&&
2067 sa_conf
->SA_BIND_PWD
!= NULL
) {
2070 authMethods
= __s_api_strValue(cfg
, NS_LDAP_AUTH_P
,
2072 if (authMethods
!= NULL
&&
2073 strstr(authMethods
, "sasl/GSSAPI") != NULL
) {
2075 * The received DUAProfile specifies
2076 * sasl/GSSAPI as an auth. mechanism.
2077 * The bind DN and password will be
2080 syslog(LOG_INFO
, gettext("sasl/GSSAPI will be "
2081 "used as an authentication method. "
2082 "The bind DN and password will "
2090 if (__ns_ldap_setParamValue(cfg
,
2092 sa_conf
->SA_BIND_DN
,
2093 errorp
) != NS_LDAP_SUCCESS
) {
2094 __s_api_destroy_config(cfg
);
2095 return (NS_LDAP_CONFIG
);
2098 if (__ns_ldap_setParamValue(cfg
,
2099 NS_LDAP_BINDPASSWD_P
,
2100 sa_conf
->SA_BIND_PWD
,
2101 errorp
) != NS_LDAP_SUCCESS
) {
2102 __s_api_destroy_config(cfg
);
2103 return (NS_LDAP_CONFIG
);
2108 default: /* NS_CACHEMGR */
2109 return (NS_LDAP_SUCCESS
);
2112 __s_api_init_config(cfg
);
2113 /* Connection management should use the new config now. */
2114 __s_api_reinit_conn_mgmt_new_config(cfg
);
2115 __ns_ldap_setServer(TRUE
);
2117 (void) mutex_lock(&dir_servers
.listReplaceLock
);
2118 if ((ret_code
= initGlobalList(errorp
)) != NS_SUCCESS
) {
2119 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2122 dir_servers
.standalone
= 1;
2123 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2125 return (NS_LDAP_SUCCESS
);
2130 * serverAddr is the address of a server and
2131 * request is one of the following:
2132 * NS_CACHE_NEW: get a new server address, addr is ignored.
2133 * NS_CACHE_NORESP: get the next one, remove addr from list.
2134 * NS_CACHE_NEXT: get the next one, keep addr on list.
2135 * NS_CACHE_WRITE: get a non-replica server, if possible, if not, same
2138 * NS_CACHE_ADDR_IP: return server address as is, this is default.
2139 * NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only
2140 * self credential case requires such format.
2144 * a structure of type ns_server_info_t containing the server address
2145 * or name, server controls and supported SASL mechanisms.
2146 * NOTE: Caller should allocate space for the structure and free
2147 * all the space allocated by the function for the information contained
2150 * error - an error object describing an error, if any.
2153 __s_api_findRootDSE(const char *request
,
2154 const char *serverAddr
,
2155 const char *addrType
,
2156 ns_server_info_t
*ret
,
2157 ns_ldap_error_t
**error
)
2159 dir_server_list_t
*current_list
= NULL
;
2160 ns_ldap_return_code ret_code
;
2162 int matched
= FALSE
;
2163 dir_server_t
*server
= NULL
;
2164 char errmsg
[MAXERROR
];
2166 (void) mutex_lock(&dir_servers
.listReplaceLock
);
2167 if (dir_servers
.list
== NULL
) {
2168 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2169 (void) snprintf(errmsg
,
2171 gettext("The list of root DSEs is empty: "
2172 "the Standalone mode was not properly initialized"));
2175 NS_CONFIG_NOTLOADED
,
2178 return (NS_LDAP_INTERNAL
);
2181 current_list
= dir_servers
.list
;
2182 (void) rw_rdlock(¤t_list
->listDestroyLock
);
2183 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2186 * The code below is mostly the clone of the
2187 * ldap_cachemgr::cachemgr_getldap.c::getldap_get_serverInfo() function.
2188 * Currently we have two different server lists: one is maintained
2189 * by libsldap ('standalone' mode), the other is in ldap_cachemgr
2190 * (a part of its standard functionality).
2194 * If NS_CACHE_NEW, or the server info is new,
2195 * starts from the beginning of the list.
2197 (void) mutex_lock(¤t_list
->nsServers
[0]->updateStatus
);
2198 if (strcmp(request
, NS_CACHE_NEW
) == 0 ||
2199 current_list
->nsServers
[0]->info
== INFO_STATUS_NEW
) {
2202 (void) mutex_unlock(¤t_list
->nsServers
[i
]->updateStatus
);
2204 for (i
= 0; current_list
->nsServers
[i
]; ++i
) {
2206 * Lock the updateStatus mutex to
2207 * make sure the server status stays the same
2208 * while the data is being processed.
2210 if (matched
== FALSE
&&
2211 strcmp(current_list
->nsServers
[i
]->ip
,
2214 if (strcmp(request
, NS_CACHE_NORESP
) == 0) {
2217 * if the server has already been removed,
2220 (void) mutex_lock(¤t_list
->
2221 nsServers
[i
]->updateStatus
);
2222 if (current_list
->nsServers
[i
]->status
==
2223 INFO_SERVER_REMOVED
) {
2224 (void) mutex_unlock(¤t_list
->
2229 (void) mutex_unlock(¤t_list
->
2234 * if the information is new,
2235 * give this server one more chance.
2237 (void) mutex_lock(¤t_list
->
2240 if (current_list
->nsServers
[i
]->info
==
2242 current_list
->nsServers
[i
]->status
==
2244 server
= current_list
->nsServers
[i
];
2245 (void) mutex_unlock(¤t_list
->
2251 * it is recommended that
2252 * before removing the
2253 * server from the list,
2254 * the server should be
2255 * contacted one more time
2256 * to make sure that it is
2257 * really unavailable.
2258 * For now, just trust the client
2259 * (i.e., the sldap library)
2260 * that it knows what it is
2261 * doing and would not try
2262 * to mess up the server
2265 current_list
->nsServers
[i
]->status
=
2266 INFO_SERVER_REMOVED
;
2267 (void) mutex_unlock(¤t_list
->
2274 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
2281 if (strcmp(request
, NS_CACHE_WRITE
) == 0) {
2283 * ldap_cachemgr checks here if the server
2284 * is not a non-replica server (a server
2285 * of type INFO_RW_WRITEABLE). But currently
2286 * it considers all the servers in its list
2289 (void) mutex_lock(¤t_list
->
2292 if (current_list
->nsServers
[i
]->status
==
2294 (void) mutex_unlock(¤t_list
->
2297 server
= current_list
->nsServers
[i
];
2301 (void) mutex_lock(¤t_list
->
2304 if (current_list
->nsServers
[i
]->status
==
2306 (void) mutex_unlock(¤t_list
->
2309 server
= current_list
->nsServers
[i
];
2314 (void) mutex_unlock(¤t_list
->
2320 if (server
== NULL
) {
2321 (void) rw_unlock(¤t_list
->listDestroyLock
);
2322 (void) snprintf(errmsg
,
2324 gettext("No servers are available"));
2327 NS_CONFIG_NOTLOADED
,
2330 return (NS_LDAP_NOTFOUND
);
2333 (void) mutex_lock(&server
->updateStatus
);
2334 server
->info
= INFO_STATUS_OLD
;
2335 (void) mutex_unlock(&server
->updateStatus
);
2338 (void) rw_unlock(¤t_list
->listDestroyLock
);
2339 return (NS_LDAP_SUCCESS
);
2342 if (strcmp(addrType
, NS_CACHE_ADDR_HOSTNAME
) == 0) {
2343 ret_code
= __s_api_ip2hostname(server
->ip
, &ret
->serverFQDN
);
2344 if (ret_code
!= NS_LDAP_SUCCESS
) {
2345 (void) snprintf(errmsg
,
2347 gettext("The %s address "
2348 "can not be resolved into "
2349 "a host name. Returning "
2350 "the address as it is."),
2354 NS_CONFIG_NOTLOADED
,
2357 return (NS_LDAP_INTERNAL
);
2361 ret
->server
= strdup(server
->ip
);
2363 ret
->controls
= __s_api_cp2dArray(server
->controls
);
2364 ret
->saslMechanisms
= __s_api_cp2dArray(server
->saslMech
);
2366 (void) rw_unlock(¤t_list
->listDestroyLock
);
2368 return (NS_LDAP_SUCCESS
);
2372 * This function iterates through the list of the configured LDAP servers
2373 * and "pings" those which are marked as removed or if any error occurred
2374 * during the previous receiving of the server's root DSE. If the
2375 * function is able to reach such a server and get its root DSE, it
2376 * marks the server as on-line. Otherwise, the server's status is set
2378 * For each server the function tries to connect to, it fires up
2379 * a separate thread and then waits until all the treads finish.
2380 * The function returns NS_LDAP_INTERNAL if the Standalone mode was not
2381 * initialized or was canceled prior to an invocation of
2382 * __ns_ldap_pingOfflineServers().
2385 __ns_ldap_pingOfflineServers(void)
2387 dir_server_list_t
*current_list
= NULL
;
2388 ns_ldap_return_code retCode
= NS_LDAP_SUCCESS
;
2389 long srvListLength
, i
= 0;
2390 thread_t
*thrPool
, thrID
;
2391 void *status
= NULL
;
2393 (void) mutex_lock(&dir_servers
.listReplaceLock
);
2394 if (dir_servers
.list
== NULL
) {
2395 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2396 return (NS_LDAP_INTERNAL
);
2399 current_list
= dir_servers
.list
;
2400 (void) rw_wrlock(¤t_list
->listDestroyLock
);
2401 (void) mutex_unlock(&dir_servers
.listReplaceLock
);
2403 while (current_list
->nsServers
[i
] != NULL
) {
2408 thrPool
= calloc(srvListLength
, sizeof (thread_t
));
2409 if (thrPool
== NULL
) {
2410 (void) rw_unlock(¤t_list
->listDestroyLock
);
2411 return (NS_LDAP_MEMORY
);
2414 for (i
= 0; i
< srvListLength
; ++i
) {
2415 if (current_list
->nsServers
[i
]->status
!= INFO_SERVER_REMOVED
&&
2416 current_list
->nsServers
[i
]->status
!= INFO_SERVER_ERROR
) {
2419 current_list
->nsServers
[i
]->status
= INFO_SERVER_CONNECTING
;
2420 current_list
->nsServers
[i
]->info
= INFO_STATUS_NEW
;
2422 __s_api_free2dArray(current_list
->nsServers
[i
]->controls
);
2423 current_list
->nsServers
[i
]->controls
= NULL
;
2424 __s_api_free2dArray(current_list
->nsServers
[i
]->saslMech
);
2425 current_list
->nsServers
[i
]->saslMech
= NULL
;
2427 switch (thr_create(NULL
,
2429 create_ns_servers_entry
,
2430 current_list
->nsServers
[i
],
2434 current_list
->nsServers
[i
]->status
= INFO_SERVER_ERROR
;
2437 current_list
->nsServers
[i
]->status
= INFO_SERVER_ERROR
;
2438 retCode
= NS_LDAP_MEMORY
;
2444 /* A memory allocation error has occured */
2449 for (i
= 0; i
< srvListLength
; ++i
) {
2450 if (thrPool
[i
] != 0 &&
2451 thr_join(thrPool
[i
], NULL
, &status
) == 0) {
2452 if (status
== NULL
) {
2453 current_list
->nsServers
[i
]->status
=
2455 retCode
= NS_LDAP_MEMORY
;
2461 (void) rw_unlock(¤t_list
->listDestroyLock
);