ns_config.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* or http://www.opensolaris.org/os/licensing.
* 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
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* libsldap - library side configuration components
* Routines to manage the config structure
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <libintl.h>
#include <locale.h>
#include <thread.h>
#include <synch.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <crypt.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#include <netdb.h>
#include <sys/systeminfo.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <limits.h>
#include "ns_sldap.h"
#include "ns_internal.h"
#include "ns_cache_door.h"
#pragma fini(_free_config)
static mutex_t ns_parse_lock = DEFAULTMUTEX;
static mutex_t ns_loadrefresh_lock = DEFAULTMUTEX;
static ns_config_t *current_config = NULL;
static int cache_server = FALSE;
/*
* Parameter Index Type validation routines
*/
static int
__s_val_postime(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf);
static int
__s_val_basedn(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf);
static int
__s_val_binddn(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf);
static int
__s_val_bindpw(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf);
static int
__s_val_serverList(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf);
/*
* Forward declarations
*/
static ns_parse_status
verify_value(ns_config_t *cfg, char *name, char *value, char *errstr);
static int
set_default_value(ns_config_t *configptr, char *name, char *value,
ns_ldap_error_t **error);
static void
set_curr_config(ns_config_t *ptr);
static int
__door_getldapconfig(char **buffer, int *buflen, ns_ldap_error_t **error);
static ns_config_t *
SetDoorInfo(char *buffer, ns_ldap_error_t **errorp);
static boolean_t
timetorefresh(ns_config_t *cfg);
static ns_config_t *
LoadCacheConfiguration(ns_ldap_error_t **error);
static void **
dupParam(ns_param_t *ptr);
static time_t
conv_time(char *s);
/*
* Structures used in enum <-> string mapping routines
*/
static ns_enum_map ns_auth_enum_v1[] = {
{ ENUM2INT(NS_LDAP_EA_NONE), "NS_LDAP_AUTH_NONE" },
{ ENUM2INT(NS_LDAP_EA_SIMPLE), "NS_LDAP_AUTH_SIMPLE" },
{ ENUM2INT(NS_LDAP_EA_SASL_CRAM_MD5), "NS_LDAP_AUTH_SASL_CRAM_MD5" },
{ -1, NULL },
};
static ns_enum_map ns_auth_enum_v2[] = {
{ ENUM2INT(NS_LDAP_EA_NONE), "none" },
{ ENUM2INT(NS_LDAP_EA_SIMPLE), "simple" },
{ ENUM2INT(NS_LDAP_EA_SASL_CRAM_MD5), "sasl/CRAM-MD5" },
{ ENUM2INT(NS_LDAP_EA_SASL_DIGEST_MD5), "sasl/DIGEST-MD5" },
{ ENUM2INT(NS_LDAP_EA_SASL_DIGEST_MD5_INT),
"sasl/DIGEST-MD5:auth-int" },
{ ENUM2INT(NS_LDAP_EA_SASL_DIGEST_MD5_CONF),
"sasl/DIGEST-MD5:auth-conf" },
{ ENUM2INT(NS_LDAP_EA_SASL_EXTERNAL), "sasl/EXTERNAL" },
{ ENUM2INT(NS_LDAP_EA_TLS_NONE), "tls:none" },
{ ENUM2INT(NS_LDAP_EA_TLS_SIMPLE), "tls:simple" },
{ ENUM2INT(NS_LDAP_EA_TLS_SASL_CRAM_MD5), "tls:sasl/CRAM-MD5" },
{ ENUM2INT(NS_LDAP_EA_TLS_SASL_DIGEST_MD5), "tls:sasl/DIGEST-MD5" },
{ ENUM2INT(NS_LDAP_EA_TLS_SASL_DIGEST_MD5_INT),
"tls:sasl/DIGEST-MD5:auth-int" },
{ ENUM2INT(NS_LDAP_EA_TLS_SASL_DIGEST_MD5_CONF),
"tls:sasl/DIGEST-MD5:auth-conf" },
{ ENUM2INT(NS_LDAP_EA_TLS_SASL_EXTERNAL), "tls:sasl/EXTERNAL" },
{ -1, NULL },
};
/* V1 ONLY */
static ns_enum_map ns_sec_enum_v1[] = {
{ ENUM2INT(NS_LDAP_TLS_NONE), "NS_LDAP_SEC_NONE" },
{ -1, NULL },
};
/* V2 ONLY */
static ns_enum_map ns_cred_enum_v2[] = {
{ ENUM2INT(NS_LDAP_CRED_ANON), "anonymous" },
{ ENUM2INT(NS_LDAP_CRED_PROXY), "proxy" },
{ ENUM2INT(NS_LDAP_CRED_SELF), "self" },
{ -1, NULL },
};
static ns_enum_map ns_ref_enum_v1[] = {
{ ENUM2INT(NS_LDAP_FOLLOWREF), "NS_LDAP_FOLLOWREF" },
{ ENUM2INT(NS_LDAP_NOREF), "NS_LDAP_NOREF" },
{ -1, NULL },
};
static ns_enum_map ns_ref_enum_v2[] = {
{ ENUM2INT(NS_LDAP_FOLLOWREF), "TRUE" },
{ ENUM2INT(NS_LDAP_NOREF), "FALSE" },
{ -1, NULL },
};
static ns_enum_map ns_scope_enum_v1[] = {
{ ENUM2INT(NS_LDAP_SCOPE_BASE), "NS_LDAP_SCOPE_BASE" },
{ ENUM2INT(NS_LDAP_SCOPE_ONELEVEL), "NS_LDAP_SCOPE_ONELEVEL" },
{ ENUM2INT(NS_LDAP_SCOPE_SUBTREE), "NS_LDAP_SCOPE_SUBTREE" },
{ -1, NULL },
};
static ns_enum_map ns_scope_enum_v2[] = {
{ ENUM2INT(NS_LDAP_SCOPE_BASE), "base" },
{ ENUM2INT(NS_LDAP_SCOPE_ONELEVEL), "one" },
{ ENUM2INT(NS_LDAP_SCOPE_SUBTREE), "sub" },
{ -1, NULL },
};
static ns_enum_map ns_pref_enum[] = {
{ ENUM2INT(NS_LDAP_PREF_FALSE), "NS_LDAP_FALSE" },
{ ENUM2INT(NS_LDAP_PREF_TRUE), "NS_LDAP_TRUE" },
{ -1, NULL },
};
static int ns_def_auth_v1[] = {
ENUM2INT(NS_LDAP_EA_NONE),
0
};
static int ns_def_auth_v2[] = {
ENUM2INT(NS_LDAP_EA_NONE),
0
};
static int ns_def_cred_v1[] = {
ENUM2INT(NS_LDAP_CRED_PROXY),
0
};
static int ns_def_cred_v2[] = {
ENUM2INT(NS_LDAP_CRED_ANON),
0
};
/*
* The next macro places an integer in the first sizeof(int) bytes of a
* void pointer location. For 32-bit, it is the same as "(void *) i". It
* is used to solve a problem found during 64-bit testing. The problem
* was that for a configuration parameter such as NS_LDAP_SEARCH_REF_P,
* which is of type INT and has defined default value, an int
* variable(ns_param.ns_pu.i) defined inside an union(ns_pu) structure, is
* used to access the defined default value. This requires the default
* value to be in the first sizeof(int) bytes of the union element. If
* just using "(void *) intval" to declare the default value in the
* following defconfig[] structure, the intval data will be placed is the
* last sizeof(int) bytes. In which case, when accessing via ns_pu_i in
* a 64-bit system, ZERO will be returned as the default value, not the
* defined one.
*
* Note since amd64 is little-endian, the problem is not an issue.
* INT2VOIDPTR will just leave the data (i) unchanged.
*/
#if defined(__amd64)
#define INT2VOIDPTR(i) (void *)i
#else
#define INT2VOIDPTR(i) \
(void *)(((long)(i))<<(8*(sizeof (void *) - sizeof (int))))
#endif
/*
* The default configuration table
* Version 1 entries are first, V2 entries follow.
*/
static ns_default_config defconfig[] = {
/* optional V1 profile */
{"NS_LDAP_FILE_VERSION", NS_LDAP_FILE_VERSION_P,
CLIENTCONFIG, CHARPTR, TRUE, NS_LDAP_V1,
NULL, /* No version number defined in V1 */
{ CHARPTR, 0, (void *)NS_LDAP_VERSION_1 },
NULL, NULL },
/* ---------- V1 profile ---------- */
{"NS_LDAP_BINDDN", NS_LDAP_BINDDN_P,
CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V1,
_P1_BINDDN,
{ CHARPTR, 0, NULL },
__s_val_binddn, NULL },
{"NS_LDAP_BINDPASSWD", NS_LDAP_BINDPASSWD_P,
CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V1,
_P1_BINDPASSWORD,
{ CHARPTR, 0, NULL },
__s_val_bindpw, NULL },
{"NS_LDAP_SERVERS", NS_LDAP_SERVERS_P,
SERVERCONFIG, ARRAYCP, FALSE, NS_LDAP_V1,
_P1_SERVERS,
{ ARRAYCP, 0, NULL },
__s_val_serverList, NULL },
{"NS_LDAP_SEARCH_BASEDN", NS_LDAP_SEARCH_BASEDN_P,
SERVERCONFIG, CHARPTR, TRUE, NS_LDAP_V1,
_P1_SEARCHBASEDN,
{ CHARPTR, 0, NULL },
__s_val_basedn, NULL },
{"NS_LDAP_AUTH", NS_LDAP_AUTH_P,
CLIENTCONFIG, ARRAYAUTH, FALSE, NS_LDAP_V1,
_P1_AUTHMETHOD,
{ ARRAYAUTH, 1, (void *)&ns_def_auth_v1[0] },
NULL, ns_auth_enum_v1 },
{"NS_LDAP_TRANSPORT_SEC", NS_LDAP_TRANSPORT_SEC_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V1,
_P1_TRANSPORTSECURITY,
{ INT, 0, INT2VOIDPTR(NS_LDAP_TLS_NONE) },
NULL, ns_sec_enum_v1 },
{"NS_LDAP_SEARCH_REF", NS_LDAP_SEARCH_REF_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V1,
_P1_SEARCHREFERRAL,
{ INT, 0, INT2VOIDPTR(NS_LDAP_FOLLOWREF) },
NULL, ns_ref_enum_v1 },
{"NS_LDAP_DOMAIN", NS_LDAP_DOMAIN_P,
CLIENTCONFIG, CHARPTR, TRUE, NS_LDAP_V1,
NULL, /* not defined in the Profile */
{ CHARPTR, 0, NULL },
NULL, NULL },
{"NS_LDAP_EXP", NS_LDAP_EXP_P,
SERVERCONFIG, TIMET, TRUE, NS_LDAP_V1,
NULL, /* initialized by code to time+NS_LDAP_CACHETTL */
{ INT, 0, 0 },
NULL, NULL },
{"NS_LDAP_CERT_PATH", NS_LDAP_CERT_PATH_P,
CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V1,
_P1_CERTIFICATEPATH,
{ CHARPTR, 0, NULL },
NULL, NULL },
{"NS_LDAP_CERT_PASS", NS_LDAP_CERT_PASS_P,
CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V1,
_P1_CERTIFICATEPASSWORD,
{ CHARPTR, 0, NULL },
NULL, NULL },
{"NS_LDAP_SEARCH_DN", NS_LDAP_SEARCH_DN_P,
CLIENTCONFIG, SSDLIST, FALSE, NS_LDAP_V1,
_P1_DATASEARCHDN,
{ SSDLIST, 0, NULL },
NULL, NULL },
{"NS_LDAP_SEARCH_SCOPE", NS_LDAP_SEARCH_SCOPE_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V1,
_P1_SEARCHSCOPE,
{ INT, 0, INT2VOIDPTR(NS_LDAP_SCOPE_ONELEVEL) },
NULL, ns_scope_enum_v1 },
{"NS_LDAP_SEARCH_TIME", NS_LDAP_SEARCH_TIME_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V1,
_P1_SEARCHTIMELIMIT,
{ INT, 0, INT2VOIDPTR(NS_DEFAULT_SEARCH_TIMEOUT) },
NULL, NULL },
{"NS_LDAP_SERVER_PREF", NS_LDAP_SERVER_PREF_P,
CLIENTCONFIG, ARRAYCP, FALSE, NS_LDAP_V1,
_P1_PREFERREDSERVER,
{ ARRAYCP, 0, NULL },
__s_val_serverList, NULL },
{"NS_LDAP_PREF_ONLY", NS_LDAP_PREF_ONLY_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V1,
_P1_PREFERREDSERVERONLY,
{ INT, 0, INT2VOIDPTR(NS_LDAP_PREF_FALSE) },
NULL, ns_pref_enum },
{"NS_LDAP_CACHETTL", NS_LDAP_CACHETTL_P,
CLIENTCONFIG, CHARPTR, TRUE, NS_LDAP_V1,
_P1_CACHETTL,
{ CHARPTR, 0, (void *)EXP_DEFAULT_TTL },
__s_val_postime, NULL },
{"NS_LDAP_PROFILE", NS_LDAP_PROFILE_P,
CLIENTCONFIG, CHARPTR, TRUE, NS_LDAP_V1,
_P_CN,
{ CHARPTR, 0, (void *)DEFAULTCONFIGNAME },
NULL, NULL },
{"NS_LDAP_BIND_TIME", NS_LDAP_BIND_TIME_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V1,
_P1_BINDTIMELIMIT,
{ INT, 0, INT2VOIDPTR(NS_DEFAULT_BIND_TIMEOUT) },
NULL, NULL },
/* This configuration option is not visible in V1 */
{"NS_LDAP_CREDENTIAL_LEVEL", NS_LDAP_CREDENTIAL_LEVEL_P,
CLIENTCONFIG, ARRAYCRED, TRUE, NS_LDAP_V1,
NULL, /* No version defined in V1 */
{ ARRAYCRED, 0, (void *)&ns_def_cred_v1[0] },
NULL, NULL },
/* ---------- V2 profile ---------- */
{"NS_LDAP_FILE_VERSION", NS_LDAP_FILE_VERSION_P,
CLIENTCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
NULL, /* No version number defined in V1 */
{ CHARPTR, 0, (void *)NS_LDAP_VERSION_2 },
NULL, NULL },
{"NS_LDAP_BINDDN", NS_LDAP_BINDDN_P,
CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
NULL, /* not defined in the Profile */
{ CHARPTR, 0, NULL },
__s_val_binddn, NULL },
{"NS_LDAP_BINDPASSWD", NS_LDAP_BINDPASSWD_P,
CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
NULL, /* not defined in the Profile */
{ CHARPTR, 0, NULL },
__s_val_bindpw, NULL },
{"NS_LDAP_EXP", NS_LDAP_EXP_P,
SERVERCONFIG, TIMET, TRUE, NS_LDAP_V2,
NULL, /* initialized by code to time+NS_LDAP_CACHETTL */
{ INT, 0, 0 },
NULL, NULL },
{"NS_LDAP_SERVER_PREF", NS_LDAP_SERVER_PREF_P,
CLIENTCONFIG, SERVLIST, FALSE, NS_LDAP_V2,
_P2_PREFERREDSERVER,
{ SERVLIST, 0, NULL },
__s_val_serverList, NULL },
{"NS_LDAP_SERVERS", NS_LDAP_SERVERS_P,
SERVERCONFIG, SERVLIST, FALSE, NS_LDAP_V2,
_P2_DEFAULTSERVER,
{ SERVLIST, 0, NULL },
__s_val_serverList, NULL },
{"NS_LDAP_SEARCH_BASEDN", NS_LDAP_SEARCH_BASEDN_P,
SERVERCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
_P2_SEARCHBASEDN,
{ CHARPTR, 0, NULL },
__s_val_basedn, NULL },
{"NS_LDAP_SEARCH_SCOPE", NS_LDAP_SEARCH_SCOPE_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V2,
_P2_SEARCHSCOPE,
{ INT, 0, INT2VOIDPTR(NS_LDAP_SCOPE_ONELEVEL) },
NULL, ns_scope_enum_v2 },
{"NS_LDAP_AUTH", NS_LDAP_AUTH_P,
CLIENTCONFIG, ARRAYAUTH, FALSE, NS_LDAP_V2,
_P2_AUTHMETHOD,
{ ARRAYAUTH, 2, (void *)&ns_def_auth_v2[0] },
NULL, ns_auth_enum_v2 },
{"NS_LDAP_CREDENTIAL_LEVEL", NS_LDAP_CREDENTIAL_LEVEL_P,
CLIENTCONFIG, ARRAYCRED, FALSE, NS_LDAP_V2,
_P2_CREDENTIALLEVEL,
{ ARRAYCRED, 0, (void *)&ns_def_cred_v2[0] },
NULL, ns_cred_enum_v2 },
{"NS_LDAP_SERVICE_SEARCH_DESC", NS_LDAP_SERVICE_SEARCH_DESC_P,
CLIENTCONFIG, SSDLIST, FALSE, NS_LDAP_V2,
_P2_SERVICESEARCHDESC,
{ SSDLIST, 0, NULL },
NULL, NULL },
{"NS_LDAP_SEARCH_TIME", NS_LDAP_SEARCH_TIME_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V2,
_P2_SEARCHTIMELIMIT,
{ INT, 0, INT2VOIDPTR(NS_DEFAULT_SEARCH_TIMEOUT) },
NULL, NULL },
{"NS_LDAP_BIND_TIME", NS_LDAP_BIND_TIME_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V2,
_P2_BINDTIMELIMIT,
{ INT, 0, INT2VOIDPTR(NS_DEFAULT_BIND_TIMEOUT) },
NULL, NULL },
{"NS_LDAP_SEARCH_REF", NS_LDAP_SEARCH_REF_P,
CLIENTCONFIG, INT, TRUE, NS_LDAP_V2,
_P2_FOLLOWREFERRALS,
{ INT, 0, INT2VOIDPTR(NS_LDAP_FOLLOWREF) },
NULL, ns_ref_enum_v2 },
{"NS_LDAP_CACHETTL", NS_LDAP_CACHETTL_P,
CLIENTCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
_P2_PROFILETTL,
{ CHARPTR, 0, (void *)EXP_DEFAULT_TTL },
__s_val_postime, NULL },
{"NS_LDAP_ATTRIBUTEMAP", NS_LDAP_ATTRIBUTEMAP_P,
CLIENTCONFIG, ATTRMAP, FALSE, NS_LDAP_V2,
_P2_ATTRIBUTEMAP,
{ ATTRMAP, 0, NULL },
NULL, NULL },
{"NS_LDAP_OBJECTCLASSMAP", NS_LDAP_OBJECTCLASSMAP_P,
CLIENTCONFIG, OBJMAP, FALSE, NS_LDAP_V2,
_P2_OBJECTCLASSMAP,
{ OBJMAP, 0, NULL },
NULL, NULL },
{"NS_LDAP_PROFILE", NS_LDAP_PROFILE_P,
CLIENTCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
_P_CN,
{ CHARPTR, 0, (void *)DEFAULTCONFIGNAME },
NULL, NULL },
{"NS_LDAP_SERVICE_AUTH_METHOD", NS_LDAP_SERVICE_AUTH_METHOD_P,
CLIENTCONFIG, SAMLIST, FALSE, NS_LDAP_V2,
_P2_SERVICEAUTHMETHOD,
{ SAMLIST, 0, NULL },
NULL, NULL },
{"NS_LDAP_SERVICE_CRED_LEVEL", NS_LDAP_SERVICE_CRED_LEVEL_P,
CLIENTCONFIG, SCLLIST, FALSE, NS_LDAP_V2,
_P2_SERVICECREDLEVEL,
{ SCLLIST, 0, NULL },
NULL, NULL },
{"NS_LDAP_HOST_CERTPATH", NS_LDAP_HOST_CERTPATH_P,
CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
NULL, /* not defined in the Profile */
{ CHARPTR, 0, (void *)NSLDAPDIRECTORY },
NULL, NULL },
/* array terminator [not an entry] */
{NULL, NS_LDAP_FILE_VERSION_P,
CLIENTCONFIG, NS_UNKNOWN, TRUE, NULL,
NULL,
{ NS_UNKNOWN, 0, NULL },
NULL, NULL },
};
static char *
__getdomainname()
{
/*
* The sysinfo man page recommends using a buffer size
* of 257 bytes. MAXHOSTNAMELEN is 256. So add 1 here.
*/
char buf[MAXHOSTNAMELEN + 1];
int status;
status = sysinfo(SI_SRPC_DOMAIN, buf, MAXHOSTNAMELEN);
if (status < 0)
return (NULL);
/* error: not enough space to hold returned value */
if (status > sizeof (buf))
return (NULL);
return (strdup(buf));
}
void
__ns_ldap_setServer(int set)
{
cache_server = set;
}
static boolean_t
timetorefresh(ns_config_t *cfg)
{
struct timeval tp;
static time_t expire = 0;
if (cfg == NULL || gettimeofday(&tp, NULL) == -1)
return (B_TRUE);
if (cfg->paramList[NS_LDAP_EXP_P].ns_ptype == TIMET)
expire = cfg->paramList[NS_LDAP_EXP_P].ns_tm;
else
return (B_TRUE);
return (expire != 0 && tp.tv_sec > expire);
}
int
__s_get_enum_value(ns_config_t *ptr, char *value, ParamIndexType i)
{
register ns_enum_map *mapp;
char *pstart = value;
char *pend;
int len;
if (pstart == NULL)
return (-1);
/* skip leading spaces */
while (*pstart == SPACETOK)
pstart++;
/* skip trailing spaces */
pend = pstart + strlen(pstart) - 1;
for (; pend >= pstart && *pend == SPACETOK; pend--);
len = pend - pstart + 1;
if (len == 0)
return (-1);
switch (i) {
case NS_LDAP_AUTH_P:
if (ptr->version == NS_LDAP_V1)
mapp = &ns_auth_enum_v1[0];
else
mapp = &ns_auth_enum_v2[0];
break;
case NS_LDAP_TRANSPORT_SEC_P:
return (-1);
case NS_LDAP_SEARCH_SCOPE_P:
if (ptr->version == NS_LDAP_V1)
mapp = &ns_scope_enum_v1[0];
else
mapp = &ns_scope_enum_v2[0];
break;
case NS_LDAP_SEARCH_REF_P:
if (ptr->version == NS_LDAP_V1)
mapp = &ns_ref_enum_v1[0];
else
mapp = &ns_ref_enum_v2[0];
break;
case NS_LDAP_PREF_ONLY_P:
mapp = &ns_pref_enum[0];
break;
case NS_LDAP_CREDENTIAL_LEVEL_P:
if (ptr->version == NS_LDAP_V1)
return (-1);
else
mapp = &ns_cred_enum_v2[0];
break;
case NS_LDAP_SERVICE_AUTH_METHOD_P:
mapp = &ns_auth_enum_v2[0];
break;
case NS_LDAP_SERVICE_CRED_LEVEL_P:
mapp = &ns_cred_enum_v2[0];
break;
default:
return (-1);
}
for (; mapp->name != NULL; mapp++) {
if (strncasecmp(pstart, mapp->name, len) == 0 &&
(strlen(mapp->name) == len)) {
return (mapp->value);
}
}
return (-1);
}
char *
__s_get_auth_name(ns_config_t *ptr, AuthType_t type)
{
register ns_enum_map *mapp;
if (ptr->version == NS_LDAP_V1)
mapp = &ns_auth_enum_v1[0];
else
mapp = &ns_auth_enum_v2[0];
for (; mapp->name != NULL; mapp++) {
if (type == INT2AUTHENUM(mapp->value)) {
return (mapp->name);
}
}
return ("Unknown AuthType_t type specified");
}
char *
__s_get_security_name(ns_config_t *ptr, TlsType_t type)
{
register ns_enum_map *mapp;
if (ptr->version == NS_LDAP_V1) {
mapp = &ns_sec_enum_v1[0];
for (; mapp->name != NULL; mapp++) {
if (type == INT2SECENUM(mapp->value)) {
return (mapp->name);
}
}
}
return ("Unknown TlsType_t type specified");
}
char *
__s_get_scope_name(ns_config_t *ptr, ScopeType_t type)
{
register ns_enum_map *mapp;
if (ptr->version == NS_LDAP_V1)
mapp = &ns_scope_enum_v1[0];
else
mapp = &ns_scope_enum_v2[0];
for (; mapp->name != NULL; mapp++) {
if (type == INT2SCOPEENUM(mapp->value)) {
return (mapp->name);
}
}
return ("Unknown ScopeType_t type specified");
}
char *
__s_get_pref_name(PrefOnly_t type)
{
register ns_enum_map *mapp = &ns_pref_enum[0];
for (; mapp->name != NULL; mapp++) {
if (type == INT2PREFONLYENUM(mapp->value)) {
return (mapp->name);
}
}
return ("Unknown PrefOnly_t type specified");
}
char *
__s_get_searchref_name(ns_config_t *ptr, SearchRef_t type)
{
register ns_enum_map *mapp;
if (ptr->version == NS_LDAP_V1)
mapp = &ns_ref_enum_v1[0];
else
mapp = &ns_ref_enum_v2[0];
for (; mapp->name != NULL; mapp++) {
if (type == INT2SEARCHREFENUM(mapp->value)) {
return (mapp->name);
}
}
return ("Unknown SearchRef_t type specified");
}
static char *
__s_get_credlvl_name(ns_config_t *ptr, CredLevel_t type)
{
register ns_enum_map *mapp;
if (ptr->version == NS_LDAP_V2) {
mapp = &ns_cred_enum_v2[0];
for (; mapp->name != NULL; mapp++) {
if (type == INT2CREDLEVELENUM(mapp->value)) {
return (mapp->name);
}
}
}
return ("Unknown CredLevel_t type specified");
}
static void
destroy_param(ns_config_t *ptr, ParamIndexType type)
{
int i, j;
char **ppc;
if (ptr == NULL)
return;
/*
* This routine is not lock protected because
* the config param it may be destroying is not
* necessarily THE config. Mutex protect elsewhere.
*/
switch (ptr->paramList[type].ns_ptype) {
case CHARPTR:
if (ptr->paramList[type].ns_pc) {
free(ptr->paramList[type].ns_pc);
ptr->paramList[type].ns_pc = NULL;
}
break;
case SAMLIST:
case SCLLIST:
case SSDLIST:
case ARRAYCP:
case SERVLIST:
if (ptr->paramList[type].ns_ppc) {
ppc = ptr->paramList[type].ns_ppc;
j = ptr->paramList[type].ns_acnt;
for (i = 0; i < j && ppc[i] != NULL; i++) {
free((void *)ppc[i]);
}
free((void *)ppc);
ptr->paramList[type].ns_ppc = NULL;
}
break;
case ARRAYAUTH:
case ARRAYCRED:
if (ptr->paramList[type].ns_pi) {
free(ptr->paramList[type].ns_pi);
ptr->paramList[type].ns_pi = NULL;
}
break;
case INT:
ptr->paramList[type].ns_i = 0;
break;
case ATTRMAP:
break;
case OBJMAP:
break;
default:
break;
}
ptr->paramList[type].ns_ptype = NS_UNKNOWN;
}
static void
destroy_config(ns_config_t *ptr)
{
ParamIndexType i;
if (ptr != NULL) {
if (ptr->domainName != NULL)
free(ptr->domainName);
ptr->domainName = NULL;
for (i = 0; i <= LAST_VALUE; i++) {
destroy_param(ptr, i);
}
__s_api_destroy_hash(ptr);
free(ptr);
}
}
/*
* Marks the ns_config_t to be deleted and then releases it. (If no other
* caller is using, then __s_api_release_config will destroy it.)
*
* Note that __s_api_destroy_config should only be called if the caller has
* created the ns_config_t with __s_api_create_config (with the exception
* of set_curr_config). The ns_config_t should be private to the caller.
*
* This function should not be called with the current_config except by
* set_curr_config which locks ns_parse_lock to ensure that no thread
* will be waiting on current_config->config_mutex. This ensures that
* no caller with be waiting on cfg->config_mutex while it is being
* destroyed by __s_api_release_config.
*/
void
__s_api_destroy_config(ns_config_t *cfg)
{
if (cfg != NULL) {
(void) mutex_lock(&cfg->config_mutex);
cfg->delete = TRUE;
(void) mutex_unlock(&cfg->config_mutex);
__s_api_release_config(cfg);
}
}
/*
* Increment the configuration use count by one - assumes ns_parse_lock has
* been obtained
*/
static ns_config_t *
get_curr_config_unlocked()
{
ns_config_t *cfg;
ns_config_t *ret;
cfg = current_config;
ret = cfg;
if (cfg != NULL) {
(void) mutex_lock(&cfg->config_mutex);
if (cfg->delete)
ret = NULL;
else
cfg->nUse++;
(void) mutex_unlock(&cfg->config_mutex);
}
return (ret);
}
/*
* set_curr_config sets the current config to
* the specified ns_config_t. Note that this function
* is similar to the project private function __s_api_init_config
* except that it does not release the new ns_config_t
*/
static void
set_curr_config(ns_config_t *ptr)
{
ns_config_t *cfg;
(void) mutex_lock(&ns_parse_lock);
cfg = get_curr_config_unlocked();
if (cfg != ptr) {
__s_api_destroy_config(cfg);
current_config = ptr;
}
(void) mutex_unlock(&ns_parse_lock);
}
/*
* Decrements the ns_config_t usage count by one. Delete if delete flag
* is set and no other callers are using.
*/
void
__s_api_release_config(ns_config_t *cfg)
{
if (cfg != NULL) {
(void) mutex_lock(&cfg->config_mutex);
cfg->nUse--;
if (cfg->nUse == 0 && cfg->delete) {
destroy_config(cfg);
} else
(void) mutex_unlock(&cfg->config_mutex);
}
}
/*
* __s_api_init_config function destroys the previous configuration
* sets the new configuration and then releases it
*/
void
__s_api_init_config(ns_config_t *ptr)
{
set_curr_config(ptr);
__s_api_release_config(ptr);
}
/*
* Create an ns_config_t, set the usage count to one
*/
ns_config_t *
__s_api_create_config(void)
{
ns_config_t *ret;
ret = (ns_config_t *)calloc(1, sizeof (ns_config_t));
if (ret == NULL)
return (NULL);
ret->domainName = __getdomainname();
if (ret->domainName == NULL) {
free(ret);
return (NULL);
}
ret->version = NS_LDAP_V1;
(void) mutex_init(&ret->config_mutex, USYNC_THREAD, NULL);
ret->nUse = 1;
ret->delete = B_FALSE;
return (ret);
}
ns_config_t *
__s_api_get_default_config(void)
{
ns_config_t *cfg;
(void) mutex_lock(&ns_parse_lock);
cfg = get_curr_config_unlocked();
(void) mutex_unlock(&ns_parse_lock);
return (cfg);
}
static char *
stripdup(const char *instr)
{
char *pstart = (char *)instr;
char *pend, *ret;
int len;
if (pstart == NULL)
return (NULL);
/* remove leading spaces */
while (*pstart == SPACETOK)
pstart++;
/* remove trailing spaces */
pend = pstart + strlen(pstart) - 1;
for (; pend >= pstart && *pend == SPACETOK; pend--);
len = pend - pstart + 1;
if ((ret = malloc(len + 1)) == NULL)
return (NULL);
if (len != 0) {
(void) strncpy(ret, pstart, len);
}
ret[len] = '\0';
return (ret);
}
static boolean_t
has_port(char **ppc, int cnt)
{
int j;
const char *s;
const char *begin;
/*
* Don't check that address is legal - only determine
* if there is a port specified
*/
if (ppc != NULL) {
for (j = 0; j < cnt; j++) {
begin = ppc[j];
s = begin + strlen(begin);
while (s >= begin) {
if (*s == ']')
break;
else if (*s == COLONTOK)
return (B_TRUE);
s--;
}
}
}
return (B_FALSE);
}
/*
* Note that __s_api_crosscheck is assumed to be called with an ns_config_t
* that is properly protected - so that it will not change during the
* duration of the call
*/
/* Size of errstr needs to be MAXERROR */
ns_parse_status
__s_api_crosscheck(ns_config_t *ptr, char *errstr, int check_dn)
{
int value, j;
time_t tm;
const char *str, *str1;
boolean_t has_tls = B_FALSE;
boolean_t is_ok = B_TRUE;
int i, len, cnt;
const char *begin;
char **ppc;
int *pi;
if (ptr == NULL)
return (NS_SUCCESS);
/* check for no server specified */
if (ptr->paramList[NS_LDAP_SERVERS_P].ns_ppc == NULL) {
if (ptr->version == NS_LDAP_V1) {
str = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_SERVERS_P));
(void) snprintf(errstr, MAXERROR,
gettext("Configuration Error: No entry for "
"'%s' found"), str);
return (NS_PARSE_ERR);
} else if (ptr->paramList[NS_LDAP_SERVER_PREF_P].ns_ppc ==
NULL) {
str = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_SERVERS_P));
str1 = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_SERVER_PREF_P));
(void) snprintf(errstr, MAXERROR,
gettext("Configuration Error: "
"Neither '%s' nor '%s' is defined"), str, str1);
return (NS_PARSE_ERR);
}
}
if (ptr->paramList[NS_LDAP_CERT_PASS_P].ns_pc != NULL &&
ptr->paramList[NS_LDAP_CERT_PATH_P].ns_pc == NULL) {
str = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_CERT_PASS_P));
str1 = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_CERT_PATH_P));
(void) snprintf(errstr, MAXERROR,
gettext("Configuration Error: %s specified "
"but no value for '%s' found"), str, str1);
return (NS_PARSE_ERR);
}
if (ptr->paramList[NS_LDAP_CERT_PASS_P].ns_pc == NULL &&
ptr->paramList[NS_LDAP_CERT_PATH_P].ns_pc != NULL) {
str = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_CERT_PATH_P));
str1 = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_CERT_PASS_P));
(void) snprintf(errstr, MAXERROR,
gettext("Configuration Error: %s specified "
"but no value for '%s' found"), str, str1);
return (NS_PARSE_ERR);
}
/* check if search basedn has been specified */
if (ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_ppc == NULL) {
str = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_SEARCH_BASEDN_P));
(void) snprintf(errstr, MAXERROR,
gettext("Configuration Error: No entry for "
"'%s' found"), str);
return (NS_PARSE_ERR);
}
if (check_dn) {
/* check for auth value....passwd/bindn if necessary */
for (j = 0; ptr->paramList[NS_LDAP_AUTH_P].ns_pi != NULL &&
ptr->paramList[NS_LDAP_AUTH_P].ns_pi[j] != NULL; j++) {
value = ptr->paramList[NS_LDAP_AUTH_P].ns_pi[j];
switch (value) {
case NS_LDAP_EA_SIMPLE:
case NS_LDAP_EA_SASL_CRAM_MD5:
case NS_LDAP_EA_SASL_DIGEST_MD5:
case NS_LDAP_EA_SASL_DIGEST_MD5_INT:
case NS_LDAP_EA_SASL_DIGEST_MD5_CONF:
case NS_LDAP_EA_TLS_SIMPLE:
case NS_LDAP_EA_TLS_SASL_CRAM_MD5:
case NS_LDAP_EA_TLS_SASL_DIGEST_MD5:
case NS_LDAP_EA_TLS_SASL_DIGEST_MD5_INT:
case NS_LDAP_EA_TLS_SASL_DIGEST_MD5_CONF:
if (ptr->paramList[NS_LDAP_BINDDN_P].ns_ppc == NULL) {
str = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_BINDDN_P));
(void) snprintf(errstr, MAXERROR,
gettext("Configuration Error: No entry for "
"'%s' found"), str);
return (NS_PARSE_ERR);
}
if (ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_ppc
== NULL) {
str = NULL_OR_STR(__s_api_get_configname(
NS_LDAP_BINDPASSWD_P));
(void) snprintf(errstr, MAXERROR,
gettext("Configuration Error: No entry for "
"'%s' found"), str);
return (NS_PARSE_ERR);
}
break;
}
}
}
/*
* Check to see if port and tls are both configured. This is not
* supported until starttls is supported.
*/
pi = ptr->paramList[NS_LDAP_AUTH_P].ns_pi;
if (pi != NULL) {
cnt = ptr->paramList[NS_LDAP_AUTH_P].ns_acnt;
for (j = 0; j < cnt && !has_tls; j++) {
has_tls = (pi[j] == NS_LDAP_EA_TLS_NONE) ||
(pi[j] == NS_LDAP_EA_TLS_SIMPLE) ||
(pi[j] == NS_LDAP_EA_TLS_SASL_CRAM_MD5) ||
(pi[j] == NS_LDAP_EA_TLS_SASL_DIGEST_MD5) ||
(pi[j] == NS_LDAP_EA_TLS_SASL_DIGEST_MD5_INT) ||
(pi[j] == NS_LDAP_EA_TLS_SASL_DIGEST_MD5_CONF) ||
(pi[j] == NS_LDAP_EA_TLS_SASL_EXTERNAL);
}
}
ppc = ptr->paramList[NS_LDAP_SERVICE_AUTH_METHOD_P].ns_ppc;
if (!has_tls && ppc != NULL) {
cnt = ptr->paramList[NS_LDAP_SERVICE_AUTH_METHOD_P].ns_acnt;
for (j = 0; j < cnt && !has_tls; j++) {
begin = ppc[j];
/* skip over service tag */
if (begin != NULL)
begin = strchr(begin, ':');
if (!has_tls && begin != NULL) {
len = strlen(begin) - 3;
for (i = 0; i < len; i++)
if (strncasecmp(begin + i, "tls:", 4) == 0)
break;
has_tls = i < len;
}
}
}
if (has_tls) {
is_ok = !has_port(ptr->paramList[NS_LDAP_SERVERS_P].ns_ppc,
ptr->paramList[NS_LDAP_SERVERS_P].ns_acnt);
ppc = ptr->paramList[NS_LDAP_SERVER_PREF_P].ns_ppc;
if (is_ok)
is_ok = !has_port(ptr->paramList[NS_LDAP_SERVER_PREF_P].ns_ppc,
ptr->paramList[NS_LDAP_SERVER_PREF_P].ns_acnt);
}
if (!is_ok) {
(void) snprintf(errstr, MAXERROR,
gettext("Configuration Error: "
"Cannot specify LDAP port with tls"));
return (NS_PARSE_ERR);
}
/*
* If NS_LDAP_CACHETTL is not specified,
* init NS_LDAP_EXP_P here. Otherwise,
* ldap_cachemgr will never refresh the profile.
* Set it to current time + default
* NS_LDAP_CACHETTL
*/
if (ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc == NULL) {
tm = conv_time(
defconfig[NS_LDAP_CACHETTL_P].defval.ns_pc);
ptr->paramList[NS_LDAP_EXP_P].ns_ptype = TIMET;
if (tm != 0) {
tm += time(NULL);
}
ptr->paramList[NS_LDAP_EXP_P].ns_tm = tm;
}
return (NS_SUCCESS);
}
int
__s_api_get_type(const char *value, ParamIndexType *type)
{
int i;
for (i = 0; defconfig[i].name != NULL; i++) {
if (strcasecmp(defconfig[i].name, value) == 0) {
*type = defconfig[i].index;
return (0);
}
}
return (-1);
}
/*
* Externally defined version of get_type.
* Includes extra error checking
*/
int
__ns_ldap_getParamType(const char *value, ParamIndexType *type)
{
if (value == NULL || type == NULL)
return (-1);
return (__s_api_get_type(value, type));
}
int
__s_api_get_versiontype(ns_config_t *ptr, char *value, ParamIndexType *type)
{
ns_version_t ver;
int i;
if (ptr == NULL)
return (-1);
ver = ptr->version;
for (i = 0; defconfig[i].name != NULL; i++) {
if (strcasecmp(defconfig[i].name, value) == 0) {
if (defconfig[i].version == ver) {
*type = defconfig[i].index;
return (0);
}
}
}
return (-1);
}
int
__s_api_get_profiletype(char *value, ParamIndexType *type)
{
int i;
for (i = 0; defconfig[i].name != NULL; i++) {
if (defconfig[i].profile_name == NULL)
continue;
if (strcasecmp(defconfig[i].profile_name, value) == 0) {
*type = defconfig[i].index;
return (0);
}
}
return (-1);
}
int
__s_api_get_configtype(ParamIndexType type)
{
int i;
for (i = 0; defconfig[i].name != NULL; i++) {
if (defconfig[i].index == type) {
return (defconfig[i].config_type);
}
}
return (-1);
}
const char *
__s_api_get_configname(ParamIndexType type)
{
int i;
for (i = 0; defconfig[i].name != NULL; i++) {
if (defconfig[i].index == type) {
if (defconfig[i].name[0] == '\0')
return (NULL);
else
return (defconfig[i].name);
}
}
return (NULL);
}
static ns_default_config *
get_defconfig(ns_config_t *ptr, ParamIndexType type)
{
ns_version_t ver;
int i;
ver = ptr->version;
for (i = 0; defconfig[i].name != NULL; i++) {
if (defconfig[i].index == type &&
defconfig[i].version == ver) {
return (&defconfig[i]);
}
}
return (NULL);
}
static int
set_default_value(ns_config_t *configptr, char *name,
char *value, ns_ldap_error_t **error)
{
ParamIndexType i;
int ret;
char errstr[MAXERROR];
if (__s_api_get_type(name, &i) < 0) {
(void) snprintf(errstr, sizeof (errstr), gettext(
"Illegal type name (%s).\n"), name);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
NULL);
return (NS_LDAP_CONFIG);
}
if (i != NS_LDAP_SERVERS_P &&
i != NS_LDAP_SERVICE_AUTH_METHOD_P &&
i != NS_LDAP_SERVICE_CRED_LEVEL_P &&
i != NS_LDAP_SERVICE_SEARCH_DESC_P &&
i != NS_LDAP_SERVER_PREF_P &&
i != NS_LDAP_SEARCH_DN_P) {
if (configptr->paramList[i].ns_ptype != NS_UNKNOWN) {
destroy_param(configptr, i);
}
}
ret = __ns_ldap_setParamValue(configptr, i, value, error);
return (ret);
}
/*
* Initialize config to a default state
* By default leave configuration empty
* getParam will automatically get the
* appropriate default value if none exists
*/
void
__ns_ldap_default_config()
{
ns_config_t *ptr;
ptr = __s_api_create_config();
if (ptr == NULL)
return;
set_curr_config(ptr);
__s_api_release_config(ptr);
}
/*
* Get the current configuration pointer and return it.
* If necessary initialize or refresh the current
* configuration as applicable.
*/
ns_config_t *
__s_api_loadrefresh_config()
{
ns_config_t *cfg;
ns_config_t *new_cfg;
ns_ldap_error_t *errorp;
/* We want to refresh only one configuration at a time */
(void) mutex_lock(&ns_loadrefresh_lock);
cfg = __s_api_get_default_config();
/* (re)initialize configuration if necessary */
if (timetorefresh(cfg)) {
new_cfg = LoadCacheConfiguration(&errorp);
if (new_cfg != NULL) {
__s_api_release_config(cfg);
set_curr_config(new_cfg);
cfg = new_cfg;
}
if (errorp != NULL)
(void) __ns_ldap_freeError(&errorp);
}
(void) mutex_unlock(&ns_loadrefresh_lock);
return (cfg);
}
/*
* In general this routine is not very usefull. Individual routines can be
* created to do this job. Once that is done, this function can be removed.
* Size of errstr buffer needs to be MAXERROR.
*/
static ns_parse_status
verify_value(ns_config_t *cfg, char *name, char *value, char *errstr)
{
ParamIndexType index = 0;
int found = 0, j;
char *ptr = NULL, *strptr = NULL, buffer[BUFSIZE];
char *rest;
ns_default_config *def = NULL;
if (__s_api_get_type(name, &index) != 0) {
(void) snprintf(errstr, MAXERROR,
gettext("Unknown keyword encountered '%s'."), name);
return (NS_PARSE_ERR);
}
def = get_defconfig(cfg, index);
/* eat up beginning quote, if any */
while (value != NULL && (*value == QUOTETOK || *value == SPACETOK))
value++;
/* eat up space/quote at end of value */
if (strlen(value) > 0)
ptr = value + strlen(value) - 1;
else
ptr = value;
for (; ptr != value && (*ptr == SPACETOK || *ptr == QUOTETOK); ptr--) {
*ptr = '\0';
}
switch (index) {
case NS_LDAP_EXP_P:
case NS_LDAP_CACHETTL_P:
case NS_LDAP_CERT_PATH_P:
case NS_LDAP_CERT_PASS_P:
case NS_LDAP_CERT_NICKNAME_P:
case NS_LDAP_BINDDN_P:
case NS_LDAP_BINDPASSWD_P:
case NS_LDAP_DOMAIN_P:
case NS_LDAP_SEARCH_BASEDN_P:
case NS_LDAP_SEARCH_TIME_P:
case NS_LDAP_PROFILE_P:
case NS_LDAP_AUTH_P:
case NS_LDAP_SEARCH_SCOPE_P:
case NS_LDAP_CREDENTIAL_LEVEL_P:
case NS_LDAP_SERVICE_SEARCH_DESC_P:
case NS_LDAP_BIND_TIME_P:
case NS_LDAP_ATTRIBUTEMAP_P:
case NS_LDAP_OBJECTCLASSMAP_P:
case NS_LDAP_SERVICE_AUTH_METHOD_P:
case NS_LDAP_SERVICE_CRED_LEVEL_P:
case NS_LDAP_HOST_CERTPATH_P:
break;
case NS_LDAP_SEARCH_DN_P:
/* depreciated because of service descriptors */
/* Parse as appropriate at descriptor create time */
break;
case NS_LDAP_FILE_VERSION_P:
if (value != NULL &&
strcasecmp(value, NS_LDAP_VERSION_1) != 0 &&
strcasecmp(value, NS_LDAP_VERSION_2) != 0) {
(void) snprintf(errstr, MAXERROR,
gettext("Version mismatch, expected "
"cache version '%s' or '%s' but "
"encountered version '%s'."),
NS_LDAP_VERSION_1,
NS_LDAP_VERSION_2, value);
return (NS_PARSE_ERR);
}
break;
case NS_LDAP_SERVERS_P:
case NS_LDAP_SERVER_PREF_P:
(void) strcpy(buffer, value);
strptr = strtok_r(buffer, ",", &rest);
while (strptr != NULL) {
char *tmp = NULL;
tmp = stripdup(strptr);
if (tmp == NULL || (strchr(tmp, ' ') != NULL)) {
(void) snprintf(errstr, MAXERROR,
gettext("Invalid parameter values "
"'%s' specified for keyword '%s'."),
tmp, name);
free(tmp);
return (NS_PARSE_ERR);
}
free(tmp);
strptr = strtok_r(NULL, ",", &rest);
}
break;
default:
found = 0; j = 0;
while (def->allowed != NULL &&
def->allowed[j].name != NULL && j < DEFMAX) {
if (strcmp(def->allowed[j].name,
value) == 0) {
found = 1;
break;
}
j++;
}
if (!found) {
(void) snprintf(errstr, MAXERROR,
gettext("Invalid option specified for "
"'%s' keyword. '%s' is not a recognized "
"keyword value."), name, value);
return (NS_PARSE_ERR);
}
}
return (NS_SUCCESS);
}
void
__s_api_split_key_value(char *buffer, char **name, char **value)
{
char *ptr;
*name = buffer;
/* split into name value pair */
if ((ptr = strchr(buffer, TOKENSEPARATOR)) != NULL) {
*ptr = '\0';
ptr++;
/* trim whitespace */
while (*ptr == SPACETOK)
ptr++;
*value = ptr;
}
}
/*
* Set a parameter value in a generic configuration structure
* Assume any necessary locks are in place. This routine would
* be better named: __ns_ldap_translateString2Param
*
* This routine translates external string format into internal
* param format and saves the result in the param table.
*/
int
__ns_ldap_setParamValue(ns_config_t *ptr, const ParamIndexType type,
const void *data, ns_ldap_error_t **error)
{
ns_default_config *def = NULL;
ns_param_t conf;
ns_mapping_t *map, *rmap;
int i, j, len;
char *cp, *cp2, *end;
char *tcp = NULL;
char errstr[2 * MAXERROR];
char tbuf[100], *ptbuf;
char *sid, *origA, **mapA;
char **attr;
time_t tm;
int free_memory, exitrc;
char **p;
/* Find ParamIndexType default configuration data */
def = get_defconfig(ptr, type);
if (def == NULL) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid ParamIndexType (%d)"), type);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
NULL);
return (NS_LDAP_CONFIG);
}
(void) memset(&conf, 0, sizeof (conf));
/* data is actually const char */
cp = (char *)data;
/* eat up beginning quote, if any */
while (cp && (*cp == QUOTETOK || *cp == SPACETOK))
cp++;
/* eat up space/quote at end of value */
end = cp2 = cp + strlen(cp) - 1;
for (; cp2 > cp && (*cp2 == SPACETOK || *cp2 == QUOTETOK); cp2--)
;
/* data is const, must duplicate */
if (cp2 != end) {
tcp = (char *)calloc((int)(cp2 - cp + 2), sizeof (char));
if (tcp == NULL)
return (NS_LDAP_MEMORY);
end = cp2;
cp2 = tcp;
while (cp <= end) {
*cp2++ = *cp++;
}
*cp2 = '\0';
cp = tcp;
}
/* Parse data according to type */
switch (def->data_type) {
case INT:
switch (def->index) {
case NS_LDAP_PREF_ONLY_P:
case NS_LDAP_SEARCH_REF_P:
case NS_LDAP_SEARCH_SCOPE_P:
i = __s_get_enum_value(ptr, cp, def->index);
if (i < 0) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid %s (%d)"), def->name,
def->index);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
conf.ns_i = i;
break;
case NS_LDAP_TRANSPORT_SEC_P: /* ignore TRANSPORT_SEC */
break;
default:
cp2 = cp;
if ((*cp2 == '+') || (*cp2 == '-'))
cp2++;
for (/* empty */; *cp2; cp2++) {
if (isdigit(*cp2))
continue;
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid %s (%d)"), def->name,
def->index);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
i = atoi(cp);
conf.ns_i = i;
break;
}
break;
case TIMET:
/* Do nothing with a TIMET. Initialize it below */
break;
case CHARPTR:
conf.ns_pc = (char *)strdup(cp);
if (conf.ns_pc == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
break;
case SAMLIST:
/* first check to see if colon (:) is there */
if ((strchr(cp, COLONTOK)) == NULL) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid serviceAuthenticationMethod (%s)"),
cp);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
/* Appends an entry to the existing list */
if (ptr->paramList[type].ns_ptype != SAMLIST) {
conf.ns_ppc = (char **)calloc(2, sizeof (char *));
if (conf.ns_ppc == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = 1;
conf.ns_ppc[0] = (char *)strdup(cp);
if (conf.ns_ppc[0] == NULL) {
free(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
} else {
char *dp, *dpend;
int fnd = 0;
/* Attempt to replace if possible */
dpend = strchr(cp, COLONTOK);
len = dpend - cp;
dp = (char *)malloc(len+1);
if (dp == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
(void) strlcpy(dp, cp, len+1);
fnd = 0;
for (j = 0; j < ptr->paramList[type].ns_acnt; j++) {
dpend = strchr(ptr->paramList[type].ns_ppc[j],
COLONTOK);
if (dpend == NULL)
continue;
i = dpend - ptr->paramList[type].ns_ppc[j];
if (i != len)
continue;
if (strncmp(ptr->paramList[type].ns_ppc[j],
dp, len) == 0) {
conf.ns_acnt =
ptr->paramList[type].ns_acnt;
conf.ns_ppc =
ptr->paramList[type].ns_ppc;
ptr->paramList[type].ns_ppc = NULL;
free(conf.ns_ppc[j]);
conf.ns_ppc[j] = (char *)strdup(cp);
if (conf.ns_ppc[j] == NULL) {
free(dp);
__s_api_free2dArray
(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
fnd = 1;
break;
}
}
free(dp);
if (fnd)
break; /* Replaced completed */
/* Append */
len = ptr->paramList[type].ns_acnt + 1;
if (len > 1) {
p = (char **)dupParam(&ptr->paramList[type]);
if (p == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
} else
p = NULL;
conf.ns_ppc =
(char **)realloc(p, (len+1) * sizeof (char *));
if (conf.ns_ppc == NULL) {
__s_api_free2dArray(p);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = len;
conf.ns_ppc[len-1] = (char *)strdup(cp);
if (conf.ns_ppc[len-1] == NULL) {
__s_api_free2dArray(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_ppc[len] = NULL;
}
break;
case SCLLIST:
/* first check to see if colon (:) is there */
if ((strchr(cp, COLONTOK)) == NULL) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid serviceCredentialLevel (%s)"),
cp);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
/* Appends an entry to the existing list */
if (ptr->paramList[type].ns_ptype != SCLLIST) {
conf.ns_ppc = (char **)calloc(2, sizeof (char *));
if (conf.ns_ppc == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = 1;
conf.ns_ppc[0] = (char *)strdup(cp);
if (conf.ns_ppc[0] == NULL) {
free(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
} else {
char *dp, *dpend;
int fnd = 0;
/* Attempt to replace if possible */
dpend = strchr(cp, COLONTOK);
len = dpend - cp;
dp = (char *)malloc(len+1);
if (dp == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
(void) strlcpy(dp, cp, len+1);
fnd = 0;
for (j = 0; j < ptr->paramList[type].ns_acnt; j++) {
dpend = strchr(ptr->paramList[type].ns_ppc[j],
COLONTOK);
if (dpend == NULL)
continue;
i = dpend - ptr->paramList[type].ns_ppc[j];
if (i != len)
continue;
if (strncmp(ptr->paramList[type].ns_ppc[j],
dp, len) == 0) {
conf.ns_acnt =
ptr->paramList[type].ns_acnt;
conf.ns_ppc =
ptr->paramList[type].ns_ppc;
ptr->paramList[type].ns_ppc = NULL;
free(conf.ns_ppc[j]);
conf.ns_ppc[j] = (char *)strdup(cp);
if (conf.ns_ppc[j] == NULL) {
free(dp);
__s_api_free2dArray
(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
fnd = 1;
break;
}
}
free(dp);
if (fnd)
break; /* Replaced completed */
/* Append */
len = ptr->paramList[type].ns_acnt + 1;
if (len > 1) {
p = (char **)dupParam(&ptr->paramList[type]);
if (p == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
} else
p = NULL;
conf.ns_ppc =
(char **)realloc(p, (len+1) * sizeof (char *));
if (conf.ns_ppc == NULL) {
__s_api_free2dArray(p);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = len;
conf.ns_ppc[len-1] = (char *)strdup(cp);
if (conf.ns_ppc[len-1] == NULL) {
__s_api_free2dArray(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_ppc[len] = NULL;
}
break;
case SSDLIST:
/*
* first check to see if colon (:) is there,
* if so, make sure the serviceId is specified,
* i.e., colon is not the first character
*/
if ((strchr(cp, COLONTOK)) == NULL || *cp == COLONTOK) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid serviceSearchDescriptor (%s)"),
cp);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
/* Appends an entry to the existing list */
if (ptr->paramList[type].ns_ptype != SSDLIST) {
conf.ns_ppc = (char **)calloc(2, sizeof (char *));
if (conf.ns_ppc == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = 1;
conf.ns_ppc[0] = (char *)strdup(cp);
if (conf.ns_ppc[0] == NULL) {
free(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
} else {
char *dp, *dpend;
int fnd = 0;
/* Attempt to replace if possible */
dpend = strchr(cp, COLONTOK);
len = dpend - cp;
dp = (char *)malloc(len+1);
if (dp == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
(void) strlcpy(dp, cp, len+1);
fnd = 0;
for (j = 0; j < ptr->paramList[type].ns_acnt; j++) {
dpend = strchr(ptr->paramList[type].ns_ppc[j],
COLONTOK);
if (dpend == NULL)
continue;
i = dpend - ptr->paramList[type].ns_ppc[j];
if (i != len)
continue;
if (strncmp(ptr->paramList[type].ns_ppc[j],
dp, len) == 0) {
conf.ns_acnt =
ptr->paramList[type].ns_acnt;
conf.ns_ppc =
ptr->paramList[type].ns_ppc;
ptr->paramList[type].ns_ppc = NULL;
free(conf.ns_ppc[j]);
conf.ns_ppc[j] = (char *)strdup(cp);
if (conf.ns_ppc[j] == NULL) {
free(dp);
__s_api_free2dArray
(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
fnd = 1;
break;
}
}
free(dp);
if (fnd)
break; /* Replaced completed */
/* Append */
len = ptr->paramList[type].ns_acnt + 1;
if (len > 1) {
p = (char **)dupParam(&ptr->paramList[type]);
if (p == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
} else
p = NULL;
conf.ns_ppc =
(char **)realloc(p, (len+1) * sizeof (char *));
if (conf.ns_ppc == NULL) {
__s_api_free2dArray(p);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = len;
conf.ns_ppc[len-1] = (char *)strdup(cp);
if (conf.ns_ppc[len-1] == NULL) {
__s_api_free2dArray(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_ppc[len] = NULL;
}
break;
case ARRAYCP:
len = 0;
for (cp2 = cp; *cp2; cp2++) {
if (*cp2 == COMMATOK)
len++;
}
if (cp != cp2)
len++;
if (len == 0) {
conf.ns_ppc = (char **)NULL;
conf.ns_acnt = 0;
break;
}
conf.ns_ppc = (char **)calloc(len + 1, sizeof (char *));
if (conf.ns_ppc == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = len;
i = 0;
for (cp2 = cp; *cp2; cp2++) {
if (*cp2 == COMMATOK) {
j = cp2 - cp + 1;
conf.ns_ppc[i] = (char *)malloc(j + 1);
if (conf.ns_ppc[i] == NULL) {
__s_api_free2dArray(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
(void) strlcpy(conf.ns_ppc[i], cp, j);
cp = cp2+1;
while (*cp == SPACETOK || *cp == COMMATOK)
cp++;
cp2 = cp - 1;
i++;
}
}
j = cp2 - cp + 1;
conf.ns_ppc[i] = (char *)malloc(j + 1);
if (conf.ns_ppc[i] == NULL) {
__s_api_free2dArray(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
(void) strlcpy(conf.ns_ppc[i], cp, j);
break;
case SERVLIST:
len = 0;
for (cp2 = cp; *cp2; cp2++) {
if (*cp2 == SPACETOK || *cp2 == COMMATOK) {
len++;
for (; *(cp2 + 1) == SPACETOK ||
*(cp2 +1) == COMMATOK; cp2++)
;
}
}
if (cp != cp2)
len++;
if (len == 0) {
conf.ns_ppc = (char **)NULL;
conf.ns_acnt = 0;
break;
}
conf.ns_ppc = (char **)calloc(len + 1, sizeof (char *));
if (conf.ns_ppc == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = len;
i = 0;
for (cp2 = cp; *cp2; cp2++) {
if (*cp2 == SPACETOK || *cp2 == COMMATOK) {
j = cp2 - cp + 1;
conf.ns_ppc[i] = (char *)malloc(j + 1);
if (conf.ns_ppc[i] == NULL) {
__s_api_free2dArray(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
(void) strlcpy(conf.ns_ppc[i], cp, j);
cp = cp2+1;
while (*cp == SPACETOK || *cp == COMMATOK)
cp++;
cp2 = cp - 1;
i++;
}
}
j = cp2 - cp + 1;
conf.ns_ppc[i] = (char *)malloc(j + 1);
if (conf.ns_ppc[i] == NULL) {
__s_api_free2dArray(conf.ns_ppc);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
(void) strlcpy(conf.ns_ppc[i], cp, j);
break;
case ARRAYAUTH:
len = 0;
for (cp2 = cp; *cp2; cp2++) {
if (*cp2 == SEMITOK || *cp2 == COMMATOK)
len++;
}
if (cp != cp2)
len++;
if (len == 0) {
conf.ns_pi = (int *)NULL;
conf.ns_acnt = 0;
break;
}
conf.ns_pi = (int *)calloc(len + 1, sizeof (int));
if (conf.ns_pi == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = len;
i = 0;
for (cp2 = cp; *cp2; cp2++) {
if (*cp2 == SEMITOK || *cp2 == COMMATOK) {
j = cp2 - cp + 1;
if (j > sizeof (tbuf)) {
j = -1;
ptbuf = cp;
} else {
(void) strlcpy(tbuf, cp, j);
j = __s_get_enum_value(ptr, tbuf,
def->index);
ptbuf = tbuf;
}
if (j < 0) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid authenticationMethod (%s)"),
ptbuf);
MKERROR(LOG_ERR, *error,
NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
free(conf.ns_pi);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
conf.ns_pi[i] = j;
cp = cp2+1;
i++;
}
}
j = cp2 - cp + 1;
if (j > sizeof (tbuf)) {
j = -1;
ptbuf = cp;
} else {
(void) strlcpy(tbuf, cp, j);
j = __s_get_enum_value(ptr, tbuf, def->index);
ptbuf = tbuf;
}
if (j < 0) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid authenticationMethod (%s)"), ptbuf);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
conf.ns_pi[i] = j;
break;
case ARRAYCRED:
len = 0;
for (cp2 = cp; *cp2; cp2++) {
if (*cp2 == SPACETOK)
len++;
}
if (cp != cp2)
len++;
if (len == 0) {
conf.ns_pi = (int *)NULL;
conf.ns_acnt = 0;
break;
}
conf.ns_pi = (int *)calloc(len + 1, sizeof (int));
if (conf.ns_pi == NULL) {
if (tcp != NULL)
free(tcp);
return (NS_LDAP_MEMORY);
}
conf.ns_acnt = len;
i = 0;
for (cp2 = cp; *cp2; cp2++) {
if (*cp2 == SPACETOK) {
j = cp2 - cp + 1;
if (j > sizeof (tbuf)) {
j = -1;
ptbuf = cp;
} else {
(void) strlcpy(tbuf, cp, j);
j = __s_get_enum_value(ptr, tbuf,
def->index);
ptbuf = tbuf;
}
if (j < 0) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid credentialLevel (%s)"),
ptbuf);
MKERROR(LOG_ERR, *error,
NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
free(conf.ns_pi);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
conf.ns_pi[i] = j;
cp = cp2+1;
i++;
}
}
j = cp2 - cp + 1;
if (j > sizeof (tbuf)) {
j = -1;
ptbuf = cp;
} else {
(void) strlcpy(tbuf, cp, j);
j = __s_get_enum_value(ptr, tbuf, def->index);
ptbuf = tbuf;
}
if (j < 0) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid credentialLevel (%s)"), ptbuf);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
conf.ns_pi[i] = j;
break;
case ATTRMAP:
case OBJMAP:
i = __s_api_parse_map(cp, &sid, &origA, &mapA);
if (i != NS_HASH_RC_SUCCESS) {
if (i == NS_HASH_RC_NO_MEMORY) {
exitrc = NS_LDAP_MEMORY;
} else {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: "
"invalid schema mapping (%s)"), cp);
exitrc = NS_LDAP_CONFIG;
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
}
if (tcp)
free(tcp);
return (exitrc);
}
/*
* Add reverse map first.
* There could be more than one.
*/
for (attr = mapA; *attr; attr++) {
free_memory = 1;
exitrc = NS_LDAP_MEMORY;
rmap = (ns_mapping_t *)calloc(1,
sizeof (ns_mapping_t));
if (rmap) {
rmap->service = strdup(sid);
if (rmap->service) {
rmap->orig = strdup(*attr);
if (rmap->orig) {
rmap->map = (char **)calloc(2,
sizeof (char *));
if (rmap->map) {
(rmap->map)[0] =
strdup(origA);
if ((rmap->map)[0])
free_memory = 0;
}
}
}
}
if (free_memory == 0) {
if (def->data_type == ATTRMAP) {
rmap->type = NS_ATTR_MAP;
i = __s_api_add_map2hash(ptr,
NS_HASH_RAMAP, rmap);
} else {
rmap->type = NS_OBJ_MAP;
i = __s_api_add_map2hash(ptr,
NS_HASH_ROMAP, rmap);
}
if (i != NS_HASH_RC_SUCCESS) {
switch (i) {
case NS_HASH_RC_CONFIG_ERROR:
exitrc = NS_LDAP_INTERNAL;
(void) snprintf(errstr,
sizeof (errstr),
gettext(
"Unable to set value: "
"no configuration info "
"for schema map "
"update (%s)"), cp);
MKERROR(LOG_ERR, *error,
NS_LDAP_INTERNAL,
strdup(errstr),
NULL);
break;
case NS_HASH_RC_EXISTED:
exitrc = NS_LDAP_CONFIG;
(void) snprintf(errstr,
sizeof (errstr),
gettext(
"Unable to set value: "
"schema map "
"already existed for "
"(%s, %s)."),
*attr, origA);
MKERROR(LOG_ERR, *error,
NS_CONFIG_SYNTAX,
strdup(errstr),
NULL);
break;
case NS_HASH_RC_NO_MEMORY:
exitrc = NS_LDAP_MEMORY;
break;
}
free_memory = 1;
}
}
if (free_memory) {
if (tcp)
free(tcp);
free(sid);
free(origA);
__s_api_free2dArray(mapA);
if (rmap) {
if (rmap->service)
free(rmap->service);
if (rmap->orig)
free(rmap->orig);
if (rmap->map) {
if ((rmap->map)[0])
free((rmap->map)[0]);
free(rmap->map);
}
free(rmap);
}
return (exitrc);
}
}
/*
* For performance gain,
* add a "schema mapping existed" indicator
* for the given service if not already added.
* This dummy map needs not be removed, if
* the next real map add operation fails.
* since the caller, e.g. ldap_cachemgr.
* should exit anyway.
*/
free_memory = 1;
exitrc = NS_LDAP_MEMORY;
map = (ns_mapping_t *)calloc(1,
sizeof (ns_mapping_t));
if (map) {
map->service = strdup(sid);
if (map->service) {
map->orig = strdup(
NS_HASH_SCHEMA_MAPPING_EXISTED);
if (map->orig) {
map->map = (char **)calloc(2,
sizeof (char *));
if (map->map) {
(map->map)[0] =
strdup(sid);
if ((map->map)[0])
free_memory = 0;
}
}
}
}
if (free_memory == 0) {
map->type = NS_ATTR_MAP;
/*
* add to reverse map,
* so that "ldapclient list"
* would not show it
*/
i = __s_api_add_map2hash(ptr,
NS_HASH_RAMAP, map);
/*
* ignore "map already existed" error,
* just need one per service.
* Need however to free memory allocated
* for map.
*/
if (i != NS_HASH_RC_SUCCESS &&
i != NS_HASH_RC_EXISTED) {
switch (i) {
case NS_HASH_RC_CONFIG_ERROR:
exitrc = NS_LDAP_INTERNAL;
(void) snprintf(errstr,
sizeof (errstr),
gettext(
"Unable to set value: "
"no configuration info "
"for schema map "
"update (%s)"), cp);
MKERROR(LOG_ERR, *error,
NS_LDAP_INTERNAL,
strdup(errstr),
NULL);
break;
case NS_HASH_RC_NO_MEMORY:
exitrc = NS_LDAP_MEMORY;
break;
}
free_memory = 1;
} else if (i == NS_HASH_RC_EXISTED) {
if (map->service)
free(map->service);
if (map->orig)
free(map->orig);
if (map->map) {
if ((map->map)[0])
free((map->map)[0]);
free(map->map);
}
free(map);
map = NULL;
}
}
if (free_memory) {
if (tcp)
free(tcp);
free(sid);
free(origA);
__s_api_free2dArray(mapA);
if (map) {
if (map->service)
free(map->service);
if (map->orig)
free(map->orig);
if (map->map) {
if ((map->map)[0])
free((map->map)[0]);
free(map->map);
}
free(map);
}
return (exitrc);
}
/*
* add the real schema map
*/
free_memory = 1;
exitrc = NS_LDAP_MEMORY;
map = (ns_mapping_t *)calloc(1, sizeof (ns_mapping_t));
if (map) {
map->service = sid;
map->orig = origA;
map->map = mapA;
if (def->data_type == ATTRMAP) {
map->type = NS_ATTR_MAP;
i = __s_api_add_map2hash(ptr,
NS_HASH_AMAP, map);
} else {
map->type = NS_OBJ_MAP;
i = __s_api_add_map2hash(ptr,
NS_HASH_OMAP, map);
}
if (i != NS_HASH_RC_SUCCESS) {
switch (i) {
case NS_HASH_RC_CONFIG_ERROR:
exitrc = NS_LDAP_INTERNAL;
(void) snprintf(errstr,
sizeof (errstr),
gettext(
"Unable to set value: "
"no configuration info "
"for schema map "
"update (%s)"), cp);
MKERROR(LOG_ERR, *error,
NS_LDAP_INTERNAL,
strdup(errstr),
NULL);
break;
case NS_HASH_RC_EXISTED:
exitrc = NS_LDAP_CONFIG;
(void) snprintf(errstr,
sizeof (errstr),
gettext(
"Unable to set value: "
"schema map "
"already existed for "
"'%s'."), origA);
MKERROR(LOG_ERR, *error,
NS_CONFIG_SYNTAX,
strdup(errstr),
NULL);
break;
case NS_HASH_RC_NO_MEMORY:
exitrc = NS_LDAP_MEMORY;
break;
}
free_memory = 1;
} else
free_memory = 0;
}
if (free_memory) {
if (tcp)
free(tcp);
free(sid);
free(origA);
__s_api_free2dArray(mapA);
if (map)
free(map);
return (exitrc);
}
break;
default:
/* This should never happen. */
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set value: invalid configuration "
"type (%d)"), def->data_type);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
NULL);
if (tcp != NULL)
free(tcp);
return (NS_LDAP_CONFIG);
}
conf.ns_ptype = def->data_type;
if (tcp != NULL)
free(tcp);
/* Individually written verify routines here can replace */
/* verify_value. Verify conf (data) as appropriate here */
if (def->ns_verify != NULL) {
if ((*def->ns_verify)(type, def, &conf, errstr) != NS_SUCCESS) {
ns_param_t sav_conf;
(void) snprintf(errstr, sizeof (errstr),
gettext("%s"), errstr);
MKERROR(LOG_WARNING, *error, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
sav_conf = ptr->paramList[type];
ptr->paramList[type] = conf;
destroy_param(ptr, type);
ptr->paramList[type] = sav_conf;
return (NS_LDAP_CONFIG);
}
}
/* post evaluate the data */
/*
* if this is for setting a password,
* encrypt the password first.
* NOTE evalue() is smart and will just return
* the value passed if it is already encrypted.
*
* Init NS_LDAP_EXP_P here when CACHETTL is updated
*/
if (type == NS_LDAP_BINDPASSWD_P) {
cp = conf.ns_pc;
cp2 = evalue((char *)cp);
conf.ns_pc = cp2;
free(cp);
cp = NULL;
} else if (type == NS_LDAP_FILE_VERSION_P) {
ptr->version = NS_LDAP_V1;
if (strcasecmp(conf.ns_pc, NS_LDAP_VERSION_2) == 0) {
ptr->version = NS_LDAP_V2;
}
} else if (type == NS_LDAP_CACHETTL_P) {
cp = conf.ns_pc;
tm = conv_time(cp);
ptr->paramList[NS_LDAP_EXP_P].ns_ptype = TIMET;
if (tm != 0) {
tm += time(NULL);
}
ptr->paramList[NS_LDAP_EXP_P].ns_tm = tm;
}
/* Everything checks out move new values into param */
destroy_param(ptr, type);
/* Assign new/updated value into paramList */
ptr->paramList[type] = conf;
return (NS_LDAP_SUCCESS);
}
/*
* Set a parameter value in the 'config' configuration structure
* Lock as appropriate
*/
int
__ns_ldap_setParam(const ParamIndexType type,
const void *data, ns_ldap_error_t **error)
{
ns_ldap_error_t *errorp;
int ret;
char errstr[2 * MAXERROR];
ns_config_t *cfg;
ns_config_t *new_cfg;
/* We want to refresh only one configuration at a time */
(void) mutex_lock(&ns_loadrefresh_lock);
cfg = __s_api_get_default_config();
if (cache_server == TRUE) {
if (cfg == NULL) {
__ns_ldap_default_config();
cfg = __s_api_get_default_config();
if (cfg == NULL) {
(void) mutex_unlock(&ns_loadrefresh_lock);
return (NS_LDAP_MEMORY);
}
}
} else {
/*
* This code always return error here on client side,
* this needs to change once libsldap is used by more
* applications that need to set parameters.
*/
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to set parameter from a client in "
"__ns_ldap_setParam()"));
MKERROR(LOG_WARNING, *error, NS_CONFIG_SYNTAX, strdup(errstr),
NULL);
if (cfg != NULL)
__s_api_release_config(cfg);
(void) mutex_unlock(&ns_loadrefresh_lock);
return (NS_LDAP_CONFIG);
}
/* (re)initialize configuration if necessary */
if (cache_server == FALSE && timetorefresh(cfg)) {
new_cfg = LoadCacheConfiguration(&errorp);
__s_api_release_config(cfg);
if (new_cfg == NULL) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to load configuration '%s' "
"('%s')."), NSCONFIGFILE,
errorp != NULL && errorp->message != NULL ?
errorp->message : "");
MKERROR(LOG_WARNING, *error, NS_CONFIG_NOTLOADED,
strdup(errstr), NULL);
if (errorp != NULL)
(void) __ns_ldap_freeError(&errorp);
(void) mutex_unlock(&ns_loadrefresh_lock);
return (NS_LDAP_CONFIG);
}
set_curr_config(new_cfg);
cfg = new_cfg;
}
(void) mutex_unlock(&ns_loadrefresh_lock);
/* translate input and save in the parameter list */
ret = __ns_ldap_setParamValue(cfg, type, data, error);
__s_api_release_config(cfg);
return (ret);
}
/*
* Make a copy of a parameter entry
*/
static void **
dupParam(ns_param_t *ptr)
{
int count, i;
void **dupdata, *ret;
int *intptr;
char *cp, tmbuf[32];
static time_t expire = 0;
ns_auth_t *ap;
switch (ptr->ns_ptype) {
case ARRAYAUTH:
case ARRAYCRED:
case SAMLIST:
case SCLLIST:
case SSDLIST:
case SERVLIST:
case ARRAYCP:
count = ptr->ns_acnt;
if (count == 0)
return (NULL);
break;
case CHARPTR:
case INT:
case TIMET:
count = 1;
}
dupdata = (void **)calloc((count + 1), sizeof (void *));
if (dupdata == NULL)
return (NULL);
switch (ptr->ns_ptype) {
case ARRAYAUTH:
for (i = 0; i < count; i++) {
ap = __s_api_AuthEnumtoStruct(
(EnumAuthType_t)ptr->ns_pi[i]);
if (ap == NULL) {
free(dupdata);
return (NULL);
}
dupdata[i] = ap;
}
break;
case ARRAYCRED:
for (i = 0; i < count; i++) {
intptr = (int *)malloc(sizeof (int));
if (intptr == NULL) {
free(dupdata);
return (NULL);
}
dupdata[i] = (void *)intptr;
*intptr = ptr->ns_pi[i];
}
break;
case SAMLIST:
case SCLLIST:
case SSDLIST:
case SERVLIST:
case ARRAYCP:
for (i = 0; i < count; i++) {
ret = (void *)strdup(ptr->ns_ppc[i]);
if (ret == NULL) {
free(dupdata);
return (NULL);
}
dupdata[i] = ret;
}
break;
case CHARPTR:
if (ptr->ns_pc == NULL) {
free(dupdata);
return (NULL);
}
ret = (void *)strdup(ptr->ns_pc);
if (ret == NULL) {
free(dupdata);
return (NULL);
}
dupdata[0] = ret;
break;
case INT:
intptr = (int *)malloc(sizeof (int));
if (intptr == NULL) {
free(dupdata);
return (NULL);
}
*intptr = ptr->ns_i;
dupdata[0] = (void *)intptr;
break;
case TIMET:
expire = ptr->ns_tm;
tmbuf[31] = '\0';
cp = lltostr((long)expire, &tmbuf[31]);
ret = (void *)strdup(cp);
if (ret == NULL) {
free(dupdata);
return (NULL);
}
dupdata[0] = ret;
break;
}
return (dupdata);
}
int
__ns_ldap_freeParam(void ***data)
{
void **tmp;
int i = 0;
if (*data == NULL)
return (NS_LDAP_SUCCESS);
for (i = 0, tmp = *data; tmp[i] != NULL; i++)
free(tmp[i]);
free(*data);
*data = NULL;
return (NS_LDAP_SUCCESS);
}
/*
* Get the internal format for a parameter value. This
* routine makes a copy of an internal param value from
* the currently active parameter list and returns it.
*/
int
__ns_ldap_getParam(const ParamIndexType Param,
void ***data, ns_ldap_error_t **error)
{
char errstr[2 * MAXERROR];
ns_ldap_error_t *errorp;
ns_default_config *def;
ns_config_t *cfg;
ns_config_t *new_cfg;
if (data == NULL)
return (NS_LDAP_INVALID_PARAM);
*data = NULL;
/* We want to refresh only one configuration at a time */
(void) mutex_lock(&ns_loadrefresh_lock);
cfg = __s_api_get_default_config();
/* (re)initialize configuration if necessary */
if (cache_server == FALSE && timetorefresh(cfg)) {
new_cfg = LoadCacheConfiguration(&errorp);
__s_api_release_config(cfg);
if (new_cfg == NULL) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Unable to load configuration "
"'%s' ('%s')."),
NSCONFIGFILE,
errorp != NULL && errorp->message != NULL ?
errorp->message : "");
MKERROR(LOG_WARNING, *error, NS_CONFIG_NOTLOADED,
strdup(errstr), NULL);
if (errorp != NULL)
(void) __ns_ldap_freeError(&errorp);
(void) mutex_unlock(&ns_loadrefresh_lock);
return (NS_LDAP_CONFIG);
}
set_curr_config(new_cfg);
cfg = new_cfg;
}
(void) mutex_unlock(&ns_loadrefresh_lock);
if (cfg == NULL) {
(void) snprintf(errstr, sizeof (errstr),
gettext("No configuration information available."));
MKERROR(LOG_ERR, *error, NS_CONFIG_NOTLOADED,
strdup(errstr), NULL);
return (NS_LDAP_CONFIG);
}
if (Param == NS_LDAP_DOMAIN_P) {
*data = (void **)calloc(2, sizeof (void *));
if (*data == NULL) {
__s_api_release_config(cfg);
return (NS_LDAP_MEMORY);
}
(*data)[0] = (void *)strdup(cfg->domainName);
if ((*data)[0] == NULL) {
free(*data);
__s_api_release_config(cfg);
return (NS_LDAP_MEMORY);
}
} else if (cfg->paramList[Param].ns_ptype == NS_UNKNOWN) {
/* get default */
def = get_defconfig(cfg, Param);
if (def != NULL)
*data = dupParam(&def->defval);
} else {
*data = dupParam(&(cfg->paramList[Param]));
}
__s_api_release_config(cfg);
return (NS_LDAP_SUCCESS);
}
/*
* This routine takes a parameter in internal format and
* translates it into a variety of string formats for various
* outputs (doors/file/ldif). This routine would be better
* named: __ns_ldap_translateParam2String
*/
char *
__s_api_strValue(ns_config_t *cfg, char *str,
int bufsz, ParamIndexType index,
ns_strfmt_t fmt)
{
ns_default_config *def = NULL;
ns_param_t *ptr;
ns_hash_t *hptr;
ns_mapping_t *mptr;
char ibuf[14], *buf;
char abuf[64], **cpp;
int alen, count, i, sz;
int seplen = strlen(COMMASEP) + strlen(DOORLINESEP);
int first;
if (cfg == NULL || str == NULL)
return (NULL);
/* NS_LDAP_EXP and TRANSPORT_SEC are not exported externally */
if (index == NS_LDAP_EXP_P || index == NS_LDAP_TRANSPORT_SEC_P)
return (NULL);
/* Return nothing if the value is the default */
if (cfg->paramList[index].ns_ptype == NS_UNKNOWN)
return (NULL);
ptr = &(cfg->paramList[index]);
abuf[0] = '\0';
alen = 0;
/* get default */
def = get_defconfig(cfg, index);
if (def == NULL)
return (NULL);
switch (fmt) {
case NS_DOOR_FMT:
(void) strlcpy(abuf, def->name, sizeof (abuf));
(void) strlcat(abuf, EQUALSEP, sizeof (abuf));
break;
case NS_FILE_FMT:
(void) strlcpy(abuf, def->name, sizeof (abuf));
(void) strlcat(abuf, EQUSPSEP, sizeof (abuf));
break;
case NS_LDIF_FMT:
/* If no LDIF attr exists ignore the entry */
if (def->profile_name == NULL)
return (NULL);
(void) strlcpy(abuf, def->profile_name, sizeof (abuf));
(void) strlcat(abuf, COLSPSEP, sizeof (abuf));
break;
default:
break;
}
alen = strlen(abuf);
if (alen > bufsz)
return (NULL);
buf = str;
(void) strlcpy(buf, abuf, bufsz);
switch (ptr->ns_ptype) {
case ARRAYAUTH:
count = ptr->ns_acnt;
sz = 0;
for (i = 0; i < count; i++) {
sz += strlen(__s_get_auth_name(cfg,
(AuthType_t)(ptr->ns_pi[i]))) + seplen;
}
sz = sz + alen + 1;
if (sz <= bufsz) {
buf = str;
} else {
buf = (char *)calloc(sz, sizeof (char));
if (buf == NULL)
return (NULL);
(void) strcpy(buf, abuf);
}
for (i = 0; i < count; i++) {
(void) strcat(buf,
__s_get_auth_name(cfg,
(AuthType_t)(ptr->ns_pi[i])));
if (i != count-1) {
if (cfg->version == NS_LDAP_V1)
(void) strcat(buf, COMMASEP);
else
(void) strcat(buf, SEMISEP);
}
}
break;
case ARRAYCRED:
count = ptr->ns_acnt;
sz = 0;
for (i = 0; i < count; i++) {
sz += strlen(__s_get_credlvl_name(cfg,
(CredLevel_t)ptr->ns_pi[i])) + seplen;
}
sz = sz + alen + 1;
if (sz <= bufsz) {
buf = str;
} else {
buf = (char *)calloc(sz, sizeof (char));
if (buf == NULL)
return (NULL);
(void) strcpy(buf, abuf);
}
for (i = 0; i < count; i++) {
(void) strcat(buf,
__s_get_credlvl_name(cfg,
(CredLevel_t)ptr->ns_pi[i]));
if (i != count-1) {
(void) strcat(buf, SPACESEP);
}
}
break;
case SAMLIST:
case SCLLIST:
case SSDLIST:
count = ptr->ns_acnt;
sz = 0;
for (i = 0; i < count; i++) {
sz += strlen(ptr->ns_ppc[i]) + seplen;
}
sz = sz + alen + 1;
/*
* We need to allocate buffer depending on the 'fmt' and
* on the number of ns_ptype's present(count) as we add
* name' or 'profile_name' and DOORLINESEP or new line
* char to the buffer - see below.
*/
switch (fmt) {
case NS_LDIF_FMT:
sz += count * (strlen(def->profile_name)
+ strlen(COLSPSEP) + strlen("\n"));
break;
case NS_FILE_FMT:
sz += count * (strlen(def->name)
+ strlen(EQUALSEP) + strlen("\n"));
break;
case NS_DOOR_FMT:
sz += count * (strlen(def->name)
+ strlen(EQUALSEP) + strlen(DOORLINESEP));
break;
}
if (sz <= bufsz) {
buf = str;
} else {
buf = (char *)calloc(sz, sizeof (char));
if (buf == NULL)
return (NULL);
(void) strcpy(buf, abuf);
}
for (i = 0; i < count; i++) {
(void) strcat(buf, ptr->ns_ppc[i]);
if (i != count-1) {
/* Separate items */
switch (fmt) {
case NS_DOOR_FMT:
(void) strcat(buf, DOORLINESEP);
(void) strcat(buf, def->name);
(void) strcat(buf, EQUALSEP);
break;
case NS_FILE_FMT:
(void) strcat(buf, "\n");
(void) strcat(buf, def->name);
(void) strcat(buf, EQUSPSEP);
break;
case NS_LDIF_FMT:
(void) strcat(buf, "\n");
(void) strcat(buf, def->profile_name);
(void) strcat(buf, COLSPSEP);
break;
}
}
}
break;
case ARRAYCP:
count = ptr->ns_acnt;
sz = 0;
for (i = 0; i < count; i++) {
sz += strlen(ptr->ns_ppc[i]) + seplen;
}
sz = sz + alen + 1;
if (sz <= bufsz) {
buf = str;
} else {
buf = (char *)calloc(sz, sizeof (char));
if (buf == NULL)
return (NULL);
(void) strcpy(buf, abuf);
}
for (i = 0; i < count; i++) {
(void) strcat(buf, ptr->ns_ppc[i]);
if (i != count-1) {
(void) strcat(buf, COMMASEP);
}
}
break;
case SERVLIST:
count = ptr->ns_acnt;
sz = 0;
for (i = 0; i < count; i++) {
sz += strlen(ptr->ns_ppc[i]) + seplen;
}
sz = sz + alen + 1;
if (sz <= bufsz) {
buf = str;
} else {
buf = (char *)calloc(sz, sizeof (char));
if (buf == NULL)
return (NULL);
(void) strcpy(buf, abuf);
}
for (i = 0; i < count; i++) {
(void) strcat(buf, ptr->ns_ppc[i]);
if (i != count-1) {
if (fmt == NS_LDIF_FMT)
(void) strcat(buf, SPACESEP);
else
(void) strcat(buf, COMMASEP);
}
}
break;
case CHARPTR:
if (ptr->ns_pc == NULL)
break;
sz = strlen(ptr->ns_pc) + alen + 1;
if (sz > bufsz) {
buf = (char *)calloc(sz, sizeof (char));
if (buf == NULL)
return (NULL);
(void) strcpy(buf, abuf);
}
(void) strcat(buf, ptr->ns_pc);
break;
case INT:
switch (def->index) {
case NS_LDAP_PREF_ONLY_P:
(void) strcat(buf,
__s_get_pref_name((PrefOnly_t)ptr->ns_i));
break;
case NS_LDAP_SEARCH_REF_P:
(void) strcat(buf,
__s_get_searchref_name(cfg,
(SearchRef_t)ptr->ns_i));
break;
case NS_LDAP_SEARCH_SCOPE_P:
(void) strcat(buf,
__s_get_scope_name(cfg,
(ScopeType_t)ptr->ns_i));
break;
default:
(void) snprintf(ibuf, sizeof (ibuf),
"%d", ptr->ns_i);
(void) strcat(buf, ibuf);
break;
}
break;
case ATTRMAP:
buf[0] = '\0';
first = 1;
for (hptr = cfg->llHead; hptr; hptr = hptr->h_llnext) {
if (hptr->h_type != NS_HASH_AMAP) {
continue;
}
if (!first) {
if (fmt == NS_DOOR_FMT)
(void) strcat(buf, DOORLINESEP);
else
(void) strcat(buf, "\n");
}
mptr = hptr->h_map;
(void) strcat(buf, abuf);
(void) strcat(buf, mptr->service);
(void) strcat(buf, COLONSEP);
(void) strcat(buf, mptr->orig);
(void) strcat(buf, EQUALSEP);
for (cpp = mptr->map; cpp && *cpp; cpp++) {
if (cpp != mptr->map)
(void) strcat(buf, SPACESEP);
(void) strcat(buf, *cpp);
}
first = 0;
}
break;
case OBJMAP:
buf[0] = '\0';
first = 1;
for (hptr = cfg->llHead; hptr; hptr = hptr->h_llnext) {
if (hptr->h_type != NS_HASH_OMAP) {
continue;
}
if (!first) {
if (fmt == NS_DOOR_FMT)
(void) strcat(buf, DOORLINESEP);
else
(void) strcat(buf, "\n");
}
mptr = hptr->h_map;
(void) strcat(buf, abuf);
(void) strcat(buf, mptr->service);
(void) strcat(buf, COLONSEP);
(void) strcat(buf, mptr->orig);
(void) strcat(buf, EQUALSEP);
for (cpp = mptr->map; cpp && *cpp; cpp++) {
if (cpp != mptr->map)
(void) strcat(buf, SPACESEP);
(void) strcat(buf, *cpp);
}
first = 0;
}
break;
}
return (buf);
}
static int
__door_getldapconfig(char **buffer, int *buflen, ns_ldap_error_t **error)
{
typedef union {
ldap_data_t s_d;
char s_b[DOORBUFFERSIZE];
} space_t;
space_t *space;
ldap_data_t *sptr;
int ndata;
int adata;
char errstr[MAXERROR];
char *domainname;
domainname = __getdomainname();
if (domainname == NULL || buffer == NULL || buflen == NULL ||
(strlen(domainname) >= (sizeof (space_t)
- sizeof (space->s_d.ldap_call.ldap_callnumber)))) {
return (NS_LDAP_OP_FAILED);
}
space = (space_t *)calloc(1, sizeof (space_t));
if (space == NULL)
return (NS_LDAP_OP_FAILED);
adata = (sizeof (ldap_call_t) + strlen(domainname) +1);
ndata = sizeof (space_t);
space->s_d.ldap_call.ldap_callnumber = GETLDAPCONFIGV1;
(void) strcpy(space->s_d.ldap_call.ldap_u.domainname, domainname);
free(domainname);
domainname = NULL;
sptr = &space->s_d;
switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) {
case SUCCESS:
break;
case NOTFOUND:
(void) snprintf(errstr, sizeof (errstr),
gettext("Door call to "
"ldap_cachemgr failed - error: %d."),
space->s_d.ldap_ret.ldap_errno);
MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
strdup(errstr), NULL);
free(space);
return (NS_LDAP_OP_FAILED);
default:
free(space);
return (NS_LDAP_OP_FAILED);
}
/* copy info from door call to buffer here */
*buflen = strlen(space->s_d.ldap_ret.ldap_u.config) + 1;
*buffer = calloc(*buflen, sizeof (char));
if (*buffer == NULL) {
free(space);
return (NS_LDAP_MEMORY);
}
(void) strcpy(*buffer, space->s_d.ldap_ret.ldap_u.config);
if (sptr != &space->s_d) {
(void) munmap((char *)sptr, ndata);
} else {
free(space);
space = NULL;
}
*error = NULL;
return (NS_LDAP_SUCCESS);
}
/*
* SetDoorInfo parses ldapcachemgr configuration information
* and verifies that the profile is version 1 or version 2 based.
* version 2 profiles must have a version number as the first profile
* attribute in the configuration.
*/
static ns_config_t *
SetDoorInfo(char *buffer, ns_ldap_error_t **errorp)
{
ns_config_t *ptr;
char errstr[MAXERROR], errbuf[MAXERROR];
char *name, *value, valbuf[BUFSIZE];
char *strptr;
char *rest;
char *bufptr = buffer;
ParamIndexType i;
int ret;
int first = 1;
int errfnd = 0;
if (errorp == NULL)
return (NULL);
*errorp = NULL;
ptr = __s_api_create_config();
if (ptr == NULL) {
return (NULL);
}
strptr = (char *)strtok_r(bufptr, DOORLINESEP, &rest);
for (; ; ) {
if (strptr == NULL)
break;
(void) strlcpy(valbuf, strptr, sizeof (valbuf));
__s_api_split_key_value(valbuf, &name, &value);
/* Use get_versiontype and check for V1 vs V2 prototypes */
if (__s_api_get_versiontype(ptr, name, &i) < 0) {
(void) snprintf(errstr, sizeof (errstr),
"%s (%s)\n",
gettext("Illegal profile entry "
"line in configuration."),
name);
errfnd++;
/* Write verify routines and get rid of verify_value here */
} else if (verify_value(ptr, name,
value, errbuf) != NS_SUCCESS) {
(void) snprintf(errstr, sizeof (errstr),
gettext("%s\n"), errbuf);
errfnd++;
} else if (!first && i == NS_LDAP_FILE_VERSION_P) {
(void) snprintf(errstr, sizeof (errstr),
gettext("Illegal NS_LDAP_FILE_VERSION "
"line in configuration.\n"));
errfnd++;
}
if (errfnd) {
MKERROR(LOG_ERR, *errorp, NS_CONFIG_SYNTAX,
strdup(errstr), NULL);
} else {
ret = set_default_value(ptr, name, value, errorp);
}
if (errfnd || ret != NS_SUCCESS) {
__s_api_destroy_config(ptr);
return (NULL);
}
first = 0;
strptr = (char *)strtok_r(NULL, DOORLINESEP, &rest);
}
if (__s_api_crosscheck(ptr, errstr, B_TRUE) != NS_SUCCESS) {
__s_api_destroy_config(ptr);
MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX, strdup(errstr),
NULL);
return (NULL);
}
return (ptr);
}
static ns_config_t *
LoadCacheConfiguration(ns_ldap_error_t **error)
{
char *buffer = NULL;
int buflen = 0;
int ret;
ns_config_t *cfg;
*error = NULL;
ret = __door_getldapconfig(&buffer, &buflen, error);
if (ret != NS_LDAP_SUCCESS) {
if (*error != NULL && (*error)->message != NULL)
syslog(LOG_WARNING, "libsldap: %s", (*error)->message);
return (NULL);
}
/* now convert from door format */
cfg = SetDoorInfo(buffer, error);
free(buffer);
if (cfg == NULL && *error != NULL && (*error)->message != NULL)
syslog(LOG_WARNING, "libsldap: %s", (*error)->message);
return (cfg);
}
/*
* converts the time string into seconds. The time string can be specified
* using one of the following time units:
* #s (# of seconds)
* #m (# of minutes)
* #h (# of hours)
* #d (# of days)
* #w (# of weeks)
* NOTE: you can only specify one the above. No combination of the above
* units is allowed. If no unit specified, it will default to "seconds".
*/
static time_t
conv_time(char *s)
{
time_t t;
char c;
int l, m;
long tot;
l = strlen(s);
if (l == 0)
return (0);
c = s[--l];
m = 0;
switch (c) {
case 'w': /* weeks */
m = 604800;
break;
case 'd': /* days */
m = 86400;
break;
case 'h': /* hours */
m = 3600;
break;
case 'm': /* minutes */
m = 60;
break;
case 's': /* seconds */
m = 1;
break;
/* the default case is set to "second" */
}
if (m != 0)
s[l] = '\0';
else
m = 1;
errno = 0;
tot = atol(s);
if ((0 == tot) && (EINVAL == errno))
return (0);
if (((LONG_MAX == tot) || (LONG_MIN == tot)) && (EINVAL == errno))
return (0);
tot = tot * m;
t = (time_t)tot;
return (t);
}
ns_auth_t *
__s_api_AuthEnumtoStruct(const EnumAuthType_t i)
{
ns_auth_t *ap;
ap = (ns_auth_t *)calloc(1, sizeof (ns_auth_t));
if (ap == NULL)
return (NULL);
switch (i) {
case NS_LDAP_EA_NONE:
break;
case NS_LDAP_EA_SIMPLE:
ap->type = NS_LDAP_AUTH_SIMPLE;
break;
case NS_LDAP_EA_SASL_CRAM_MD5:
ap->type = NS_LDAP_AUTH_SASL;
ap->saslmech = NS_LDAP_SASL_CRAM_MD5;
break;
case NS_LDAP_EA_SASL_DIGEST_MD5:
ap->type = NS_LDAP_AUTH_SASL;
ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
break;
case NS_LDAP_EA_SASL_DIGEST_MD5_INT:
ap->type = NS_LDAP_AUTH_SASL;
ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
ap->saslopt = NS_LDAP_SASLOPT_INT;
break;
case NS_LDAP_EA_SASL_DIGEST_MD5_CONF:
ap->type = NS_LDAP_AUTH_SASL;
ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
ap->saslopt = NS_LDAP_SASLOPT_PRIV;
break;
case NS_LDAP_EA_SASL_EXTERNAL:
ap->type = NS_LDAP_AUTH_SASL;
ap->saslmech = NS_LDAP_SASL_EXTERNAL;
break;
case NS_LDAP_EA_TLS_NONE:
ap->type = NS_LDAP_AUTH_TLS;
ap->tlstype = NS_LDAP_TLS_NONE;
break;
case NS_LDAP_EA_TLS_SIMPLE:
ap->type = NS_LDAP_AUTH_TLS;
ap->tlstype = NS_LDAP_TLS_SIMPLE;
break;
case NS_LDAP_EA_TLS_SASL_CRAM_MD5:
ap->type = NS_LDAP_AUTH_TLS;
ap->tlstype = NS_LDAP_TLS_SASL;
ap->saslmech = NS_LDAP_SASL_CRAM_MD5;
break;
case NS_LDAP_EA_TLS_SASL_DIGEST_MD5:
ap->type = NS_LDAP_AUTH_TLS;
ap->tlstype = NS_LDAP_TLS_SASL;
ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
break;
case NS_LDAP_EA_TLS_SASL_DIGEST_MD5_INT:
ap->type = NS_LDAP_AUTH_TLS;
ap->tlstype = NS_LDAP_TLS_SASL;
ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
ap->saslopt = NS_LDAP_SASLOPT_INT;
break;
case NS_LDAP_EA_TLS_SASL_DIGEST_MD5_CONF:
ap->type = NS_LDAP_AUTH_TLS;
ap->tlstype = NS_LDAP_TLS_SASL;
ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
ap->saslopt = NS_LDAP_SASLOPT_PRIV;
break;
case NS_LDAP_EA_TLS_SASL_EXTERNAL:
ap->type = NS_LDAP_AUTH_TLS;
ap->tlstype = NS_LDAP_TLS_SASL;
ap->saslmech = NS_LDAP_SASL_EXTERNAL;
break;
default:
/* should never get here */
free(ap);
return (NULL);
}
return (ap);
}
/*
* Parameter Index Type validation routines
*/
/* Validate a positive integer */
/* Size of errbuf needs to be MAXERROR */
/* ARGSUSED */
static int
__s_val_postime(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf)
{
char *cp;
long tot;
if (param && param->ns_ptype == CHARPTR && param->ns_pc) {
for (cp = param->ns_pc; cp && *cp; cp++) {
if (*cp >= '0' && *cp <= '9')
continue;
switch (*cp) {
case 'w': /* weeks */
case 'd': /* days */
case 'h': /* hours */
case 'm': /* minutes */
case 's': /* seconds */
if (*(cp+1) == '\0') {
break;
}
default:
(void) strcpy(errbuf, "Illegal time value");
return (NS_PARSE_ERR);
}
}
/* Valid form: [0-9][0-9]*[wdhms]* */
tot = atol(param->ns_pc); /* check overflow */
if (tot >= 0)
return (NS_SUCCESS);
}
(void) snprintf(errbuf, MAXERROR,
gettext("Illegal time value in %s"), def->name);
return (NS_PARSE_ERR);
}
/* Validate the Base DN */
/* It can be empty (RootDSE request) or needs to have an '=' */
/* Size of errbuf needs to be MAXERROR */
/* ARGSUSED */
static int
__s_val_basedn(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf)
{
if (param && param->ns_ptype == CHARPTR &&
i == NS_LDAP_SEARCH_BASEDN_P &&
((param->ns_pc == NULL) || /* empty */
(*(param->ns_pc) == '\0') || /* empty */
(strchr(param->ns_pc, '=') != NULL))) /* '=' */
{
return (NS_SUCCESS);
}
(void) snprintf(errbuf, MAXERROR,
gettext("Non-existent or invalid DN in %s"),
def->name);
return (NS_PARSE_ERR);
}
/* Validate the serverList */
/* For each server in list, check if valid IP or hostname */
/* Size of errbuf needs to be MAXERROR */
/* ARGSUSED */
static int
__s_val_serverList(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf)
{
for (i = 0; i < param->ns_acnt; i++) {
if ((__s_api_isipv4(param->ns_ppc[i])) ||
(__s_api_isipv6(param->ns_ppc[i])) ||
(__s_api_ishost(param->ns_ppc[i]))) {
continue;
}
/* err */
(void) snprintf(errbuf, MAXERROR,
gettext("Invalid server (%s) in %s"),
param->ns_ppc[i], def->name);
return (NS_PARSE_ERR);
}
return (NS_SUCCESS);
}
/* Check for a BINDDN */
/* It can not be empty and needs to have an '=' */
/* Size of errbuf needs to be MAXERROR */
/* ARGSUSED */
static int
__s_val_binddn(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf)
{
if (param && param->ns_ptype == CHARPTR &&
i == NS_LDAP_BINDDN_P &&
((param->ns_pc == NULL) ||
((*(param->ns_pc) != '\0') &&
(strchr(param->ns_pc, '=') != NULL)))) {
return (NS_SUCCESS);
}
(void) snprintf(errbuf, MAXERROR,
gettext("NULL or invalid proxy bind DN"));
return (NS_PARSE_ERR);
}
/* Check for a BINDPASSWD */
/* The string can not be NULL or empty */
/* Size of errbuf needs to be MAXERROR */
/* ARGSUSED */
static int
__s_val_bindpw(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf)
{
if (param && param->ns_ptype == CHARPTR &&
i == NS_LDAP_BINDPASSWD_P &&
((param->ns_pc == NULL) ||
(*(param->ns_pc) != '\0'))) {
return (NS_SUCCESS);
}
(void) snprintf(errbuf, MAXERROR,
gettext("NULL proxy bind password"));
return (NS_PARSE_ERR);
}
/*
* __s_get_hostcertpath returns either the configured host certificate path
* or, if none, the default host certificate path (/var/ldap). Note that this
* does not use __ns_ldap_getParam because it may be called during connection
* setup. This can fail due to insufficient memory.
*/
char *
__s_get_hostcertpath(void)
{
ns_config_t *cfg;
ns_param_t *param;
char *ret = NULL;
cfg = __s_api_get_default_config();
if (cfg != NULL) {
param = &cfg->paramList[NS_LDAP_HOST_CERTPATH_P];
if (param->ns_ptype == CHARPTR)
ret = strdup(param->ns_pc);
__s_api_release_config(cfg);
}
if (ret == NULL)
ret = strdup(NSLDAPDIRECTORY);
return (ret);
}
static void
_free_config()
{
if (current_config != NULL)
destroy_config(current_config);
current_config = NULL;
}