xref: /titanic_51/usr/src/lib/libsldap/common/ns_confmgr.c (revision 521f69c05c5de4e5f848122e2fc5b8f1c6a9e0c6)
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), NULL);
127 		return (NS_NOTFOUND);
128 	}
129 
130 	emptyfile = 1;
131 	lineno = 0;
132 	for (; ; ) {
133 		if ((linelen = read_line(fp, buffer, sizeof (buffer),
134 		    errstr)) < 0)
135 			/* End of file */
136 			break;
137 		lineno++;
138 		if (linelen == 0)
139 			continue;
140 		/* get rid of comment lines */
141 		if (buffer[0] == '#')
142 			continue;
143 		emptyfile = 0;
144 		name = NULL;
145 		value = NULL;
146 		__s_api_split_key_value(buffer, &name, &value);
147 		if (name == NULL || value == NULL) {
148 			(void) snprintf(errstr, sizeof (errstr),
149 			    gettext("Missing Name or Value on line %d."),
150 			    lineno);
151 			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
152 			    strdup(errstr), NULL);
153 			(void) fclose(fp);
154 			return (NS_PARSE_ERR);
155 		}
156 		if (__s_api_get_versiontype(ptr, name, &i) != 0) {
157 			(void) snprintf(errstr, sizeof (errstr),
158 			    gettext("Illegal profile type on line %d."),
159 			    lineno);
160 			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
161 			    strdup(errstr), NULL);
162 			(void) fclose(fp);
163 			return (NS_PARSE_ERR);
164 		}
165 		if (!first && i == NS_LDAP_FILE_VERSION_P) {
166 			(void) snprintf(errstr, sizeof (errstr),
167 			    gettext("Illegal NS_LDAP_FILE_VERSION "
168 			    "on line %d."), lineno);
169 			MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
170 			    strdup(errstr), NULL);
171 			(void) fclose(fp);
172 			return (NS_PARSE_ERR);
173 		}
174 		first = 0;
175 		switch (__s_api_get_configtype(i)) {
176 		case SERVERCONFIG:
177 		case CLIENTCONFIG:
178 			if (cred_file == 0) {
179 				ret = __ns_ldap_setParamValue(ptr, i, value,
180 				    error);
181 				if (ret != NS_SUCCESS) {
182 					(void) fclose(fp);
183 					return (ret);
184 				}
185 			} else if (i != NS_LDAP_FILE_VERSION_P) {
186 				(void) snprintf(errstr, sizeof (errstr),
187 				    gettext("Illegal entry in '%s' on "
188 				    "line %d"), file, lineno);
189 				MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
190 				    strdup(errstr), NULL);
191 				(void) fclose(fp);
192 				return (NS_PARSE_ERR);
193 			}
194 			break;
195 		case CREDCONFIG:
196 			if (i == NS_LDAP_FILE_VERSION_P)
197 				break;
198 			if (cred_file) {
199 				ret = __ns_ldap_setParamValue(ptr, i, value,
200 				    error);
201 				if (ret != NS_SUCCESS) {
202 					(void) fclose(fp);
203 					return (ret);
204 				}
205 			} else {
206 				(void) snprintf(errstr, sizeof (errstr),
207 				    gettext("Illegal entry in '%s' on "
208 				    "line %d"), file, lineno);
209 				MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
210 				    strdup(errstr), NULL);
211 				(void) fclose(fp);
212 				return (NS_PARSE_ERR);
213 			}
214 		}
215 	}
216 	(void) fclose(fp);
217 	if (!cred_file && emptyfile) {
218 		/* Error in read_line */
219 		(void) snprintf(errstr, sizeof (errstr),
220 		    gettext("Empty config file: '%s'"), file);
221 		MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
222 		    NULL);
223 		return (NS_PARSE_ERR);
224 	}
225 	if (linelen == -2) {
226 		/* Error in read_line */
227 		(void) snprintf(errstr, sizeof (errstr),
228 		    gettext("Line too long in '%s'"), file);
229 		MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
230 		    NULL);
231 		return (NS_PARSE_ERR);
232 	}
233 	return (NS_SUCCESS);
234 }
235 
236 
237 static
238 ns_ldap_return_code
239 set_attr(ns_config_t *config_struct,
240 		char *attr_name,
241 		char *attr_val,
242 		ns_ldap_error_t **errorp)
243 {
244 	ParamIndexType	idx;
245 	char		errmsg[MAXERROR];
246 
247 	if (errorp == NULL) {
248 		return (NS_LDAP_INVALID_PARAM);
249 	}
250 
251 	*errorp = NULL;
252 
253 	/*
254 	 * This double call is made due to the presence of
255 	 * two sets of LDAP config. attribute names.
256 	 * An LDAP configuration can be obtained either from a server
257 	 * or from SMF. The former sends a DUA with attributes' names
258 	 * styled like "preferredServerList". But local configurations
259 	 * will have names inherited from the /var/ldap/ldap* files such as
260 	 * "NS_LDAP_SERVER_PREF".
261 	 * So, the standalone bits are able to process both sets of
262 	 * attributes' names.
263 	 */
264 	if (__s_api_get_profiletype(attr_name, &idx) < 0 &&
265 	    __s_api_get_versiontype(config_struct, attr_name, &idx) < 0) {
266 		(void) snprintf(errmsg, sizeof (errmsg),
267 		    gettext("Illegal DUAProfile property: <%s>."), attr_name);
268 		MKERROR(LOG_ERR, *errorp, NS_LDAP_CONFIG, strdup(errmsg), NULL);
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 static int
411 _print2buf(LineBuf *line, char *toprint, int addsep)
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 (addsep) {
422 		newsz += strlen(DOORLINESEP);
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 (addsep) {
453 		(void) strlcat(line->str, DOORLINESEP, 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  */
467 
468 ns_ldap_error_t *
469 __ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname, ns_config_t *new)
470 {
471 	ns_config_t	*ptr;
472 	char		errstr[MAXERROR];
473 	ns_ldap_error_t	*errorp;
474 	char		string[BUFSIZE];
475 	char		*str;
476 	ParamIndexType	i = 0;
477 	int		len;
478 	ldap_config_out_t *cout;
479 
480 	/*
481 	 * If new is NULL, it outputs the flatten data of current default
482 	 * config, if it's non-NULL, it outputs the flatten data of a temporary
483 	 * config. It's used to compare the new config data with the current
484 	 * default config data.
485 	 */
486 	if (new == NULL)
487 		ptr = __s_api_get_default_config();
488 	else
489 		ptr = new;
490 	if (ptr == NULL) {
491 		(void) snprintf(errstr, sizeof (errstr),
492 		    gettext("No configuration information available for %s."),
493 		    domainname == NULL ? "<no domain specified>" : domainname);
494 		MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
495 		    strdup(errstr), NULL);
496 		return (errorp);
497 	}
498 	(void) memset((char *)configinfo, 0, sizeof (LineBuf));
499 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
500 		/* the credential for shadow update is not to be exposed */
501 		if (i == NS_LDAP_ADMIN_BINDDN_P ||
502 		    i == NS_LDAP_ADMIN_BINDPASSWD_P)
503 			continue;
504 		str = __s_api_strValue(ptr, string, sizeof (string), i,
505 		    NS_DOOR_FMT);
506 		if (str == NULL)
507 			continue;
508 		if (_print2buf(configinfo, str, 1) != 0) {
509 			(void) snprintf(errstr, sizeof (errstr),
510 			    gettext("_print2buf: Out of memory."));
511 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
512 			    strdup(errstr), NULL);
513 			__s_api_release_config(ptr);
514 			if (str != (char *)&string[0]) {
515 				free(str);
516 				str = NULL;
517 			}
518 			return (errorp);
519 		}
520 		if (str != (char *)&string[0]) {
521 			free(str);
522 			str = NULL;
523 		}
524 	}
525 	if (new == NULL)
526 		__s_api_release_config(ptr);
527 
528 	/*
529 	 * The new interface of the configuration between ldap_cachemgr
530 	 * & libsldap contains a header structure ldap_config_out_t.
531 	 * The flatten configuration data configinfo->str is cloned
532 	 * to cout->config_str, configinfo->len is saved in
533 	 * cout->data_size and cout->cookie is set later after this function
534 	 * is returned in ldap_cachemgr.
535 	 * configinfo->str & configinfo->len are reused to save info of
536 	 * header + data.
537 	 * The format:
538 	 * [cookie|data_size|config_str .............]
539 	 */
540 
541 	if (configinfo->str) {
542 		len = sizeof (ldap_config_out_t) - sizeof (int) +
543 		    configinfo->len;
544 		if ((cout = calloc(1, len)) == NULL) {
545 			free(configinfo->str);
546 			configinfo->str = NULL;
547 			configinfo->len = 0;
548 			(void) snprintf(errstr, sizeof (errstr),
549 			    gettext("calloc: Out of memory."));
550 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
551 			    strdup(errstr), NULL);
552 			return (errorp);
553 		}
554 		/*
555 		 * cout->cookie is set by the caller,
556 		 * which is in ldap_cachemgr.
557 		 */
558 		cout->data_size = configinfo->len;
559 		(void) memcpy(cout->config_str, configinfo->str,
560 		    configinfo->len);
561 		free(configinfo->str);
562 		configinfo->str = (char *)cout;
563 		configinfo->len = len;
564 	}
565 	return (NULL);
566 }
567 
568 
569 ns_ldap_error_t *
570 __ns_ldap_DumpLdif(char *filename)
571 {
572 	ns_config_t	*ptr;
573 	char		errstr[MAXERROR];
574 	ns_ldap_error_t	*errorp;
575 	char		string[BUFSIZE];
576 	char		*str;
577 	FILE		*fp;
578 	ParamIndexType	i = 0;
579 	char		*profile, *container, *base;
580 
581 	ptr = __s_api_get_default_config();
582 	if (ptr == NULL) {
583 		(void) snprintf(errstr, sizeof (errstr),
584 		    gettext("No configuration information available."));
585 		MKERROR(LOG_ERR, errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
586 		    NULL);
587 		return (errorp);
588 	}
589 
590 	if (filename == NULL) {
591 		fp = stdout;
592 	} else {
593 		fp = fopen(filename, "wF");
594 		if (fp == NULL) {
595 			(void) snprintf(errstr, sizeof (errstr),
596 			    gettext("Unable to open filename %s for ldif "
597 			    "dump (errno=%d)."), filename, errno);
598 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_FILE,
599 			    strdup(errstr), NULL);
600 			__s_api_release_config(ptr);
601 			return (errorp);
602 		}
603 		(void) fchmod(fileno(fp), 0444);
604 	}
605 
606 	if (ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_ptype != CHARPTR ||
607 	    ptr->paramList[NS_LDAP_PROFILE_P].ns_ptype != CHARPTR) {
608 		(void) snprintf(errstr, sizeof (errstr),
609 		    gettext("Required BaseDN and/or Profile name "
610 		    "ldif fields not present"));
611 		MKERROR(LOG_WARNING, errorp, NS_CONFIG_FILE, strdup(errstr),
612 		    NULL);
613 		__s_api_release_config(ptr);
614 		return (errorp);
615 	}
616 
617 	profile = ptr->paramList[NS_LDAP_PROFILE_P].ns_pc;
618 	base = ptr->paramList[NS_LDAP_SEARCH_BASEDN_P].ns_pc;
619 	container = _PROFILE_CONTAINER;
620 
621 	/*
622 	 * Construct DN, but since this is the profile, there is no need
623 	 * to worry about mapping.  The profile itself can not be mapped
624 	 */
625 	(void) fprintf(fp, "dn: cn=%s,ou=%s,%s\n", profile, container, base);
626 
627 	/* dump objectclass names */
628 	if (ptr->version == NS_LDAP_V1) {
629 		(void) fprintf(fp, "ObjectClass: top\nObjectClass: %s\n",
630 		    _PROFILE1_OBJECTCLASS);
631 	} else {
632 		(void) fprintf(fp, "ObjectClass: top\nObjectClass: %s\n",
633 		    _PROFILE2_OBJECTCLASS);
634 	}
635 
636 	/* For each parameter - construct value */
637 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
638 		str = __s_api_strValue(ptr, string, BUFSIZ, i, NS_LDIF_FMT);
639 		if (str == NULL)
640 			continue;
641 		/*
642 		 * don't dump binddn, bind password, admin binddn, admin
643 		 * bind password, enableShadowUpdate flag, or cert path
644 		 * as they are not part of version 2 profiles
645 		 */
646 		if ((i != NS_LDAP_BINDDN_P) &&
647 		    (i != NS_LDAP_BINDPASSWD_P) &&
648 		    (i != NS_LDAP_ADMIN_BINDDN_P) &&
649 		    (i != NS_LDAP_ADMIN_BINDPASSWD_P) &&
650 		    (i != NS_LDAP_ENABLE_SHADOW_UPDATE_P) &&
651 		    (i != NS_LDAP_HOST_CERTPATH_P))
652 			(void) fprintf(fp, "%s\n", str);
653 		if (str != (char *)&string[0]) {
654 			free(str);
655 			str = NULL;
656 		}
657 	}
658 
659 	if (filename != NULL)
660 		(void) fclose(fp);
661 
662 	__s_api_release_config(ptr);
663 	return (NULL);
664 }
665 
666 /*
667  * This routine can process the configuration  and/or
668  * the credential files at the same time.
669  * files is char *[3] = { "config", "cred", NULL };
670  */
671 
672 static
673 ns_ldap_error_t *
674 __ns_ldap_DumpConfigFiles(char **files)
675 {
676 	char		*filename;
677 	int		fi;
678 	int		docred;
679 	ns_config_t	*ptr;
680 	char		string[BUFSIZE];
681 	char		*str;
682 	char		errstr[MAXERROR];
683 	ParamIndexType	i = 0;
684 	FILE		*fp;
685 	int		rc;
686 	ns_ldap_error_t	*errorp = NULL;
687 	struct stat	buf;
688 	int		cfgtype;
689 	boolean_t	file_export_error = B_FALSE;
690 
691 	ptr = __s_api_get_default_config();
692 	if (ptr == NULL) {
693 		(void) snprintf(errstr, sizeof (errstr),
694 		    gettext("No configuration information available."));
695 		MKERROR(LOG_ERR, errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
696 		    NULL);
697 		return (errorp);
698 	}
699 
700 	for (fi = 0; fi < 2; fi++) {
701 		docred = 0;
702 		filename = files[fi];
703 		if (filename == NULL)
704 			continue;
705 		if (fi == 1)
706 			docred++;
707 		rc = stat(filename, &buf);
708 		fp = fopen(filename, "wF");
709 		if (fp == NULL) {
710 			(void) snprintf(errstr, sizeof (errstr),
711 			    gettext("Unable to open filename %s"
712 			    " for configuration dump (%s)."),
713 			    filename, strerror(errno));
714 			MKERROR(LOG_ERR, errorp, NS_CONFIG_FILE,
715 			    strdup(errstr), NULL);
716 			__s_api_release_config(ptr);
717 			return (errorp);
718 		}
719 		if (rc == 0) {
720 			if (fchmod(fileno(fp), buf.st_mode) != 0) {
721 				(void) snprintf(errstr, sizeof (errstr),
722 				    gettext("Unable to set permissions for file"
723 				    " %s for configuration dump (%s)."),
724 				    filename, strerror(errno));
725 				(void) fclose(fp);
726 				file_export_error = B_TRUE;
727 				break;
728 			}
729 		} else {
730 			if (fchmod(fileno(fp), 0400) != 0) {
731 				(void) snprintf(errstr, sizeof (errstr),
732 				    gettext("Unable to set permissions for file"
733 				    " %s for configuration dump (%s)."),
734 				    filename, strerror(errno));
735 				(void) fclose(fp);
736 				file_export_error = B_TRUE;
737 				break;
738 			}
739 		}
740 		if (fprintf(fp, "#\n# %s\n#\n", DONOTEDIT) < 0) {
741 			(void) snprintf(errstr, sizeof (errstr), gettext(
742 			    "Writing to file %s for configuration dump failed "
743 			    "(%s)."), filename, strerror(errno));
744 			file_export_error = B_TRUE;
745 		}
746 
747 		/* assume VERSION is set and it outputs first */
748 
749 		/* For each parameter - construct value */
750 		for (i = 0; !file_export_error && (i <= NS_LDAP_MAX_PIT_P);
751 		    i++) {
752 			cfgtype = __s_api_get_configtype(i);
753 			if ((docred == 0 && cfgtype == CREDCONFIG) ||
754 			    (docred == 1 && cfgtype != CREDCONFIG))
755 				continue;
756 
757 			str = __s_api_strValue(ptr, string, BUFSIZ, i,
758 			    NS_FILE_FMT);
759 			if (str == NULL)
760 				continue;
761 			if (fprintf(fp, "%s\n", str) < 0) {
762 				(void) snprintf(errstr, sizeof (errstr),
763 				    gettext("Writing to file %s for"
764 				    "configuration dump failed (%s)."),
765 				    filename, strerror(errno));
766 				file_export_error = B_TRUE;
767 			}
768 
769 			if (str != (char *)&string[0]) {
770 				free(str);
771 				str = NULL;
772 			}
773 		}
774 		if (fclose(fp) != 0) {
775 			/* Break if error already hit */
776 			if (file_export_error)
777 				break;
778 
779 			(void) snprintf(errstr, sizeof (errstr), gettext(
780 			    "Writing to file %s for configuration dump failed "
781 			    "during file close (%s)."), filename,
782 			    strerror(errno));
783 			file_export_error = B_TRUE;
784 			break;
785 		}
786 
787 	}
788 
789 	if (file_export_error) {
790 		MKERROR(LOG_ERR, errorp, NS_CONFIG_FILE,
791 		    strdup(errstr), NULL);
792 		(void) unlink(filename);
793 	}
794 
795 	__s_api_release_config(ptr);
796 	return (errorp);
797 }
798 
799 ns_ldap_error_t *
800 __ns_ldap_DumpConfiguration(char *file)
801 {
802 	ns_ldap_error_t	*ret;
803 	char		*files[3];
804 
805 	files[0] = NULL;
806 	files[1] = NULL;
807 	files[2] = NULL;
808 	if (strcmp(file, NSCONFIGFILE) == 0) {
809 		files[0] = file;
810 	} else if (strcmp(file, NSCONFIGREFRESH) == 0) {
811 		files[0] = file;
812 	} else if (strcmp(file, NSCREDFILE) == 0) {
813 		files[1] = file;
814 	} else if (strcmp(file, NSCREDREFRESH) == 0) {
815 		files[1] = file;
816 	}
817 	ret = __ns_ldap_DumpConfigFiles(files);
818 	return (ret);
819 }
820 
821 /*
822  * **************************************************************
823  * Misc Routines
824  * **************************************************************
825  */
826 
827 ns_config_t *
828 __ns_ldap_make_config(ns_ldap_result_t *result)
829 {
830 	int		l, m;
831 	char		val[BUFSIZ];
832 	char    	*attrname;
833 	ns_ldap_entry_t	*entry;
834 	ns_ldap_attr_t	*attr;
835 	char		**attrval;
836 	ParamIndexType	index;
837 	ns_config_t	*ptr;
838 	ns_ldap_error_t	*error = NULL;
839 	int		firsttime;
840 	int		prof_ver;
841 	ns_config_t	*curr_ptr = NULL;
842 	char		errstr[MAXERROR];
843 	ns_ldap_error_t	*errorp;
844 
845 	if (result == NULL)
846 		return (NULL);
847 
848 	if (result->entries_count > 1) {
849 		(void) snprintf(errstr, MAXERROR,
850 		    gettext("Configuration Error: More than one profile "
851 		    "found"));
852 		MKERROR(LOG_ERR, errorp, NS_PARSE_ERR, strdup(errstr), NULL);
853 		(void) __ns_ldap_freeError(&errorp);
854 		return (NULL);
855 	}
856 
857 	ptr = __s_api_create_config();
858 	if (ptr == NULL)
859 		return (NULL);
860 
861 	curr_ptr = __s_api_get_default_config();
862 	if (curr_ptr == NULL) {
863 		__s_api_destroy_config(ptr);
864 		return (NULL);
865 	}
866 
867 	/* Check to see if the profile is version 1 or version 2 */
868 	prof_ver = 1;
869 	entry = result->entry;
870 	for (l = 0; l < entry->attr_count; l++) {
871 		attr = entry->attr_pair[l];
872 
873 		attrname = attr->attrname;
874 		if (attrname == NULL)
875 			continue;
876 		if (strcasecmp(attrname, "objectclass") == 0) {
877 			for (m = 0; m < attr->value_count; m++) {
878 				if (strcasecmp(_PROFILE2_OBJECTCLASS,
879 				    attr->attrvalue[m]) == 0) {
880 					prof_ver = 2;
881 					break;
882 				}
883 			}
884 		}
885 	}
886 	/* update the configuration to accept v1 or v2 attributes */
887 	if (prof_ver == 1) {
888 		(void) strcpy(val, NS_LDAP_VERSION_1);
889 		(void) __ns_ldap_setParamValue(ptr, NS_LDAP_FILE_VERSION_P,
890 		    val, &error);
891 	} else {
892 		(void) strcpy(val, NS_LDAP_VERSION_2);
893 		(void) __ns_ldap_setParamValue(ptr, NS_LDAP_FILE_VERSION_P,
894 		    val, &error);
895 	}
896 
897 	for (l = 0; l < entry->attr_count; l++) {
898 		attr = entry->attr_pair[l];
899 
900 		attrname = attr->attrname;
901 		if (attrname == NULL)
902 			continue;
903 		if (__s_api_get_profiletype(attrname, &index) != 0)
904 			continue;
905 
906 		attrval = attr->attrvalue;
907 		switch (index) {
908 		case NS_LDAP_SEARCH_DN_P:
909 		case NS_LDAP_SERVICE_SEARCH_DESC_P:
910 		case NS_LDAP_ATTRIBUTEMAP_P:
911 		case NS_LDAP_OBJECTCLASSMAP_P:
912 		case NS_LDAP_SERVICE_CRED_LEVEL_P:
913 		case NS_LDAP_SERVICE_AUTH_METHOD_P:
914 			/* Multiple Value - insert 1 at a time */
915 			for (m = 0; m < attr->value_count; m++) {
916 				(void) __ns_ldap_setParamValue(ptr, index,
917 				    attrval[m], &error);
918 			}
919 			break;
920 		default:
921 			firsttime = 1;
922 			/* Single or Multiple Value */
923 			val[0] = '\0';
924 			for (m = 0; m < attr->value_count; m++) {
925 				if (firsttime == 1) {
926 					firsttime = 0;
927 					(void) strlcpy(val, attrval[m],
928 					    sizeof (val));
929 				} else {
930 					(void) strlcat(val, " ", sizeof (val));
931 					(void) strlcat(val, attrval[m],
932 					    sizeof (val));
933 				}
934 			}
935 			(void) __ns_ldap_setParamValue(ptr, index, val, &error);
936 
937 			break;
938 		}
939 	}
940 	if (ptr->version != NS_LDAP_V1) {
941 		ParamIndexType i;
942 		if (curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_ptype == CHARPTR) {
943 			(void) __ns_ldap_setParamValue(ptr, NS_LDAP_BINDDN_P,
944 			    curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_pc,
945 			    &error);
946 		}
947 		if (curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_ptype ==
948 		    CHARPTR) {
949 			(void) __ns_ldap_setParamValue(ptr,
950 			    NS_LDAP_BINDPASSWD_P,
951 			    curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_pc,
952 			    &error);
953 		}
954 		i = NS_LDAP_ENABLE_SHADOW_UPDATE_P;
955 		if (curr_ptr->paramList[i].ns_ptype == INT) {
956 			char *val;
957 			val = __s_get_shadowupdate_name(
958 			    curr_ptr->paramList[i].ns_i);
959 			(void) __ns_ldap_setParamValue(ptr, i, val, &error);
960 		}
961 		if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_ptype ==
962 		    CHARPTR) {
963 			(void) __ns_ldap_setParamValue(ptr,
964 			    NS_LDAP_ADMIN_BINDDN_P,
965 			    curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_pc,
966 			    &error);
967 		}
968 		if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_ptype ==
969 		    CHARPTR) {
970 			(void) __ns_ldap_setParamValue(ptr,
971 			    NS_LDAP_ADMIN_BINDPASSWD_P,
972 			    curr_ptr->
973 			    paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_pc,
974 			    &error);
975 		}
976 		if (curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_ptype ==
977 		    CHARPTR) {
978 			(void) __ns_ldap_setParamValue(ptr,
979 			    NS_LDAP_HOST_CERTPATH_P,
980 			    curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_pc,
981 			    &error);
982 		}
983 	}
984 	__s_api_release_config(curr_ptr);
985 	return (ptr);
986 }
987 
988 /*
989  * Download a profile into our internal structure.  The calling application
990  * needs to DumpConfig() to save the information to NSCONFIGFILE and NSCREDFILE
991  * if desired.
992  */
993 int
994 __ns_ldap_download(const char *profile, char *addr, char *baseDN,
995 	ns_ldap_error_t **errorp)
996 {
997 	char filter[BUFSIZ];
998 	int rc;
999 	ns_ldap_result_t *result = NULL;
1000 	ns_config_t	*ptr = NULL;
1001 	ns_config_t	*new_ptr = NULL;
1002 	char		errstr[MAXERROR];
1003 
1004 	*errorp = NULL;
1005 	if (baseDN == NULL)
1006 		return (NS_LDAP_INVALID_PARAM);
1007 
1008 	ptr = __s_api_get_default_config();
1009 	if (ptr == NULL) {
1010 		(void) snprintf(errstr, sizeof (errstr),
1011 		    gettext("No configuration information available."));
1012 		MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
1013 		    NULL);
1014 		return (NS_LDAP_CONFIG);
1015 	}
1016 
1017 	rc = __ns_ldap_setParamValue(ptr, NS_LDAP_SEARCH_BASEDN_P, baseDN,
1018 	    errorp);
1019 	if (rc != NS_LDAP_SUCCESS) {
1020 		__s_api_release_config(ptr);
1021 		return (rc);
1022 	}
1023 
1024 	rc = __ns_ldap_setParamValue(ptr, NS_LDAP_SERVERS_P, addr, errorp);
1025 	__s_api_release_config(ptr);
1026 	if (rc != NS_LDAP_SUCCESS)
1027 		return (rc);
1028 
1029 	(void) snprintf(filter, sizeof (filter), _PROFILE_FILTER,
1030 	    _PROFILE1_OBJECTCLASS, _PROFILE2_OBJECTCLASS, profile);
1031 	rc = __ns_ldap_list(_PROFILE_CONTAINER, (const char *)filter,
1032 	    NULL, NULL, NULL, 0, &result, errorp, NULL, NULL);
1033 
1034 	if (rc != NS_LDAP_SUCCESS)
1035 		return (rc);
1036 
1037 	new_ptr = __ns_ldap_make_config(result);
1038 	(void) __ns_ldap_freeResult(&result);
1039 
1040 	if (new_ptr == NULL)
1041 		return (NS_LDAP_OP_FAILED);
1042 
1043 	rc = __s_api_crosscheck(new_ptr, errstr, B_FALSE);
1044 	if (rc != NS_LDAP_SUCCESS) {
1045 		__s_api_destroy_config(new_ptr);
1046 		MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
1047 		    NULL);
1048 		return (NS_LDAP_CONFIG);
1049 	}
1050 
1051 	__s_api_init_config(new_ptr);
1052 	return (rc);
1053 }
1054 
1055 /*
1056  * **************************************************************
1057  * Configuration Printing Routines
1058  * **************************************************************
1059  */
1060 
1061 /*
1062  * Yes the use of stdio is okay here because all we are doing is sending
1063  * output to stdout.  This would not be necessary if we could get to the
1064  * configuration pointer outside this file.
1065  */
1066 ns_ldap_error_t *
1067 __ns_ldap_print_config(int verbose)
1068 {
1069 	ns_config_t	*ptr;
1070 	char		errstr[MAXERROR];
1071 	ns_ldap_error_t *errorp;
1072 	char		string[BUFSIZE];
1073 	char		*str;
1074 	int		i;
1075 
1076 	ptr = __s_api_get_default_config();
1077 	if (ptr == NULL) {
1078 		errorp = __ns_ldap_LoadConfiguration();
1079 		if (errorp != NULL)
1080 			return (errorp);
1081 		ptr = __s_api_get_default_config();
1082 		if (ptr == NULL) {
1083 			(void) snprintf(errstr, sizeof (errstr),
1084 			    gettext("No configuration information."));
1085 			MKERROR(LOG_WARNING, errorp, NS_CONFIG_NOTLOADED,
1086 			    strdup(errstr), NULL);
1087 			return (errorp);
1088 		}
1089 	}
1090 
1091 	if (verbose && (ptr->domainName != NULL)) {
1092 		(void) fputs("ptr->domainName ", stdout);
1093 		(void) fputs(ptr->domainName, stdout);
1094 		(void) putchar('\n');
1095 	}
1096 	/* For each parameter - construct value */
1097 	for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
1098 			/*
1099 			 * Version 1 skipped this entry because:
1100 			 *
1101 			 * don't print default cache TTL for now since
1102 			 * we don't store it in the ldap_client_file.
1103 			 */
1104 		if ((i == NS_LDAP_CACHETTL_P) && (ptr->version == NS_LDAP_V1))
1105 			continue;
1106 
1107 		/* the credential for shadow update is not to be exposed */
1108 		if (i == NS_LDAP_ADMIN_BINDDN_P ||
1109 		    i == NS_LDAP_ADMIN_BINDPASSWD_P)
1110 			continue;
1111 
1112 		str = __s_api_strValue(ptr, string, BUFSIZ, i, NS_FILE_FMT);
1113 		if (str == NULL)
1114 			continue;
1115 		if (verbose)
1116 			(void) putchar('\t');
1117 		(void) fprintf(stdout, "%s\n", str);
1118 		if (str != (char *)&string[0]) {
1119 			free(str);
1120 			str = NULL;
1121 		}
1122 	}
1123 
1124 	__s_api_release_config(ptr);
1125 	return (NULL);
1126 }
1127