xref: /illumos-gate/usr/src/lib/libsldap/common/ns_confmgr.c (revision 99dda20867d903eec23291ba1ecb18a82d70096b)
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 2008 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: Out of memory."));
256 		MKERROR(LOG_ERR, error, NS_CONFIG_NOTLOADED,
257 		    strdup(errstr), NULL);
258 		return (error);
259 	}
260 
261 	/* Load in Configuration file */
262 	ret = read_file(ptr, 0, &error);
263 	if (ret != NS_SUCCESS) {
264 		__s_api_destroy_config(ptr);
265 		return (error);
266 	}
267 
268 	/* Load in Credential file */
269 	ret = read_file(ptr, 1, &error);
270 	if (ret != NS_SUCCESS) {
271 		__s_api_destroy_config(ptr);
272 		return (error);
273 	}
274 
275 	if (__s_api_crosscheck(ptr, errstr, B_TRUE) != NS_SUCCESS) {
276 		__s_api_destroy_config(ptr);
277 		MKERROR(LOG_ERR, error, NS_CONFIG_SYNTAX, strdup(errstr), NULL);
278 		return (error);
279 	}
280 
281 	__s_api_init_config(ptr);
282 	return (NULL);
283 }
284 
285 
286 static int
287 _print2buf(LineBuf *line, char *toprint, int addsep)
288 {
289 	int	newsz = 0;
290 	int	newmax = 0;
291 	char	*str;
292 
293 	if (line == NULL)
294 		return (-1);
295 
296 	newsz = strlen(toprint) + line->len + 1;
297 	if (addsep) {
298 		newsz += strlen(DOORLINESEP);
299 	}
300 	if (line->alloc == 0 || newsz > line->alloc) {
301 		/* Round up to next buffer and add 1 */
302 		newmax = (((newsz+(BUFSIZ-1))/BUFSIZ)+1) * BUFSIZ;
303 		if (line->alloc == 0)
304 			line->str = (char *)calloc(newmax, 1);
305 		else {
306 			/*
307 			 * if realloc() returns NULL,
308 			 * the original buffer is untouched.
309 			 * It needs to be freed.
310 			 */
311 			str = (char *)realloc(line->str, newmax);
312 			if (str == NULL) {
313 				free(line->str);
314 				line->str = NULL;
315 			}
316 			else
317 				line->str = str;
318 		}
319 		line->alloc = newmax;
320 		if (line->str == NULL) {
321 			line->alloc = 0;
322 			line->len = 0;
323 			return (-1);
324 		}
325 	}
326 	/* now add new 'toprint' data to buffer */
327 	(void) strlcat(line->str, toprint, line->alloc);
328 	if (addsep) {
329 		(void) strlcat(line->str, DOORLINESEP, line->alloc);
330 	}
331 	line->len = newsz;
332 	return (0);
333 }
334 
335 
336 /*
337  * __ns_ldap_LoadDoorInfo is a routine used by the ldapcachemgr
338  * to create a configuration buffer to transmit back to a client
339  * domainname is transmitted to ldapcachemgr and ldapcachemgr uses
340  * it to select a configuration to transmit back.  Otherwise it
341  * is essentially unused in sldap.
342  */
343 
344 ns_ldap_error_t *
345 __ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname)
346 {
347 	ns_config_t	*ptr;
348 	char		errstr[MAXERROR];
349 	ns_ldap_error_t	*errorp;
350 	char		string[BUFSIZE];
351 	char		*str;
352 	ParamIndexType	i = 0;
353 
354 	ptr = __s_api_get_default_config();
355 	if (ptr == NULL) {
356 		(void) snprintf(errstr, sizeof (errstr),
357 		    gettext("No configuration information available for %s."),
358 		    domainname == NULL ? "<no domain specified>" : domainname);
359 		MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
360 		    strdup(errstr), NULL);
361 		return (errorp);
362 	}
363 	(void) memset((char *)configinfo, 0, sizeof (LineBuf));
364 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
365 		str = __s_api_strValue(ptr, string, sizeof (string), i,
366 		    NS_DOOR_FMT);
367 		if (str == NULL)
368 			continue;
369 		if (_print2buf(configinfo, str, 1) != 0) {
370 			(void) snprintf(errstr, sizeof (errstr),
371 			    gettext("_print2buf: Out of memory."));
372 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
373 			    strdup(errstr), NULL);
374 			__s_api_release_config(ptr);
375 			if (str != (char *)&string[0]) {
376 				free(str);
377 				str = NULL;
378 			}
379 			return (errorp);
380 		}
381 		if (str != (char *)&string[0]) {
382 			free(str);
383 			str = NULL;
384 		}
385 	}
386 	__s_api_release_config(ptr);
387 	return (NULL);
388 }
389 
390 
391 ns_ldap_error_t *
392 __ns_ldap_DumpLdif(char *filename)
393 {
394 	ns_config_t	*ptr;
395 	char		errstr[MAXERROR];
396 	ns_ldap_error_t	*errorp;
397 	char		string[BUFSIZE];
398 	char		*str;
399 	FILE		*fp;
400 	ParamIndexType	i = 0;
401 	char		*profile, *container, *base;
402 
403 	ptr = __s_api_get_default_config();
404 	if (ptr == NULL) {
405 		(void) snprintf(errstr, sizeof (errstr),
406 		    gettext("No configuration information available."));
407 		MKERROR(LOG_ERR, errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
408 		    NULL);
409 		return (errorp);
410 	}
411 
412 	if (filename == NULL) {
413 		fp = stdout;
414 	} else {
415 		fp = fopen(filename, "wF");
416 		if (fp == NULL) {
417 			(void) snprintf(errstr, sizeof (errstr),
418 			    gettext("Unable to open filename %s for ldif "
419 			    "dump (errno=%d)."), filename, errno);
420 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_FILE,
421 			    strdup(errstr), NULL);
422 			__s_api_release_config(ptr);
423 			return (errorp);
424 		}
425 		(void) fchmod(fileno(fp), 0444);
426 	}
427 
428 	if (ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_ptype != CHARPTR ||
429 	    ptr->paramList[NS_LDAP_PROFILE_P].ns_ptype != CHARPTR) {
430 		(void) snprintf(errstr, sizeof (errstr),
431 		    gettext("Required BaseDN and/or Profile name "
432 		    "ldif fields not present"));
433 		MKERROR(LOG_WARNING, errorp, NS_CONFIG_FILE, strdup(errstr),
434 		    NULL);
435 		__s_api_release_config(ptr);
436 		return (errorp);
437 	}
438 
439 	profile = ptr->paramList[NS_LDAP_PROFILE_P].ns_pc;
440 	base = ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_pc;
441 	container = _PROFILE_CONTAINER;
442 
443 	/*
444 	 * Construct DN, but since this is the profile, there is no need
445 	 * to worry about mapping.  The profile itself can not be mapped
446 	 */
447 	(void) fprintf(fp, "dn: cn=%s,ou=%s,%s\n", profile, container, base);
448 
449 	/* dump objectclass names */
450 	if (ptr->version == NS_LDAP_V1) {
451 		(void) fprintf(fp, "ObjectClass: top\nObjectClass: %s\n",
452 		    _PROFILE1_OBJECTCLASS);
453 	} else {
454 		(void) fprintf(fp, "ObjectClass: top\nObjectClass: %s\n",
455 		    _PROFILE2_OBJECTCLASS);
456 	}
457 
458 	/* For each parameter - construct value */
459 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
460 		str = __s_api_strValue(ptr, string, BUFSIZ, i, NS_LDIF_FMT);
461 		if (str == NULL)
462 			continue;
463 		/*
464 		 * don't dump binddn, bind password, or cert path as they
465 		 * are not part of version 2 profiles
466 		 */
467 		if ((i != NS_LDAP_BINDDN_P) && (i != NS_LDAP_BINDPASSWD_P) &&
468 		    (i != NS_LDAP_HOST_CERTPATH_P))
469 			(void) fprintf(fp, "%s\n", str);
470 		if (str != (char *)&string[0]) {
471 			free(str);
472 			str = NULL;
473 		}
474 	}
475 
476 	if (filename != NULL)
477 		(void) fclose(fp);
478 
479 	__s_api_release_config(ptr);
480 	return (NULL);
481 }
482 
483 /*
484  * This routine can process the configuration  and/or
485  * the credential files at the same time.
486  * files is char *[3] = { "config", "cred", NULL };
487  */
488 
489 static
490 ns_ldap_error_t *
491 __ns_ldap_DumpConfigFiles(char **files)
492 {
493 	char		*filename;
494 	int		fi;
495 	int		docred;
496 	ns_config_t	*ptr;
497 	char		string[BUFSIZE];
498 	char		*str;
499 	char		errstr[MAXERROR];
500 	ParamIndexType	i = 0;
501 	FILE		*fp;
502 	int		rc;
503 	ns_ldap_error_t	*errorp = NULL;
504 	struct stat	buf;
505 	int		cfgtype;
506 	boolean_t	file_export_error = B_FALSE;
507 
508 	ptr = __s_api_get_default_config();
509 	if (ptr == NULL) {
510 		(void) snprintf(errstr, sizeof (errstr),
511 		    gettext("No configuration information available."));
512 		MKERROR(LOG_ERR, errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
513 		    NULL);
514 		return (errorp);
515 	}
516 
517 	for (fi = 0; fi < 2; fi++) {
518 		docred = 0;
519 		filename = files[fi];
520 		if (filename == NULL)
521 			continue;
522 		if (fi == 1)
523 			docred++;
524 		rc = stat(filename, &buf);
525 		fp = fopen(filename, "wF");
526 		if (fp == NULL) {
527 			(void) snprintf(errstr, sizeof (errstr),
528 			    gettext("Unable to open filename %s"
529 			    " for configuration dump (%s)."),
530 			    filename, strerror(errno));
531 			MKERROR(LOG_ERR, errorp, NS_CONFIG_FILE,
532 			    strdup(errstr), NULL);
533 			__s_api_release_config(ptr);
534 			return (errorp);
535 		}
536 		if (rc == 0) {
537 			if (fchmod(fileno(fp), buf.st_mode) != 0) {
538 				(void) snprintf(errstr, sizeof (errstr),
539 				    gettext("Unable to set permissions for file"
540 				    " %s for configuration dump (%s)."),
541 				    filename, strerror(errno));
542 				(void) fclose(fp);
543 				file_export_error = B_TRUE;
544 				break;
545 			}
546 		} else {
547 			if (fchmod(fileno(fp), 0400) != 0) {
548 				(void) snprintf(errstr, sizeof (errstr),
549 				    gettext("Unable to set permissions for file"
550 				    " %s for configuration dump (%s)."),
551 				    filename, strerror(errno));
552 				(void) fclose(fp);
553 				file_export_error = B_TRUE;
554 				break;
555 			}
556 		}
557 		if (fprintf(fp, "#\n# %s\n#\n", DONOTEDIT) < 0) {
558 			(void) snprintf(errstr, sizeof (errstr), gettext(
559 			    "Writing to file %s for configuration dump failed "
560 			    "(%s)."), filename, strerror(errno));
561 			file_export_error = B_TRUE;
562 		}
563 
564 		/* assume VERSION is set and it outputs first */
565 
566 		/* For each parameter - construct value */
567 		for (i = 0; !file_export_error && (i <= NS_LDAP_MAX_PIT_P);
568 		    i++) {
569 			cfgtype = __s_api_get_configtype(i);
570 			if ((docred == 0 && cfgtype == CREDCONFIG) ||
571 			    (docred == 1 && cfgtype != CREDCONFIG))
572 				continue;
573 
574 			str = __s_api_strValue(ptr, string, BUFSIZ, i,
575 			    NS_FILE_FMT);
576 			if (str == NULL)
577 				continue;
578 			if (fprintf(fp, "%s\n", str) < 0) {
579 				(void) snprintf(errstr, sizeof (errstr),
580 				    gettext("Writing to file %s for"
581 				    "configuration dump failed (%s)."),
582 				    filename, strerror(errno));
583 				file_export_error = B_TRUE;
584 			}
585 
586 			if (str != (char *)&string[0]) {
587 				free(str);
588 				str = NULL;
589 			}
590 		}
591 		if (fclose(fp) != 0) {
592 			/* Break if error already hit */
593 			if (file_export_error)
594 				break;
595 
596 			(void) snprintf(errstr, sizeof (errstr), gettext(
597 			    "Writing to file %s for configuration dump failed "
598 			    "during file close (%s)."), filename,
599 			    strerror(errno));
600 			file_export_error = B_TRUE;
601 			break;
602 		}
603 
604 	}
605 
606 	if (file_export_error) {
607 		MKERROR(LOG_ERR, errorp, NS_CONFIG_FILE,
608 		    strdup(errstr), NULL);
609 		(void) unlink(filename);
610 	}
611 
612 	__s_api_release_config(ptr);
613 	return (errorp);
614 }
615 
616 ns_ldap_error_t *
617 __ns_ldap_DumpConfiguration(char *file)
618 {
619 	ns_ldap_error_t	*ret;
620 	char		*files[3];
621 
622 	files[0] = NULL;
623 	files[1] = NULL;
624 	files[2] = NULL;
625 	if (strcmp(file, NSCONFIGFILE) == 0) {
626 		files[0] = file;
627 	} else if (strcmp(file, NSCONFIGREFRESH) == 0) {
628 		files[0] = file;
629 	} else if (strcmp(file, NSCREDFILE) == 0) {
630 		files[1] = file;
631 	} else if (strcmp(file, NSCREDREFRESH) == 0) {
632 		files[1] = file;
633 	}
634 	ret = __ns_ldap_DumpConfigFiles(files);
635 	return (ret);
636 }
637 
638 /*
639  * **************************************************************
640  * Misc Routines
641  * **************************************************************
642  */
643 
644 ns_config_t *
645 __ns_ldap_make_config(ns_ldap_result_t *result)
646 {
647 	int		l, m;
648 	char		val[BUFSIZ];
649 	char    	*attrname;
650 	ns_ldap_entry_t	*entry;
651 	ns_ldap_attr_t	*attr;
652 	char		**attrval;
653 	ParamIndexType	index;
654 	ns_config_t	*ptr;
655 	ns_ldap_error_t	*error = NULL;
656 	int		firsttime;
657 	int		prof_ver;
658 	ns_config_t	*curr_ptr = NULL;
659 	char		errstr[MAXERROR];
660 	ns_ldap_error_t	*errorp;
661 
662 	if (result == NULL)
663 		return (NULL);
664 
665 	if (result->entries_count > 1) {
666 		(void) snprintf(errstr, MAXERROR,
667 		    gettext("Configuration Error: More than one profile "
668 		    "found"));
669 		MKERROR(LOG_ERR, errorp, NS_PARSE_ERR, strdup(errstr), NULL);
670 		(void) __ns_ldap_freeError(&errorp);
671 		return (NULL);
672 	}
673 
674 	ptr = __s_api_create_config();
675 	if (ptr == NULL)
676 		return (NULL);
677 
678 	curr_ptr = __s_api_get_default_config();
679 	if (curr_ptr == NULL) {
680 		__s_api_destroy_config(ptr);
681 		return (NULL);
682 	}
683 
684 	/* Check to see if the profile is version 1 or version 2 */
685 	prof_ver = 1;
686 	entry = result->entry;
687 	for (l = 0; l < entry->attr_count; l++) {
688 		attr = entry->attr_pair[l];
689 
690 		attrname = attr->attrname;
691 		if (attrname == NULL)
692 			continue;
693 		if (strcasecmp(attrname, "objectclass") == 0) {
694 			for (m = 0; m < attr->value_count; m++) {
695 				if (strcasecmp(_PROFILE2_OBJECTCLASS,
696 				    attr->attrvalue[m]) == 0) {
697 					prof_ver = 2;
698 					break;
699 				}
700 			}
701 		}
702 	}
703 	/* update the configuration to accept v1 or v2 attributes */
704 	if (prof_ver == 1) {
705 		(void) strcpy(val, NS_LDAP_VERSION_1);
706 		(void) __ns_ldap_setParamValue(ptr, NS_LDAP_FILE_VERSION_P,
707 		    val, &error);
708 	} else {
709 		(void) strcpy(val, NS_LDAP_VERSION_2);
710 		(void) __ns_ldap_setParamValue(ptr, NS_LDAP_FILE_VERSION_P,
711 		    val, &error);
712 	}
713 
714 	for (l = 0; l < entry->attr_count; l++) {
715 		attr = entry->attr_pair[l];
716 
717 		attrname = attr->attrname;
718 		if (attrname == NULL)
719 			continue;
720 		if (__s_api_get_profiletype(attrname, &index) != 0)
721 			continue;
722 
723 		attrval = attr->attrvalue;
724 		switch (index) {
725 		case NS_LDAP_SEARCH_DN_P:
726 		case NS_LDAP_SERVICE_SEARCH_DESC_P:
727 		case NS_LDAP_ATTRIBUTEMAP_P:
728 		case NS_LDAP_OBJECTCLASSMAP_P:
729 		case NS_LDAP_SERVICE_CRED_LEVEL_P:
730 		case NS_LDAP_SERVICE_AUTH_METHOD_P:
731 			/* Multiple Value - insert 1 at a time */
732 			for (m = 0; m < attr->value_count; m++) {
733 				(void) __ns_ldap_setParamValue(ptr, index,
734 				    attrval[m], &error);
735 			}
736 			break;
737 		default:
738 			firsttime = 1;
739 			/* Single or Multiple Value */
740 			val[0] = '\0';
741 			for (m = 0; m < attr->value_count; m++) {
742 				if (firsttime == 1) {
743 					firsttime = 0;
744 					(void) strlcpy(val, attrval[m],
745 					    sizeof (val));
746 				} else {
747 					(void) strlcat(val, " ", sizeof (val));
748 					(void) strlcat(val, attrval[m],
749 					    sizeof (val));
750 				}
751 			}
752 			(void) __ns_ldap_setParamValue(ptr, index, val, &error);
753 
754 			break;
755 		}
756 	}
757 	if (ptr->version != NS_LDAP_V1) {
758 		if (curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_ptype == CHARPTR) {
759 			(void) __ns_ldap_setParamValue(ptr, NS_LDAP_BINDDN_P,
760 			    curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_pc,
761 			    &error);
762 		}
763 		if (curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_ptype ==
764 		    CHARPTR) {
765 			(void) __ns_ldap_setParamValue(ptr,
766 			    NS_LDAP_BINDPASSWD_P,
767 			    curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_pc,
768 			    &error);
769 		}
770 		if (curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_ptype ==
771 		    CHARPTR) {
772 			(void) __ns_ldap_setParamValue(ptr,
773 			    NS_LDAP_HOST_CERTPATH_P,
774 			    curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_pc,
775 			    &error);
776 		}
777 	}
778 	__s_api_release_config(curr_ptr);
779 	return (ptr);
780 }
781 
782 /*
783  * Download a profile into our internal structure.  The calling application
784  * needs to DumpConfig() to save the information to NSCONFIGFILE and NSCREDFILE
785  * if desired.
786  */
787 int
788 __ns_ldap_download(const char *profile, char *addr, char *baseDN,
789 	ns_ldap_error_t **errorp)
790 {
791 	char filter[BUFSIZ];
792 	int rc;
793 	ns_ldap_result_t *result = NULL;
794 	ns_config_t	*ptr = NULL;
795 	ns_config_t	*new_ptr = NULL;
796 	char		errstr[MAXERROR];
797 
798 	*errorp = NULL;
799 	if (baseDN == NULL)
800 		return (NS_LDAP_INVALID_PARAM);
801 
802 	ptr = __s_api_get_default_config();
803 	if (ptr == NULL) {
804 		(void) snprintf(errstr, sizeof (errstr),
805 		    gettext("No configuration information available."));
806 		MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
807 		    NULL);
808 		return (NS_LDAP_CONFIG);
809 	}
810 
811 	rc = __ns_ldap_setParamValue(ptr, NS_LDAP_SEARCH_BASEDN_P, baseDN,
812 	    errorp);
813 	if (rc != NS_LDAP_SUCCESS) {
814 		__s_api_release_config(ptr);
815 		return (rc);
816 	}
817 
818 	rc = __ns_ldap_setParamValue(ptr, NS_LDAP_SERVERS_P, addr, errorp);
819 	__s_api_release_config(ptr);
820 	if (rc != NS_LDAP_SUCCESS)
821 		return (rc);
822 
823 	(void) snprintf(filter, sizeof (filter), _PROFILE_FILTER,
824 	    _PROFILE1_OBJECTCLASS, _PROFILE2_OBJECTCLASS, profile);
825 	rc = __ns_ldap_list(_PROFILE_CONTAINER, (const char *)filter,
826 	    NULL, NULL, NULL, 0, &result, errorp, NULL, NULL);
827 
828 	if (rc != NS_LDAP_SUCCESS)
829 		return (rc);
830 
831 	new_ptr = __ns_ldap_make_config(result);
832 	(void) __ns_ldap_freeResult(&result);
833 
834 	if (new_ptr == NULL)
835 		return (NS_LDAP_OP_FAILED);
836 
837 	rc = __s_api_crosscheck(new_ptr, errstr, B_FALSE);
838 	if (rc != NS_LDAP_SUCCESS) {
839 		__s_api_destroy_config(new_ptr);
840 		MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
841 		    NULL);
842 		return (NS_LDAP_CONFIG);
843 	}
844 
845 	__s_api_init_config(new_ptr);
846 	return (rc);
847 }
848 
849 /*
850  * **************************************************************
851  * Configuration Printing Routines
852  * **************************************************************
853  */
854 
855 /*
856  * Yes the use of stdio is okay here because all we are doing is sending
857  * output to stdout.  This would not be necessary if we could get to the
858  * configuration pointer outside this file.
859  */
860 ns_ldap_error_t *
861 __ns_ldap_print_config(int verbose)
862 {
863 	ns_config_t	*ptr;
864 	char		errstr[MAXERROR];
865 	ns_ldap_error_t *errorp;
866 	char		string[BUFSIZE];
867 	char		*str;
868 	int		i;
869 
870 	ptr = __s_api_get_default_config();
871 	if (ptr == NULL) {
872 		errorp = __ns_ldap_LoadConfiguration();
873 		if (errorp != NULL)
874 			return (errorp);
875 		ptr = __s_api_get_default_config();
876 		if (ptr == NULL) {
877 			(void) snprintf(errstr, sizeof (errstr),
878 			    gettext("No configuration information."));
879 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
880 			    strdup(errstr), NULL);
881 			return (errorp);
882 		}
883 	}
884 
885 	if (verbose && (ptr->domainName != NULL)) {
886 		(void) fputs("ptr->domainName ", stdout);
887 		(void) fputs(ptr->domainName, stdout);
888 		(void) putchar('\n');
889 	}
890 	/* For each parameter - construct value */
891 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
892 			/*
893 			 * Version 1 skipped this entry because:
894 			 *
895 			 * don't print default cache TTL for now since
896 			 * we don't store it in the ldap_client_file.
897 			 */
898 		if ((i == NS_LDAP_CACHETTL_P) && (ptr->version == NS_LDAP_V1))
899 			continue;
900 
901 		str = __s_api_strValue(ptr, string, BUFSIZ, i, NS_FILE_FMT);
902 		if (str == NULL)
903 			continue;
904 		if (verbose)
905 			(void) putchar('\t');
906 		(void) fprintf(stdout, "%s\n", str);
907 		if (str != (char *)&string[0]) {
908 			free(str);
909 			str = NULL;
910 		}
911 	}
912 
913 	__s_api_release_config(ptr);
914 	return (NULL);
915 }
916