diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libsldap/common/ns_config.c | |
download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libsldap/common/ns_config.c')
-rw-r--r-- | usr/src/lib/libsldap/common/ns_config.c | 3664 |
1 files changed, 3664 insertions, 0 deletions
diff --git a/usr/src/lib/libsldap/common/ns_config.c b/usr/src/lib/libsldap/common/ns_config.c new file mode 100644 index 0000000000..1e52104c6c --- /dev/null +++ b/usr/src/lib/libsldap/common/ns_config.c @@ -0,0 +1,3664 @@ +/* + * 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; +} |