/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * libsldap - library side configuration components * Routines to manage the config structure */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ns_sldap.h" #include "ns_internal.h" #include "ns_cache_door.h" #include "ns_connmgmt.h" #pragma fini(__s_api_shutdown_conn_mgmt, \ _free_config, __ns_ldap_doorfd_close) 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; extern thread_key_t ns_cmgkey; /* * 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_config_t *, 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_SASL_GSSAPI), "sasl/GSSAPI" }, { 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 ns_enum_map ns_shadow_update_enum[] = { { ENUM2INT(NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE), "FALSE" }, { ENUM2INT(NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE), "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_ENABLE_SHADOW_UPDATE", NS_LDAP_ENABLE_SHADOW_UPDATE_P, CREDCONFIG, INT, TRUE, NS_LDAP_V2, NULL, /* not defined in the Profile */ { INT, 0, INT2VOIDPTR(NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE) }, NULL, ns_shadow_update_enum }, {"NS_LDAP_ADMIN_BINDDN", NS_LDAP_ADMIN_BINDDN_P, CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2, NULL, /* not defined in the Profile */ { CHARPTR, 0, NULL }, __s_val_binddn, NULL }, {"NS_LDAP_ADMIN_BINDPASSWD", NS_LDAP_ADMIN_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_ENABLE_SHADOW_UPDATE_P: mapp = &ns_shadow_update_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"); } char * __s_get_shadowupdate_name(enableShadowUpdate_t type) { register ns_enum_map *mapp; mapp = &ns_shadow_update_enum[0]; for (; mapp->name != NULL; mapp++) { if (type == INT2SHADOWUPDATENUM(mapp->value)) { return (mapp->name); } } return ("Unknown enableShadowUpdate_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 == current_config) current_config = 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, boolean_t global) { ns_config_t *ret; ret = cfg; if (cfg != NULL) { (void) mutex_lock(&cfg->config_mutex); /* * allow access to per connection management (non-global) * config so operations on connection being closed can still * be completed */ if (cfg->delete && global == B_TRUE) ret = NULL; else cfg->nUse++; (void) mutex_unlock(&cfg->config_mutex); } return (ret); } /* * set_curr_config_global sets the current global config to the * specified ns_config_t. Note that this function is similar * to the project private function __s_api_init_config_global * except that it does not release the new ns_config_t. */ static void set_curr_config_global(ns_config_t *ptr) { ns_config_t *cfg; ns_config_t *cur_cfg; (void) mutex_lock(&ns_parse_lock); cur_cfg = current_config; cfg = get_curr_config_unlocked(cur_cfg, B_TRUE); if (cfg != ptr) { __s_api_destroy_config(cfg); current_config = ptr; } (void) mutex_unlock(&ns_parse_lock); } /* * set_curr_config sets the current config or the per connection * management one 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. Also note * that if there's no per connection management one to set, the * global current config will be set. */ static void set_curr_config(ns_config_t *ptr) { ns_config_t *cfg; ns_config_t *cur_cfg; ns_conn_mgmt_t *cmg; int rc; rc = thr_getspecific(ns_cmgkey, (void **)&cmg); /* set the per connection management config if possible */ if (rc == 0 && cmg != NULL && cmg->config != NULL) { (void) mutex_lock(&cmg->cfg_lock); cur_cfg = cmg->config; cfg = get_curr_config_unlocked(cur_cfg, B_FALSE); if (cfg != ptr) { __s_api_destroy_config(cfg); cmg->config = ptr; } (void) mutex_unlock(&cmg->cfg_lock); return; } /* else set the global current config */ set_curr_config_global(ptr); } /* * 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 global configuration * sets the new global configuration and then releases it */ void __s_api_init_config_global(ns_config_t *ptr) { set_curr_config_global(ptr); __s_api_release_config(ptr); } /* * __s_api_init_config function destroys the previous configuration * sets the new configuration and then releases it. The configuration * may be the global one or the per connection management one. */ 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); } /* * __s_api_get_default_config_global returns the current global config */ ns_config_t * __s_api_get_default_config_global(void) { ns_config_t *cfg; ns_config_t *cur_cfg; (void) mutex_lock(&ns_parse_lock); cur_cfg = current_config; cfg = get_curr_config_unlocked(cur_cfg, B_TRUE); (void) mutex_unlock(&ns_parse_lock); return (cfg); } /* * __s_api_get_default_config returns the current global config or the * per connection management one. */ ns_config_t * __s_api_get_default_config(void) { ns_config_t *cfg; ns_config_t *cur_cfg; ns_conn_mgmt_t *cmg; int rc; rc = thr_getspecific(ns_cmgkey, (void **)&cmg); /* get the per connection management config if available */ if (rc == 0 && cmg != NULL && cmg->config != NULL) { (void) mutex_lock(&cmg->cfg_lock); cur_cfg = cmg->config; cfg = get_curr_config_unlocked(cur_cfg, B_FALSE); (void) mutex_unlock(&cmg->cfg_lock); return (cfg); } /* else get the global current config */ return (__s_api_get_default_config_global()); } 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); } /* * 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; int i, cnt; int self, gssapi; 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; } } } /* * 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; } /* * If credential level self is defined, there should be * at least an auth method sasl/GSSAPI and vice versa. */ self = 0; cnt = ptr->paramList[NS_LDAP_CREDENTIAL_LEVEL_P].ns_acnt; for (i = 0; i < cnt; i++) { if (ptr->paramList[NS_LDAP_CREDENTIAL_LEVEL_P].ns_pi[i] == NS_LDAP_CRED_SELF) self++; } gssapi = 0; cnt = ptr->paramList[NS_LDAP_AUTH_P].ns_acnt; for (i = 0; i < cnt; i++) { if (ptr->paramList[NS_LDAP_AUTH_P].ns_pi[i] == NS_LDAP_EA_SASL_GSSAPI) gssapi++; } if (gssapi == 0 && self > 0) { (void) snprintf(errstr, MAXERROR, gettext("Configuration Error: " "Credential level self requires " "authentication method sasl/GSSAPI")); return (NS_PARSE_ERR); } if (gssapi > 0 && self == 0) { (void) snprintf(errstr, MAXERROR, gettext("Configuration Error: " "Authentication method sasl/GSSAPI " "requires credential level self")); return (NS_PARSE_ERR); } 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. If global is set, returns * the global one. */ static ns_config_t * loadrefresh_config(boolean_t global) { 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); if (global == B_TRUE) cfg = __s_api_get_default_config_global(); else cfg = __s_api_get_default_config(); /* (re)initialize configuration if necessary */ if (!__s_api_isStandalone() && timetorefresh(cfg)) { new_cfg = LoadCacheConfiguration(cfg, &errorp); if (new_cfg != NULL && new_cfg != cfg) { __s_api_release_config(cfg); if (global == B_TRUE) set_curr_config_global(new_cfg); else set_curr_config(new_cfg); cfg = new_cfg; } if (errorp != NULL) (void) __ns_ldap_freeError(&errorp); } (void) mutex_unlock(&ns_loadrefresh_lock); return (cfg); } /* * Get the current global configuration pointer and return it. * If necessary initialize or refresh the current * configuration as applicable. */ ns_config_t * __s_api_loadrefresh_config_global() { return (loadrefresh_config(B_TRUE)); } /* * Get the current configuration pointer and return it. * If necessary initialize or refresh the current * configuration as applicable. The configuration may * be the global one or the per connection management one. */ ns_config_t * __s_api_loadrefresh_config() { return (loadrefresh_config(B_FALSE)); } /* * 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_ADMIN_BINDDN_P: case NS_LDAP_ADMIN_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: case NS_LDAP_ENABLE_SHADOW_UPDATE_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 || type == NS_LDAP_ADMIN_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 *cfg_g = (ns_config_t *)-1; ns_config_t *new_cfg; boolean_t reinit_connmgmt = B_FALSE; /* 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 (!__s_api_isStandalone() && cache_server == FALSE && timetorefresh(cfg)) cfg_g = __s_api_get_default_config_global(); /* only (re)initialize the global configuration */ if (cfg == cfg_g) { if (cfg_g != NULL) __s_api_release_config(cfg_g); new_cfg = LoadCacheConfiguration(cfg, &errorp); if (new_cfg != cfg) __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); } if (new_cfg != cfg) { set_curr_config_global(new_cfg); cfg = new_cfg; reinit_connmgmt = B_TRUE; } } (void) mutex_unlock(&ns_loadrefresh_lock); if (reinit_connmgmt == B_TRUE) __s_api_reinit_conn_mgmt_new_config(cfg); /* 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 *cfg_g = (ns_config_t *)-1; ns_config_t *new_cfg; boolean_t reinit_connmgmt = B_FALSE; 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 (!__s_api_isStandalone() && cache_server == FALSE && timetorefresh(cfg)) cfg_g = __s_api_get_default_config_global(); /* only (re)initialize the global configuration */ if (cfg == cfg_g) { if (cfg_g != NULL) __s_api_release_config(cfg_g); new_cfg = LoadCacheConfiguration(cfg, &errorp); if (new_cfg != cfg) __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); } if (new_cfg != cfg) { set_curr_config_global(new_cfg); cfg = new_cfg; reinit_connmgmt = B_TRUE; } } (void) mutex_unlock(&ns_loadrefresh_lock); if (reinit_connmgmt == B_TRUE) __s_api_reinit_conn_mgmt_new_config(cfg); 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; case NS_LDAP_ENABLE_SHADOW_UPDATE_P: (void) strlcat(buf, __s_get_shadowupdate_name( (enableShadowUpdate_t)ptr->ns_i), bufsz); 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; ns_ldap_return_code retCode; ldap_config_out_t *cfghdr; *error = NULL; 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_MEMORY); 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 NS_CACHE_SUCCESS: break; case NS_CACHE_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); } retCode = NS_LDAP_SUCCESS; /* copy info from door call to buffer here */ cfghdr = &sptr->ldap_ret.ldap_u.config_str; *buflen = offsetof(ldap_config_out_t, config_str) + cfghdr->data_size + 1; *buffer = calloc(*buflen, sizeof (char)); if (*buffer == NULL) { retCode = NS_LDAP_MEMORY; } else (void) memcpy(*buffer, cfghdr, *buflen - 1); if (sptr != &space->s_d) { (void) munmap((char *)sptr, ndata); } free(space); return (retCode); } /* * 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; ldap_config_out_t *cfghdr; if (errorp == NULL) return (NULL); *errorp = NULL; ptr = __s_api_create_config(); if (ptr == NULL) { return (NULL); } /* get config cookie from the header */ cfghdr = (ldap_config_out_t *)bufptr; ptr->config_cookie = cfghdr->cookie; bufptr = (char *)cfghdr->config_str; 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_config_t *oldcfg, ns_ldap_error_t **error) { char *buffer = NULL; int buflen = 0; int ret; ns_config_t *cfg; ldap_config_out_t *cfghdr; ldap_get_chg_cookie_t old_cookie; ldap_get_chg_cookie_t new_cookie; *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); } /* No need to reload configuration if config cookie is the same */ cfghdr = (ldap_config_out_t *)buffer; new_cookie = cfghdr->cookie; if (oldcfg != NULL) old_cookie = oldcfg->config_cookie; if (oldcfg != NULL && old_cookie.mgr_pid == new_cookie.mgr_pid && old_cookie.seq_num == new_cookie.seq_num) { free(buffer); return (oldcfg); } /* 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_SASL_GSSAPI: ap->type = NS_LDAP_AUTH_SASL; ap->saslmech = NS_LDAP_SASL_GSSAPI; ap->saslopt = NS_LDAP_SASLOPT_INT | NS_LDAP_SASLOPT_PRIV; 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) { char *dntype; if (param && param->ns_ptype == CHARPTR && (i == NS_LDAP_BINDDN_P || i == NS_LDAP_ADMIN_BINDDN_P) && ((param->ns_pc == NULL) || ((*(param->ns_pc) != '\0') && (strchr(param->ns_pc, '=') != NULL)))) { return (NS_SUCCESS); } if (i == NS_LDAP_BINDDN_P) dntype = "proxy"; else dntype = "update"; (void) snprintf(errbuf, MAXERROR, gettext("NULL or invalid %s bind DN"), dntype); 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) { char *pwtype; if (param && param->ns_ptype == CHARPTR && (i == NS_LDAP_BINDPASSWD_P || i == NS_LDAP_ADMIN_BINDPASSWD_P) && ((param->ns_pc == NULL) || (*(param->ns_pc) != '\0'))) { return (NS_SUCCESS); } if (i == NS_LDAP_BINDPASSWD_P) pwtype = "proxy"; else pwtype = "admin"; (void) snprintf(errbuf, MAXERROR, gettext("NULL %s bind password"), pwtype); 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; }