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