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