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