xref: /illumos-gate/usr/src/lib/libnisdb/nis_parse_ldap_map.c (revision a63c99a2145c99a38d5ff19422b132400428ed9d)
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 2015 Gary Mills
24   * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
25   * Use is subject to license terms.
26   */
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 <locale.h>
35  
36  #include "ldap_parse.h"
37  #include "nis_parse_ldap_conf.h"
38  #include "nis_parse_ldap_yp_util.h"
39  #include "nis_parse_ldap_util.h"
40  
41  /* other attribute functions */
42  static char *getIndex(const char **s_cur, const char *end_s);
43  static bool_t get_ttls(const char *s, const char *s_end,
44      __nis_table_mapping_t *t_mapping);
45  static __nis_object_dn_t *parse_object_dn(const char *s, const char *end);
46  static int	parse_name_fields(const char *name_s, const char *name_s_end,
47  	__nis_table_mapping_t *t_mapping);
48  static void get_mapping_rule(const char *s, int len,
49      __nis_table_mapping_t *tbl, bool_t to_ldap);
50  static bool_t get_deleteDisp(const char *s_begin, const char *s_end,
51      __nis_object_dn_t *obj_dn);
52  
53  /* mapping rule functions */
54  static const char *get_lhs(const char *s, const char *end_s,
55      __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
56  static const char *get_lhs_match(const char *s, const char *end_s,
57      __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
58  static const char *get_lhs_paren_item(const char *s, const char *end_s,
59      __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
60  static const char *get_rhs(const char *s, const char *end_s,
61      __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
62  static const char *get_mapping_item(const char *s, const char *end_s,
63      __nis_mapping_item_t *item, __nis_mapping_item_type_t type);
64  static const char *get_print_mapping_element(const char *s,
65      const char *end_s, char *fmt_string, __nis_mapping_element_t *e,
66      __nis_mapping_item_type_t item_type);
67  static const char *get_subElement(const char *s, const char *end_s,
68      __nis_mapping_sub_element_t *subelement,
69      __nis_mapping_item_type_t type);
70  static bool_t get_mapping_format(const char *fmt_string,
71      __nis_mapping_format_t **fmt, int *nfmt, int *numItems,
72      bool_t print_mapping);
73  extern __yp_domain_context_t ypDomains;
74  
75  /*
76   * FUNCTION:	add_mapping_attribute
77   *
78   *	Adds the attribute value to __nis_table_mapping_t
79   *	if the value is not yet set for the given database.
80   *
81   * RETURN VALUE:	0 on success, -1 on failure
82   *
83   * INPUT:		attribute number and value
84   */
85  
86  int
87  add_mapping_attribute(
88  	config_key		attrib_num,
89  	const char		*attrib_val,
90  	int			attrib_len,
91  	__nis_table_mapping_t	**table_mapping)
92  {
93  	const char		*s;
94  	const char		*attrib_end;
95  	const char		*db_id_end;
96  	const char		*begin_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  
382  	attrib_end = attrib_val + attrib_len;
383  	for (s = attrib_val; s < attrib_end; s++) {
384  		if (*s == COLON_CHAR) {
385  			break;
386  		}
387  	}
388  	while (s > attrib_val && is_whitespace(s[-1]))
389  		s--;
390  
391  	if (s == attrib_val) {
392  		p_error = parse_unexpected_data_end_rule;
393  		return (-1);
394  	}
395  
396  	if (ypDomains == NULL) {
397  		/*
398  		 * No point allocating. We cant return the resulting structure,
399  		 * so just return failure. Should not ever happen because we
400  		 * are always called with a pointer to the global ypDomains
401  		 * structure.
402  		 */
403  		return (-1);
404  	}
405  
406  	switch (attrib_num) {
407  		case key_yp_domain_context:
408  			numDomains = ypDomains->numDomains;
409  			ypDomains->domainLabels =
410  				(char **)s_realloc(ypDomains->domainLabels,
411  				(numDomains + 1) *
412  				sizeof (ypDomains->domainLabels[0]));
413  			if (ypDomains->domainLabels == NULL) {
414  				p_error = parse_no_mem_error;
415  				free_yp_domain_context(ypDomains);
416  				break;
417  			}
418  			ypDomains->domainLabels[numDomains] =
419  				s_strndup(attrib_val, s - attrib_val);
420  			if (ypDomains->domainLabels[numDomains] == NULL) {
421  				p_error = parse_no_mem_error;
422  				free_yp_domain_context(ypDomains);
423  				break;
424  			}
425  			ypDomains->numDomains = numDomains + 1;
426  			while (s < attrib_end && is_whitespace(*s))
427  				s++;
428  			if (*s == COLON_CHAR)
429  				s++;
430  			while (s < attrib_end && is_whitespace(*s))
431  				s++;
432  			ypDomains->domains =
433  				(char **)s_realloc(ypDomains->domains,
434  				(numDomains + 1) *
435  				sizeof (ypDomains->domains[0]));
436  			if (ypDomains->domains == NULL) {
437  				p_error = parse_no_mem_error;
438  				free_yp_domain_context(ypDomains);
439  				break;
440  			}
441  
442  			if (s < attrib_end) {
443  				while (is_whitespace(attrib_end[-1]))
444  					attrib_end--;
445  				ypDomains->domains[numDomains] =
446  					s_strndup_esc(s, attrib_end - s);
447  				if (ypDomains->domains[numDomains] == NULL) {
448  					p_error = parse_no_mem_error;
449  					free_yp_domain_context(ypDomains);
450  					break;
451  				}
452  			} else {
453  				p_error = parse_unexpected_yp_domain_end_error;
454  				free(ypDomains->domainLabels[numDomains]);
455  				ypDomains->domainLabels[numDomains] = NULL;
456  				ypDomains->numDomains--;
457  				free_yp_domain_context(ypDomains);
458  			}
459  			break;
460  		case key_yppasswdd_domains:
461  			ypDomains->yppasswddDomainLabels =
462  				(char **)s_realloc(
463  				ypDomains->yppasswddDomainLabels,
464  				(ypDomains->numYppasswdd + 1) *
465  				sizeof (ypDomains->yppasswddDomainLabels[0]));
466  			if (ypDomains->yppasswddDomainLabels == NULL) {
467  				p_error = parse_no_mem_error;
468  				break;
469  			}
470  			ypDomains->yppasswddDomainLabels
471  				[ypDomains->numYppasswdd] =
472  				s_strndup(attrib_val, s - attrib_val);
473  			if (ypDomains->yppasswddDomainLabels
474  				[ypDomains->numYppasswdd] == NULL) {
475  				p_error = parse_no_mem_error;
476  			}
477  			ypDomains->numYppasswdd++;
478  			break;
479  	}
480  
481  	return (p_error == no_parse_error ? 0 : -1);
482  }
483  
484  /*
485   * FUNCTION:	get_ttls
486   *
487   *	Parse time to live attribute
488   *
489   * RETURN VALUE:	TRUE on success, FALSE on failure
490   *
491   * INPUT:		the attribute value
492   */
493  
494  static bool_t
495  get_ttls(
496  	const char		*s,
497  	const char		*s_end,
498  	__nis_table_mapping_t	*t_mapping)
499  {
500  	time_t		initTtlHi	= 0;
501  	time_t		initTtlLo	= 0;
502  	time_t		ttl		= 0;
503  	time_t		digit;
504  
505  	/*
506  	 * attribute should be of the form
507  	 * initialTTLlo ":" initialTTLhi ":" runningTTL
508  	 */
509  
510  	if (s == s_end) {
511  		p_error = parse_bad_ttl_format_error;
512  		return (FALSE);
513  	}
514  
515  	if (isdigit(*s)) {
516  		while (s < s_end && isdigit(*s)) {
517  			digit = (*s++) - '0';
518  			if (WILL_OVERFLOW_TIME(initTtlLo, digit))
519  				initTtlLo = TIME_MAX;
520  			else
521  				initTtlLo = initTtlLo * 10 + digit;
522  		}
523  	} else {
524  		initTtlLo = ONE_HOUR;
525  	}
526  
527  	while (s < s_end && is_whitespace(*s))
528  		s++;
529  	if (s + 1 >= s_end || *s++ != COLON_CHAR) {
530  		p_error = parse_bad_ttl_format_error;
531  		return (FALSE);
532  	}
533  
534  	while (s < s_end && is_whitespace(*s))
535  		s++;
536  	if (isdigit(*s)) {
537  		while (s < s_end && isdigit(*s)) {
538  			digit = (*s++) - '0';
539  			if (WILL_OVERFLOW_TIME(initTtlHi, digit))
540  				initTtlHi = TIME_MAX;
541  			else
542  				initTtlHi = initTtlHi * 10 + digit;
543  		}
544  	} else {
545  		initTtlHi = initTtlLo;
546  	}
547  
548  	while (s < s_end && is_whitespace(*s))
549  		s++;
550  	if (s >= s_end || *s++ != COLON_CHAR) {
551  		p_error = parse_bad_ttl_format_error;
552  		return (FALSE);
553  	}
554  
555  	while (s < s_end && is_whitespace(*s))
556  		s++;
557  	if (isdigit(*s)) {
558  		while (s < s_end && isdigit(*s)) {
559  			digit = (*s++) - '0';
560  			if (WILL_OVERFLOW_TIME(ttl, digit))
561  				ttl = TIME_MAX;
562  			else
563  				ttl = ttl * 10 + digit;
564  		}
565  	} else {
566  		ttl = ONE_HOUR;
567  	}
568  	while (s < s_end && is_whitespace(*s))
569  		s++;
570  	if (s != s_end) {
571  		p_error = parse_bad_ttl_format_error;
572  		return (FALSE);
573  	}
574  
575  	t_mapping->initTtlLo = initTtlLo;
576  	t_mapping->initTtlHi = initTtlHi;
577  	t_mapping->ttl = ttl;
578  	return (TRUE);
579  }
580  
581  /*
582   * FUNCTION:	parse_name_fields
583   *
584   * Parse yp name fields
585   *
586   * RETURN VALUE:	0 on success, non-zero on failure
587   *
588   * INPUTS:		attrib_value and attribute_end pointers.
589   */
590  
591  static int
592  parse_name_fields(const char *name_s,
593  	const char *name_s_end,
594  	__nis_table_mapping_t   *t_map)
595  {
596  	int	i, n = 0;
597  	int nElements = 0;
598  	int numSplits = 0;
599  	int parse_next_line = 1;
600  	int itm_count = 0;
601  	const char	*begin_fmt;
602  	const char	*end_fmt;
603  	const char	*begin_token;
604  	const char	*end_token;
605  	char	*fmt_string = NULL;
606  	__nis_mapping_format_t  *base = NULL;
607  	__nis_mapping_item_t    *item = NULL;
608  	__nis_mapping_element_t *elmnt = NULL;
609  	__nis_mapping_item_type_t   item_type = mit_nisplus;
610  	token_type	token;
611  
612  	t_map->numColumns = 0;
613  
614  	for (; parse_next_line > 0; parse_next_line--) {
615  		nElements = 0;
616  		item = NULL;
617  		base = NULL;
618  		while (name_s < name_s_end && *name_s != OPEN_PAREN_CHAR)
619  			name_s++;
620  		if (name_s == name_s_end) {
621  			p_error = parse_unexpected_data_end_rule;
622  			return (1);
623  		}
624  		while (name_s < name_s_end && *name_s != DOUBLE_QUOTE_CHAR)
625  			name_s++;
626  		if (name_s == name_s_end) {
627  			p_error = parse_unexpected_data_end_rule;
628  			return (1);
629  		}
630  		begin_fmt = ++name_s; /* start of format string */
631  		while (name_s < name_s_end && *name_s != DOUBLE_QUOTE_CHAR)
632  			name_s++;
633  		if (name_s == name_s_end) {
634  			p_error = parse_unexpected_data_end_rule;
635  			return (1);
636  		}
637  		end_fmt = name_s;
638  		fmt_string = s_strndup(begin_fmt, end_fmt - begin_fmt);
639  		if (fmt_string == NULL) {
640  			p_error = parse_no_mem_error;
641  			return (2);
642  		}
643  		if (!get_mapping_format(fmt_string, &base, &n, NULL, FALSE)) {
644  			p_error = parse_internal_error;
645  			free(fmt_string);
646  			fmt_string = NULL;
647  			return (3);
648  		}
649  		free(fmt_string);
650  		fmt_string = NULL;
651  		for (n = 0; base[n].type != mmt_end; n++) {
652  			if (base[n].type != mmt_item && base[n].type
653  				!= mmt_berstring) {
654  				if (base[n].type == mmt_berstring_null)
655  					base[n].type = mmt_berstring;
656  				continue;
657  			}
658  			while (name_s < name_s_end && *name_s != COMMA_CHAR)
659  				name_s++;
660  			name_s++;    /* now at comma char */
661  			while (name_s < name_s_end && is_whitespace(*name_s))
662  				name_s++;
663  			begin_token = name_s++;
664  			end_token = name_s_end;
665  			name_s = get_next_token(
666  				&begin_token, &end_token, &token);
667  			if (name_s == NULL) {
668  				p_error = parse_item_expected_error;
669  				return (4);
670  			}
671  			if (token != string_token) {
672  				p_error = parse_item_expected_error;
673  				return (5);
674  			}
675  			item = (__nis_mapping_item_t *)s_realloc(item,
676  				(nElements + 1) *
677  				sizeof (__nis_mapping_item_t));
678  			if (item == NULL) {
679  				p_error = parse_no_mem_error;
680  				return (2);
681  			}
682  			name_s = get_mapping_item(begin_token, name_s_end,
683  				&item[nElements], item_type);
684  			if (name_s == NULL) {
685  				p_error = parse_unmatched_escape;
686  				for (n = 0; n < (nElements + 1); n++)
687  					free_mapping_item(&item[n]);
688  				free_mapping_format(base);
689  				return (4);
690  			}
691  			nElements++;
692  		}
693  		if (p_error != no_parse_error) {
694  			for (n = 0; n < (nElements + 1); n++)
695  				free_mapping_item(&item[n]);
696  			free_mapping_format(base);
697  			return (6);
698  		}
699  		name_s = skip_token(name_s, name_s_end, close_paren_token);
700  		if (name_s == NULL) {
701  			p_error = parse_close_paren_expected_error;
702  			for (n = 0; n < (nElements + 1); n++)
703  				free_mapping_item(&item[n]);
704  			free_mapping_format(base);
705  			return (4);
706  		}
707  		while (name_s < name_s_end && is_whitespace(*name_s))
708  			name_s++;
709  		if (*name_s == COMMA_CHAR)
710  			parse_next_line++;
711  
712  		if (nElements == 0) {
713  			p_error = parse_no_match_item;
714  			for (n = 0; n < (nElements + 1); n++)
715  				free_mapping_item(&item[n]);
716  			free_mapping_format(base);
717  			return (7);
718  		}
719  		elmnt = (__nis_mapping_element_t *)s_realloc(elmnt,
720  			(numSplits + 1) *
721  			sizeof (__nis_mapping_element_t));
722  		if (elmnt == NULL) {
723  			for (n = 0; n < (nElements + 1); n++)
724  				free_mapping_item(&item[n]);
725  			free_mapping_format(base);
726  			p_error = parse_no_mem_error;
727  			return (2);
728  		}
729  		elmnt[numSplits].type = me_match;
730  		elmnt[numSplits].element.match.numItems = nElements;
731  		elmnt[numSplits].element.match.item = item;
732  		elmnt[numSplits].element.match.fmt = base;
733  		item = NULL;
734  		base = NULL;
735  
736  		t_map->e = elmnt;
737  		t_map->numSplits = numSplits;
738  		n = t_map->numColumns;
739  
740  		for (i = n, itm_count = 0; i < n + nElements; i++) {
741  			if (t_map->e[numSplits].element.
742  				match.item[itm_count].name) {
743  				if (!add_column(t_map,
744  					t_map->e[numSplits].element.
745  					match.item[itm_count].name))
746  					return (1);
747  				itm_count++;
748  			} else {
749  				p_error = parse_internal_error;
750  				for (n = 0; n < (nElements + 1); n++)
751  					free_mapping_item(&item[n]);
752  				free_mapping_format(base);
753  				free_mapping_element(elmnt);
754  				return (1);
755  			}
756  		}
757  		numSplits++;
758  	}
759  	elmnt = NULL;
760  
761  	if (item != NULL) {
762  		for (n = 0; n < t_map->numColumns; n++) {
763  			free_mapping_item(&item[n]);
764  		}
765  		free(item);
766  	}
767  	if (elmnt != NULL)
768  		free_mapping_element(elmnt);
769  	if (base != NULL)
770  		free_mapping_format(base);
771  
772  	return (p_error == no_parse_error ? 0 : -1);
773  }
774  
775  /*
776   * FUNCTION:	parse_object_dn
777   *
778   *	Parse object dn attribute
779   *
780   * RETURN VALUE:	__nis_object_dn_t on success
781   *			NULL on failure
782   *
783   * INPUT:		the attribute value
784   */
785  
786  static __nis_object_dn_t *
787  parse_object_dn(const char *s, const char *end)
788  {
789  	const char		*s_begin;
790  	const char		*s_end;
791  	object_dn_token		token;
792  	parse_object_dn_state	dn_state	= dn_begin_parse;
793  	__nis_object_dn_t	*obj_dn		= NULL;
794  	__nis_object_dn_t	*next		= NULL;
795  	__nis_object_dn_t	*last		= NULL;
796  
797  	/*
798  	 * The attribute should be of form
799  	 * objectDN *( ";" objectDN )
800  	 * objectDN = readObjectSpec [":"[writeObjectSpec]]
801  	 * readObjectSpec = [baseAndScope [filterAttrValList]]
802  	 * writeObjectSpec = [baseAndScope [attrValList [":" deleteDisp]]]
803  	 */
804  
805  	while (s < end) {
806  		s_begin = s;
807  		s_end = end;
808  		s = get_next_object_dn_token(&s_begin, &s_end, &token);
809  		if (s == NULL)
810  			break;
811  
812  		if (token == dn_no_token || token == dn_semi_token) {
813  			if (obj_dn == NULL)
814  				obj_dn = next;
815  			else
816  				last->next = next;
817  			last = next;
818  			next = NULL;
819  			if (token == dn_no_token)
820  				break;
821  			dn_state = dn_begin_parse;
822  		}
823  		if (next == NULL) {
824  			next = (__nis_object_dn_t *)
825  				s_calloc(1, sizeof (__nis_object_dn_t));
826  			if (next == NULL)
827  				break;
828  			next->read.scope = LDAP_SCOPE_ONELEVEL;
829  			next->write.scope = LDAP_SCOPE_UNKNOWN;
830  			next->delDisp = dd_always;
831  		}
832  		if (token == dn_semi_token)
833  			continue;
834  
835  		switch (dn_state) {
836  		    case dn_begin_parse:
837  			if (token == dn_ques_token)
838  				dn_state = dn_got_read_q_scope;
839  			else if (token == dn_colon_token) {
840  				dn_state = dn_got_write_colon;
841  				next->write.scope = LDAP_SCOPE_ONELEVEL;
842  			} else {
843  				if (!validate_dn(s_begin, s_end - s_begin))
844  					break;
845  				next->read.base =
846  					s_strndup_esc(s_begin, s_end - s_begin);
847  				dn_state = dn_got_read_dn;
848  			}
849  			break;
850  		    case dn_got_read_dn:
851  			if (token == dn_ques_token)
852  				dn_state = dn_got_read_q_scope;
853  			else if (token == dn_colon_token) {
854  				dn_state = dn_got_write_colon;
855  				next->write.scope = LDAP_SCOPE_ONELEVEL;
856  			} else
857  				p_error = parse_object_dn_syntax_error;
858  			break;
859  		    case dn_got_read_q_scope:
860  			if (token == dn_ques_token)
861  				dn_state = dn_got_read_q_filter;
862  			else if (token == dn_colon_token) {
863  				dn_state = dn_got_write_colon;
864  				next->write.scope = LDAP_SCOPE_ONELEVEL;
865  			} else if (token == dn_base_token) {
866  				next->read.scope = LDAP_SCOPE_BASE;
867  				dn_state = dn_got_read_scope;
868  			} else if (token == dn_one_token) {
869  				next->read.scope = LDAP_SCOPE_ONELEVEL;
870  				dn_state = dn_got_read_scope;
871  			} else if (token == dn_sub_token) {
872  				next->read.scope = LDAP_SCOPE_SUBTREE;
873  				dn_state = dn_got_read_scope;
874  			} else {
875  				p_error = parse_invalid_scope;
876  			}
877  			break;
878  		    case dn_got_read_scope:
879  			if (token == dn_ques_token)
880  				dn_state = dn_got_read_q_filter;
881  			else if (token == dn_colon_token) {
882  				dn_state = dn_got_write_colon;
883  				next->write.scope = LDAP_SCOPE_ONELEVEL;
884  			} else
885  				p_error = parse_object_dn_syntax_error;
886  			break;
887  		    case dn_got_read_q_filter:
888  			if (token == dn_ques_token) {
889  				p_error = parse_object_dn_syntax_error;
890  			} else if (token == dn_colon_token) {
891  				dn_state = dn_got_write_colon;
892  				next->write.scope = LDAP_SCOPE_ONELEVEL;
893  			} else {
894  				if (!validate_ldap_filter(s_begin, s_end))
895  					break;
896  				next->read.attrs =
897  					s_strndup_esc(s_begin, s_end - s_begin);
898  				dn_state = dn_got_read_filter;
899  			}
900  			break;
901  		    case dn_got_read_filter:
902  			if (token == dn_ques_token) {
903  				p_error = parse_object_dn_syntax_error;
904  			} else if (token == dn_colon_token) {
905  				dn_state = dn_got_write_colon;
906  				next->write.scope = LDAP_SCOPE_ONELEVEL;
907  			} else
908  				p_error = parse_object_dn_syntax_error;
909  			break;
910  		    case dn_got_write_colon:
911  			if (token == dn_ques_token)
912  				dn_state = dn_got_write_q_scope;
913  			else if (token == dn_colon_token) {
914  				dn_state = dn_got_delete_colon;
915  			} else {
916  				if (!validate_dn(s_begin, s_end - s_begin))
917  					break;
918  				next->write.base =
919  					s_strndup_esc(s_begin, s_end - s_begin);
920  				dn_state = dn_got_write_dn;
921  			}
922  			break;
923  		    case dn_got_write_dn:
924  			if (token == dn_ques_token)
925  				dn_state = dn_got_write_q_scope;
926  			else if (token == dn_colon_token) {
927  				dn_state = dn_got_delete_colon;
928  			} else
929  				p_error = parse_object_dn_syntax_error;
930  			break;
931  		    case dn_got_write_q_scope:
932  			if (token == dn_ques_token)
933  				dn_state = dn_got_write_q_filter;
934  			else if (token == dn_colon_token) {
935  				dn_state = dn_got_delete_colon;
936  			} else if (token == dn_base_token) {
937  				next->write.scope = LDAP_SCOPE_BASE;
938  				dn_state = dn_got_write_scope;
939  			} else if (token == dn_one_token) {
940  				next->write.scope = LDAP_SCOPE_ONELEVEL;
941  				dn_state = dn_got_write_scope;
942  			} else if (token == dn_sub_token) {
943  				next->write.scope = LDAP_SCOPE_SUBTREE;
944  				dn_state = dn_got_write_scope;
945  			} else {
946  				p_error = parse_invalid_scope;
947  			}
948  			break;
949  		    case dn_got_write_scope:
950  			if (token == dn_ques_token)
951  				dn_state = dn_got_write_q_filter;
952  			else if (token == dn_colon_token) {
953  				dn_state = dn_got_delete_colon;
954  			} else
955  				p_error = parse_object_dn_syntax_error;
956  			break;
957  		    case dn_got_write_q_filter:
958  			if (token == dn_ques_token) {
959  				p_error = parse_object_dn_syntax_error;
960  			} else if (token == dn_colon_token) {
961  				dn_state = dn_got_delete_colon;
962  			} else {
963  				if (!validate_ldap_filter(s_begin, s_end))
964  					break;
965  				next->write.attrs =
966  					s_strndup_esc(s_begin, s_end - s_begin);
967  				dn_state = dn_got_write_filter;
968  			}
969  			break;
970  		    case dn_got_write_filter:
971  			if (token == dn_ques_token) {
972  				p_error = parse_object_dn_syntax_error;
973  			} else if (token == dn_colon_token) {
974  				dn_state = dn_got_delete_colon;
975  
976  			} else
977  				p_error = parse_semi_expected_error;
978  			break;
979  		    case dn_got_delete_colon:
980  			if (token == dn_ques_token) {
981  				p_error = parse_object_dn_syntax_error;
982  			} else if (token == dn_colon_token) {
983  				p_error = parse_object_dn_syntax_error;
984  			} else {
985  				if (!get_deleteDisp(s_begin, s_end, next))
986  					break;
987  				dn_state = dn_got_delete_dsp;
988  			}
989  			break;
990  		    case dn_got_delete_dsp:
991  			p_error = parse_object_dn_syntax_error;
992  			break;
993  		}
994  
995  		if (p_error != no_parse_error)
996  			break;
997  	}
998  	if (p_error != no_parse_error) {
999  		if (obj_dn != NULL)
1000  			free_object_dn(obj_dn);
1001  		if (next != NULL)
1002  			free_object_dn(next);
1003  		obj_dn = NULL;
1004  	} else if (next != NULL) {
1005  		if (obj_dn == NULL)
1006  			obj_dn = next;
1007  		else
1008  			last->next = next;
1009  	} else if (obj_dn == NULL)
1010  		obj_dn = (__nis_object_dn_t *)
1011  			s_calloc(1, sizeof (__nis_object_dn_t));
1012  
1013  	return (obj_dn);
1014  }
1015  
1016  /*
1017   * FUNCTION:	get_mapping_rule
1018   *
1019   *	Parse mapping rule attributes
1020   *
1021   * RETURN VALUE:	None. Errors determined by p_error
1022   *
1023   * INPUT:		the attribute value and mapping rule type
1024   */
1025  
1026  static void
1027  get_mapping_rule(
1028  	const char		*s,
1029  	int			len,
1030  	__nis_table_mapping_t	*tbl,
1031  	bool_t			to_ldap)
1032  {
1033  	const char		*end_s			= s + len;
1034  	const char		*begin_token;
1035  	const char		*end_token;
1036  	__nis_mapping_rule_t	**rule			= NULL;
1037  	__nis_mapping_rule_t	*next			= NULL;
1038  	/* __nis_mapping_rule_t	**r; */
1039  	token_type		t;
1040  	int			nRules			= 0;
1041  	const char		*s1;
1042  	int			i;
1043  
1044  	/*
1045  	 * The attribute value is of the form
1046  	 * colattrspec *("," colattrspec)
1047  	 * colattrspec	= lhs "=" rhs
1048  	 * lhs		= lval | namespeclist
1049  	 * rhs		= rval | [namespec]
1050  	 */
1051  
1052  	for (;;) {
1053  		if ((next = (__nis_mapping_rule_t *)
1054  		    s_calloc(1, sizeof (__nis_mapping_rule_t))) == NULL)
1055  			break;
1056  
1057  		s = get_lhs(s, end_s, &next->lhs,
1058  			to_ldap ? mit_ldap : mit_nisplus);
1059  		if (s == NULL)
1060  			break;
1061  
1062  		begin_token = s;
1063  		end_token = end_s;
1064  		s1 = get_next_token(&begin_token, &end_token, &t);
1065  		if (s1 == NULL)
1066  			break;
1067  		if (!(to_ldap && (t == comma_token || t == no_token))) {
1068  			s = get_rhs(s, end_s, &next->rhs,
1069  				to_ldap ? mit_nisplus : mit_ldap);
1070  			if (s == NULL)
1071  				break;
1072  		}
1073  
1074  		if (next->lhs.numElements > 1 &&
1075  		    (next->rhs.numElements != 1 ||
1076  		    next->rhs.element[0].type != me_split)) {
1077  			p_error = parse_lhs_rhs_type_mismatch;
1078  			break;
1079  		}
1080  		if (rule == NULL) {
1081  			rule = (__nis_mapping_rule_t **)
1082  				malloc(sizeof (__nis_mapping_rule_t *));
1083  			if (rule == NULL)
1084  				break;
1085  		} else {
1086  			rule = (__nis_mapping_rule_t **)s_realloc(rule,
1087  				(nRules + 1) *
1088  				sizeof (__nis_mapping_rule_t *));
1089  			if (rule == NULL)
1090  				break;
1091  		}
1092  
1093  		rule[nRules++] = next;
1094  		next = NULL;
1095  
1096  		begin_token = s;
1097  		end_token = end_s;
1098  		s = get_next_token(&begin_token, &end_token, &t);
1099  		if (s == NULL)
1100  			break;
1101  		if (t == comma_token)
1102  			continue;
1103  		if (t != no_token) {
1104  			p_error = parse_unexpected_data_end_rule;
1105  			break;
1106  		}
1107  		if (to_ldap) {
1108  			tbl->numRulesToLDAP = nRules;
1109  			tbl->ruleToLDAP = rule;
1110  		} else {
1111  			tbl->numRulesFromLDAP = nRules;
1112  			tbl->ruleFromLDAP = rule;
1113  		}
1114  		return;
1115  	}
1116  
1117  	if (rule) {
1118  		for (i = 0; i < nRules; i++)
1119  			free_mapping_rule(rule[i]);
1120  		free(rule);
1121  	}
1122  	if (next)
1123  		free_mapping_rule(next);
1124  }
1125  
1126  /*
1127   * FUNCTION:	get_lhs
1128   *
1129   *	Parse left hand side of mapping rule attribute
1130   *
1131   * RETURN VALUE:	NULL if error
1132   *			position of beginning rhs
1133   *
1134   * INPUT:		the attribute value and mapping rule type
1135   */
1136  
1137  static const char *
1138  get_lhs(const char			*s,
1139  	const char			*end_s,
1140  	__nis_mapping_rlhs_t		*lhs,
1141  	__nis_mapping_item_type_t	item_type)
1142  {
1143  	token_type		t;
1144  	const char		*begin_token;
1145  	const char		*end_token;
1146  	const char		*sav_s;
1147  	__nis_mapping_element_t	*e		= NULL;
1148  
1149  	/*
1150  	 *	lhs can be expressed as:
1151  	 *		item
1152  	 *		(item)
1153  	 *		(item list)
1154  	 *		(fmt, item list)
1155  	 *
1156  	 * lhs = lval | namespeclist
1157  	 * lval = "(" formatspec "," namespec *("," namespec) ")"
1158  	 * namespeclist = namespec | "(" namespec *("," namespec) ")"
1159  	 */
1160  
1161  	for (; p_error == no_parse_error; ) {
1162  		begin_token = s;
1163  		end_token = end_s;
1164  		s = get_next_token(&begin_token, &end_token, &t);
1165  		if (s == NULL)
1166  			break;
1167  		if (t == no_token) {
1168  			p_error = parse_unexpected_data_end_rule;
1169  			break;
1170  		}
1171  
1172  		e = (__nis_mapping_element_t *)
1173  			s_calloc(1, sizeof (__nis_mapping_element_t));
1174  		if (e == NULL)
1175  			break;
1176  
1177  		if (t == open_paren_token) {
1178  			free(e);
1179  			e = NULL;
1180  
1181  			begin_token = s;
1182  			end_token = end_s;
1183  			sav_s = s;
1184  			s = get_next_token(&begin_token, &end_token, &t);
1185  			if (s == NULL)
1186  				break;
1187  
1188  			if (t == quoted_string_token) {
1189  				s = get_lhs_match(sav_s, end_s, lhs, item_type);
1190  				if (s == NULL)
1191  					break;
1192  			} else if (t == string_token) {
1193  				s = get_lhs_paren_item(sav_s, end_s, lhs,
1194  					item_type);
1195  				if (s == NULL)
1196  					break;
1197  			} else {
1198  				p_error = parse_bad_lhs_format_error;
1199  				break;
1200  			}
1201  		} else if (t == string_token) {
1202  			s = get_mapping_item(begin_token, end_s,
1203  				&e->element.item, item_type);
1204  			if (s == NULL)
1205  				break;
1206  			e->type = me_item;
1207  			if (!add_element(e, lhs))
1208  				break;
1209  			e = NULL;
1210  		} else {
1211  			p_error = parse_bad_lhs_format_error;
1212  			break;
1213  		}
1214  
1215  		s = skip_token(s, end_s, equal_token);
1216  		if (s == NULL)
1217  			break;
1218  		if (p_error == no_parse_error)
1219  			return (s);
1220  	}
1221  	if (e != NULL)
1222  		free_mapping_element(e);
1223  
1224  	return (NULL);
1225  }
1226  
1227  /*
1228   * FUNCTION:	get_lhs_match
1229   *
1230   *	Parse left hand side of mapping rule attribute in case of
1231   *	matching rule
1232   *
1233   * RETURN VALUE:	NULL if error
1234   *			position of beginning rhs
1235   *
1236   * INPUT:		the attribute value and mapping rule type
1237   */
1238  
1239  static const char *
1240  get_lhs_match(
1241  	const char			*s,
1242  	const char			*end_s,
1243  	__nis_mapping_rlhs_t		*lhs,
1244  	__nis_mapping_item_type_t	item_type)
1245  {
1246  	token_type			t;
1247  	const char			*begin_token;
1248  	const char			*end_token;
1249  	int				n		= 0;
1250  	int				nElements	= 0;
1251  	char				*fmt_string	= NULL;
1252  	__nis_mapping_format_t		*base		= NULL;
1253  	__nis_mapping_item_t		*item		= NULL;
1254  	__nis_mapping_item_t		*itm;
1255  	__nis_mapping_element_t		*e;
1256  
1257  	/*
1258  	 *  lval = "(" formatspec "," namespec *("," namespec) ")"
1259  	 */
1260  
1261  	for (; p_error == no_parse_error; ) {
1262  		begin_token = s;
1263  		end_token = end_s;
1264  		s = get_next_token(&begin_token, &end_token, &t);
1265  		if (s == NULL || t != quoted_string_token) {
1266  			p_error = parse_internal_error;
1267  			break;
1268  		}
1269  
1270  
1271  		fmt_string = s_strndup(begin_token, end_token - begin_token);
1272  		if (fmt_string == NULL)
1273  			break;
1274  
1275  		if (!get_mapping_format(fmt_string, &base, &n, NULL, FALSE))
1276  			break;
1277  
1278  		for (n = 0; base[n].type != mmt_end; n++) {
1279  			if (base[n].type != mmt_item &&
1280  			    base[n].type != mmt_berstring) {
1281  				if (base[n].type == mmt_berstring_null)
1282  					base[n].type = mmt_berstring;
1283  				continue;
1284  			}
1285  			s = skip_token(s, end_s, comma_token);
1286  			if (s == NULL) {
1287  				p_error = parse_not_enough_extract_items;
1288  				break;
1289  			}
1290  			begin_token = s;
1291  			end_token = end_s;
1292  			s = get_next_token(&begin_token, &end_token, &t);
1293  			if (s == NULL)
1294  				break;
1295  			if (t != string_token) {
1296  				p_error = parse_item_expected_error;
1297  				break;
1298  			}
1299  			itm = (__nis_mapping_item_t *)
1300  				s_realloc(item, (nElements + 1) *
1301  				sizeof (__nis_mapping_item_t));
1302  			if (itm == NULL)
1303  				break;
1304  			item = itm;
1305  
1306  			s = get_mapping_item(begin_token, end_s,
1307  				&item[nElements], item_type);
1308  			if (s == NULL)
1309  				break;
1310  			nElements++;
1311  		}
1312  		if (p_error != no_parse_error)
1313  			break;
1314  
1315  		s = skip_token(s, end_s, close_paren_token);
1316  		if (s == NULL)
1317  			break;
1318  		free(fmt_string);
1319  		fmt_string = NULL;
1320  
1321  		if (nElements == 0) {
1322  			p_error = parse_no_match_item;
1323  			break;
1324  		}
1325  		e = (__nis_mapping_element_t *)s_calloc(1,
1326  			sizeof (__nis_mapping_element_t));
1327  		if (e == NULL)
1328  			break;
1329  		e->type = me_match;
1330  		e->element.match.numItems = nElements;
1331  		e->element.match.item = item;
1332  		e->element.match.fmt = base;
1333  		lhs->numElements = 1;
1334  		lhs->element = e;
1335  
1336  		if (p_error == no_parse_error)
1337  			return (s);
1338  	}
1339  	if (item == NULL) {
1340  		for (n = 0; n < nElements; n++)
1341  			free_mapping_item(&item[n]);
1342  		free(item);
1343  	}
1344  	if (fmt_string != NULL)
1345  		free(fmt_string);
1346  	if (base != NULL)
1347  		free_mapping_format(base);
1348  
1349  	return (NULL);
1350  }
1351  
1352  /*
1353   * FUNCTION:	get_lhs_paren_item
1354   *
1355   *	Parse left hand side of mapping rule attribute in case of
1356   *	(item1, ..., item-n)
1357   *
1358   * RETURN VALUE:	NULL if error
1359   *			position of beginning rhs
1360   *
1361   * INPUT:		the attribute value and mapping rule type
1362   */
1363  
1364  static const char *
1365  get_lhs_paren_item(
1366  	const char			*s,
1367  	const char			*end_s,
1368  	__nis_mapping_rlhs_t		*lhs,
1369  	__nis_mapping_item_type_t	item_type)
1370  {
1371  	token_type		t;
1372  	const char		*begin_token;
1373  	const char		*end_token;
1374  	__nis_mapping_element_t	*e		= NULL;
1375  	int			n		= 0;
1376  	int			i;
1377  
1378  	/*
1379  	 * "(" namespec *("," namespec) ")"
1380  	 */
1381  
1382  	for (;;) {
1383  		e = (__nis_mapping_element_t *)s_realloc(e, (n + 1) *
1384  			sizeof (__nis_mapping_element_t));
1385  		if (e == NULL)
1386  			break;
1387  
1388  		s = get_mapping_item(s, end_s, &e[n].element.item,
1389  			item_type);
1390  		if (s == NULL)
1391  			break;
1392  		e[n].type = me_item;
1393  		n++;
1394  
1395  		begin_token = s;
1396  		end_token = end_s;
1397  		s = get_next_token(&begin_token, &end_token, &t);
1398  		if (s != NULL && t == close_paren_token) {
1399  			lhs->numElements = n;
1400  			if (n == 1)
1401  				e[0].element.item.repeat = TRUE;
1402  			lhs->element = e;
1403  			return (s);
1404  		}
1405  		if (s == NULL || t != comma_token) {
1406  			p_error = parse_comma_expected_error;
1407  			break;
1408  		}
1409  	}
1410  	for (i = 0; i < n; i++)
1411  		free_mapping_element(&e[i]);
1412  	if (e != NULL)
1413  		free(e);
1414  	return (NULL);
1415  }
1416  
1417  /*
1418   * FUNCTION:	get_rhs
1419   *
1420   *	Parse right hand side of mapping rule attribute
1421   *
1422   * RETURN VALUE:	NULL if error
1423   *			position of beginning next mapping rule
1424   *
1425   * INPUT:		the attribute value and mapping rule type
1426   */
1427  
1428  static const char *
1429  get_rhs(
1430  	const char			*s,
1431  	const char			*end_s,
1432  	__nis_mapping_rlhs_t		*rhs,
1433  	__nis_mapping_item_type_t	item_type)
1434  {
1435  	/*
1436  	 * This handles the following cases:
1437  	 *	name				me_item
1438  	 *	(name)				me_item
1439  	 *	(fmt, name-list)		me_print
1440  	 *	(item, fmt)			me_extract
1441  	 */
1442  
1443  	token_type		t;
1444  	const char		*begin_token;
1445  	const char		*end_token;
1446  	char			*str		= NULL;
1447  	__nis_mapping_format_t	*fmt		= NULL;
1448  	__nis_mapping_element_t	*e		= NULL;
1449  	__nis_mapping_item_t	item;
1450  	int			n;
1451  
1452  	(void) memset(&item, 0, sizeof (item));
1453  
1454  	for (; p_error == no_parse_error; ) {
1455  		begin_token = s;
1456  		end_token = end_s;
1457  		s = get_next_token(&begin_token, &end_token, &t);
1458  		if (s == NULL)
1459  			break;
1460  
1461  		e = (__nis_mapping_element_t *)
1462  			s_calloc(1, sizeof (__nis_mapping_element_t));
1463  		if (e == NULL)
1464  			break;
1465  
1466  		if (t == string_token) {
1467  			s = get_mapping_item(begin_token, end_s,
1468  				&e->element.item, item_type);
1469  		} else if (t == open_paren_token) {
1470  			begin_token = s;
1471  			end_token = end_s;
1472  			s = get_next_token(&begin_token, &end_token, &t);
1473  			if (s == NULL)
1474  				break;
1475  			if (t == string_token) {
1476  				/* (item, fmt) - me_extract */
1477  				/* (item, "c") - me_split */
1478  				s = get_mapping_item(begin_token, end_s,
1479  					&item, item_type);
1480  				if (s == NULL)
1481  					break;
1482  				begin_token = s;
1483  				end_token = end_s;
1484  				s = get_next_token(&begin_token, &end_token,
1485  					&t);
1486  				if (s == NULL)
1487  					break;
1488  				else if (t == close_paren_token) {
1489  					item.repeat = TRUE;
1490  					e->element.item = item;
1491  					e->type = me_item;
1492  					rhs->numElements = 1;
1493  					rhs->element = e;
1494  					return (s);
1495  				} else if (t != comma_token) {
1496  					p_error = parse_comma_expected_error;
1497  					break;
1498  				}
1499  
1500  				begin_token = s;
1501  				end_token = end_s;
1502  				s = get_next_token(&begin_token, &end_token,
1503  					&t);
1504  				if (s == NULL || t != quoted_string_token) {
1505  				    p_error =
1506  					parse_format_string_expected_error;
1507  				    break;
1508  				}
1509  
1510  				if (end_token == begin_token + 1 ||
1511  				    (*begin_token == ESCAPE_CHAR &&
1512  				    end_token == begin_token + 2)) {
1513  					e->type = me_split;
1514  					e->element.split.item = item;
1515  					e->element.split.delim = *begin_token;
1516  				} else {
1517  					str = s_strndup(begin_token,
1518  						end_token - begin_token);
1519  					if (str == NULL)
1520  						break;
1521  					if (!get_mapping_format(str, &fmt,
1522  					    NULL, &n, FALSE))
1523  						break;
1524  					free(str);
1525  					str = NULL;
1526  					if (n != 1) {
1527  					    p_error =
1528  						parse_bad_extract_format_spec;
1529  					    break;
1530  					}
1531  					e->type = me_extract;
1532  					e->element.extract.item = item;
1533  					e->element.extract.fmt = fmt;
1534  				}
1535  				s = skip_token(s, end_s, close_paren_token);
1536  			} else if (t == quoted_string_token) {
1537  				/* (fmt, name-list) - me_print */
1538  				str = s_strndup(begin_token,
1539  					end_token - begin_token);
1540  				if (str == NULL)
1541  					break;
1542  
1543  				s = get_print_mapping_element(s, end_s,
1544  					str, e, item_type);
1545  				free(str);
1546  				str = NULL;
1547  			} else {
1548  				p_error = parse_start_rhs_unrecognized;
1549  				break;
1550  			}
1551  		} else {
1552  			p_error = parse_start_rhs_unrecognized;
1553  			break;
1554  		}
1555  		if (s == NULL)
1556  			break;
1557  		rhs->numElements = 1;
1558  		rhs->element = e;
1559  		if (p_error == no_parse_error)
1560  			return (s);
1561  	}
1562  	if (str)
1563  		free(str);
1564  	if (fmt != NULL)
1565  		free_mapping_format(fmt);
1566  	if (e != NULL)
1567  		free_mapping_element(e);
1568  	free_mapping_item(&item);
1569  
1570  	return (NULL);
1571  }
1572  
1573  /*
1574   * FUNCTION:	get_print_mapping_element
1575   *
1576   *	Parse a print mapping rule attribute in case of the form
1577   *	(fmt, name-list)
1578   *
1579   * RETURN VALUE:	NULL if error
1580   *			position of beginning next mapping rule
1581   *
1582   * INPUT:		the attribute value and mapping rule type
1583   */
1584  
1585  static const char *
1586  get_print_mapping_element(
1587  	const char			*s,
1588  	const char			*end_s,
1589  	char				*fmt_string,
1590  	__nis_mapping_element_t		*e,
1591  	__nis_mapping_item_type_t	item_type)
1592  {
1593  	token_type			t;
1594  	const char			*begin_token;
1595  	const char			*end_token;
1596  	char				elide;
1597  	bool_t				doElide;
1598  	__nis_mapping_format_t		*base		= NULL;
1599  	__nis_mapping_sub_element_t	*subElement	= NULL;
1600  	int				n		= 0;
1601  	int				nSub		= 0;
1602  	int				numSubElements;
1603  
1604  	for (; p_error == no_parse_error; ) {
1605  		if (!get_mapping_format(fmt_string, &base, &n,
1606  		    &numSubElements, TRUE))
1607  			break;
1608  		subElement = (__nis_mapping_sub_element_t *)
1609  			s_calloc(numSubElements,
1610  			sizeof (__nis_mapping_sub_element_t));
1611  		if (subElement == NULL)
1612  			break;
1613  		for (n = 0; base[n].type != mmt_end; n++) {
1614  			if (base[n].type != mmt_item &&
1615  				base[n].type != mmt_berstring) {
1616  			    if (base[n].type == mmt_berstring_null)
1617  				base[n].type = mmt_berstring;
1618  			    continue;
1619  			}
1620  			if (nSub < numSubElements) {
1621  				s = skip_token(s, end_s, comma_token);
1622  				if (s == NULL) {
1623  					p_error = parse_bad_print_format;
1624  					break;
1625  				}
1626  			}
1627  
1628  			/* namelist may have parens around it */
1629  			s = get_subElement(s, end_s, &subElement[nSub],
1630  				item_type);
1631  			if (s == NULL)
1632  				break;
1633  			nSub++;
1634  		}
1635  		if (p_error != no_parse_error)
1636  			break;
1637  
1638  		begin_token = s;
1639  		end_token = end_s;
1640  		s = get_next_token(&begin_token, &end_token, &t);
1641  		if (s == NULL || t == no_token) {
1642  			p_error = parse_unexpected_data_end_rule;
1643  			break;
1644  		} else if (t == close_paren_token) {
1645  			doElide = FALSE;
1646  			elide = '\0';
1647  		} else if (t == comma_token) {
1648  			begin_token = s;
1649  			end_token = end_s;
1650  			s = get_next_token(&begin_token, &end_token, &t);
1651  			if (s != NULL && t == quoted_string_token &&
1652  			    (end_token == begin_token + 1 ||
1653  			    (*begin_token == ESCAPE_CHAR &&
1654  			    end_token == begin_token + 2))) {
1655  				if (numSubElements != 1 ||
1656  				    subElement->type == me_extract ||
1657  				    subElement->type == me_split) {
1658  					p_error = parse_cannot_elide;
1659  					break;
1660  				}
1661  				if (subElement->type == me_item &&
1662  				    !subElement->element.item.repeat) {
1663  					p_error = parse_cannot_elide;
1664  					break;
1665  				}
1666  				elide = *begin_token;
1667  				doElide = TRUE;
1668  
1669  			} else {
1670  				p_error = parse_bad_elide_char;
1671  				break;
1672  			}
1673  			s = skip_token(s, end_s, close_paren_token);
1674  			if (s == NULL)
1675  				break;
1676  		}
1677  
1678  		e->type = me_print;
1679  		e->element.print.fmt = base;
1680  		e->element.print.numSubElements = numSubElements;
1681  		e->element.print.subElement = subElement;
1682  		e->element.print.elide = elide;
1683  		e->element.print.doElide = doElide;
1684  
1685  		if (p_error == no_parse_error)
1686  			return (s);
1687  	}
1688  	if (base)
1689  		free_mapping_format(base);
1690  	if (subElement != NULL) {
1691  		for (n = 0; n < numSubElements; n++)
1692  			free_mapping_sub_element(&subElement[n]);
1693  		free(subElement);
1694  	}
1695  
1696  	return (NULL);
1697  }
1698  
1699  /*
1700   * FUNCTION:	get_mapping_item
1701   *
1702   *	Parse attribute string to get mapping item
1703   *
1704   * RETURN VALUE:	NULL if error
1705   *			position of beginning next token after item
1706   *
1707   * INPUT:		the attribute value and mapping rule type
1708   */
1709  
1710  static const char *
1711  get_mapping_item(
1712  	const char			*s,
1713  	const char			*end_s,
1714  	__nis_mapping_item_t		*item,
1715  	__nis_mapping_item_type_t	type)
1716  {
1717  	token_type			t;
1718  	const char			*begin_token;
1719  	const char			*end_token;
1720  	char				*name		= NULL;
1721  	char				*index_string;
1722  	const char			*s_sav;
1723  	int				len;
1724  
1725  	(void) memset(item, 0, sizeof (*item));
1726  
1727  	/*
1728  	 * A namepec is defined as follows:
1729  	 * namespec	= ["ldap:"] attrspec [searchTriple] |
1730  	 *		  ["nis+:"] colspec  [objectspec]
1731  	 *
1732  	 * The form of the item is assumed to be as follows:
1733  	 * ["ldap:"] attrspec [searchTriple]
1734  	 * attrspec = attribute | "(" attribute ")"
1735  	 * searchTriple	= ":" [baseDN] ["?" [scope] ["?" [filter]]]
1736  	 * baseDN = Base DN for search
1737  	 * scope = "base" | "one" | "sub"
1738  	 * filter = LDAP search filter
1739  	 *
1740  	 * The form of the objectspec is as follows:
1741  	 * ["nis+:"] colspec  [objectspec]
1742  	 * objectspec	= objectname | "[" indexlist "]" tablename
1743  	 * objectname	= The name of a NIS+ object
1744  	 * tablename	= The name of a NIS+ table
1745  	 * indexlist	= colspec ["," colspec]
1746  	 * colspec	= colname "=" colvalue
1747  	 * colname	= The name of a column in the table
1748  	 * colvalue	= colvaluestring | \" colvaluestring \"
1749  	 */
1750  
1751  	for (; p_error == no_parse_error; ) {
1752  		while (s < end_s && is_whitespace(*s))
1753  			s++;
1754  		len = end_s - s;
1755  		if (yp2ldap) {
1756  			if ((begin_token = skip_string("ldap:", s,
1757  				len)) != NULL) {
1758  				item->type = mit_ldap;
1759  			} else if ((begin_token = skip_string("yp:", s,
1760  				len)) != NULL) {
1761  				item->type = mit_nisplus;
1762  			} else {
1763  				item->type = type;
1764  				begin_token = s;
1765  			}
1766  		} else {
1767  			if ((begin_token = skip_string("ldap:", s,
1768  				len)) != NULL) {
1769  			item->type = mit_ldap;
1770  			} else if ((begin_token = skip_string("nis+:", s,
1771  				len)) != NULL) {
1772  				item->type = mit_nisplus;
1773  			} else if ((begin_token = skip_string("nisplus:", s,
1774  				len)) != NULL) {
1775  				item->type = mit_nisplus;
1776  			} else {
1777  				item->type = type;
1778  				begin_token = s;
1779  			}
1780  		}
1781  
1782  		end_token = end_s;
1783  		s = get_next_token(&begin_token, &end_token, &t);
1784  		if (s == NULL || t != string_token) {
1785  			p_error = parse_bad_item_format;
1786  			break;
1787  		}
1788  
1789  		item->name = s_strndup_esc(begin_token,
1790  			end_token - begin_token);
1791  		if (item->name == NULL)
1792  			break;
1793  		if (item->type == mit_ldap) {
1794  			item->searchSpec.triple.scope = LDAP_SCOPE_UNKNOWN;
1795  			begin_token = s;
1796  			end_token = end_s;
1797  			s_sav = s;
1798  			s = get_next_token(&begin_token, &end_token, &t);
1799  			if (s != NULL && t == colon_token) {
1800  				s = get_search_triple(s, end_s,
1801  					&item->searchSpec.triple);
1802  				if (s == NULL)
1803  					break;
1804  			} else
1805  				s = s_sav;
1806  		} else if (item->type == mit_nisplus) {
1807  			while (s < end_s && is_whitespace(*s))
1808  				s++;
1809  
1810  			if (s < end_s && *s == OPEN_BRACKET) {
1811  				index_string = getIndex(&s, end_s);
1812  				if (index_string == NULL)
1813  					break;
1814  				(void) parse_index(index_string,
1815  					index_string + strlen(index_string),
1816  					&item->searchSpec.obj.index);
1817  				free(index_string);
1818  				if (p_error != no_parse_error)
1819  					break;
1820  			}
1821  			s_sav = s;
1822  			begin_token = s;
1823  			end_token = end_s;
1824  			s = get_next_token(&begin_token, &end_token, &t);
1825  			if (s != NULL && t == string_token) {
1826  				name = s_strndup_esc(begin_token,
1827  					end_token - begin_token);
1828  				if (name == NULL)
1829  					break;
1830  				item->searchSpec.obj.name = name;
1831  			} else
1832  				s = s_sav;
1833  		}
1834  		if (p_error == no_parse_error)
1835  			return (s);
1836  	}
1837  	free_mapping_item(item);
1838  	(void) memset(item, 0, sizeof (*item));
1839  	if (name == NULL)
1840  		free(name);
1841  	return (NULL);
1842  }
1843  
1844  static const char *
1845  get_print_sub_element(const char		*s,
1846  		const char			*end_s,
1847  		__nis_mapping_item_type_t	type,
1848  		__nis_mapping_sub_element_t	*sub)
1849  {
1850  
1851  	int			k;
1852  	int			n;
1853  	const char		*begin_token;
1854  	const char		*end_token;
1855  	token_type		t;
1856  	__nis_mapping_format_t	*base;
1857  	__nis_mapping_item_t	*print_item;
1858  
1859  	k = 0;
1860  	base = sub->element.print.fmt;
1861  	print_item = sub->element.print.item;
1862  	sub->element.print.doElide = FALSE;
1863  	sub->element.print.elide = '\0';
1864  
1865  	for (n = 0; base[n].type != mmt_end; n++) {
1866  		if (base[n].type != mmt_item && base[n].type != mmt_berstring) {
1867  			if (base[n].type == mmt_berstring_null)
1868  					base[n].type = mmt_berstring;
1869  			continue;
1870  		}
1871  		s = skip_token(s, end_s, comma_token);
1872  		if (s == NULL) {
1873  			p_error = parse_bad_print_format;
1874  			break;
1875  		}
1876  
1877  		begin_token = s;
1878  		end_token = end_s;
1879  		s = get_next_token(&begin_token, &end_token, &t);
1880  		if (s == NULL)
1881  			break;
1882  		/*
1883  		 * Determine if of the form
1884  		 * ("fmt", (item), "delim") or
1885  		 * ("fmt", item1, item2, ..., item n)
1886  		 */
1887  		if (t == open_paren_token) {
1888  			if (sub->element.print.numItems != 1) {
1889  				p_error = parse_invalid_print_arg;
1890  				break;
1891  			}
1892  			s = get_mapping_item(s, end_s, &print_item[k++], type);
1893  			s = skip_token(s, end_s, close_paren_token);
1894  			s = skip_token(s, end_s, comma_token);
1895  			if (s == NULL) {
1896  				p_error = parse_bad_print_format;
1897  				break;
1898  			}
1899  			begin_token = s;
1900  			end_token = end_s;
1901  			s = get_next_token(&begin_token, &end_token, &t);
1902  			if (s == NULL)
1903  				break;
1904  			if (t != quoted_string_token ||
1905  				    begin_token + 1 != end_token) {
1906  				p_error = parse_bad_elide_char;
1907  				break;
1908  			}
1909  			sub->element.print.elide = *begin_token;
1910  			sub->element.print.doElide = TRUE;
1911  			print_item[0].repeat = TRUE;
1912  			break;
1913  		}
1914  		s = get_mapping_item(begin_token, end_s,
1915  			&print_item[k++], type);
1916  		if (s == NULL)
1917  			break;
1918  
1919  		if (p_error != no_parse_error)
1920  			break;
1921  	}
1922  
1923  	return (p_error == no_parse_error ? s : NULL);
1924  }
1925  
1926  /*
1927   * FUNCTION:	get_subElement
1928   *
1929   *	Parse attribute string to get sub element item
1930   *
1931   * RETURN VALUE:	NULL if error
1932   *			position of beginning next token after item
1933   *
1934   * INPUT:		the attribute value and mapping rule type
1935   */
1936  
1937  static const char *
1938  get_subElement(
1939  	const char			*s,
1940  	const char			*end_s,
1941  	__nis_mapping_sub_element_t	*subelement,
1942  	__nis_mapping_item_type_t	type)
1943  {
1944  	token_type			t;
1945  	const char			*begin_token;
1946  	const char			*end_token;
1947  	char				*fmt_string;
1948  	__nis_mapping_item_t		item;
1949  	__nis_mapping_element_type_t	e_type;
1950  	__nis_mapping_item_t		*print_item	= NULL;
1951  	__nis_mapping_format_t		*base		= NULL;
1952  	int				n		= 0;
1953  	int				numItems	= 0;
1954  	unsigned char			delim;
1955  	__nis_mapping_sub_element_t	sub;
1956  
1957  /*
1958   *	What is the form of we are expecting here
1959   *	item					me_item
1960   *	(item)					me_item
1961   *	("fmt", item1, item2, ..., item n)	me_print
1962   *	("fmt", (item), "elide")		me_print
1963   *	(name, "delim")				me_split
1964   *	(item, "fmt")				me_extract
1965   */
1966  	(void) memset(&item, 0, sizeof (item));
1967  
1968  	for (; p_error == no_parse_error; ) {
1969  		begin_token = s;
1970  		end_token = end_s;
1971  		s = get_next_token(&begin_token, &end_token, &t);
1972  		if (s == NULL)
1973  			break;
1974  		if (t == string_token) {	/* me_item */
1975  			s = get_mapping_item(begin_token, end_s,
1976  				&subelement->element.item, type);
1977  			if (s == NULL)
1978  				break;
1979  			subelement->type = me_item;
1980  			return (s);
1981  		} else if (t != open_paren_token) {
1982  			p_error = parse_item_expected_error;
1983  			break;
1984  		}
1985  
1986  		begin_token = s;
1987  		end_token = end_s;
1988  		s = get_next_token(&begin_token, &end_token, &t);
1989  		if (s == NULL)
1990  			break;
1991  
1992  		if (t != string_token && t != quoted_string_token) {
1993  			p_error = parse_item_expected_error;
1994  			break;
1995  		}
1996  		e_type = me_print;
1997  		if (t == string_token) {
1998  			/* me_item, me_extract or me_split */
1999  			s = get_mapping_item(begin_token, end_s, &item, type);
2000  			if (s == NULL)
2001  				break;
2002  
2003  			begin_token = s;
2004  			end_token = end_s;
2005  			s = get_next_token(&begin_token, &end_token, &t);
2006  			if (s == NULL) {
2007  				p_error = parse_unexpected_data_end_rule;
2008  				break;
2009  			} else if (t == close_paren_token) {
2010  				subelement->type = me_item;
2011  				item.repeat = TRUE;
2012  				subelement->element.item = item;
2013  				if (yp2ldap) {
2014  					while (s < end_s && is_whitespace(*s))
2015  						s++;
2016  					if (s == end_s) {
2017  						p_error =
2018  						parse_unexpected_data_end_rule;
2019  						break;
2020  					}
2021  					if (*s == DASH_CHAR && s < end_s) {
2022  						s++;
2023  						while (s < end_s &&
2024  							is_whitespace(*s))
2025  							s++;
2026  						begin_token = s;
2027  						end_token = end_s;
2028  
2029  						subelement->element.item.exItem
2030  							=
2031  							(__nis_mapping_item_t *)
2032  					s_malloc(sizeof (__nis_mapping_item_t));
2033  						if (!subelement->
2034  						element.item.exItem)
2035  							break;
2036  						s = get_mapping_item(s, end_s,
2037  							subelement->
2038  							element.item.exItem,
2039  							type);
2040  						if (s == NULL) {
2041  							p_error =
2042  							parse_internal_error;
2043  							free_mapping_item(
2044  							subelement->
2045  							element.item.exItem);
2046  							subelement->
2047  							element.item.exItem =
2048  								NULL;
2049  							break;
2050  						}
2051  					}
2052  				}
2053  				return (s);
2054  			} else if (t != comma_token) {
2055  				p_error = parse_comma_expected_error;
2056  				break;
2057  			}
2058  
2059  			begin_token = s;
2060  			end_token = end_s;
2061  			s = get_next_token(&begin_token, &end_token, &t);
2062  			if (s == NULL || t != quoted_string_token) {
2063  				p_error = parse_format_string_expected_error;
2064  				break;
2065  			}
2066  			if (end_token == begin_token + 1 ||
2067  			    (*begin_token == ESCAPE_CHAR &&
2068  			    end_token == begin_token + 2)) {
2069  					/* me_split */
2070  				delim = (unsigned char)end_token[-1];
2071  				s = skip_token(s, end_s, close_paren_token);
2072  				if (s == NULL)
2073  					break;
2074  				subelement->element.split.item = item;
2075  				subelement->element.split.delim = delim;
2076  				subelement->type = me_split;
2077  				return (s);
2078  			}
2079  			e_type = me_extract;
2080  		}
2081  		fmt_string = s_strndup(begin_token, end_token - begin_token);
2082  		if (fmt_string == NULL)
2083  			break;
2084  		if (!get_mapping_format(fmt_string, &base, &n, &numItems,
2085  		    e_type == me_print)) {
2086  			free(fmt_string);
2087  			break;
2088  		}
2089  		free(fmt_string);
2090  
2091  		if (numItems != 1 && e_type == me_extract) {
2092  			p_error = numItems == 0 ?
2093  				parse_not_enough_extract_items :
2094  				parse_too_many_extract_items;
2095  			break;
2096  		} else if (numItems > 0 && e_type == me_print) {
2097  			print_item = (__nis_mapping_item_t *)s_calloc(numItems,
2098  				sizeof (__nis_mapping_item_t));
2099  			if (print_item == NULL)
2100  				break;
2101  		}
2102  
2103  		if (e_type == me_print) {
2104  			sub.element.print.numItems = numItems;
2105  			sub.element.print.fmt = base;
2106  			sub.element.print.item = print_item;
2107  			s = get_print_sub_element(s, end_s, type, &sub);
2108  			if (s == NULL)
2109  				break;
2110  		}
2111  		s = skip_token(s, end_s, close_paren_token);
2112  		if (s == NULL)
2113  			break;
2114  
2115  		subelement->type = e_type;
2116  		if (e_type == me_extract) {
2117  			subelement->element.extract.fmt = base;
2118  			subelement->element.extract.item = item;
2119  		} else {
2120  			subelement->type = me_print;
2121  			subelement->element.print.fmt = base;
2122  			subelement->element.print.numItems = numItems;
2123  			subelement->element.print.item = print_item;
2124  			subelement->element.print.doElide =
2125  				sub.element.print.doElide;
2126  			subelement->element.print.elide =
2127  				sub.element.print.elide;
2128  		}
2129  		if (p_error == no_parse_error)
2130  			return (s);
2131  	}
2132  	free_mapping_item(&item);
2133  	if (base != NULL)
2134  		free_mapping_format(base);
2135  	if (print_item) {
2136  		for (n = 0; n < numItems; n++)
2137  			free_mapping_item(&print_item[n]);
2138  		free(print_item);
2139  	}
2140  
2141  	return (NULL);
2142  }
2143  
2144  /*
2145   * FUNCTION:	skip_get_dn
2146   *
2147   *	Get first token after dn
2148   *
2149   * RETURN VALUE:	NULL if error (not valid dn)
2150   *			position of beginning next token after dn
2151   *
2152   * INPUT:		the attribute value
2153   */
2154  
2155  const char *
2156  skip_get_dn(const char *dn, const char *end)
2157  {
2158  	size_t		len		= 0;
2159  	bool_t		in_quote	= FALSE;
2160  	bool_t		goteq		= FALSE;
2161  	bool_t		gotch		= FALSE;
2162  	bool_t		done		= FALSE;
2163  	bool_t		last_comma	= FALSE;
2164  	const char	*last_dn	= dn;
2165  
2166  	while (!done) {
2167  		dn += len;
2168  		if (last_comma) {
2169  			last_dn = dn;
2170  			last_comma = FALSE;
2171  		}
2172  		if (dn >= end)
2173  			break;
2174  		len = 1;
2175  		switch (*dn) {
2176  			case ESCAPE_CHAR:
2177  				len = 2;
2178  				gotch = TRUE;
2179  				break;
2180  			case DOUBLE_QUOTE_CHAR:
2181  				in_quote = !in_quote;
2182  				break;
2183  			case QUESTION_MARK:
2184  			case CLOSE_PAREN_CHAR:
2185  			case COLON_CHAR:
2186  				done = !in_quote;
2187  				/* FALLTHRU */
2188  			case SEMI_COLON_CHAR:
2189  			case PLUS_SIGN:
2190  			case COMMA_CHAR:
2191  				if (!in_quote) {
2192  					if (!goteq || !gotch)
2193  						return (last_dn);
2194  					goteq = FALSE;
2195  					gotch = FALSE;
2196  					if (*dn != PLUS_SIGN)
2197  						last_dn = dn;
2198  					last_comma = *dn == COMMA_CHAR;
2199  				} else {
2200  					gotch = TRUE;
2201  				}
2202  				break;
2203  			case EQUAL_CHAR:
2204  				if (!in_quote) {
2205  					if (!gotch || goteq)
2206  						return (NULL);
2207  					goteq = TRUE;
2208  					gotch = FALSE;
2209  				} else {
2210  					gotch = TRUE;
2211  				}
2212  				break;
2213  			default:
2214  				if (!is_whitespace(*dn))
2215  					gotch = TRUE;
2216  				break;
2217  		}
2218  	}
2219  
2220  	if (dn == end) {
2221  		if (!in_quote && goteq && gotch)
2222  			last_dn = dn;
2223  	}
2224  
2225  	return (last_dn);
2226  }
2227  
2228  /*
2229   * FUNCTION:	get_ldap_filter_element
2230   *
2231   *	Get an ldap filter element for a given string
2232   *
2233   * RETURN VALUE:	NULL if error
2234   *			__nis_mapping_element_t if success
2235   *
2236   * INPUT:		the string to parse
2237   */
2238  
2239  static __nis_mapping_element_t *
2240  get_ldap_filter_element(
2241  	const char			*s,
2242  	const char			*end_s
2243  )
2244  {
2245  	token_type			t;
2246  	const char			*begin_token;
2247  	const char			*end_token;
2248  	char				*format_str;
2249  	__nis_mapping_element_t		*e		= NULL;
2250  
2251  	begin_token = s;
2252  	end_token = end_s;
2253  	s = get_next_token(&begin_token, &end_token, &t);
2254  	if (s == NULL || t != open_paren_token)
2255  		return (NULL);
2256  
2257  	begin_token = s;
2258  	end_token = end_s;
2259  	s = get_next_token(&begin_token, &end_token, &t);
2260  	if (s == NULL || t != quoted_string_token)
2261  		return (NULL);
2262  
2263  	format_str = s_strndup(begin_token, end_token - begin_token);
2264  	if (format_str == NULL)
2265  		return (NULL);
2266  	e = (__nis_mapping_element_t *)
2267  		s_calloc(1, sizeof (__nis_mapping_element_t));
2268  	if (e != NULL) {
2269  		(void) get_print_mapping_element(s, end_s,
2270  				format_str, e, mit_nisplus);
2271  		if (p_error != no_parse_error) {
2272  			free_mapping_element(e);
2273  			e = NULL;
2274  		}
2275  	}
2276  	free(format_str);
2277  	return (e);
2278  }
2279  
2280  /*
2281   * FUNCTION:	get_search_triple
2282   *
2283   *	Get the search triple or if NULL determine if valid
2284   *
2285   * RETURN VALUE:	NULL if error
2286   *			position of beginning next token after
2287   *			search triple
2288   *
2289   * INPUT:		the attribute value
2290   */
2291  
2292  const char *
2293  get_search_triple(
2294  	const char			*s,
2295  	const char			*end_s,
2296  	__nis_search_triple_t		*triple
2297  )
2298  {
2299  	const char	*begin_token;
2300  	const char	*end_token;
2301  	char		*search_base	= NULL;
2302  	int		scope		= LDAP_SCOPE_ONELEVEL;
2303  	char		*filter		= NULL;
2304  	const char	*s1;
2305  	__nis_mapping_element_t
2306  			*element	= NULL;
2307  
2308  	/*
2309  	 * The form of the searchTriple is assumed to be as follows:
2310  	 * searchTriple	= [baseDN] ["?" [scope] ["?" [filter]]]
2311  	 * baseDN = Base DN for search
2312  	 * scope = "base" | "one" | "sub"
2313  	 * filter = LDAP search filter
2314  	 */
2315  	for (; p_error == no_parse_error; ) {
2316  		while (s < end_s && is_whitespace(*s))
2317  			s++;
2318  		if (s == end_s)
2319  			break;
2320  
2321  		if (!IS_TERMINAL_CHAR(*s)) {
2322  			begin_token = s;
2323  			s = skip_get_dn(begin_token, end_s);
2324  			if (s == NULL) {
2325  				p_error = parse_invalid_dn;
2326  				break;
2327  			}
2328  			if (triple != NULL) {
2329  				search_base = s_strndup(begin_token,
2330  					s - begin_token);
2331  				if (search_base == NULL)
2332  					break;
2333  			}
2334  			while (s < end_s && is_whitespace(*s))
2335  				s++;
2336  			if (s == end_s)
2337  				break;
2338  		}
2339  
2340  		if (!IS_TERMINAL_CHAR(*s)) {
2341  			p_error = parse_bad_ldap_item_format;
2342  			break;
2343  		}
2344  		if (*s != QUESTION_MARK)
2345  			break;
2346  
2347  		s++;
2348  		while (s < end_s && is_whitespace(*s))
2349  			s++;
2350  		if (s == end_s)
2351  			break;
2352  
2353  		/* base, one, or sub, or empty value */
2354  		if (!IS_TERMINAL_CHAR(*s)) {
2355  			if ((s1 = skip_string("base", s, end_s - s)) != NULL) {
2356  				scope = LDAP_SCOPE_BASE;
2357  			} else if ((s1 = skip_string("one", s, end_s - s)) !=
2358  					NULL) {
2359  				scope = LDAP_SCOPE_ONELEVEL;
2360  			} else if ((s1 = skip_string("sub", s, end_s - s)) !=
2361  					NULL) {
2362  				scope = LDAP_SCOPE_SUBTREE;
2363  			} else if (s + 1 < end_s && *s != QUESTION_MARK) {
2364  				p_error = parse_invalid_scope;
2365  				break;
2366  			}
2367  			if (s1 != NULL)
2368  				s = s1;
2369  			while (s < end_s && is_whitespace(*s))
2370  				s++;
2371  		}
2372  
2373  		if (s == end_s)
2374  			break;
2375  		if (*s != QUESTION_MARK)
2376  			break;
2377  		s++;
2378  		while (s < end_s && is_whitespace(*s))
2379  			s++;
2380  		if (s == end_s || IS_TERMINAL_CHAR(*s))
2381  			break;
2382  
2383  		/* LDAP search filter */
2384  		if (*s == OPEN_PAREN_CHAR) {
2385  		    begin_token = s;
2386  		    end_token = end_s;
2387  		    s = get_ldap_filter(&begin_token, &end_token);
2388  		    if (s == NULL)
2389  			break;
2390  		    s = end_token;
2391  		    element = get_ldap_filter_element(begin_token, end_token);
2392  		    if (element != NULL)
2393  			break;
2394  		} else {
2395  		    begin_token = s;
2396  		    end_token = end_s;
2397  		    s = get_ava_list(&begin_token, &end_token, TRUE);
2398  		    if (s == NULL)
2399  			break;
2400  		    s = end_token;
2401  		}
2402  		if (triple != NULL)
2403  			filter = s_strndup(begin_token, s - begin_token);
2404  		if (p_error == no_parse_error)
2405  			break;
2406  	}
2407  	if (p_error == no_parse_error && triple != NULL) {
2408  		triple->base = search_base;
2409  		triple->scope = scope;
2410  		triple->attrs = filter;
2411  		triple->element = element;
2412  		element = NULL;
2413  		filter = NULL;
2414  		search_base = NULL;
2415  	}
2416  
2417  	if (search_base != NULL)
2418  		free(search_base);
2419  	if (filter != NULL)
2420  		free(filter);
2421  	if (element != NULL) {
2422  		free_mapping_element(element);
2423  		free(element);
2424  	}
2425  	return (p_error == no_parse_error ? s : NULL);
2426  }
2427  
2428  /*
2429   * FUNCTION:	get_mapping_format
2430   *
2431   *	Get the __nis_mapping_format_t from the string
2432   *
2433   * RETURN VALUE:	FALSE if error
2434   *			TRUE if __nis_mapping_format_t returned
2435   *
2436   * INPUT:		the format string
2437   */
2438  
2439  static bool_t
2440  get_mapping_format(
2441  	const char		*fmt_string,
2442  	__nis_mapping_format_t	**fmt,
2443  	int			*nfmt,
2444  	int			*numItems,
2445  	bool_t			print_mapping)
2446  {
2447  	const char		*f	= fmt_string;
2448  	const char		*ef;
2449  	__nis_mapping_format_t	*b;
2450  	__nis_mapping_format_t	*base	= NULL;
2451  	int			n	= 0;
2452  	int			nItems	= 0;
2453  
2454  	f = fmt_string;
2455  	ef = f + strlen(f);
2456  	base = (__nis_mapping_format_t *)
2457  	    s_calloc(1, sizeof (__nis_mapping_format_t));
2458  
2459  	if (base == NULL)
2460  		return (FALSE);
2461  	base->type = mmt_begin;
2462  	n++;
2463  
2464  	for (;;) {
2465  		b = (__nis_mapping_format_t *)s_realloc(
2466  		    base, (n + 1) * sizeof (__nis_mapping_format_t));
2467  
2468  		if (b == NULL)
2469  			break;
2470  		base = b;
2471  		base[n].type = mmt_end;
2472  		if (f == ef) {
2473  			if (nfmt)
2474  				*nfmt = n + 1;
2475  			*fmt = base;
2476  			if (numItems)
2477  				*numItems = nItems;
2478  			return (TRUE);
2479  		}
2480  		if (print_mapping)
2481  		    f = get_next_print_format_item(f, ef, &base[n]);
2482  		else
2483  		    f = get_next_extract_format_item(f, ef, &base[n]);
2484  
2485  
2486  		if (f == NULL)
2487  			break;
2488  		if (base[n].type == mmt_item ||
2489  			base[n].type == mmt_berstring)
2490  			nItems++;
2491  		n++;
2492  	}
2493  	if (base != NULL)
2494  		free_mapping_format(base);
2495  	return (FALSE);
2496  }
2497  
2498  /*
2499   * FUNCTION:	getIndex
2500   *
2501   *	Returns a string containing the index
2502   *
2503   * RETURN VALUE:	NULL if error
2504   *			a string containing the index
2505   *
2506   * INPUT:		attribute containing the index
2507   */
2508  
2509  static char *
2510  getIndex(const char **s_cur, const char *s_end)
2511  {
2512  	const char	*s		= *s_cur + 1;
2513  	const char	*s1;
2514  	char		*s_index;
2515  	char		*s_index1;
2516  	char		*s_index_end;
2517  	int		n_brackets	= 1;
2518  	bool_t		in_quotes	= FALSE;
2519  	char		*index		= NULL;
2520  
2521  	while (s < s_end && is_whitespace(*s))
2522  		s++;
2523  	for (s1 = s; s1 < s_end; s1++) {
2524  		if (*s1 == ESCAPE_CHAR)
2525  			s1++;
2526  		else if (*s1 == DOUBLE_QUOTE_CHAR) {
2527  			in_quotes = !in_quotes;
2528  		} else if (in_quotes)
2529  			;
2530  		else if (*s1 == CLOSE_BRACKET) {
2531  			if (--n_brackets == 0)
2532  				break;
2533  		} else if (*s1 == OPEN_BRACKET)
2534  			n_brackets++;
2535  	}
2536  
2537  	if (n_brackets == 0) {
2538  		index = s_strndup(s, s1 - s);
2539  		if (index != NULL) {
2540  			s_index_end = index + (s1 - s);
2541  			s_index1 = index;
2542  			for (s_index = index; s_index < s_index_end;
2543  			    s_index++) {
2544  				if (*s_index == ESCAPE_CHAR) {
2545  					*s_index1++ = *s_index++;
2546  				} else if (*s_index == DOUBLE_QUOTE_CHAR) {
2547  					in_quotes = !in_quotes;
2548  				} else if (!in_quotes &&
2549  				    is_whitespace(*s_index)) {
2550  					continue;
2551  				}
2552  				*s_index1++ = *s_index;
2553  			}
2554  			*s_index1 = *s_index;
2555  
2556  			s = s1 + 1;
2557  
2558  			while (s < s_end && is_whitespace(*s))
2559  				s++;
2560  			*s_cur = s;
2561  		}
2562  	} else
2563  		p_error = parse_mismatched_brackets;
2564  
2565  	return (index);
2566  }
2567  
2568  /*
2569   * FUNCTION:	parse_index
2570   *
2571   *	Parse attribute string to get __nis_index_t
2572   *
2573   * RETURN VALUE:	FALSE if error
2574   *			TRUE if __nis_index_t returned
2575   *
2576   * INPUT:		the attribute value to parse
2577   */
2578  
2579  bool_t
2580  parse_index(const char *s, const char *end_s, __nis_index_t *index)
2581  {
2582  	const char		*begin_token;
2583  	const char		*end_token;
2584  	char			*name_str	= NULL;
2585  	char			**name;
2586  	char			*fmt_string	= NULL;
2587  	__nis_mapping_format_t	*v		= NULL;
2588  	__nis_mapping_format_t	**value;
2589  	token_type		t;
2590  	int			n		 = 0;
2591  
2592  	if (index != NULL)
2593  		(void) memset(index, 0, sizeof (*index));
2594  
2595  	while (s < end_s) {
2596  		if (n > 0) {
2597  			s = skip_token(s, end_s, comma_token);
2598  			if (s == NULL) {
2599  				p_error = parse_bad_index_format;
2600  				break;
2601  			}
2602  		}
2603  		begin_token = s;
2604  		end_token = end_s;
2605  		s = get_next_token(&begin_token, &end_token, &t);
2606  		if (s == NULL)
2607  			break;
2608  		if (t != string_token) {
2609  			p_error = parse_bad_index_format;
2610  			break;
2611  		}
2612  		s = skip_token(s, end_s, equal_token);
2613  		if (s == NULL) {
2614  			p_error = parse_bad_index_format;
2615  			break;
2616  		}
2617  		if (index != NULL) {
2618  			name_str = s_strndup_esc(begin_token,
2619  				end_token - begin_token);
2620  			if (name_str == NULL)
2621  				break;
2622  		}
2623  		begin_token = s;
2624  		end_token = end_s;
2625  		s = get_next_token(&begin_token, &end_token, &t);
2626  		if (s == NULL)
2627  			break;
2628  		if (t != string_token && t != quoted_string_token) {
2629  			p_error = parse_bad_index_format;
2630  			break;
2631  		}
2632  		fmt_string = s_strndup(begin_token, end_token - begin_token);
2633  		if (fmt_string == NULL)
2634  			break;
2635  		if (!get_mapping_format(fmt_string, &v, NULL, NULL, FALSE))
2636  			break;
2637  		free(fmt_string);
2638  		fmt_string = NULL;
2639  		if (index != NULL) {
2640  			name = s_realloc(index->name,
2641  				(n + 1) * sizeof (char *));
2642  			if (name == NULL)
2643  				break;
2644  			value = s_realloc(index->value,
2645  				(n + 1) * sizeof (__nis_mapping_format_t *));
2646  			if (value == NULL)
2647  				break;
2648  			name[n] = name_str;
2649  			name_str = NULL;
2650  			value[n] = v;
2651  			v = NULL;
2652  			index->numIndexes = ++n;
2653  			index->name = name;
2654  			index->value = value;
2655  		} else if (v != NULL) {
2656  			free_mapping_format(v);
2657  			v = NULL;
2658  		}
2659  	}
2660  	if (p_error != no_parse_error) {
2661  		if (name_str != NULL)
2662  			free(name_str);
2663  		if (v != NULL)
2664  			free_mapping_format(v);
2665  		if (fmt_string != NULL)
2666  			free(fmt_string);
2667  		if (index != NULL)
2668  			free_index(index);
2669  	}
2670  	return (p_error != no_parse_error);
2671  }
2672  
2673  /*
2674   * FUNCTION:	get_deleteDisp
2675   *
2676   *	Parse deleteDisp. Sets p_error if an error occurred.
2677   *
2678   * RETURN VALUE:	TRUE on success
2679   *			FAILURE on failure
2680   *
2681   * INPUT:		begin and end of string and __nis_object_dn_t
2682   */
2683  
2684  static bool_t
2685  get_deleteDisp(const char *s_begin, const char *s_end,
2686  		__nis_object_dn_t *obj_dn)
2687  {
2688  	/*
2689  	 * deleteDisp: "always" | perDbId | "never"
2690  	 * perDbId: "dbid" "=" delDatabaseId
2691  	 */
2692  
2693  	if (same_string("always", s_begin, s_end - s_begin)) {
2694  		obj_dn->delDisp = dd_always;
2695  	} else if (same_string("never", s_begin, s_end - s_begin)) {
2696  		obj_dn->delDisp = dd_never;
2697  	} else if ((s_begin = skip_string("dbid", s_begin, s_end - s_begin))
2698  			!= NULL) {
2699  		obj_dn->delDisp = dd_perDbId;
2700  		while (s_begin < s_end && is_whitespace(*s_begin))
2701  			s_begin++;
2702  		if (s_begin == s_end || *s_begin != EQUAL_CHAR) {
2703  			p_error = parse_object_dn_syntax_error;
2704  		} else {
2705  			s_begin++;
2706  			while (s_begin < s_end && is_whitespace(*s_begin))
2707  				s_begin++;
2708  			while (s_begin < s_end && is_whitespace(s_end[-1]))
2709  				s_end--;
2710  			if (s_begin == s_end) {
2711  				p_error = parse_object_dn_syntax_error;
2712  			} else {
2713  				obj_dn->dbIdName =
2714  					s_strndup(s_begin, s_end - s_begin);
2715  			}
2716  		}
2717  	} else {
2718  		p_error = parse_object_dn_syntax_error;
2719  	}
2720  	return (p_error == no_parse_error);
2721  }
2722