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