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, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <string.h>
     31 #include <stdlib.h>
     32 #include <ctype.h>
     33 #include <fcntl.h>
     34 #include <unistd.h>
     35 #include <locale.h>
     36 
     37 #include "ldap_parse.h"
     38 #include "nis_parse_ldap_conf.h"
     39 
     40 /* other attribute functions */
     41 static char *getIndex(const char **s_cur, const char *end_s);
     42 static bool_t get_ttls(const char *s, const char *s_end,
     43     __nis_table_mapping_t *t_mapping);
     44 static __nis_object_dn_t *parse_object_dn(const char *s, const char *end);
     45 static int	parse_name_fields(const char *name_s, const char *name_s_end,
     46 	__nis_table_mapping_t *t_mapping);
     47 static void get_mapping_rule(const char *s, int len,
     48     __nis_table_mapping_t *tbl, bool_t to_ldap);
     49 static bool_t get_deleteDisp(const char *s_begin, const char *s_end,
     50     __nis_object_dn_t *obj_dn);
     51 
     52 /* mapping rule functions */
     53 static const char *get_lhs(const char *s, const char *end_s,
     54     __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
     55 static const char *get_lhs_match(const char *s, const char *end_s,
     56     __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
     57 static const char *get_lhs_paren_item(const char *s, const char *end_s,
     58     __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
     59 static const char *get_rhs(const char *s, const char *end_s,
     60     __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
     61 static const char *get_mapping_item(const char *s, const char *end_s,
     62     __nis_mapping_item_t *item, __nis_mapping_item_type_t type);
     63 static const char *get_print_mapping_element(const char *s,
     64     const char *end_s, char *fmt_string, __nis_mapping_element_t *e,
     65     __nis_mapping_item_type_t item_type);
     66 static const char *get_subElement(const char *s, const char *end_s,
     67     __nis_mapping_sub_element_t *subelement,
     68     __nis_mapping_item_type_t type);
     69 static bool_t get_mapping_format(const char *fmt_string,
     70     __nis_mapping_format_t **fmt, int *nfmt, int *numItems,
     71     bool_t print_mapping);
     72 extern __yp_domain_context_t ypDomains;
     73 
     74 /*
     75  * FUNCTION:	add_mapping_attribute
     76  *
     77  *	Adds the attribute value to __nis_table_mapping_t
     78  *	if the value is not yet set for the given database.
     79  *
     80  * RETURN VALUE:	0 on success, -1 on failure
     81  *
     82  * INPUT:		attribute number and value
     83  */
     84 
     85 int
     86 add_mapping_attribute(
     87 	config_key		attrib_num,
     88 	const char		*attrib_val,
     89 	int			attrib_len,
     90 	__nis_table_mapping_t	**table_mapping)
     91 {
     92 	const char		*s;
     93 	const char		*attrib_end;
     94 	const char		*db_id_end;
     95 	const char		*begin_token;
     96 	const char		*end_token;
     97 	char			*index_string;
     98 	__nis_object_dn_t	*objectDN;
     99 	__nis_table_mapping_t	*t_mapping;
    100 	__nis_table_mapping_t	*t;
    101 
    102 	bool_t			new_mapping	= FALSE;
    103 	int				nm;
    104 	char			*tmp_dbId;
    105 
    106 	attrib_end = attrib_val + attrib_len;
    107 	for (s = attrib_val; s < attrib_end; s++)
    108 		if (*s == COLON_CHAR)
    109 			break;
    110 
    111 	if (s == attrib_end || *attrib_val == COLON_CHAR) {
    112 		p_error = parse_unexpected_data_end_rule;
    113 		return (-1);
    114 	}
    115 
    116 	db_id_end = s;
    117 	while (s > attrib_val && is_whitespace(s[-1]))
    118 		s--;
    119 
    120 	if (s == attrib_val) {
    121 		p_error = parse_unexpected_data_end_rule;
    122 		return (-1);
    123 	}
    124 
    125 	if (yp2ldap) {
    126 		tmp_dbId = s_strndup(attrib_val, s - attrib_val);
    127 		if (tmp_dbId == NULL) {
    128 			p_error = parse_no_mem_error;
    129 			return (-1);
    130 		}
    131 		if (strchr(tmp_dbId, COMMA_CHAR)) {
    132 			/* domain explicitly specified */
    133 			nm = check_domain_specific_order(tmp_dbId,
    134 				attrib_num, *table_mapping, &ypDomains);
    135 			/*
    136 			 * No logging is needed here, as
    137 			 * check_domain_specific_order
    138 			 * will log any appropriate errors.
    139 			 */
    140 			if (nm != 0) {
    141 				free(tmp_dbId);
    142 				return (-1);
    143 			}
    144 		}
    145 		free(tmp_dbId);
    146 	}
    147 
    148 	if ((t_mapping = find_table_mapping(attrib_val,
    149 			s - attrib_val, *table_mapping)) == NULL) {
    150 		/* No mapping with this id, create one */
    151 		t_mapping = (__nis_table_mapping_t *)
    152 			s_calloc(1, sizeof (__nis_table_mapping_t));
    153 
    154 		if (t_mapping == NULL) {
    155 			p_error = parse_no_mem_error;
    156 			return (-1);
    157 		}
    158 		(void) initialize_table_mapping(t_mapping);
    159 
    160 		/* dbId is the label before the colon */
    161 		t_mapping->dbId = s_strndup(attrib_val, s - attrib_val);
    162 		if (t_mapping->dbId == NULL) {
    163 			p_error = parse_no_mem_error;
    164 			free(t_mapping);
    165 			return (-1);
    166 		}
    167 		new_mapping = TRUE;
    168 	} else {
    169 		/* a table mapping already exists, use it */
    170 		new_mapping = FALSE;
    171 	}
    172 
    173 	s = db_id_end + 1;
    174 	while (s < attrib_end && is_whitespace(*s))
    175 		s++;
    176 
    177 	switch (attrib_num) {
    178 		case key_yp_map_flags:
    179 			if (t_mapping->usedns_flag != 0 ||
    180 				t_mapping->securemap_flag != 0) {
    181 				warn_duplicate_map(t_mapping->dbId,
    182 					attrib_num);
    183 				break;
    184 			}
    185 			while (is_whitespace(*s) && s < attrib_end)
    186 				s++;
    187 			while (s < attrib_end) {
    188 				if (s < attrib_end && *s == 'b')
    189 					t_mapping->usedns_flag = 1;
    190 				if (s < attrib_end && *s == 's')
    191 					t_mapping->securemap_flag = 1;
    192 				s++;
    193 			}
    194 			break;
    195 		case key_yp_comment_char:
    196 			if (t_mapping->commentChar !=
    197 				DEFAULT_COMMENT_CHAR) {
    198 				warn_duplicate_map(t_mapping->dbId, attrib_num);
    199 				break;
    200 			}
    201 			while (is_whitespace(*s) && s < attrib_end)
    202 				s++;
    203 			if (s < attrib_end && (s+1) < attrib_end &&
    204 				(s+2) <= attrib_end) {
    205 				while (is_whitespace(attrib_end[-1]))
    206 					attrib_end--;
    207 				while (*s != SINGLE_QUOTE_CHAR)
    208 					s++;
    209 				if (*s == SINGLE_QUOTE_CHAR &&
    210 					*(s+2) == SINGLE_QUOTE_CHAR) {
    211 					t_mapping->commentChar = *(s+1);
    212 				} else if (*s == SINGLE_QUOTE_CHAR &&
    213 					*(s+1) == SINGLE_QUOTE_CHAR) {
    214 					t_mapping->commentChar = NULL;
    215 				} else {
    216 					/* anything else is an error */
    217 					p_error = parse_bad_yp_comment_error;
    218 				}
    219 				break;
    220 			} else {
    221 				p_error = parse_bad_yp_comment_error;
    222 				break;
    223 			}
    224 		case key_yp_repeated_field_separators:
    225 			while (s < attrib_end && is_whitespace(*s))
    226 				s++;
    227 			if (s < attrib_end) {
    228 				while (is_whitespace(attrib_end[-1]))
    229 					attrib_end--;
    230 				while (s < attrib_end &&
    231 						*s != DOUBLE_QUOTE_CHAR)
    232 					s++;
    233 				s++;
    234 				begin_token = s;
    235 				while (s < attrib_end &&
    236 						*s != DOUBLE_QUOTE_CHAR) {
    237 					if (*s == ESCAPE_CHAR)
    238 						s++;
    239 					s++;
    240 				}
    241 				t_mapping->separatorStr =
    242 					s_strndup(begin_token, s - begin_token);
    243 				if (t_mapping->separatorStr == NULL)
    244 					break;
    245 			} else {
    246 				p_error = parse_bad_field_separator_error;
    247 			}
    248 			break;
    249 		case key_yp_name_fields:
    250 		case key_yp_split_field:
    251 			if (t_mapping->e || t_mapping->numSplits > 0) {
    252 				warn_duplicate_map(t_mapping->dbId,
    253 					attrib_num);
    254 				break;
    255 			}
    256 			if (parse_name_fields(s, attrib_end, t_mapping)) {
    257 				p_error = parse_bad_name_field;
    258 			}
    259 			break;
    260 		case key_yp_db_id_map:
    261 		case key_db_id_map:
    262 			if (t_mapping->objName != NULL) {
    263 				warn_duplicate_map(t_mapping->dbId, attrib_num);
    264 				break;
    265 			}
    266 
    267 			if (s < attrib_end && *s == OPEN_BRACKET) {
    268 				index_string = getIndex(&s, attrib_end);
    269 				if (index_string == NULL)
    270 					break;
    271 				(void) parse_index(index_string,
    272 					index_string + strlen(index_string),
    273 					&t_mapping->index);
    274 				free(index_string);
    275 				if (p_error != no_parse_error)
    276 					break;
    277 			}
    278 			while (is_whitespace(*s) && s < attrib_end)
    279 				s++;
    280 			if (s < attrib_end) {
    281 				while (is_whitespace(attrib_end[-1]))
    282 					attrib_end--;
    283 				t_mapping->objName =
    284 					s_strndup_esc(s, attrib_end - s);
    285 			} else {
    286 				if (yp2ldap) {
    287 					p_error = parse_bad_map_error;
    288 				} else {
    289 					t_mapping->objName = s_strndup(s, 0);
    290 				}
    291 			}
    292 			break;
    293 
    294 		case key_yp_entry_ttl:
    295 		case key_entry_ttl:
    296 			if (t_mapping->initTtlLo != (time_t)NO_VALUE_SET) {
    297 				warn_duplicate_map(t_mapping->dbId, attrib_num);
    298 				break;
    299 			}
    300 
    301 			if (!get_ttls(s, attrib_end, t_mapping))
    302 				p_error = parse_bad_ttl_format_error;
    303 			break;
    304 
    305 		case key_yp_ldap_object_dn:
    306 		case key_ldap_object_dn:
    307 			if (t_mapping->objectDN != NULL) {
    308 				warn_duplicate_map(t_mapping->dbId, attrib_num);
    309 				break;
    310 			}
    311 			objectDN = parse_object_dn(s, attrib_end);
    312 			if (objectDN == NULL)
    313 				break;
    314 			t_mapping->objectDN = objectDN;
    315 			t_mapping->seq_num = seq_num++;
    316 			break;
    317 
    318 		case key_nis_to_ldap_map:
    319 		case key_nisplus_to_ldap_map:
    320 			if (t_mapping->ruleToLDAP != 0) {
    321 				warn_duplicate_map(t_mapping->dbId, attrib_num);
    322 				break;
    323 			}
    324 
    325 			get_mapping_rule(s, attrib_end - s, t_mapping, TRUE);
    326 			break;
    327 
    328 		case key_ldap_to_nis_map:
    329 		case key_ldap_to_nisplus_map:
    330 			if (t_mapping->ruleFromLDAP != NULL) {
    331 				warn_duplicate_map(t_mapping->dbId, attrib_num);
    332 				break;
    333 			}
    334 
    335 			get_mapping_rule(s, attrib_end - s, t_mapping, FALSE);
    336 			break;
    337 
    338 		default:
    339 			p_error = parse_internal_error;
    340 			break;
    341 	}
    342 	if (p_error == no_parse_error) {
    343 		if (new_mapping) {
    344 			if (*table_mapping == NULL)
    345 				*table_mapping = t_mapping;
    346 			else {
    347 				for (t = *table_mapping; t->next != NULL;
    348 				    t = t->next)
    349 					;
    350 				t->next = t_mapping;
    351 			}
    352 		}
    353 	} else {
    354 		if (new_mapping)
    355 			free_table_mapping(t_mapping);
    356 	}
    357 	return (p_error == no_parse_error ? 0 : -1);
    358 }
    359 
    360 /*
    361  * FUNCTION:	add_ypdomains_attribute
    362  *
    363  * Adds the yp domains information to the __yp_domain_context_t
    364  * structure.
    365  *
    366  * RETURN:		0 on success, -1 on failure
    367  *
    368  * INPUT:		attribute number and value
    369  */
    370 
    371 int
    372 add_ypdomains_attribute(
    373 	config_key		attrib_num,
    374 	const char		*attrib_val,
    375 	int				attrib_len,
    376 	__yp_domain_context_t	*ypDomains)
    377 {
    378 	const char 		*s;
    379 	const char		*attrib_end;
    380 	int				numDomains = 0;
    381 	int 			i;
    382 	char			*tmp_str;
    383 	int				ret = 0;
    384 
    385 	attrib_end = attrib_val + attrib_len;
    386 	for (s = attrib_val; s < attrib_end; s++) {
    387 		if (*s == COLON_CHAR) {
    388 			break;
    389 		}
    390 	}
    391 	while (s > attrib_val && is_whitespace(s[-1]))
    392 		s--;
    393 
    394 	if (s == attrib_val) {
    395 		p_error = parse_unexpected_data_end_rule;
    396 		return (-1);
    397 	}
    398 
    399 	if (ypDomains == NULL) {
    400 		/*
    401 		 * No point allocating. We cant return the resulting structure,
    402 		 * so just return failure. Should not ever happen because we
    403 		 * are always called with a pointer to the global ypDomains
    404 		 * structure.
    405 		 */
    406 		return (-1);
    407 	}
    408 
    409 	switch (attrib_num) {
    410 		case key_yp_domain_context:
    411 			numDomains = ypDomains->numDomains;
    412 			ypDomains->domainLabels =
    413 				(char **)s_realloc(ypDomains->domainLabels,
    414 				(numDomains + 1) *
    415 				sizeof (ypDomains->domainLabels[0]));
    416 			if (ypDomains->domainLabels == NULL) {
    417 				p_error = parse_no_mem_error;
    418 				free_yp_domain_context(ypDomains);
    419 				break;
    420 			}
    421 			ypDomains->domainLabels[numDomains] =
    422 				s_strndup(attrib_val, s - attrib_val);
    423 			if (ypDomains->domainLabels[numDomains] == NULL) {
    424 				p_error = parse_no_mem_error;
    425 				free_yp_domain_context(ypDomains);
    426 				break;
    427 			}
    428 			ypDomains->numDomains = numDomains + 1;
    429 			while (s < attrib_end && is_whitespace(*s))
    430 				s++;
    431 			if (*s == COLON_CHAR)
    432 				s++;
    433 			while (s < attrib_end && is_whitespace(*s))
    434 				s++;
    435 			ypDomains->domains =
    436 				(char **)s_realloc(ypDomains->domains,
    437 				(numDomains + 1) *
    438 				sizeof (ypDomains->domains[0]));
    439 			if (ypDomains->domains == NULL) {
    440 				p_error = parse_no_mem_error;
    441 				free_yp_domain_context(ypDomains);
    442 				break;
    443 			}
    444 
    445 			if (s < attrib_end) {
    446 				while (is_whitespace(attrib_end[-1]))
    447 					attrib_end--;
    448 				ypDomains->domains[numDomains] =
    449 					s_strndup_esc(s, attrib_end - s);
    450 				if (ypDomains->domains[numDomains] == NULL) {
    451 					p_error = parse_no_mem_error;
    452 					free_yp_domain_context(ypDomains);
    453 					break;
    454 				}
    455 			} else {
    456 				p_error = parse_unexpected_yp_domain_end_error;
    457 				free(ypDomains->domainLabels[numDomains]);
    458 				ypDomains->domainLabels[numDomains] = NULL;
    459 				ypDomains->numDomains--;
    460 				free_yp_domain_context(ypDomains);
    461 			}
    462 			break;
    463 		case key_yppasswdd_domains:
    464 			ypDomains->yppasswddDomainLabels =
    465 				(char **)s_realloc(
    466 				ypDomains->yppasswddDomainLabels,
    467 				(ypDomains->numYppasswdd + 1) *
    468 				sizeof (ypDomains->yppasswddDomainLabels[0]));
    469 			if (ypDomains->yppasswddDomainLabels == NULL) {
    470 				p_error = parse_no_mem_error;
    471 				break;
    472 			}
    473 			ypDomains->yppasswddDomainLabels
    474 				[ypDomains->numYppasswdd] =
    475 				s_strndup(attrib_val, s - attrib_val);
    476 			if (ypDomains->yppasswddDomainLabels
    477 				[ypDomains->numYppasswdd] == NULL) {
    478 				p_error = parse_no_mem_error;
    479 			}
    480 			ypDomains->numYppasswdd++;
    481 			break;
    482 	}
    483 
    484 	return (p_error == no_parse_error ? 0 : -1);
    485 }
    486 
    487 /*
    488  * FUNCTION:	get_ttls
    489  *
    490  *	Parse time to live attribute
    491  *
    492  * RETURN VALUE:	TRUE on success, FALSE on failure
    493  *
    494  * INPUT:		the attribute value
    495  */
    496 
    497 static bool_t
    498 get_ttls(
    499 	const char		*s,
    500 	const char		*s_end,
    501 	__nis_table_mapping_t	*t_mapping)
    502 {
    503 	time_t		initTtlHi	= 0;
    504 	time_t		initTtlLo	= 0;
    505 	time_t		ttl		= 0;
    506 	time_t		digit;
    507 
    508 	/*
    509 	 * attribute should be of the form
    510 	 * initialTTLlo ":" initialTTLhi ":" runningTTL
    511 	 */
    512 
    513 	if (s == s_end) {
    514 		p_error = parse_bad_ttl_format_error;
    515 		return (FALSE);
    516 	}
    517 
    518 	if (isdigit(*s)) {
    519 		while (s < s_end && isdigit(*s)) {
    520 			digit = (*s++) - '0';
    521 			if (WILL_OVERFLOW_TIME(initTtlLo, digit))
    522 				initTtlLo = TIME_MAX;
    523 			else
    524 				initTtlLo = initTtlLo * 10 + digit;
    525 		}
    526 	} else {
    527 		initTtlLo = ONE_HOUR;
    528 	}
    529 
    530 	while (s < s_end && is_whitespace(*s))
    531 		s++;
    532 	if (s + 1 >= s_end || *s++ != COLON_CHAR) {
    533 		p_error = parse_bad_ttl_format_error;
    534 		return (FALSE);
    535 	}
    536 
    537 	while (s < s_end && is_whitespace(*s))
    538 		s++;
    539 	if (isdigit(*s)) {
    540 		while (s < s_end && isdigit(*s)) {
    541 			digit = (*s++) - '0';
    542 			if (WILL_OVERFLOW_TIME(initTtlHi, digit))
    543 				initTtlHi = TIME_MAX;
    544 			else
    545 				initTtlHi = initTtlHi * 10 + digit;
    546 		}
    547 	} else {
    548 		initTtlHi = initTtlLo;
    549 	}
    550 
    551 	while (s < s_end && is_whitespace(*s))
    552 		s++;
    553 	if (s >= s_end || *s++ != COLON_CHAR) {
    554 		p_error = parse_bad_ttl_format_error;
    555 		return (FALSE);
    556 	}
    557 
    558 	while (s < s_end && is_whitespace(*s))
    559 		s++;
    560 	if (isdigit(*s)) {
    561 		while (s < s_end && isdigit(*s)) {
    562 			digit = (*s++) - '0';
    563 			if (WILL_OVERFLOW_TIME(ttl, digit))
    564 				ttl = TIME_MAX;
    565 			else
    566 				ttl = ttl * 10 + digit;
    567 		}
    568 	} else {
    569 		ttl = ONE_HOUR;
    570 	}
    571 	while (s < s_end && is_whitespace(*s))
    572 		s++;
    573 	if (s != s_end) {
    574 		p_error = parse_bad_ttl_format_error;
    575 		return (FALSE);
    576 	}
    577 
    578 	t_mapping->initTtlLo = initTtlLo;
    579 	t_mapping->initTtlHi = initTtlHi;
    580 	t_mapping->ttl = ttl;
    581 	return (TRUE);
    582 }
    583 
    584 /*
    585  * FUNCTION:	parse_name_fields
    586  *
    587  * Parse yp name fields
    588  *
    589  * RETURN VALUE:	0 on success, non-zero on failure
    590  *
    591  * INPUTS:		attrib_value and attribute_end pointers.
    592  */
    593 
    594 static int
    595 parse_name_fields(const char *name_s,
    596 	const char *name_s_end,
    597 	__nis_table_mapping_t   *t_map)
    598 {
    599 	int	i, n = 0;
    600 	int nElements = 0;
    601 	int numSplits = 0;
    602 	int parse_next_line = 1;
    603 	int itm_count = 0;
    604 	const char	*begin_fmt;
    605 	const char	*end_fmt;
    606 	const char	*begin_token;
    607 	const char	*end_token;
    608 	char	*fmt_string = NULL;
    609 	__nis_mapping_format_t  *base = NULL;
    610 	__nis_mapping_item_t    *item = NULL;
    611 	__nis_mapping_element_t *elmnt = NULL;
    612 	__nis_mapping_item_type_t   item_type = mit_nisplus;
    613 	token_type	token;
    614 
    615 	t_map->numColumns = 0;
    616 
    617 	for (; parse_next_line > 0; parse_next_line--) {
    618 		nElements = 0;
    619 		item = NULL;
    620 		base = NULL;
    621 		while (name_s < name_s_end && *name_s != OPEN_PAREN_CHAR)
    622 			name_s++;
    623 		if (name_s == name_s_end) {
    624 			p_error = parse_unexpected_data_end_rule;
    625 			return (1);
    626 		}
    627 		while (name_s < name_s_end && *name_s != DOUBLE_QUOTE_CHAR)
    628 			name_s++;
    629 		if (name_s == name_s_end) {
    630 			p_error = parse_unexpected_data_end_rule;
    631 			return (1);
    632 		}
    633 		begin_fmt = ++name_s; /* start of format string */
    634 		while (name_s < name_s_end && *name_s != DOUBLE_QUOTE_CHAR)
    635 			name_s++;
    636 		if (name_s == name_s_end) {
    637 			p_error = parse_unexpected_data_end_rule;
    638 			return (1);
    639 		}
    640 		end_fmt = name_s;
    641 		fmt_string = s_strndup(begin_fmt, end_fmt - begin_fmt);
    642 		if (fmt_string == NULL) {
    643 			p_error = parse_no_mem_error;
    644 			return (2);
    645 		}
    646 		if (!get_mapping_format(fmt_string, &base, &n, NULL, FALSE)) {
    647 			p_error = parse_internal_error;
    648 			free(fmt_string);
    649 			fmt_string = NULL;
    650 			return (3);
    651 		}
    652 		free(fmt_string);
    653 		fmt_string = NULL;
    654 		for (n = 0; base[n].type != mmt_end; n++) {
    655 			if (base[n].type != mmt_item && base[n].type
    656 				!= mmt_berstring) {
    657 				if (base[n].type == mmt_berstring_null)
    658 					base[n].type = mmt_berstring;
    659 				continue;
    660 			}
    661 			while (name_s < name_s_end && *name_s != COMMA_CHAR)
    662 				name_s++;
    663 			name_s++;    /* now at comma char */
    664 			while (name_s < name_s_end && is_whitespace(*name_s))
    665 				name_s++;
    666 			begin_token = name_s++;
    667 			end_token = name_s_end;
    668 			name_s = get_next_token(
    669 				&begin_token, &end_token, &token);
    670 			if (name_s == NULL) {
    671 				p_error = parse_item_expected_error;
    672 				return (4);
    673 			}
    674 			if (token != string_token) {
    675 				p_error = parse_item_expected_error;
    676 				return (5);
    677 			}
    678 			item = (__nis_mapping_item_t *)s_realloc(item,
    679 				(nElements + 1) *
    680 				sizeof (__nis_mapping_item_t));
    681 			if (item == NULL) {
    682 				p_error = parse_no_mem_error;
    683 				return (2);
    684 			}
    685 			name_s = get_mapping_item(begin_token, name_s_end,
    686 				&item[nElements], item_type);
    687 			if (name_s == NULL) {
    688 				p_error = parse_unmatched_escape;
    689 				for (n = 0; n < (nElements + 1); n++)
    690 					free_mapping_item(&item[n]);
    691 				free_mapping_format(base);
    692 				return (4);
    693 			}
    694 			nElements++;
    695 		}
    696 		if (p_error != no_parse_error) {
    697 			for (n = 0; n < (nElements + 1); n++)
    698 				free_mapping_item(&item[n]);
    699 			free_mapping_format(base);
    700 			return (6);
    701 		}
    702 		name_s = skip_token(name_s, name_s_end, close_paren_token);
    703 		if (name_s == NULL) {
    704 			p_error = parse_close_paren_expected_error;
    705 			for (n = 0; n < (nElements + 1); n++)
    706 				free_mapping_item(&item[n]);
    707 			free_mapping_format(base);
    708 			return (4);
    709 		}
    710 		while (name_s < name_s_end && is_whitespace(*name_s))
    711 			name_s++;
    712 		if (*name_s == COMMA_CHAR)
    713 			parse_next_line++;
    714 
    715 		if (nElements == 0) {
    716 			p_error = parse_no_match_item;
    717 			for (n = 0; n < (nElements + 1); n++)
    718 				free_mapping_item(&item[n]);
    719 			free_mapping_format(base);
    720 			return (7);
    721 		}
    722 		elmnt = (__nis_mapping_element_t *)s_realloc(elmnt,
    723 			(numSplits + 1) *
    724 			sizeof (__nis_mapping_element_t));
    725 		if (elmnt == NULL) {
    726 			for (n = 0; n < (nElements + 1); n++)
    727 				free_mapping_item(&item[n]);
    728 			free_mapping_format(base);
    729 			p_error = parse_no_mem_error;
    730 			return (2);
    731 		}
    732 		elmnt[numSplits].type = me_match;
    733 		elmnt[numSplits].element.match.numItems = nElements;
    734 		elmnt[numSplits].element.match.item = item;
    735 		elmnt[numSplits].element.match.fmt = base;
    736 		item = NULL;
    737 		base = NULL;
    738 
    739 		t_map->e = elmnt;
    740 		t_map->numSplits = numSplits;
    741 		n = t_map->numColumns;
    742 
    743 		for (i = n, itm_count = 0; i < n + nElements; i++) {
    744 			if (t_map->e[numSplits].element.
    745 				match.item[itm_count].name) {
    746 				if (!add_column(t_map,
    747 					t_map->e[numSplits].element.
    748 					match.item[itm_count].name))
    749 					return (1);
    750 				itm_count++;
    751 			} else {
    752 				p_error = parse_internal_error;
    753 				for (n = 0; n < (nElements + 1); n++)
    754 					free_mapping_item(&item[n]);
    755 				free_mapping_format(base);
    756 				free_mapping_element(elmnt);
    757 				return (1);
    758 			}
    759 		}
    760 		numSplits++;
    761 	}
    762 	elmnt = NULL;
    763 
    764 	if (item != NULL) {
    765 		for (n = 0; n < t_map->numColumns; n++) {
    766 			free_mapping_item(&item[n]);
    767 		}
    768 		free(item);
    769 	}
    770 	if (elmnt != NULL)
    771 		free_mapping_element(elmnt);
    772 	if (base != NULL)
    773 		free_mapping_format(base);
    774 
    775 	return (p_error == no_parse_error ? 0 : -1);
    776 }
    777 
    778 /*
    779  * FUNCTION:	parse_object_dn
    780  *
    781  *	Parse object dn attribute
    782  *
    783  * RETURN VALUE:	__nis_object_dn_t on success
    784  *			NULL on failure
    785  *
    786  * INPUT:		the attribute value
    787  */
    788 
    789 static __nis_object_dn_t *
    790 parse_object_dn(const char *s, const char *end)
    791 {
    792 	const char		*s_begin;
    793 	const char		*s_end;
    794 	object_dn_token		token;
    795 	parse_object_dn_state	dn_state	= dn_begin_parse;
    796 	__nis_object_dn_t	*obj_dn		= NULL;
    797 	__nis_object_dn_t	*next		= NULL;
    798 	__nis_object_dn_t	*last		= NULL;
    799 
    800 	/*
    801 	 * The attribute should be of form
    802 	 * objectDN *( ";" objectDN )
    803 	 * objectDN = readObjectSpec [":"[writeObjectSpec]]
    804 	 * readObjectSpec = [baseAndScope [filterAttrValList]]
    805 	 * writeObjectSpec = [baseAndScope [attrValList [":" deleteDisp]]]
    806 	 */
    807 
    808 	while (s < end) {
    809 		s_begin = s;
    810 		s_end = end;
    811 		s = get_next_object_dn_token(&s_begin, &s_end, &token);
    812 		if (s == NULL)
    813 			break;
    814 
    815 		if (token == dn_no_token || token == dn_semi_token) {
    816 			if (obj_dn == NULL)
    817 				obj_dn = next;
    818 			else
    819 				last->next = next;
    820 			last = next;
    821 			next = NULL;
    822 			if (token == dn_no_token)
    823 				break;
    824 			dn_state = dn_begin_parse;
    825 		}
    826 		if (next == NULL) {
    827 			next = (__nis_object_dn_t *)
    828 				s_calloc(1, sizeof (__nis_object_dn_t));
    829 			if (next == NULL)
    830 				break;
    831 			next->read.scope = LDAP_SCOPE_ONELEVEL;
    832 			next->write.scope = LDAP_SCOPE_UNKNOWN;
    833 			next->delDisp = dd_always;
    834 		}
    835 		if (token == dn_semi_token)
    836 			continue;
    837 
    838 		switch (dn_state) {
    839 		    case dn_begin_parse:
    840 			if (token == dn_ques_token)
    841 				dn_state = dn_got_read_q_scope;
    842 			else if (token == dn_colon_token) {
    843 				dn_state = dn_got_write_colon;
    844 				next->write.scope = LDAP_SCOPE_ONELEVEL;
    845 			} else {
    846 				if (!validate_dn(s_begin, s_end - s_begin))
    847 					break;
    848 				next->read.base =
    849 					s_strndup_esc(s_begin, s_end - s_begin);
    850 				dn_state = dn_got_read_dn;
    851 			}
    852 			break;
    853 		    case dn_got_read_dn:
    854 			if (token == dn_ques_token)
    855 				dn_state = dn_got_read_q_scope;
    856 			else if (token == dn_colon_token) {
    857 				dn_state = dn_got_write_colon;
    858 				next->write.scope = LDAP_SCOPE_ONELEVEL;
    859 			} else
    860 				p_error = parse_object_dn_syntax_error;
    861 			break;
    862 		    case dn_got_read_q_scope:
    863 			if (token == dn_ques_token)
    864 				dn_state = dn_got_read_q_filter;
    865 			else if (token == dn_colon_token) {
    866 				dn_state = dn_got_write_colon;
    867 				next->write.scope = LDAP_SCOPE_ONELEVEL;
    868 			} else if (token == dn_base_token) {
    869 				next->read.scope = LDAP_SCOPE_BASE;
    870 				dn_state = dn_got_read_scope;
    871 			} else if (token == dn_one_token) {
    872 				next->read.scope = LDAP_SCOPE_ONELEVEL;
    873 				dn_state = dn_got_read_scope;
    874 			} else if (token == dn_sub_token) {
    875 				next->read.scope = LDAP_SCOPE_SUBTREE;
    876 				dn_state = dn_got_read_scope;
    877 			} else {
    878 				p_error = parse_invalid_scope;
    879 			}
    880 			break;
    881 		    case dn_got_read_scope:
    882 			if (token == dn_ques_token)
    883 				dn_state = dn_got_read_q_filter;
    884 			else if (token == dn_colon_token) {
    885 				dn_state = dn_got_write_colon;
    886 				next->write.scope = LDAP_SCOPE_ONELEVEL;
    887 			} else
    888 				p_error = parse_object_dn_syntax_error;
    889 			break;
    890 		    case dn_got_read_q_filter:
    891 			if (token == dn_ques_token) {
    892 				p_error = parse_object_dn_syntax_error;
    893 			} else if (token == dn_colon_token) {
    894 				dn_state = dn_got_write_colon;
    895 				next->write.scope = LDAP_SCOPE_ONELEVEL;
    896 			} else {
    897 				if (!validate_ldap_filter(s_begin, s_end))
    898 					break;
    899 				next->read.attrs =
    900 					s_strndup_esc(s_begin, s_end - s_begin);
    901 				dn_state = dn_got_read_filter;
    902 			}
    903 			break;
    904 		    case dn_got_read_filter:
    905 			if (token == dn_ques_token) {
    906 				p_error = parse_object_dn_syntax_error;
    907 			} else if (token == dn_colon_token) {
    908 				dn_state = dn_got_write_colon;
    909 				next->write.scope = LDAP_SCOPE_ONELEVEL;
    910 			} else
    911 				p_error = parse_object_dn_syntax_error;
    912 			break;
    913 		    case dn_got_write_colon:
    914 			if (token == dn_ques_token)
    915 				dn_state = dn_got_write_q_scope;
    916 			else if (token == dn_colon_token) {
    917 				dn_state = dn_got_delete_colon;
    918 			} else {
    919 				if (!validate_dn(s_begin, s_end - s_begin))
    920 					break;
    921 				next->write.base =
    922 					s_strndup_esc(s_begin, s_end - s_begin);
    923 				dn_state = dn_got_write_dn;
    924 			}
    925 			break;
    926 		    case dn_got_write_dn:
    927 			if (token == dn_ques_token)
    928 				dn_state = dn_got_write_q_scope;
    929 			else if (token == dn_colon_token) {
    930 				dn_state = dn_got_delete_colon;
    931 			} else
    932 				p_error = parse_object_dn_syntax_error;
    933 			break;
    934 		    case dn_got_write_q_scope:
    935 			if (token == dn_ques_token)
    936 				dn_state = dn_got_write_q_filter;
    937 			else if (token == dn_colon_token) {
    938 				dn_state = dn_got_delete_colon;
    939 			} else if (token == dn_base_token) {
    940 				next->write.scope = LDAP_SCOPE_BASE;
    941 				dn_state = dn_got_write_scope;
    942 			} else if (token == dn_one_token) {
    943 				next->write.scope = LDAP_SCOPE_ONELEVEL;
    944 				dn_state = dn_got_write_scope;
    945 			} else if (token == dn_sub_token) {
    946 				next->write.scope = LDAP_SCOPE_SUBTREE;
    947 				dn_state = dn_got_write_scope;
    948 			} else {
    949 				p_error = parse_invalid_scope;
    950 			}
    951 			break;
    952 		    case dn_got_write_scope:
    953 			if (token == dn_ques_token)
    954 				dn_state = dn_got_write_q_filter;
    955 			else if (token == dn_colon_token) {
    956 				dn_state = dn_got_delete_colon;
    957 			} else
    958 				p_error = parse_object_dn_syntax_error;
    959 			break;
    960 		    case dn_got_write_q_filter:
    961 			if (token == dn_ques_token) {
    962 				p_error = parse_object_dn_syntax_error;
    963 			} else if (token == dn_colon_token) {
    964 				dn_state = dn_got_delete_colon;
    965 			} else {
    966 				if (!validate_ldap_filter(s_begin, s_end))
    967 					break;
    968 				next->write.attrs =
    969 					s_strndup_esc(s_begin, s_end - s_begin);
    970 				dn_state = dn_got_write_filter;
    971 			}
    972 			break;
    973 		    case dn_got_write_filter:
    974 			if (token == dn_ques_token) {
    975 				p_error = parse_object_dn_syntax_error;
    976 			} else if (token == dn_colon_token) {
    977 				dn_state = dn_got_delete_colon;
    978 
    979 			} else
    980 				p_error = parse_semi_expected_error;
    981 			break;
    982 		    case dn_got_delete_colon:
    983 			if (token == dn_ques_token) {
    984 				p_error = parse_object_dn_syntax_error;
    985 			} else if (token == dn_colon_token) {
    986 				p_error = parse_object_dn_syntax_error;
    987 			} else {
    988 				if (!get_deleteDisp(s_begin, s_end, next))
    989 					break;
    990 				dn_state = dn_got_delete_dsp;
    991 			}
    992 			break;
    993 		    case dn_got_delete_dsp:
    994 			p_error = parse_object_dn_syntax_error;
    995 			break;
    996 		}
    997 
    998 		if (p_error != no_parse_error)
    999 			break;
   1000 	}
   1001 	if (p_error != no_parse_error) {
   1002 		if (obj_dn != NULL)
   1003 			free_object_dn(obj_dn);
   1004 		if (next != NULL)
   1005 			free_object_dn(next);
   1006 		obj_dn = NULL;
   1007 	} else if (next != NULL) {
   1008 		if (obj_dn == NULL)
   1009 			obj_dn = next;
   1010 		else
   1011 			last->next = next;
   1012 	} else if (obj_dn == NULL)
   1013 		obj_dn = (__nis_object_dn_t *)
   1014 			s_calloc(1, sizeof (__nis_object_dn_t));
   1015 
   1016 	return (obj_dn);
   1017 }
   1018 
   1019 /*
   1020  * FUNCTION:	get_mapping_rule
   1021  *
   1022  *	Parse mapping rule attributes
   1023  *
   1024  * RETURN VALUE:	None. Errors determined by p_error
   1025  *
   1026  * INPUT:		the attribute value and mapping rule type
   1027  */
   1028 
   1029 static void
   1030 get_mapping_rule(
   1031 	const char		*s,
   1032 	int			len,
   1033 	__nis_table_mapping_t	*tbl,
   1034 	bool_t			to_ldap)
   1035 {
   1036 	const char		*end_s			= s + len;
   1037 	const char		*begin_token;
   1038 	const char		*end_token;
   1039 	__nis_mapping_rule_t	**rule			= NULL;
   1040 	__nis_mapping_rule_t	*next			= NULL;
   1041 	/* __nis_mapping_rule_t	**r; */
   1042 	token_type		t;
   1043 	int			nRules			= 0;
   1044 	const char		*s1;
   1045 	int			i;
   1046 
   1047 	/*
   1048 	 * The attribute value is of the form
   1049 	 * colattrspec *("," colattrspec)
   1050 	 * colattrspec	= lhs "=" rhs
   1051 	 * lhs		= lval | namespeclist
   1052 	 * rhs		= rval | [namespec]
   1053 	 */
   1054 
   1055 	for (;;) {
   1056 		if ((next = (__nis_mapping_rule_t *)
   1057 		    s_calloc(1, sizeof (__nis_mapping_rule_t))) == NULL)
   1058 			break;
   1059 
   1060 		s = get_lhs(s, end_s, &next->lhs,
   1061 			to_ldap ? mit_ldap : mit_nisplus);
   1062 		if (s == NULL)
   1063 			break;
   1064 
   1065 		begin_token = s;
   1066 		end_token = end_s;
   1067 		s1 = get_next_token(&begin_token, &end_token, &t);
   1068 		if (s1 == NULL)
   1069 			break;
   1070 		if (!(to_ldap && (t == comma_token || t == no_token))) {
   1071 			s = get_rhs(s, end_s, &next->rhs,
   1072 				to_ldap ? mit_nisplus : mit_ldap);
   1073 			if (s == NULL)
   1074 				break;
   1075 		}
   1076 
   1077 		if (next->lhs.numElements > 1 &&
   1078 		    (next->rhs.numElements != 1 ||
   1079 		    next->rhs.element[0].type != me_split)) {
   1080 			p_error = parse_lhs_rhs_type_mismatch;
   1081 			break;