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