#define __STANDALONE_MODULE__
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <libintl.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <locale.h>
#include <errno.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <strings.h>
#include <thread.h>
#include <nsswitch.h>
#include <nss_dbdefs.h>
#include <nss.h>
#include "ns_cache_door.h"
#include "ns_internal.h"
#include "ns_connmgmt.h"
typedef enum {
INFO_SERVER_JUST_INITED = -1,
INFO_SERVER_UNKNOWN = 0,
INFO_SERVER_CONNECTING = 1,
INFO_SERVER_UP = 2,
INFO_SERVER_ERROR = 3,
INFO_SERVER_REMOVED = 4
} dir_server_status_t;
typedef enum {
INFO_STATUS_NEW = 2,
INFO_STATUS_OLD = 3
} dir_server_info_t;
typedef struct dir_server {
char *ip;
char **controls;
char **saslMech;
dir_server_status_t status;
mutex_t updateStatus;
dir_server_info_t info;
} dir_server_t;
typedef struct dir_server_list {
dir_server_t **nsServers;
rwlock_t listDestroyLock;
} dir_server_list_t;
struct {
dir_server_list_t *list;
int standalone;
mutex_t listReplaceLock;
const int initFlag;
thread_key_t standaloneInitKey;
} dir_servers = {NULL, 0, DEFAULTMUTEX, '1'};
typedef struct switchDatabase {
char *conf;
uint32_t alloced;
} switch_database_t;
static thread_key_t switchConfigKey;
#pragma init(createStandaloneKey)
#define DONT_INCLUDE_ATTR_NAMES 0
#define INCLUDE_ATTR_NAMES 1
#define IS_PROFILE 1
#define NOT_PROFILE 0
#define MAX_HOSTADDR_LEN (INET6_ADDRSTRLEN + 6 + 12)
static
void
switch_conf_disposer(void *data)
{
switch_database_t *localData = (switch_database_t *)data;
free(localData->conf);
free(localData);
}
static
void
createStandaloneKey()
{
if (thr_keycreate(&dir_servers.standaloneInitKey, NULL) != 0) {
syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
"key needed for sharing ldap connections"));
}
if (thr_keycreate(&switchConfigKey, switch_conf_disposer) != 0) {
syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
"key containing current nsswitch configuration"));
}
}
void
__s_api_setInitMode()
{
(void) thr_setspecific(dir_servers.standaloneInitKey,
(void *) &dir_servers.initFlag);
}
void
__s_api_unsetInitMode()
{
(void) thr_setspecific(dir_servers.standaloneInitKey, NULL);
}
int
__s_api_isInitializing() {
int *flag = NULL;
(void) thr_getspecific(dir_servers.standaloneInitKey, (void **) &flag);
return (flag != NULL && *flag == dir_servers.initFlag);
}
int
__s_api_isStandalone()
{
int mode;
(void) mutex_lock(&dir_servers.listReplaceLock);
mode = dir_servers.standalone;
(void) mutex_unlock(&dir_servers.listReplaceLock);
return (mode);
}
static
int
remove_ldap(char *dst, char *src, int dst_buf_len)
{
int i = 0;
if (strlen(src) >= dst_buf_len)
return (0);
while (*src != '\0') {
if (isspace(*src)) {
dst[i++] = *src;
while (isspace(*src))
src++;
}
if (strncmp(src, "ldap", 4) != 0) {
while (!isspace(*src)) {
dst[i++] = *src++;
if (dst[i-1] == '\0')
return (1);
}
if (isspace(*src)) {
dst[i++] = *src;
while (isspace(*src))
src++;
}
if (*src == '[')
while (*src != ']') {
dst[i++] = *src++;
if (dst[i-1] == '\0')
return (1);
}
}
if (strncmp(src, "ldap", 4) == 0) {
if (isspace(*(src+4)) || *(src+4) == '\0') {
src += 4;
while (isspace(*src))
src++;
if (*src == '[') {
while (*src++ != ']') {
if (*src == '\0') {
dst[i++] = '\0';
return (1);
}
}
}
while (isspace(*src))
src++;
}
}
if (*src == '\0')
dst[i++] = '\0';
}
return (1);
}
static
char *
get_db(const char *db_name)
{
char *ptr;
switch_database_t *hostService = NULL;
FILE *fp = fopen(__NSW_CONFIG_FILE, "rF");
char *linep, line[NSS_BUFSIZ];
if (fp == NULL) {
syslog(LOG_WARNING, gettext("libsldap: can not read %s"),
__NSW_CONFIG_FILE);
return (NULL);
}
while ((linep = fgets(line, NSS_BUFSIZ, fp)) != NULL) {
while (isspace(*linep)) {
++linep;
}
if (*linep == '#') {
continue;
}
if (strncmp(linep, db_name, strlen(db_name)) != 0) {
continue;
}
if ((linep = strchr(linep, ':')) != NULL) {
if (linep[strlen(linep) - 1] == '\n') {
linep[strlen(linep) - 1] = '\0';
}
while (isspace(*++linep))
;
if ((ptr = strchr(linep, '#')) != NULL) {
while (--ptr >= linep && isspace(*ptr))
;
*(ptr + 1) = '\0';
}
if (strlen(linep) == 0) {
continue;
}
break;
}
}
(void) fclose(fp);
if (linep == NULL) {
syslog(LOG_WARNING,
gettext("libsldap: the %s database "
"is missing from %s"),
db_name,
__NSW_CONFIG_FILE);
return (NULL);
}
(void) thr_getspecific(switchConfigKey, (void **) &hostService);
if (hostService == NULL) {
hostService = calloc(1, sizeof (switch_database_t));
if (hostService == NULL) {
return (NULL);
}
(void) thr_setspecific(switchConfigKey, hostService);
}
if (strlen(linep) >= hostService->alloced) {
ptr = (char *)realloc((void *)hostService->conf,
strlen(linep) + 1);
if (ptr == NULL) {
free((void *)hostService->conf);
hostService->conf = NULL;
hostService->alloced = 0;
return (NULL);
}
bzero(ptr, strlen(linep) + 1);
hostService->conf = ptr;
hostService->alloced = strlen(linep) + 1;
}
if (remove_ldap(hostService->conf, linep, hostService->alloced))
return (hostService->conf);
else
return (NULL);
}
static
void
_initf_ipnodes(nss_db_params_t *p)
{
char *services = get_db("ipnodes");
p->name = NSS_DBNAM_IPNODES;
p->flags |= NSS_USE_DEFAULT_CONFIG;
p->default_config = services == NULL ? "" : services;
}
static
void
_initf_hosts(nss_db_params_t *p)
{
char *services = get_db("hosts");
p->name = NSS_DBNAM_HOSTS;
p->flags |= NSS_USE_DEFAULT_CONFIG;
p->default_config = services == NULL ? "" : services;
}
static
struct hostent *
_filter_gethostbyaddr_r(const char *addr, int len, int type,
struct hostent *result, char *buffer, int buflen,
int *h_errnop)
{
DEFINE_NSS_DB_ROOT(db_root_hosts);
DEFINE_NSS_DB_ROOT(db_root_ipnodes);
nss_XbyY_args_t arg;
nss_status_t res;
int (*str2ent)();
void (*nss_initf)();
nss_db_root_t *nss_db_root;
int dbop;
switch (type) {
case AF_INET:
str2ent = str2hostent;
nss_initf = _initf_hosts;
nss_db_root = &db_root_hosts;
dbop = NSS_DBOP_HOSTS_BYADDR;
break;
case AF_INET6:
str2ent = str2hostent6;
nss_initf = _initf_ipnodes;
nss_db_root = &db_root_ipnodes;
dbop = NSS_DBOP_IPNODES_BYADDR;
break;
default:
return (NULL);
}
NSS_XbyY_INIT(&arg, result, buffer, buflen, str2ent);
arg.key.hostaddr.addr = addr;
arg.key.hostaddr.len = len;
arg.key.hostaddr.type = type;
arg.stayopen = 0;
arg.h_errno = NETDB_SUCCESS;
res = nss_search(nss_db_root, nss_initf, dbop, &arg);
arg.status = res;
*h_errnop = arg.h_errno;
return (struct hostent *)NSS_XbyY_FINI(&arg);
}
struct hostent *
__s_api_hostname2ip(const char *name,
struct hostent *result, char *buffer, int buflen,
int *h_errnop)
{
DEFINE_NSS_DB_ROOT(db_root_ipnodes);
DEFINE_NSS_DB_ROOT(db_root_hosts);
nss_XbyY_args_t arg;
nss_status_t res;
struct in_addr addr;
struct in6_addr addr6;
if (inet_pton(AF_INET, name, &addr) > 0) {
if (buflen < strlen(name) + 1 +
sizeof (char *) * 2 +
sizeof (struct in_addr) +
sizeof (struct in_addr *) * 2) {
*h_errnop = TRY_AGAIN;
return (NULL);
}
result->h_addrtype = AF_INET;
result->h_length = sizeof (struct in_addr);
(void) strncpy(buffer, name, buflen);
result->h_addr_list = (char **)ROUND_UP(
buffer + strlen(name) + 1,
sizeof (char *));
result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
sizeof (char *));
result->h_aliases[0] = buffer;
result->h_aliases[1] = NULL;
bcopy(&addr,
buffer + buflen - sizeof (struct in_addr),
sizeof (struct in_addr));
result->h_addr_list[0] = buffer + buflen -
sizeof (struct in_addr);
result->h_addr_list[1] = NULL;
result->h_aliases = result->h_addr_list;
result->h_name = buffer;
*h_errnop = NETDB_SUCCESS;
return (result);
}
if (inet_pton(AF_INET6, name, &addr6) > 0) {
if (buflen < strlen(name) + 1 +
sizeof (char *) * 2 +
sizeof (struct in6_addr) +
sizeof (struct in6_addr *) * 2) {
*h_errnop = TRY_AGAIN;
return (NULL);
}
result->h_addrtype = AF_INET6;
result->h_length = sizeof (struct in6_addr);
(void) strncpy(buffer, name, buflen);
result->h_addr_list = (char **)ROUND_UP(
buffer + strlen(name) + 1,
sizeof (char *));
result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
sizeof (char *));
result->h_aliases[0] = buffer;
result->h_aliases[1] = NULL;
bcopy(&addr6,
buffer + buflen - sizeof (struct in6_addr),
sizeof (struct in6_addr));
result->h_addr_list[0] = buffer + buflen -
sizeof (struct in6_addr);
result->h_addr_list[1] = NULL;
result->h_aliases = result->h_addr_list;
result->h_name = buffer;
*h_errnop = NETDB_SUCCESS;
return (result);
}
NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
arg.key.name = name;
arg.stayopen = 0;
arg.h_errno = NETDB_SUCCESS;
res = nss_search(&db_root_ipnodes, _initf_ipnodes,
NSS_DBOP_IPNODES_BYNAME, &arg);
if (res == NSS_NOTFOUND || res == NSS_UNAVAIL) {
arg.h_errno = NETDB_SUCCESS;
res = nss_search(&db_root_hosts, _initf_hosts,
NSS_DBOP_HOSTS_BYNAME, &arg);
}
arg.status = res;
*h_errnop = arg.h_errno;
return ((struct hostent *)NSS_XbyY_FINI(&arg));
}
ns_ldap_return_code
__s_api_ip2hostname(char *ipaddr, char **hostname) {
struct in_addr in;
struct in6_addr in6;
struct hostent *hp = NULL, hostEnt;
char buffer[NSS_BUFLEN_HOSTS];
int buflen = NSS_BUFLEN_HOSTS;
char *start = NULL,
*end = NULL,
delim = '\0';
char *port = NULL,
*addr = NULL;
int errorNum = 0,
len = 0;
if (ipaddr == NULL || hostname == NULL)
return (NS_LDAP_INVALID_PARAM);
*hostname = NULL;
if ((addr = strdup(ipaddr)) == NULL)
return (NS_LDAP_MEMORY);
if (addr[0] == '[') {
start = &addr[1];
if ((end = strchr(addr, ']')) != NULL) {
*end = '\0';
delim = ']';
if (*(end + 1) == ':')
port = end + 2;
} else {
free(addr);
return (NS_LDAP_INVALID_PARAM);
}
} else if ((end = strchr(addr, ':')) != NULL) {
*end = '\0';
delim = ':';
start = addr;
port = end + 1;
} else
start = addr;
if (inet_pton(AF_INET, start, &in) == 1) {
hp = _filter_gethostbyaddr_r((char *)&in,
sizeof (in.s_addr),
AF_INET,
&hostEnt,
buffer,
buflen,
&errorNum);
if (hp && hp->h_name) {
len = strlen(hp->h_name) + 1;
if (port)
len += strlen(port) + 1;
if ((*hostname = malloc(len)) == NULL) {
free(addr);
return (NS_LDAP_MEMORY);
}
if (port)
(void) snprintf(*hostname, len, "%s:%s",
hp->h_name, port);
else
(void) strlcpy(*hostname, hp->h_name, len);
free(addr);
return (NS_LDAP_SUCCESS);
} else {
free(addr);
return (NS_LDAP_NOTFOUND);
}
} else if (inet_pton(AF_INET6, start, &in6) == 1) {
hp = _filter_gethostbyaddr_r((char *)&in6,
sizeof (in6.s6_addr),
AF_INET6,
&hostEnt,
buffer,
buflen,
&errorNum);
if (hp && hp->h_name) {
len = strlen(hp->h_name) + 1;
if (port)
len += strlen(port) + 1;
if ((*hostname = malloc(len)) == NULL) {
free(addr);
return (NS_LDAP_MEMORY);
}
if (port)
(void) snprintf(*hostname, len, "%s:%s",
hp->h_name, port);
else
(void) strlcpy(*hostname, hp->h_name, len);
free(addr);
return (NS_LDAP_SUCCESS);
} else {
free(addr);
return (NS_LDAP_NOTFOUND);
}
} else {
if (end)
*end = delim;
*hostname = addr;
return (NS_LDAP_SUCCESS);
}
}
static
ns_ldap_return_code
convert_to_door_line(LDAP* ld,
LDAPMessage *result_msg,
int include_names,
int is_profile,
char **door_line)
{
uint32_t total_length = 0, attr_len = 0, i;
LDAPMessage *e;
char *a, **vals;
BerElement *ber;
int seen_objectclass = 0, rewind = 0;
if (!door_line) {
return (NS_LDAP_INVALID_PARAM);
}
*door_line = NULL;
if ((e = ldap_first_entry(ld, result_msg)) == NULL) {
return (NS_LDAP_NOTFOUND);
}
for (a = ldap_first_attribute(ld, e, &ber);
a != NULL;
a = ldap_next_attribute(ld, e, ber)) {
if ((vals = ldap_get_values(ld, e, a)) != NULL) {
for (i = 0; vals[i] != NULL; i++) {
total_length += (include_names ?
strlen(a) : 0) +
strlen(vals[i]) +
strlen(DOORLINESEP) +1;
}
ldap_value_free(vals);
}
ldap_memfree(a);
}
if (ber != NULL) {
ber_free(ber, 0);
}
if (total_length == 0) {
return (NS_LDAP_NOTFOUND);
}
*door_line = (char *)malloc(total_length + 1);
if (*door_line == NULL) {
return (NS_LDAP_MEMORY);
}
**door_line = '\0';
a = ldap_first_attribute(ld, e, &ber);
while (a != NULL) {
if (is_profile) {
if (seen_objectclass) {
if (strcasecmp(a, "objectclass") == 0) {
a = ldap_next_attribute(ld, e, ber);
continue;
}
} else {
if (strcasecmp(a, "objectclass") == 0) {
seen_objectclass = 1;
rewind = 1;
} else {
a = ldap_next_attribute(ld, e, ber);
continue;
}
}
}
if ((vals = ldap_get_values(ld, e, a)) != NULL) {
for (i = 0; vals[i] != NULL; i++) {
if (include_names) {
attr_len += strlen(a);
}
attr_len += strlen(vals[i]) +
strlen(DOORLINESEP) + 2;
if (include_names) {
(void) snprintf(*door_line +
strlen(*door_line),
attr_len,
"%s=%s%s",
a, vals[i],
DOORLINESEP);
} else {
(void) snprintf(*door_line +
strlen(*door_line),
attr_len,
"%s%s",
vals[i],
DOORLINESEP);
}
}
ldap_value_free(vals);
}
ldap_memfree(a);
if (rewind) {
if (ber != NULL) {
ber_free(ber, 0);
}
a = ldap_first_attribute(ld, e, &ber);
rewind = 0;
} else {
a = ldap_next_attribute(ld, e, ber);
}
}
if (ber != NULL) {
ber_free(ber, 0);
}
if (e != result_msg) {
(void) ldap_msgfree(e);
}
return (NS_LDAP_SUCCESS);
}
static
ns_ldap_return_code
getDirBaseDN(LDAP *ld, const char *domain_name, char **dir_base_dn)
{
struct timeval tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
char *attrs[2], *DNlist, *rest, *ptr;
char filter[BUFSIZ], *a = NULL;
int ldap_rc;
LDAPMessage *resultMsg = NULL;
ns_ldap_return_code ret_code;
attrs[0] = "namingcontexts";
attrs[1] = NULL;
ldap_rc = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
attrs, 0, NULL, NULL, &tv, 0, &resultMsg);
switch (ldap_rc) {
case LDAP_SUCCESS:
break;
default:
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
return (NS_LDAP_OP_FAILED);
}
if ((ret_code = convert_to_door_line(ld,
resultMsg,
DONT_INCLUDE_ATTR_NAMES,
NOT_PROFILE,
&DNlist)) != NS_LDAP_SUCCESS) {
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
return (ret_code);
}
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
if (DNlist == NULL ||
(ptr = strtok_r(DNlist, DOORLINESEP, &rest)) == NULL) {
return (NS_LDAP_NOTFOUND);
}
attrs[0] = "dn";
do {
(void) snprintf(filter,
BUFSIZ,
"(&(objectclass=nisDomainObject)"
"(nisdomain=%s))",
domain_name);
ldap_rc = ldap_search_ext_s(ld,
ptr,
LDAP_SCOPE_SUBTREE,
filter,
attrs,
0,
NULL,
NULL,
&tv,
0,
&resultMsg);
if (ldap_rc != LDAP_SUCCESS) {
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
continue;
}
if ((a = ldap_get_dn(ld, resultMsg)) != NULL) {
*dir_base_dn = strdup(a);
ldap_memfree(a);
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
if (!*dir_base_dn) {
free(DNlist);
return (NS_LDAP_MEMORY);
}
break;
}
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
} while (ptr = strtok_r(NULL, DOORLINESEP, &rest));
free(DNlist);
if (!*dir_base_dn) {
return (NS_LDAP_NOTFOUND);
}
return (NS_LDAP_SUCCESS);
}
static
ns_ldap_return_code
getDUAProfile(LDAP *ld,
const char *dir_base_dn,
const char *profile_name,
char **profile)
{
char searchBaseDN[BUFSIZ], filter[BUFSIZ];
LDAPMessage *resultMsg = NULL;
struct timeval tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
int ldap_rc;
ns_ldap_return_code ret_code;
(void) snprintf(searchBaseDN, BUFSIZ, "ou=profile,%s", dir_base_dn);
(void) snprintf(filter,
BUFSIZ,
_PROFILE_FILTER,
_PROFILE1_OBJECTCLASS,
_PROFILE2_OBJECTCLASS,
profile_name);
ldap_rc = ldap_search_ext_s(ld,
searchBaseDN,
LDAP_SCOPE_SUBTREE,
filter,
NULL,
0,
NULL,
NULL,
&tv,
0,
&resultMsg);
switch (ldap_rc) {
case LDAP_SUCCESS:
break;
default:
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
return (NS_LDAP_OP_FAILED);
}
ret_code = convert_to_door_line(ld,
resultMsg,
INCLUDE_ATTR_NAMES,
IS_PROFILE,
profile);
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
return (ret_code);
}
static
char *
domainname2baseDN(char *domain_name, char *buffer, uint16_t buf_len)
{
char *nextDC, *chr;
uint16_t i, length;
if (!domain_name || !buffer || buf_len == 0) {
return (NULL);
}
buffer[0] = '\0';
nextDC = chr = domain_name;
length = strlen(domain_name);
for (i = 0; i < length + 1; ++i, ++chr) {
if (*chr != '.' && *chr != '\0') {
continue;
}
*chr = '\0';
if (strlcat(buffer, "dc=", buf_len) >= buf_len)
return (NULL);
if (strlcat(buffer, nextDC, buf_len) >= buf_len)
return (NULL);
if (i < length) {
if (strlcat(buffer, ",", buf_len) >= buf_len)
return (NULL);
nextDC = chr + 1;
*chr = '.';
}
}
return (buffer);
}
ns_ldap_return_code
__ns_ldap_getConnectionInfoFromDUA(const ns_dir_server_t *server,
const ns_cred_t *cred,
char **dua_profile,
char **dir_base_dn,
ns_ldap_error_t **errorp)
{
char serverAddr[MAX_HOSTADDR_LEN];
char *dirBaseDN = NULL, *duaProfile = NULL;
ns_cred_t default_cred;
ns_ldap_return_code ret_code;
ns_config_t *config_struct = __s_api_create_config();
ConnectionID sessionId = 0;
Connection *session = NULL;
char errmsg[MAXERROR];
char buffer[NSS_BUFLEN_HOSTS];
ns_conn_user_t *cu = NULL;
if (errorp == NULL) {
__s_api_destroy_config(config_struct);
return (NS_LDAP_INVALID_PARAM);
}
*errorp = NULL;
if (server == NULL) {
__s_api_destroy_config(config_struct);
return (NS_LDAP_INVALID_PARAM);
}
if (config_struct == NULL) {
return (NS_LDAP_MEMORY);
}
if (!cred) {
default_cred.cred.unix_cred.passwd = NULL;
default_cred.cred.unix_cred.userID = NULL;
default_cred.auth.type = NS_LDAP_AUTH_NONE;
}
(void) strncpy(buffer, server->server, sizeof (buffer));
if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SERVERS_P, buffer,
errorp) != NS_LDAP_SUCCESS) {
__s_api_destroy_config(config_struct);
return (NS_LDAP_CONFIG);
}
if (server->port > 0) {
(void) snprintf(serverAddr,
sizeof (serverAddr),
"%s:%hu",
buffer,
server->port);
} else {
(void) strncpy(serverAddr, buffer, sizeof (serverAddr));
}
if (domainname2baseDN(server->domainName ?
server->domainName : config_struct->domainName,
buffer, NSS_BUFLEN_HOSTS) == NULL) {
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("Can not convert %s into a base DN name"),
server->domainName ?
server->domainName : config_struct->domainName);
MKERROR(LOG_ERR,
*errorp,
NS_LDAP_INTERNAL,
strdup(errmsg),
NS_LDAP_MEMORY);
__s_api_destroy_config(config_struct);
return (NS_LDAP_INTERNAL);
}
if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SEARCH_BASEDN_P,
buffer, errorp) != NS_LDAP_SUCCESS) {
__s_api_destroy_config(config_struct);
return (NS_LDAP_CONFIG);
}
if (__s_api_crosscheck(config_struct, errmsg, B_FALSE) != NS_SUCCESS) {
__s_api_destroy_config(config_struct);
return (NS_LDAP_CONFIG);
}
__s_api_init_config(config_struct);
__s_api_setInitMode();
cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE);
if (cu == NULL) {
return (NS_LDAP_INTERNAL);
}
if ((ret_code = __s_api_getConnection(serverAddr,
NS_LDAP_NEW_CONN,
cred ? cred : &default_cred,
&sessionId,
&session,
errorp,
0,
0,
cu)) != NS_LDAP_SUCCESS) {
__s_api_conn_user_free(cu);
__s_api_unsetInitMode();
return (ret_code);
}
__s_api_unsetInitMode();
if ((ret_code = getDirBaseDN(session->ld,
server->domainName ?
server->domainName :
config_struct->domainName,
&dirBaseDN)) != NS_LDAP_SUCCESS) {
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("Can not find the "
"nisDomainObject for domain %s\n"),
server->domainName ?
server->domainName : config_struct->domainName);
MKERROR(LOG_ERR,
*errorp,
ret_code,
strdup(errmsg),
NS_LDAP_MEMORY);
__s_api_conn_user_free(cu);
DropConnection(sessionId, NS_LDAP_NEW_CONN);
return (ret_code);
}
if ((ret_code = getDUAProfile(session->ld,
dirBaseDN,
server->profileName ?
server->profileName : "default",
&duaProfile)) != NS_LDAP_SUCCESS) {
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("Can not find the "
"%s DUAProfile\n"),
server->profileName ?
server->profileName : "default");
MKERROR(LOG_ERR,
*errorp,
ret_code,
strdup(errmsg),
NS_LDAP_MEMORY);
__s_api_conn_user_free(cu);
DropConnection(sessionId, NS_LDAP_NEW_CONN);
return (ret_code);
}
if (dir_base_dn) {
*dir_base_dn = dirBaseDN;
} else {
free(dirBaseDN);
}
if (dua_profile) {
*dua_profile = duaProfile;
} else {
free(duaProfile);
}
__s_api_conn_user_free(cu);
DropConnection(sessionId, NS_LDAP_NEW_CONN);
return (NS_LDAP_SUCCESS);
}
ns_ldap_return_code
__ns_ldap_getRootDSE(const char *server_addr,
char **root_dse,
ns_ldap_error_t **errorp,
int anon_fallback)
{
char errmsg[MAXERROR];
ns_ldap_return_code ret_code;
ConnectionID sessionId = 0;
Connection *session = NULL;
struct timeval tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
char *attrs[3];
int ldap_rc, ldaperrno = 0;
LDAPMessage *resultMsg = NULL;
void **paramVal = NULL;
ns_cred_t anon;
ns_conn_user_t *cu = NULL;
if (errorp == NULL) {
return (NS_LDAP_INVALID_PARAM);
}
*errorp = NULL;
if (!root_dse) {
return (NS_LDAP_INVALID_PARAM);
}
if (!server_addr) {
return (NS_LDAP_INVALID_PARAM);
}
__s_api_setInitMode();
cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE);
if (cu == NULL) {
return (NS_LDAP_INTERNAL);
}
if ((ret_code = __s_api_getConnection(server_addr,
NS_LDAP_NEW_CONN,
NULL,
&sessionId,
&session,
errorp,
0,
0,
cu)) != NS_LDAP_SUCCESS) {
if (anon_fallback == 0) {
syslog(LOG_WARNING,
gettext("libsldap: can not get the root DSE from "
" the %s server: %s. "
"Falling back to anonymous disabled.\n"),
server_addr,
errorp && *errorp && (*errorp)->message ?
(*errorp)->message : "");
if (errorp != NULL && *errorp != NULL) {
(void) __ns_ldap_freeError(errorp);
}
__s_api_unsetInitMode();
return (ret_code);
}
syslog(LOG_WARNING,
gettext("libsldap: Falling back to anonymous, non-SSL"
" mode for __ns_ldap_getRootDSE. %s\n"),
errorp && *errorp && (*errorp)->message ?
(*errorp)->message : "");
(void) memset(&anon, 0, sizeof (ns_cred_t));
anon.auth.type = NS_LDAP_AUTH_NONE;
if (*errorp != NULL) {
(void) __ns_ldap_freeError(errorp);
}
*errorp = NULL;
ret_code = __s_api_getConnection(server_addr,
NS_LDAP_NEW_CONN,
&anon,
&sessionId,
&session,
errorp,
0,
0,
cu);
if (ret_code != NS_LDAP_SUCCESS) {
__s_api_conn_user_free(cu);
__s_api_unsetInitMode();
return (ret_code);
}
}
__s_api_unsetInitMode();
(void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P, ¶mVal, errorp);
if (paramVal != NULL && *paramVal != NULL) {
tv.tv_sec = **((int **)paramVal);
(void) __ns_ldap_freeParam(¶mVal);
}
if (*errorp != NULL) {
(void) __ns_ldap_freeError(errorp);
}
attrs[0] = "supportedControl";
attrs[1] = "supportedsaslmechanisms";
attrs[2] = NULL;
ldap_rc = ldap_search_ext_s(session->ld,
"",
LDAP_SCOPE_BASE,
"(objectclass=*)",
attrs,
0,
NULL,
NULL,
&tv,
0,
&resultMsg);
if (ldap_rc != LDAP_SUCCESS) {
(void) ldap_get_option(session->ld,
LDAP_OPT_ERROR_NUMBER,
&ldaperrno);
(void) snprintf(errmsg,
sizeof (errmsg),
gettext(ldap_err2string(ldaperrno)));
MKERROR(LOG_ERR,
*errorp,
NS_LDAP_OP_FAILED,
strdup(errmsg),
NS_LDAP_MEMORY);
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
__s_api_conn_user_free(cu);
DropConnection(sessionId, NS_LDAP_NEW_CONN);
return (NS_LDAP_OP_FAILED);
}
__s_api_conn_user_free(cu);
ret_code = convert_to_door_line(session->ld,
resultMsg,
INCLUDE_ATTR_NAMES,
NOT_PROFILE,
root_dse);
if (ret_code == NS_LDAP_NOTFOUND) {
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("No root DSE data "
"for server %s returned."),
server_addr);
MKERROR(LOG_ERR,
*errorp,
NS_LDAP_NOTFOUND,
strdup(errmsg),
NS_LDAP_MEMORY);
}
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
resultMsg = NULL;
}
DropConnection(sessionId, NS_LDAP_NEW_CONN);
return (ret_code);
}
static
void *
disposeOfOldList(void *param)
{
dir_server_list_t *old_list = (dir_server_list_t *)param;
long i = 0, j;
(void) rw_wrlock(&old_list->listDestroyLock);
while (old_list->nsServers[i]) {
free(old_list->nsServers[i]->ip);
j = 0;
while (old_list->nsServers[i]->controls &&
old_list->nsServers[i]->controls[j]) {
free(old_list->nsServers[i]->controls[j]);
++j;
}
free(old_list->nsServers[i]->controls);
j = 0;
while (old_list->nsServers[i]->saslMech &&
old_list->nsServers[i]->saslMech[j]) {
free(old_list->nsServers[i]->saslMech[j]);
++j;
}
free(old_list->nsServers[i]->saslMech);
++i;
}
free(old_list->nsServers[0]);
free(old_list->nsServers);
(void) rw_unlock(&old_list->listDestroyLock);
(void) rwlock_destroy(&old_list->listDestroyLock);
free(old_list);
return (NULL);
}
void
__ns_ldap_cancelStandalone(void)
{
dir_server_list_t *old_list;
(void) mutex_lock(&dir_servers.listReplaceLock);
dir_servers.standalone = 0;
if (!dir_servers.list) {
(void) mutex_unlock(&dir_servers.listReplaceLock);
return;
}
old_list = dir_servers.list;
dir_servers.list = NULL;
(void) mutex_unlock(&dir_servers.listReplaceLock);
(void) disposeOfOldList(old_list);
}
static
void*
create_ns_servers_entry(void *param)
{
#define CHUNK_SIZE 16
dir_server_t *server = (dir_server_t *)param;
ns_ldap_return_code *retCode = calloc(1,
sizeof (ns_ldap_return_code));
uint32_t sc_counter = 0, sm_counter = 0;
uint32_t sc_mem_blocks = 1, sm_mem_blocks = 1;
char *rootDSE = NULL, *attr, *val, *rest, **ptr;
ns_ldap_error_t *error = NULL;
if (retCode == NULL) {
return (NULL);
}
*retCode = __ns_ldap_getRootDSE(server->ip,
&rootDSE,
&error,
SA_ALLOW_FALLBACK);
if (*retCode == NS_LDAP_MEMORY) {
free(retCode);
return (NULL);
}
if (*retCode != NS_LDAP_SUCCESS) {
server->status = INFO_SERVER_ERROR;
syslog(LOG_WARNING,
gettext("libsldap (\"standalone\" mode): "
"can not obtain the root DSE from %s. %s"),
server->ip,
error && error->message ? error->message : "");
if (error) {
(void) __ns_ldap_freeError(&error);
}
return (retCode);
}
attr = strtok_r(rootDSE, DOORLINESEP, &rest);
if (attr == NULL) {
free(rootDSE);
server->status = INFO_SERVER_ERROR;
syslog(LOG_WARNING,
gettext("libsldap (\"standalone\" mode): "
"the root DSE from %s is empty or corrupted."),
server->ip);
*retCode = NS_LDAP_INTERNAL;
return (retCode);
}
server->controls = (char **)calloc(CHUNK_SIZE, sizeof (char *));
server->saslMech = (char **)calloc(CHUNK_SIZE, sizeof (char *));
if (server->controls == NULL || server->saslMech == NULL) {
free(rootDSE);
free(retCode);
return (NULL);
}
do {
if ((val = strchr(attr, '=')) == NULL) {
continue;
}
++val;
if (strncasecmp(attr,
_SASLMECHANISM,
_SASLMECHANISM_LEN) == 0) {
if (sm_counter == CHUNK_SIZE * sm_mem_blocks - 1) {
ptr = (char **)realloc(server->saslMech,
CHUNK_SIZE *
++sm_mem_blocks *
sizeof (char *));
if (ptr == NULL) {
*retCode = NS_LDAP_MEMORY;
break;
}
bzero((char *)ptr +
(sm_counter + 1) *
sizeof (char *),
CHUNK_SIZE *
sm_mem_blocks *
sizeof (char *) -
(sm_counter + 1) *
sizeof (char *));
server->saslMech = ptr;
}
server->saslMech[sm_counter] = strdup(val);
if (server->saslMech[sm_counter] == NULL) {
*retCode = NS_LDAP_MEMORY;
break;
}
++sm_counter;
continue;
}
if (strncasecmp(attr,
_SUPPORTEDCONTROL,
_SUPPORTEDCONTROL_LEN) == 0) {
if (sc_counter == CHUNK_SIZE * sc_mem_blocks - 1) {
ptr = (char **)realloc(server->controls,
CHUNK_SIZE *
++sc_mem_blocks *
sizeof (char *));
if (ptr == NULL) {
*retCode = NS_LDAP_MEMORY;
break;
}
bzero((char *)ptr +
(sc_counter + 1) *
sizeof (char *),
CHUNK_SIZE *
sc_mem_blocks *
sizeof (char *) -
(sc_counter + 1) *
sizeof (char *));
server->controls = ptr;
}
server->controls[sc_counter] = strdup(val);
if (server->controls[sc_counter] == NULL) {
*retCode = NS_LDAP_MEMORY;
break;
}
++sc_counter;
continue;
}
} while (attr = strtok_r(NULL, DOORLINESEP, &rest));
free(rootDSE);
if (*retCode == NS_LDAP_MEMORY) {
free(retCode);
return (NULL);
}
server->controls[sc_counter] = NULL;
server->saslMech[sm_counter] = NULL;
server->status = INFO_SERVER_UP;
return (retCode);
#undef CHUNK_SIZE
}
static
ns_ldap_return_code
createDirServerList(dir_server_list_t **new_list,
ns_ldap_error_t **errorp)
{
char **serverList;
ns_ldap_return_code retCode = NS_LDAP_SUCCESS;
dir_server_t *tmpSrvArray;
long srvListLength, i;
thread_t *thrPool, thrID;
void *status = NULL;
if (errorp == NULL) {
return (NS_LDAP_INVALID_PARAM);
}
*errorp = NULL;
if (new_list == NULL) {
return (NS_LDAP_INVALID_PARAM);
}
retCode = __s_api_getServers(&serverList, errorp);
if (retCode != NS_LDAP_SUCCESS || serverList == NULL) {
return (retCode);
}
for (i = 0; serverList[i]; ++i) {
;
}
srvListLength = i;
thrPool = calloc(srvListLength, sizeof (thread_t));
if (thrPool == NULL) {
__s_api_free2dArray(serverList);
return (NS_LDAP_MEMORY);
}
*new_list = (dir_server_list_t *)calloc(1,
sizeof (dir_server_list_t));
if (*new_list == NULL) {
__s_api_free2dArray(serverList);
free(thrPool);
return (NS_LDAP_MEMORY);
}
(void) rwlock_init(&(*new_list)->listDestroyLock, USYNC_THREAD, NULL);
(*new_list)->nsServers = (dir_server_t **)calloc(srvListLength + 1,
sizeof (dir_server_t *));
if ((*new_list)->nsServers == NULL) {
free(*new_list);
*new_list = NULL;
__s_api_free2dArray(serverList);
free(thrPool);
return (NS_LDAP_MEMORY);
}
tmpSrvArray = (dir_server_t *)calloc(srvListLength,
sizeof (dir_server_t));
for (i = 0; i < srvListLength; ++i) {
(*new_list)->nsServers[i] = &tmpSrvArray[i];
(*new_list)->nsServers[i]->info = INFO_STATUS_NEW;
(void) mutex_init(&(*new_list)->nsServers[i]->updateStatus,
USYNC_THREAD,
NULL);
(*new_list)->nsServers[i]->ip = strdup(serverList[i]);
if ((*new_list)->nsServers[i]->ip == NULL) {
retCode = NS_LDAP_MEMORY;
break;
}
(*new_list)->nsServers[i]->status = INFO_SERVER_CONNECTING;
switch (thr_create(NULL,
0,
create_ns_servers_entry,
(*new_list)->nsServers[i],
0,
&thrID)) {
case EAGAIN:
(*new_list)->nsServers[i]->status =
INFO_SERVER_ERROR;
continue;
case ENOMEM:
(*new_list)->nsServers[i]->status =
INFO_SERVER_ERROR;
continue;
default:
thrPool[i] = thrID;
continue;
}
}
for (i = 0; i < srvListLength; ++i) {
if (thrPool[i] != 0 &&
thr_join(thrPool[i], NULL, &status) == 0) {
if (status == NULL) {
(*new_list)->nsServers[i]->status =
INFO_SERVER_ERROR;
}
free(status);
}
}
__s_api_free2dArray(serverList);
free(thrPool);
if (retCode == NS_LDAP_MEMORY) {
(void) disposeOfOldList(*new_list);
return (NS_LDAP_MEMORY);
}
return (NS_LDAP_SUCCESS);
}
static
ns_ldap_return_code
initGlobalList(ns_ldap_error_t **error)
{
dir_server_list_t *new_list, *old_list;
ns_ldap_return_code ret_code;
thread_t tid;
ret_code = createDirServerList(&new_list, error);
if (ret_code != NS_LDAP_SUCCESS) {
return (ret_code);
}
old_list = dir_servers.list;
dir_servers.list = new_list;
if (old_list) {
(void) thr_create(NULL,
0,
disposeOfOldList,
old_list,
THR_DETACHED,
&tid);
}
return (NS_LDAP_SUCCESS);
}
static
struct {
char *authMech;
ns_auth_t auth;
} authArray[] = {{"none", {NS_LDAP_AUTH_NONE,
NS_LDAP_TLS_NONE,
NS_LDAP_SASL_NONE,
NS_LDAP_SASLOPT_NONE}},
{"simple", {NS_LDAP_AUTH_SIMPLE,
NS_LDAP_TLS_NONE,
NS_LDAP_SASL_NONE,
NS_LDAP_SASLOPT_NONE}},
{"tls:simple", {NS_LDAP_AUTH_TLS,
NS_LDAP_TLS_SIMPLE,
NS_LDAP_SASL_NONE,
NS_LDAP_SASLOPT_NONE}},
{"tls:sasl/CRAM-MD5", {NS_LDAP_AUTH_TLS,
NS_LDAP_TLS_SASL,
NS_LDAP_SASL_CRAM_MD5,
NS_LDAP_SASLOPT_NONE}},
{"tls:sasl/DIGEST-MD5", {NS_LDAP_AUTH_TLS,
NS_LDAP_TLS_SASL,
NS_LDAP_SASL_DIGEST_MD5,
NS_LDAP_SASLOPT_NONE}},
{"sasl/CRAM-MD5", {NS_LDAP_AUTH_SASL,
NS_LDAP_TLS_SASL,
NS_LDAP_SASL_CRAM_MD5,
NS_LDAP_SASLOPT_NONE}},
{"sasl/DIGEST-MD5", {NS_LDAP_AUTH_SASL,
NS_LDAP_TLS_SASL,
NS_LDAP_SASL_DIGEST_MD5,
NS_LDAP_SASLOPT_NONE}},
{"sasl/GSSAPI", {NS_LDAP_AUTH_SASL,
NS_LDAP_TLS_SASL,
NS_LDAP_SASL_GSSAPI,
NS_LDAP_SASLOPT_PRIV | NS_LDAP_SASLOPT_INT}},
{NULL, {NS_LDAP_AUTH_NONE,
NS_LDAP_TLS_NONE,
NS_LDAP_SASL_NONE,
NS_LDAP_SASLOPT_NONE}}};
ns_ldap_return_code
__ns_ldap_initAuth(const char *auth_mech,
ns_auth_t *auth,
ns_ldap_error_t **errorp)
{
uint32_t i;
char errmsg[MAXERROR];
if (auth_mech == NULL) {
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("Invalid authentication method specified\n"));
MKERROR(LOG_WARNING,
*errorp,
NS_LDAP_INTERNAL,
strdup(errmsg),
NS_LDAP_MEMORY);
return (NS_LDAP_INTERNAL);
}
for (i = 0; authArray[i].authMech != NULL; ++i) {
if (strcasecmp(auth_mech, authArray[i].authMech) == 0) {
*auth = authArray[i].auth;
return (NS_LDAP_SUCCESS);
}
}
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("Invalid authentication method specified\n"));
MKERROR(LOG_WARNING,
*errorp,
NS_LDAP_INTERNAL,
strdup(errmsg),
NS_LDAP_MEMORY);
return (NS_LDAP_INTERNAL);
}
ns_ldap_return_code
__ns_ldap_initStandalone(const ns_standalone_conf_t *sa_conf,
ns_ldap_error_t **errorp) {
ns_cred_t user_cred = {{NS_LDAP_AUTH_NONE,
NS_LDAP_TLS_NONE,
NS_LDAP_SASL_NONE,
NS_LDAP_SASLOPT_NONE},
NULL,
{NULL, NULL}};
char *dua_profile = NULL;
char errmsg[MAXERROR];
ns_config_t *cfg;
int ret_code;
if (sa_conf->SA_BIND_DN == NULL && sa_conf->SA_BIND_PWD != NULL ||
sa_conf->SA_BIND_DN != NULL && sa_conf->SA_BIND_PWD == NULL) {
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("Bind DN and bind password"
" must both be provided\n"));
MKERROR(LOG_ERR,
*errorp,
NS_CONFIG_NOTLOADED,
strdup(errmsg),
NS_LDAP_MEMORY);
return (NS_LDAP_INTERNAL);
}
switch (sa_conf->type) {
case NS_LDAP_SERVER:
if (sa_conf->SA_BIND_DN != NULL) {
user_cred.cred.unix_cred.userID = sa_conf->SA_BIND_DN;
user_cred.auth.type = NS_LDAP_AUTH_SIMPLE;
}
if (sa_conf->SA_BIND_PWD != NULL) {
user_cred.cred.unix_cred.passwd = sa_conf->SA_BIND_PWD;
}
if (sa_conf->SA_AUTH != NULL) {
user_cred.auth.type = sa_conf->SA_AUTH->type;
user_cred.auth.tlstype = sa_conf->SA_AUTH->tlstype;
user_cred.auth.saslmech = sa_conf->SA_AUTH->saslmech;
user_cred.auth.saslopt = sa_conf->SA_AUTH->saslopt;
}
if (sa_conf->SA_CERT_PATH != NULL) {
user_cred.hostcertpath = sa_conf->SA_CERT_PATH;
}
ret_code = __ns_ldap_getConnectionInfoFromDUA(
&sa_conf->ds_profile.server,
&user_cred,
&dua_profile,
NULL,
errorp);
if (ret_code != NS_LDAP_SUCCESS) {
return (ret_code);
}
cfg = __s_api_create_config_door_str(dua_profile, errorp);
if (cfg == NULL) {
free(dua_profile);
return (NS_LDAP_CONFIG);
}
if (sa_conf->SA_CERT_PATH != NULL) {
char *certPathAttr;
ParamIndexType type;
switch (cfg->version) {
case NS_LDAP_V1:
certPathAttr = "NS_LDAP_CERT_PATH";
break;
default:
certPathAttr = "NS_LDAP_HOST_CERTPATH";
break;
}
if (__s_api_get_versiontype(cfg,
certPathAttr,
&type) == 0 &&
(ret_code = __ns_ldap_setParamValue(cfg,
type,
sa_conf->SA_CERT_PATH,
errorp)) != NS_LDAP_SUCCESS) {
__s_api_destroy_config(cfg);
return (ret_code);
}
}
if (sa_conf->SA_BIND_DN != NULL &&
sa_conf->SA_BIND_PWD != NULL) {
char *authMethods;
authMethods = __s_api_strValue(cfg, NS_LDAP_AUTH_P,
NS_FILE_FMT);
if (authMethods != NULL &&
strstr(authMethods, "sasl/GSSAPI") != NULL) {
syslog(LOG_INFO, gettext("sasl/GSSAPI will be "
"used as an authentication method. "
"The bind DN and password will "
"be ignored.\n"));
free(authMethods);
break;
}
if (authMethods != NULL)
free(authMethods);
if (__ns_ldap_setParamValue(cfg,
NS_LDAP_BINDDN_P,
sa_conf->SA_BIND_DN,
errorp) != NS_LDAP_SUCCESS) {
__s_api_destroy_config(cfg);
return (NS_LDAP_CONFIG);
}
if (__ns_ldap_setParamValue(cfg,
NS_LDAP_BINDPASSWD_P,
sa_conf->SA_BIND_PWD,
errorp) != NS_LDAP_SUCCESS) {
__s_api_destroy_config(cfg);
return (NS_LDAP_CONFIG);
}
}
break;
default:
return (NS_LDAP_SUCCESS);
}
__s_api_init_config(cfg);
__s_api_reinit_conn_mgmt_new_config(cfg);
__ns_ldap_setServer(TRUE);
(void) mutex_lock(&dir_servers.listReplaceLock);
if ((ret_code = initGlobalList(errorp)) != NS_SUCCESS) {
(void) mutex_unlock(&dir_servers.listReplaceLock);
return (ret_code);
}
dir_servers.standalone = 1;
(void) mutex_unlock(&dir_servers.listReplaceLock);
return (NS_LDAP_SUCCESS);
}
ns_ldap_return_code
__s_api_findRootDSE(const char *request,
const char *serverAddr,
const char *addrType,
ns_server_info_t *ret,
ns_ldap_error_t **error)
{
dir_server_list_t *current_list = NULL;
ns_ldap_return_code ret_code;
long i = 0;
int matched = FALSE;
dir_server_t *server = NULL;
char errmsg[MAXERROR];
(void) mutex_lock(&dir_servers.listReplaceLock);
if (dir_servers.list == NULL) {
(void) mutex_unlock(&dir_servers.listReplaceLock);
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("The list of root DSEs is empty: "
"the Standalone mode was not properly initialized"));
MKERROR(LOG_ERR,
*error,
NS_CONFIG_NOTLOADED,
strdup(errmsg),
NS_LDAP_MEMORY);
return (NS_LDAP_INTERNAL);
}
current_list = dir_servers.list;
(void) rw_rdlock(¤t_list->listDestroyLock);
(void) mutex_unlock(&dir_servers.listReplaceLock);
(void) mutex_lock(¤t_list->nsServers[0]->updateStatus);
if (strcmp(request, NS_CACHE_NEW) == 0 ||
current_list->nsServers[0]->info == INFO_STATUS_NEW) {
matched = TRUE;
}
(void) mutex_unlock(¤t_list->nsServers[i]->updateStatus);
for (i = 0; current_list->nsServers[i]; ++i) {
if (matched == FALSE &&
strcmp(current_list->nsServers[i]->ip,
serverAddr) == 0) {
matched = TRUE;
if (strcmp(request, NS_CACHE_NORESP) == 0) {
(void) mutex_lock(¤t_list->
nsServers[i]->updateStatus);
if (current_list->nsServers[i]->status ==
INFO_SERVER_REMOVED) {
(void) mutex_unlock(¤t_list->
nsServers[i]->
updateStatus);
continue;
}
(void) mutex_unlock(¤t_list->
nsServers[i]->
updateStatus);
(void) mutex_lock(¤t_list->
nsServers[i]->
updateStatus);
if (current_list->nsServers[i]->info ==
INFO_STATUS_NEW &&
current_list->nsServers[i]->status ==
INFO_SERVER_UP) {
server = current_list->nsServers[i];
(void) mutex_unlock(¤t_list->
nsServers[i]->
updateStatus);
break;
} else {
current_list->nsServers[i]->status =
INFO_SERVER_REMOVED;
(void) mutex_unlock(¤t_list->
nsServers[i]->
updateStatus);
continue;
}
} else {
continue;
}
}
if (matched) {
if (strcmp(request, NS_CACHE_WRITE) == 0) {
(void) mutex_lock(¤t_list->
nsServers[i]->
updateStatus);
if (current_list->nsServers[i]->status ==
INFO_SERVER_UP) {
(void) mutex_unlock(¤t_list->
nsServers[i]->
updateStatus);
server = current_list->nsServers[i];
break;
}
} else {
(void) mutex_lock(¤t_list->
nsServers[i]->
updateStatus);
if (current_list->nsServers[i]->status ==
INFO_SERVER_UP) {
(void) mutex_unlock(¤t_list->
nsServers[i]->
updateStatus);
server = current_list->nsServers[i];
break;
}
}
(void) mutex_unlock(¤t_list->
nsServers[i]->
updateStatus);
}
}
if (server == NULL) {
(void) rw_unlock(¤t_list->listDestroyLock);
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("No servers are available"));
MKERROR(LOG_ERR,
*error,
NS_CONFIG_NOTLOADED,
strdup(errmsg),
NS_LDAP_MEMORY);
return (NS_LDAP_NOTFOUND);
}
(void) mutex_lock(&server->updateStatus);
server->info = INFO_STATUS_OLD;
(void) mutex_unlock(&server->updateStatus);
if (ret == NULL) {
(void) rw_unlock(¤t_list->listDestroyLock);
return (NS_LDAP_SUCCESS);
}
if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
ret_code = __s_api_ip2hostname(server->ip, &ret->serverFQDN);
if (ret_code != NS_LDAP_SUCCESS) {
(void) snprintf(errmsg,
sizeof (errmsg),
gettext("The %s address "
"can not be resolved into "
"a host name. Returning "
"the address as it is."),
server->ip);
MKERROR(LOG_ERR,
*error,
NS_CONFIG_NOTLOADED,
strdup(errmsg),
NS_LDAP_MEMORY);
return (NS_LDAP_INTERNAL);
}
}
ret->server = strdup(server->ip);
ret->controls = __s_api_cp2dArray(server->controls);
ret->saslMechanisms = __s_api_cp2dArray(server->saslMech);
(void) rw_unlock(¤t_list->listDestroyLock);
return (NS_LDAP_SUCCESS);
}
ns_ldap_return_code
__ns_ldap_pingOfflineServers(void)
{
dir_server_list_t *current_list = NULL;
ns_ldap_return_code retCode = NS_LDAP_SUCCESS;
long srvListLength, i = 0;
thread_t *thrPool, thrID;
void *status = NULL;
(void) mutex_lock(&dir_servers.listReplaceLock);
if (dir_servers.list == NULL) {
(void) mutex_unlock(&dir_servers.listReplaceLock);
return (NS_LDAP_INTERNAL);
}
current_list = dir_servers.list;
(void) rw_wrlock(¤t_list->listDestroyLock);
(void) mutex_unlock(&dir_servers.listReplaceLock);
while (current_list->nsServers[i] != NULL) {
++i;
}
srvListLength = i;
thrPool = calloc(srvListLength, sizeof (thread_t));
if (thrPool == NULL) {
(void) rw_unlock(¤t_list->listDestroyLock);
return (NS_LDAP_MEMORY);
}
for (i = 0; i < srvListLength; ++i) {
if (current_list->nsServers[i]->status != INFO_SERVER_REMOVED &&
current_list->nsServers[i]->status != INFO_SERVER_ERROR) {
continue;
}
current_list->nsServers[i]->status = INFO_SERVER_CONNECTING;
current_list->nsServers[i]->info = INFO_STATUS_NEW;
__s_api_free2dArray(current_list->nsServers[i]->controls);
current_list->nsServers[i]->controls = NULL;
__s_api_free2dArray(current_list->nsServers[i]->saslMech);
current_list->nsServers[i]->saslMech = NULL;
switch (thr_create(NULL,
0,
create_ns_servers_entry,
current_list->nsServers[i],
0,
&thrID)) {
case EAGAIN:
current_list->nsServers[i]->status = INFO_SERVER_ERROR;
continue;
case ENOMEM:
current_list->nsServers[i]->status = INFO_SERVER_ERROR;
retCode = NS_LDAP_MEMORY;
break;
default:
thrPool[i] = thrID;
continue;
}
break;
}
for (i = 0; i < srvListLength; ++i) {
if (thrPool[i] != 0 &&
thr_join(thrPool[i], NULL, &status) == 0) {
if (status == NULL) {
current_list->nsServers[i]->status =
INFO_SERVER_ERROR;
retCode = NS_LDAP_MEMORY;
}
free(status);
}
}
(void) rw_unlock(¤t_list->listDestroyLock);
free(thrPool);
return (retCode);
}