xref: /titanic_50/usr/src/lib/libnisdb/nis_parse_ldap_conf.c (revision e79c98e6c943cb3032f272714ff4ce6137d40394)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <locale.h>
36 #include <sys/stat.h>
37 #include <lber.h>
38 #include <ldap.h>
39 #include <deflt.h>
40 
41 #include "ldap_map.h"
42 
43 #include "ldap_parse.h"
44 #include "ldap_glob.h"
45 #include "nis_parse_ldap_conf.h"
46 
47 __nis_ldap_proxy_info	proxyInfo		=
48 	{NULL, (auth_method_t)NO_VALUE_SET, (tls_method_t)NO_VALUE_SET, NULL,
49 		NULL, NULL, NULL, NULL, (follow_referral_t)NO_VALUE_SET};
50 __nis_config_t		ldapConfig;
51 __nisdb_table_mapping_t ldapDBTableMapping;
52 __nis_table_mapping_t	*ldapTableMapping	= NULL;
53 __yp_domain_context_t	ypDomains;
54 
55 parse_error		p_error			= no_parse_error;
56 int			cur_line_num		= 0;
57 int			start_line_num		= 0;
58 int			seq_num 		= 0;
59 const char		*warn_file		= NULL;
60 
61 char			_key_val[38];
62 const char		*command_line_source	= NULL;
63 const char		*file_source		= NULL;
64 const char		*ldap_source		= NULL;
65 
66 static
67 const char *const	*cmdline_config		= NULL;
68 static bool_t		got_config_data		= FALSE;
69 
70 /* high level parsing functions functions */
71 static int parse_ldap_cmd_line(const char *const *cmdline_options,
72     __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config,
73     __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info,
74     __nisdb_table_mapping_t *table_info);
75 static int parse_ldap_default_conf(__nis_ldap_proxy_info *proxy_info,
76     __nis_config_t *nis_config, __nis_config_info_t *config_info,
77     __nisdb_table_mapping_t *table_info);
78 static int parse_ldap_config_file(const char *config_file,
79     __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config,
80     __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info,
81     __nisdb_table_mapping_t *table_info);
82 static int parse_ldap_config_dn_attrs(__nis_ldap_proxy_info *proxy_info,
83     __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping,
84     __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info);
85 static int yp_parse_ldap_default_conf(__nis_ldap_proxy_info *proxy_info,
86 	__nis_config_t *nis_config, __nis_config_info_t *config_info,
87 	__nisdb_table_mapping_t *table_info);
88 
89 
90 /* helper functions */
91 static config_key get_attrib_num_cmdline(const char *s,
92     const char **begin_s, const char **end_s);
93 static config_key get_file_attr_val(int fd, char **attr_val);
94 static void get_attribute_list(
95 	const __nis_ldap_proxy_info *proxy_info,
96 	const __nis_config_t *nis_config,
97 	const __nis_config_info_t *config_info,
98 	const __nisdb_table_mapping_t *table_info,
99 	char **ldap_config_attributes);
100 
101 /*
102  * FUNCTION:	parse_ldap_migration
103  *
104  *	Parses the information for LDAP. The values are first
105  *	obtained from the command line, secondly from the preference
106  *	file, and finally from an LDAP profile (if so configured in
107  *	the command line or preference file). Any unset values will
108  *	be set to their default values.
109  *
110  *	If no command line options, no settings in the /etc/default
111  *  configuration file, and no mapping file, then no mapping
112  *  should be used.
113  *
114  * RETURN VALUE:
115  *			0	Success
116  *			-1	Config file stat/open or parse error
117  *			1	No mapping should be used.
118  *
119  * INPUT:		command line parameters, configuration file
120  */
121 
122 int
123 parse_ldap_migration(
124 	const char *const	*cmdline_options,
125 	const char		*config_file)
126 {
127 	int			rc	= 0;
128 	__nis_config_info_t	config_info
129 				= {NULL, NULL, (auth_method_t)NO_VALUE_SET,
130 					(tls_method_t)NO_VALUE_SET, NULL,
131 					NULL, NULL};
132 	struct stat		buf;
133 	int i = 0;
134 
135 	p_error = no_parse_error;
136 
137 	if (verbose)
138 		report_info("Getting LDAP configuration", NULL);
139 
140 	initialize_parse_structs(&proxyInfo, &ldapConfig, &ldapDBTableMapping);
141 
142 	if (yp2ldap)
143 		initialize_yp_parse_structs(&ypDomains);
144 
145 	if (cmdline_options != NULL) {
146 		got_config_data = TRUE;
147 		/* NIS to LDAP does not read command line attributes */
148 		if (!yp2ldap)
149 			rc = parse_ldap_cmd_line(cmdline_options, &proxyInfo,
150 				&ldapConfig, &ldapTableMapping, &config_info,
151 				&ldapDBTableMapping);
152 		else
153 			rc = 0;
154 	}
155 
156 	if (rc == 0) {
157 		if (yp2ldap)
158 			rc = yp_parse_ldap_default_conf(&proxyInfo, &ldapConfig,
159 				&config_info, &ldapDBTableMapping);
160 		else
161 			rc = parse_ldap_default_conf(&proxyInfo, &ldapConfig,
162 				&config_info, &ldapDBTableMapping);
163 	}
164 
165 	if (config_file == NULL) {
166 		if (yp2ldap) {
167 			if (stat(YP_DEFAULT_MAPPING_FILE, &buf) == 0)
168 				config_file = YP_DEFAULT_MAPPING_FILE;
169 		} else {
170 			if (stat(DEFAULT_MAPPING_FILE, &buf) == 0)
171 				config_file = DEFAULT_MAPPING_FILE;
172 		}
173 	}
174 
175 	if (rc == 0 && config_file != NULL) {
176 		got_config_data = TRUE;
177 		warn_file = config_file;
178 		cmdline_config = cmdline_options;
179 		if (yp2ldap)
180 			rc = yp_parse_ldap_config_file(config_file, &proxyInfo,
181 				&ldapConfig, &ldapTableMapping, &config_info,
182 				&ldapDBTableMapping, &ypDomains);
183 		else
184 			rc = parse_ldap_config_file(config_file, &proxyInfo,
185 				&ldapConfig, &ldapTableMapping, &config_info,
186 				&ldapDBTableMapping);
187 
188 		warn_file = NULL;
189 		cmdline_config = NULL;
190 	}
191 	if (rc == 0 && (config_info.config_dn != NULL) &&
192 			(config_info.config_dn[0] != '\0')) {
193 		rc = parse_ldap_config_dn_attrs(&proxyInfo,
194 			&ldapConfig, &ldapTableMapping, &config_info,
195 			&ldapDBTableMapping);
196 	}
197 
198 	free_config_info(&config_info);
199 
200 	if (rc == 0 && got_config_data == FALSE)
201 		rc = 1;
202 
203 	set_default_values(&proxyInfo, &ldapConfig, &ldapDBTableMapping);
204 
205 	if (yp2ldap == 1 && rc == 0) {
206 		rc = second_parser_pass(&ldapTableMapping);
207 		if (rc == 0)
208 			rc = final_parser_pass(&ldapTableMapping, &ypDomains);
209 		if (rc == -2)
210 			return (-1);
211 	}
212 
213 	if (rc == 0)
214 		rc = finish_parse(&proxyInfo, &ldapTableMapping);
215 
216 	if (rc == 0)
217 		rc = linked2hash(ldapTableMapping);
218 
219 	if ((rc == 0) && yptol_mode)
220 		rc = map_id_list_init();
221 
222 	if (rc != 0) {
223 		free_parse_structs();
224 	} else if (verbose)
225 		report_info("LDAP configuration complete", NULL);
226 	return (rc);
227 }
228 
229 /*
230  * FUNCTION:	parse_ldap_cmd_line
231  *
232  *	Parses the information for LDAP from the command line
233  *
234  * RETURN VALUE:	0 on success, -1 on failure
235  *
236  * INPUT:		command line values
237  */
238 
239 static int
240 parse_ldap_cmd_line(
241 	const char *const	*cmdline_options,
242 	__nis_ldap_proxy_info	*proxy_info,
243 	__nis_config_t		*nis_config,
244 	__nis_table_mapping_t	**table_mapping,
245 	__nis_config_info_t	*config_info,
246 	__nisdb_table_mapping_t	*table_info)
247 {
248 	int		rc = 0;
249 	config_key	attrib_num;
250 	const char	*begin_s;
251 	const char	*end_s;
252 
253 	if (verbose)
254 		report_info("Command line values: ", NULL);
255 	while (*cmdline_options != NULL) {
256 		if (verbose)
257 			report_info("\t", *cmdline_options);
258 
259 		attrib_num = get_attrib_num_cmdline(
260 		    *cmdline_options, &begin_s, &end_s);
261 		if (attrib_num == key_bad) {
262 			command_line_source = "command line";
263 			report_error(*cmdline_options, NULL);
264 			command_line_source = NULL;
265 			rc = -1;
266 			break;
267 		} else if (IS_CONFIG_KEYWORD(attrib_num)) {
268 			rc = add_config_attribute(attrib_num,
269 			    begin_s, end_s - begin_s, config_info);
270 		} else if (IS_BIND_INFO(attrib_num)) {
271 			rc = add_bind_attribute(attrib_num,
272 			    begin_s, end_s - begin_s, proxy_info);
273 		} else if (IS_OPER_INFO(attrib_num)) {
274 			rc = add_operation_attribute(attrib_num,
275 			    begin_s, end_s - begin_s, nis_config,
276 			    table_info);
277 		} else {
278 			rc = add_mapping_attribute(attrib_num,
279 			    begin_s, end_s - begin_s, table_mapping);
280 		}
281 
282 		if (rc < 0) {
283 			command_line_source = "command line";
284 			report_error(begin_s, _key_val);
285 			command_line_source = NULL;
286 			break;
287 		}
288 		cmdline_options++;
289 	}
290 	return (rc);
291 }
292 
293 static int
294 parse_ldap_default_conf(
295 	__nis_ldap_proxy_info *proxy_info,
296 	__nis_config_t *nis_config,
297 	__nis_config_info_t *config_info,
298 	__nisdb_table_mapping_t	*table_info)
299 {
300 	int		rc = 0;
301 	char		*ldap_config_attributes[n_config_keys];
302 	char		attr_buf[128];
303 	char		*attr;
304 	static char	*attr_val;
305 	int		defflags;
306 	config_key	attrib_num;
307 	int		i;
308 	int		len;
309 	int		attr_len;
310 
311 		if (defopen(ETCCONFFILE) == 0) {
312 			file_source = ETCCONFFILE;
313 			if (verbose)
314 				report_info(
315 				"default configuration values: ", NULL);
316 			/* Set defread() to be case insensitive */
317 			defflags = defcntl(DC_GETFLAGS, 0);
318 			TURNOFF(defflags, DC_CASE);
319 			(void) defcntl(DC_SETFLAGS, defflags);
320 
321 			get_attribute_list(proxy_info, nis_config, config_info,
322 				table_info, ldap_config_attributes);
323 			i = 0;
324 			while ((attr = ldap_config_attributes[i++]) != NULL) {
325 				strlcpy(attr_buf, attr, sizeof (attr_buf));
326 				/*
327 				 * if nisplusUpdateBatching, make sure
328 				 * we don't match nisplusUpdateBatchingTimeout
329 				 */
330 				if (strcmp(attr, UPDATE_BATCHING) == 0) {
331 					attr_len = strlen(attr);
332 					attr_buf[attr_len] = '=';
333 					attr_buf[attr_len + 1] = '\0';
334 					attr_val = defread(attr_buf);
335 
336 					if (attr_val == 0) {
337 						attr_buf[attr_len] = ' ';
338 						attr_val = defread(attr_buf);
339 					}
340 					if (attr_val == 0) {
341 						attr_buf[attr_len] = '\t';
342 						attr_val = defread(attr_buf);
343 					}
344 					if (attr_val == 0) {
345 						attr_buf[attr_len] = '\n';
346 						attr_val = defread(attr_buf);
347 					}
348 				} else {
349 					attr_val = defread(attr_buf);
350 				}
351 				if (attr_val == 0)
352 					continue;
353 
354 				got_config_data = TRUE;
355 				attrib_num = get_attrib_num(attr, strlen(attr));
356 				if (attrib_num == key_bad) {
357 					report_error(attr, NULL);
358 					rc = -1;
359 					break;
360 				}
361 
362 				/*
363 				 * Allow either entries of the form
364 				 *	attr val
365 				 *	   or
366 				 *	attr = val
367 				 */
368 				while (is_whitespace(*attr_val))
369 					attr_val++;
370 				if (*attr_val == '=')
371 					attr_val++;
372 				while (is_whitespace(*attr_val))
373 					attr_val++;
374 				len = strlen(attr_val);
375 				while (len > 0 &&
376 					is_whitespace(attr_val[len - 1]))
377 					len--;
378 
379 				if (verbose) {
380 					report_info("\t", attr);
381 					report_info("\t\t", attr_val);
382 				}
383 				if (IS_BIND_INFO(attrib_num)) {
384 					rc = add_bind_attribute(attrib_num,
385 					    attr_val, len, proxy_info);
386 				} else if (IS_OPER_INFO(attrib_num)) {
387 					rc = add_operation_attribute(attrib_num,
388 						attr_val, len, nis_config,
389 						table_info);
390 				}
391 				if (p_error != no_parse_error) {
392 					report_error(attr_val, attr);
393 					rc = -1;
394 					break;
395 				}
396 			}
397 			file_source = NULL;
398 			/* Close the /etc/default file */
399 			(void) defopen(0);
400 		}
401 		return (rc);
402 }
403 
404 static int
405 yp_parse_ldap_default_conf(
406 	__nis_ldap_proxy_info *proxy_info,
407 	__nis_config_t	*nis_config,
408 	__nis_config_info_t *config_info,
409 	__nisdb_table_mapping_t *table_info)
410 {
411 	int rc = 0;
412 	char		*ldap_config_attributes[n_config_keys];
413 	char		attr_buf[128];
414 	char		*attr;
415 	static 	char *attr_val;
416 	int		defflags;
417 	config_key	attrib_num;
418 	int 	i, len, attr_len;
419 
420 	if ((defopen(YP_ETCCONFFILE)) == 0) {
421 		file_source = YP_ETCCONFFILE;
422 		if (verbose)
423 			report_info("default configuration values: ", NULL);
424 		/* Set defread() to be case insensitive */
425 			defflags = defcntl(DC_GETFLAGS, 0);
426 			TURNOFF(defflags, DC_CASE);
427 			(void) defcntl(DC_SETFLAGS, defflags);
428 
429 			get_attribute_list(proxy_info, nis_config, config_info,
430 				table_info, ldap_config_attributes);
431 			i = 0;
432 			while ((attr = ldap_config_attributes[i++]) != NULL) {
433 				if ((strlcpy(attr_buf, attr,
434 					sizeof (attr_buf))) >=
435 					sizeof (attr_buf)) {
436 					report_error(
437 				"Static buffer attr_buf overflow", NULL);
438 					return (-1);
439 				}
440 
441 				if ((attr_val = defread(attr_buf)) == 0)
442 					continue;
443 
444 				got_config_data = TRUE;
445 				attrib_num = get_attrib_num(attr, strlen(attr));
446 				if (attrib_num == key_bad) {
447 					report_error(attr, NULL);
448 					rc = -1;
449 					break;
450 				}
451 
452 				/*
453 				 * Allow either entries of the form
454 				 * attr val
455 				 * or
456 				 * attr = val
457 				 */
458 				while (is_whitespace(*attr_val))
459 					attr_val++;
460 				if (*attr_val == '=')
461 					attr_val++;
462 				while (is_whitespace(*attr_val))
463 					attr_val++;
464 				len = strlen(attr_val);
465 				while (len > 0 &&
466 					is_whitespace(attr_val[len - 1]))
467 					len--;
468 
469 				if (verbose) {
470 					report_info("\t", attr);
471 					report_info("\t\t", attr_val);
472 				}
473 				if (IS_YP_BIND_INFO(attrib_num)) {
474 					rc = add_bind_attribute(attrib_num,
475 						attr_val, len, proxy_info);
476 				} else if (IS_YP_OPER_INFO(attrib_num)) {
477 					rc = add_operation_attribute(attrib_num,
478 						attr_val, len, nis_config,
479 						table_info);
480 				}
481 				if (p_error != no_parse_error) {
482 					report_error(attr_val, attr);
483 					rc = -1;
484 					break;
485 				}
486 			}
487 			file_source = NULL;
488 			/* Close the /etc/default file */
489 			(void) defopen(0);
490 		}
491 		return (rc);
492 }
493 
494 /*
495  * FUNCTION:	get_attrib_num_cmdline
496  *
497  *	Parses the information for LDAP from the command line
498  *	The form of the command line request is
499  *		-x attribute=value
500  *
501  * RETURN VALUE:	0 on success, -1 on failure
502  *
503  * INPUT:		command line values
504  */
505 
506 static config_key
507 get_attrib_num_cmdline(
508 	const char	*s,
509 	const char 	**begin_s,
510 	const char 	**end_s)
511 {
512 	const char	*s_end		= s + strlen(s);
513 	const char	*equal_s;
514 	const char	*s1;
515 	config_key	attrib_num;
516 
517 	while (s < s_end && is_whitespace(*s))
518 		s++;
519 
520 	for (equal_s = s; equal_s < s_end; equal_s++)
521 		if (*equal_s == EQUAL_CHAR)
522 			break;
523 
524 	if (equal_s == s_end) {
525 		p_error = parse_bad_command_line_attribute_format;
526 		return (key_bad);
527 	}
528 
529 	for (s1 = equal_s; s1 > s && is_whitespace(s1[-1]); s1--)
530 		;
531 
532 	if (s1 == s) {
533 		p_error = parse_bad_command_line_attribute_format;
534 		return (key_bad);
535 	}
536 
537 	attrib_num = get_attrib_num(s, s1 - s);
538 
539 	if (attrib_num != key_bad) {
540 		s1 = equal_s + 1;
541 		while (s1 < s_end && is_whitespace(*s1))
542 			s1++;
543 		*begin_s = s1;
544 		while (s_end > s1 && is_whitespace(s_end[-1]))
545 			s_end--;
546 		*end_s = s_end;
547 	}
548 
549 	return (attrib_num);
550 }
551 
552 /*
553  * FUNCTION:	parse_ldap_config_file
554  *
555  *	Parses the information for LDAP from a configuration
556  *	file. If no file is specified, /var/nis/NIS+LDAPmapping
557  *	is used
558  *
559  * RETURN VALUE:	0 on success, -1 on failure
560  *
561  * INPUT:		configuration file name
562  */
563 
564 static int
565 parse_ldap_config_file(
566 	const char 		*config_file,
567 	__nis_ldap_proxy_info	*proxy_info,
568 	__nis_config_t		*nis_config,
569 	__nis_table_mapping_t	**table_mapping,
570 	__nis_config_info_t	*config_info,
571 	__nisdb_table_mapping_t	*table_info)
572 {
573 	int		rc = 0;
574 	config_key	attrib_num;
575 	int		fd;
576 	char		*attr_val;
577 	int		len;
578 
579 	if ((fd = open(config_file, O_RDONLY)) == -1) {
580 		p_error = parse_open_file_error;
581 		report_error(config_file, NULL);
582 		return (-1);
583 	}
584 
585 	start_line_num = 1;
586 	cur_line_num = 1;
587 
588 	if (verbose)
589 		report_info("Reading configuration from ", config_file);
590 
591 	file_source = config_file;
592 	while ((attrib_num = get_file_attr_val(fd, &attr_val)) > 0) {
593 		len = attr_val == NULL ? 0 : strlen(attr_val);
594 		if (IS_CONFIG_KEYWORD(attrib_num)) {
595 			rc = add_config_attribute(attrib_num,
596 			    attr_val, len, config_info);
597 		} else if (IS_BIND_INFO(attrib_num)) {
598 			rc = add_bind_attribute(attrib_num,
599 			    attr_val, len, proxy_info);
600 		} else if (IS_OPER_INFO(attrib_num)) {
601 			rc = add_operation_attribute(attrib_num,
602 			    attr_val, len, nis_config, table_info);
603 		} else {
604 			rc = add_mapping_attribute(attrib_num,
605 		    attr_val, len, table_mapping);
606 		}
607 
608 		if (rc < 0) {
609 			report_error(attr_val == NULL ?
610 				"<no attribute>" : attr_val, _key_val);
611 			if (attr_val)
612 				free(attr_val);
613 			break;
614 		}
615 		if (attr_val)
616 			free(attr_val);
617 	}
618 
619 	(void) close(fd);
620 	if (attrib_num == key_bad) {
621 		report_error(_key_val, NULL);
622 		rc = -1;
623 	}
624 	start_line_num = 0;
625 	file_source = NULL;
626 	return (rc);
627 }
628 
629 /*
630  * FUNCTION:	yp_parse_ldap_config_file
631  *
632  * Parses the information for LDAP from a configuration
633  * file. If no file is specified, /var/yp/NISLDAPmapping
634  * is used
635  *
636  * RETURN VALUE:    0 on success, -1 on failure
637  *
638  * INPUT:       configuration file name
639  */
640 
641 int
642 yp_parse_ldap_config_file(
643 	const char	*config_file,
644 	__nis_ldap_proxy_info	*proxy_info,
645 	__nis_config_t			*nis_config,
646 	__nis_table_mapping_t	**table_mapping,
647 	__nis_config_info_t		*config_info,
648 	__nisdb_table_mapping_t	*table_info,
649 	__yp_domain_context_t	*ypDomains)
650 {
651 	int	rc = 0;
652 	int	numDomains = 0;
653 	config_key	attrib_num;
654 	int	fd;
655 	char	*attr_val = NULL;
656 	int		len;
657 
658 	if ((fd = open(config_file, O_RDONLY)) == -1) {
659 		p_error = parse_open_file_error;
660 		report_error(config_file, NULL);
661 		return (-1);
662 	}
663 
664 	start_line_num = 1;
665 	cur_line_num = 1;
666 
667 	if (verbose)
668 		report_info("Reading configuration from ", config_file);
669 
670 	file_source = config_file;
671 	while ((attrib_num = get_file_attr_val(fd, &attr_val)) > 0) {
672 		len = attr_val == NULL ? 0 : strlen(attr_val);
673 		if (IS_YP_CONFIG_KEYWORD(attrib_num)) {
674 			rc = add_config_attribute(attrib_num,
675 				attr_val, len, config_info);
676 		} else if (IS_YP_BIND_INFO(attrib_num)) {
677 			rc = add_bind_attribute(attrib_num,
678 				attr_val, len, proxy_info);
679 		} else if (IS_YP_OPER_INFO(attrib_num)) {
680 			rc = add_operation_attribute(attrib_num,
681 				attr_val, len, nis_config, table_info);
682 		} else if (IS_YP_DOMAIN_INFO(attrib_num)) {
683 			rc = add_ypdomains_attribute(attrib_num,
684 				attr_val, len, ypDomains);
685 		} else if (IS_YP_MAP_ATTR(attrib_num)) {
686 			rc = add_mapping_attribute(attrib_num,
687 				attr_val, len, table_mapping);
688 		} else {
689 			rc = -1;
690 			p_error = parse_unsupported_format;
691 		}
692 
693 		if (rc < 0) {
694 			report_error(attr_val == NULL ?
695 				"<no attribute>" : attr_val, _key_val);
696 			if (attr_val)
697 				free(attr_val);
698 			break;
699 		}
700 		if (attr_val) {
701 			free(attr_val);
702 			attr_val = NULL;
703 		}
704 	}
705 
706 	(void) close(fd);
707 	if (attrib_num == key_bad) {
708 		report_error(_key_val, NULL);
709 		rc = -1;
710 	}
711 	start_line_num = 0;
712 	file_source = NULL;
713 	return (rc);
714 }
715 
716 /*
717  * FUNCTION:	get_file_attr_val
718  *
719  *	Gets the next attribute from the configuration file.
720  *
721  * RETURN VALUE:	The config key if more attributes
722  *			no_more_keys if eof
723  *			key_bad if error
724  */
725 
726 static config_key
727 get_file_attr_val(int fd, char **attr_val)
728 {
729 	char		buf[BUFSIZE];
730 	char		*start_tag;
731 	char		*start_val;
732 	char		*end_val;
733 	char		*cut_here;
734 	char		*s;
735 	char		*a;
736 	char		*attribute_value;
737 	int		ret;
738 	config_key	attrib_num = no_more_keys;
739 	int		found_quote = 0;
740 
741 	*attr_val = NULL;
742 
743 	if ((ret = read_line(fd, buf, sizeof (buf))) > 0) {
744 		for (s = buf; is_whitespace(*s); s++)
745 			;
746 
747 		start_tag = s;
748 		while (*s != '\0' && !is_whitespace(*s))
749 			s++;
750 
751 		if (verbose)
752 			report_info("\t", start_tag);
753 		attrib_num = get_attrib_num(start_tag, s - start_tag);
754 		if (attrib_num == key_bad)
755 			return (key_bad);
756 
757 		while (is_whitespace(*s))
758 			s++;
759 		if (*s == '\0')
760 			return (attrib_num);
761 		start_val = s;
762 
763 		/* note that read_line will not return a line ending with \ */
764 		for (; *s != '\0'; s++) {
765 			if (*s == ESCAPE_CHAR)
766 				s++;
767 		}
768 		while (s > start_val && is_whitespace(s[-1]))
769 			s--;
770 
771 		attribute_value =
772 		(char *)calloc(1, (size_t)(s - start_val) + 1);
773 		if (attribute_value == NULL) {
774 			p_error = parse_no_mem_error;
775 			return (key_bad);
776 		}
777 		attr_val[0] = attribute_value;
778 
779 		a = *attr_val;
780 		end_val = s;
781 		cut_here = 0;
782 		for (s = start_val; s < end_val; s++) {
783 			if (*s == POUND_SIGN) {
784 					cut_here = s;
785 					while (s < end_val) {
786 						if (*s == DOUBLE_QUOTE_CHAR ||
787 						*s == SINGLE_QUOTE_CHAR) {
788 							cut_here = 0;
789 							break;
790 						}
791 						s++;
792 					}
793 			}
794 		}
795 		if (cut_here != 0)
796 			end_val = cut_here;
797 
798 		for (s = start_val; s < end_val; s++)
799 			*a++ = *s;
800 		*a++ = '\0';
801 	}
802 	if (ret == -1)
803 		return (key_bad);
804 
805 	return (attrib_num);
806 }
807 
808 static LDAP *
809 connect_to_ldap_config_server(
810 	char			*sever_name,
811 	int			server_port,
812 	__nis_config_info_t	*config_info)
813 {
814 	int		rc		= 0;
815 	LDAP		*ld		= NULL;
816 	int		ldapVersion	= LDAP_VERSION3;
817 	int		derefOption	= LDAP_DEREF_ALWAYS;
818 	int		timelimit	= LDAP_NO_LIMIT;
819 	int		sizelimit	= LDAP_NO_LIMIT;
820 	int		errnum;
821 	bool_t		retrying	= FALSE;
822 	int		sleep_seconds	= 1;
823 	struct berval	cred;
824 
825 	if (config_info->tls_method == no_tls) {
826 		ld = ldap_init(sever_name, server_port);
827 		if (ld == NULL) {
828 			p_error = parse_ldap_init_error;
829 			report_error(strerror(errno), NULL);
830 			return (NULL);
831 		}
832 	} else {
833 		if ((errnum = ldapssl_client_init(
834 			config_info->tls_cert_db, NULL)) < 0) {
835 			p_error = parse_ldapssl_client_init_error;
836 			report_error(ldapssl_err2string(errnum), NULL);
837 			return (NULL);
838 		}
839 		ld = ldapssl_init(sever_name, server_port, 1);
840 		if (ld == NULL) {
841 			p_error = parse_ldapssl_init_error;
842 			report_error(strerror(errno), NULL);
843 			return (NULL);
844 		}
845 	}
846 
847 	(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
848 		&ldapVersion);
849 	(void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
850 	(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
851 	(void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit);
852 	(void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
853 
854 	/*
855 	 * Attempt to bind to the LDAP server.
856 	 * We will loop until success or until an error other
857 	 * than LDAP_CONNECT_ERROR or LDAP_SERVER_DOWN
858 	 */
859 	if (verbose)
860 		report_info("Connecting to ", sever_name);
861 
862 	for (;;) {
863 		if (config_info->auth_method == simple) {
864 			errnum = ldap_simple_bind_s(ld, config_info->proxy_dn,
865 				config_info->proxy_passwd);
866 		} else if (config_info->auth_method == cram_md5) {
867 			cred.bv_len = strlen(config_info->proxy_passwd);
868 			cred.bv_val = config_info->proxy_passwd;
869 			errnum = ldap_sasl_cram_md5_bind_s(ld,
870 				config_info->proxy_dn, &cred, NULL, NULL);
871 		} else if (config_info->auth_method == digest_md5) {
872 			cred.bv_len = strlen(config_info->proxy_passwd);
873 			cred.bv_val = config_info->proxy_passwd;
874 			errnum = ldap_x_sasl_digest_md5_bind_s(ld,
875 				config_info->proxy_dn, &cred, NULL, NULL);
876 		} else {
877 			errnum = ldap_simple_bind_s(ld, NULL, NULL);
878 		}
879 
880 		if (errnum == LDAP_SUCCESS)
881 			break;
882 
883 		if (errnum == LDAP_CONNECT_ERROR ||
884 			errnum == LDAP_SERVER_DOWN) {
885 			if (!retrying) {
886 				if (verbose)
887 				    report_info(
888 					"LDAP server unavailable. Retrying...",
889 					NULL);
890 				retrying = TRUE;
891 			}
892 			(void) sleep(sleep_seconds);
893 			sleep_seconds *= 2;
894 			if (sleep_seconds > MAX_LDAP_CONFIG_RETRY_TIME)
895 				sleep_seconds = MAX_LDAP_CONFIG_RETRY_TIME;
896 			p_error = no_parse_error;
897 			continue;
898 		}
899 		p_error = parse_ldap_bind_error;
900 		report_error2(config_info->proxy_dn, ldap_err2string(errnum));
901 		(void) ldap_unbind(ld);
902 		return (NULL);
903 	}
904 
905 	if (verbose)
906 		report_info("Reading values from ", config_info->config_dn);
907 
908 	return (ld);
909 }
910 
911 /*
912  * FUNCTION:	process_ldap_config_result
913  *
914  *	Extracts the LDAPMessage containing the nis+/LDAP
915  *	configuration
916  *
917  * RETURN VALUE:	0 on success, -1 on failure
918  *
919  * INPUT:		LDAP		the LDAP connection
920  *			LDAPMessage	the LDAP message
921  */
922 
923 static int
924 process_ldap_config_result(
925 	LDAP			*ld,
926 	LDAPMessage		*resultMsg,
927 	__nis_ldap_proxy_info	*proxy_info,
928 	__nis_config_t		*nis_config,
929 	__nis_table_mapping_t	**table_mapping,
930 	__nisdb_table_mapping_t	*table_info)
931 {
932 	LDAPMessage	*e;
933 	int		errnum;
934 	char		*attr;
935 	BerElement	*ber		= NULL;
936 	config_key	attrib_num;
937 	char		**vals;
938 	int		n;
939 	int		i;
940 	char		*attr_val;
941 	int		len;
942 	int		rc = 0;
943 	bool_t		error_reported	= FALSE;
944 
945 	e = ldap_first_entry(ld, resultMsg);
946 
947 	if (e != NULL) {
948 		for (attr = ldap_first_attribute(ld, e, &ber);
949 			attr != NULL;
950 			attr = ldap_next_attribute(ld, e, ber)) {
951 		    if (verbose)
952 			report_info("\t", attr);
953 		    attrib_num = get_attrib_num(attr, strlen(attr));
954 		    if (attrib_num == key_bad) {
955 				report_error(attr, NULL);
956 				break;
957 		    }
958 		    if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
959 			n = ldap_count_values(vals);
960 			/* parse the attribute values */
961 			for (i = 0; i < n; i++) {
962 				attr_val = vals[i];
963 				while (is_whitespace(*attr_val))
964 					attr_val++;
965 				if (verbose)
966 					report_info("\t\t", attr_val);
967 				len = strlen(attr_val);
968 				while (len > 0 &&
969 				    is_whitespace(attr_val[len - 1]))
970 					len--;
971 				if (yp2ldap) {
972 					if (IS_YP_BIND_INFO(attrib_num)) {
973 						rc = add_bind_attribute(
974 							attrib_num, attr_val,
975 							len, proxy_info);
976 					} else if (IS_YP_OPER_INFO(
977 						attrib_num)) {
978 						rc = add_operation_attribute(
979 						attrib_num, attr_val, len,
980 						nis_config, table_info);
981 					} else if (IS_YP_MAP_ATTR(
982 						attrib_num)) {
983 						rc = add_mapping_attribute(
984 						attrib_num, attr_val, len,
985 						table_mapping);
986 					} else {
987 						p_error =
988 						parse_unsupported_format;
989 					}
990 				} else {
991 					if (IS_BIND_INFO(attrib_num)) {
992 						rc = add_bind_attribute(
993 						attrib_num, attr_val, len,
994 						proxy_info);
995 					} else if (IS_OPER_INFO(attrib_num)) {
996 						rc = add_operation_attribute(
997 						attrib_num, attr_val, len,
998 						nis_config,
999 						    table_info);
1000 					} else {
1001 						rc = add_mapping_attribute(
1002 						attrib_num, attr_val, len,
1003 						table_mapping);
1004 					}
1005 				}
1006 				if (p_error != no_parse_error) {
1007 					report_error(attr_val, attr);
1008 					error_reported = TRUE;
1009 					break;
1010 				}
1011 			}
1012 			ldap_value_free(vals);
1013 		    } else {
1014 			(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
1015 				&errnum);
1016 			if (errnum != LDAP_SUCCESS)
1017 				p_error = parse_ldap_get_values_error;
1018 		    }
1019 		    ldap_memfree(attr);
1020 		    if (p_error != no_parse_error)
1021 			break;
1022 		}
1023 		} else {
1024 		errnum = ldap_result2error(ld, resultMsg, FALSE);
1025 		if (errnum != LDAP_SUCCESS)
1026 			p_error = parse_ldap_search_error;
1027 	}
1028 	if (ber != NULL)
1029 		ber_free(ber, 0);
1030 
1031 	if (!error_reported && p_error != no_parse_error) {
1032 		report_error(ldap_err2string(errnum), 0);
1033 	}
1034 
1035 	if (p_error != no_parse_error)
1036 		rc = -1;
1037 	return (rc);
1038 }
1039 
1040 /*
1041  * FUNCTION:	process_ldap_referral
1042  *
1043  *	Retrieves the configuration for a referral url
1044  *
1045  * RETURN VALUE:	0 on success, -1 on failure, 1 on skip
1046  *
1047  * INPUT:		url		the ldap url
1048  *			__nis_ldap_proxy_info
1049  */
1050 
1051 static int
1052 process_ldap_referral(
1053 	char			*url,
1054 	char			**attrs,
1055 	__nis_ldap_proxy_info	*proxy_info,
1056 	__nis_config_t		*nis_config,
1057 	__nis_table_mapping_t	**table_mapping,
1058 	__nis_config_info_t	*config_info,
1059 	__nisdb_table_mapping_t	*table_info)
1060 {
1061 	LDAPURLDesc	*ludpp		= NULL;
1062 	int		rc;
1063 	LDAP		*ld		= NULL;
1064 	int		errnum;
1065 	LDAPMessage	*resultMsg	= NULL;
1066 
1067 	if ((rc = ldap_url_parse(url, &ludpp)) != LDAP_SUCCESS)
1068 		return (1);
1069 
1070 #ifdef LDAP_URL_OPT_SECURE
1071 	if (ludpp->lud_options & LDAP_URL_OPT_SECURE) {
1072 		if (config_info->tls_method != ssl_tls) {
1073 			ldap_free_urldesc(ludpp);
1074 			return (1);
1075 		}
1076 	} else {
1077 		if (config_info->tls_method != no_tls) {
1078 			ldap_free_urldesc(ludpp);
1079 			return (1);
1080 		}
1081 	}
1082 #endif
1083 
1084 	if ((ld = connect_to_ldap_config_server(ludpp->lud_host,
1085 			ludpp->lud_port, config_info)) == NULL) {
1086 		ldap_free_urldesc(ludpp);
1087 		return (-1);
1088 	}
1089 
1090 	errnum = ldap_search_s(ld, config_info->config_dn, LDAP_SCOPE_BASE,
1091 		"objectclass=nisplusLDAPconfig", attrs, 0, &resultMsg);
1092 
1093 	ldap_source = config_info->config_dn;
1094 
1095 	if (errnum != LDAP_SUCCESS) {
1096 		p_error = parse_ldap_search_error;
1097 		report_error(ldap_err2string(errnum), 0);
1098 		rc = -1;
1099 	} else {
1100 		rc = process_ldap_config_result(ld, resultMsg, proxy_info,
1101 			nis_config, table_mapping, table_info);
1102 	}
1103 
1104 	ldap_source = NULL;
1105 	(void) ldap_unbind(ld);
1106 	if (resultMsg != NULL)
1107 		(void) ldap_msgfree(resultMsg);
1108 
1109 	return (rc);
1110 }
1111 
1112 /*
1113  * FUNCTION:	process_ldap_referral_msg
1114  *
1115  *	Retrieves the configuration from referred servers
1116  *
1117  * RETURN VALUE:	0 on success, -1 on failure
1118  *
1119  * INPUT:		LDAP		the LDAP connection
1120  *			LDAPMessage	the LDAP message
1121  *			__nis_ldap_proxy_info
1122  */
1123 
1124 static int
1125 process_ldap_referral_msg(
1126 	LDAP			*ld,
1127 	LDAPMessage		*resultMsg,
1128 	char			**attrs,
1129 	__nis_ldap_proxy_info	*proxy_info,
1130 	__nis_config_t		*nis_config,
1131 	__nis_table_mapping_t	**table_mapping,
1132 	__nis_config_info_t	*config_info,
1133 	__nisdb_table_mapping_t	*table_info)
1134 {
1135 	int	errCode;
1136 	char	**referralsp	= NULL;
1137 	int	i;
1138 	int	rc;
1139 
1140 	rc = ldap_parse_result(ld, resultMsg, &errCode, NULL, NULL, &referralsp,
1141 			NULL, 0);
1142 
1143 	if (rc != LDAP_SUCCESS || errCode != LDAP_REFERRAL) {
1144 		p_error = parse_ldap_get_values_error;
1145 		report_error(ldap_err2string(errCode), 0);
1146 		rc = -1;
1147 	} else {
1148 		for (i = 0; referralsp[i] != NULL; i++) {
1149 			rc = process_ldap_referral(referralsp[i], attrs,
1150 				proxy_info, nis_config, table_mapping,
1151 				config_info, table_info);
1152 			if (rc <= 0)
1153 				break;
1154 			else
1155 				report_info("Cannot use referral \n",
1156 					referralsp[i]);
1157 
1158 		}
1159 		if (rc > 0) {
1160 			p_error = parse_no_available_referrals_error;
1161 			report_error(0, 0);
1162 		}
1163 	}
1164 
1165 	if (referralsp)
1166 		ldap_value_free(referralsp);
1167 
1168 	return (rc);
1169 }
1170 
1171 /*
1172  * FUNCTION:	parse_ldap_config_dn_attrs
1173  *
1174  *	Parses the information for LDAP from the LDAP profile
1175  *	- the profile object name, the LDAP server, and the
1176  *	authentication method must be specified.
1177  *
1178  * RETURN VALUE:	0 on success, -1 on failure
1179  *
1180  * INPUT:		__nis_ldap_proxy_info
1181  */
1182 
1183 static int
1184 parse_ldap_config_dn_attrs(
1185 	__nis_ldap_proxy_info	*proxy_info,
1186 	__nis_config_t		*nis_config,
1187 	__nis_table_mapping_t	**table_mapping,
1188 	__nis_config_info_t	*config_info,
1189 	__nisdb_table_mapping_t	*table_info)
1190 {
1191 	int		rc		= 0;
1192 	LDAP		*ld		= NULL;
1193 	int		errnum;
1194 	char		*ldap_config_attributes[n_config_keys];
1195 	LDAPMessage	*resultMsg	= NULL;
1196 
1197 	/* Determine if properly configured for LDAP lookup */
1198 	if (config_info->auth_method == simple &&
1199 	    config_info->proxy_dn == NULL)
1200 		p_error = parse_no_proxy_dn_error;
1201 	else if (config_info->auth_method ==
1202 	    (auth_method_t)NO_VALUE_SET)
1203 		p_error = parse_no_config_auth_error;
1204 	else if ((config_info->default_servers == NULL) ||
1205 			(config_info->default_servers[0] == '\0'))
1206 		p_error = parse_no_config_server_addr;
1207 	if (p_error != no_parse_error) {
1208 		report_error(NULL, NULL);
1209 		return (-1);
1210 	}
1211 
1212 	if (config_info->tls_method == (tls_method_t)NO_VALUE_SET)
1213 		config_info->tls_method = no_tls;
1214 	else if (config_info->tls_method == ssl_tls &&
1215 			(config_info->tls_cert_db == NULL ||
1216 			*config_info->tls_cert_db == '\0')) {
1217 		p_error = parse_no_config_cert_db;
1218 		report_error(NULL, NULL);
1219 		return (-1);
1220 	}
1221 
1222 	if (verbose)
1223 		report_info(
1224 			"Getting configuration from LDAP server(s): ",
1225 			config_info->default_servers);
1226 
1227 	/* Determine which attributes should be retrieved */
1228 	get_attribute_list(proxy_info, nis_config, NULL, table_info,
1229 		ldap_config_attributes);
1230 
1231 	if ((ld = connect_to_ldap_config_server(config_info->default_servers, 0,
1232 			config_info)) == NULL)
1233 		return (-1);
1234 
1235 	/* Get the attribute values */
1236 	errnum = ldap_search_s(ld, config_info->config_dn, LDAP_SCOPE_BASE,
1237 			"objectclass=nisplusLDAPconfig",
1238 			ldap_config_attributes, 0, &resultMsg);
1239 	ldap_source = config_info->config_dn;
1240 
1241 	if (errnum == LDAP_REFERRAL) {
1242 		rc = process_ldap_referral_msg(ld, resultMsg,
1243 			ldap_config_attributes, proxy_info, nis_config,
1244 			table_mapping, config_info, table_info);
1245 	} else if (errnum != LDAP_SUCCESS) {
1246 		p_error = parse_ldap_search_error;
1247 		report_error(ldap_err2string(errnum), 0);
1248 		rc = -1;
1249 	} else {
1250 		rc = process_ldap_config_result(ld, resultMsg, proxy_info,
1251 			nis_config, table_mapping, table_info);
1252 	}
1253 
1254 	ldap_source = NULL;
1255 	(void) ldap_unbind(ld);
1256 	if (resultMsg != NULL)
1257 		(void) ldap_msgfree(resultMsg);
1258 
1259 	return (rc);
1260 }
1261 
1262 bool_t
1263 is_cmd_line_option(config_key a_num)
1264 {
1265 	const char *const	*cmdline_options = cmdline_config;
1266 	config_key		attrib_num;
1267 	const char		*begin_s;
1268 	const char		*end_s;
1269 
1270 	if (cmdline_options == NULL)
1271 		return (FALSE);
1272 
1273 	while (*cmdline_options != NULL) {
1274 		attrib_num = get_attrib_num_cmdline(
1275 		    *cmdline_options, &begin_s, &end_s);
1276 		if (attrib_num == a_num)
1277 			break;
1278 		cmdline_options++;
1279 	}
1280 	return (*cmdline_options != NULL);
1281 }
1282 
1283 /*
1284  * FUNCTION:	get_attribute_list
1285  *
1286  *	Get a list of attributes from the LDAP server that have not yet
1287  *	been gotten. If config_info is NULL, the associated parameters
1288  *	are not needed.
1289  *
1290  * RETURN VALUE:	none
1291  *
1292  * INPUT:		Returns a list of parameters in attributes
1293  *			which is assumed to be of sufficient size.
1294  */
1295 
1296 static void
1297 get_attribute_list(
1298 	const __nis_ldap_proxy_info	*proxy_info,
1299 	const __nis_config_t		*nis_config,
1300 	const __nis_config_info_t	*config_info,
1301 	const __nisdb_table_mapping_t	*table_info,
1302 	char				**attributes)
1303 {
1304 	int		n_attrs;
1305 
1306 	/* Determine which attributes should be retrieved */
1307 	n_attrs = 0;
1308 
1309 	if (config_info != NULL) {
1310 		if (yp2ldap) {
1311 			if (config_info->config_dn == NULL)
1312 				attributes[n_attrs++] = YP_CONFIG_DN;
1313 			if (config_info->default_servers == NULL)
1314 				attributes[n_attrs++] = YP_CONFIG_SERVER_LIST;
1315 			if (config_info->auth_method ==
1316 				(auth_method_t)NO_VALUE_SET)
1317 				attributes[n_attrs++] = YP_CONFIG_AUTH_METHOD;
1318 			if (config_info->tls_method ==
1319 				(tls_method_t)NO_VALUE_SET)
1320 				attributes[n_attrs++] = YP_CONFIG_TLS_OPTION;
1321 			if (config_info->proxy_dn == NULL)
1322 				attributes[n_attrs++] = YP_CONFIG_PROXY_USER;
1323 			if (config_info->proxy_passwd == NULL)
1324 				attributes[n_attrs++] = YP_CONFIG_PROXY_PASSWD;
1325 			if (config_info->tls_cert_db == NULL)
1326 				attributes[n_attrs++] = YP_CONFIG_TLS_CERT_DB;
1327 		} else {
1328 			if (config_info->config_dn == NULL)
1329 				attributes[n_attrs++] = CONFIG_DN;
1330 			if (config_info->default_servers == NULL)
1331 				attributes[n_attrs++] = CONFIG_SERVER_LIST;
1332 			if (config_info->auth_method ==
1333 				(auth_method_t)NO_VALUE_SET)
1334 				attributes[n_attrs++] = CONFIG_AUTH_METHOD;
1335 			if (config_info->tls_method ==
1336 				(tls_method_t)NO_VALUE_SET)
1337 				attributes[n_attrs++] = CONFIG_TLS_OPTION;
1338 			if (config_info->proxy_dn == NULL)
1339 				attributes[n_attrs++] = CONFIG_PROXY_USER;
1340 			if (config_info->proxy_passwd == NULL)
1341 				attributes[n_attrs++] = CONFIG_PROXY_PASSWD;
1342 			if (config_info->tls_cert_db == NULL)
1343 				attributes[n_attrs++] = CONFIG_TLS_CERT_DB;
1344 		}
1345 	} else {
1346 		if (yp2ldap) {
1347 			attributes[n_attrs++] = YP_DOMAIN_CONTEXT;
1348 			attributes[n_attrs++] = YPPASSWDD_DOMAINS;
1349 			attributes[n_attrs++] = YP_DB_ID_MAP;
1350 			attributes[n_attrs++] = YP_COMMENT_CHAR;
1351 			attributes[n_attrs++] = YP_MAP_FLAGS;
1352 			attributes[n_attrs++] = YP_ENTRY_TTL;
1353 			attributes[n_attrs++] = YP_NAME_FIELDS;
1354 			attributes[n_attrs++] = YP_SPLIT_FIELD;
1355 			attributes[n_attrs++] = YP_REPEATED_FIELD_SEPARATORS;
1356 			attributes[n_attrs++] = YP_LDAP_OBJECT_DN;
1357 			attributes[n_attrs++] = NIS_TO_LDAP_MAP;
1358 			attributes[n_attrs++] = LDAP_TO_NIS_MAP;
1359 		} else {
1360 			attributes[n_attrs++] = DB_ID_MAP;
1361 			attributes[n_attrs++] = ENTRY_TTL;
1362 			attributes[n_attrs++] = LDAP_OBJECT_DN;
1363 			attributes[n_attrs++] = NISPLUS_TO_LDAP_MAP;
1364 			attributes[n_attrs++] = LDAP_TO_NISPLUS_MAP;
1365 		}
1366 	}
1367 
1368 	if (yp2ldap) {
1369 		if (proxy_info->default_servers == NULL)
1370 			attributes[n_attrs++] = PREFERRED_SERVERS;
1371 		if (proxy_info->auth_method == (auth_method_t)NO_VALUE_SET)
1372 			attributes[n_attrs++] = AUTH_METHOD;
1373 		if (proxy_info->tls_method == (tls_method_t)NO_VALUE_SET)
1374 			attributes[n_attrs++] = YP_TLS_OPTION;
1375 		if (proxy_info->tls_cert_db == NULL)
1376 			attributes[n_attrs++] = YP_TLS_CERT_DB;
1377 		if (proxy_info->default_search_base == NULL)
1378 			attributes[n_attrs++] = SEARCH_BASE;
1379 		if (proxy_info->proxy_dn == NULL)
1380 			attributes[n_attrs++] = YP_PROXY_USER;
1381 		if (proxy_info->proxy_passwd == NULL)
1382 			attributes[n_attrs++] = YP_PROXY_PASSWD;
1383 		if (proxy_info->default_nis_domain == NULL)
1384 			attributes[n_attrs++] = YP_LDAP_BASE_DOMAIN;
1385 		if (proxy_info->bind_timeout.tv_sec ==
1386 			(time_t)NO_VALUE_SET)
1387 			attributes[n_attrs++] = YP_BIND_TIMEOUT;
1388 		if (proxy_info->search_timeout.tv_sec ==
1389 			(time_t)NO_VALUE_SET)
1390 			attributes[n_attrs++] = YP_SEARCH_TIMEOUT;
1391 		if (proxy_info->modify_timeout.tv_sec ==
1392 			(time_t)NO_VALUE_SET)
1393 			attributes[n_attrs++] = YP_MODIFY_TIMEOUT;
1394 		if (proxy_info->add_timeout.tv_sec == (time_t)NO_VALUE_SET)
1395 			attributes[n_attrs++] = YP_ADD_TIMEOUT;
1396 		if (proxy_info->delete_timeout.tv_sec ==
1397 			(time_t)NO_VALUE_SET)
1398 			attributes[n_attrs++] = YP_DELETE_TIMEOUT;
1399 		if (proxy_info->search_time_limit == (int)NO_VALUE_SET)
1400 			attributes[n_attrs++] = YP_SEARCH_TIME_LIMIT;
1401 		if (proxy_info->search_size_limit == (int)NO_VALUE_SET)
1402 			attributes[n_attrs++] = YP_SEARCH_SIZE_LIMIT;
1403 		if (proxy_info->follow_referral ==
1404 			(follow_referral_t)NO_VALUE_SET)
1405 			attributes[n_attrs++] = YP_FOLLOW_REFERRAL;
1406 
1407 		if (table_info->retrieveError ==
1408 			(__nis_retrieve_error_t)NO_VALUE_SET)
1409 			attributes[n_attrs++] = YP_RETRIEVE_ERROR_ACTION;
1410 		if (table_info->retrieveErrorRetry.attempts == NO_VALUE_SET)
1411 			attributes[n_attrs++] = YP_RETREIVE_ERROR_ATTEMPTS;
1412 		if (table_info->retrieveErrorRetry.timeout ==
1413 			(time_t)NO_VALUE_SET)
1414 			attributes[n_attrs++] = YP_RETREIVE_ERROR_TIMEOUT;
1415 		if (table_info->storeError ==
1416 			(__nis_store_error_t)NO_VALUE_SET)
1417 			attributes[n_attrs++] = YP_STORE_ERROR_ACTION;
1418 		if (table_info->storeErrorRetry.attempts == NO_VALUE_SET)
1419 			attributes[n_attrs++] = YP_STORE_ERROR_ATTEMPTS;
1420 		if (table_info->storeErrorRetry.timeout ==
1421 			(time_t)NO_VALUE_SET)
1422 			attributes[n_attrs++] = YP_STORE_ERROR_TIMEOUT;
1423 		if (table_info->refreshError ==
1424 			(__nis_refresh_error_t)NO_VALUE_SET)
1425 			attributes[n_attrs++] = REFRESH_ERROR_ACTION;
1426 		if (table_info->refreshErrorRetry.attempts == NO_VALUE_SET)
1427 			attributes[n_attrs++] = REFRESH_ERROR_ATTEMPTS;
1428 		if (table_info->refreshErrorRetry.timeout ==
1429 			(time_t)NO_VALUE_SET)
1430 			attributes[n_attrs++] = REFRESH_ERROR_TIMEOUT;
1431 		if (table_info->matchFetch ==
1432 			(__nis_match_fetch_t)NO_VALUE_SET)
1433 			attributes[n_attrs++] = YP_MATCH_FETCH;
1434 	} else {
1435 		if (proxy_info->default_servers == NULL)
1436 			attributes[n_attrs++] = PREFERRED_SERVERS;
1437 		if (proxy_info->auth_method == (auth_method_t)NO_VALUE_SET)
1438 			attributes[n_attrs++] = AUTH_METHOD;
1439 		if (proxy_info->tls_method == (tls_method_t)NO_VALUE_SET)
1440 			attributes[n_attrs++] = TLS_OPTION;
1441 		if (proxy_info->tls_cert_db == NULL)
1442 			attributes[n_attrs++] = TLS_CERT_DB;
1443 		if (proxy_info->default_search_base == NULL)
1444 			attributes[n_attrs++] = SEARCH_BASE;
1445 		if (proxy_info->proxy_dn == NULL)
1446 			attributes[n_attrs++] = PROXY_USER;
1447 		if (proxy_info->proxy_passwd == NULL)
1448 			attributes[n_attrs++] = PROXY_PASSWD;
1449 		if (proxy_info->default_nis_domain == NULL)
1450 			attributes[n_attrs++] = LDAP_BASE_DOMAIN;
1451 		if (proxy_info->bind_timeout.tv_sec ==
1452 			(time_t)NO_VALUE_SET)
1453 			attributes[n_attrs++] = BIND_TIMEOUT;
1454 		if (proxy_info->search_timeout.tv_sec ==
1455 			(time_t)NO_VALUE_SET)
1456 			attributes[n_attrs++] = SEARCH_TIMEOUT;
1457 		if (proxy_info->modify_timeout.tv_sec ==
1458 			(time_t)NO_VALUE_SET)
1459 			attributes[n_attrs++] = MODIFY_TIMEOUT;
1460 		if (proxy_info->add_timeout.tv_sec == (time_t)NO_VALUE_SET)
1461 			attributes[n_attrs++] = ADD_TIMEOUT;
1462 		if (proxy_info->delete_timeout.tv_sec ==
1463 			(time_t)NO_VALUE_SET)
1464 			attributes[n_attrs++] = DELETE_TIMEOUT;
1465 		if (proxy_info->search_time_limit == (int)NO_VALUE_SET)
1466 			attributes[n_attrs++] = SEARCH_TIME_LIMIT;
1467 		if (proxy_info->search_size_limit == (int)NO_VALUE_SET)
1468 			attributes[n_attrs++] = SEARCH_SIZE_LIMIT;
1469 		if (proxy_info->follow_referral ==
1470 			(follow_referral_t)NO_VALUE_SET)
1471 			attributes[n_attrs++] = FOLLOW_REFERRAL;
1472 
1473 		if (table_info->retrieveError ==
1474 			(__nis_retrieve_error_t)NO_VALUE_SET)
1475 			attributes[n_attrs++] = RETRIEVE_ERROR_ACTION;
1476 		if (table_info->retrieveErrorRetry.attempts == NO_VALUE_SET)
1477 			attributes[n_attrs++] = RETREIVE_ERROR_ATTEMPTS;
1478 		if (table_info->retrieveErrorRetry.timeout ==
1479 			(time_t)NO_VALUE_SET)
1480 			attributes[n_attrs++] = RETREIVE_ERROR_TIMEOUT;
1481 		if (table_info->storeError ==
1482 			(__nis_store_error_t)NO_VALUE_SET)
1483 			attributes[n_attrs++] = STORE_ERROR_ACTION;
1484 		if (table_info->storeErrorRetry.attempts == NO_VALUE_SET)
1485 			attributes[n_attrs++] = STORE_ERROR_ATTEMPTS;
1486 		if (table_info->storeErrorRetry.timeout ==
1487 			(time_t)NO_VALUE_SET)
1488 			attributes[n_attrs++] = STORE_ERROR_TIMEOUT;
1489 		if (table_info->refreshError ==
1490 			(__nis_refresh_error_t)NO_VALUE_SET)
1491 			attributes[n_attrs++] = REFRESH_ERROR_ACTION;
1492 		if (table_info->refreshErrorRetry.attempts == NO_VALUE_SET)
1493 			attributes[n_attrs++] = REFRESH_ERROR_ATTEMPTS;
1494 		if (table_info->refreshErrorRetry.timeout ==
1495 			(time_t)NO_VALUE_SET)
1496 			attributes[n_attrs++] = REFRESH_ERROR_TIMEOUT;
1497 		if (table_info->matchFetch ==
1498 			(__nis_match_fetch_t)NO_VALUE_SET)
1499 			attributes[n_attrs++] = MATCH_FETCH;
1500 	}
1501 
1502 	switch (nis_config->initialUpdate) {
1503 		case (__nis_initial_update_t)NO_VALUE_SET:
1504 			attributes[n_attrs++] = INITIAL_UPDATE_ACTION;
1505 			attributes[n_attrs++] = INITIAL_UPDATE_ONLY;
1506 			break;
1507 		case (__nis_initial_update_t)INITIAL_UPDATE_NO_ACTION:
1508 		case (__nis_initial_update_t)NO_INITIAL_UPDATE_NO_ACTION:
1509 			attributes[n_attrs++] = INITIAL_UPDATE_ACTION;
1510 			break;
1511 		case (__nis_initial_update_t)FROM_NO_INITIAL_UPDATE:
1512 		case (__nis_initial_update_t)TO_NO_INITIAL_UPDATE:
1513 			attributes[n_attrs++] = INITIAL_UPDATE_ONLY;
1514 			break;
1515 	}
1516 
1517 	if (nis_config->threadCreationError ==
1518 	    (__nis_thread_creation_error_t)NO_VALUE_SET)
1519 		attributes[n_attrs++] = THREAD_CREATE_ERROR_ACTION;
1520 	if (nis_config->threadCreationErrorTimeout.attempts == NO_VALUE_SET)
1521 		attributes[n_attrs++] = THREAD_CREATE_ERROR_ATTEMPTS;
1522 	if (nis_config->threadCreationErrorTimeout.timeout ==
1523 			(time_t)NO_VALUE_SET)
1524 		attributes[n_attrs++] = THREAD_CREATE_ERROR_TIMEOUT;
1525 	if (nis_config->dumpError == (__nis_dump_error_t)NO_VALUE_SET)
1526 		attributes[n_attrs++] = DUMP_ERROR_ACTION;
1527 	if (nis_config->dumpErrorTimeout.attempts == NO_VALUE_SET)
1528 		attributes[n_attrs++] = DUMP_ERROR_ATTEMPTS;
1529 	if (nis_config->dumpErrorTimeout.timeout == (time_t)NO_VALUE_SET)
1530 		attributes[n_attrs++] = DUMP_ERROR_TIMEOUT;
1531 	if (nis_config->resyncService == (__nis_resync_service_t)NO_VALUE_SET)
1532 		attributes[n_attrs++] = RESYNC;
1533 	if (nis_config->updateBatching ==
1534 			(__nis_update_batching_t)NO_VALUE_SET)
1535 		attributes[n_attrs++] = UPDATE_BATCHING;
1536 	if (nis_config->updateBatchingTimeout.timeout == (time_t)NO_VALUE_SET)
1537 		attributes[n_attrs++] = UPDATE_BATCHING_TIMEOUT;
1538 	if (nis_config->numberOfServiceThreads == (int)NO_VALUE_SET)
1539 		attributes[n_attrs++] = NUMBER_THEADS;
1540 	if (nis_config->emulate_yp == (int)NO_VALUE_SET)
1541 		attributes[n_attrs++] = YP_EMULATION;
1542 
1543 	/* maxRPCRecordSize is not configurable through LDAP profiles */
1544 	if (nis_config->maxRPCRecordSize == (int)NO_VALUE_SET)
1545 		attributes[n_attrs++] = MAX_RPC_RECSIZE;
1546 
1547 	attributes[n_attrs++] = NULL;
1548 }
1549 
1550 /*
1551  *	Notes on adding new attributes
1552  *	1. Determine where the attribute value will be saved
1553  *	    Currently, the following structures are defined:
1554  *		__nis_config_info_t	config_info
1555  *		__nis_ldap_proxy_info	proxyInfo
1556  *		__nis_config_t		ldapConfig
1557  *		__nisdb_table_mapping_t	ldapDBTableMapping
1558  *		__nis_table_mapping_t	ldapTableMapping
1559  *	    or add a new structure or variable - this will require
1560  *	    more code.
1561  *	2. Initialize the value to a known unconfigured value.
1562  *	    This can be done in initialize_parse_structs or
1563  *	    parse_ldap_migration.
1564  *	3. In the header file nis_parse_ldap_conf.h, add the name
1565  *	    of the attribute. (Currently, the attribute name is assumed
1566  *	    to be the same for the command line, the preference file,
1567  *	    and LDAP.) The names are grouped logically. Add a corresponding
1568  *	    config_key to the enum. Note that position in this file is
1569  *	    essential because the macros such as IS_BIND_INFO depend on
1570  *	    the sequence. The corresponding macro (IS_CONFIG_KEYWORD,
1571  *	    IS_BIND_INFO, or IS_OPER_INFO) may need to be adjusted. These
1572  *	    are used to partition the attributes into smaller chunks.
1573  *	4. Add the correspond entry to the keyword_lookup array in
1574  *	    nis_parse_ldap_attr.c, which is used to determine the config_key
1575  *	    from the corresponding key word.
1576  *	5. Add the attribute to the list of attributes to retrieve from
1577  *	    the LDAP server if no value has been set in the function
1578  *	    parse_ldap_config_dn_attrs. (This assumes that the attribute
1579  *	    is not used to get the configuration from the LDAP server.)
1580  *	6. Add logic to parse the individual attribute in
1581  *	    add_config_attribute, add_bind_attribute,
1582  *	    add_operation_attribute, or add_mapping_attribute depending
1583  *	    which group of attributes the added attribute belongs to.
1584  *	7. In set_default_values, if the attribute value has not been set, set
1585  *	    the default value. If any additional fixup is needed depending
1586  *	    on other configuration values, it should be done here.
1587  *	8. If an attribute name is a subset of another, parse_ldap_default_conf
1588  *          should be modified.
1589  *	9. Add the new attribute to the class action script
1590  *	   usr/src/pkgdefs/common_files/i.defrpc.nisd, if the user
1591  *	   configured value has to be preserved across upgrades
1592  */
1593