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 2006 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <stdio.h>
     29 #include <string.h>
     30 #include <stdlib.h>
     31 #include <ctype.h>
     32 #include <fcntl.h>
     33 #include <unistd.h>
     34 #include <errno.h>
     35 #include <locale.h>
     36 #include <sys/stat.h>
     37 #include <lber.h>
     38 #include <ldap.h>
     39 #include <deflt.h>
     40 
     41 #include "ldap_map.h"
     42 
     43 #include "ldap_parse.h"
     44 #include "ldap_glob.h"
     45 #include "nis_parse_ldap_conf.h"
     46 
     47 __nis_ldap_proxy_info	proxyInfo		=
     48 	{NULL, (auth_method_t)NO_VALUE_SET, (tls_method_t)NO_VALUE_SET, NULL,
     49 		NULL, NULL, NULL, NULL, (follow_referral_t)NO_VALUE_SET};
     50 __nis_config_t		ldapConfig;
     51 __nisdb_table_mapping_t ldapDBTableMapping;
     52 __nis_table_mapping_t	*ldapTableMapping	= NULL;
     53 __yp_domain_context_t	ypDomains;
     54 
     55 parse_error		p_error			= no_parse_error;
     56 int			cur_line_num		= 0;
     57 int			start_line_num		= 0;
     58 int			seq_num 		= 0;
     59 const char		*warn_file		= NULL;
     60 
     61 char			_key_val[38];
     62 const char		*command_line_source	= NULL;
     63 const char		*file_source		= NULL;
     64 const char		*ldap_source		= NULL;
     65 
     66 static
     67 const char *const	*cmdline_config		= NULL;
     68 static bool_t		got_config_data		= FALSE;
     69 
     70 /* high level parsing functions functions */
     71 static int parse_ldap_cmd_line(const char *const *cmdline_options,
     72     __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config,
     73     __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info,
     74     __nisdb_table_mapping_t *table_info);
     75 static int parse_ldap_default_conf(__nis_ldap_proxy_info *proxy_info,
     76     __nis_config_t *nis_config, __nis_config_info_t *config_info,
     77     __nisdb_table_mapping_t *table_info);
     78 static int parse_ldap_config_file(const char *config_file,
     79     __nis_ldap_proxy_info *proxy_info, __nis_config_t *nis_config,
     80     __nis_table_mapping_t **table_mapping, __nis_config_info_t *config_info,
     81     __nisdb_table_mapping_t *table_info);
     82 static int parse_ldap_config_dn_attrs(__nis_ldap_proxy_info *proxy_info,
     83     __nis_config_t *nis_config, __nis_table_mapping_t **table_mapping,
     84     __nis_config_info_t *config_info, __nisdb_table_mapping_t *table_info);
     85 static int yp_parse_ldap_default_conf(__nis_ldap_proxy_info *proxy_info,
     86 	__nis_config_t *nis_config, __nis_config_info_t *config_info,
     87 	__nisdb_table_mapping_t *table_info);
     88 
     89 
     90 /* helper functions */
     91 static config_key get_attrib_num_cmdline(const char *s,
     92     const char **begin_s, const char **end_s);
     93 static config_key get_file_attr_val(int fd, char **attr_val);
     94 static void get_attribute_list(
     95 	const __nis_ldap_proxy_info *proxy_info,
     96 	const __nis_config_t *nis_config,
     97 	const __nis_config_info_t *config_info,
     98 	const __nisdb_table_mapping_t *table_info,
     99 	char **ldap_config_attributes);
    100 
    101 /*
    102  * FUNCTION:	parse_ldap_migration
    103  *
    104  *	Parses the information for LDAP. The values are first
    105  *	obtained from the command line, secondly from the preference
    106  *	file, and finally from an LDAP profile (if so configured in
    107  *	the command line or preference file). Any unset values will
    108  *	be set to their default values.
    109  *
    110  *	If no command line options, no settings in the /etc/default
    111  *  configuration file, and no mapping file, then no mapping
    112  *  should be used.
    113  *
    114  * RETURN VALUE:
    115  *			0	Success
    116  *			-1	Config file stat/open or parse error
    117  *			1	No mapping should be used.
    118  *
    119  * INPUT:		command line parameters, configuration file
    120  */
    121 
    122 int
    123 parse_ldap_migration(
    124 	const char *const	*cmdline_options,
    125 	const char		*config_file)
    126 {
    127 	int			rc	= 0;
    128 	__nis_config_info_t	config_info
    129 				= {NULL, NULL, (auth_method_t)NO_VALUE_SET,
    130 					(tls_method_t)NO_VALUE_SET, NULL,
    131 					NULL, NULL};
    132 	struct stat		buf;
    133 	int i = 0;
    134 
    135 	p_error = no_parse_error;
    136 
    137 	if (verbose)
    138 		report_info("Getting LDAP configuration", NULL);
    139 
    140 	initialize_parse_structs(&proxyInfo, &ldapConfig, &ldapDBTableMapping);
    141 
    142 	if (yp2ldap)
    143 		initialize_yp_parse_structs(&ypDomains);
    144 
    145 	if (cmdline_options != NULL) {
    146 		got_config_data = TRUE;
    147 		/* NIS to LDAP does not read command line attributes */
    148 		if (!yp2ldap)
    149 			rc = parse_ldap_cmd_line(cmdline_options, &proxyInfo,
    150 				&ldapConfig, &ldapTableMapping, &config_info,
    151 				&ldapDBTableMapping);
    152 		else
    153 			rc = 0;
    154 	}
    155 
    156 	if (rc == 0) {
    157 		if (yp2ldap)
    158 			rc = yp_parse_ldap_default_conf(&proxyInfo, &ldapConfig,
    159 				&config_info, &ldapDBTableMapping);
    160 		else
    161 			rc = parse_ldap_default_conf(&proxyInfo, &ldapConfig,
    162 				&config_info, &ldapDBTableMapping);
    163 	}
    164 
    165 	if (config_file == NULL) {
    166 		if (yp2ldap) {
    167 			if (stat(YP_DEFAULT_MAPPING_FILE, &buf) == 0)
    168 				config_file = YP_DEFAULT_MAPPING_FILE;
    169 		} else {
    170 			if (stat(DEFAULT_MAPPING_FILE, &buf) == 0)
    171 				config_file = DEFAULT_MAPPING_FILE;
    172 		}
    173 	}
    174 
    175 	if (rc == 0 && config_file != NULL) {
    176 		got_config_data = TRUE;
    177 		warn_file = config_file;
    178 		cmdline_config = cmdline_options;
    179 		if (yp2ldap)
    180 			rc = yp_parse_ldap_config_file(config_file, &proxyInfo,
    181 				&ldapConfig, &ldapTableMapping, &config_info,
    182 				&ldapDBTableMapping, &ypDomains);
    183 		else
    184 			rc = parse_ldap_config_file(config_file, &proxyInfo,
    185 				&ldapConfig, &ldapTableMapping, &config_info,
    186 				&ldapDBTableMapping);
    187 
    188 		warn_file = NULL;
    189 		cmdline_config = NULL;
    190 	}
    191 	if (rc == 0 && (config_info.config_dn != NULL) &&
    192 			(config_info.config_dn[0] != '\0')) {
    193 		rc = parse_ldap_config_dn_attrs(&proxyInfo,
    194 			&ldapConfig, &ldapTableMapping, &config_info,
    195 			&ldapDBTableMapping);
    196 	}
    197 
    198 	free_config_info(&config_info);
    199 
    200 	if (rc == 0 && got_config_data == FALSE)
    201 		rc = 1;
    202 
    203 	set_default_values(&proxyInfo, &ldapConfig, &ldapDBTableMapping);
    204 
    205 	if (yp2ldap == 1 && rc == 0) {
    206 		rc = second_parser_pass(&ldapTableMapping);
    207 		if (rc == 0)
    208 			rc = final_parser_pass(&ldapTableMapping, &ypDomains);
    209 		if (rc == -2)
    210 			return (-1);
    211 	}
    212 
    213 	if (rc == 0)
    214 		rc = finish_parse(&proxyInfo, &ldapTableMapping);
    215 
    216 	if (rc == 0)
    217 		rc = linked2hash(ldapTableMapping);
    218 
    219 	if ((rc == 0) && yptol_mode)
    220 		rc = map_id_list_init();
    221 
    222 	if (rc != 0) {
    223 		free_parse_structs();
    224 	} else if (verbose)
    225 		report_info("LDAP configuration complete", NULL);
    226 	return (rc);
    227 }
    228 
    229 /*
    230  * FUNCTION:	parse_ldap_cmd_line
    231  *
    232  *	Parses the information for LDAP from the command line
    233  *
    234  * RETURN VALUE:	0 on success, -1 on failure
    235  *
    236  * INPUT:		command line values
    237  */
    238 
    239 static int
    240 parse_ldap_cmd_line(
    241 	const char *const	*cmdline_options,
    242 	__nis_ldap_proxy_info	*proxy_info,
    243 	__nis_config_t		*nis_config,
    244 	__nis_table_mapping_t	**table_mapping,
    245 	__nis_config_info_t	*config_info,
    246 	__nisdb_table_mapping_t	*table_info)
    247 {
    248 	int		rc = 0;
    249 	config_key	attrib_num;
    250 	const char	*begin_s;
    251 	const char	*end_s;
    252 
    253 	if (verbose)
    254 		report_info("Command line values: ", NULL);
    255 	while (*cmdline_options != NULL) {
    256 		if (verbose)
    257 			report_info("\t", *cmdline_options);
    258 
    259 		attrib_num = get_attrib_num_cmdline(
    260 		    *cmdline_options, &begin_s, &end_s);
    261 		if (attrib_num == key_bad) {
    262 			command_line_source = "command line";
    263 			report_error(*cmdline_options, NULL);
    264 			command_line_source = NULL;
    265 			rc = -1;
    266 			break;
    267 		} else if (IS_CONFIG_KEYWORD(attrib_num)) {
    268 			rc = add_config_attribute(attrib_num,
    269 			    begin_s, end_s - begin_s, config_info);
    270 		} else if (IS_BIND_INFO(attrib_num)) {
    271 			rc = add_bind_attribute(attrib_num,
    272 			    begin_s, end_s - begin_s, proxy_info);
    273 		} else if (IS_OPER_INFO(attrib_num)) {
    274 			rc = add_operation_attribute(attrib_num,
    275 			    begin_s, end_s - begin_s, nis_config,
    276 			    table_info);
    277 		} else {
    278 			rc = add_mapping_attribute(attrib_num,
    279 			    begin_s, end_s - begin_s, table_mapping);
    280 		}
    281 
    282 		if (rc < 0) {
    283 			command_line_source = "command line";
    284 			report_error(begin_s, _key_val);
    285 			command_line_source = NULL;
    286 			break;
    287 		}
    288 		cmdline_options++;
    289 	}
    290 	return (rc);
    291 }
    292 
    293 static int
    294 parse_ldap_default_conf(
    295 	__nis_ldap_proxy_info *proxy_info,
    296 	__nis_config_t *nis_config,
    297 	__nis_config_info_t *config_info,
    298 	__nisdb_table_mapping_t	*table_info)
    299 {
    300 	int		rc = 0;
    301 	char		*ldap_config_attributes[n_config_keys];
    302 	char		attr_buf[128];
    303 	char		*attr;
    304 	static char	*attr_val;
    305 	int		defflags;
    306 	config_key	attrib_num;
    307 	int		i;
    308 	int		len;
    309 	int		attr_len;
    310 
    311 		if (defopen(ETCCONFFILE) == 0) {
    312 			file_source = ETCCONFFILE;
    313 			if (verbose)
    314 				report_info(
    315 				"default configuration values: ", NULL);
    316 			/* Set defread() to be case insensitive */
    317 			defflags = defcntl(DC_GETFLAGS, 0);
    318 			TURNOFF(defflags, DC_CASE);
    319 			(void) defcntl(DC_SETFLAGS, defflags);
    320 
    321 			get_attribute_list(proxy_info, nis_config, config_info,
    322 				table_info, ldap_config_attributes);
    323 			i = 0;
    324 			while ((attr = ldap_config_attributes[i++]) != NULL) {
    325 				strlcpy(attr_buf, attr, sizeof (attr_buf));
    326 				/*
    327 				 * if nisplusUpdateBatching, make sure
    328 				 * we don't match nisplusUpdateBatchingTimeout
    329 				 */
    330 				if (strcmp(attr, UPDATE_BATCHING) == 0) {
    331 					attr_len = strlen(attr);
    332 					attr_buf[attr_len] = '=';
    333 					attr_buf[attr_len + 1] = '\0';
    334 					attr_val = defread(attr_buf);
    335 
    336 					if (attr_val == 0) {
    337 						attr_buf[attr_len] = ' ';
    338 						attr_val = defread(attr_buf);
    339 					}
    340 					if (attr_val == 0) {
    341 						attr_buf[attr_len] = '\t';
    342 						attr_val = defread(attr_buf);
    343 					}
    344 					if (attr_val == 0) {
    345 						attr_buf[attr_len] = '\n';
    346 						attr_val = defread(attr_buf);
    347 					}
    348 				} else {
    349 					attr_val = defread(attr_buf);
    350 				}
    351 				if (attr_val == 0)
    352 					continue;
    353 
    354 				got_config_data = TRUE;
    355 				attrib_num = get_attrib_num(attr, strlen(attr));
    356 				if (attrib_num == key_bad) {
    357 					report_error(attr, NULL);
    358 					rc = -1;
    359 					break;
    360 				}
    361 
    362 				/*
    363 				 * Allow either entries of the form
    364 				 *	attr val
    365 				 *	   or
    366 				 *	attr = val
    367 				 */
    368 				while (is_whitespace(*attr_val))
    369 					attr_val++;
    370 				if (*attr_val == '=')
    371 					attr_val++;
    372 				while (is_whitespace(*attr_val))
    373 					attr_val++;
    374 				len = strlen(attr_val);
    375 				while (len > 0 &&
    376 					is_whitespace(attr_val[len - 1]))
    377 					len--;
    378 
    379 				if (verbose) {
    380 					report_info("\t", attr);
    381 					report_info("\t\t", attr_val);
    382 				}
    383 				if (IS_BIND_INFO(attrib_num)) {
    384 					rc = add_bind_attribute(attrib_num,
    385 					    attr_val, len, proxy_info);
    386 				} else if (IS_OPER_INFO(attrib_num)) {
    387 					rc = add_operation_attribute(attrib_num,
    388 						attr_val, len, nis_config,
    389 						table_info);
    390 				}
    391 				if (p_error != no_parse_error) {
    392 					report_error(attr_val, attr);
    393 					rc = -1;
    394 					break;
    395 				}
    396 			}
    397 			file_source = NULL;
    398 			/* Close the /etc/default file */
    399 			(void) defopen(0);
    400 		}
    401 		return (rc);
    402 }
    403 
    404 static int
    405 yp_parse_ldap_default_conf(
    406 	__nis_ldap_proxy_info *proxy_info,
    407 	__nis_config_t	*nis_config,
    408 	__nis_config_info_t *config_info,
    409 	__nisdb_table_mapping_t *table_info)
    410 {
    411 	int rc = 0;
    412 	char		*ldap_config_attributes[n_config_keys];
    413 	char		attr_buf[128];
    414 	char		*attr;
    415 	static 	char *attr_val;
    416 	int		defflags;
    417 	config_key	attrib_num;
    418 	int 	i, len, attr_len;
    419 
    420 	if ((defopen(YP_ETCCONFFILE)) == 0) {
    421 		file_source = YP_ETCCONFFILE;
    422 		if (verbose)
    423 			report_info("default configuration values: ", NULL);
    424 		/* Set defread() to be case insensitive */
    425 			defflags = defcntl(DC_GETFLAGS, 0);
    426 			TURNOFF(defflags, DC_CASE);
    427 			(void) defcntl(DC_SETFLAGS, defflags);
    428 
    429 			get_attribute_list(proxy_info, nis_config, config_info,
    430 				table_info, ldap_config_attributes);
    431 			i = 0;
    432 			while ((attr = ldap_config_attributes[i++]) != NULL) {
    433 				if ((strlcpy(attr_buf, attr,
    434 					sizeof (attr_buf))) >=
    435 					sizeof (attr_buf)) {
    436 					report_error(
    437 				"Static buffer attr_buf overflow", NULL);
    438 					return (-1);
    439 				}
    440 
    441 				if ((attr_val = defread(attr_buf)) == 0)
    442 					continue;
    443 
    444 				got_config_data = TRUE;
    445 				attrib_num = get_attrib_num(attr, strlen(attr));
    446 				if (attrib_num == key_bad) {
    447 					report_error(attr, NULL);
    448 					rc = -1;
    449 					break;
    450 				}
    451 
    452 				/*
    453 				 * Allow either entries of the form
    454 				 * attr val
    455 				 * or
    456 				 * attr = val
    457 				 */
    458 				while (is_whitespace(*attr_val))
    459 					attr_val++;
    460 				if (*attr_val == '=')
    461 					attr_val++;
    462 				while (is_whitespace(*attr_val))
    463 					attr_val++;
    464 				len = strlen(attr_val);
    465 				while (len > 0 &&
    466 					is_whitespace(attr_val[len - 1]))
    467 					len--;
    468 
    469 				if (verbose) {
    470 					report_info("\t", attr);
    471 					report_info("\t\t", attr_val);
    472 				}
    473 				if (IS_YP_BIND_INFO(attrib_num)) {
    474 					rc = add_bind_attribute(attrib_num,
    475 						attr_val, len, proxy_info);
    476 				} else if (IS_YP_OPER_INFO(attrib_num)) {
    477 					rc = add_operation_attribute(attrib_num,
    478 						attr_val, len, nis_config,
    479 						table_info);
    480 				}
    481 				if (p_error != no_parse_error) {
    482 					report_error(attr_val, attr);
    483 					rc = -1;
    484 					break;
    485 				}
    486 			}
    487 			file_source = NULL;
    488 			/* Close the /etc/default file */
    489 			(void) defopen(0);
    490 		}
    491 		return (rc);
    492 }
    493 
    494 /*
    495  * FUNCTION:	get_attrib_num_cmdline
    496  *
    497  *	Parses the information for LDAP from the command line
    498  *	The form of the command line request is
    499  *		-x attribute=value
    500  *
    501  * RETURN VALUE:	0 on success, -1 on failure
    502  *
    503  * INPUT:		command line values
    504  */
    505 
    506 static config_key
    507 get_attrib_num_cmdline(
    508 	const char	*s,
    509 	const char 	**begin_s,
    510 	const char 	**end_s)
    511 {
    512 	const char	*s_end		= s + strlen(s);
    513 	const char	*equal_s;
    514 	const char	*s1;
    515 	config_key	attrib_num;
    516 
    517 	while (s < s_end && is_whitespace(*s))
    518 		s++;
    519 
    520 	for (equal_s = s; equal_s < s_end; equal_s++)
    521 		if (*equal_s == EQUAL_CHAR)
    522 			break;
    523 
    524 	if (equal_s == s_end) {
    525 		p_error = parse_bad_command_line_attribute_format;
    526 		return (key_bad);
    527 	}
    528 
    529 	for (s1 = equal_s; s1 > s && is_whitespace(s1[-1]); s1--)
    530 		;
    531 
    532 	if (s1 == s) {
    533 		p_error = parse_bad_command_line_attribute_format;
    534 		return (key_bad);
    535 	}
    536 
    537 	attrib_num = get_attrib_num(s, s1 - s);
    538 
    539 	if (attrib_num != key_bad) {
    540 		s1 = equal_s + 1;
    541 		while (s1 < s_end && is_whitespace(*s1))
    542 			s1++;
    543 		*begin_s = s1;
    544 		while (s_end > s1 && is_whitespace(s_end[-1]))
    545 			s_end--;
    546 		*end_s = s_end;
    547 	}
    548 
    549 	return (attrib_num);
    550 }
    551 
    552 /*
    553  * FUNCTION:	parse_ldap_config_file
    554  *
    555  *	Parses the information for LDAP from a configuration
    556  *	file. If no file is specified, /var/nis/NIS+LDAPmapping
    557  *	is used
    558  *
    559  * RETURN VALUE:	0 on success, -1 on failure
    560  *
    561  * INPUT:		configuration file name
    562  */
    563 
    564 static int
    565 parse_ldap_config_file(
    566 	const char 		*config_file,
    567 	__nis_ldap_proxy_info	*proxy_info,
    568 	__nis_config_t		*nis_config,
    569 	__nis_table_mapping_t	**table_mapping,
    570 	__nis_config_info_t	*config_info,
    571 	__nisdb_table_mapping_t	*table_info)
    572 {
    573 	int		rc = 0;
    574 	config_key	attrib_num;
    575 	int		fd;
    576 	char		*attr_val;
    577 	int		len;
    578 
    579 	if ((fd = open(config_file, O_RDONLY)) == -1) {
    580 		p_error = parse_open_file_error;
    581 		report_error(config_file, NULL);
    582 		return (-1);
    583 	}
    584 
    585 	start_line_num = 1;
    586 	cur_line_num = 1;
    587 
    588 	if (verbose)
    589 		report_info("Reading configuration from ", config_file);
    590 
    591 	file_source = config_file;
    592 	while ((attrib_num = get_file_attr_val(fd, &attr_val)) > 0) {
    593 		len = attr_val == NULL ? 0 : strlen(attr_val);
    594 		if (IS_CONFIG_KEYWORD(attrib_num)) {
    595 			rc = add_config_attribute(attrib_num,
    596 			    attr_val, len, config_info);
    597 		} else if (IS_BIND_INFO(attrib_num)) {
    598 			rc = add_bind_attribute(attrib_num,
    599 			    attr_val, len, proxy_info);
    600 		} else if (IS_OPER_INFO(attrib_num)) {
    601 			rc = add_operation_attribute(attrib_num,
    602 			    attr_val, len, nis_config, table_info);
    603 		} else {
    604 			rc = add_mapping_attribute(attrib_num,
    605 		    attr_val, len, table_mapping);
    606 		}
    607 
    608 		if (rc < 0) {
    609 			report_error(attr_val == NULL ?
    610 				"<no attribute>" : attr_val, _key_val);
    611 			if (attr_val)
    612 				free(attr_val);
    613 			break;
    614 		}
    615 		if (attr_val)
    616 			free(attr_val);
    617 	}
    618 
    619 	(void) close(fd);
    620 	if (attrib_num == key_bad) {
    621 		report_error(_key_val, NULL);
    622 		rc = -1;
    623 	}
    624 	start_line_num = 0;
    625 	file_source = NULL;
    626 	return (rc);
    627 }
    628 
    629 /*
    630  * FUNCTION:	yp_parse_ldap_config_file
    631  *
    632  * Parses the information for LDAP from a configuration
    633  * file. If no file is specified, /var/yp/NISLDAPmapping
    634  * is used
    635  *
    636  * RETURN VALUE:    0 on success, -1 on failure
    637  *
    638  * INPUT:       configuration file name
    639  */
    640 
    641 int
    642 yp_parse_ldap_config_file(
    643 	const char	*config_file,
    644 	__nis_ldap_proxy_info	*proxy_info,
    645 	__nis_config_t			*nis_config,
    646 	__nis_table_mapping_t	**table_mapping,
    647 	__nis_config_info_t		*config_info,
    648 	__nisdb_table_mapping_t	*table_info,
    649 	__yp_domain_context_t	*ypDomains)
    650 {
    651 	int	rc = 0;
    652 	int	numDomains = 0;
    653 	config_key	attrib_num;
    654 	int	fd;
    655 	char	*attr_val = NULL;
    656 	int		len;
    657 
    658 	if ((fd = open(config_file, O_RDONLY)) == -1) {
    659 		p_error = parse_open_file_error;
    660 		report_error(config_file, NULL);
    661 		return (-1);
    662 	}
    663 
    664 	start_line_num = 1;
    665 	cur_line_num = 1;
    666 
    667 	if (verbose)
    668 		report_info("Reading configuration from ", config_file);
    669 
    670 	file_source = config_file;
    671 	while ((attrib_num = get_file_attr_val(fd, &attr_val)) > 0) {
    672 		len = attr_val == NULL ? 0 : strlen(attr_val);
    673 		if (IS_YP_CONFIG_KEYWORD(attrib_num)) {
    674 			rc = add_config_attribute(attrib_num,
    675 				attr_val, len, config_info);
    676 		} else if (IS_YP_BIND_INFO(attrib_num)) {
    677 			rc = add_bind_attribute(attrib_num,
    678 				attr_val, len, proxy_info);
    679 		} else if (IS_YP_OPER_INFO(attrib_num)) {
    680 			rc = add_operation_attribute(attrib_num,
    681 				attr_val, len, nis_config, table_info);
    682 		} else if (IS_YP_DOMAIN_INFO(attrib_num)) {
    683 			rc = add_ypdomains_attribute(attrib_num,
    684 				attr_val, len, ypDomains);
    685 		} else if (IS_YP_MAP_ATTR(attrib_num)) {
    686 			rc = add_mapping_attribute(attrib_num,
    687 				attr_val, len, table_mapping);
    688 		} else {
    689 			rc = -1;
    690 			p_error = parse_unsupported_format;
    691 		}
    692 
    693 		if (rc < 0) {
    694 			report_error(attr_val == NULL ?
    695 				"<no attribute>" : attr_val, _key_val);
    696 			if (attr_val)
    697 				free(attr_val);
    698 			break;
    699 		}
    700 		if (attr_val) {
    701 			free(attr_val);
    702 			attr_val = NULL;
    703 		}
    704 	}
    705 
    706 	(void) close(fd);
    707 	if (attrib_num == key_bad) {
    708 		report_error(_key_val, NULL);
    709 		rc = -1;
    710 	}
    711 	start_line_num = 0;
    712 	file_source = NULL;
    713 	return (rc);
    714 }
    715 
    716 /*
    717  * FUNCTION:	get_file_attr_val
    718  *
    719  *	Gets the next attribute from the configuration file.
    720  *
    721  * RETURN VALUE:	The config key if more attributes
    722  *			no_more_keys if eof
    723  *			key_bad if error
    724  */
    725 
    726 static config_key
    727 get_file_attr_val(int fd, char **attr_val)
    728 {
    729 	char		buf[BUFSIZE];
    730 	char		*start_tag;
    731 	char		*start_val;
    732 	char		*end_val;
    733 	char		*cut_here;
    734 	char		*s;
    735 	char		*a;
    736 	char		*attribute_value;
    737 	int		ret;
    738 	config_key	attrib_num = no_more_keys;
    739 	int		found_quote = 0;
    740 
    741 	*attr_val = NULL;
    742 
    743 	if ((ret = read_line(fd, buf, sizeof (buf))) > 0) {
    744 		for (s = buf; is_whitespace(*s); s++)
    745 			;
    746 
    747 		start_tag = s;
    748 		while (*s != '\0' && !is_whitespace(*s))
    749 			s++;
    750 
    751 		if (verbose)
    752 			report_info("\t", start_tag);
    753 		attrib_num = get_attrib_num(start_tag, s - start_tag);
    754 		if (attrib_num == key_bad)
    755 			return (key_bad);
    756 
    757 		while (is_whitespace(*s))
    758 			s++;
    759 		if (*s == '\0')
    760 			return (attrib_num);
    761 		start_val = s;
    762 
    763 		/* note that read_line will not return a line ending with \ */
    764 		for (; *s != '\0'; s++) {
    765 			if (*s == ESCAPE_CHAR)
    766 				s++;
    767 		}
    768 		while (s > start_val && is_whitespace(s[-1]))
    769 			s--;
    770 
    771 		attribute_value =
    772 		(char *)calloc(1, (size_t)(s - start_val) + 1);
    773 		if (attribute_value == NULL) {
    774 			p_error = parse_no_mem_error;
    775 			return (key_bad);
    776 		}
    777 		attr_val[0] = attribute_value;
    778 
    779 		a = *attr_val;
    780 		end_val = s;
    781 		cut_here = 0;
    782 		for (s = start_val; s < end_val; s++) {
    783 			if (*s == POUND_SIGN) {
    784 					cut_here = s;
    785 					while (s < end_val) {
    786 						if (*s == DOUBLE_QUOTE_CHAR ||
    787 						*s == SINGLE_QUOTE_CHAR) {
    788 							cut_here = 0;
    789 							break;
    790 						}
    791 						s++;
    792 					}
    793 			}
    794 		}
    795 		if (cut_here != 0)
    796 			end_val = cut_here;
    797 
    798 		for (s = start_val; s < end_val; s++)
    799 			*a++ = *s;
    800 		*a++ = '\0';
    801 	}
    802 	if (ret == -1)
    803 		return (key_bad);
    804 
    805 	return (attrib_num);
    806 }
    807 
    808 static LDAP *
    809 connect_to_ldap_config_server(
    810 	char			*sever_name,
    811 	int			server_port,
    812 	__nis_config_info_t	*config_info)
    813 {
    814 	int		rc		= 0;
    815 	LDAP		*ld		= NULL;
    816 	int		ldapVersion	= LDAP_VERSION3;
    817 	int		derefOption	= LDAP_DEREF_ALWAYS;
    818 	int		timelimit	= LDAP_NO_LIMIT;
    819 	int		sizelimit	= LDAP_NO_LIMIT;
    820 	int		errnum;
    821 	bool_t		retrying	= FALSE;
    822 	int		sleep_seconds	= 1;
    823 	struct berval	cred;
    824 
    825 	if (config_info->tls_method == no_tls) {
    826 		ld = ldap_init(sever_name, server_port);
    827 		if (ld == NULL) {
    828 			p_error = parse_ldap_init_error;
    829 			report_error(strerror(errno), NULL);
    830 			return (NULL);
    831 		}
    832 	} else {
    833 		if ((errnum = ldapssl_client_init(
    834 			config_info->tls_cert_db, NULL)) < 0) {
    835 			p_error = parse_ldapssl_client_init_error;
    836 			report_error(ldapssl_err2string(errnum), NULL);
    837 			return (NULL);
    838 		}
    839 		ld = ldapssl_init(sever_name, server_port, 1);
    840 		if (ld == NULL) {
    841 			p_error = parse_ldapssl_init_error;
    842 			report_error(strerror(errno), NULL);
    843 			return (NULL);
    844 		}
    845 	}
    846 
    847 	(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
    848 		&ldapVersion);
    849 	(void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
    850 	(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
    851 	(void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit);
    852 	(void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
    853 
    854 	/*
    855 	 * Attempt to bind to the LDAP server.
    856 	 * We will loop until success or until an error other
    857 	 * than LDAP_CONNECT_ERROR or LDAP_SERVER_DOWN
    858 	 */
    859 	if (verbose)
    860 		report_info("Connecting to ", sever_name);
    861 
    862 	for (;;) {
    863 		if (config_info->auth_method == simple) {
    864 			errnum = ldap_simple_bind_s(ld, config_info->proxy_dn,
    865 				config_info->proxy_passwd);
    866 		} else if (config_info->auth_method == cram_md5) {
    867 			cred.bv_len = strlen(config_info->proxy_passwd);
    868 			cred.bv_val = config_info->proxy_passwd;
    869 			errnum = ldap_sasl_cram_md5_bind_s(ld,
    870 				config_info->proxy_dn, &cred, NULL, NULL);
    871 		} else if (config_info->auth_method == digest_md5) {
    872 			cred.bv_len = strlen(config_info->proxy_passwd);
    873 			cred.bv_val = config_info->proxy_passwd;
    874 			errnum = ldap_x_sasl_digest_md5_bind_s(ld,
    875 				config_info->proxy_dn, &cred, NULL, NULL);
    876 		} else {
    877 			errnum = ldap_simple_bind_s(ld, NULL, NULL);
    878 		}
    879 
    880 		if (errnum == LDAP_SUCCESS)
    881 			break;
    882 
    883 		if (errnum == LDAP_CONNECT_ERROR ||
    884 			errnum == LDAP_SERVER_DOWN) {
    885 			if (!retrying) {
    886 				if (verbose)
    887 				    report_info(
    888 					"LDAP server unavailable. Retrying...",
    889 					NULL);
    890 				retrying = TRUE;
    891 			}
    892 			(void) sleep(sleep_seconds);
    893 			sleep_seconds *= 2;
    894 			if (sleep_seconds > MAX_LDAP_CONFIG_RETRY_TIME)
    895 				sleep_seconds = MAX_LDAP_CONFIG_RETRY_TIME;
    896 			p_error = no_parse_error;
    897 			continue;
    898 		}
    899 		p_error = parse_ldap_bind_error;
    900 		report_error2(config_info->proxy_dn, ldap_err2string(errnum));
    901 		(void) ldap_unbind(ld);
    902 		return (NULL);
    903 	}
    904 
    905 	if (verbose)
    906 		report_info("Reading values from ", config_info->config_dn);
    907 
    908 	return (ld);
    909 }
    910 
    911 /*
    912  * FUNCTION:	process_ldap_config_result
    913  *
    914  *	Extracts the LDAPMessage containing the nis+/LDAP
    915  *	configuration
    916  *
    917  * RETURN VALUE:	0 on success, -1 on failure
    918  *
    919  * INPUT:		LDAP		the LDAP connection
    920  *			LDAPMessage	the LDAP message
    921  */
    922 
    923 static int
    924 process_ldap_config_result(
    925 	LDAP			*ld,
    926 	LDAPMessage		*resultMsg,
    927 	__nis_ldap_proxy_info	*proxy_info,
    928 	__nis_config_t		*nis_config,
    929 	__nis_table_mapping_t	**table_mapping,
    930 	__nisdb_table_mapping_t	*table_info)
    931 {
    932 	LDAPMessage	*e;
    933 	int		errnum;
    934 	char		*attr;
    935 	BerElement	*ber		= NULL;
    936 	config_key	attrib_num;
    937 	char		**vals;
    938 	int		n;
    939 	int		i;
    940 	char		*attr_val;
    941 	int		len;
    942 	int		rc = 0;
    943 	bool_t		error_reported	= FALSE;
    944 
    945 	e = ldap_first_entry(ld, resultMsg);
    946 
    947 	if (e != NULL) {
    948 		for (attr = ldap_first_attribute(ld, e, &ber);
    949 			attr != NULL;
    950 			attr = ldap_next_attribute(ld, e, ber)) {
    951 		    if (verbose)
    952 			report_info("\t", attr);
    953 		    attrib_num = get_attrib_num(attr, strlen(attr));
    954 		    if (attrib_num == key_bad) {
    955 				report_error(attr, NULL);
    956 				break;
    957 		    }
    958 		    if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
    959 			n = ldap_count_values(vals);
    960 			/* parse the attribute values */
    961 			for (i = 0; i < n; i++) {
    962 				attr_val = vals[i];
    963 				while (is_whitespace(*attr_val))
    964 					attr_val++;
    965 				if (verbose)
    966 					report_info("\t\t", attr_val);
    967 				len = strlen(attr_val);
    968 				while (len > 0 &&
    969 				    is_whitespace(attr_val[len - 1]))
    970 					len--;
    971 				if (yp2ldap) {
    972 					if (IS_YP_BIND_INFO(attrib_num)) {
    973 						rc = add_bind_attribute(
    974 							attrib_num, attr_val,
    975 							len, proxy_info);
    976 					} else if (IS_YP_OPER_INFO(
    977 						attrib_num)) {
    978 						rc = add_operation_attribute(
    979 						attrib_num, attr_val, len,
    980 						nis_config, table_info);
    981 					} else if (IS_YP_MAP_ATTR(
    982 						attrib_num)) {
    983 						rc = add_mapping_attribute(
    984 						attrib_num, attr_val, len,
    985 						table_mapping);
    986 					} else {
    987 						p_error =
    988 						parse_unsupported_format;
    989 					}
    990 				} else {
    991 					if (IS_BIND_INFO(attrib_num)) {
    992 						rc = add_bind_attribute(
    993 						attrib_num, attr_val, len,
    994 						proxy_info);
    995 					} else if (IS_OPER_INFO(attrib_num)) {
    996 						rc = add_operation_attribute(
    997 						attrib_num, attr_val, len,
    998 						nis_config,
    999 						    table_info);
   1000 					} else {
   1001 						rc = add_mapping_attribute(
   1002 						attrib_num, attr_val, len,
   1003 						table_mapping);
   1004 					}
   1005 				}
   1006 				if (p_error != no_parse_error) {
   1007 					report_error(attr_val, attr);
   1008 					error_reported = TRUE;
   1009 					break;
   1010 				}
   1011 			}
   1012 			ldap_value_free(vals);
   1013 		    } else {
   1014 			(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
   1015 				&errnum);
   1016 			if (errnum != LDAP_SUCCESS)
   1017 				p_error = parse_ldap_get_values_error;
   1018 		    }
   1019 		    ldap_memfree(attr);
   1020 		    if (p_error != no_parse_error)
   1021 			break;
   1022 		}
   1023 		} else {
   1024 		errnum = ldap_result2error(ld, resultMsg, FALSE);
   1025 		if (errnum != LDAP_SUCCESS)
   1026 			p_error = parse_ldap_search_error;
   1027 	}
   1028 	if (ber != NULL)
   1029 		ber_free(ber, 0);
   1030 
   1031 	if (!error_reported && p_error != no_parse_error) {
   1032 		report_error(ldap_err2string(errnum), 0);
   1033 	}
   1034 
   1035 	if (p_error != no_parse_error)
   1036 		rc = -1;
   1037 	return (rc);
   1038 }
   1039 
   1040 /*
   1041  * FUNCTION:	process_ldap_referral
   1042  *
   1043  *	Retrieves the configuration for a referral url
   1044  *
   1045  * RETURN VALUE:	0 on success, -1 on failure, 1 on skip
   1046  *
   1047  * INPUT:		url		the ldap url
   1048  *			__nis_ldap_proxy_info
   1049  */
   1050 
   1051 static int
   1052 process_ldap_referral(
   1053 	char			*url,
   1054 	char			**attrs,
   1055 	__nis_ldap_proxy_info	*proxy_info,
   1056 	__nis_config_t		*nis_config,
   1057 	__nis_table_mapping_t	**table_mapping,
   1058 	__nis_config_info_t	*config_info,
   1059 	__nisdb_table_mapping_t	*table_info)
   1060 {
   1061 	LDAPURLDesc	*ludpp		= NULL;
   1062 	int		rc;
   1063 	LDAP		*ld		= NULL;
   1064 	int		errnum;
   1065 	LDAPMessage	*resultMsg	= NULL;
   1066 
   1067 	if ((rc = ldap_url_parse(url, &ludpp)) != LDAP_SUCCESS)
   1068 		return (1);
   1069 
   1070 #ifdef LDAP_URL_OPT_SECURE
   1071 	if (ludpp->lud_options & LDAP_URL_OPT_SECURE) {
   1072 		if (config_info->tls_method != ssl_tls) {
   1073 			ldap_free_urldesc(ludpp);
   1074 			return (1);
   1075 		}
   1076 	} else {
   1077 		if (config_info->tls_method != no_tls) {
   1078 			ldap_free_urldesc(ludpp);
   1079 			return (1);
   1080 		}
   1081 	}
   1082 #endif
   1083 
   1084 	if ((ld = connect_to_ldap_config_server(ludpp->lud_host,
   1085 			ludpp->lud_port, config_info)) == NULL) {
   1086 		ldap_free_urldesc(ludpp);
   1087 		return (-1);
   1088 	}
   1089 
   1090 	errnum = ldap_search_s(ld, config_info->config_dn,