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