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