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