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