xref: /titanic_51/usr/src/lib/libsldap/common/ns_config.c (revision ccbf80fa3b6bf6b986dca9037e5ad9d6c9f9fa65)
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 
61 static mutex_t		ns_parse_lock = DEFAULTMUTEX;
62 static mutex_t		ns_loadrefresh_lock = DEFAULTMUTEX;
63 static ns_config_t	*current_config = NULL;
64 
65 static int		cache_server = FALSE;
66 
67 /*
68  * Parameter Index Type validation routines
69  */
70 static int
71 __s_val_postime(ParamIndexType i, ns_default_config *def,
72 		ns_param_t *param, char *errbuf);
73 static int
74 __s_val_basedn(ParamIndexType i, ns_default_config *def,
75 		ns_param_t *param, char *errbuf);
76 
77 static int
78 __s_val_binddn(ParamIndexType i, ns_default_config *def,
79 		ns_param_t *param, char *errbuf);
80 
81 static int
82 __s_val_bindpw(ParamIndexType i, ns_default_config *def,
83 		ns_param_t *param, char *errbuf);
84 
85 static 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 
93 static ns_parse_status
94 verify_value(ns_config_t *cfg, char *name, char *value, char *errstr);
95 
96 static int
97 set_default_value(ns_config_t *configptr, char *name, char *value,
98 	ns_ldap_error_t **error);
99 
100 static void
101 set_curr_config(ns_config_t *ptr);
102 
103 static int
104 __door_getldapconfig(char **buffer, int *buflen, ns_ldap_error_t **error);
105 
106 static ns_config_t *
107 SetDoorInfo(char *buffer, ns_ldap_error_t **errorp);
108 
109 static boolean_t
110 timetorefresh(ns_config_t *cfg);
111 
112 static ns_config_t *
113 LoadCacheConfiguration(ns_ldap_error_t **error);
114 
115 static void **
116 dupParam(ns_param_t *ptr);
117 
118 static time_t
119 conv_time(char *s);
120 
121 /*
122  * Structures used in enum <-> string mapping routines
123  */
124 
125 static 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 
132 static 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 */
156 static 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 */
162 static 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 
169 static 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 
175 static ns_enum_map ns_ref_enum_v2[] = {
176 	{ ENUM2INT(NS_LDAP_FOLLOWREF), "TRUE" },
177 	{ ENUM2INT(NS_LDAP_NOREF), "FALSE" },
178 	{ -1, NULL },
179 };
180 
181 static 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 
188 static 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 
195 static 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 
201 static int	ns_def_auth_v1[] = {
202 	ENUM2INT(NS_LDAP_EA_NONE),
203 	0
204 };
205 
206 static int	ns_def_auth_v2[] = {
207 	ENUM2INT(NS_LDAP_EA_NONE),
208 	0
209 };
210 
211 static int	ns_def_cred_v1[] = {
212 	ENUM2INT(NS_LDAP_CRED_PROXY),
213 	0
214 };
215 
216 static 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  */
249 static 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 
512 static 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 
531 void
532 __ns_ldap_setServer(int set)
533 {
534 	cache_server = set;
535 }
536 
537 static boolean_t
538 timetorefresh(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 
554 int
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 
624 char *
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 
643 char *
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 
661 char *
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 
680 char *
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 
693 char *
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 
711 static 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 
727 static void
728 destroy_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 
783 static void
784 destroy_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 
815 void
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 
832 static ns_config_t *
833 get_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 
858 static void
859 set_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 
877 void
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  */
894 void
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 
906 ns_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 
926 ns_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 
938 static char *
939 stripdup(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 
963 static boolean_t
964 has_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 */
997 ns_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 
1210 int
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 
1229 int
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 
1237 int
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 
1259 int
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 
1275 int
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 
1288 const 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 
1304 static ns_default_config *
1305 get_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 
1321 static int
1322 set_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 
1360 void
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 
1379 ns_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  */
1410 static ns_parse_status
1411 verify_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 
1522 void
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  */
1547 int
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 
2611 int
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 
2686 static void **
2687 dupParam(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 
2791 int
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 
2816 int
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 
2898 char *
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 
3215 static 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  */
3292 static ns_config_t *
3293 SetDoorInfo(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 
3366 static ns_config_t *
3367 LoadCacheConfiguration(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  */
3403 static time_t
3404 conv_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 
3451 ns_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 */
3544 static 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 */
3584 static 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 */
3607 static 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 */
3632 static 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 */
3653 static 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 
3675 char *
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 
3694 static void
3695 _free_config()
3696 {
3697 	if (current_config != NULL)
3698 		destroy_config(current_config);
3699 
3700 	current_config = NULL;
3701 }
3702