/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#define __STANDALONE_MODULE__
#include <stdio.h>
#include <stdlib.h>
#include <libintl.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <locale.h>
#include <errno.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"
extern int str2hostent(const char *, int, void *, char *, int);
extern int str2hostent6(const char *, int, void *, char *, int);
typedef enum {
INFO_SERVER_UNKNOWN = 0,
typedef enum {
typedef struct dir_server {
char *ip;
char **controls;
char **saslMech;
} dir_server_t;
typedef struct dir_server_list {
struct {
/* The local list of the directory servers' root DSEs. */
/* The flag indicating if libsldap is in the 'Standalone' mode. */
int standalone;
/*
* The mutex ensuring that only one thread performs
* the initialization of the list.
*/
/*
* A flag indicating that a particular thread is
* in the 'ldap_cachemgr' mode. It is stored by thread as
* a thread specific data.
*/
const int initFlag;
/*
* A thread specific key storing
* the the 'ldap_cachemgr' mode indicator.
*/
typedef struct switchDatabase {
char *conf;
#pragma init(createStandaloneKey)
#define DONT_INCLUDE_ATTR_NAMES 0
#define NOT_PROFILE 0
/* INET6_ADDRSTRLEN + ":" + <5-digit port> + some round-up */
static
void
{
}
/*
* This function initializes an indication that a thread obtaining a root DSE
* will be switched to the 'ldap_cachemgr' mode. Within the thread libsldap
* will not invoke the __s_api_requestServer function. Instead, the library
* will establish a connection to the server specified by
* the __ns_ldap_getRootDSE function.
* Since ldap_cachmgr can obtain a DUAProfile and root DSEs at the same time
* and we do not want to affect a thread obtaining a DUAProfile,
* the 'ldap_cachemgr' mode is thread private.
* In addition, this function creates a key holding temporary configuration
* for the "hosts" and "ipnodes" databases which is used by the "SKIPDB"
* mechanism (__s_api_ip2hostname() & _s_api_hostname2ip()).
*/
static
void
{
"key needed for sharing ldap connections"));
}
"key containing current nsswitch configuration"));
}
}
/*
* This function sets the 'ldap_cachemgr' mode indication.
*/
void
{
(void *) &dir_servers.initFlag);
}
/*
* This function unset the 'ldap_cachemgr' mode indication.
*/
void
{
}
/*
* This function checks if the 'ldap_cachemgr' mode indication is set.
*/
int
}
/*
* This function checks if the process runs in the 'Standalone' mode.
* In this mode libsldap will check the local, process private list of root DSEs
* instead of requesting them via a door call to ldap_cachemgr.
*/
int
{
int mode;
return (mode);
}
static
int
{
int i = 0;
return (0);
while (*src != '\0') {
/* Copy up to one space from source. */
src++;
}
/* If not "ldap", just copy. */
/* At the end of string? */
return (1);
}
/* Copy up to one space from source. */
src++;
}
/* Copy also the criteria section */
if (*src == '[')
while (*src != ']') {
/* Shouln't happen if format is right */
return (1);
}
}
/* If next part is ldap, skip over it ... */
src += 4;
src++;
if (*src == '[') {
while (*src++ != ']') {
/*
* See comment above about
* correct format.
*/
if (*src == '\0') {
dst[i++] = '\0';
return (1);
}
}
}
src++;
}
}
if (*src == '\0')
dst[i++] = '\0';
}
return (1);
}
static
char *
{
char *ptr;
return (NULL);
}
++linep;
}
if (*linep == '#') {
continue;
}
continue;
}
}
;
;
}
continue;
}
break;
}
}
gettext("libsldap: the %s database "
"is missing from %s"),
return (NULL);
}
if (hostService == NULL) {
if (hostService == NULL) {
return (NULL);
}
}
/*
* In a long-living process threads can perform several
* getXbyY requests. And the windows between those requests
* can be long. The nsswitch configuration can change from time
* to time. So instead of allocating/freeing memory every time
* the API is called, reallocate memory only when the current
* configuration for the database being used is longer than
* the previous one.
*/
hostService->alloced = 0;
return (NULL);
}
}
return (hostService->conf);
else
return (NULL);
}
static
void
{
p->name = NSS_DBNAM_IPNODES;
p->flags |= NSS_USE_DEFAULT_CONFIG;
}
static
void
{
p->name = NSS_DBNAM_HOSTS;
p->flags |= NSS_USE_DEFAULT_CONFIG;
}
/*
* This function is an analog of the standard gethostbyaddr_r()
* function with an exception that it removes the 'ldap' back-end
* looks up using remaining back-ends.
*/
static
struct hostent *
int *h_errnop)
{
int (*str2ent)();
void (*nss_initf)();
int dbop;
switch (type) {
case AF_INET:
break;
case AF_INET6:
default:
return (NULL);
}
}
/*
* This routine is an analog of gethostbyaddr_r().
* But in addition __s_api_hostname2ip() performs the "LDAP SKIPDB" activity
* prior to querying the name services.
* If the buffer is not big enough to accommodate a returning data,
* NULL is returned and h_errnop is set to TRY_AGAIN.
*/
struct hostent *
int *h_errnop)
{
sizeof (char *) * 2 + /* The h_aliases member */
sizeof (struct in_addr) +
sizeof (struct in_addr *) * 2) {
return (NULL);
}
sizeof (char *));
sizeof (char *));
sizeof (struct in_addr));
sizeof (struct in_addr);
return (result);
}
sizeof (char *) * 2 + /* The h_aliases member */
sizeof (struct in6_addr) +
sizeof (struct in6_addr *) * 2) {
return (NULL);
}
sizeof (char *));
sizeof (char *));
sizeof (struct in6_addr));
sizeof (struct in6_addr);
return (result);
}
}
}
/*
* Convert an IP to a host name.
*/
int errorNum = 0,
len = 0;
return (NS_LDAP_INVALID_PARAM);
return (NS_LDAP_MEMORY);
if (addr[0] == '[') {
/*
* Assume it's [ipv6]:port
* Extract ipv6 IP
*/
*end = '\0';
delim = ']';
/* extract port */
} else {
return (NS_LDAP_INVALID_PARAM);
}
/* assume it's ipv4:port */
*end = '\0';
delim = ':';
} else
/* No port */
/* IPv4 */
&hostEnt,
&errorNum);
/* hostname + '\0' */
if (port)
/* ':' + port */
return (NS_LDAP_MEMORY);
}
if (port)
else
return (NS_LDAP_SUCCESS);
} else {
return (NS_LDAP_NOTFOUND);
}
/* IPv6 */
&hostEnt,
&errorNum);
/* hostname + '\0' */
if (port)
/* ':' + port */
return (NS_LDAP_MEMORY);
}
if (port)
else
return (NS_LDAP_SUCCESS);
} else {
return (NS_LDAP_NOTFOUND);
}
} else {
/*
* A hostname
* Return it as is
*/
if (end)
return (NS_LDAP_SUCCESS);
}
}
/*
* This function obtains data returned by an LDAP search request and puts it
* in a string in the ldap_cachmgr(1) door call format.
*
* INPUT:
* ld - a pointer to an LDAP structure used for a search operation,
* result_msg - a pointer to an LDAPMessage returned by the search,
* include_names - if set to INCLUDE_ATTR_NAMES, the output buffer will
* contain attribute names.
* Otherwise, only values will be return.
*
* OUTPUT:
* a buffer containing server info in the following format:
* [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
*
* Should be free'ed by the caller.
*/
static
int include_names,
int is_profile,
char **door_line)
{
LDAPMessage *e;
char *a, **vals;
if (!door_line) {
return (NS_LDAP_INVALID_PARAM);
}
return (NS_LDAP_NOTFOUND);
}
/* calculate length of received data */
a != NULL;
total_length += (include_names ?
strlen(a) : 0) +
}
}
ldap_memfree(a);
}
}
if (total_length == 0) {
return (NS_LDAP_NOTFOUND);
}
/* copy the data */
/* add 1 for the last '\0' */
return (NS_LDAP_MEMORY);
}
/* make it an empty string first */
**door_line = '\0';
while (a != NULL) {
if (is_profile) {
/*
* If we're processing DUAConfigProfile, we need to make
* sure we put objectclass attribute first.
* __s_api_create_config_door_str depends on that.
*/
if (seen_objectclass) {
if (strcasecmp(a, "objectclass") == 0) {
/* Skip objectclass now. */
continue;
}
} else {
if (strcasecmp(a, "objectclass") == 0) {
seen_objectclass = 1;
rewind = 1;
} else {
/* Skip all but objectclass first. */
continue;
}
}
}
if (include_names) {
}
if (include_names) {
"%s=%s%s",
a, vals[i],
} else {
"%s%s",
vals[i],
}
}
}
ldap_memfree(a);
/* Rewind */
if (rewind) {
}
rewind = 0;
} else {
}
}
}
if (e != result_msg) {
(void) ldap_msgfree(e);
}
return (NS_LDAP_SUCCESS);
}
/*
* This function looks up the base DN of a directory serving
* a specified domain name.
*
* INPUT:
* ld - a pointer to an LDAP structure used for the search operation,
* domain_name - the name of a domain.
*
* OUTPUT:
* a buffer containing a directory's base DN found.
* Should be free'ed by the caller.
*/
static
{
int ldap_rc;
/* Get the whole list of naming contexts residing on the server */
attrs[0] = "namingcontexts";
switch (ldap_rc) {
/* If successful, the root DSE was found. */
case LDAP_SUCCESS:
break;
/*
* If the root DSE was not found, the server does
* not comply with the LDAP v3 protocol.
*/
default:
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
return (NS_LDAP_OP_FAILED);
/* NOTREACHED */
break;
}
&DNlist)) != NS_LDAP_SUCCESS) {
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
return (ret_code);
}
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
return (NS_LDAP_NOTFOUND);
}
attrs[0] = "dn";
do {
/*
* For each context try to find a NIS domain object
* which 'nisdomain' attribute's value matches the domain name
*/
"(&(objectclass=nisDomainObject)"
"(nisdomain=%s))",
ptr,
0,
NULL,
NULL,
&tv,
0,
&resultMsg);
if (ldap_rc != LDAP_SUCCESS) {
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
continue;
}
(void) ldap_msgfree(resultMsg);
continue;
}
*dir_base_dn = strdup(a);
ldap_memfree(a);
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
if (!*dir_base_dn) {
return (NS_LDAP_MEMORY);
}
break;
}
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
if (!*dir_base_dn) {
return (NS_LDAP_NOTFOUND);
}
return (NS_LDAP_SUCCESS);
}
/*
* This function parses the results of a search operation
* requesting a DUAProfile.
*
* INPUT:
* ld - a pointer to an LDAP structure used for the search operation,
* dir_base_dn - the name of a directory's base DN,
* profile_name - the name of a DUAProfile to be obtained.
*
* OUTPUT:
* a buffer containing the DUAProfile in the following format:
* [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
* Should be free'ed by the caller.
*/
static
const char *dir_base_dn,
const char *profile_name,
char **profile)
{
int ldap_rc;
NULL,
0,
NULL,
NULL,
&tv,
0,
&resultMsg);
switch (ldap_rc) {
/* If successful, the DUA profile was found. */
case LDAP_SUCCESS:
break;
/*
* If the root DSE was not found, the server does
* not comply with the LDAP v3 protocol.
*/
default:
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
return (NS_LDAP_OP_FAILED);
/* NOTREACHED */
break;
}
profile);
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
return (ret_code);
}
/*
* This function derives the directory's base DN from a provided domain name.
*
* INPUT:
* domain_name - the name of a domain to be converted into a base DN,
* buffer - contains the derived base DN,
* buf_len - the length of the buffer.
*
* OUTPUT:
* The function returns the address of the buffer or NULL.
*/
static
char *
{
return (NULL);
}
buffer[0] = '\0';
/* Simply replace dots with "dc=" */
continue;
}
*chr = '\0';
return (NULL);
return (NULL);
if (i < length) {
/*
* The end of the domain name
* has not been reached yet
*/
return (NULL);
*chr = '.';
}
}
return (buffer);
}
/*
* This function obtains the directory's base DN and a DUAProfile
* from a specified server.
*
* INPUT:
* server - a structure describing a server to connect to and
* a DUAProfile to be obtained from the server,
* cred - credentials to be used during establishing connections to
* the server.
*
* OUTPUT:
* dua_profile - a buffer containing the DUAProfile in the following format:
* [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
* dir_base_dn - a buffer containing the base DN,
* errorp - an error object describing an error, if any.
*
* All the output data structures should be free'ed by the caller.
*/
char **dua_profile,
char **dir_base_dn,
{
return (NS_LDAP_INVALID_PARAM);
}
return (NS_LDAP_INVALID_PARAM);
}
if (config_struct == NULL) {
return (NS_LDAP_MEMORY);
}
/*
* If no credentials are specified, try to establish a connection
* as anonymous.
*/
if (!cred) {
}
/* Now create a default LDAP configuration */
errorp) != NS_LDAP_SUCCESS) {
return (NS_LDAP_CONFIG);
}
/* Put together the address and the port specified by the user app. */
(void) snprintf(serverAddr,
sizeof (serverAddr),
"%s:%hu",
} else {
}
/*
* There is no default value for the 'Default Search Base DN' attribute.
* Derive one from the domain name to make __s_api_crosscheck() happy.
*/
sizeof (errmsg),
gettext("Can not convert %s into a base DN name"),
server->domainName ?
*errorp,
return (NS_LDAP_INTERNAL);
}
return (NS_LDAP_CONFIG);
}
!= NS_SUCCESS) {
return (NS_LDAP_CONFIG);
}
return (NS_LDAP_INTERNAL);
}
&session,
0,
0,
cu)) != NS_LDAP_SUCCESS) {
return (ret_code);
}
server->domainName ?
server->domainName :
&dirBaseDN)) != NS_LDAP_SUCCESS) {
sizeof (errmsg),
gettext("Can not find the "
"nisDomainObject for domain %s\n"),
server->domainName ?
*errorp,
return (ret_code);
}
/*
* And here obtain a DUAProfile which will be used
* as a real configuration.
*/
&duaProfile)) != NS_LDAP_SUCCESS) {
sizeof (errmsg),
gettext("Can not find the "
"%s DUAProfile\n"),
*errorp,
return (ret_code);
}
if (dir_base_dn) {
*dir_base_dn = dirBaseDN;
} else {
}
if (dua_profile) {
} else {
}
return (NS_LDAP_SUCCESS);
}
/*
* set_ldap_server_type tries to determine the type of server where the
* rootDSE data 'root_dse' is obtained. Currently it checks for server
* specific objectclasses or attribute values to determine the type:
* ODSEE : has venderName attribute value: "Sun Microsystems, Inc."
* OPENLDAP: has objectclass OpenLDAProotDSE
* AD : has attribute isGlobalCatalogReady
* A type of unkonwn is returned if not one of these three.
*/
static ns_ldap_server_type_t
{
/* make a working copy of root_dse */
return (type);
continue;
}
*val++ = '\0';
break;
}
}
break;
}
break;
}
continue;
}
}
return (type);
}
/*
* This function obtains the root DSE from a specified server.
* Note this function creates a private temporary unshared connection.
* It does not participate in connection sharing. It returns data
* can then be used to create a shared connection if desired.
*
* There is a similar function getServerInfo() in ns_connect.c
* which is used to obtain the same information for cases where
* the information is not available from the ldap_cachemgr.
* The functionality is turned off by the flag NS_LDAP_NO_ROOT_DSE_INFO
* in __s_api_getConnection()
*
* INPUT:
* server_addr - an adress of a server to be connected to.
*
* OUTPUT:
* root_dse - a buffer containing the root DSE in the following format:
* [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
* For example: ( here | used as DOORLINESEP for visual purposes)
* supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL
* Should be free'ed by the caller.
*
* server_type - type of server, DSEE, AD, OpenLDAP, etc.
*/
char **root_dse,
int anon_fallback)
{
char *attrs[] = {
"supportedControl",
"supportedsaslmechanisms",
"vendorName",
"objectclass",
"isGlobalCatalogReady",
};
return (NS_LDAP_INVALID_PARAM);
/*
* Get a new (private) connection
* All the credentials will be taken from the current
* libsldap configuration.
*/
if (ret_code != NS_LDAP_SUCCESS) {
/* Fallback to anonymous mode is disabled. Stop. */
if (anon_fallback == 0) {
gettext("libsldap: can not get the root DSE from "
" the %s server: %s. "
"Falling back to anonymous disabled.\n"),
(void) __ns_ldap_freeError(errorp);
}
return (ret_code);
}
/*
* Fallback to anonymous, non-SSL mode for backward
* compatibility reasons. This mode should only be used when
* this function (__ns_ldap_getRootDSE) is called from
* ldap_cachemgr(1M).
*/
gettext("libsldap: Falling back to anonymous, non-SSL"
" mode for __ns_ldap_getRootDSE. %s\n"),
/* Setup the anon credential for anonymous connection. */
(void) __ns_ldap_freeError(errorp);
if (ret_code != NS_LDAP_SUCCESS) {
(void) __ns_ldap_freeError(errorp);
return (ret_code);
}
}
/* get search timeout value */
if (rc == NS_LDAP_SUCCESS) {
(void) __ns_ldap_freeParam(¶mVal);
}
} else {
(void) __ns_ldap_freeError(errorp);
}
/* Get root DSE from the server specified by the caller. */
if (ldap_rc != LDAP_SUCCESS) {
/*
* Unable to get root DSE: server may be down,
* connection is not a valid LDAPv3 or other error
*/
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
return (NS_LDAP_OP_FAILED);
}
/*
* Successful root DSE search. Now try to interpret it.
*/
if (ret_code == NS_LDAP_NOTFOUND) {
gettext("No root DSE data for server %s returned."),
}
if (resultMsg) {
(void) ldap_msgfree(resultMsg);
}
return (ret_code);
}
/*
* This function destroys the local list of root DSEs. The input parameter is
* a pointer to the list to be erased.
* The type of the pointer passed to this function should be
* (dir_server_list_t *).
*/
static
void *
{
long i = 0, j;
/* Destroy the old list */
j = 0;
++j;
}
j = 0;
++j;
}
++i;
}
/*
* All the structures pointed by old_list->nsServers were allocated
* in one chunck. The nsServers[0] pointer points to the beginning
* of that chunck.
*/
return (NULL);
}
/*
* This function cancels the Standalone mode and destroys the list of root DSEs.
*/
void
{
dir_servers.standalone = 0;
if (!dir_servers.list) {
return;
}
(void) disposeOfOldList(old_list);
}
static
void*
{
sizeof (ns_ldap_return_code));
return (NULL);
}
/*
* We call this function in non anon-fallback mode because we
* want the whole procedure to fail as soon as possible to
* indicate there are problems with connecting to the server.
*/
&rootDSE,
&error,
if (*retCode == NS_LDAP_MEMORY) {
return (NULL);
}
/*
* If the root DSE can not be obtained, log an error and keep the
* server.
*/
if (*retCode != NS_LDAP_SUCCESS) {
gettext("libsldap (\"standalone\" mode): "
"can not obtain the root DSE from %s. %s"),
if (error) {
(void) __ns_ldap_freeError(&error);
}
return (retCode);
}
/* Get the first attribute of the root DSE. */
gettext("libsldap (\"standalone\" mode): "
"the root DSE from %s is empty or corrupted."),
return (retCode);
}
return (NULL);
}
do {
continue;
}
++val;
if (strncasecmp(attr,
_SASLMECHANISM_LEN) == 0) {
++sm_mem_blocks *
sizeof (char *));
break;
}
(sm_counter + 1) *
sizeof (char *),
sizeof (char *) -
(sm_counter + 1) *
sizeof (char *));
}
break;
}
++sm_counter;
continue;
}
if (strncasecmp(attr,
_SUPPORTEDCONTROL_LEN) == 0) {
++sc_mem_blocks *
sizeof (char *));
break;
}
(sc_counter + 1) *
sizeof (char *),
sizeof (char *) -
(sc_counter + 1) *
sizeof (char *));
}
break;
}
++sc_counter;
continue;
}
if (*retCode == NS_LDAP_MEMORY) {
return (NULL);
}
return (retCode);
}
/*
* This function creates a new local list of root DSEs from all the servers
* mentioned in the DUAProfile (or local NS BEC) and returns
* a pointer to the list.
*/
static
{
char **serverList;
long srvListLength, i;
return (NS_LDAP_INVALID_PARAM);
}
return (NS_LDAP_INVALID_PARAM);
}
return (retCode);
}
for (i = 0; serverList[i]; ++i) {
;
}
srvListLength = i;
return (NS_LDAP_MEMORY);
}
sizeof (dir_server_list_t));
return (NS_LDAP_MEMORY);
}
sizeof (dir_server_t *));
return (NS_LDAP_MEMORY);
}
/*
* Allocate a set of dir_server_t structures as an array,
* with one alloc call and then initialize the nsServers pointers
* with the addresses of the array's members.
*/
sizeof (dir_server_t));
for (i = 0; i < srvListLength; ++i) {
NULL);
break;
}
switch (thr_create(NULL,
0,
0,
&thrID)) {
case EAGAIN:
continue;
/* NOTREACHED */
break;
case ENOMEM:
continue;
/* NOTREACHED */
break;
default:
continue;
/* NOTREACHED */
break;
}
}
for (i = 0; i < srvListLength; ++i) {
if (thrPool[i] != 0 &&
/*
* Some memory allocation problems occured. Just
* ignore the server and hope there will be some
* other good ones.
*/
}
}
}
if (retCode == NS_LDAP_MEMORY) {
(void) disposeOfOldList(*new_list);
return (NS_LDAP_MEMORY);
}
return (NS_LDAP_SUCCESS);
}
/*
* This functions replaces the local list of root DSEs with a new one and starts
* a thread destroying the old list. There is no need for other threads to wait
* until the old list will be destroyed.
* Since it is possible that more than one thread can start creating the list,
* this function should be protected by mutexes to be sure that only one thread
* performs the initialization.
*/
static
{
if (ret_code != NS_LDAP_SUCCESS) {
return (ret_code);
}
if (old_list) {
(void) thr_create(NULL,
0,
&tid);
}
return (NS_LDAP_SUCCESS);
}
static
struct {
char *authMech;
{"simple", {NS_LDAP_AUTH_SIMPLE,
{"tls:simple", {NS_LDAP_AUTH_TLS,
{"tls:sasl/CRAM-MD5", {NS_LDAP_AUTH_TLS,
{"tls:sasl/DIGEST-MD5", {NS_LDAP_AUTH_TLS,
{"sasl/CRAM-MD5", {NS_LDAP_AUTH_SASL,
{"sasl/DIGEST-MD5", {NS_LDAP_AUTH_SASL,
{"sasl/GSSAPI", {NS_LDAP_AUTH_SASL,
{
uint32_t i;
sizeof (errmsg),
gettext("Invalid authentication method specified\n"));
*errorp,
return (NS_LDAP_INTERNAL);
}
return (NS_LDAP_SUCCESS);
}
}
sizeof (errmsg),
gettext("Invalid authentication method specified\n"));
*errorp,
return (NS_LDAP_INTERNAL);
}
/*
* This function "informs" libsldap that a client application has specified
* a directory to use. The function obtains a DUAProfile, credentials,
* and naming context. During all further operations on behalf
* of the application requested a standalone schema libsldap will use
* the information obtained by __ns_ldap_initStandalone() instead of
* door_call(3C)ing ldap_cachemgr(1M).
*
* INPUT:
* sa_conf - a structure describing where and in which way to obtain all
* the configuration describing how to communicate to
* a choosen LDAP directory,
* errorp - an error object describing an error occured.
*/
ns_ldap_error_t **errorp) {
NULL,
int ret_code;
sizeof (errmsg),
gettext("Bind DN and bind password"
" must both be provided\n"));
*errorp,
return (NS_LDAP_INTERNAL);
}
case NS_LDAP_SERVER:
}
}
}
}
NULL,
errorp);
if (ret_code != NS_LDAP_SUCCESS) {
return (ret_code);
}
return (NS_LDAP_CONFIG);
}
char *certPathAttr;
case NS_LDAP_V1:
certPathAttr = "NS_LDAP_CERT_PATH";
break;
default: /* Version 2 */
certPathAttr = "NS_LDAP_HOST_CERTPATH";
break;
}
&type) == 0 &&
type,
errorp)) != NS_LDAP_SUCCESS) {
return (ret_code);
}
}
char *authMethods;
if (authMethods != NULL &&
/*
* The received DUAProfile specifies
* The bind DN and password will be
* ignored.
*/
"used as an authentication method. "
"The bind DN and password will "
"be ignored.\n"));
break;
}
if (authMethods != NULL)
errorp) != NS_LDAP_SUCCESS) {
return (NS_LDAP_CONFIG);
}
errorp) != NS_LDAP_SUCCESS) {
return (NS_LDAP_CONFIG);
}
}
break;
default: /* NS_CACHEMGR */
return (NS_LDAP_SUCCESS);
}
/* Connection management should use the new config now. */
return (ret_code);
}
return (NS_LDAP_SUCCESS);
}
/*
* INPUT:
* serverAddr is the address of a server and
* request is one of the following:
* NS_CACHE_NEW: get a new server address, addr is ignored.
* NS_CACHE_NORESP: get the next one, remove addr from list.
* NS_CACHE_NEXT: get the next one, keep addr on list.
* NS_CACHE_WRITE: get a non-replica server, if possible, if not, same
* as NS_CACHE_NEXT.
* addrType:
* NS_CACHE_ADDR_IP: return server address as is, this is default.
* NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only
* self credential case requires such format.
* OUTPUT:
* ret
*
* a structure of type ns_server_info_t containing the server address
* or name, server controls and supported SASL mechanisms.
* NOTE: Caller should allocate space for the structure and free
* all the space allocated by the function for the information contained
* in the structure.
*
* error - an error object describing an error, if any.
*/
const char *serverAddr,
const char *addrType,
{
long i = 0;
sizeof (errmsg),
gettext("The list of root DSEs is empty: "
"the Standalone mode was not properly initialized"));
*error,
return (NS_LDAP_INTERNAL);
}
/*
* The code below is mostly the clone of the
* ldap_cachemgr::cachemgr_getldap.c::getldap_get_serverInfo() function.
* Currently we have two different server lists: one is maintained
* by libsldap ('standalone' mode), the other is in ldap_cachemgr
* (a part of its standard functionality).
*/
/*
* If NS_CACHE_NEW, or the server info is new,
* starts from the beginning of the list.
*/
}
for (i = 0; current_list->nsServers[i]; ++i) {
/*
* Lock the updateStatus mutex to
* make sure the server status stays the same
* while the data is being processed.
*/
serverAddr) == 0) {
/*
* if the server has already been removed,
* don't bother.
*/
(void) mutex_lock(¤t_list->
nsServers[i]->updateStatus);
(void) mutex_unlock(¤t_list->
nsServers[i]->
continue;
}
(void) mutex_unlock(¤t_list->
nsServers[i]->
/*
* if the information is new,
* give this server one more chance.
*/
(void) mutex_lock(¤t_list->
nsServers[i]->
(void) mutex_unlock(¤t_list->
nsServers[i]->
break;
} else {
/*
* it is recommended that
* before removing the
* server from the list,
* the server should be
* contacted one more time
* to make sure that it is
* really unavailable.
* For now, just trust the client
* (i.e., the sldap library)
* that it knows what it is
* doing and would not try
* to mess up the server
* list.
*/
(void) mutex_unlock(¤t_list->
nsServers[i]->
continue;
}
} else {
/*
* req == NS_CACHE_NEXT or NS_CACHE_WRITE
*/
continue;
}
}
if (matched) {
/*
* ldap_cachemgr checks here if the server
* is not a non-replica server (a server
* of type INFO_RW_WRITEABLE). But currently
* it considers all the servers in its list
* as those.
*/
(void) mutex_lock(¤t_list->
nsServers[i]->
(void) mutex_unlock(¤t_list->
nsServers[i]->
break;
}
} else {
(void) mutex_lock(¤t_list->
nsServers[i]->
(void) mutex_unlock(¤t_list->
nsServers[i]->
break;
}
}
(void) mutex_unlock(¤t_list->
nsServers[i]->
}
}
sizeof (errmsg),
gettext("No servers are available"));
*error,
return (NS_LDAP_NOTFOUND);
}
return (NS_LDAP_SUCCESS);
}
if (ret_code != NS_LDAP_SUCCESS) {
sizeof (errmsg),
gettext("The %s address "
"can not be resolved into "
"a host name. Returning "
"the address as it is."),
*error,
return (NS_LDAP_INTERNAL);
}
}
return (NS_LDAP_SUCCESS);
}
/*
* This function iterates through the list of the configured LDAP servers
* and "pings" those which are marked as removed or if any error occurred
* during the previous receiving of the server's root DSE. If the
* function is able to reach such a server and get its root DSE, it
* marks the server as on-line. Otherwise, the server's status is set
* to "Error".
* For each server the function tries to connect to, it fires up
* a separate thread and then waits until all the treads finish.
* The function returns NS_LDAP_INTERNAL if the Standalone mode was not
* initialized or was canceled prior to an invocation of
* __ns_ldap_pingOfflineServers().
*/
{
long srvListLength, i = 0;
return (NS_LDAP_INTERNAL);
}
++i;
}
srvListLength = i;
return (NS_LDAP_MEMORY);
}
for (i = 0; i < srvListLength; ++i) {
continue;
}
switch (thr_create(NULL,
0,
current_list->nsServers[i],
0,
&thrID)) {
case EAGAIN:
continue;
/* NOTREACHED */
break;
case ENOMEM:
break;
default:
continue;
/* NOTREACHED */
break;
}
/* A memory allocation error has occured */
break;
}
for (i = 0; i < srvListLength; ++i) {
if (thrPool[i] != 0 &&
}
}
}
return (retCode);
}