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