ns_config.c revision 2830:5228d1267a01
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * libsldap - library side configuration components
30 * Routines to manage the config structure
31 */
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <strings.h>
37#include <libintl.h>
38#include <locale.h>
39#include <thread.h>
40#include <synch.h>
41#include <errno.h>
42#include <unistd.h>
43#include <fcntl.h>
44#include <ctype.h>
45#include <crypt.h>
46#include <arpa/inet.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <syslog.h>
50#include <netdb.h>
51#include <sys/systeminfo.h>
52#include <sys/mman.h>
53#include <sys/time.h>
54#include <limits.h>
55#include "ns_sldap.h"
56#include "ns_internal.h"
57#include "ns_cache_door.h"
58
59#pragma fini(_free_config)
60
61static mutex_t		ns_parse_lock = DEFAULTMUTEX;
62static mutex_t		ns_loadrefresh_lock = DEFAULTMUTEX;
63static ns_config_t	*current_config = NULL;
64
65static int		cache_server = FALSE;
66
67/*
68 * Parameter Index Type validation routines
69 */
70static int
71__s_val_postime(ParamIndexType i, ns_default_config *def,
72		ns_param_t *param, char *errbuf);
73static int
74__s_val_basedn(ParamIndexType i, ns_default_config *def,
75		ns_param_t *param, char *errbuf);
76
77static int
78__s_val_binddn(ParamIndexType i, ns_default_config *def,
79		ns_param_t *param, char *errbuf);
80
81static int
82__s_val_bindpw(ParamIndexType i, ns_default_config *def,
83		ns_param_t *param, char *errbuf);
84
85static int
86__s_val_serverList(ParamIndexType i, ns_default_config *def,
87		ns_param_t *param, char *errbuf);
88
89/*
90 * Forward declarations
91 */
92
93static ns_parse_status
94verify_value(ns_config_t *cfg, char *name, char *value, char *errstr);
95
96static int
97set_default_value(ns_config_t *configptr, char *name, char *value,
98	ns_ldap_error_t **error);
99
100static void
101set_curr_config(ns_config_t *ptr);
102
103static int
104__door_getldapconfig(char **buffer, int *buflen, ns_ldap_error_t **error);
105
106static ns_config_t *
107SetDoorInfo(char *buffer, ns_ldap_error_t **errorp);
108
109static boolean_t
110timetorefresh(ns_config_t *cfg);
111
112static ns_config_t *
113LoadCacheConfiguration(ns_ldap_error_t **error);
114
115static void **
116dupParam(ns_param_t *ptr);
117
118static time_t
119conv_time(char *s);
120
121/*
122 * Structures used in enum <-> string mapping routines
123 */
124
125static ns_enum_map ns_auth_enum_v1[] = {
126	{ ENUM2INT(NS_LDAP_EA_NONE), "NS_LDAP_AUTH_NONE" },
127	{ ENUM2INT(NS_LDAP_EA_SIMPLE), "NS_LDAP_AUTH_SIMPLE" },
128	{ ENUM2INT(NS_LDAP_EA_SASL_CRAM_MD5), "NS_LDAP_AUTH_SASL_CRAM_MD5" },
129	{ -1, NULL },
130};
131
132static ns_enum_map ns_auth_enum_v2[] = {
133	{ ENUM2INT(NS_LDAP_EA_NONE), "none" },
134	{ ENUM2INT(NS_LDAP_EA_SIMPLE), "simple" },
135	{ ENUM2INT(NS_LDAP_EA_SASL_CRAM_MD5), "sasl/CRAM-MD5" },
136	{ ENUM2INT(NS_LDAP_EA_SASL_DIGEST_MD5), "sasl/DIGEST-MD5" },
137	{ ENUM2INT(NS_LDAP_EA_SASL_DIGEST_MD5_INT),
138			"sasl/DIGEST-MD5:auth-int" },
139	{ ENUM2INT(NS_LDAP_EA_SASL_DIGEST_MD5_CONF),
140			"sasl/DIGEST-MD5:auth-conf" },
141	{ ENUM2INT(NS_LDAP_EA_SASL_EXTERNAL), "sasl/EXTERNAL" },
142	{ ENUM2INT(NS_LDAP_EA_SASL_GSSAPI), "sasl/GSSAPI" },
143	{ ENUM2INT(NS_LDAP_EA_TLS_NONE), "tls:none" },
144	{ ENUM2INT(NS_LDAP_EA_TLS_SIMPLE), "tls:simple" },
145	{ ENUM2INT(NS_LDAP_EA_TLS_SASL_CRAM_MD5), "tls:sasl/CRAM-MD5" },
146	{ ENUM2INT(NS_LDAP_EA_TLS_SASL_DIGEST_MD5), "tls:sasl/DIGEST-MD5" },
147	{ ENUM2INT(NS_LDAP_EA_TLS_SASL_DIGEST_MD5_INT),
148			"tls:sasl/DIGEST-MD5:auth-int" },
149	{ ENUM2INT(NS_LDAP_EA_TLS_SASL_DIGEST_MD5_CONF),
150			"tls:sasl/DIGEST-MD5:auth-conf" },
151	{ ENUM2INT(NS_LDAP_EA_TLS_SASL_EXTERNAL), "tls:sasl/EXTERNAL" },
152	{ -1, NULL },
153};
154
155	/* V1 ONLY */
156static ns_enum_map ns_sec_enum_v1[] = {
157	{ ENUM2INT(NS_LDAP_TLS_NONE), "NS_LDAP_SEC_NONE" },
158	{ -1, NULL },
159};
160
161	/* V2 ONLY */
162static ns_enum_map ns_cred_enum_v2[] = {
163	{ ENUM2INT(NS_LDAP_CRED_ANON), "anonymous" },
164	{ ENUM2INT(NS_LDAP_CRED_PROXY), "proxy" },
165	{ ENUM2INT(NS_LDAP_CRED_SELF), "self" },
166	{ -1, NULL },
167};
168
169static ns_enum_map ns_ref_enum_v1[] = {
170	{ ENUM2INT(NS_LDAP_FOLLOWREF), "NS_LDAP_FOLLOWREF" },
171	{ ENUM2INT(NS_LDAP_NOREF), "NS_LDAP_NOREF" },
172	{ -1, NULL },
173};
174
175static ns_enum_map ns_ref_enum_v2[] = {
176	{ ENUM2INT(NS_LDAP_FOLLOWREF), "TRUE" },
177	{ ENUM2INT(NS_LDAP_NOREF), "FALSE" },
178	{ -1, NULL },
179};
180
181static ns_enum_map ns_scope_enum_v1[] = {
182	{ ENUM2INT(NS_LDAP_SCOPE_BASE), "NS_LDAP_SCOPE_BASE" },
183	{ ENUM2INT(NS_LDAP_SCOPE_ONELEVEL), "NS_LDAP_SCOPE_ONELEVEL" },
184	{ ENUM2INT(NS_LDAP_SCOPE_SUBTREE), "NS_LDAP_SCOPE_SUBTREE" },
185	{ -1, NULL },
186};
187
188static ns_enum_map ns_scope_enum_v2[] = {
189	{ ENUM2INT(NS_LDAP_SCOPE_BASE), "base" },
190	{ ENUM2INT(NS_LDAP_SCOPE_ONELEVEL), "one" },
191	{ ENUM2INT(NS_LDAP_SCOPE_SUBTREE), "sub" },
192	{ -1, NULL },
193};
194
195static ns_enum_map ns_pref_enum[] = {
196	{ ENUM2INT(NS_LDAP_PREF_FALSE), "NS_LDAP_FALSE" },
197	{ ENUM2INT(NS_LDAP_PREF_TRUE), "NS_LDAP_TRUE" },
198	{ -1, NULL },
199};
200
201static int	ns_def_auth_v1[] = {
202	ENUM2INT(NS_LDAP_EA_NONE),
203	0
204};
205
206static int	ns_def_auth_v2[] = {
207	ENUM2INT(NS_LDAP_EA_NONE),
208	0
209};
210
211static int	ns_def_cred_v1[] = {
212	ENUM2INT(NS_LDAP_CRED_PROXY),
213	0
214};
215
216static int	ns_def_cred_v2[] = {
217	ENUM2INT(NS_LDAP_CRED_ANON),
218	0
219};
220
221/*
222 * The next macro places an integer in the first sizeof(int) bytes of a
223 * void pointer location. For 32-bit, it is the same as "(void *) i". It
224 * is used to solve a problem found during 64-bit testing.  The problem
225 * was that for a configuration parameter such as NS_LDAP_SEARCH_REF_P,
226 * which is of type INT and has defined default value, an int
227 * variable(ns_param.ns_pu.i) defined inside an union(ns_pu) structure, is
228 * used to access the defined default value. This requires the default
229 * value to be in the first sizeof(int) bytes of the union element.  If
230 * just using "(void *) intval" to declare the default value in the
231 * following defconfig[] structure, the intval data will be placed is the
232 * last sizeof(int) bytes. In which case, when accessing via ns_pu_i in
233 * a 64-bit system, ZERO will be returned as the default value, not the
234 * defined one.
235 *
236 * Note since amd64 is little-endian, the problem is not an issue.
237 * INT2VOIDPTR will just leave the data (i) unchanged.
238 */
239#if defined(__amd64)
240#define	INT2VOIDPTR(i)	(void *)i
241#else
242#define	INT2VOIDPTR(i)	\
243	(void *)(((long)(i))<<(8*(sizeof (void *) - sizeof (int))))
244#endif
245/*
246 * The default configuration table
247 * Version 1 entries are first, V2 entries follow.
248 */
249static ns_default_config defconfig[] = {
250	/* optional V1 profile */
251	{"NS_LDAP_FILE_VERSION", NS_LDAP_FILE_VERSION_P,
252		CLIENTCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V1,
253		NULL,	/* No version number defined in V1 */
254		{ CHARPTR, 0, (void *)NS_LDAP_VERSION_1 },
255		NULL, NULL },
256
257	/* ---------- V1 profile ---------- */
258	{"NS_LDAP_BINDDN", NS_LDAP_BINDDN_P,
259		CREDCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V1,
260		_P1_BINDDN,
261		{ CHARPTR, 0, NULL },
262		__s_val_binddn, NULL },
263
264	{"NS_LDAP_BINDPASSWD", NS_LDAP_BINDPASSWD_P,
265		CREDCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V1,
266		_P1_BINDPASSWORD,
267		{ CHARPTR, 0, NULL },
268		__s_val_bindpw, NULL },
269
270	{"NS_LDAP_SERVERS", NS_LDAP_SERVERS_P,
271		SERVERCONFIG,	ARRAYCP,	FALSE,	NS_LDAP_V1,
272		_P1_SERVERS,
273		{ ARRAYCP, 0, NULL },
274		__s_val_serverList, NULL },
275
276	{"NS_LDAP_SEARCH_BASEDN", NS_LDAP_SEARCH_BASEDN_P,
277		SERVERCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V1,
278		_P1_SEARCHBASEDN,
279		{ CHARPTR, 0, NULL },
280		__s_val_basedn, NULL },
281
282	{"NS_LDAP_AUTH", NS_LDAP_AUTH_P,
283		CLIENTCONFIG,	ARRAYAUTH,	FALSE,	NS_LDAP_V1,
284		_P1_AUTHMETHOD,
285		{ ARRAYAUTH, 1, (void *)&ns_def_auth_v1[0] },
286		NULL, ns_auth_enum_v1 },
287
288	{"NS_LDAP_TRANSPORT_SEC", NS_LDAP_TRANSPORT_SEC_P,
289		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V1,
290		_P1_TRANSPORTSECURITY,
291		{ INT, 0, INT2VOIDPTR(NS_LDAP_TLS_NONE) },
292		NULL, ns_sec_enum_v1 },
293
294	{"NS_LDAP_SEARCH_REF", NS_LDAP_SEARCH_REF_P,
295		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V1,
296		_P1_SEARCHREFERRAL,
297		{ INT, 0, INT2VOIDPTR(NS_LDAP_FOLLOWREF) },
298		NULL, ns_ref_enum_v1 },
299
300	{"NS_LDAP_DOMAIN", NS_LDAP_DOMAIN_P,
301		CLIENTCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V1,
302		NULL,	/* not defined in the Profile */
303		{ CHARPTR, 0, NULL },
304		NULL, NULL },
305
306	{"NS_LDAP_EXP", NS_LDAP_EXP_P,
307		SERVERCONFIG,	TIMET,		TRUE,	NS_LDAP_V1,
308		NULL,	/* initialized by code to time+NS_LDAP_CACHETTL */
309		{ INT, 0, 0 },
310		NULL, NULL },
311
312	{"NS_LDAP_CERT_PATH", NS_LDAP_CERT_PATH_P,
313		CREDCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V1,
314		_P1_CERTIFICATEPATH,
315		{ CHARPTR, 0, NULL },
316		NULL, NULL },
317
318	{"NS_LDAP_CERT_PASS", NS_LDAP_CERT_PASS_P,
319		CREDCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V1,
320		_P1_CERTIFICATEPASSWORD,
321		{ CHARPTR, 0, NULL },
322		NULL, NULL },
323
324	{"NS_LDAP_SEARCH_DN", NS_LDAP_SEARCH_DN_P,
325		CLIENTCONFIG,	SSDLIST,	FALSE,	NS_LDAP_V1,
326		_P1_DATASEARCHDN,
327		{ SSDLIST, 0, NULL },
328		NULL, NULL },
329
330	{"NS_LDAP_SEARCH_SCOPE", NS_LDAP_SEARCH_SCOPE_P,
331		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V1,
332		_P1_SEARCHSCOPE,
333		{ INT, 0, INT2VOIDPTR(NS_LDAP_SCOPE_ONELEVEL) },
334		NULL, ns_scope_enum_v1 },
335
336	{"NS_LDAP_SEARCH_TIME", NS_LDAP_SEARCH_TIME_P,
337		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V1,
338		_P1_SEARCHTIMELIMIT,
339		{ INT, 0, INT2VOIDPTR(NS_DEFAULT_SEARCH_TIMEOUT) },
340		NULL, NULL },
341
342	{"NS_LDAP_SERVER_PREF", NS_LDAP_SERVER_PREF_P,
343		CLIENTCONFIG,	ARRAYCP,	FALSE,	NS_LDAP_V1,
344		_P1_PREFERREDSERVER,
345		{ ARRAYCP, 0, NULL },
346		__s_val_serverList, NULL },
347
348	{"NS_LDAP_PREF_ONLY", NS_LDAP_PREF_ONLY_P,
349		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V1,
350		_P1_PREFERREDSERVERONLY,
351		{ INT, 0, INT2VOIDPTR(NS_LDAP_PREF_FALSE) },
352		NULL, ns_pref_enum },
353
354	{"NS_LDAP_CACHETTL", NS_LDAP_CACHETTL_P,
355		CLIENTCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V1,
356		_P1_CACHETTL,
357		{ CHARPTR, 0, (void *)EXP_DEFAULT_TTL },
358		__s_val_postime, NULL },
359
360	{"NS_LDAP_PROFILE", NS_LDAP_PROFILE_P,
361		CLIENTCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V1,
362		_P_CN,
363		{ CHARPTR, 0, (void *)DEFAULTCONFIGNAME },
364		NULL, NULL },
365
366	{"NS_LDAP_BIND_TIME", NS_LDAP_BIND_TIME_P,
367		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V1,
368		_P1_BINDTIMELIMIT,
369		{ INT, 0, INT2VOIDPTR(NS_DEFAULT_BIND_TIMEOUT) },
370		NULL, NULL },
371
372	/* This configuration option is not visible in V1 */
373	{"NS_LDAP_CREDENTIAL_LEVEL", NS_LDAP_CREDENTIAL_LEVEL_P,
374		CLIENTCONFIG,	ARRAYCRED,	TRUE,	NS_LDAP_V1,
375		NULL,	/* No version defined in V1 */
376		{ ARRAYCRED, 0, (void *)&ns_def_cred_v1[0] },
377		NULL, NULL },
378
379	/* ---------- V2 profile ---------- */
380	{"NS_LDAP_FILE_VERSION", NS_LDAP_FILE_VERSION_P,
381		CLIENTCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V2,
382		NULL,	/* No version number defined in V1 */
383		{ CHARPTR, 0, (void *)NS_LDAP_VERSION_2 },
384		NULL, NULL },
385
386	{"NS_LDAP_BINDDN", NS_LDAP_BINDDN_P,
387		CREDCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V2,
388		NULL,	/* not defined in the Profile */
389		{ CHARPTR, 0, NULL },
390		__s_val_binddn, NULL },
391	{"NS_LDAP_BINDPASSWD", NS_LDAP_BINDPASSWD_P,
392		CREDCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V2,
393		NULL,	/* not defined in the Profile */
394		{ CHARPTR, 0, NULL },
395		__s_val_bindpw, NULL },
396	{"NS_LDAP_EXP", NS_LDAP_EXP_P,
397		SERVERCONFIG,	TIMET,		TRUE,	NS_LDAP_V2,
398		NULL,	/* initialized by code to time+NS_LDAP_CACHETTL */
399		{ INT, 0, 0 },
400		NULL, NULL },
401
402	{"NS_LDAP_SERVER_PREF", NS_LDAP_SERVER_PREF_P,
403		CLIENTCONFIG,	SERVLIST,	FALSE,	NS_LDAP_V2,
404		_P2_PREFERREDSERVER,
405		{ SERVLIST, 0, NULL },
406		__s_val_serverList, NULL },
407
408	{"NS_LDAP_SERVERS", NS_LDAP_SERVERS_P,
409		SERVERCONFIG,	SERVLIST,	FALSE,	NS_LDAP_V2,
410		_P2_DEFAULTSERVER,
411		{ SERVLIST, 0, NULL },
412		__s_val_serverList, NULL },
413
414	{"NS_LDAP_SEARCH_BASEDN", NS_LDAP_SEARCH_BASEDN_P,
415		SERVERCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V2,
416		_P2_SEARCHBASEDN,
417		{ CHARPTR, 0, NULL },
418		__s_val_basedn, NULL },
419
420	{"NS_LDAP_SEARCH_SCOPE", NS_LDAP_SEARCH_SCOPE_P,
421		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V2,
422		_P2_SEARCHSCOPE,
423		{ INT, 0, INT2VOIDPTR(NS_LDAP_SCOPE_ONELEVEL) },
424		NULL, ns_scope_enum_v2 },
425
426	{"NS_LDAP_AUTH", NS_LDAP_AUTH_P,
427		CLIENTCONFIG,	ARRAYAUTH,	FALSE,	NS_LDAP_V2,
428		_P2_AUTHMETHOD,
429		{ ARRAYAUTH, 2, (void *)&ns_def_auth_v2[0] },
430		NULL, ns_auth_enum_v2 },
431
432	{"NS_LDAP_CREDENTIAL_LEVEL", NS_LDAP_CREDENTIAL_LEVEL_P,
433		CLIENTCONFIG,	ARRAYCRED,	FALSE,	NS_LDAP_V2,
434		_P2_CREDENTIALLEVEL,
435		{ ARRAYCRED, 0, (void *)&ns_def_cred_v2[0] },
436		NULL, ns_cred_enum_v2 },
437
438	{"NS_LDAP_SERVICE_SEARCH_DESC", NS_LDAP_SERVICE_SEARCH_DESC_P,
439		CLIENTCONFIG,	SSDLIST,	FALSE,	NS_LDAP_V2,
440		_P2_SERVICESEARCHDESC,
441		{ SSDLIST, 0, NULL },
442		NULL, NULL },
443
444	{"NS_LDAP_SEARCH_TIME", NS_LDAP_SEARCH_TIME_P,
445		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V2,
446		_P2_SEARCHTIMELIMIT,
447		{ INT, 0, INT2VOIDPTR(NS_DEFAULT_SEARCH_TIMEOUT) },
448		NULL, NULL },
449
450	{"NS_LDAP_BIND_TIME", NS_LDAP_BIND_TIME_P,
451		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V2,
452		_P2_BINDTIMELIMIT,
453		{ INT, 0, INT2VOIDPTR(NS_DEFAULT_BIND_TIMEOUT) },
454		NULL, NULL },
455
456	{"NS_LDAP_SEARCH_REF", NS_LDAP_SEARCH_REF_P,
457		CLIENTCONFIG,	INT,		TRUE,	NS_LDAP_V2,
458		_P2_FOLLOWREFERRALS,
459		{ INT, 0, INT2VOIDPTR(NS_LDAP_FOLLOWREF) },
460		NULL, ns_ref_enum_v2 },
461
462	{"NS_LDAP_CACHETTL", NS_LDAP_CACHETTL_P,
463		CLIENTCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V2,
464		_P2_PROFILETTL,
465		{ CHARPTR, 0, (void *)EXP_DEFAULT_TTL },
466		__s_val_postime, NULL },
467
468	{"NS_LDAP_ATTRIBUTEMAP", NS_LDAP_ATTRIBUTEMAP_P,
469		CLIENTCONFIG,	ATTRMAP,	FALSE,	NS_LDAP_V2,
470		_P2_ATTRIBUTEMAP,
471		{ ATTRMAP, 0, NULL },
472		NULL, NULL },
473
474	{"NS_LDAP_OBJECTCLASSMAP", NS_LDAP_OBJECTCLASSMAP_P,
475		CLIENTCONFIG,	OBJMAP,		FALSE,	NS_LDAP_V2,
476		_P2_OBJECTCLASSMAP,
477		{ OBJMAP, 0, NULL },
478		NULL, NULL },
479
480	{"NS_LDAP_PROFILE", NS_LDAP_PROFILE_P,
481		CLIENTCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V2,
482		_P_CN,
483		{ CHARPTR, 0, (void *)DEFAULTCONFIGNAME },
484		NULL, NULL },
485
486	{"NS_LDAP_SERVICE_AUTH_METHOD", NS_LDAP_SERVICE_AUTH_METHOD_P,
487		CLIENTCONFIG,	SAMLIST,	FALSE,	NS_LDAP_V2,
488		_P2_SERVICEAUTHMETHOD,
489		{ SAMLIST, 0, NULL },
490		NULL, NULL },
491
492	{"NS_LDAP_SERVICE_CRED_LEVEL", NS_LDAP_SERVICE_CRED_LEVEL_P,
493		CLIENTCONFIG,	SCLLIST,	FALSE,	NS_LDAP_V2,
494		_P2_SERVICECREDLEVEL,
495		{ SCLLIST, 0, NULL },
496		NULL, NULL },
497
498	{"NS_LDAP_HOST_CERTPATH", NS_LDAP_HOST_CERTPATH_P,
499		CREDCONFIG,	CHARPTR,	TRUE,	NS_LDAP_V2,
500		NULL,	/* not defined in the Profile */
501		{ CHARPTR, 0, (void *)NSLDAPDIRECTORY },
502		NULL, NULL },
503
504	/* array terminator [not an entry] */
505	{NULL, NS_LDAP_FILE_VERSION_P,
506		CLIENTCONFIG,	NS_UNKNOWN,	TRUE,	NULL,
507		NULL,
508		{ NS_UNKNOWN, 0, NULL },
509		NULL, NULL },
510};
511
512static char *
513__getdomainname()
514{
515	/*
516	 * The sysinfo man page recommends using a buffer size
517	 * of 257 bytes. MAXHOSTNAMELEN is 256. So add 1 here.
518	 */
519	char	buf[MAXHOSTNAMELEN + 1];
520	int	status;
521
522	status = sysinfo(SI_SRPC_DOMAIN, buf, MAXHOSTNAMELEN);
523	if (status < 0)
524		return (NULL);
525	/* error: not enough space to hold returned value */
526	if (status > sizeof (buf))
527		return (NULL);
528	return (strdup(buf));
529}
530
531void
532__ns_ldap_setServer(int set)
533{
534	cache_server = set;
535}
536
537static boolean_t
538timetorefresh(ns_config_t *cfg)
539{
540	struct timeval	tp;
541	static time_t	expire = 0;
542
543	if (cfg == NULL || gettimeofday(&tp, NULL) == -1)
544		return (B_TRUE);
545
546	if (cfg->paramList[NS_LDAP_EXP_P].ns_ptype == TIMET)
547		expire = cfg->paramList[NS_LDAP_EXP_P].ns_tm;
548	else
549		return (B_TRUE);
550
551	return (expire != 0 && tp.tv_sec > expire);
552}
553
554int
555__s_get_enum_value(ns_config_t *ptr, char *value, ParamIndexType i)
556{
557	register ns_enum_map	*mapp;
558	char			*pstart = value;
559	char			*pend;
560	int			len;
561
562	if (pstart == NULL)
563		return (-1);
564
565	/* skip leading spaces */
566	while (*pstart == SPACETOK)
567		pstart++;
568	/* skip trailing spaces */
569	pend = pstart + strlen(pstart) - 1;
570	for (; pend >= pstart && *pend == SPACETOK; pend--);
571	len = pend - pstart + 1;
572	if (len == 0)
573		return (-1);
574
575	switch (i) {
576	case NS_LDAP_AUTH_P:
577		if (ptr->version == NS_LDAP_V1)
578			mapp = &ns_auth_enum_v1[0];
579		else
580			mapp = &ns_auth_enum_v2[0];
581		break;
582	case NS_LDAP_TRANSPORT_SEC_P:
583		return (-1);
584	case NS_LDAP_SEARCH_SCOPE_P:
585		if (ptr->version == NS_LDAP_V1)
586			mapp = &ns_scope_enum_v1[0];
587		else
588			mapp = &ns_scope_enum_v2[0];
589		break;
590	case NS_LDAP_SEARCH_REF_P:
591		if (ptr->version == NS_LDAP_V1)
592			mapp = &ns_ref_enum_v1[0];
593		else
594			mapp = &ns_ref_enum_v2[0];
595		break;
596	case NS_LDAP_PREF_ONLY_P:
597		mapp = &ns_pref_enum[0];
598		break;
599	case NS_LDAP_CREDENTIAL_LEVEL_P:
600		if (ptr->version == NS_LDAP_V1)
601			return (-1);
602		else
603			mapp = &ns_cred_enum_v2[0];
604		break;
605	case NS_LDAP_SERVICE_AUTH_METHOD_P:
606		mapp = &ns_auth_enum_v2[0];
607		break;
608	case NS_LDAP_SERVICE_CRED_LEVEL_P:
609		mapp = &ns_cred_enum_v2[0];
610		break;
611	default:
612		return (-1);
613	}
614
615	for (; mapp->name != NULL; mapp++) {
616		if (strncasecmp(pstart, mapp->name, len) == 0 &&
617			(strlen(mapp->name) == len)) {
618			return (mapp->value);
619		}
620	}
621	return (-1);
622}
623
624char *
625__s_get_auth_name(ns_config_t *ptr, AuthType_t type)
626{
627	register ns_enum_map	*mapp;
628
629	if (ptr->version == NS_LDAP_V1)
630		mapp = &ns_auth_enum_v1[0];
631	else
632		mapp = &ns_auth_enum_v2[0];
633
634	for (; mapp->name != NULL; mapp++) {
635		if (type == INT2AUTHENUM(mapp->value)) {
636			return (mapp->name);
637		}
638	}
639	return ("Unknown AuthType_t type specified");
640}
641
642
643char *
644__s_get_security_name(ns_config_t *ptr, TlsType_t type)
645{
646	register ns_enum_map	*mapp;
647
648	if (ptr->version == NS_LDAP_V1) {
649		mapp = &ns_sec_enum_v1[0];
650
651		for (; mapp->name != NULL; mapp++) {
652			if (type == INT2SECENUM(mapp->value)) {
653				return (mapp->name);
654			}
655		}
656	}
657	return ("Unknown TlsType_t type specified");
658}
659
660
661char *
662__s_get_scope_name(ns_config_t *ptr, ScopeType_t type)
663{
664	register ns_enum_map	*mapp;
665
666	if (ptr->version == NS_LDAP_V1)
667		mapp = &ns_scope_enum_v1[0];
668	else
669		mapp = &ns_scope_enum_v2[0];
670
671	for (; mapp->name != NULL; mapp++) {
672		if (type == INT2SCOPEENUM(mapp->value)) {
673			return (mapp->name);
674		}
675	}
676	return ("Unknown ScopeType_t type specified");
677}
678
679
680char *
681__s_get_pref_name(PrefOnly_t type)
682{
683	register ns_enum_map	*mapp = &ns_pref_enum[0];
684
685	for (; mapp->name != NULL; mapp++) {
686		if (type == INT2PREFONLYENUM(mapp->value)) {
687			return (mapp->name);
688		}
689	}
690	return ("Unknown PrefOnly_t type specified");
691}
692
693char *
694__s_get_searchref_name(ns_config_t *ptr, SearchRef_t type)
695{
696	register ns_enum_map	*mapp;
697
698	if (ptr->version == NS_LDAP_V1)
699		mapp = &ns_ref_enum_v1[0];
700	else
701		mapp = &ns_ref_enum_v2[0];
702
703	for (; mapp->name != NULL; mapp++) {
704		if (type == INT2SEARCHREFENUM(mapp->value)) {
705			return (mapp->name);
706		}
707	}
708	return ("Unknown SearchRef_t type specified");
709}
710
711static char *
712__s_get_credlvl_name(ns_config_t *ptr, CredLevel_t type)
713{
714	register ns_enum_map	*mapp;
715
716	if (ptr->version == NS_LDAP_V2) {
717		mapp = &ns_cred_enum_v2[0];
718		for (; mapp->name != NULL; mapp++) {
719			if (type == INT2CREDLEVELENUM(mapp->value)) {
720				return (mapp->name);
721			}
722		}
723	}
724	return ("Unknown CredLevel_t type specified");
725}
726
727static void
728destroy_param(ns_config_t *ptr, ParamIndexType type)
729{
730	int	i, j;
731	char	**ppc;
732
733	if (ptr == NULL)
734		return;
735
736	/*
737	 * This routine is not lock protected because
738	 * the config param it may be destroying is not
739	 * necessarily THE config.  Mutex protect elsewhere.
740	 */
741	switch (ptr->paramList[type].ns_ptype) {
742	case CHARPTR:
743		if (ptr->paramList[type].ns_pc) {
744			free(ptr->paramList[type].ns_pc);
745			ptr->paramList[type].ns_pc = NULL;
746		}
747		break;
748	case SAMLIST:
749	case SCLLIST:
750	case SSDLIST:
751	case ARRAYCP:
752	case SERVLIST:
753		if (ptr->paramList[type].ns_ppc) {
754			ppc = ptr->paramList[type].ns_ppc;
755			j = ptr->paramList[type].ns_acnt;
756			for (i = 0; i < j && ppc[i] != NULL; i++) {
757				free((void *)ppc[i]);
758			}
759			free((void *)ppc);
760			ptr->paramList[type].ns_ppc = NULL;
761		}
762		break;
763	case ARRAYAUTH:
764	case ARRAYCRED:
765		if (ptr->paramList[type].ns_pi) {
766			free(ptr->paramList[type].ns_pi);
767			ptr->paramList[type].ns_pi = NULL;
768		}
769		break;
770	case INT:
771		ptr->paramList[type].ns_i = 0;
772		break;
773	case ATTRMAP:
774		break;
775	case OBJMAP:
776		break;
777	default:
778		break;
779	}
780	ptr->paramList[type].ns_ptype = NS_UNKNOWN;
781}
782
783static void
784destroy_config(ns_config_t *ptr)
785{
786	ParamIndexType	i;
787
788	if (ptr != NULL) {
789		if (ptr->domainName != NULL)
790			free(ptr->domainName);
791			ptr->domainName = NULL;
792		for (i = 0; i <= LAST_VALUE; i++) {
793			destroy_param(ptr, i);
794		}
795		__s_api_destroy_hash(ptr);
796		free(ptr);
797	}
798}
799
800/*
801 * Marks the ns_config_t to be deleted and then releases it. (If no other
802 * caller is using, then __s_api_release_config will destroy it.)
803 *
804 * Note that __s_api_destroy_config should only be called if the caller has
805 * created the ns_config_t with __s_api_create_config (with the exception
806 * of set_curr_config). The ns_config_t should be private to the caller.
807 *
808 * This function should not be called with the current_config except by
809 * set_curr_config which locks ns_parse_lock to ensure that no thread
810 * will be waiting on current_config->config_mutex. This ensures that
811 * no caller with be waiting on cfg->config_mutex while it is being
812 * destroyed by __s_api_release_config.
813 */
814
815void
816__s_api_destroy_config(ns_config_t *cfg)
817{
818	if (cfg != NULL) {
819		(void) mutex_lock(&cfg->config_mutex);
820		cfg->delete = TRUE;
821		(void) mutex_unlock(&cfg->config_mutex);
822		__s_api_release_config(cfg);
823	}
824}
825
826
827/*
828 * Increment the configuration use count by one - assumes ns_parse_lock has
829 * been obtained
830 */
831
832static ns_config_t *
833get_curr_config_unlocked()
834{
835	ns_config_t *cfg;
836	ns_config_t *ret;
837
838	cfg = current_config;
839	ret = cfg;
840	if (cfg != NULL) {
841		(void) mutex_lock(&cfg->config_mutex);
842		if (cfg->delete)
843			ret = NULL;
844		else
845			cfg->nUse++;
846		(void) mutex_unlock(&cfg->config_mutex);
847	}
848	return (ret);
849}
850
851/*
852 * set_curr_config sets the current config to
853 * the specified ns_config_t. Note that this function
854 * is similar to the project private function __s_api_init_config
855 * except that it does not release the new ns_config_t
856 */
857
858static void
859set_curr_config(ns_config_t *ptr)
860{
861	ns_config_t *cfg;
862
863	(void) mutex_lock(&ns_parse_lock);
864	cfg = get_curr_config_unlocked();
865	if (cfg != ptr) {
866		__s_api_destroy_config(cfg);
867		current_config = ptr;
868	}
869	(void) mutex_unlock(&ns_parse_lock);
870}
871
872/*
873 * Decrements the ns_config_t usage count by one. Delete if delete flag
874 * is set and no other callers are using.
875 */
876
877void
878__s_api_release_config(ns_config_t *cfg)
879{
880	if (cfg != NULL) {
881		(void) mutex_lock(&cfg->config_mutex);
882		cfg->nUse--;
883		if (cfg->nUse == 0 && cfg->delete) {
884			destroy_config(cfg);
885		} else
886			(void) mutex_unlock(&cfg->config_mutex);
887	}
888}
889
890/*
891 * __s_api_init_config function destroys the previous configuration
892 * sets the new configuration and then releases it
893 */
894void
895__s_api_init_config(ns_config_t *ptr)
896{
897	set_curr_config(ptr);
898	__s_api_release_config(ptr);
899}
900
901
902/*
903 * Create an ns_config_t, set the usage count to one
904 */
905
906ns_config_t *
907__s_api_create_config(void)
908{
909	ns_config_t	*ret;
910	ret = (ns_config_t *)calloc(1, sizeof (ns_config_t));
911	if (ret == NULL)
912		return (NULL);
913
914	ret->domainName = __getdomainname();
915	if (ret->domainName == NULL) {
916		free(ret);
917		return (NULL);
918	}
919	ret->version = NS_LDAP_V1;
920	(void) mutex_init(&ret->config_mutex, USYNC_THREAD, NULL);
921	ret->nUse = 1;
922	ret->delete = B_FALSE;
923	return (ret);
924}
925
926ns_config_t *
927__s_api_get_default_config(void)
928{
929	ns_config_t *cfg;
930
931	(void) mutex_lock(&ns_parse_lock);
932	cfg = get_curr_config_unlocked();
933	(void) mutex_unlock(&ns_parse_lock);
934
935	return (cfg);
936}
937
938static char *
939stripdup(const char *instr)
940{
941	char	*pstart = (char *)instr;
942	char	*pend, *ret;
943	int	len;
944
945	if (pstart == NULL)
946		return (NULL);
947	/* remove leading spaces */
948	while (*pstart == SPACETOK)
949		pstart++;
950	/* remove trailing spaces */
951	pend = pstart + strlen(pstart) - 1;
952	for (; pend >= pstart && *pend == SPACETOK; pend--);
953	len = pend - pstart + 1;
954	if ((ret = malloc(len + 1)) == NULL)
955		return (NULL);
956	if (len != 0) {
957		(void) strncpy(ret, pstart, len);
958	}
959	ret[len] = '\0';
960	return (ret);
961}
962
963static boolean_t
964has_port(char **ppc, int cnt)
965{
966	int		j;
967	const char	*s;
968	const char	*begin;
969
970	/*
971	 * Don't check that address is legal - only determine
972	 * if there is a port specified
973	 */
974	if (ppc != NULL) {
975		for (j = 0; j < cnt; j++) {
976			begin = ppc[j];
977			s = begin + strlen(begin);
978			while (s >= begin) {
979				if (*s == ']')
980					break;
981				else if (*s == COLONTOK)
982					return (B_TRUE);
983				s--;
984			}
985		}
986	}
987	return (B_FALSE);
988}
989
990/*
991 * Note that __s_api_crosscheck is assumed to be called with an ns_config_t
992 * that is properly protected - so that it will not change during the
993 * duration of the call
994 */
995
996/* Size of errstr needs to be MAXERROR */
997ns_parse_status
998__s_api_crosscheck(ns_config_t *ptr, char *errstr, int check_dn)
999{
1000	int		value, j;
1001	time_t		tm;
1002	const char	*str, *str1;
1003	boolean_t	has_tls = B_FALSE;
1004	boolean_t	is_ok = B_TRUE;
1005	int		i, len, cnt;
1006	const char	*begin;
1007	char		**ppc;
1008	int		*pi, self, gssapi;
1009
1010
1011	if (ptr == NULL)
1012		return (NS_SUCCESS);
1013
1014	/* check for no server specified */
1015	if (ptr->paramList[NS_LDAP_SERVERS_P].ns_ppc == NULL) {
1016		if (ptr->version == NS_LDAP_V1) {
1017			str = NULL_OR_STR(__s_api_get_configname(
1018					NS_LDAP_SERVERS_P));
1019			(void) snprintf(errstr, MAXERROR,
1020				gettext("Configuration Error: No entry for "
1021				"'%s' found"), str);
1022			return (NS_PARSE_ERR);
1023		} else if (ptr->paramList[NS_LDAP_SERVER_PREF_P].ns_ppc ==
1024			NULL) {
1025			str = NULL_OR_STR(__s_api_get_configname(
1026				NS_LDAP_SERVERS_P));
1027			str1 = NULL_OR_STR(__s_api_get_configname(
1028				NS_LDAP_SERVER_PREF_P));
1029			(void) snprintf(errstr, MAXERROR,
1030				gettext("Configuration Error: "
1031				"Neither '%s' nor '%s' is defined"), str, str1);
1032			return (NS_PARSE_ERR);
1033		}
1034	}
1035	if (ptr->paramList[NS_LDAP_CERT_PASS_P].ns_pc != NULL &&
1036		ptr->paramList[NS_LDAP_CERT_PATH_P].ns_pc == NULL) {
1037			str = NULL_OR_STR(__s_api_get_configname(
1038					NS_LDAP_CERT_PASS_P));
1039			str1 = NULL_OR_STR(__s_api_get_configname(
1040					NS_LDAP_CERT_PATH_P));
1041			(void) snprintf(errstr, MAXERROR,
1042			gettext("Configuration Error: %s specified "
1043				"but no value for '%s' found"), str, str1);
1044		return (NS_PARSE_ERR);
1045	}
1046	if (ptr->paramList[NS_LDAP_CERT_PASS_P].ns_pc == NULL &&
1047		ptr->paramList[NS_LDAP_CERT_PATH_P].ns_pc != NULL) {
1048			str = NULL_OR_STR(__s_api_get_configname(
1049					NS_LDAP_CERT_PATH_P));
1050			str1 = NULL_OR_STR(__s_api_get_configname(
1051					NS_LDAP_CERT_PASS_P));
1052			(void) snprintf(errstr, MAXERROR,
1053			gettext("Configuration Error: %s specified "
1054				"but no value for '%s' found"), str, str1);
1055		return (NS_PARSE_ERR);
1056	}
1057	/* check if search basedn has been specified */
1058	if (ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_ppc == NULL) {
1059		str = NULL_OR_STR(__s_api_get_configname(
1060				NS_LDAP_SEARCH_BASEDN_P));
1061		(void) snprintf(errstr, MAXERROR,
1062			gettext("Configuration Error: No entry for "
1063			    "'%s' found"), str);
1064		return (NS_PARSE_ERR);
1065	}
1066
1067	if (check_dn) {
1068	    /* check for auth value....passwd/bindn if necessary */
1069
1070	    for (j = 0; ptr->paramList[NS_LDAP_AUTH_P].ns_pi != NULL &&
1071		    ptr->paramList[NS_LDAP_AUTH_P].ns_pi[j] != NULL; j++) {
1072		value = ptr->paramList[NS_LDAP_AUTH_P].ns_pi[j];
1073		switch (value) {
1074		    case NS_LDAP_EA_SIMPLE:
1075		    case NS_LDAP_EA_SASL_CRAM_MD5:
1076		    case NS_LDAP_EA_SASL_DIGEST_MD5:
1077		    case NS_LDAP_EA_SASL_DIGEST_MD5_INT:
1078		    case NS_LDAP_EA_SASL_DIGEST_MD5_CONF:
1079		    case NS_LDAP_EA_TLS_SIMPLE:
1080		    case NS_LDAP_EA_TLS_SASL_CRAM_MD5:
1081		    case NS_LDAP_EA_TLS_SASL_DIGEST_MD5:
1082		    case NS_LDAP_EA_TLS_SASL_DIGEST_MD5_INT:
1083		    case NS_LDAP_EA_TLS_SASL_DIGEST_MD5_CONF:
1084			if (ptr->paramList[NS_LDAP_BINDDN_P].ns_ppc == NULL) {
1085				str = NULL_OR_STR(__s_api_get_configname(
1086					NS_LDAP_BINDDN_P));
1087				(void) snprintf(errstr, MAXERROR,
1088				gettext("Configuration Error: No entry for "
1089				    "'%s' found"), str);
1090				return (NS_PARSE_ERR);
1091			}
1092			if (ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_ppc
1093				== NULL) {
1094				str = NULL_OR_STR(__s_api_get_configname(
1095					NS_LDAP_BINDPASSWD_P));
1096				(void) snprintf(errstr, MAXERROR,
1097				gettext("Configuration Error: No entry for "
1098					"'%s' found"), str);
1099				return (NS_PARSE_ERR);
1100			}
1101			break;
1102		}
1103	    }
1104	}
1105
1106	/*
1107	 * Check to see if port and tls are both configured. This is not
1108	 * supported until starttls is supported.
1109	 */
1110
1111	pi = ptr->paramList[NS_LDAP_AUTH_P].ns_pi;
1112	if (pi != NULL) {
1113	    cnt = ptr->paramList[NS_LDAP_AUTH_P].ns_acnt;
1114	    for (j = 0; j < cnt && !has_tls; j++) {
1115		has_tls = (pi[j] == NS_LDAP_EA_TLS_NONE) ||
1116			(pi[j] == NS_LDAP_EA_TLS_SIMPLE) ||
1117			(pi[j] == NS_LDAP_EA_TLS_SASL_CRAM_MD5) ||
1118			(pi[j] == NS_LDAP_EA_TLS_SASL_DIGEST_MD5) ||
1119			(pi[j] == NS_LDAP_EA_TLS_SASL_DIGEST_MD5_INT) ||
1120			(pi[j] == NS_LDAP_EA_TLS_SASL_DIGEST_MD5_CONF) ||
1121			(pi[j] == NS_LDAP_EA_TLS_SASL_EXTERNAL);
1122	    }
1123	}
1124
1125	ppc = ptr->paramList[NS_LDAP_SERVICE_AUTH_METHOD_P].ns_ppc;
1126	if (!has_tls && ppc != NULL) {
1127		cnt = ptr->paramList[NS_LDAP_SERVICE_AUTH_METHOD_P].ns_acnt;
1128		for (j = 0; j < cnt && !has_tls; j++) {
1129			begin = ppc[j];
1130			/* skip over service tag */
1131			if (begin != NULL)
1132				begin = strchr(begin, ':');
1133			if (!has_tls && begin != NULL) {
1134			    len = strlen(begin) - 3;
1135			    for (i = 0; i < len; i++)
1136				if (strncasecmp(begin + i, "tls:", 4) == 0)
1137					break;
1138			    has_tls = i < len;
1139			}
1140		}
1141	}
1142
1143	if (has_tls) {
1144	    is_ok = !has_port(ptr->paramList[NS_LDAP_SERVERS_P].ns_ppc,
1145		ptr->paramList[NS_LDAP_SERVERS_P].ns_acnt);
1146	    ppc = ptr->paramList[NS_LDAP_SERVER_PREF_P].ns_ppc;
1147	    if (is_ok)
1148		is_ok = !has_port(ptr->paramList[NS_LDAP_SERVER_PREF_P].ns_ppc,
1149			ptr->paramList[NS_LDAP_SERVER_PREF_P].ns_acnt);
1150	}
1151	if (!is_ok) {
1152		(void) snprintf(errstr, MAXERROR,
1153			gettext("Configuration Error: "
1154				"Cannot specify LDAP port with tls"));
1155		return (NS_PARSE_ERR);
1156	}
1157
1158	/*
1159	 * If NS_LDAP_CACHETTL is not specified,
1160	 * init NS_LDAP_EXP_P here. Otherwise,
1161	 * ldap_cachemgr will never refresh the profile.
1162	 * Set it to current time + default
1163	 * NS_LDAP_CACHETTL
1164	 */
1165	if (ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc == NULL) {
1166		tm = conv_time(
1167			defconfig[NS_LDAP_CACHETTL_P].defval.ns_pc);
1168		ptr->paramList[NS_LDAP_EXP_P].ns_ptype = TIMET;
1169		if (tm != 0) {
1170			tm += time(NULL);
1171		}
1172		ptr->paramList[NS_LDAP_EXP_P].ns_tm = tm;
1173	}
1174	/*
1175	 * If credential level self is defined, there should be
1176	 * at least an auth method sasl/GSSAPI and vice versa.
1177	 */
1178	self = 0;
1179	cnt = ptr->paramList[NS_LDAP_CREDENTIAL_LEVEL_P].ns_acnt;
1180	for (i = 0; i < cnt; i++) {
1181		if (ptr->paramList[NS_LDAP_CREDENTIAL_LEVEL_P].ns_pi[i] ==
1182				NS_LDAP_CRED_SELF)
1183			self++;
1184	}
1185	gssapi = 0;
1186	cnt = ptr->paramList[NS_LDAP_AUTH_P].ns_acnt;
1187	for (i = 0; i < cnt; i++) {
1188		if (ptr->paramList[NS_LDAP_AUTH_P].ns_pi[i] ==
1189			NS_LDAP_EA_SASL_GSSAPI)
1190			gssapi++;
1191	}
1192	if (gssapi == 0 && self > 0) {
1193		(void) snprintf(errstr, MAXERROR,
1194			gettext("Configuration Error: "
1195				"Credential level self requires "
1196				"authentication method sasl/GSSAPI"));
1197		return (NS_PARSE_ERR);
1198	}
1199	if (gssapi > 0 && self == 0) {
1200		(void) snprintf(errstr, MAXERROR,
1201			gettext("Configuration Error: "
1202				"Authentication method sasl/GSSAPI "
1203				"requires credential level self"));
1204		return (NS_PARSE_ERR);
1205	}
1206	return (NS_SUCCESS);
1207}
1208
1209
1210int
1211__s_api_get_type(const char *value, ParamIndexType *type)
1212{
1213	int	i;
1214
1215	for (i = 0; defconfig[i].name != NULL; i++) {
1216		if (strcasecmp(defconfig[i].name, value) == 0) {
1217			*type = defconfig[i].index;
1218			return (0);
1219		}
1220	}
1221	return (-1);
1222}
1223
1224/*
1225 * Externally defined version of get_type.
1226 * Includes extra error checking
1227 */
1228
1229int
1230__ns_ldap_getParamType(const char *value, ParamIndexType *type)
1231{
1232	if (value == NULL || type == NULL)
1233		return (-1);
1234	return (__s_api_get_type(value, type));
1235}
1236
1237int
1238__s_api_get_versiontype(ns_config_t *ptr, char *value, ParamIndexType *type)
1239{
1240	ns_version_t	ver;
1241	int		i;
1242
1243	if (ptr == NULL)
1244		return (-1);
1245
1246	ver = ptr->version;
1247
1248	for (i = 0; defconfig[i].name != NULL; i++) {
1249		if (strcasecmp(defconfig[i].name, value) == 0) {
1250			if (defconfig[i].version == ver) {
1251				*type = defconfig[i].index;
1252				return (0);
1253			}
1254		}
1255	}
1256	return (-1);
1257}
1258
1259int
1260__s_api_get_profiletype(char *value, ParamIndexType *type)
1261{
1262	int	i;
1263
1264	for (i = 0; defconfig[i].name != NULL; i++) {
1265		if (defconfig[i].profile_name == NULL)
1266			continue;
1267		if (strcasecmp(defconfig[i].profile_name, value) == 0) {
1268			*type = defconfig[i].index;
1269			return (0);
1270		}
1271	}
1272	return (-1);
1273}
1274
1275int
1276__s_api_get_configtype(ParamIndexType type)
1277{
1278	int i;
1279
1280	for (i = 0; defconfig[i].name != NULL; i++) {
1281		if (defconfig[i].index == type) {
1282			return (defconfig[i].config_type);
1283		}
1284	}
1285	return (-1);
1286}
1287
1288const char *
1289__s_api_get_configname(ParamIndexType type)
1290{
1291	int i;
1292
1293	for (i = 0; defconfig[i].name != NULL; i++) {
1294		if (defconfig[i].index == type) {
1295			if (defconfig[i].name[0] == '\0')
1296				return (NULL);
1297			else
1298				return (defconfig[i].name);
1299		}
1300	}
1301	return (NULL);
1302}
1303
1304static ns_default_config *
1305get_defconfig(ns_config_t *ptr, ParamIndexType type)
1306{
1307	ns_version_t	ver;
1308	int		i;
1309
1310	ver = ptr->version;
1311
1312	for (i = 0; defconfig[i].name != NULL; i++) {
1313		if (defconfig[i].index == type &&
1314		    defconfig[i].version == ver) {
1315			return (&defconfig[i]);
1316		}
1317	}
1318	return (NULL);
1319}
1320
1321static int
1322set_default_value(ns_config_t *configptr, char *name,
1323			char *value, ns_ldap_error_t **error)
1324{
1325	ParamIndexType	i;
1326	int		ret;
1327	char		errstr[MAXERROR];
1328
1329	if (__s_api_get_type(name, &i) < 0) {
1330		(void) snprintf(errstr, sizeof (errstr), gettext(
1331			"Illegal type name (%s).\n"), name);
1332		MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
1333			NULL);
1334		return (NS_LDAP_CONFIG);
1335	}
1336
1337	if (i != NS_LDAP_SERVERS_P &&
1338		i != NS_LDAP_SERVICE_AUTH_METHOD_P &&
1339		i != NS_LDAP_SERVICE_CRED_LEVEL_P &&
1340		i != NS_LDAP_SERVICE_SEARCH_DESC_P &&
1341		i != NS_LDAP_SERVER_PREF_P &&
1342		i != NS_LDAP_SEARCH_DN_P) {
1343		if (configptr->paramList[i].ns_ptype != NS_UNKNOWN) {
1344			destroy_param(configptr, i);
1345		}
1346	}
1347
1348	ret = __ns_ldap_setParamValue(configptr, i, value, error);
1349	return (ret);
1350}
1351
1352
1353/*
1354 * Initialize config to a default state
1355 * By default leave configuration empty
1356 * getParam will automatically get the
1357 * appropriate default value if none exists
1358 */
1359
1360void
1361__ns_ldap_default_config()
1362{
1363	ns_config_t	*ptr;
1364
1365	ptr = __s_api_create_config();
1366	if (ptr == NULL)
1367		return;
1368
1369	set_curr_config(ptr);
1370	__s_api_release_config(ptr);
1371}
1372
1373/*
1374 * Get the current configuration pointer and return it.
1375 * If necessary initialize or refresh the current
1376 * configuration as applicable.
1377 */
1378
1379ns_config_t *
1380__s_api_loadrefresh_config()
1381{
1382	ns_config_t		*cfg;
1383	ns_config_t		*new_cfg;
1384	ns_ldap_error_t		*errorp;
1385
1386	/* We want to refresh only one configuration at a time */
1387	(void) mutex_lock(&ns_loadrefresh_lock);
1388	cfg = __s_api_get_default_config();
1389
1390	/* (re)initialize configuration if necessary */
1391	if (timetorefresh(cfg)) {
1392		new_cfg = LoadCacheConfiguration(&errorp);
1393		if (new_cfg != NULL) {
1394			__s_api_release_config(cfg);
1395			set_curr_config(new_cfg);
1396			cfg = new_cfg;
1397		}
1398		if (errorp != NULL)
1399			(void) __ns_ldap_freeError(&errorp);
1400	}
1401	(void) mutex_unlock(&ns_loadrefresh_lock);
1402	return (cfg);
1403}
1404
1405/*
1406 * In general this routine is not very usefull. Individual routines can be
1407 * created to do this job.  Once that is done, this function can be removed.
1408 * Size of errstr buffer needs to be MAXERROR.
1409 */
1410static ns_parse_status
1411verify_value(ns_config_t *cfg, char *name, char *value, char *errstr)
1412{
1413	ParamIndexType	index = 0;
1414	int		found = 0, j;
1415	char		*ptr = NULL, *strptr = NULL, buffer[BUFSIZE];
1416	char		*rest;
1417	ns_default_config	*def = NULL;
1418
1419	if (__s_api_get_type(name, &index) != 0) {
1420		(void) snprintf(errstr, MAXERROR,
1421			gettext("Unknown keyword encountered '%s'."), name);
1422		return (NS_PARSE_ERR);
1423	}
1424
1425	def = get_defconfig(cfg, index);
1426
1427	/* eat up beginning quote, if any */
1428	while (value != NULL && (*value == QUOTETOK || *value == SPACETOK))
1429		value++;
1430
1431	/* eat up space/quote at end of value */
1432	if (strlen(value) > 0)
1433		ptr = value + strlen(value) - 1;
1434	else
1435		ptr = value;
1436	for (; ptr != value && (*ptr == SPACETOK || *ptr == QUOTETOK); ptr--) {
1437		*ptr = '\0';
1438	}
1439
1440	switch (index) {
1441	case NS_LDAP_EXP_P:
1442	case NS_LDAP_CACHETTL_P:
1443	case NS_LDAP_CERT_PATH_P:
1444	case NS_LDAP_CERT_PASS_P:
1445	case NS_LDAP_CERT_NICKNAME_P:
1446	case NS_LDAP_BINDDN_P:
1447	case NS_LDAP_BINDPASSWD_P:
1448	case NS_LDAP_DOMAIN_P:
1449	case NS_LDAP_SEARCH_BASEDN_P:
1450	case NS_LDAP_SEARCH_TIME_P:
1451	case NS_LDAP_PROFILE_P:
1452	case NS_LDAP_AUTH_P:
1453	case NS_LDAP_SEARCH_SCOPE_P:
1454	case NS_LDAP_CREDENTIAL_LEVEL_P:
1455	case NS_LDAP_SERVICE_SEARCH_DESC_P:
1456	case NS_LDAP_BIND_TIME_P:
1457	case NS_LDAP_ATTRIBUTEMAP_P:
1458	case NS_LDAP_OBJECTCLASSMAP_P:
1459	case NS_LDAP_SERVICE_AUTH_METHOD_P:
1460	case NS_LDAP_SERVICE_CRED_LEVEL_P:
1461	case NS_LDAP_HOST_CERTPATH_P:
1462		break;
1463	case NS_LDAP_SEARCH_DN_P:
1464		/* depreciated because of service descriptors */
1465		/* Parse as appropriate at descriptor create time */
1466		break;
1467	case NS_LDAP_FILE_VERSION_P:
1468		if (value != NULL &&
1469			strcasecmp(value, NS_LDAP_VERSION_1) != 0 &&
1470			strcasecmp(value, NS_LDAP_VERSION_2) != 0) {
1471			(void) snprintf(errstr, MAXERROR,
1472				gettext("Version mismatch, expected "
1473				    "cache version '%s' or '%s' but "
1474				    "encountered version '%s'."),
1475				    NS_LDAP_VERSION_1,
1476				    NS_LDAP_VERSION_2, value);
1477				return (NS_PARSE_ERR);
1478		}
1479		break;
1480	case NS_LDAP_SERVERS_P:
1481	case NS_LDAP_SERVER_PREF_P:
1482		(void) strcpy(buffer, value);
1483		strptr = strtok_r(buffer, ",", &rest);
1484		while (strptr != NULL) {
1485			char	*tmp = NULL;
1486			tmp = stripdup(strptr);
1487			if (tmp == NULL || (strchr(tmp, ' ') != NULL)) {
1488				(void) snprintf(errstr, MAXERROR,
1489				    gettext("Invalid parameter values "
1490				    "'%s' specified for keyword '%s'."),
1491				    tmp, name);
1492				free(tmp);
1493				return (NS_PARSE_ERR);
1494			}
1495			free(tmp);
1496			strptr = strtok_r(NULL, ",", &rest);
1497		}
1498		break;
1499	default:
1500		found = 0; j = 0;
1501		while (def->allowed != NULL &&
1502			def->allowed[j].name != NULL && j < DEFMAX) {
1503			if (strcmp(def->allowed[j].name,
1504			    value) == 0) {
1505				found = 1;
1506				break;
1507			}
1508			j++;
1509		}
1510		if (!found) {
1511			    (void) snprintf(errstr, MAXERROR,
1512			    gettext("Invalid option specified for "
1513			    "'%s' keyword. '%s' is not a recognized "
1514			    "keyword value."), name, value);
1515			return (NS_PARSE_ERR);
1516		}
1517	}
1518
1519	return (NS_SUCCESS);
1520}
1521
1522void
1523__s_api_split_key_value(char *buffer, char **name, char **value)
1524{
1525	char	*ptr;
1526
1527	*name = buffer;
1528	/* split into name value pair */
1529	if ((ptr = strchr(buffer, TOKENSEPARATOR)) != NULL) {
1530		*ptr = '\0';
1531		ptr++;
1532		/* trim whitespace */
1533		while (*ptr == SPACETOK)
1534			ptr++;
1535		*value = ptr;
1536	}
1537}
1538
1539/*
1540 * Set a parameter value in a generic configuration structure
1541 * Assume any necessary locks are in place.  This routine would
1542 * be better named: __ns_ldap_translateString2Param
1543 *
1544 * This routine translates external string format into internal
1545 * param format and saves the result in the param table.
1546 */
1547int
1548__ns_ldap_setParamValue(ns_config_t *ptr, const ParamIndexType type,
1549		const void *data, ns_ldap_error_t **error)
1550{
1551	ns_default_config	*def = NULL;
1552	ns_param_t		conf;
1553	ns_mapping_t		*map, *rmap;
1554	int			i, j, len;
1555	char			*cp, *cp2, *end;
1556	char			*tcp = NULL;
1557	char			errstr[2 * MAXERROR];
1558	char			tbuf[100], *ptbuf;
1559	char			*sid, *origA, **mapA;
1560	char			**attr;
1561	time_t			tm;
1562	int 			free_memory, exitrc;
1563	char			**p;
1564
1565	/* Find ParamIndexType default configuration data */
1566	def = get_defconfig(ptr, type);
1567	if (def == NULL) {
1568		(void) snprintf(errstr, sizeof (errstr),
1569				gettext("Unable to set value: "
1570					"invalid ParamIndexType (%d)"), type);
1571		MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
1572			NULL);
1573		return (NS_LDAP_CONFIG);
1574	}
1575
1576	(void) memset(&conf, 0, sizeof (conf));
1577
1578	/* data is actually const char */
1579	cp = (char *)data;
1580
1581	/* eat up beginning quote, if any */
1582	while (cp && (*cp == QUOTETOK || *cp == SPACETOK))
1583		cp++;
1584
1585	/* eat up space/quote at end of value */
1586	end = cp2 = cp + strlen(cp) - 1;
1587	for (; cp2 > cp && (*cp2 == SPACETOK || *cp2 == QUOTETOK); cp2--)
1588		;
1589	/* data is const, must duplicate */
1590	if (cp2 != end) {
1591		tcp = (char *)calloc((int)(cp2 - cp + 2), sizeof (char));
1592		if (tcp == NULL)
1593			return (NS_LDAP_MEMORY);
1594		end = cp2;
1595		cp2 = tcp;
1596		while (cp <= end) {
1597			*cp2++ = *cp++;
1598		}
1599		*cp2 = '\0';
1600		cp = tcp;
1601	}
1602
1603	/* Parse data according to type */
1604	switch (def->data_type) {
1605	case INT:
1606		switch (def->index) {
1607		case NS_LDAP_PREF_ONLY_P:
1608		case NS_LDAP_SEARCH_REF_P:
1609		case NS_LDAP_SEARCH_SCOPE_P:
1610			i = __s_get_enum_value(ptr, cp, def->index);
1611			if (i < 0) {
1612				(void) snprintf(errstr, sizeof (errstr),
1613					gettext("Unable to set value: "
1614					"invalid %s (%d)"), def->name,
1615					def->index);
1616				MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
1617					strdup(errstr), NULL);
1618				if (tcp != NULL)
1619					free(tcp);
1620				return (NS_LDAP_CONFIG);
1621			}
1622			conf.ns_i = i;
1623			break;
1624		case NS_LDAP_TRANSPORT_SEC_P:	/* ignore TRANSPORT_SEC */
1625			break;
1626		default:
1627			cp2 = cp;
1628			if ((*cp2 == '+') || (*cp2 == '-'))
1629				cp2++;
1630			for (/* empty */; *cp2; cp2++) {
1631				if (isdigit(*cp2))
1632					continue;
1633
1634				(void) snprintf(errstr, sizeof (errstr),
1635					gettext("Unable to set value: "
1636					"invalid %s (%d)"), def->name,
1637					def->index);
1638				MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
1639						strdup(errstr), NULL);
1640				if (tcp != NULL)
1641					free(tcp);
1642				return (NS_LDAP_CONFIG);
1643			}
1644			i = atoi(cp);
1645			conf.ns_i = i;
1646			break;
1647		}
1648		break;
1649	case TIMET:
1650		/* Do nothing with a TIMET.  Initialize it below */
1651		break;
1652	case CHARPTR:
1653		conf.ns_pc = (char *)strdup(cp);
1654		if (conf.ns_pc == NULL) {
1655			if (tcp != NULL)
1656				free(tcp);
1657			return (NS_LDAP_MEMORY);
1658		}
1659		break;
1660	case SAMLIST:
1661		/* first check to see if colon (:) is there */
1662		if ((strchr(cp, COLONTOK)) == NULL) {
1663			(void) snprintf(errstr, sizeof (errstr),
1664				gettext("Unable to set value: "
1665				"invalid serviceAuthenticationMethod (%s)"),
1666				cp);
1667			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
1668					strdup(errstr), NULL);
1669			if (tcp != NULL)
1670				free(tcp);
1671			return (NS_LDAP_CONFIG);
1672		}
1673		/* Appends an entry to the existing list */
1674		if (ptr->paramList[type].ns_ptype != SAMLIST) {
1675			conf.ns_ppc = (char **)calloc(2, sizeof (char *));
1676			if (conf.ns_ppc == NULL) {
1677				if (tcp != NULL)
1678					free(tcp);
1679				return (NS_LDAP_MEMORY);
1680			}
1681			conf.ns_acnt = 1;
1682			conf.ns_ppc[0] = (char *)strdup(cp);
1683			if (conf.ns_ppc[0] == NULL) {
1684				free(conf.ns_ppc);
1685				if (tcp != NULL)
1686					free(tcp);
1687				return (NS_LDAP_MEMORY);
1688			}
1689		} else {
1690			char *dp, *dpend;
1691			int fnd = 0;
1692
1693			/* Attempt to replace if possible */
1694			dpend = strchr(cp, COLONTOK);
1695			len = dpend - cp;
1696			dp = (char *)malloc(len+1);
1697			if (dp == NULL) {
1698				if (tcp != NULL)
1699					free(tcp);
1700				return (NS_LDAP_MEMORY);
1701			}
1702			(void) strlcpy(dp, cp, len+1);
1703			fnd = 0;
1704			for (j = 0; j < ptr->paramList[type].ns_acnt; j++) {
1705				dpend = strchr(ptr->paramList[type].ns_ppc[j],
1706						COLONTOK);
1707				if (dpend == NULL)
1708					continue;
1709				i = dpend - ptr->paramList[type].ns_ppc[j];
1710				if (i != len)
1711					continue;
1712				if (strncmp(ptr->paramList[type].ns_ppc[j],
1713					    dp, len) == 0) {
1714					conf.ns_acnt =
1715						ptr->paramList[type].ns_acnt;
1716					conf.ns_ppc =
1717						ptr->paramList[type].ns_ppc;
1718					ptr->paramList[type].ns_ppc = NULL;
1719					free(conf.ns_ppc[j]);
1720					conf.ns_ppc[j] = (char *)strdup(cp);
1721					if (conf.ns_ppc[j] == NULL) {
1722						free(dp);
1723						__s_api_free2dArray
1724							(conf.ns_ppc);
1725						if (tcp != NULL)
1726							free(tcp);
1727						return (NS_LDAP_MEMORY);
1728					}
1729					fnd = 1;
1730					break;
1731				}
1732			}
1733			free(dp);
1734
1735			if (fnd)
1736				break;	/* Replaced completed */
1737
1738			/* Append */
1739			len = ptr->paramList[type].ns_acnt + 1;
1740			if (len > 1) {
1741				p = (char **)dupParam(&ptr->paramList[type]);
1742				if (p == NULL) {
1743					if (tcp != NULL)
1744						free(tcp);
1745					return (NS_LDAP_MEMORY);
1746				}
1747			} else
1748				p = NULL;
1749			conf.ns_ppc =
1750				(char **)realloc(p, (len+1) * sizeof (char *));
1751			if (conf.ns_ppc == NULL) {
1752				__s_api_free2dArray(p);
1753				if (tcp != NULL)
1754					free(tcp);
1755				return (NS_LDAP_MEMORY);
1756			}
1757			conf.ns_acnt = len;
1758			conf.ns_ppc[len-1] = (char *)strdup(cp);
1759			if (conf.ns_ppc[len-1] == NULL) {
1760				__s_api_free2dArray(conf.ns_ppc);
1761				if (tcp != NULL)
1762					free(tcp);
1763				return (NS_LDAP_MEMORY);
1764			}
1765			conf.ns_ppc[len] = NULL;
1766		}
1767		break;
1768	case SCLLIST:
1769		/* first check to see if colon (:) is there */
1770		if ((strchr(cp, COLONTOK)) == NULL) {
1771			(void) snprintf(errstr, sizeof (errstr),
1772				gettext("Unable to set value: "
1773				"invalid serviceCredentialLevel (%s)"),
1774				cp);
1775			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
1776					strdup(errstr), NULL);
1777			if (tcp != NULL)
1778				free(tcp);
1779			return (NS_LDAP_CONFIG);
1780		}
1781		/* Appends an entry to the existing list */
1782		if (ptr->paramList[type].ns_ptype != SCLLIST) {
1783			conf.ns_ppc = (char **)calloc(2, sizeof (char *));
1784			if (conf.ns_ppc == NULL) {
1785				if (tcp != NULL)
1786					free(tcp);
1787				return (NS_LDAP_MEMORY);
1788			}
1789			conf.ns_acnt = 1;
1790			conf.ns_ppc[0] = (char *)strdup(cp);
1791			if (conf.ns_ppc[0] == NULL) {
1792				free(conf.ns_ppc);
1793				if (tcp != NULL)
1794					free(tcp);
1795				return (NS_LDAP_MEMORY);
1796			}
1797		} else {
1798			char *dp, *dpend;
1799			int fnd = 0;
1800
1801			/* Attempt to replace if possible */
1802			dpend = strchr(cp, COLONTOK);
1803			len = dpend - cp;
1804			dp = (char *)malloc(len+1);
1805			if (dp == NULL) {
1806				if (tcp != NULL)
1807					free(tcp);
1808				return (NS_LDAP_MEMORY);
1809			}
1810			(void) strlcpy(dp, cp, len+1);
1811			fnd = 0;
1812			for (j = 0; j < ptr->paramList[type].ns_acnt; j++) {
1813				dpend = strchr(ptr->paramList[type].ns_ppc[j],
1814						COLONTOK);
1815				if (dpend == NULL)
1816					continue;
1817				i = dpend - ptr->paramList[type].ns_ppc[j];
1818				if (i != len)
1819					continue;
1820				if (strncmp(ptr->paramList[type].ns_ppc[j],
1821					    dp, len) == 0) {
1822					conf.ns_acnt =
1823						ptr->paramList[type].ns_acnt;
1824					conf.ns_ppc =
1825						ptr->paramList[type].ns_ppc;
1826					ptr->paramList[type].ns_ppc = NULL;
1827					free(conf.ns_ppc[j]);
1828					conf.ns_ppc[j] = (char *)strdup(cp);
1829					if (conf.ns_ppc[j] == NULL) {
1830						free(dp);
1831						__s_api_free2dArray
1832							(conf.ns_ppc);
1833						if (tcp != NULL)
1834							free(tcp);
1835						return (NS_LDAP_MEMORY);
1836					}
1837					fnd = 1;
1838					break;
1839				}
1840			}
1841			free(dp);
1842
1843			if (fnd)
1844				break;	/* Replaced completed */
1845
1846			/* Append */
1847			len = ptr->paramList[type].ns_acnt + 1;
1848			if (len > 1) {
1849				p = (char **)dupParam(&ptr->paramList[type]);
1850				if (p == NULL) {
1851					if (tcp != NULL)
1852						free(tcp);
1853					return (NS_LDAP_MEMORY);
1854				}
1855			} else
1856				p = NULL;
1857			conf.ns_ppc =
1858				(char **)realloc(p, (len+1) * sizeof (char *));
1859			if (conf.ns_ppc == NULL) {
1860				__s_api_free2dArray(p);
1861				if (tcp != NULL)
1862					free(tcp);
1863				return (NS_LDAP_MEMORY);
1864			}
1865			conf.ns_acnt = len;
1866			conf.ns_ppc[len-1] = (char *)strdup(cp);
1867			if (conf.ns_ppc[len-1] == NULL) {
1868				__s_api_free2dArray(conf.ns_ppc);
1869				if (tcp != NULL)
1870					free(tcp);
1871				return (NS_LDAP_MEMORY);
1872			}
1873			conf.ns_ppc[len] = NULL;
1874		}
1875		break;
1876	case SSDLIST:
1877		/*
1878		 * first check to see if colon (:) is there,
1879		 * if so, make sure the serviceId is specified,
1880		 * i.e., colon is not the first character
1881		 */
1882		if ((strchr(cp, COLONTOK)) == NULL || *cp == COLONTOK) {
1883			(void) snprintf(errstr, sizeof (errstr),
1884				gettext("Unable to set value: "
1885				"invalid serviceSearchDescriptor (%s)"),
1886				cp);
1887			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
1888					strdup(errstr), NULL);
1889			if (tcp != NULL)
1890				free(tcp);
1891			return (NS_LDAP_CONFIG);
1892		}
1893		/* Appends an entry to the existing list */
1894		if (ptr->paramList[type].ns_ptype != SSDLIST) {
1895			conf.ns_ppc = (char **)calloc(2, sizeof (char *));
1896			if (conf.ns_ppc == NULL) {
1897				if (tcp != NULL)
1898					free(tcp);
1899				return (NS_LDAP_MEMORY);
1900			}
1901			conf.ns_acnt = 1;
1902			conf.ns_ppc[0] = (char *)strdup(cp);
1903			if (conf.ns_ppc[0] == NULL) {
1904				free(conf.ns_ppc);
1905				if (tcp != NULL)
1906					free(tcp);
1907				return (NS_LDAP_MEMORY);
1908			}
1909		} else {
1910			char *dp, *dpend;
1911			int fnd = 0;
1912
1913			/* Attempt to replace if possible */
1914			dpend = strchr(cp, COLONTOK);
1915			len = dpend - cp;
1916			dp = (char *)malloc(len+1);
1917			if (dp == NULL) {
1918				if (tcp != NULL)
1919					free(tcp);
1920				return (NS_LDAP_MEMORY);
1921			}
1922			(void) strlcpy(dp, cp, len+1);
1923			fnd = 0;
1924			for (j = 0; j < ptr->paramList[type].ns_acnt; j++) {
1925				dpend = strchr(ptr->paramList[type].ns_ppc[j],
1926						COLONTOK);
1927				if (dpend == NULL)
1928					continue;
1929				i = dpend - ptr->paramList[type].ns_ppc[j];
1930				if (i != len)
1931					continue;
1932				if (strncmp(ptr->paramList[type].ns_ppc[j],
1933					    dp, len) == 0) {
1934					conf.ns_acnt =
1935						ptr->paramList[type].ns_acnt;
1936					conf.ns_ppc =
1937						ptr->paramList[type].ns_ppc;
1938					ptr->paramList[type].ns_ppc = NULL;
1939					free(conf.ns_ppc[j]);
1940					conf.ns_ppc[j] = (char *)strdup(cp);
1941					if (conf.ns_ppc[j] == NULL) {
1942						free(dp);
1943						__s_api_free2dArray
1944							(conf.ns_ppc);
1945						if (tcp != NULL)
1946							free(tcp);
1947						return (NS_LDAP_MEMORY);
1948					}
1949					fnd = 1;
1950					break;
1951				}
1952			}
1953			free(dp);
1954
1955			if (fnd)
1956				break;	/* Replaced completed */
1957
1958			/* Append */
1959			len = ptr->paramList[type].ns_acnt + 1;
1960			if (len > 1) {
1961				p = (char **)dupParam(&ptr->paramList[type]);
1962				if (p == NULL) {
1963					if (tcp != NULL)
1964						free(tcp);
1965					return (NS_LDAP_MEMORY);
1966				}
1967			} else
1968				p = NULL;
1969			conf.ns_ppc =
1970				(char **)realloc(p, (len+1) * sizeof (char *));
1971			if (conf.ns_ppc == NULL) {
1972				__s_api_free2dArray(p);
1973				if (tcp != NULL)
1974					free(tcp);
1975				return (NS_LDAP_MEMORY);
1976			}
1977			conf.ns_acnt = len;
1978			conf.ns_ppc[len-1] = (char *)strdup(cp);
1979			if (conf.ns_ppc[len-1] == NULL) {
1980				__s_api_free2dArray(conf.ns_ppc);
1981				if (tcp != NULL)
1982					free(tcp);
1983				return (NS_LDAP_MEMORY);
1984			}
1985			conf.ns_ppc[len] = NULL;
1986		}
1987		break;
1988	case ARRAYCP:
1989		len = 0;
1990		for (cp2 = cp; *cp2; cp2++) {
1991			if (*cp2 == COMMATOK)
1992				len++;
1993		}
1994		if (cp != cp2)
1995			len++;
1996		if (len == 0) {
1997			conf.ns_ppc = (char **)NULL;
1998			conf.ns_acnt = 0;
1999			break;
2000		}
2001		conf.ns_ppc = (char **)calloc(len + 1, sizeof (char *));
2002		if (conf.ns_ppc == NULL) {
2003			if (tcp != NULL)
2004				free(tcp);
2005			return (NS_LDAP_MEMORY);
2006		}
2007		conf.ns_acnt = len;
2008		i = 0;
2009		for (cp2 = cp; *cp2; cp2++) {
2010			if (*cp2 == COMMATOK) {
2011				j = cp2 - cp + 1;
2012				conf.ns_ppc[i] = (char *)malloc(j + 1);
2013				if (conf.ns_ppc[i] == NULL) {
2014					__s_api_free2dArray(conf.ns_ppc);
2015					if (tcp != NULL)
2016						free(tcp);
2017					return (NS_LDAP_MEMORY);
2018				}
2019				(void) strlcpy(conf.ns_ppc[i], cp, j);
2020				cp = cp2+1;
2021				while (*cp == SPACETOK || *cp == COMMATOK)
2022					cp++;
2023				cp2 = cp - 1;
2024				i++;
2025			}
2026		}
2027		j = cp2 - cp + 1;
2028		conf.ns_ppc[i] = (char *)malloc(j + 1);
2029		if (conf.ns_ppc[i] == NULL) {
2030			__s_api_free2dArray(conf.ns_ppc);
2031			if (tcp != NULL)
2032				free(tcp);
2033			return (NS_LDAP_MEMORY);
2034		}
2035		(void) strlcpy(conf.ns_ppc[i], cp, j);
2036		break;
2037	case SERVLIST:
2038		len = 0;
2039		for (cp2 = cp; *cp2; cp2++) {
2040			if (*cp2 == SPACETOK || *cp2 == COMMATOK) {
2041				len++;
2042				for (; *(cp2 + 1) == SPACETOK ||
2043					    *(cp2 +1) == COMMATOK; cp2++)
2044					;
2045			}
2046		}
2047		if (cp != cp2)
2048			len++;
2049		if (len == 0) {
2050			conf.ns_ppc = (char **)NULL;
2051			conf.ns_acnt = 0;
2052			break;
2053		}
2054		conf.ns_ppc = (char **)calloc(len + 1, sizeof (char *));
2055		if (conf.ns_ppc == NULL) {
2056			if (tcp != NULL)
2057				free(tcp);
2058			return (NS_LDAP_MEMORY);
2059		}
2060		conf.ns_acnt = len;
2061		i = 0;
2062		for (cp2 = cp; *cp2; cp2++) {
2063			if (*cp2 == SPACETOK || *cp2 == COMMATOK) {
2064				j = cp2 - cp + 1;
2065				conf.ns_ppc[i] = (char *)malloc(j + 1);
2066				if (conf.ns_ppc[i] == NULL) {
2067					__s_api_free2dArray(conf.ns_ppc);
2068					if (tcp != NULL)
2069						free(tcp);
2070					return (NS_LDAP_MEMORY);
2071				}
2072				(void) strlcpy(conf.ns_ppc[i], cp, j);
2073				cp = cp2+1;
2074				while (*cp == SPACETOK || *cp == COMMATOK)
2075					cp++;
2076				cp2 = cp - 1;
2077				i++;
2078			}
2079		}
2080		j = cp2 - cp + 1;
2081		conf.ns_ppc[i] = (char *)malloc(j + 1);
2082		if (conf.ns_ppc[i] == NULL) {
2083			__s_api_free2dArray(conf.ns_ppc);
2084			if (tcp != NULL)
2085				free(tcp);
2086			return (NS_LDAP_MEMORY);
2087		}
2088		(void) strlcpy(conf.ns_ppc[i], cp, j);
2089		break;
2090	case ARRAYAUTH:
2091		len = 0;
2092		for (cp2 = cp; *cp2; cp2++) {
2093			if (*cp2 == SEMITOK || *cp2 == COMMATOK)
2094				len++;
2095		}
2096		if (cp != cp2)
2097			len++;
2098		if (len == 0) {
2099			conf.ns_pi = (int *)NULL;
2100			conf.ns_acnt = 0;
2101			break;
2102		}
2103		conf.ns_pi = (int *)calloc(len + 1, sizeof (int));
2104		if (conf.ns_pi == NULL) {
2105			if (tcp != NULL)
2106				free(tcp);
2107			return (NS_LDAP_MEMORY);
2108		}
2109		conf.ns_acnt = len;
2110		i = 0;
2111		for (cp2 = cp; *cp2; cp2++) {
2112			if (*cp2 == SEMITOK || *cp2 == COMMATOK) {
2113				j = cp2 - cp + 1;
2114				if (j > sizeof (tbuf)) {
2115					j = -1;
2116					ptbuf = cp;
2117				} else {
2118					(void) strlcpy(tbuf, cp, j);
2119					j = __s_get_enum_value(ptr, tbuf,
2120						def->index);
2121					ptbuf = tbuf;
2122				}
2123				if (j < 0) {
2124					(void) snprintf(errstr, sizeof (errstr),
2125					gettext("Unable to set value: "
2126					"invalid authenticationMethod (%s)"),
2127					ptbuf);
2128					MKERROR(LOG_ERR, *error,
2129						NS_CONFIG_SYNTAX,
2130						strdup(errstr), NULL);
2131					free(conf.ns_pi);
2132					if (tcp != NULL)
2133						free(tcp);
2134					return (NS_LDAP_CONFIG);
2135				}
2136				conf.ns_pi[i] = j;
2137				cp = cp2+1;
2138				i++;
2139			}
2140		}
2141		j = cp2 - cp + 1;
2142		if (j > sizeof (tbuf)) {
2143			j = -1;
2144			ptbuf = cp;
2145		} else {
2146			(void) strlcpy(tbuf, cp, j);
2147			j = __s_get_enum_value(ptr, tbuf, def->index);
2148			ptbuf = tbuf;
2149		}
2150		if (j < 0) {
2151			(void) snprintf(errstr, sizeof (errstr),
2152				gettext("Unable to set value: "
2153				"invalid authenticationMethod (%s)"), ptbuf);
2154			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
2155				strdup(errstr), NULL);
2156			if (tcp != NULL)
2157				free(tcp);
2158			return (NS_LDAP_CONFIG);
2159		}
2160		conf.ns_pi[i] = j;
2161		break;
2162	case ARRAYCRED:
2163		len = 0;
2164		for (cp2 = cp; *cp2; cp2++) {
2165			if (*cp2 == SPACETOK)
2166				len++;
2167		}
2168		if (cp != cp2)
2169			len++;
2170		if (len == 0) {
2171			conf.ns_pi = (int *)NULL;
2172			conf.ns_acnt = 0;
2173			break;
2174		}
2175		conf.ns_pi = (int *)calloc(len + 1, sizeof (int));
2176		if (conf.ns_pi == NULL) {
2177			if (tcp != NULL)
2178				free(tcp);
2179			return (NS_LDAP_MEMORY);
2180		}
2181		conf.ns_acnt = len;
2182		i = 0;
2183		for (cp2 = cp; *cp2; cp2++) {
2184			if (*cp2 == SPACETOK) {
2185				j = cp2 - cp + 1;
2186				if (j > sizeof (tbuf)) {
2187					j = -1;
2188					ptbuf = cp;
2189				} else {
2190					(void) strlcpy(tbuf, cp, j);
2191					j = __s_get_enum_value(ptr, tbuf,
2192						def->index);
2193					ptbuf = tbuf;
2194				}
2195				if (j < 0) {
2196					(void) snprintf(errstr, sizeof (errstr),
2197					gettext("Unable to set value: "
2198					"invalid credentialLevel (%s)"),
2199					ptbuf);
2200					MKERROR(LOG_ERR, *error,
2201						NS_CONFIG_SYNTAX,
2202						strdup(errstr), NULL);
2203					free(conf.ns_pi);
2204					if (tcp != NULL)
2205						free(tcp);
2206					return (NS_LDAP_CONFIG);
2207				}
2208				conf.ns_pi[i] = j;
2209				cp = cp2+1;
2210				i++;
2211			}
2212		}
2213		j = cp2 - cp + 1;
2214		if (j > sizeof (tbuf)) {
2215			j = -1;
2216			ptbuf = cp;
2217		} else {
2218			(void) strlcpy(tbuf, cp, j);
2219			j = __s_get_enum_value(ptr, tbuf, def->index);
2220			ptbuf = tbuf;
2221		}
2222		if (j < 0) {
2223			(void) snprintf(errstr, sizeof (errstr),
2224				gettext("Unable to set value: "
2225				"invalid credentialLevel (%s)"), ptbuf);
2226			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
2227				strdup(errstr), NULL);
2228			if (tcp != NULL)
2229				free(tcp);
2230			return (NS_LDAP_CONFIG);
2231		}
2232		conf.ns_pi[i] = j;
2233		break;
2234	case ATTRMAP:
2235	case OBJMAP:
2236		i = __s_api_parse_map(cp, &sid, &origA, &mapA);
2237		if (i != NS_HASH_RC_SUCCESS) {
2238			if (i == NS_HASH_RC_NO_MEMORY) {
2239				exitrc = NS_LDAP_MEMORY;
2240			} else {
2241				(void) snprintf(errstr, sizeof (errstr),
2242				gettext("Unable to set value: "
2243				"invalid schema mapping (%s)"), cp);
2244				exitrc = NS_LDAP_CONFIG;
2245				MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
2246					strdup(errstr), NULL);
2247			}
2248			if (tcp)
2249				free(tcp);
2250			return (exitrc);
2251		}
2252
2253		/*
2254		 * Add reverse map first.
2255		 * There could be more than one.
2256		 */
2257		for (attr = mapA; *attr; attr++) {
2258
2259			free_memory = 1;
2260			exitrc = NS_LDAP_MEMORY;
2261
2262			rmap = (ns_mapping_t *)calloc(1,
2263				sizeof (ns_mapping_t));
2264			if (rmap) {
2265				rmap->service = strdup(sid);
2266				if (rmap->service) {
2267					rmap->orig = strdup(*attr);
2268					if (rmap->orig) {
2269						rmap->map = (char **)calloc(2,
2270							sizeof (char *));
2271						if (rmap->map) {
2272							(rmap->map)[0] =
2273								strdup(origA);
2274							if ((rmap->map)[0])
2275								free_memory = 0;
2276						}
2277					}
2278				}
2279			}
2280
2281			if (free_memory == 0) {
2282				if (def->data_type == ATTRMAP) {
2283					rmap->type = NS_ATTR_MAP;
2284					i = __s_api_add_map2hash(ptr,
2285						NS_HASH_RAMAP, rmap);
2286				} else {
2287					rmap->type = NS_OBJ_MAP;
2288					i = __s_api_add_map2hash(ptr,
2289						NS_HASH_ROMAP, rmap);
2290				}
2291
2292				if (i != NS_HASH_RC_SUCCESS) {
2293					switch (i) {
2294					case NS_HASH_RC_CONFIG_ERROR:
2295						exitrc = NS_LDAP_INTERNAL;
2296						(void) snprintf(errstr,
2297							sizeof (errstr),
2298							gettext(
2299							"Unable to set value: "
2300							"no configuration info "
2301							"for schema map "
2302							"update (%s)"), cp);
2303						MKERROR(LOG_ERR, *error,
2304							NS_LDAP_INTERNAL,
2305							strdup(errstr),
2306							NULL);
2307						break;
2308					case NS_HASH_RC_EXISTED:
2309						exitrc = NS_LDAP_CONFIG;
2310						(void) snprintf(errstr,
2311							sizeof (errstr),
2312							gettext(
2313							"Unable to set value: "
2314							"schema map "
2315							"already existed for "
2316							"(%s, %s)."),
2317							*attr, origA);
2318						MKERROR(LOG_ERR, *error,
2319							NS_CONFIG_SYNTAX,
2320							strdup(errstr),
2321							NULL);
2322						break;
2323					case NS_HASH_RC_NO_MEMORY:
2324						exitrc = NS_LDAP_MEMORY;
2325						break;
2326					}
2327					free_memory = 1;
2328				}
2329			}
2330
2331			if (free_memory) {
2332				if (tcp)
2333					free(tcp);
2334				free(sid);
2335				free(origA);
2336				__s_api_free2dArray(mapA);
2337				if (rmap) {
2338					if (rmap->service)
2339						free(rmap->service);
2340					if (rmap->orig)
2341						free(rmap->orig);
2342					if (rmap->map) {
2343						if ((rmap->map)[0])
2344							free((rmap->map)[0]);
2345						free(rmap->map);
2346					}
2347					free(rmap);
2348				}
2349				return (exitrc);
2350			}
2351		}
2352
2353		/*
2354		 * For performance gain,
2355		 * add a "schema mapping existed" indicator
2356		 * for the given service if not already added.
2357		 * This dummy map needs not be removed, if
2358		 * the next real map add operation fails.
2359		 * since the caller, e.g. ldap_cachemgr.
2360		 * should exit anyway.
2361		 */
2362		free_memory = 1;
2363		exitrc = NS_LDAP_MEMORY;
2364
2365		map = (ns_mapping_t *)calloc(1,
2366			sizeof (ns_mapping_t));
2367		if (map) {
2368			map->service = strdup(sid);
2369			if (map->service) {
2370				map->orig = strdup(
2371				NS_HASH_SCHEMA_MAPPING_EXISTED);
2372				if (map->orig) {
2373					map->map = (char **)calloc(2,
2374						sizeof (char *));
2375					if (map->map) {
2376						(map->map)[0] =
2377							strdup(sid);
2378						if ((map->map)[0])
2379							free_memory = 0;
2380					}
2381				}
2382			}
2383		}
2384
2385		if (free_memory == 0) {
2386			map->type = NS_ATTR_MAP;
2387			/*
2388			 * add to reverse map,
2389			 * so that "ldapclient list"
2390			 * would not show it
2391			 */
2392			i = __s_api_add_map2hash(ptr,
2393				NS_HASH_RAMAP, map);
2394
2395			/*
2396			 * ignore "map already existed" error,
2397			 * just need one per service.
2398			 * Need however to free memory allocated
2399			 * for map.
2400			 */
2401			if (i != NS_HASH_RC_SUCCESS &&
2402				i != NS_HASH_RC_EXISTED) {
2403				switch (i) {
2404				case NS_HASH_RC_CONFIG_ERROR:
2405					exitrc = NS_LDAP_INTERNAL;
2406					(void) snprintf(errstr,
2407						sizeof (errstr),
2408						gettext(
2409						"Unable to set value: "
2410						"no configuration info "
2411						"for schema map "
2412						"update (%s)"), cp);
2413					MKERROR(LOG_ERR, *error,
2414						NS_LDAP_INTERNAL,
2415						strdup(errstr),
2416						NULL);
2417					break;
2418				case NS_HASH_RC_NO_MEMORY:
2419					exitrc = NS_LDAP_MEMORY;
2420					break;
2421				}
2422				free_memory = 1;
2423			} else if (i == NS_HASH_RC_EXISTED) {
2424				if (map->service)
2425					free(map->service);
2426				if (map->orig)
2427					free(map->orig);
2428				if (map->map) {
2429					if ((map->map)[0])
2430						free((map->map)[0]);
2431					free(map->map);
2432				}
2433				free(map);
2434				map = NULL;
2435			}
2436		}
2437
2438		if (free_memory) {
2439			if (tcp)
2440				free(tcp);
2441			free(sid);
2442			free(origA);
2443			__s_api_free2dArray(mapA);
2444			if (map) {
2445				if (map->service)
2446					free(map->service);
2447				if (map->orig)
2448					free(map->orig);
2449				if (map->map) {
2450					if ((map->map)[0])
2451						free((map->map)[0]);
2452					free(map->map);
2453				}
2454				free(map);
2455			}
2456			return (exitrc);
2457		}
2458
2459		/*
2460		 * add the real schema map
2461		 */
2462		free_memory = 1;
2463		exitrc = NS_LDAP_MEMORY;
2464		map = (ns_mapping_t *)calloc(1, sizeof (ns_mapping_t));
2465		if (map) {
2466			map->service = sid;
2467			map->orig = origA;
2468			map->map = mapA;
2469
2470			if (def->data_type == ATTRMAP) {
2471				map->type = NS_ATTR_MAP;
2472				i = __s_api_add_map2hash(ptr,
2473					NS_HASH_AMAP, map);
2474			} else {
2475				map->type = NS_OBJ_MAP;
2476				i = __s_api_add_map2hash(ptr,
2477					NS_HASH_OMAP, map);
2478			}
2479
2480			if (i != NS_HASH_RC_SUCCESS) {
2481				switch (i) {
2482				case NS_HASH_RC_CONFIG_ERROR:
2483					exitrc = NS_LDAP_INTERNAL;
2484					(void) snprintf(errstr,
2485						sizeof (errstr),
2486						gettext(
2487						"Unable to set value: "
2488						"no configuration info "
2489						"for schema map "
2490						"update (%s)"), cp);
2491					MKERROR(LOG_ERR, *error,
2492						NS_LDAP_INTERNAL,
2493						strdup(errstr),
2494						NULL);
2495					break;
2496				case NS_HASH_RC_EXISTED:
2497					exitrc = NS_LDAP_CONFIG;
2498					(void) snprintf(errstr,
2499						sizeof (errstr),
2500						gettext(
2501						"Unable to set value: "
2502						"schema map "
2503						"already existed for "
2504						"'%s'."), origA);
2505					MKERROR(LOG_ERR, *error,
2506						NS_CONFIG_SYNTAX,
2507						strdup(errstr),
2508						NULL);
2509					break;
2510				case NS_HASH_RC_NO_MEMORY:
2511					exitrc = NS_LDAP_MEMORY;
2512					break;
2513				}
2514				free_memory = 1;
2515			} else
2516				free_memory = 0;
2517		}
2518
2519		if (free_memory) {
2520			if (tcp)
2521				free(tcp);
2522			free(sid);
2523			free(origA);
2524			__s_api_free2dArray(mapA);
2525			if (map)
2526				free(map);
2527			return (exitrc);
2528		}
2529
2530		break;
2531	default:
2532		/* This should never happen. */
2533		(void) snprintf(errstr, sizeof (errstr),
2534			gettext("Unable to set value: invalid configuration "
2535			"type (%d)"), def->data_type);
2536		MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
2537			NULL);
2538		if (tcp != NULL)
2539			free(tcp);
2540		return (NS_LDAP_CONFIG);
2541	}
2542	conf.ns_ptype = def->data_type;
2543	if (tcp != NULL)
2544		free(tcp);
2545
2546	/* Individually written verify routines here can replace */
2547	/* verify_value.  Verify conf (data) as appropriate here */
2548	if (def->ns_verify != NULL) {
2549		if ((*def->ns_verify)(type, def, &conf, errstr) != NS_SUCCESS) {
2550			ns_param_t sav_conf;
2551
2552			(void) snprintf(errstr, sizeof (errstr),
2553					gettext("%s"), errstr);
2554			MKERROR(LOG_WARNING, *error, NS_CONFIG_SYNTAX,
2555				strdup(errstr), NULL);
2556
2557			sav_conf = ptr->paramList[type];
2558			ptr->paramList[type] = conf;
2559			destroy_param(ptr, type);
2560			ptr->paramList[type] = sav_conf;
2561
2562			return (NS_LDAP_CONFIG);
2563		}
2564	}
2565
2566	/* post evaluate the data */
2567
2568	/*
2569	 * if this is for setting a password,
2570	 * encrypt the password first.
2571	 * NOTE evalue() is smart and will just return
2572	 * the value passed if it is already encrypted.
2573	 *
2574	 * Init NS_LDAP_EXP_P here when CACHETTL is updated
2575	 */
2576	if (type == NS_LDAP_BINDPASSWD_P) {
2577		cp = conf.ns_pc;
2578		cp2 = evalue((char *)cp);
2579		conf.ns_pc = cp2;
2580		free(cp);
2581		cp = NULL;
2582	} else if (type == NS_LDAP_FILE_VERSION_P) {
2583		ptr->version = NS_LDAP_V1;
2584		if (strcasecmp(conf.ns_pc, NS_LDAP_VERSION_2) == 0) {
2585			ptr->version = NS_LDAP_V2;
2586		}
2587	} else if (type == NS_LDAP_CACHETTL_P) {
2588		cp = conf.ns_pc;
2589		tm = conv_time(cp);
2590		ptr->paramList[NS_LDAP_EXP_P].ns_ptype = TIMET;
2591		if (tm != 0) {
2592			tm += time(NULL);
2593		}
2594		ptr->paramList[NS_LDAP_EXP_P].ns_tm = tm;
2595	}
2596
2597	/* Everything checks out move new values into param */
2598	destroy_param(ptr, type);
2599	/* Assign new/updated value into paramList */
2600	ptr->paramList[type] = conf;
2601
2602	return (NS_LDAP_SUCCESS);
2603}
2604
2605
2606/*
2607 * Set a parameter value in the 'config' configuration structure
2608 * Lock as appropriate
2609 */
2610
2611int
2612__ns_ldap_setParam(const ParamIndexType type,
2613		const void *data, ns_ldap_error_t **error)
2614{
2615	ns_ldap_error_t		*errorp;
2616	int			ret;
2617	char			errstr[2 * MAXERROR];
2618	ns_config_t		*cfg;
2619	ns_config_t		*new_cfg;
2620
2621	/* We want to refresh only one configuration at a time */
2622	(void) mutex_lock(&ns_loadrefresh_lock);
2623	cfg = __s_api_get_default_config();
2624
2625	if (cache_server == TRUE) {
2626	    if (cfg == NULL) {
2627		__ns_ldap_default_config();
2628		cfg = __s_api_get_default_config();
2629		if (cfg == NULL) {
2630			(void) mutex_unlock(&ns_loadrefresh_lock);
2631			return (NS_LDAP_MEMORY);
2632		}
2633	    }
2634	} else {
2635		/*
2636		 * This code always return error here on client side,
2637		 * this needs to change once libsldap is used by more
2638		 * applications that need to set parameters.
2639		 */
2640		(void) snprintf(errstr, sizeof (errstr),
2641			gettext("Unable to set parameter from a client in "
2642			"__ns_ldap_setParam()"));
2643		MKERROR(LOG_WARNING, *error, NS_CONFIG_SYNTAX, strdup(errstr),
2644			NULL);
2645		if (cfg != NULL)
2646			__s_api_release_config(cfg);
2647		(void) mutex_unlock(&ns_loadrefresh_lock);
2648		return (NS_LDAP_CONFIG);
2649	}
2650
2651	/* (re)initialize configuration if necessary */
2652	if (cache_server == FALSE && timetorefresh(cfg)) {
2653		new_cfg = LoadCacheConfiguration(&errorp);
2654		__s_api_release_config(cfg);
2655		if (new_cfg == NULL) {
2656			(void) snprintf(errstr, sizeof (errstr),
2657				gettext("Unable to load configuration '%s' "
2658				"('%s')."), NSCONFIGFILE,
2659				errorp != NULL && errorp->message != NULL ?
2660				errorp->message : "");
2661			MKERROR(LOG_WARNING, *error, NS_CONFIG_NOTLOADED,
2662				strdup(errstr), NULL);
2663			if (errorp != NULL)
2664				(void) __ns_ldap_freeError(&errorp);
2665			(void) mutex_unlock(&ns_loadrefresh_lock);
2666			return (NS_LDAP_CONFIG);
2667		}
2668		set_curr_config(new_cfg);
2669		cfg = new_cfg;
2670	}
2671	(void) mutex_unlock(&ns_loadrefresh_lock);
2672
2673	/* translate input and save in the parameter list */
2674	ret = __ns_ldap_setParamValue(cfg, type, data, error);
2675
2676	__s_api_release_config(cfg);
2677
2678	return (ret);
2679}
2680
2681
2682/*
2683 * Make a copy of a parameter entry
2684 */
2685
2686static void **
2687dupParam(ns_param_t *ptr)
2688{
2689	int		count, i;
2690	void		**dupdata, *ret;
2691	int		*intptr;
2692	char		*cp, tmbuf[32];
2693	static time_t	expire = 0;
2694	ns_auth_t	*ap;
2695
2696	switch (ptr->ns_ptype) {
2697	case ARRAYAUTH:
2698	case ARRAYCRED:
2699	case SAMLIST:
2700	case SCLLIST:
2701	case SSDLIST:
2702	case SERVLIST:
2703	case ARRAYCP:
2704		count = ptr->ns_acnt;
2705		if (count == 0)
2706			return (NULL);
2707		break;
2708	case CHARPTR:
2709	case INT:
2710	case TIMET:
2711		count = 1;
2712	}
2713
2714	dupdata = (void **)calloc((count + 1), sizeof (void *));
2715	if (dupdata == NULL)
2716		return (NULL);
2717
2718	switch (ptr->ns_ptype) {
2719	case ARRAYAUTH:
2720		for (i = 0; i < count; i++) {
2721			ap = __s_api_AuthEnumtoStruct(
2722				(EnumAuthType_t)ptr->ns_pi[i]);
2723			if (ap == NULL) {
2724				free(dupdata);
2725				return (NULL);
2726			}
2727			dupdata[i] = ap;
2728		}
2729		break;
2730	case ARRAYCRED:
2731		for (i = 0; i < count; i++) {
2732			intptr = (int *)malloc(sizeof (int));
2733			if (intptr == NULL) {
2734				free(dupdata);
2735				return (NULL);
2736			}
2737			dupdata[i] = (void *)intptr;
2738			*intptr = ptr->ns_pi[i];
2739		}
2740		break;
2741	case SAMLIST:
2742	case SCLLIST:
2743	case SSDLIST:
2744	case SERVLIST:
2745	case ARRAYCP:
2746		for (i = 0; i < count; i++) {
2747			ret = (void *)strdup(ptr->ns_ppc[i]);
2748			if (ret == NULL) {
2749				free(dupdata);
2750				return (NULL);
2751			}
2752			dupdata[i] = ret;
2753		}
2754		break;
2755	case CHARPTR:
2756		if (ptr->ns_pc == NULL) {
2757			free(dupdata);
2758			return (NULL);
2759		}
2760		ret = (void *)strdup(ptr->ns_pc);
2761		if (ret == NULL) {
2762			free(dupdata);
2763			return (NULL);
2764		}
2765		dupdata[0] = ret;
2766		break;
2767	case INT:
2768		intptr = (int *)malloc(sizeof (int));
2769		if (intptr == NULL) {
2770			free(dupdata);
2771			return (NULL);
2772		}
2773		*intptr = ptr->ns_i;
2774		dupdata[0] = (void *)intptr;
2775		break;
2776	case TIMET:
2777		expire = ptr->ns_tm;
2778		tmbuf[31] = '\0';
2779		cp = lltostr((long)expire, &tmbuf[31]);
2780		ret = (void *)strdup(cp);
2781		if (ret == NULL) {
2782			free(dupdata);
2783			return (NULL);
2784		}
2785		dupdata[0] = ret;
2786		break;
2787	}
2788	return (dupdata);
2789}
2790
2791int
2792__ns_ldap_freeParam(void ***data)
2793{
2794	void	**tmp;
2795	int	i = 0;
2796
2797	if (*data == NULL)
2798		return (NS_LDAP_SUCCESS);
2799
2800	for (i = 0, tmp = *data; tmp[i] != NULL; i++)
2801		free(tmp[i]);
2802
2803	free(*data);
2804
2805	*data = NULL;
2806
2807	return (NS_LDAP_SUCCESS);
2808}
2809
2810/*
2811 * Get the internal format for a parameter value.  This
2812 * routine makes a copy of an internal param value from
2813 * the currently active parameter list and returns it.
2814 */
2815
2816int
2817__ns_ldap_getParam(const ParamIndexType Param,
2818		void ***data, ns_ldap_error_t **error)
2819{
2820	char			errstr[2 * MAXERROR];
2821	ns_ldap_error_t		*errorp;
2822	ns_default_config	*def;
2823	ns_config_t		*cfg;
2824	ns_config_t		*new_cfg;
2825
2826	if (data == NULL)
2827		return (NS_LDAP_INVALID_PARAM);
2828
2829	*data = NULL;
2830
2831	/* We want to refresh only one configuration at a time */
2832	(void) mutex_lock(&ns_loadrefresh_lock);
2833	cfg = __s_api_get_default_config();
2834
2835	/* (re)initialize configuration if necessary */
2836	if (cache_server == FALSE && timetorefresh(cfg)) {
2837		new_cfg = LoadCacheConfiguration(&errorp);
2838		__s_api_release_config(cfg);
2839		if (new_cfg == NULL) {
2840			(void) snprintf(errstr, sizeof (errstr),
2841				gettext("Unable to load configuration "
2842					"'%s' ('%s')."),
2843				NSCONFIGFILE,
2844				errorp != NULL && errorp->message != NULL ?
2845				errorp->message : "");
2846			MKERROR(LOG_WARNING, *error, NS_CONFIG_NOTLOADED,
2847				strdup(errstr), NULL);
2848			if (errorp != NULL)
2849				(void) __ns_ldap_freeError(&errorp);
2850			(void) mutex_unlock(&ns_loadrefresh_lock);
2851			return (NS_LDAP_CONFIG);
2852		}
2853		set_curr_config(new_cfg);
2854		cfg = new_cfg;
2855	}
2856	(void) mutex_unlock(&ns_loadrefresh_lock);
2857
2858	if (cfg == NULL) {
2859		(void) snprintf(errstr, sizeof (errstr),
2860		    gettext("No configuration information available."));
2861		MKERROR(LOG_ERR, *error, NS_CONFIG_NOTLOADED,
2862			strdup(errstr), NULL);
2863		return (NS_LDAP_CONFIG);
2864	}
2865
2866	if (Param == NS_LDAP_DOMAIN_P) {
2867		*data = (void **)calloc(2, sizeof (void *));
2868		if (*data == NULL) {
2869			__s_api_release_config(cfg);
2870			return (NS_LDAP_MEMORY);
2871		}
2872		(*data)[0] = (void *)strdup(cfg->domainName);
2873		if ((*data)[0] == NULL) {
2874			free(*data);
2875			__s_api_release_config(cfg);
2876			return (NS_LDAP_MEMORY);
2877		}
2878	} else if (cfg->paramList[Param].ns_ptype == NS_UNKNOWN) {
2879		/* get default */
2880		def = get_defconfig(cfg, Param);
2881		if (def != NULL)
2882			*data = dupParam(&def->defval);
2883	} else {
2884		*data = dupParam(&(cfg->paramList[Param]));
2885	}
2886	__s_api_release_config(cfg);
2887
2888	return (NS_LDAP_SUCCESS);
2889}
2890
2891/*
2892 * This routine takes a parameter in internal format and
2893 * translates it into a variety of string formats for various
2894 * outputs (doors/file/ldif).  This routine would be better
2895 * named: __ns_ldap_translateParam2String
2896 */
2897
2898char *
2899__s_api_strValue(ns_config_t *cfg, char *str,
2900			int bufsz, ParamIndexType index,
2901			ns_strfmt_t fmt)
2902{
2903	ns_default_config *def = NULL;
2904	ns_param_t	*ptr;
2905	ns_hash_t	*hptr;
2906	ns_mapping_t	*mptr;
2907	char		ibuf[14], *buf;
2908	char		abuf[64], **cpp;
2909	int		alen, count, i, sz;
2910	int		seplen = strlen(COMMASEP) + strlen(DOORLINESEP);
2911	int		first;
2912
2913	if (cfg == NULL || str == NULL)
2914		return (NULL);
2915
2916	/* NS_LDAP_EXP and TRANSPORT_SEC are not exported externally */
2917	if (index == NS_LDAP_EXP_P || index == NS_LDAP_TRANSPORT_SEC_P)
2918		return (NULL);
2919
2920	/* Return nothing if the value is the default */
2921	if (cfg->paramList[index].ns_ptype == NS_UNKNOWN)
2922		return (NULL);
2923
2924	ptr = &(cfg->paramList[index]);
2925
2926	abuf[0] = '\0';
2927	alen = 0;
2928
2929	/* get default */
2930	def = get_defconfig(cfg, index);
2931	if (def == NULL)
2932		return (NULL);
2933
2934	switch (fmt) {
2935	case NS_DOOR_FMT:
2936		(void) strlcpy(abuf, def->name, sizeof (abuf));
2937		(void) strlcat(abuf, EQUALSEP, sizeof (abuf));
2938		break;
2939	case NS_FILE_FMT:
2940		(void) strlcpy(abuf, def->name, sizeof (abuf));
2941		(void) strlcat(abuf, EQUSPSEP, sizeof (abuf));
2942		break;
2943	case NS_LDIF_FMT:
2944		/* If no LDIF attr exists ignore the entry */
2945		if (def->profile_name == NULL)
2946			return (NULL);
2947		(void) strlcpy(abuf, def->profile_name, sizeof (abuf));
2948		(void) strlcat(abuf, COLSPSEP, sizeof (abuf));
2949		break;
2950	default:
2951		break;
2952	}
2953	alen = strlen(abuf);
2954	if (alen > bufsz)
2955		return (NULL);
2956
2957	buf = str;
2958	(void) strlcpy(buf, abuf, bufsz);
2959
2960	switch (ptr->ns_ptype) {
2961	case ARRAYAUTH:
2962		count = ptr->ns_acnt;
2963		sz = 0;
2964		for (i = 0; i < count; i++) {
2965			sz += strlen(__s_get_auth_name(cfg,
2966				(AuthType_t)(ptr->ns_pi[i]))) + seplen;
2967		}
2968		sz = sz + alen + 1;
2969		if (sz <= bufsz) {
2970			buf = str;
2971		} else {
2972			buf = (char *)calloc(sz, sizeof (char));
2973			if (buf == NULL)
2974				return (NULL);
2975			(void) strcpy(buf, abuf);
2976		}
2977		for (i = 0; i < count; i++) {
2978			(void) strcat(buf,
2979				__s_get_auth_name(cfg,
2980				(AuthType_t)(ptr->ns_pi[i])));
2981			if (i != count-1) {
2982				if (cfg->version == NS_LDAP_V1)
2983					(void) strcat(buf, COMMASEP);
2984				else
2985					(void) strcat(buf, SEMISEP);
2986			}
2987		}
2988		break;
2989	case ARRAYCRED:
2990		count = ptr->ns_acnt;
2991		sz = 0;
2992		for (i = 0; i < count; i++) {
2993			sz += strlen(__s_get_credlvl_name(cfg,
2994				(CredLevel_t)ptr->ns_pi[i])) + seplen;
2995		}
2996		sz = sz + alen + 1;
2997		if (sz <= bufsz) {
2998			buf = str;
2999		} else {
3000			buf = (char *)calloc(sz, sizeof (char));
3001			if (buf == NULL)
3002				return (NULL);
3003			(void) strcpy(buf, abuf);
3004		}
3005		for (i = 0; i < count; i++) {
3006			(void) strcat(buf,
3007				__s_get_credlvl_name(cfg,
3008				(CredLevel_t)ptr->ns_pi[i]));
3009			if (i != count-1) {
3010				(void) strcat(buf, SPACESEP);
3011			}
3012		}
3013		break;
3014	case SAMLIST:
3015	case SCLLIST:
3016	case SSDLIST:
3017		count = ptr->ns_acnt;
3018		sz = 0;
3019		for (i = 0; i < count; i++) {
3020			sz += strlen(ptr->ns_ppc[i]) + seplen;
3021		}
3022		sz = sz + alen + 1;
3023		/*
3024		 * We need to allocate buffer depending on the 'fmt' and
3025		 * on the number of ns_ptype's present(count) as we add
3026		 * name' or 'profile_name' and DOORLINESEP or new line
3027		 * char to the buffer - see below.
3028		 */
3029		switch (fmt) {
3030		case NS_LDIF_FMT:
3031			sz += count * (strlen(def->profile_name)
3032				+ strlen(COLSPSEP) + strlen("\n"));
3033			break;
3034		case NS_FILE_FMT:
3035			sz += count * (strlen(def->name)
3036				+ strlen(EQUALSEP) + strlen("\n"));
3037			break;
3038		case NS_DOOR_FMT:
3039			sz += count * (strlen(def->name)
3040				+ strlen(EQUALSEP) + strlen(DOORLINESEP));
3041			break;
3042		}
3043		if (sz <= bufsz) {
3044			buf = str;
3045		} else {
3046			buf = (char *)calloc(sz, sizeof (char));
3047			if (buf == NULL)
3048				return (NULL);
3049			(void) strcpy(buf, abuf);
3050		}
3051		for (i = 0; i < count; i++) {
3052			(void) strcat(buf, ptr->ns_ppc[i]);
3053			if (i != count-1) {
3054				/* Separate items */
3055				switch (fmt) {
3056				case NS_DOOR_FMT:
3057					(void) strcat(buf, DOORLINESEP);
3058					(void) strcat(buf, def->name);
3059					(void) strcat(buf, EQUALSEP);
3060					break;
3061				case NS_FILE_FMT:
3062					(void) strcat(buf, "\n");
3063					(void) strcat(buf, def->name);
3064					(void) strcat(buf, EQUSPSEP);
3065					break;
3066				case NS_LDIF_FMT:
3067					(void) strcat(buf, "\n");
3068					(void) strcat(buf, def->profile_name);
3069					(void) strcat(buf, COLSPSEP);
3070					break;
3071				}
3072			}
3073		}
3074		break;
3075	case ARRAYCP:
3076		count = ptr->ns_acnt;
3077		sz = 0;
3078		for (i = 0; i < count; i++) {
3079			sz += strlen(ptr->ns_ppc[i]) + seplen;
3080		}
3081		sz = sz + alen + 1;
3082		if (sz <= bufsz) {
3083			buf = str;
3084		} else {
3085			buf = (char *)calloc(sz, sizeof (char));
3086			if (buf == NULL)
3087				return (NULL);
3088			(void) strcpy(buf, abuf);
3089		}
3090		for (i = 0; i < count; i++) {
3091			(void) strcat(buf, ptr->ns_ppc[i]);
3092			if (i != count-1) {
3093				(void) strcat(buf, COMMASEP);
3094			}
3095		}
3096		break;
3097	case SERVLIST:
3098		count = ptr->ns_acnt;
3099		sz = 0;
3100		for (i = 0; i < count; i++) {
3101			sz += strlen(ptr->ns_ppc[i]) + seplen;
3102		}
3103		sz = sz + alen + 1;
3104		if (sz <= bufsz) {
3105			buf = str;
3106		} else {
3107			buf = (char *)calloc(sz, sizeof (char));
3108			if (buf == NULL)
3109				return (NULL);
3110			(void) strcpy(buf, abuf);
3111		}
3112		for (i = 0; i < count; i++) {
3113			(void) strcat(buf, ptr->ns_ppc[i]);
3114			if (i != count-1) {
3115				if (fmt == NS_LDIF_FMT)
3116					(void) strcat(buf, SPACESEP);
3117				else
3118					(void) strcat(buf, COMMASEP);
3119			}
3120		}
3121		break;
3122	case CHARPTR:
3123		if (ptr->ns_pc == NULL)
3124			break;
3125		sz = strlen(ptr->ns_pc) + alen + 1;
3126		if (sz > bufsz) {
3127			buf = (char *)calloc(sz, sizeof (char));
3128			if (buf == NULL)
3129				return (NULL);
3130			(void) strcpy(buf, abuf);
3131		}
3132		(void) strcat(buf, ptr->ns_pc);
3133		break;
3134	case INT:
3135		switch (def->index) {
3136		case NS_LDAP_PREF_ONLY_P:
3137			(void) strcat(buf,
3138				__s_get_pref_name((PrefOnly_t)ptr->ns_i));
3139			break;
3140		case NS_LDAP_SEARCH_REF_P:
3141			(void) strcat(buf,
3142				__s_get_searchref_name(cfg,
3143				(SearchRef_t)ptr->ns_i));
3144			break;
3145		case NS_LDAP_SEARCH_SCOPE_P:
3146			(void) strcat(buf,
3147				__s_get_scope_name(cfg,
3148				(ScopeType_t)ptr->ns_i));
3149			break;
3150		default:
3151			(void) snprintf(ibuf, sizeof (ibuf),
3152				"%d", ptr->ns_i);
3153			(void) strcat(buf, ibuf);
3154			break;
3155		}
3156		break;
3157	case ATTRMAP:
3158		buf[0] = '\0';
3159		first = 1;
3160		for (hptr = cfg->llHead; hptr; hptr = hptr->h_llnext) {
3161			if (hptr->h_type != NS_HASH_AMAP) {
3162				continue;
3163			}
3164			if (!first) {
3165				if (fmt == NS_DOOR_FMT)
3166					(void) strcat(buf, DOORLINESEP);
3167				else
3168					(void) strcat(buf, "\n");
3169			}
3170			mptr = hptr->h_map;
3171			(void) strcat(buf, abuf);
3172			(void) strcat(buf, mptr->service);
3173			(void) strcat(buf, COLONSEP);
3174			(void) strcat(buf, mptr->orig);
3175			(void) strcat(buf, EQUALSEP);
3176			for (cpp = mptr->map; cpp && *cpp; cpp++) {
3177				if (cpp != mptr->map)
3178					(void) strcat(buf, SPACESEP);
3179				(void) strcat(buf, *cpp);
3180			}
3181			first = 0;
3182		}
3183		break;
3184	case OBJMAP:
3185		buf[0] = '\0';
3186		first = 1;
3187		for (hptr = cfg->llHead; hptr; hptr = hptr->h_llnext) {
3188			if (hptr->h_type != NS_HASH_OMAP) {
3189				continue;
3190			}
3191			if (!first) {
3192				if (fmt == NS_DOOR_FMT)
3193					(void) strcat(buf, DOORLINESEP);
3194				else
3195					(void) strcat(buf, "\n");
3196			}
3197			mptr = hptr->h_map;
3198			(void) strcat(buf, abuf);
3199			(void) strcat(buf, mptr->service);
3200			(void) strcat(buf, COLONSEP);
3201			(void) strcat(buf, mptr->orig);
3202			(void) strcat(buf, EQUALSEP);
3203			for (cpp = mptr->map; cpp && *cpp; cpp++) {
3204				if (cpp != mptr->map)
3205					(void) strcat(buf, SPACESEP);
3206				(void) strcat(buf, *cpp);
3207			}
3208			first = 0;
3209		}
3210		break;
3211	}
3212	return (buf);
3213}
3214
3215static int
3216__door_getldapconfig(char **buffer, int *buflen, ns_ldap_error_t **error)
3217{
3218	typedef union {
3219		ldap_data_t	s_d;
3220		char		s_b[DOORBUFFERSIZE];
3221	} space_t;
3222	space_t	*space;
3223
3224	ldap_data_t	*sptr;
3225	int		ndata;
3226	int		adata;
3227	char		errstr[MAXERROR];
3228	char		*domainname;
3229
3230	domainname = __getdomainname();
3231	if (domainname == NULL || buffer == NULL || buflen == NULL ||
3232	    (strlen(domainname) >= (sizeof (space_t)
3233		- sizeof (space->s_d.ldap_call.ldap_callnumber)))) {
3234		return (NS_LDAP_OP_FAILED);
3235	}
3236
3237	space = (space_t *)calloc(1, sizeof (space_t));
3238	if (space == NULL)
3239		return (NS_LDAP_OP_FAILED);
3240
3241	adata = (sizeof (ldap_call_t) + strlen(domainname) +1);
3242	ndata = sizeof (space_t);
3243	space->s_d.ldap_call.ldap_callnumber = GETLDAPCONFIGV1;
3244	(void) strcpy(space->s_d.ldap_call.ldap_u.domainname, domainname);
3245	free(domainname);
3246	domainname = NULL;
3247	sptr = &space->s_d;
3248
3249	switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) {
3250	case SUCCESS:
3251		break;
3252	case NOTFOUND:
3253		(void) snprintf(errstr, sizeof (errstr),
3254			gettext("Door call to "
3255			"ldap_cachemgr failed - error: %d."),
3256			space->s_d.ldap_ret.ldap_errno);
3257		MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
3258			strdup(errstr), NULL);
3259		free(space);
3260		return (NS_LDAP_OP_FAILED);
3261	default:
3262		free(space);
3263		return (NS_LDAP_OP_FAILED);
3264	}
3265
3266	/* copy info from door call to buffer here */
3267	*buflen = strlen(space->s_d.ldap_ret.ldap_u.config) + 1;
3268	*buffer = calloc(*buflen, sizeof (char));
3269	if (*buffer == NULL) {
3270		free(space);
3271		return (NS_LDAP_MEMORY);
3272	}
3273	(void) strcpy(*buffer, space->s_d.ldap_ret.ldap_u.config);
3274
3275	if (sptr != &space->s_d) {
3276		(void) munmap((char *)sptr, ndata);
3277	} else {
3278		free(space);
3279		space = NULL;
3280	}
3281	*error = NULL;
3282
3283	return (NS_LDAP_SUCCESS);
3284}
3285
3286/*
3287 * SetDoorInfo parses ldapcachemgr configuration information
3288 * and verifies that the profile is version 1 or version 2 based.
3289 * version 2 profiles must have a version number as the first profile
3290 * attribute in the configuration.
3291 */
3292static ns_config_t *
3293SetDoorInfo(char *buffer, ns_ldap_error_t **errorp)
3294{
3295	ns_config_t	*ptr;
3296	char		errstr[MAXERROR], errbuf[MAXERROR];
3297	char		*name, *value, valbuf[BUFSIZE];
3298	char		*strptr;
3299	char		*rest;
3300	char		*bufptr = buffer;
3301	ParamIndexType	i;
3302	int		ret;
3303	int		first = 1;
3304	int		errfnd = 0;
3305
3306	if (errorp == NULL)
3307		return (NULL);
3308	*errorp = NULL;
3309
3310	ptr = __s_api_create_config();
3311	if (ptr == NULL) {
3312		return (NULL);
3313	}
3314
3315	strptr = (char *)strtok_r(bufptr, DOORLINESEP, &rest);
3316	for (; ; ) {
3317		if (strptr == NULL)
3318			break;
3319		(void) strlcpy(valbuf, strptr, sizeof (valbuf));
3320		__s_api_split_key_value(valbuf, &name, &value);
3321		/* Use get_versiontype and check for V1 vs V2 prototypes */
3322		if (__s_api_get_versiontype(ptr, name, &i) < 0) {
3323			(void) snprintf(errstr, sizeof (errstr),
3324					"%s (%s)\n",
3325					gettext("Illegal profile entry "
3326					"line in configuration."),
3327					name);
3328			errfnd++;
3329		/* Write verify routines and get rid of verify_value here */
3330		} else if (verify_value(ptr, name,
3331					value, errbuf) != NS_SUCCESS) {
3332			(void) snprintf(errstr, sizeof (errstr),
3333				gettext("%s\n"), errbuf);
3334			errfnd++;
3335		} else if (!first && i == NS_LDAP_FILE_VERSION_P) {
3336			(void) snprintf(errstr, sizeof (errstr),
3337					gettext("Illegal NS_LDAP_FILE_VERSION "
3338					"line in configuration.\n"));
3339			errfnd++;
3340		}
3341		if (errfnd) {
3342			MKERROR(LOG_ERR, *errorp, NS_CONFIG_SYNTAX,
3343				strdup(errstr), NULL);
3344		} else {
3345			ret = set_default_value(ptr, name, value, errorp);
3346		}
3347		if (errfnd || ret != NS_SUCCESS) {
3348			__s_api_destroy_config(ptr);
3349			return (NULL);
3350		}
3351		first = 0;
3352
3353		strptr = (char *)strtok_r(NULL, DOORLINESEP, &rest);
3354	}
3355
3356	if (__s_api_crosscheck(ptr, errstr, B_TRUE) != NS_SUCCESS) {
3357		__s_api_destroy_config(ptr);
3358		MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX, strdup(errstr),
3359			NULL);
3360		return (NULL);
3361	}
3362
3363	return (ptr);
3364}
3365
3366static ns_config_t *
3367LoadCacheConfiguration(ns_ldap_error_t **error)
3368{
3369	char		*buffer = NULL;
3370	int		buflen = 0;
3371	int		ret;
3372	ns_config_t	*cfg;
3373
3374	*error = NULL;
3375	ret = __door_getldapconfig(&buffer, &buflen, error);
3376
3377	if (ret != NS_LDAP_SUCCESS) {
3378		if (*error != NULL && (*error)->message != NULL)
3379			syslog(LOG_WARNING, "libsldap: %s", (*error)->message);
3380		return (NULL);
3381	}
3382
3383	/* now convert from door format */
3384	cfg = SetDoorInfo(buffer, error);
3385	free(buffer);
3386
3387	if (cfg == NULL && *error != NULL && (*error)->message != NULL)
3388		syslog(LOG_WARNING, "libsldap: %s", (*error)->message);
3389	return (cfg);
3390}
3391
3392/*
3393 * converts the time string into seconds.  The time string can be specified
3394 * using one of the following time units:
3395 * 	#s (# of seconds)
3396 *	#m (# of minutes)
3397 *	#h (# of hours)
3398 *	#d (# of days)
3399 *	#w (# of weeks)
3400 * NOTE: you can only specify one the above.  No combination of the above
3401 * units is allowed.  If no unit specified, it will default to "seconds".
3402 */
3403static time_t
3404conv_time(char *s)
3405{
3406	time_t t;
3407	char c;
3408	int l, m;
3409	long tot;
3410
3411	l = strlen(s);
3412	if (l == 0)
3413		return (0);
3414	c = s[--l];
3415	m = 0;
3416	switch (c) {
3417	case 'w': /* weeks */
3418		m = 604800;
3419		break;
3420	case 'd': /* days */
3421		m = 86400;
3422		break;
3423	case 'h': /* hours */
3424		m = 3600;
3425		break;
3426	case 'm': /* minutes */
3427		m = 60;
3428		break;
3429	case 's': /* seconds */
3430		m = 1;
3431		break;
3432	/* the default case is set to "second" */
3433	}
3434	if (m != 0)
3435		s[l] = '\0';
3436	else
3437		m = 1;
3438	errno = 0;
3439	tot = atol(s);
3440	if ((0 == tot) && (EINVAL == errno))
3441		return (0);
3442	if (((LONG_MAX == tot) || (LONG_MIN == tot)) && (EINVAL == errno))
3443		return (0);
3444
3445	tot = tot * m;
3446	t = (time_t)tot;
3447	return (t);
3448}
3449
3450
3451ns_auth_t *
3452__s_api_AuthEnumtoStruct(const EnumAuthType_t i)
3453{
3454	ns_auth_t *ap;
3455
3456	ap = (ns_auth_t *)calloc(1, sizeof (ns_auth_t));
3457	if (ap == NULL)
3458		return (NULL);
3459	switch (i) {
3460		case NS_LDAP_EA_NONE:
3461			break;
3462		case NS_LDAP_EA_SIMPLE:
3463			ap->type = NS_LDAP_AUTH_SIMPLE;
3464			break;
3465		case NS_LDAP_EA_SASL_CRAM_MD5:
3466			ap->type = NS_LDAP_AUTH_SASL;
3467			ap->saslmech = NS_LDAP_SASL_CRAM_MD5;
3468			break;
3469		case NS_LDAP_EA_SASL_DIGEST_MD5:
3470			ap->type = NS_LDAP_AUTH_SASL;
3471			ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
3472			break;
3473		case NS_LDAP_EA_SASL_DIGEST_MD5_INT:
3474			ap->type = NS_LDAP_AUTH_SASL;
3475			ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
3476			ap->saslopt = NS_LDAP_SASLOPT_INT;
3477			break;
3478		case NS_LDAP_EA_SASL_DIGEST_MD5_CONF:
3479			ap->type = NS_LDAP_AUTH_SASL;
3480			ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
3481			ap->saslopt = NS_LDAP_SASLOPT_PRIV;
3482			break;
3483		case NS_LDAP_EA_SASL_EXTERNAL:
3484			ap->type = NS_LDAP_AUTH_SASL;
3485			ap->saslmech = NS_LDAP_SASL_EXTERNAL;
3486			break;
3487		case NS_LDAP_EA_SASL_GSSAPI:
3488			ap->type = NS_LDAP_AUTH_SASL;
3489			ap->saslmech = NS_LDAP_SASL_GSSAPI;
3490			ap->saslopt = NS_LDAP_SASLOPT_INT |
3491					NS_LDAP_SASLOPT_PRIV;
3492			break;
3493		case NS_LDAP_EA_TLS_NONE:
3494			ap->type = NS_LDAP_AUTH_TLS;
3495			ap->tlstype = NS_LDAP_TLS_NONE;
3496			break;
3497		case NS_LDAP_EA_TLS_SIMPLE:
3498			ap->type = NS_LDAP_AUTH_TLS;
3499			ap->tlstype = NS_LDAP_TLS_SIMPLE;
3500			break;
3501		case NS_LDAP_EA_TLS_SASL_CRAM_MD5:
3502			ap->type = NS_LDAP_AUTH_TLS;
3503			ap->tlstype = NS_LDAP_TLS_SASL;
3504			ap->saslmech = NS_LDAP_SASL_CRAM_MD5;
3505			break;
3506		case NS_LDAP_EA_TLS_SASL_DIGEST_MD5:
3507			ap->type = NS_LDAP_AUTH_TLS;
3508			ap->tlstype = NS_LDAP_TLS_SASL;
3509			ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
3510			break;
3511		case NS_LDAP_EA_TLS_SASL_DIGEST_MD5_INT:
3512			ap->type = NS_LDAP_AUTH_TLS;
3513			ap->tlstype = NS_LDAP_TLS_SASL;
3514			ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
3515			ap->saslopt = NS_LDAP_SASLOPT_INT;
3516			break;
3517		case NS_LDAP_EA_TLS_SASL_DIGEST_MD5_CONF:
3518			ap->type = NS_LDAP_AUTH_TLS;
3519			ap->tlstype = NS_LDAP_TLS_SASL;
3520			ap->saslmech = NS_LDAP_SASL_DIGEST_MD5;
3521			ap->saslopt = NS_LDAP_SASLOPT_PRIV;
3522			break;
3523		case NS_LDAP_EA_TLS_SASL_EXTERNAL:
3524			ap->type = NS_LDAP_AUTH_TLS;
3525			ap->tlstype = NS_LDAP_TLS_SASL;
3526			ap->saslmech = NS_LDAP_SASL_EXTERNAL;
3527			break;
3528		default:
3529			/* should never get here */
3530			free(ap);
3531			return (NULL);
3532	}
3533	return (ap);
3534}
3535
3536
3537/*
3538 * Parameter Index Type validation routines
3539 */
3540
3541/* Validate a positive integer */
3542/* Size of errbuf needs to be MAXERROR */
3543/* ARGSUSED */
3544static int
3545__s_val_postime(ParamIndexType i, ns_default_config *def,
3546		ns_param_t *param, char *errbuf)
3547{
3548	char	*cp;
3549	long	tot;
3550
3551	if (param && param->ns_ptype == CHARPTR && param->ns_pc) {
3552		for (cp = param->ns_pc; cp && *cp; cp++) {
3553			if (*cp >= '0' && *cp <= '9')
3554				continue;
3555			switch (*cp) {
3556			case 'w': /* weeks */
3557			case 'd': /* days */
3558			case 'h': /* hours */
3559			case 'm': /* minutes */
3560			case 's': /* seconds */
3561				if (*(cp+1) == '\0') {
3562					break;
3563				}
3564			default:
3565				(void) strcpy(errbuf, "Illegal time value");
3566				return (NS_PARSE_ERR);
3567			}
3568		}
3569		/* Valid form:  [0-9][0-9]*[wdhms]* */
3570		tot = atol(param->ns_pc);	/* check overflow */
3571		if (tot >= 0)
3572			return (NS_SUCCESS);
3573	}
3574	(void) snprintf(errbuf, MAXERROR,
3575			gettext("Illegal time value in %s"), def->name);
3576	return (NS_PARSE_ERR);
3577}
3578
3579
3580/* Validate the Base DN */
3581/* It can be empty (RootDSE request) or needs to have an '=' */
3582/* Size of errbuf needs to be MAXERROR */
3583/* ARGSUSED */
3584static int
3585__s_val_basedn(ParamIndexType i, ns_default_config *def,
3586		ns_param_t *param, char *errbuf)
3587{
3588	if (param && param->ns_ptype == CHARPTR &&
3589	    i == NS_LDAP_SEARCH_BASEDN_P &&
3590		((param->ns_pc == NULL) || 		/* empty */
3591		(*(param->ns_pc) == '\0') ||		/* empty */
3592		(strchr(param->ns_pc, '=') != NULL)))	/* '=' */
3593	{
3594		return (NS_SUCCESS);
3595	}
3596	(void) snprintf(errbuf, MAXERROR,
3597		gettext("Non-existent or invalid DN in %s"),
3598		def->name);
3599	return (NS_PARSE_ERR);
3600}
3601
3602
3603/* Validate the serverList */
3604/* For each server in list, check if valid IP or hostname */
3605/* Size of errbuf needs to be MAXERROR */
3606/* ARGSUSED */
3607static int
3608__s_val_serverList(ParamIndexType i, ns_default_config *def,
3609		ns_param_t *param, char *errbuf)
3610{
3611	for (i = 0; i < param->ns_acnt; i++) {
3612		if ((__s_api_isipv4(param->ns_ppc[i])) ||
3613			(__s_api_isipv6(param->ns_ppc[i])) ||
3614			(__s_api_ishost(param->ns_ppc[i]))) {
3615			continue;
3616		}
3617		/* err */
3618		(void) snprintf(errbuf, MAXERROR,
3619			gettext("Invalid server (%s) in %s"),
3620			param->ns_ppc[i], def->name);
3621		return (NS_PARSE_ERR);
3622	}
3623
3624	return (NS_SUCCESS);
3625}
3626
3627
3628/* Check for a BINDDN */
3629/* It can not be empty and needs to have an '=' */
3630/* Size of errbuf needs to be MAXERROR */
3631/* ARGSUSED */
3632static int
3633__s_val_binddn(ParamIndexType i, ns_default_config *def,
3634		ns_param_t *param, char *errbuf)
3635{
3636	if (param && param->ns_ptype == CHARPTR &&
3637	    i == NS_LDAP_BINDDN_P &&
3638		((param->ns_pc == NULL) ||
3639		((*(param->ns_pc) != '\0') &&
3640		(strchr(param->ns_pc, '=') != NULL)))) {
3641		return (NS_SUCCESS);
3642	}
3643	(void) snprintf(errbuf, MAXERROR,
3644		gettext("NULL or invalid proxy bind DN"));
3645	return (NS_PARSE_ERR);
3646}
3647
3648
3649/* Check for a BINDPASSWD */
3650/* The string can not be NULL or empty */
3651/* Size of errbuf needs to be MAXERROR */
3652/* ARGSUSED */
3653static int
3654__s_val_bindpw(ParamIndexType i, ns_default_config *def,
3655		ns_param_t *param, char *errbuf)
3656{
3657	if (param && param->ns_ptype == CHARPTR &&
3658	    i == NS_LDAP_BINDPASSWD_P &&
3659		((param->ns_pc == NULL) ||
3660		(*(param->ns_pc) != '\0'))) {
3661		return (NS_SUCCESS);
3662	}
3663	(void) snprintf(errbuf, MAXERROR,
3664		gettext("NULL proxy bind password"));
3665	return (NS_PARSE_ERR);
3666}
3667
3668/*
3669 * __s_get_hostcertpath returns either the configured host certificate path
3670 * or, if none, the default host certificate path (/var/ldap). Note that this
3671 * does not use __ns_ldap_getParam because it may be called during connection
3672 * setup. This can fail due to insufficient memory.
3673 */
3674
3675char *
3676__s_get_hostcertpath(void)
3677{
3678	ns_config_t		*cfg;
3679	ns_param_t		*param;
3680	char			*ret = NULL;
3681
3682	cfg = __s_api_get_default_config();
3683	if (cfg != NULL) {
3684		param = &cfg->paramList[NS_LDAP_HOST_CERTPATH_P];
3685		if (param->ns_ptype == CHARPTR)
3686			ret = strdup(param->ns_pc);
3687		__s_api_release_config(cfg);
3688	}
3689	if (ret == NULL)
3690		ret = strdup(NSLDAPDIRECTORY);
3691	return (ret);
3692}
3693
3694static void
3695_free_config()
3696{
3697	if (current_config != NULL)
3698		destroy_config(current_config);
3699
3700	current_config = NULL;
3701}
3702