xref: /illumos-gate/usr/src/lib/libsldap/common/ns_confmgr.c (revision d4039345c8fe6e54a31d17d91e86e393fdcf401b)
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 /* libsldap - cachemgr side configuration components */
27 
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <stdlib.h>
31 #include <libintl.h>
32 #include <string.h>
33 #include <ctype.h>
34 
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <syslog.h>
39 #include <locale.h>
40 #include <errno.h>
41 #include <sys/time.h>
42 
43 #include "ns_sldap.h"
44 #include "ns_internal.h"
45 #include "ns_cache_door.h"
46 
47 #define	ALWAYS		1
48 
49 
50 /*
51  * **************************************************************
52  * Configuration File Routines
53  * **************************************************************
54  */
55 
56 
57 /* Size of the errstr buffer needs to be MAXERROR */
58 static int
59 read_line(FILE *fp, char *buffer, int buflen, char *errstr)
60 {
61 	int	linelen;
62 	char	c;
63 
64 	*errstr = '\0';
65 
66 	for (linelen = 0; linelen < buflen; ) {
67 		c = getc(fp);
68 		if (c == EOF)
69 			break;
70 		switch (c) {
71 		case '\n':
72 			if (linelen > 0 && buffer[linelen - 1] == '\\') {
73 				/* Continuation line found */
74 				--linelen;
75 			} else {
76 				/* end of line found */
77 				buffer[linelen] = '\0';
78 				return (linelen);
79 			}
80 			break;
81 		default:
82 			buffer[linelen++] = c;
83 		}
84 	}
85 
86 	if (linelen >= buflen) {
87 		(void) snprintf(errstr, MAXERROR,
88 		    gettext("Buffer overflow, line too long."));
89 		return (-2);
90 	} else if (linelen > 0 && buffer[linelen - 1] == '\\') {
91 		(void) snprintf(errstr, MAXERROR,
92 		    gettext("Unterminated continuation line."));
93 		return (-2);
94 	} else {
95 		/* end of file */
96 		buffer[linelen] = '\0';
97 	}
98 	return (linelen > 0 ? linelen : -1);
99 }
100 
101 
102 static ns_parse_status
103 read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
104 {
105 	ParamIndexType	i = 0;
106 	char		errstr[MAXERROR];
107 	char		buffer[BUFSIZE], *name, *value;
108 	int		emptyfile, lineno;
109 	FILE		*fp;
110 	int		ret;
111 	int		linelen;
112 	char		*file;
113 	int		first = 1;
114 
115 
116 	if (cred_file) {
117 		file = NSCREDFILE;
118 	} else {
119 		file = NSCONFIGFILE;
120 	}
121 	fp = fopen(file, "rF");
122 	if (fp == NULL) {
123 		(void) snprintf(errstr, sizeof (errstr),
124 		    gettext("Unable to open filename '%s' "
125 		    "for reading (errno=%d)."), file, errno);
126 		MKERROR(LOG_ERR, *error, NS_CONFIG_FILE, strdup(errstr),
127 		    NS_PARSE_ERR);
128 		return (NS_NOTFOUND);
129 	}
130 
131 	emptyfile = 1;
132 	lineno = 0;
133 	for (; ; ) {
134 		if ((linelen = read_line(fp, buffer, sizeof (buffer),
135 		    errstr)) < 0)
136 			/* End of file */
137 			break;
138 		lineno++;
139 		if (linelen == 0)
140 			continue;
141 		/* get rid of comment lines */
142 		if (buffer[0] == '#')
143 			continue;
144 		emptyfile = 0;
145 		name = NULL;
146 		value = NULL;
147 		__s_api_split_key_value(buffer, &name, &value);
148 		if (name == NULL || value == NULL) {
149 			(void) snprintf(errstr, sizeof (errstr),
150 			    gettext("Missing Name or Value on line %d."),
151 			    lineno);
152 			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
153 			    strdup(errstr), NS_PARSE_ERR);
154 			(void) fclose(fp);
155 			return (NS_PARSE_ERR);
156 		}
157 		if (__s_api_get_versiontype(ptr, name, &i) != 0) {
158 			(void) snprintf(errstr, sizeof (errstr),
159 			    gettext("Illegal profile type on line %d."),
160 			    lineno);
161 			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
162 			    strdup(errstr), NS_PARSE_ERR);
163 			(void) fclose(fp);
164 			return (NS_PARSE_ERR);
165 		}
166 		if (!first && i == NS_LDAP_FILE_VERSION_P) {
167 			(void) snprintf(errstr, sizeof (errstr),
168 			    gettext("Illegal NS_LDAP_FILE_VERSION "
169 			    "on line %d."), lineno);
170 			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
171 			    strdup(errstr), NS_PARSE_ERR);
172 			(void) fclose(fp);
173 			return (NS_PARSE_ERR);
174 		}
175 		first = 0;
176 		switch (__s_api_get_configtype(i)) {
177 		case SERVERCONFIG:
178 		case CLIENTCONFIG:
179 			if (cred_file == 0) {
180 				ret = __ns_ldap_setParamValue(ptr, i, value,
181 				    error);
182 				if (ret != NS_SUCCESS) {
183 					(void) fclose(fp);
184 					return (ret);
185 				}
186 			} else if (i != NS_LDAP_FILE_VERSION_P) {
187 				(void) snprintf(errstr, sizeof (errstr),
188 				    gettext("Illegal entry in '%s' on "
189 				    "line %d"), file, lineno);
190 				MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
191 				    strdup(errstr), NS_PARSE_ERR);
192 				(void) fclose(fp);
193 				return (NS_PARSE_ERR);
194 			}
195 			break;
196 		case CREDCONFIG:
197 			if (i == NS_LDAP_FILE_VERSION_P)
198 				break;
199 			if (cred_file) {
200 				ret = __ns_ldap_setParamValue(ptr, i, value,
201 				    error);
202 				if (ret != NS_SUCCESS) {
203 					(void) fclose(fp);
204 					return (ret);
205 				}
206 			} else {
207 				(void) snprintf(errstr, sizeof (errstr),
208 				    gettext("Illegal entry in '%s' on "
209 				    "line %d"), file, lineno);
210 				MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
211 				    strdup(errstr), NS_PARSE_ERR);
212 				(void) fclose(fp);
213 				return (NS_PARSE_ERR);
214 			}
215 		}
216 	}
217 	(void) fclose(fp);
218 	if (!cred_file && emptyfile) {
219 		/* Error in read_line */
220 		(void) snprintf(errstr, sizeof (errstr),
221 		    gettext("Empty config file: '%s'"), file);
222 		MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
223 		    NS_PARSE_ERR);
224 		return (NS_PARSE_ERR);
225 	}
226 	if (linelen == -2) {
227 		/* Error in read_line */
228 		(void) snprintf(errstr, sizeof (errstr),
229 		    gettext("Line too long in '%s'"), file);
230 		MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
231 		    NS_PARSE_ERR);
232 		return (NS_PARSE_ERR);
233 	}
234 	return (NS_SUCCESS);
235 }
236 
237 
238 static
239 ns_ldap_return_code
240 set_attr(ns_config_t *config_struct, char *attr_name, char *attr_val,
241     ns_ldap_error_t **errorp)
242 {
243 	ParamIndexType	idx;
244 	char		errmsg[MAXERROR];
245 
246 	if (errorp == NULL) {
247 		return (NS_LDAP_INVALID_PARAM);
248 	}
249 
250 	*errorp = NULL;
251 
252 	/*
253 	 * This double call is made due to the presence of
254 	 * two sets of LDAP config. attribute names.
255 	 * An LDAP configuration can be obtained either from a server
256 	 * or from SMF. The former sends a DUA with attributes' names
257 	 * styled like "preferredServerList". But local configurations
258 	 * will have names inherited from the /var/ldap/ldap* files such as
259 	 * "NS_LDAP_SERVER_PREF".
260 	 * So, the standalone bits are able to process both sets of
261 	 * attributes' names.
262 	 */
263 	if (__s_api_get_profiletype(attr_name, &idx) < 0 &&
264 	    __s_api_get_versiontype(config_struct, attr_name, &idx) < 0) {
265 		(void) snprintf(errmsg, sizeof (errmsg),
266 		    gettext("Illegal DUAProfile property: <%s>."), attr_name);
267 		MKERROR(LOG_ERR, *errorp, NS_LDAP_CONFIG, strdup(errmsg),
268 		    NS_LDAP_MEMORY);
269 		return (NS_LDAP_CONFIG);
270 	}
271 
272 	return (__ns_ldap_setParamValue(config_struct, idx, attr_val, errorp));
273 }
274 
275 
276 /*
277  * This function creates a configuration which will be used
278  * for all LDAP requests in the Standalone mode.
279  *
280  * INPUT:
281  *     config - a buffer returned by __ns_ldap_getConnectionInfo()'s
282  *              dua_profile parameter.
283  *
284  */
285 ns_config_t *
286 __s_api_create_config_door_str(char *config, ns_ldap_error_t **errorp)
287 {
288 	char		*attr, *attrName, *attrVal, *rest;
289 	ns_config_t	*configStruct = NULL;
290 	char		errmsg[MAXERROR];
291 
292 	if (config == NULL || errorp == NULL)
293 		return (NULL);
294 
295 	if ((configStruct = __s_api_create_config()) == NULL) {
296 		return (NULL);
297 	}
298 
299 	*errorp = NULL;
300 
301 	attr = strtok_r(config, DOORLINESEP, &rest);
302 	if (!attr) {
303 		__s_api_destroy_config(configStruct);
304 		(void) snprintf(errmsg, sizeof (errmsg),
305 		    gettext("DUAProfile received from the server"
306 		    " has bad format"));
307 		MKERROR(LOG_ERR, *errorp, NS_LDAP_CONFIG, strdup(errmsg), NULL);
308 		return (NULL);
309 	}
310 
311 	do {
312 		__s_api_split_key_value(attr, &attrName, &attrVal);
313 
314 		if (attrName == NULL || attrVal == NULL) {
315 			__s_api_destroy_config(configStruct);
316 			(void) snprintf(errmsg, sizeof (errmsg),
317 			    gettext("Attribute %s is not valid"), attr);
318 			MKERROR(LOG_ERR, *errorp, NS_LDAP_CONFIG,
319 			    strdup(errmsg), NULL);
320 			return (NULL);
321 		}
322 
323 		/* Get the version of the profile. */
324 		if (strcasecmp(attrName, "objectclass") == 0) {
325 			if (strcasecmp(attrVal, _PROFILE2_OBJECTCLASS) == 0) {
326 				if (__ns_ldap_setParamValue(configStruct,
327 				    NS_LDAP_FILE_VERSION_P,
328 				    NS_LDAP_VERSION_2,
329 				    errorp) != NS_LDAP_SUCCESS) {
330 					__s_api_destroy_config(configStruct);
331 					return (NULL);
332 				}
333 			} else if (strcasecmp(attrVal,
334 			    _PROFILE1_OBJECTCLASS) == 0) {
335 				if (__ns_ldap_setParamValue(configStruct,
336 				    NS_LDAP_FILE_VERSION_P,
337 				    NS_LDAP_VERSION_1,
338 				    errorp) != NS_LDAP_SUCCESS) {
339 					__s_api_destroy_config(configStruct);
340 					return (NULL);
341 				}
342 			}
343 			continue;
344 		}
345 
346 		if (set_attr(configStruct, attrName, attrVal, errorp) !=
347 		    NS_LDAP_SUCCESS) {
348 			__s_api_destroy_config(configStruct);
349 			return (NULL);
350 		}
351 	} while (attr = strtok_r(NULL, DOORLINESEP, &rest));
352 
353 	if (__s_api_crosscheck(configStruct, errmsg, B_FALSE) != NS_SUCCESS) {
354 		MKERROR(LOG_ERR, *errorp, NS_LDAP_CONFIG, strdup(errmsg), NULL);
355 		__s_api_destroy_config(configStruct);
356 		return (NULL);
357 	}
358 
359 	return (configStruct);
360 }
361 
362 
363 /*
364  * Cache Manager side of configuration file loading
365  */
366 
367 ns_ldap_error_t *
368 __ns_ldap_LoadConfiguration()
369 {
370 	ns_ldap_error_t	*error = NULL;
371 	ns_config_t	*ptr = NULL;
372 	char		errstr[MAXERROR];
373 	ns_parse_status	ret;
374 
375 
376 	ptr = __s_api_create_config();
377 	if (ptr == NULL) {
378 		(void) snprintf(errstr, sizeof (errstr),
379 		    gettext("__ns_ldap_LoadConfiguration: Out of memory."));
380 		MKERROR(LOG_ERR, error, NS_CONFIG_NOTLOADED,
381 		    strdup(errstr), NULL);
382 		return (error);
383 	}
384 
385 	/* Load in Configuration file */
386 	ret = read_file(ptr, 0, &error);
387 	if (ret != NS_SUCCESS) {
388 		__s_api_destroy_config(ptr);
389 		return (error);
390 	}
391 
392 	/* Load in Credential file */
393 	ret = read_file(ptr, 1, &error);
394 	if (ret != NS_SUCCESS) {
395 		__s_api_destroy_config(ptr);
396 		return (error);
397 	}
398 
399 	if (__s_api_crosscheck(ptr, errstr, B_TRUE) != NS_SUCCESS) {
400 		__s_api_destroy_config(ptr);
401 		MKERROR(LOG_ERR, error, NS_CONFIG_SYNTAX, strdup(errstr), NULL);
402 		return (error);
403 	}
404 
405 	__s_api_init_config(ptr);
406 	return (NULL);
407 }
408 
409 
410 int
411 __print2buf(LineBuf *line, const char *toprint, char *sep)
412 {
413 	int	newsz = 0;
414 	int	newmax = 0;
415 	char	*str;
416 
417 	if (line == NULL)
418 		return (-1);
419 
420 	newsz = strlen(toprint) + line->len + 1;
421 	if (sep != NULL) {
422 		newsz += strlen(sep);
423 	}
424 	if (line->alloc == 0 || newsz > line->alloc) {
425 		/* Round up to next buffer and add 1 */
426 		newmax = (((newsz+(BUFSIZ-1))/BUFSIZ)+1) * BUFSIZ;
427 		if (line->alloc == 0)
428 			line->str = (char *)calloc(newmax, 1);
429 		else {
430 			/*
431 			 * if realloc() returns NULL,
432 			 * the original buffer is untouched.
433 			 * It needs to be freed.
434 			 */
435 			str = (char *)realloc(line->str, newmax);
436 			if (str == NULL) {
437 				free(line->str);
438 				line->str = NULL;
439 			}
440 			else
441 				line->str = str;
442 		}
443 		line->alloc = newmax;
444 		if (line->str == NULL) {
445 			line->alloc = 0;
446 			line->len = 0;
447 			return (-1);
448 		}
449 	}
450 	/* now add new 'toprint' data to buffer */
451 	(void) strlcat(line->str, toprint, line->alloc);
452 	if (sep != NULL) {
453 		(void) strlcat(line->str, sep, line->alloc);
454 	}
455 	line->len = newsz;
456 	return (0);
457 }
458 
459 
460 /*
461  * __ns_ldap_LoadDoorInfo is a routine used by the ldapcachemgr
462  * to create a configuration buffer to transmit back to a client
463  * domainname is transmitted to ldapcachemgr and ldapcachemgr uses
464  * it to select a configuration to transmit back.  Otherwise it
465  * is essentially unused in sldap.
466  * If cred_only is not 0, then only the credentials for shadow
467  * update are taken care of.
468  */
469 
470 ns_ldap_error_t *
471 __ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname,
472     ns_config_t *new, int cred_only)
473 {
474 	ns_config_t	*ptr;
475 	char		errstr[MAXERROR];
476 	ns_ldap_error_t	*errorp;
477 	char		*str;
478 	ParamIndexType	i = 0;
479 	int		len;
480 	ldap_config_out_t *cout;
481 
482 	/*
483 	 * If new is NULL, it outputs the flatten data of current default
484 	 * config, if it's non-NULL, it outputs the flatten data of a temporary
485 	 * config. It's used to compare the new config data with the current
486 	 * default config data.
487 	 */
488 	if (new == NULL)
489 		ptr = __s_api_get_default_config();
490 	else
491 		ptr = new;
492 	if (ptr == NULL) {
493 		(void) snprintf(errstr, sizeof (errstr),
494 		    gettext("No configuration information available for %s."),
495 		    domainname == NULL ? "<no domain specified>" : domainname);
496 		MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
497 		    strdup(errstr), NULL);
498 		return (errorp);
499 	}
500 	(void) memset((char *)configinfo, 0, sizeof (LineBuf));
501 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
502 		if (cred_only) {
503 			/* only exposed credential for shadow update */
504 			if (i != NS_LDAP_ADMIN_BINDDN_P &&
505 			    i != NS_LDAP_ADMIN_BINDPASSWD_P)
506 				continue;
507 		} else {
508 			/* credential for shadow update is not to be exposed */
509 			if (i == NS_LDAP_ADMIN_BINDDN_P ||
510 			    i == NS_LDAP_ADMIN_BINDPASSWD_P)
511 				continue;
512 		}
513 		str = __s_api_strValue(ptr, i, NS_DOOR_FMT);
514 		if (str == NULL)
515 			continue;
516 		if (__print2buf(configinfo, str, DOORLINESEP)) {
517 			(void) snprintf(errstr, sizeof (errstr),
518 			    gettext("__print2buf: Out of memory."));
519 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
520 			    strdup(errstr), NULL);
521 			__s_api_release_config(ptr);
522 			free(str);
523 			return (errorp);
524 		}
525 		free(str);
526 	}
527 	if (new == NULL)
528 		__s_api_release_config(ptr);
529 
530 	/*
531 	 * The new interface of the configuration between ldap_cachemgr
532 	 * & libsldap contains a header structure ldap_config_out_t.
533 	 * The flatten configuration data configinfo->str is cloned
534 	 * to cout->config_str, configinfo->len is saved in
535 	 * cout->data_size and cout->cookie is set later after this function
536 	 * is returned in ldap_cachemgr.
537 	 * configinfo->str & configinfo->len are reused to save info of
538 	 * header + data.
539 	 * The format:
540 	 * [cookie|data_size|config_str .............]
541 	 */
542 
543 	if (configinfo->str) {
544 		len = sizeof (ldap_config_out_t) - sizeof (int) +
545 		    configinfo->len;
546 		if ((cout = calloc(1, len)) == NULL) {
547 			free(configinfo->str);
548 			configinfo->str = NULL;
549 			configinfo->len = 0;
550 			(void) snprintf(errstr, sizeof (errstr),
551 			    gettext("calloc: Out of memory."));
552 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
553 			    strdup(errstr), NULL);
554 			return (errorp);
555 		}
556 		/*
557 		 * cout->cookie is set by the caller,
558 		 * which is in ldap_cachemgr.
559 		 */
560 		cout->data_size = configinfo->len;
561 		(void) memcpy(cout->config_str, configinfo->str,
562 		    configinfo->len);
563 		free(configinfo->str);
564 		configinfo->str = (char *)cout;
565 		configinfo->len = len;
566 	}
567 	return (NULL);
568 }
569 
570 
571 ns_ldap_error_t *
572 __ns_ldap_DumpLdif(char *filename)
573 {
574 	ns_config_t	*ptr;
575 	char		errstr[MAXERROR];
576 	ns_ldap_error_t	*errorp;
577 	char		*str;
578 	FILE		*fp;
579 	ParamIndexType	i = 0;
580 	char		*profile, *container, *base;
581 
582 	ptr = __s_api_get_default_config();
583 	if (ptr == NULL) {
584 		(void) snprintf(errstr, sizeof (errstr),
585 		    gettext("No configuration information available."));
586 		MKERROR(LOG_ERR, errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
587 		    NULL);
588 		return (errorp);
589 	}
590 
591 	if (filename == NULL) {
592 		fp = stdout;
593 	} else {
594 		fp = fopen(filename, "wF");
595 		if (fp == NULL) {
596 			(void) snprintf(errstr, sizeof (errstr),
597 			    gettext("Unable to open filename %s for ldif "
598 			    "dump (errno=%d)."), filename, errno);
599 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_FILE,
600 			    strdup(errstr), NULL);
601 			__s_api_release_config(ptr);
602 			return (errorp);
603 		}
604 		(void) fchmod(fileno(fp), 0444);
605 	}
606 
607 	if (ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_ptype != CHARPTR ||
608 	    ptr->paramList[NS_LDAP_PROFILE_P].ns_ptype != CHARPTR) {
609 		(void) snprintf(errstr, sizeof (errstr),
610 		    gettext("Required BaseDN and/or Profile name "
611 		    "ldif fields not present"));
612 		MKERROR(LOG_WARNING, errorp, NS_CONFIG_FILE, strdup(errstr),
613 		    NULL);
614 		__s_api_release_config(ptr);
615 		return (errorp);
616 	}
617 
618 	profile = ptr->paramList[NS_LDAP_PROFILE_P].ns_pc;
619 	base = ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_pc;
620 	container = _PROFILE_CONTAINER;
621 
622 	/*
623 	 * Construct DN, but since this is the profile, there is no need
624 	 * to worry about mapping.  The profile itself can not be mapped
625 	 */
626 	(void) fprintf(fp, "dn: cn=%s,ou=%s,%s\n", profile, container, base);
627 
628 	/* dump objectclass names */
629 	if (ptr->version == NS_LDAP_V1) {
630 		(void) fprintf(fp, "ObjectClass: top\nObjectClass: %s\n",
631 		    _PROFILE1_OBJECTCLASS);
632 	} else {
633 		(void) fprintf(fp, "ObjectClass: top\nObjectClass: %s\n",
634 		    _PROFILE2_OBJECTCLASS);
635 	}
636 
637 	/* For each parameter - construct value */
638 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
639 		str = __s_api_strValue(ptr, i, NS_LDIF_FMT);
640 		if (str == NULL)
641 			continue;
642 		/*
643 		 * don't dump binddn, bind password, admin binddn, admin
644 		 * bind password, enableShadowUpdate flag, or cert path
645 		 * as they are not part of version 2 profiles
646 		 */
647 		if ((i != NS_LDAP_BINDDN_P) &&
648 		    (i != NS_LDAP_BINDPASSWD_P) &&
649 		    (i != NS_LDAP_ADMIN_BINDDN_P) &&
650 		    (i != NS_LDAP_ADMIN_BINDPASSWD_P) &&
651 		    (i != NS_LDAP_ENABLE_SHADOW_UPDATE_P) &&
652 		    (i != NS_LDAP_HOST_CERTPATH_P))
653 			(void) fprintf(fp, "%s\n", str);
654 		free(str);
655 	}
656 
657 	if (filename != NULL)
658 		(void) fclose(fp);
659 
660 	__s_api_release_config(ptr);
661 	return (NULL);
662 }
663 
664 /*
665  * This routine can process the configuration  and/or
666  * the credential files at the same time.
667  * files is char *[3] = { "config", "cred", NULL };
668  */
669 
670 static
671 ns_ldap_error_t *
672 __ns_ldap_DumpConfigFiles(char **files)
673 {
674 	char		*filename;
675 	int		fi;
676 	int		docred;
677 	ns_config_t	*ptr;
678 	char		*str;
679 	char		errstr[MAXERROR];
680 	ParamIndexType	i = 0;
681 	FILE		*fp;
682 	int		rc;
683 	ns_ldap_error_t	*errorp = NULL;
684 	struct stat	buf;
685 	int		cfgtype;
686 	boolean_t	file_export_error = B_FALSE;
687 
688 	ptr = __s_api_get_default_config();
689 	if (ptr == NULL) {
690 		(void) snprintf(errstr, sizeof (errstr),
691 		    gettext("No configuration information available."));
692 		MKERROR(LOG_ERR, errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
693 		    NULL);
694 		return (errorp);
695 	}
696 
697 	for (fi = 0; fi < 2; fi++) {
698 		docred = 0;
699 		filename = files[fi];
700 		if (filename == NULL)
701 			continue;
702 		if (fi == 1)
703 			docred++;
704 		rc = stat(filename, &buf);
705 		fp = fopen(filename, "wF");
706 		if (fp == NULL) {
707 			(void) snprintf(errstr, sizeof (errstr),
708 			    gettext("Unable to open filename %s"
709 			    " for configuration dump (%s)."),
710 			    filename, strerror(errno));
711 			MKERROR(LOG_ERR, errorp, NS_CONFIG_FILE,
712 			    strdup(errstr), NULL);
713 			__s_api_release_config(ptr);
714 			return (errorp);
715 		}
716 		if (rc == 0) {
717 			if (fchmod(fileno(fp), buf.st_mode) != 0) {
718 				(void) snprintf(errstr, sizeof (errstr),
719 				    gettext("Unable to set permissions for file"
720 				    " %s for configuration dump (%s)."),
721 				    filename, strerror(errno));
722 				(void) fclose(fp);
723 				file_export_error = B_TRUE;
724 				break;
725 			}
726 		} else {
727 			if (fchmod(fileno(fp), 0400) != 0) {
728 				(void) snprintf(errstr, sizeof (errstr),
729 				    gettext("Unable to set permissions for file"
730 				    " %s for configuration dump (%s)."),
731 				    filename, strerror(errno));
732 				(void) fclose(fp);
733 				file_export_error = B_TRUE;
734 				break;
735 			}
736 		}
737 		if (fprintf(fp, "#\n# %s\n#\n", DONOTEDIT) < 0) {
738 			(void) snprintf(errstr, sizeof (errstr), gettext(
739 			    "Writing to file %s for configuration dump failed "
740 			    "(%s)."), filename, strerror(errno));
741 			file_export_error = B_TRUE;
742 		}
743 
744 		/* assume VERSION is set and it outputs first */
745 
746 		/* For each parameter - construct value */
747 		for (i = 0; !file_export_error && (i <= NS_LDAP_MAX_PIT_P);
748 		    i++) {
749 			cfgtype = __s_api_get_configtype(i);
750 			if ((docred == 0 && cfgtype == CREDCONFIG) ||
751 			    (docred == 1 && cfgtype != CREDCONFIG))
752 				continue;
753 
754 			str = __s_api_strValue(ptr, i, NS_FILE_FMT);
755 			if (str == NULL)
756 				continue;
757 			if (fprintf(fp, "%s\n", str) < 0) {
758 				(void) snprintf(errstr, sizeof (errstr),
759 				    gettext("Writing to file %s for"
760 				    "configuration dump failed (%s)."),
761 				    filename, strerror(errno));
762 				file_export_error = B_TRUE;
763 			}
764 
765 			free(str);
766 		}
767 		if (fclose(fp) != 0) {
768 			/* Break if error already hit */
769 			if (file_export_error)
770 				break;
771 
772 			(void) snprintf(errstr, sizeof (errstr), gettext(
773 			    "Writing to file %s for configuration dump failed "
774 			    "during file close (%s)."), filename,
775 			    strerror(errno));
776 			file_export_error = B_TRUE;
777 			break;
778 		}
779 
780 	}
781 
782 	if (file_export_error) {
783 		MKERROR(LOG_ERR, errorp, NS_CONFIG_FILE,
784 		    strdup(errstr), NULL);
785 		(void) unlink(filename);
786 	}
787 
788 	__s_api_release_config(ptr);
789 	return (errorp);
790 }
791 
792 ns_ldap_error_t *
793 __ns_ldap_DumpConfiguration(char *file)
794 {
795 	ns_ldap_error_t	*ret;
796 	char		*files[3];
797 
798 	files[0] = NULL;
799 	files[1] = NULL;
800 	files[2] = NULL;
801 	if (strcmp(file, NSCONFIGFILE) == 0) {
802 		files[0] = file;
803 	} else if (strcmp(file, NSCONFIGREFRESH) == 0) {
804 		files[0] = file;
805 	} else if (strcmp(file, NSCREDFILE) == 0) {
806 		files[1] = file;
807 	} else if (strcmp(file, NSCREDREFRESH) == 0) {
808 		files[1] = file;
809 	}
810 	ret = __ns_ldap_DumpConfigFiles(files);
811 	return (ret);
812 }
813 
814 /*
815  * **************************************************************
816  * Misc Routines
817  * **************************************************************
818  */
819 
820 ns_config_t *
821 __ns_ldap_make_config(ns_ldap_result_t *result)
822 {
823 	int		l, m;
824 	char		val[BUFSIZE];
825 	char		*attrname;
826 	ns_ldap_entry_t	*entry;
827 	ns_ldap_attr_t	*attr;
828 	char		**attrval;
829 	ParamIndexType	index;
830 	ns_config_t	*ptr;
831 	ns_ldap_error_t	*error = NULL;
832 	int		prof_ver;
833 	ns_config_t	*curr_ptr = NULL;
834 	char		errstr[MAXERROR];
835 	ns_ldap_error_t	*errorp;
836 	LineBuf		buffer;
837 	char		*sepstr;
838 
839 	if (result == NULL)
840 		return (NULL);
841 
842 	if (result->entries_count > 1) {
843 		(void) snprintf(errstr, MAXERROR,
844 		    gettext("Configuration Error: More than one profile "
845 		    "found"));
846 		MKERROR(LOG_ERR, errorp, NS_PARSE_ERR, strdup(errstr), NULL);
847 		(void) __ns_ldap_freeError(&errorp);
848 		return (NULL);
849 	}
850 
851 	ptr = __s_api_create_config();
852 	if (ptr == NULL)
853 		return (NULL);
854 
855 	curr_ptr = __s_api_get_default_config();
856 	if (curr_ptr == NULL) {
857 		__s_api_destroy_config(ptr);
858 		return (NULL);
859 	}
860 
861 	/* Check to see if the profile is version 1 or version 2 */
862 	prof_ver = 1;
863 	entry = result->entry;
864 	for (l = 0; l < entry->attr_count; l++) {
865 		attr = entry->attr_pair[l];
866 
867 		attrname = attr->attrname;
868 		if (attrname == NULL)
869 			continue;
870 		if (strcasecmp(attrname, "objectclass") == 0) {
871 			for (m = 0; m < attr->value_count; m++) {
872 				if (strcasecmp(_PROFILE2_OBJECTCLASS,
873 				    attr->attrvalue[m]) == 0) {
874 					prof_ver = 2;
875 					break;
876 				}
877 			}
878 		}
879 	}
880 	/* update the configuration to accept v1 or v2 attributes */
881 	if (prof_ver == 1) {
882 		(void) strcpy(val, NS_LDAP_VERSION_1);
883 		(void) __ns_ldap_setParamValue(ptr, NS_LDAP_FILE_VERSION_P,
884 		    val, &error);
885 	} else {
886 		(void) strcpy(val, NS_LDAP_VERSION_2);
887 		(void) __ns_ldap_setParamValue(ptr, NS_LDAP_FILE_VERSION_P,
888 		    val, &error);
889 	}
890 
891 	for (l = 0; l < entry->attr_count; l++) {
892 		attr = entry->attr_pair[l];
893 
894 		attrname = attr->attrname;
895 		if (attrname == NULL)
896 			continue;
897 		if (__s_api_get_profiletype(attrname, &index) != 0)
898 			continue;
899 
900 		attrval = attr->attrvalue;
901 		switch (index) {
902 		case NS_LDAP_SEARCH_DN_P:
903 		case NS_LDAP_SERVICE_SEARCH_DESC_P:
904 		case NS_LDAP_ATTRIBUTEMAP_P:
905 		case NS_LDAP_OBJECTCLASSMAP_P:
906 		case NS_LDAP_SERVICE_CRED_LEVEL_P:
907 		case NS_LDAP_SERVICE_AUTH_METHOD_P:
908 			/* Multiple Value - insert 1 at a time */
909 			for (m = 0; m < attr->value_count; m++) {
910 				(void) __ns_ldap_setParamValue(ptr, index,
911 				    attrval[m], &error);
912 			}
913 			break;
914 		default:
915 			(void) memset((void *)&buffer, 0, sizeof (LineBuf));
916 
917 			/* Single or Multiple Value */
918 			for (m = 0; m < attr->value_count; m++) {
919 				sepstr = NULL;
920 				if (m != attr->value_count - 1) {
921 					sepstr = SPACESEP;
922 				}
923 				if (__print2buf(&buffer, attrval[m], sepstr))
924 					goto makeconfigerror;
925 			}
926 			(void) __ns_ldap_setParamValue(ptr, index, buffer.str,
927 			    &error);
928 			if (buffer.len > 0) {
929 				free(buffer.str);
930 				buffer.len = 0;
931 			}
932 			break;
933 		}
934 	}
935 	if (ptr->version != NS_LDAP_V1) {
936 		ParamIndexType i;
937 		if (curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_ptype == CHARPTR) {
938 			(void) __ns_ldap_setParamValue(ptr, NS_LDAP_BINDDN_P,
939 			    curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_pc,
940 			    &error);
941 		}
942 		if (curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_ptype ==
943 		    CHARPTR) {
944 			(void) __ns_ldap_setParamValue(ptr,
945 			    NS_LDAP_BINDPASSWD_P,
946 			    curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_pc,
947 			    &error);
948 		}
949 		i = NS_LDAP_ENABLE_SHADOW_UPDATE_P;
950 		if (curr_ptr->paramList[i].ns_ptype == INT) {
951 			char *valt;
952 			valt = __s_get_shadowupdate_name(
953 			    curr_ptr->paramList[i].ns_i);
954 			(void) __ns_ldap_setParamValue(ptr, i, valt, &error);
955 		}
956 		if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_ptype ==
957 		    CHARPTR) {
958 			(void) __ns_ldap_setParamValue(ptr,
959 			    NS_LDAP_ADMIN_BINDDN_P,
960 			    curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_pc,
961 			    &error);
962 		}
963 		if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_ptype ==
964 		    CHARPTR) {
965 			(void) __ns_ldap_setParamValue(ptr,
966 			    NS_LDAP_ADMIN_BINDPASSWD_P,
967 			    curr_ptr->
968 			    paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_pc,
969 			    &error);
970 		}
971 		if (curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_ptype ==
972 		    CHARPTR) {
973 			(void) __ns_ldap_setParamValue(ptr,
974 			    NS_LDAP_HOST_CERTPATH_P,
975 			    curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_pc,
976 			    &error);
977 		}
978 	}
979 	__s_api_release_config(curr_ptr);
980 	return (ptr);
981 
982 makeconfigerror:
983 	if (buffer.len > 0)
984 		free(buffer.str);
985 
986 	__s_api_debug_pause(LOG_ERR, NS_PARSE_ERR,
987 	    "__ns_ldap_make_config: Not enough memory");
988 	return (NULL);
989 }
990 
991 /*
992  * Download a profile into our internal structure.  The calling application
993  * needs to DumpConfig() to save the information to NSCONFIGFILE and NSCREDFILE
994  * if desired.
995  */
996 int
997 __ns_ldap_download(const char *profile, char *addr, char *baseDN,
998     ns_ldap_error_t **errorp)
999 {
1000 	char filter[BUFSIZE];
1001 	int rc;
1002 	ns_ldap_result_t *result = NULL;
1003 	ns_config_t	*ptr = NULL;
1004 	ns_config_t	*new_ptr = NULL;
1005 	char		errstr[MAXERROR];
1006 
1007 	*errorp = NULL;
1008 	if (baseDN == NULL)
1009 		return (NS_LDAP_INVALID_PARAM);
1010 
1011 	ptr = __s_api_get_default_config();
1012 	if (ptr == NULL) {
1013 		(void) snprintf(errstr, sizeof (errstr),
1014 		    gettext("No configuration information available."));
1015 		MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
1016 		    NS_LDAP_MEMORY);
1017 		return (NS_LDAP_CONFIG);
1018 	}
1019 
1020 	rc = __ns_ldap_setParamValue(ptr, NS_LDAP_SEARCH_BASEDN_P, baseDN,
1021 	    errorp);
1022 	if (rc != NS_LDAP_SUCCESS) {
1023 		__s_api_release_config(ptr);
1024 		return (rc);
1025 	}
1026 
1027 	rc = __ns_ldap_setParamValue(ptr, NS_LDAP_SERVERS_P, addr, errorp);
1028 	__s_api_release_config(ptr);
1029 	if (rc != NS_LDAP_SUCCESS)
1030 		return (rc);
1031 
1032 	(void) snprintf(filter, sizeof (filter), _PROFILE_FILTER,
1033 	    _PROFILE1_OBJECTCLASS, _PROFILE2_OBJECTCLASS, profile);
1034 	rc = __ns_ldap_list(_PROFILE_CONTAINER, (const char *)filter,
1035 	    NULL, NULL, NULL, 0, &result, errorp, NULL, NULL);
1036 
1037 	if (rc != NS_LDAP_SUCCESS)
1038 		return (rc);
1039 
1040 	new_ptr = __ns_ldap_make_config(result);
1041 	(void) __ns_ldap_freeResult(&result);
1042 
1043 	if (new_ptr == NULL)
1044 		return (NS_LDAP_OP_FAILED);
1045 
1046 	rc = __s_api_crosscheck(new_ptr, errstr, B_FALSE);
1047 	if (rc != NS_LDAP_SUCCESS) {
1048 		__s_api_destroy_config(new_ptr);
1049 		MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
1050 		    NS_LDAP_MEMORY);
1051 		return (NS_LDAP_CONFIG);
1052 	}
1053 
1054 	__s_api_init_config(new_ptr);
1055 	return (rc);
1056 }
1057 
1058 /*
1059  * **************************************************************
1060  * Configuration Printing Routines
1061  * **************************************************************
1062  */
1063 
1064 /*
1065  * Yes the use of stdio is okay here because all we are doing is sending
1066  * output to stdout.  This would not be necessary if we could get to the
1067  * configuration pointer outside this file.
1068  */
1069 ns_ldap_error_t *
1070 __ns_ldap_print_config(int verbose)
1071 {
1072 	ns_config_t	*ptr;
1073 	char		errstr[MAXERROR];
1074 	ns_ldap_error_t *errorp;
1075 	char		*str;
1076 	int		i;
1077 
1078 	ptr = __s_api_get_default_config();
1079 	if (ptr == NULL) {
1080 		errorp = __ns_ldap_LoadConfiguration();
1081 		if (errorp != NULL)
1082 			return (errorp);
1083 		ptr = __s_api_get_default_config();
1084 		if (ptr == NULL) {
1085 			(void) snprintf(errstr, sizeof (errstr),
1086 			    gettext("No configuration information."));
1087 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
1088 			    strdup(errstr), NULL);
1089 			return (errorp);
1090 		}
1091 	}
1092 
1093 	if (verbose && (ptr->domainName != NULL)) {
1094 		(void) fputs("ptr->domainName ", stdout);
1095 		(void) fputs(ptr->domainName, stdout);
1096 		(void) putchar('\n');
1097 	}
1098 	/* For each parameter - construct value */
1099 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
1100 			/*
1101 			 * Version 1 skipped this entry because:
1102 			 *
1103 			 * don't print default cache TTL for now since
1104 			 * we don't store it in the ldap_client_file.
1105 			 */
1106 		if ((i == NS_LDAP_CACHETTL_P) && (ptr->version == NS_LDAP_V1))
1107 			continue;
1108 
1109 		/* the credential for shadow update is not to be exposed */
1110 		if (i == NS_LDAP_ADMIN_BINDDN_P ||
1111 		    i == NS_LDAP_ADMIN_BINDPASSWD_P)
1112 			continue;
1113 
1114 		str = __s_api_strValue(ptr, i, NS_FILE_FMT);
1115 		if (str == NULL)
1116 			continue;
1117 		if (verbose)
1118 			(void) putchar('\t');
1119 		(void) fprintf(stdout, "%s\n", str);
1120 		free(str);
1121 	}
1122 
1123 	__s_api_release_config(ptr);
1124 	return (NULL);
1125 }
1126