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