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