Home | History | Annotate | Download | only in libnisdb
      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