xref: /titanic_51/usr/src/lib/libsldap/common/ns_confmgr.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1999-2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /* libsldap - cachemgr side configuration components */
30 
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <stdlib.h>
34 #include <libintl.h>
35 #include <string.h>
36 #include <ctype.h>
37 
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <syslog.h>
42 #include <locale.h>
43 #include <errno.h>
44 #include <sys/time.h>
45 
46 #include "ns_sldap.h"
47 #include "ns_internal.h"
48 #include "ns_cache_door.h"
49 
50 #define	ALWAYS		1
51 
52 
53 /*
54  * **************************************************************
55  * Configuration File Routines
56  * **************************************************************
57  */
58 
59 
60 /* Size of the errstr buffer needs to be MAXERROR */
61 static int
62 read_line(FILE *fp, char *buffer, int buflen, char *errstr)
63 {
64 	int	linelen;
65 	char	c;
66 
67 	*errstr = '\0';
68 
69 	for (linelen = 0; linelen < buflen; ) {
70 		c = getc(fp);
71 		if (c == EOF)
72 			break;
73 		switch (c) {
74 		case '\n':
75 		    if (linelen > 0 && buffer[linelen - 1] == '\\') {
76 			/* Continuation line found */
77 			--linelen;
78 		    } else {
79 			/* end of line found */
80 			buffer[linelen] = '\0';
81 			return (linelen);
82 		    }
83 		    break;
84 		default:
85 		    buffer[linelen++] = c;
86 		}
87 	}
88 
89 	if (linelen >= buflen) {
90 		(void) snprintf(errstr, MAXERROR,
91 			gettext("Buffer overflow, line too long."));
92 		return (-2);
93 	} else if (linelen > 0 && buffer[linelen - 1] == '\\') {
94 		(void) snprintf(errstr, MAXERROR,
95 			gettext("Unterminated continuation line."));
96 		return (-2);
97 	} else {
98 		/* end of file */
99 		buffer[linelen] = '\0';
100 	}
101 	return (linelen > 0 ? linelen : -1);
102 }
103 
104 
105 static ns_parse_status
106 read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
107 {
108 	ParamIndexType	i = 0;
109 	char		errstr[MAXERROR];
110 	char		buffer[BUFSIZE], *name, *value;
111 	int		emptyfile, lineno;
112 	FILE		*fp;
113 	int		ret;
114 	int		linelen;
115 	char		*file;
116 	int		first = 1;
117 
118 
119 	if (cred_file) {
120 		file = NSCREDFILE;
121 	} else {
122 		file = NSCONFIGFILE;
123 	}
124 	fp = fopen(file, "r");
125 	if (fp == NULL) {
126 		(void) snprintf(errstr, sizeof (errstr),
127 			gettext("Unable to open filename '%s' "
128 			"for reading (errno=%d)."), file, errno);
129 		MKERROR(LOG_ERR, *error, NS_CONFIG_FILE, strdup(errstr), NULL);
130 		return (NS_NOTFOUND);
131 	}
132 
133 	emptyfile = 1;
134 	lineno = 0;
135 	for (; ; ) {
136 		if ((linelen = read_line(fp, buffer, sizeof (buffer),
137 			errstr)) < 0)
138 			/* End of file */
139 			break;
140 		lineno++;
141 		if (linelen == 0)
142 			continue;
143 		/* get rid of comment lines */
144 		if (buffer[0] == '#')
145 			continue;
146 		emptyfile = 0;
147 		name = NULL;
148 		value = NULL;
149 		__s_api_split_key_value(buffer, &name, &value);
150 		if (name == NULL || value == NULL) {
151 			(void) snprintf(errstr, sizeof (errstr),
152 			    gettext("Missing Name or Value on line %d."),
153 				    lineno);
154 			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
155 				strdup(errstr), NULL);
156 			(void) fclose(fp);
157 			return (NS_PARSE_ERR);
158 		}
159 		if (__s_api_get_versiontype(ptr, name, &i) != 0) {
160 			(void) snprintf(errstr, sizeof (errstr),
161 			    gettext("Illegal profile type on line %d."),
162 				    lineno);
163 			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
164 				strdup(errstr), NULL);
165 			(void) fclose(fp);
166 			return (NS_PARSE_ERR);
167 		}
168 		if (!first && i == NS_LDAP_FILE_VERSION_P) {
169 			(void) snprintf(errstr, sizeof (errstr),
170 				gettext("Illegal NS_LDAP_FILE_VERSION "
171 				"on line %d."), lineno);
172 			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
173 				strdup(errstr), NULL);
174 			(void) fclose(fp);
175 			return (NS_PARSE_ERR);
176 		}
177 		first = 0;
178 		switch (__s_api_get_configtype(i)) {
179 		case SERVERCONFIG:
180 		case CLIENTCONFIG:
181 			if (cred_file == 0) {
182 				ret = __ns_ldap_setParamValue(ptr, i, value,
183 					error);
184 				if (ret != NS_SUCCESS) {
185 					(void) fclose(fp);
186 					return (ret);
187 				}
188 			} else if (i != NS_LDAP_FILE_VERSION_P) {
189 				(void) snprintf(errstr, sizeof (errstr),
190 					gettext("Illegal entry in '%s' on "
191 					"line %d"), file, lineno);
192 				MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
193 					strdup(errstr), NULL);
194 				(void) fclose(fp);
195 				return (NS_PARSE_ERR);
196 			}
197 			break;
198 		case CREDCONFIG:
199 			if (i == NS_LDAP_FILE_VERSION_P)
200 				break;
201 			if (cred_file) {
202 				ret = __ns_ldap_setParamValue(ptr, i, value,
203 					error);
204 				if (ret != NS_SUCCESS) {
205 					(void) fclose(fp);
206 					return (ret);
207 				}
208 			} else {
209 				(void) snprintf(errstr, sizeof (errstr),
210 					gettext("Illegal entry in '%s' on "
211 					"line %d"), file, lineno);
212 				MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
213 					strdup(errstr), NULL);
214 				(void) fclose(fp);
215 				return (NS_PARSE_ERR);
216 			}
217 		}
218 	}
219 	(void) fclose(fp);
220 	if (!cred_file && emptyfile) {
221 		/* Error in read_line */
222 		(void) snprintf(errstr, sizeof (errstr),
223 			gettext("Empty config file: '%s'"), file);
224 		MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
225 			NULL);
226 		return (NS_PARSE_ERR);
227 	}
228 	if (linelen == -2) {
229 		/* Error in read_line */
230 		(void) snprintf(errstr, sizeof (errstr),
231 			gettext("Line too long in '%s'"), file);
232 		MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
233 			NULL);
234 		return (NS_PARSE_ERR);
235 	}
236 	return (NS_SUCCESS);
237 }
238 
239 
240 /*
241  * Cache Manager side of configuration file loading
242  */
243 
244 ns_ldap_error_t *
245 __ns_ldap_LoadConfiguration()
246 {
247 	ns_ldap_error_t	*error = NULL;
248 	ns_config_t	*ptr = NULL;
249 	char		errstr[MAXERROR];
250 	ns_parse_status	ret;
251 
252 
253 	ptr = __s_api_create_config();
254 	if (ptr == NULL) {
255 		(void) snprintf(errstr, sizeof (errstr),
256 			gettext("__ns_ldap_LoadConfiguration: "
257 				"Out of memory."));
258 		MKERROR(LOG_ERR, error, NS_CONFIG_NOTLOADED,
259 			strdup(errstr), NULL);
260 		return (error);
261 	}
262 
263 	/* Load in Configuration file */
264 	ret = read_file(ptr, 0, &error);
265 	if (ret != NS_SUCCESS) {
266 		__s_api_destroy_config(ptr);
267 		return (error);
268 	}
269 
270 	/* Load in Credential file */
271 	ret = read_file(ptr, 1, &error);
272 	if (ret != NS_SUCCESS) {
273 		__s_api_destroy_config(ptr);
274 		return (error);
275 	}
276 
277 	if (__s_api_crosscheck(ptr, errstr, B_TRUE) != NS_SUCCESS) {
278 		__s_api_destroy_config(ptr);
279 		MKERROR(LOG_ERR, error, NS_CONFIG_SYNTAX, strdup(errstr), NULL);
280 		return (error);
281 	}
282 
283 	__s_api_init_config(ptr);
284 	return (NULL);
285 }
286 
287 
288 static int
289 _print2buf(LineBuf *line, char *toprint, int addsep)
290 {
291 	int	newsz = 0;
292 	int	newmax = 0;
293 	char	*str;
294 
295 	if (line == NULL)
296 		return (-1);
297 
298 	newsz = strlen(toprint) + line->len + 1;
299 	if (addsep) {
300 		newsz += strlen(DOORLINESEP);
301 	}
302 	if (line->alloc == 0 || newsz > line->alloc) {
303 		/* Round up to next buffer and add 1 */
304 		newmax = (((newsz+(BUFSIZ-1))/BUFSIZ)+1) * BUFSIZ;
305 		if (line->alloc == 0)
306 			line->str = (char *)calloc(newmax, 1);
307 		else {
308 			/*
309 			 * if realloc() returns NULL,
310 			 * the original buffer is untouched.
311 			 * It needs to be freed.
312 			 */
313 			str = (char *)realloc(line->str, newmax);
314 			if (str == NULL) {
315 				free(line->str);
316 				line->str = NULL;
317 			}
318 			else
319 				line->str = str;
320 		}
321 		line->alloc = newmax;
322 		if (line->str == NULL) {
323 			line->alloc = 0;
324 			line->len = 0;
325 			return (-1);
326 		}
327 	}
328 	/* now add new 'toprint' data to buffer */
329 	(void) strlcat(line->str, toprint, line->alloc);
330 	if (addsep) {
331 		(void) strlcat(line->str, DOORLINESEP, line->alloc);
332 	}
333 	line->len = newsz;
334 	return (0);
335 }
336 
337 
338 /*
339  * __ns_ldap_LoadDoorInfo is a routine used by the ldapcachemgr
340  * to create a configuration buffer to transmit back to a client
341  * domainname is transmitted to ldapcachemgr and ldapcachemgr uses
342  * it to select a configuration to transmit back.  Otherwise it
343  * is essentially unused in sldap.
344  */
345 
346 ns_ldap_error_t *
347 __ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname)
348 {
349 	ns_config_t	*ptr;
350 	char		errstr[MAXERROR];
351 	ns_ldap_error_t	*errorp;
352 	char		string[BUFSIZE];
353 	char		*str;
354 	ParamIndexType	i = 0;
355 
356 	ptr = __s_api_get_default_config();
357 	if (ptr == NULL) {
358 		(void) snprintf(errstr, sizeof (errstr),
359 		    gettext("No configuration information available for %s."),
360 		    domainname == NULL ? "<no domain specified>" : domainname);
361 		MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
362 			strdup(errstr), NULL);
363 		return (errorp);
364 	}
365 	(void) memset((char *)configinfo, 0, sizeof (LineBuf));
366 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
367 		str = __s_api_strValue(ptr, string, sizeof (string),
368 			i, NS_DOOR_FMT);
369 		if (str == NULL)
370 			continue;
371 		if (_print2buf(configinfo, str, 1) != 0) {
372 			(void) snprintf(errstr, sizeof (errstr),
373 				gettext("_print2buf: Out of memory."));
374 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
375 				strdup(errstr), NULL);
376 			__s_api_release_config(ptr);
377 			if (str != (char *)&string[0]) {
378 				free(str);
379 				str = NULL;
380 			}
381 			return (errorp);
382 		}
383 		if (str != (char *)&string[0]) {
384 			free(str);
385 			str = NULL;
386 		}
387 	}
388 	__s_api_release_config(ptr);
389 	return (NULL);
390 }
391 
392 
393 ns_ldap_error_t *
394 __ns_ldap_DumpLdif(char *filename)
395 {
396 	ns_config_t	*ptr;
397 	char		errstr[MAXERROR];
398 	ns_ldap_error_t	*errorp;
399 	char		string[BUFSIZE];
400 	char		*str;
401 	FILE		*fp;
402 	ParamIndexType	i = 0;
403 	char		*profile, *container, *base;
404 
405 	ptr = __s_api_get_default_config();
406 	if (ptr == NULL) {
407 		(void) snprintf(errstr, sizeof (errstr),
408 		    gettext("No configuration information available."));
409 		MKERROR(LOG_ERR, errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
410 			NULL);
411 		return (errorp);
412 	}
413 
414 	if (filename == NULL) {
415 		fp = stdout;
416 	} else {
417 		fp = fopen(filename, "w");
418 		if (fp == NULL) {
419 			(void) snprintf(errstr, sizeof (errstr),
420 				gettext("Unable to open filename %s for ldif "
421 				"dump (errno=%d)."), filename, errno);
422 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_FILE,
423 				strdup(errstr), NULL);
424 			__s_api_release_config(ptr);
425 			return (errorp);
426 		}
427 		(void) fchmod(fileno(fp), 0444);
428 	}
429 
430 	if (ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_ptype != CHARPTR ||
431 	    ptr->paramList[NS_LDAP_PROFILE_P].ns_ptype != CHARPTR) {
432 		(void) snprintf(errstr, sizeof (errstr),
433 			gettext("Required BaseDN and/or Profile name "
434 				"ldif fields not present"));
435 		MKERROR(LOG_WARNING, errorp, NS_CONFIG_FILE, strdup(errstr),
436 			NULL);
437 		__s_api_release_config(ptr);
438 		return (errorp);
439 	}
440 
441 	profile = ptr->paramList[NS_LDAP_PROFILE_P].ns_pc;
442 	base = ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_pc;
443 	container = _PROFILE_CONTAINER;
444 
445 	/*
446 	 * Construct DN, but since this is the profile, there is no need
447 	 * to worry about mapping.  The profile itself can not be mapped
448 	 */
449 	(void) fprintf(fp, "dn: cn=%s,ou=%s,%s\n", profile, container, base);
450 
451 	/* dump objectclass names */
452 	if (ptr->version == NS_LDAP_V1) {
453 		(void) fprintf(fp,
454 			"ObjectClass: top\nObjectClass: %s\n",
455 			_PROFILE1_OBJECTCLASS);
456 	} else {
457 		(void) fprintf(fp,
458 			"ObjectClass: top\n"
459 			"ObjectClass: %s\n",
460 			_PROFILE2_OBJECTCLASS);
461 	}
462 
463 	/* For each parameter - construct value */
464 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
465 		str = __s_api_strValue(ptr, string, BUFSIZ, i, NS_LDIF_FMT);
466 		if (str == NULL)
467 			continue;
468 		/*
469 		 * don't dump binddn, bind password, or cert path as they
470 		 * are not part of version 2 profiles
471 		 */
472 		if ((i != NS_LDAP_BINDDN_P) && (i != NS_LDAP_BINDPASSWD_P) &&
473 				(i != NS_LDAP_HOST_CERTPATH_P))
474 			(void) fprintf(fp, "%s\n", str);
475 		if (str != (char *)&string[0]) {
476 			free(str);
477 			str = NULL;
478 		}
479 	}
480 
481 	if (filename != NULL)
482 		(void) fclose(fp);
483 
484 	__s_api_release_config(ptr);
485 	return (NULL);
486 }
487 
488 /*
489  * This routine can process the configuration  and/or
490  * the credential files at the same time.
491  * files is char *[3] = { "config", "cred", NULL };
492  */
493 
494 static
495 ns_ldap_error_t *
496 __ns_ldap_DumpConfigFiles(char **files)
497 {
498 	char		*filename;
499 	int		fi;
500 	int		docred;
501 	ns_config_t	*ptr;
502 	char		string[BUFSIZE];
503 	char		*str;
504 	char		errstr[MAXERROR];
505 	ParamIndexType	i = 0;
506 	FILE		*fp;
507 	int		rc;
508 	ns_ldap_error_t	*errorp;
509 	struct stat	buf;
510 	int		cfgtype;
511 
512 	ptr = __s_api_get_default_config();
513 	if (ptr == NULL) {
514 		(void) snprintf(errstr, sizeof (errstr),
515 			gettext("No configuration information available."));
516 		MKERROR(LOG_ERR, errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
517 			NULL);
518 		return (errorp);
519 	}
520 
521 	for (fi = 0; fi < 2; fi++) {
522 		docred = 0;
523 		filename = files[fi];
524 		if (filename == NULL)
525 			continue;
526 		if (fi == 1)
527 			docred++;
528 		rc = stat(filename, &buf);
529 		fp = fopen(filename, "w");
530 		if (fp == NULL) {
531 			(void) snprintf(errstr, sizeof (errstr),
532 				gettext("Unable to open filename %s"
533 				" for configuration dump (errno=%d)."),
534 				filename, errno);
535 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_FILE,
536 				strdup(errstr), NULL);
537 			__s_api_release_config(ptr);
538 			return (errorp);
539 		}
540 		if (rc == 0)
541 			(void) fchmod(fileno(fp), buf.st_mode);
542 		else
543 			(void) fchmod(fileno(fp), 0400);
544 		(void) fprintf(fp, "#\n# %s\n#\n", DONOTEDIT);
545 
546 		/* assume VERSION is set and it outputs first */
547 
548 		/* For each parameter - construct value */
549 		for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
550 			cfgtype = __s_api_get_configtype(i);
551 			if ((docred == 0 && cfgtype == CREDCONFIG) ||
552 				(docred == 1 && cfgtype != CREDCONFIG))
553 				continue;
554 
555 			str = __s_api_strValue(ptr, string, BUFSIZ,
556 					i, NS_FILE_FMT);
557 			if (str == NULL)
558 				continue;
559 			(void) fprintf(fp, "%s\n", str);
560 			if (str != (char *)&string[0]) {
561 				free(str);
562 				str = NULL;
563 			}
564 		}
565 		(void) fclose(fp);
566 	}
567 
568 	__s_api_release_config(ptr);
569 	return (NULL);
570 }
571 
572 ns_ldap_error_t *
573 __ns_ldap_DumpConfiguration(char *file)
574 {
575 	ns_ldap_error_t	*ret;
576 	char		*files[3];
577 
578 	files[0] = NULL;
579 	files[1] = NULL;
580 	files[2] = NULL;
581 	if (strcmp(file, NSCONFIGFILE) == 0) {
582 		files[0] = file;
583 	} else if (strcmp(file, NSCONFIGREFRESH) == 0) {
584 		files[0] = file;
585 	} else if (strcmp(file, NSCREDFILE) == 0) {
586 		files[1] = file;
587 	} else if (strcmp(file, NSCREDREFRESH) == 0) {
588 		files[1] = file;
589 	}
590 	ret = __ns_ldap_DumpConfigFiles(files);
591 	return (ret);
592 }
593 
594 /*
595  * **************************************************************
596  * Misc Routines
597  * **************************************************************
598  */
599 
600 ns_config_t *
601 __ns_ldap_make_config(ns_ldap_result_t *result)
602 {
603 	int		i, l, m;
604 	char		val[BUFSIZ];
605 	char    	*attrname;
606 	ns_ldap_entry_t	*entry;
607 	ns_ldap_attr_t	*attr;
608 	char		**attrval;
609 	ParamIndexType	index;
610 	ns_config_t	*ptr;
611 	ns_ldap_error_t	*error = NULL;
612 	int		firsttime;
613 	int		prof_ver;
614 	ns_config_t	*curr_ptr = NULL;
615 
616 	if (result == NULL)
617 		return (NULL);
618 
619 	ptr = __s_api_create_config();
620 	if (ptr == NULL)
621 		return (NULL);
622 
623 	curr_ptr = __s_api_get_default_config();
624 	if (curr_ptr == NULL) {
625 		__s_api_destroy_config(ptr);
626 		return (NULL);
627 	}
628 
629 	/* Check to see if the profile is version 1 or version 2 */
630 	prof_ver = 1;
631 	entry = result->entry;
632 	for (i = 0; i < result->entries_count; i++) {
633 		for (l = 0; l < entry->attr_count; l++) {
634 			attr = entry->attr_pair[l];
635 
636 			attrname = attr->attrname;
637 			if (attrname == NULL)
638 				continue;
639 			if (strcasecmp(attrname, "objectclass") == 0) {
640 				for (m = 0; m < attr->value_count; m++) {
641 					if (strcasecmp(_PROFILE2_OBJECTCLASS,
642 						attr->attrvalue[m]) == 0) {
643 						prof_ver = 2;
644 						break;
645 					}
646 				}
647 			}
648 		}
649 	}
650 	/* update the configuration to accept v1 or v2 attributes */
651 	if (prof_ver == 1) {
652 		(void) strcpy(val, NS_LDAP_VERSION_1);
653 		(void) __ns_ldap_setParamValue(ptr,
654 				NS_LDAP_FILE_VERSION_P, val, &error);
655 	} else {
656 		(void) strcpy(val, NS_LDAP_VERSION_2);
657 		(void) __ns_ldap_setParamValue(ptr,
658 				NS_LDAP_FILE_VERSION_P, val, &error);
659 	}
660 
661 	entry = result->entry;
662 	for (i = 0; i < result->entries_count; i++) {
663 		for (l = 0; l < entry->attr_count; l++) {
664 			attr = entry->attr_pair[l];
665 
666 			attrname = attr->attrname;
667 			if (attrname == NULL)
668 				continue;
669 			if (__s_api_get_profiletype(attrname, &index) != 0)
670 				continue;
671 
672 			attrval = attr->attrvalue;
673 			switch (index) {
674 			case NS_LDAP_SEARCH_DN_P:
675 			case NS_LDAP_SERVICE_SEARCH_DESC_P:
676 			case NS_LDAP_ATTRIBUTEMAP_P:
677 			case NS_LDAP_OBJECTCLASSMAP_P:
678 			case NS_LDAP_SERVICE_CRED_LEVEL_P:
679 			case NS_LDAP_SERVICE_AUTH_METHOD_P:
680 				/* Multiple Value - insert 1 at a time */
681 				for (m = 0; m < attr->value_count; m++) {
682 					(void) __ns_ldap_setParamValue(ptr,
683 							index,
684 							attrval[m],
685 							&error);
686 				}
687 				break;
688 			default:
689 				firsttime = 1;
690 				/* Single or Multiple Value */
691 				val[0] = '\0';
692 				for (m = 0; m < attr->value_count; m++) {
693 					if (firsttime == 1) {
694 						firsttime = 0;
695 						(void) strlcpy(val, attrval[m],
696 							sizeof (val));
697 					} else {
698 						(void) strlcat(val, " ",
699 							sizeof (val));
700 						(void) strlcat(val, attrval[m],
701 							sizeof (val));
702 					}
703 				}
704 				(void) __ns_ldap_setParamValue(ptr, index,
705 							val, &error);
706 				break;
707 			}
708 		}
709 		entry = entry->next;
710 	}
711 	if (ptr->version != NS_LDAP_V1) {
712 	    if (curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_ptype == CHARPTR) {
713 		(void) __ns_ldap_setParamValue(ptr, NS_LDAP_BINDDN_P,
714 			curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_pc, &error);
715 	    }
716 	    if (curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_ptype == CHARPTR) {
717 		(void) __ns_ldap_setParamValue(ptr, NS_LDAP_BINDPASSWD_P,
718 			curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_pc,
719 			&error);
720 	    }
721 	    if (curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_ptype ==
722 			CHARPTR) {
723 		(void) __ns_ldap_setParamValue(ptr, NS_LDAP_HOST_CERTPATH_P,
724 			curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_pc,
725 			&error);
726 	    }
727 	}
728 	__s_api_release_config(curr_ptr);
729 	return (ptr);
730 }
731 
732 /*
733  * Download a profile into our internal structure.  The calling application
734  * needs to DumpConfig() to save the information to NSCONFIGFILE and NSCREDFILE
735  * if desired.
736  */
737 int
738 __ns_ldap_download(const char *profile, char *addr, char *baseDN,
739 	ns_ldap_error_t **errorp)
740 {
741 	char filter[BUFSIZ];
742 	int rc;
743 	ns_ldap_result_t *result = NULL;
744 	ns_config_t	*ptr = NULL;
745 	ns_config_t	*new_ptr = NULL;
746 	char		errstr[MAXERROR];
747 
748 	*errorp = NULL;
749 	if (baseDN == NULL)
750 		return (NS_LDAP_INVALID_PARAM);
751 
752 	ptr = __s_api_get_default_config();
753 	if (ptr == NULL) {
754 		(void) snprintf(errstr, sizeof (errstr),
755 		    gettext("No configuration information available."));
756 		MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
757 			NULL);
758 		return (NS_LDAP_CONFIG);
759 	}
760 
761 	rc = __ns_ldap_setParamValue(ptr, NS_LDAP_SEARCH_BASEDN_P,
762 				baseDN, errorp);
763 	if (rc != NS_LDAP_SUCCESS) {
764 		__s_api_release_config(ptr);
765 		return (rc);
766 	}
767 
768 	rc = __ns_ldap_setParamValue(ptr, NS_LDAP_SERVERS_P, addr, errorp);
769 	__s_api_release_config(ptr);
770 	if (rc != NS_LDAP_SUCCESS)
771 		return (rc);
772 
773 	(void) snprintf(filter, sizeof (filter), _PROFILE_FILTER,
774 			_PROFILE1_OBJECTCLASS,
775 			_PROFILE2_OBJECTCLASS,
776 			profile);
777 	rc = __ns_ldap_list(_PROFILE_CONTAINER, (const char *)filter,
778 		NULL, NULL, NULL, 0, &result, errorp, NULL, NULL);
779 
780 	if (rc != NS_LDAP_SUCCESS)
781 		return (rc);
782 
783 	new_ptr = __ns_ldap_make_config(result);
784 	(void) __ns_ldap_freeResult(&result);
785 
786 	rc = __s_api_crosscheck(new_ptr, errstr, B_FALSE);
787 	if (rc != NS_LDAP_SUCCESS) {
788 		__s_api_destroy_config(new_ptr);
789 		MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
790 			NULL);
791 		return (NS_LDAP_CONFIG);
792 	}
793 
794 	__s_api_init_config(new_ptr);
795 	return (rc);
796 }
797 
798 /*
799  * **************************************************************
800  * Configuration Printing Routines
801  * **************************************************************
802  */
803 
804 /*
805  * Yes the use of stdio is okay here because all we are doing is sending
806  * output to stdout.  This would not be necessary if we could get to the
807  * configuration pointer outside this file.
808  */
809 ns_ldap_error_t *
810 __ns_ldap_print_config(int verbose)
811 {
812 	ns_config_t	*ptr;
813 	char		errstr[MAXERROR];
814 	ns_ldap_error_t *errorp;
815 	char		string[BUFSIZE];
816 	char		*str;
817 	int		i;
818 
819 	ptr = __s_api_get_default_config();
820 	if (ptr == NULL) {
821 		errorp = __ns_ldap_LoadConfiguration();
822 		if (errorp != NULL)
823 			return (errorp);
824 		ptr = __s_api_get_default_config();
825 		if (ptr == NULL) {
826 			(void) snprintf(errstr, sizeof (errstr),
827 			    gettext("No configuration information."));
828 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
829 				strdup(errstr), NULL);
830 			return (errorp);
831 		}
832 	}
833 
834 	if (verbose && (ptr->domainName != NULL)) {
835 		(void) fputs("ptr->domainName ", stdout);
836 		(void) fputs(ptr->domainName, stdout);
837 		(void) putchar('\n');
838 	}
839 	/* For each parameter - construct value */
840 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
841 			/*
842 			 * Version 1 skipped this entry because:
843 			 *
844 			 * don't print default cache TTL for now since
845 			 * we don't store it in the ldap_client_file.
846 			 */
847 		if ((i == NS_LDAP_CACHETTL_P) && (ptr->version == NS_LDAP_V1))
848 			continue;
849 
850 		str = __s_api_strValue(ptr, string, BUFSIZ, i, NS_FILE_FMT);
851 		if (str == NULL)
852 			continue;
853 		if (verbose)
854 			(void) putchar('\t');
855 		(void) fprintf(stdout, "%s\n", str);
856 		if (str != (char *)&string[0]) {
857 			free(str);
858 			str = NULL;
859 		}
860 	}
861 
862 	__s_api_release_config(ptr);
863 	return (NULL);
864 }
865