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