xref: /illumos-gate/usr/src/lib/libnisdb/nis_parse_ldap_util.c (revision 8459c777fc1aaabb2f7dad05de1313aa169417cd)
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 2004 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 <errno.h>
35 #include <locale.h>
36 #include <lber.h>
37 #include <ldap.h>
38 #include <syslog.h>
39 #include <dlfcn.h>	/* for dynamic loading only */
40 
41 #include "ldap_parse.h"
42 #include "nis_parse_ldap_conf.h"
43 #include "nis_parse_ldap_err.h"
44 #include "ldap_util.h"
45 #include "ldap_util.h"
46 
47 void append_dot(char **str);
48 void	append_comma(char **str);
49 bool_t make_full_dn(char **dn, const char *base);
50 bool_t make_fqdn(__nis_object_dn_t *dn, const char *base);
51 char *get_default_ldap_base(const char *domain);
52 bool_t add_domain(char **objName, const char *domain);
53 bool_t add_column(__nis_table_mapping_t *t, const char *col_name);
54 __nis_mapping_rule_t **dup_mapping_rules(
55 	__nis_mapping_rule_t **rules, int n_rules);
56 __nis_mapping_rule_t *dup_mapping_rule(
57 	__nis_mapping_rule_t *in);
58 void *s_malloc(size_t size);
59 __nis_mapping_format_t *dup_format_mapping(
60 	__nis_mapping_format_t *in);
61 bool_t dup_mapping_element(__nis_mapping_element_t *in,
62 	__nis_mapping_element_t *out);
63 bool_t is_string_ok(char *, int);
64 
65 extern FILE *cons;
66 
67 /*
68  * FUNCTION:	free_parse_structs
69  *
70  *	Release the resources in parse results
71  *
72  */
73 
74 void
75 free_parse_structs()
76 {
77 	__nis_table_mapping_t	*t;
78 	__nis_table_mapping_t	*t1;
79 
80 	free_proxy_info(&proxyInfo);
81 	for (t = ldapTableMapping; t != NULL; t = t1) {
82 		t1 = t->next;
83 		free_table_mapping(t);
84 	}
85 	ldapTableMapping = NULL;
86 }
87 
88 /*
89  * FUNCTION:	initialize_parse_structs
90  *
91  *	Initialize fields to unset values
92  *
93  * INPUT:		__nis_ldap_proxy_info, __nis_config_t
94  * 			and __nisdb_table_mapping_t structures
95  */
96 
97 void
98 initialize_parse_structs(
99 	__nis_ldap_proxy_info	*proxy_info,
100 	__nis_config_t		*config_info,
101 	__nisdb_table_mapping_t	*table_info)
102 {
103 	proxy_info->default_servers = NULL;
104 	proxy_info->auth_method = (auth_method_t)NO_VALUE_SET;
105 	proxy_info->tls_method = (tls_method_t)NO_VALUE_SET;
106 	proxy_info->tls_cert_db = NULL;
107 	proxy_info->default_search_base = NULL;
108 	proxy_info->proxy_dn = NULL;
109 	proxy_info->proxy_passwd = NULL;
110 	proxy_info->default_nis_domain = NULL;
111 	proxy_info->bind_timeout.tv_sec = (time_t)NO_VALUE_SET;
112 	proxy_info->bind_timeout.tv_usec = 0;
113 	proxy_info->search_timeout.tv_sec = (time_t)NO_VALUE_SET;
114 	proxy_info->search_timeout.tv_usec = 0;
115 	proxy_info->modify_timeout.tv_sec = (time_t)NO_VALUE_SET;
116 	proxy_info->modify_timeout.tv_usec = 0;
117 	proxy_info->add_timeout.tv_sec = (time_t)NO_VALUE_SET;
118 	proxy_info->add_timeout.tv_usec = 0;
119 	proxy_info->delete_timeout.tv_sec = (time_t)NO_VALUE_SET;
120 	proxy_info->delete_timeout.tv_usec = 0;
121 	proxy_info->search_time_limit = (int)NO_VALUE_SET;
122 	proxy_info->search_size_limit = (int)NO_VALUE_SET;
123 	proxy_info->follow_referral = (follow_referral_t)NO_VALUE_SET;
124 
125 
126 	config_info->initialUpdate = (__nis_initial_update_t)NO_VALUE_SET;
127 	config_info->threadCreationError =
128 		(__nis_thread_creation_error_t)NO_VALUE_SET;
129 	config_info->threadCreationErrorTimeout.attempts = NO_VALUE_SET;
130 	config_info->threadCreationErrorTimeout.timeout = (time_t)NO_VALUE_SET;
131 	config_info->dumpError = (__nis_dump_error_t)NO_VALUE_SET;
132 	config_info->dumpErrorTimeout.attempts = NO_VALUE_SET;
133 	config_info->dumpErrorTimeout.timeout = (time_t)NO_VALUE_SET;
134 	config_info->resyncService = (__nis_resync_service_t)NO_VALUE_SET;
135 	config_info->updateBatching = (__nis_update_batching_t)NO_VALUE_SET;
136 	config_info->updateBatchingTimeout.timeout = (time_t)NO_VALUE_SET;
137 	config_info->numberOfServiceThreads = (int)NO_VALUE_SET;
138 	config_info->emulate_yp = (int)NO_VALUE_SET;
139 	config_info->maxRPCRecordSize = (int)NO_VALUE_SET;
140 
141 	table_info->retrieveError = (__nis_retrieve_error_t)NO_VALUE_SET;
142 	table_info->retrieveErrorRetry.attempts = NO_VALUE_SET;
143 	table_info->retrieveErrorRetry.timeout = (time_t)NO_VALUE_SET;
144 	table_info->storeError = (__nis_store_error_t)NO_VALUE_SET;
145 	table_info->storeErrorRetry.attempts = NO_VALUE_SET;
146 	table_info->storeErrorRetry.timeout = (time_t)NO_VALUE_SET;
147 	table_info->refreshError = (__nis_refresh_error_t)NO_VALUE_SET;
148 	table_info->refreshErrorRetry.attempts = NO_VALUE_SET;
149 	table_info->refreshErrorRetry.timeout = (time_t)NO_VALUE_SET;
150 	table_info->matchFetch = (__nis_match_fetch_t)NO_VALUE_SET;
151 }
152 
153 /*
154  * FUNCTION:	free_mapping_rule
155  *
156  *	Frees __nis_mapping_rule_t
157  *
158  * INPUT:		__nis_mapping_rule_t
159  */
160 
161 void
162 free_mapping_rule(__nis_mapping_rule_t	*rule)
163 {
164 	int			i;
165 	__nis_mapping_rlhs_t	*r;
166 
167 	if (rule != NULL) {
168 		r = &rule->lhs;
169 		for (i = 0; i < r->numElements; i++)
170 			free_mapping_element(&r->element[i]);
171 		if (r->element != NULL)
172 			free(r->element);
173 
174 		r = &rule->rhs;
175 		for (i = 0; i < r->numElements; i++)
176 			free_mapping_element(&r->element[i]);
177 		if (r->element != NULL)
178 			free(r->element);
179 
180 		free(rule);
181 	}
182 }
183 
184 /*
185  * FUNCTION:	free_mapping_element
186  *
187  *	Frees __nis_mapping_element_t
188  *
189  * INPUT:		__nis_mapping_element_t
190  */
191 
192 void
193 free_mapping_element(__nis_mapping_element_t *e)
194 {
195 	int	i;
196 
197 	if (e == NULL)
198 		return;
199 
200 	switch (e->type) {
201 	    case me_item:
202 		free_mapping_item(&e->element.item);
203 		break;
204 	    case me_print:
205 		if (e->element.print.fmt != NULL)
206 			free_mapping_format(e->element.print.fmt);
207 		e->element.print.fmt = NULL;
208 		for (i = 0; i < e->element.print.numSubElements; i++)
209 			free_mapping_sub_element(
210 				&e->element.print.subElement[i]);
211 		e->element.print.numSubElements = 0;
212 		if (e->element.print.subElement != NULL)
213 			free(e->element.print.subElement);
214 		e->element.print.subElement = NULL;
215 		break;
216 	    case me_split:
217 		free_mapping_item(&e->element.split.item);
218 		break;
219 	    case me_match:
220 		if (e->element.match.fmt != NULL)
221 			free_mapping_format(e->element.match.fmt);
222 		e->element.match.fmt = NULL;
223 		for (i = 0; i < e->element.match.numItems; i++)
224 			free_mapping_item(&e->element.match.item[i]);
225 		e->element.match.numItems = 0;
226 		if (e->element.match.item != NULL)
227 		    free(e->element.match.item);
228 		e->element.match.item = NULL;
229 		break;
230 	    case me_extract:
231 		if (e->element.extract.fmt != NULL)
232 			free_mapping_format(e->element.extract.fmt);
233 		e->element.extract.fmt = NULL;
234 		free_mapping_item(&e->element.extract.item);
235 		break;
236 	}
237 	e = NULL;
238 }
239 
240 /*
241  * FUNCTION:	free_table_mapping
242  *
243  *	Frees __nis_table_mapping_t
244  *
245  * INPUT:		__nis_table_mapping_t
246  */
247 
248 /*
249  * free_table_mapping does not remove the table mapping from
250  * its hashed list
251  */
252 
253 void
254 free_table_mapping(__nis_table_mapping_t *mapping)
255 {
256 	int	i;
257 
258 	if (mapping == NULL)
259 		return;
260 
261 	if (mapping->dbId != NULL)
262 		free(mapping->dbId);
263 	mapping->dbId = NULL;
264 
265 	if (mapping->objName != NULL)
266 		free(mapping->objName);
267 	mapping->objName = NULL;
268 
269 	for (i = 0; i < mapping->index.numIndexes; i++) {
270 		free(mapping->index.name[i]);
271 		free_mapping_format(mapping->index.value[i]);
272 	}
273 
274 	if (mapping->index.name != NULL)
275 		free(mapping->index.name);
276 	mapping->index.name = NULL;
277 
278 	if (mapping->index.value != NULL)
279 		free(mapping->index.value);
280 	mapping->index.value = NULL;
281 
282 	mapping->index.numIndexes = 0;
283 
284 	if (mapping->column != NULL) {
285 		for (i = 0; i < mapping->numColumns; i++) {
286 			free(mapping->column[i]);
287 		}
288 		mapping->numColumns = 0;
289 		free(mapping->column);
290 		mapping->column = NULL;
291 	}
292 
293 	if (mapping->commentChar != 0)
294 		mapping->commentChar = 0;
295 
296 	if (mapping->objectDN != NULL)
297 		free_object_dn(mapping->objectDN);
298 	mapping->objectDN = NULL;
299 
300 	if (mapping->separatorStr != NULL)
301 		mapping->separatorStr = NULL;
302 
303 	for (i = 0; i < mapping->numRulesFromLDAP; i++) {
304 		if (mapping->ruleFromLDAP[i]) /* See Comment below */
305 			free_mapping_rule(mapping->ruleFromLDAP[i]);
306 	}
307 	mapping->numRulesFromLDAP = 0;
308 
309 	if (mapping->ruleFromLDAP != NULL)
310 		free(mapping->ruleFromLDAP);
311 	mapping->ruleFromLDAP = NULL;
312 
313 	for (i = 0; i < mapping->numRulesToLDAP; i++) {
314 		if (mapping->ruleToLDAP[i])
315 		/*
316 		 * Normally mapping->ruleToLDAP[i] should
317 		 * always be non-null if
318 		 * mapping->numRulesToLDAP is > 0.
319 		 * However it is possible to have data
320 		 * corruption where numRulesToLDAP gets
321 		 * some integer value even though no real
322 		 * data is present in mapping->ruleToLDAP.
323 		 */
324 			free_mapping_rule(mapping->ruleToLDAP[i]);
325 	}
326 	mapping->numRulesToLDAP = 0;
327 
328 	if (mapping->ruleToLDAP != NULL)
329 		free(mapping->ruleToLDAP);
330 	mapping->ruleToLDAP = NULL;
331 
332 	if (mapping->e != NULL) {
333 		/* Similar logic as in above comment applies. */
334 		for (i = 0; i <= mapping->numSplits; i++) {
335 			free_mapping_element(&mapping->e[i]);
336 		}
337 		free(mapping->e);
338 	}
339 	mapping->e = NULL;
340 
341 	mapping->numSplits = 0;
342 
343 	free(mapping);
344 }
345 
346 /*
347  * FUNCTION:	free_config_info
348  *
349  *	Frees __nis_config_info_t
350  *
351  * INPUT:		__nis_config_info_t
352  */
353 
354 void
355 free_config_info(__nis_config_info_t *config_info)
356 {
357 	if (config_info->config_dn != NULL)
358 		free(config_info->config_dn);
359 	config_info->config_dn = NULL;
360 
361 	if (config_info->default_servers != NULL)
362 		free(config_info->default_servers);
363 	config_info->default_servers = NULL;
364 
365 	if (config_info->proxy_dn != NULL)
366 		free(config_info->proxy_dn);
367 	config_info->proxy_dn = NULL;
368 
369 	if (config_info->proxy_passwd != NULL)
370 		free(config_info->proxy_passwd);
371 	config_info->proxy_passwd = NULL;
372 
373 	if (config_info->tls_cert_db != NULL)
374 		free(config_info->tls_cert_db);
375 	config_info->tls_cert_db = NULL;
376 }
377 
378 /*
379  * FUNCTION:	free_proxy_info
380  *
381  *	Frees __nis_ldap_proxy_info
382  *
383  * INPUT:		__nis_ldap_proxy_info
384  */
385 
386 void
387 free_proxy_info(__nis_ldap_proxy_info *proxy_info)
388 {
389 	if (proxy_info->tls_cert_db != NULL)
390 		free(proxy_info->tls_cert_db);
391 	proxy_info->tls_cert_db = NULL;
392 
393 	if (proxy_info->default_servers != NULL)
394 		free(proxy_info->default_servers);
395 	proxy_info->default_servers = NULL;
396 
397 	if (proxy_info->default_search_base != NULL)
398 		free(proxy_info->default_search_base);
399 	proxy_info->default_search_base = NULL;
400 
401 	if (proxy_info->proxy_dn != NULL)
402 		free(proxy_info->proxy_dn);
403 	proxy_info->proxy_dn = NULL;
404 
405 	if (proxy_info->proxy_passwd != NULL)
406 		free(proxy_info->proxy_passwd);
407 	proxy_info->proxy_passwd = NULL;
408 
409 	if (proxy_info->default_nis_domain != NULL)
410 		free(proxy_info->default_nis_domain);
411 	proxy_info->default_nis_domain = NULL;
412 }
413 
414 /*
415  * FUNCTION:	free_object_dn
416  *
417  *	Frees __nis_object_dn_t
418  *
419  * INPUT:		__nis_object_dn_t
420  */
421 
422 void
423 free_object_dn(__nis_object_dn_t *obj_dn)
424 {
425 	__nis_object_dn_t	*t;
426 	int			i;
427 
428 	while (obj_dn != NULL) {
429 		if (obj_dn->read.base != NULL)
430 			free(obj_dn->read.base);
431 		obj_dn->read.base = NULL;
432 		if (obj_dn->read.attrs != NULL)
433 			free(obj_dn->read.attrs);
434 		obj_dn->read.attrs = NULL;
435 		if (obj_dn->write.base != NULL)
436 			free(obj_dn->write.base);
437 		obj_dn->write.base = NULL;
438 		if (obj_dn->write.attrs != NULL)
439 			free(obj_dn->write.attrs);
440 		obj_dn->write.attrs = NULL;
441 		if (obj_dn->dbIdName != NULL)
442 			free(obj_dn->dbIdName);
443 		obj_dn->dbIdName = NULL;
444 		for (i = 0; i < obj_dn->numDbIds; i++)
445 			free_mapping_rule(obj_dn->dbId[i]);
446 		obj_dn->numDbIds = 0;
447 
448 		if (obj_dn->dbId != NULL)
449 			free(obj_dn->dbId);
450 		obj_dn->dbId = NULL;
451 
452 		t = obj_dn;
453 		obj_dn = obj_dn->next;
454 		free(t);
455 	}
456 }
457 
458 /*
459  * FUNCTION:	free_index
460  *
461  *	Frees __nis_index_t
462  *
463  * INPUT:		__nis_index_t
464  */
465 
466 void
467 free_index(__nis_index_t *index)
468 {
469 	int	i;
470 	for (i = 0; i < index->numIndexes; i++) {
471 		free(index->name[i]);
472 		free_mapping_format(index->value[i]);
473 	}
474 	index->numIndexes = 0;
475 	if (index->name != NULL)
476 		free(index->name);
477 	index->name = NULL;
478 	if (index->value != NULL)
479 		free(index->value);
480 	index->value = NULL;
481 }
482 
483 /*
484  * FUNCTION:	free_mapping_item
485  *
486  *	Frees __nis_mapping_item_t
487  *
488  * INPUT:		__nis_mapping_item_t
489  */
490 
491 void
492 free_mapping_item(__nis_mapping_item_t	*item)
493 {
494 	if (item == NULL)
495 		return;
496 
497 	if (item->name != NULL)
498 		free(item->name);
499 	item->name = NULL;
500 	if (item->type == mit_nisplus) {
501 		free_index(&item->searchSpec.obj.index);
502 		if (item->searchSpec.obj.name != NULL)
503 			free(item->searchSpec.obj.name);
504 		item->searchSpec.obj.name = NULL;
505 	} else if (item->type == mit_ldap) {
506 		if (item->searchSpec.triple.base != NULL)
507 			free(item->searchSpec.triple.base);
508 		item->searchSpec.triple.base = NULL;
509 		if (item->searchSpec.triple.attrs != NULL)
510 			free(item->searchSpec.triple.attrs);
511 		item->searchSpec.triple.attrs = NULL;
512 		if (item->searchSpec.triple.element != NULL) {
513 			free_mapping_element(
514 				item->searchSpec.triple.element);
515 			free(item->searchSpec.triple.element);
516 		}
517 		item->searchSpec.triple.element = NULL;
518 	}
519 	if (item->exItem != NULL) {
520 		free_mapping_item(item->exItem);
521 		free(item->exItem);
522 		item->exItem = 0;
523 	}
524 }
525 
526 /*
527  * FUNCTION:	free_mapping_format
528  *
529  *	Frees __nis_mapping_format_t
530  *
531  * INPUT:		__nis_mapping_format_t
532  */
533 
534 void
535 free_mapping_format(__nis_mapping_format_t *fmt)
536 {
537 	__nis_mapping_format_t *f = fmt;
538 
539 	while (fmt->type != mmt_end) {
540 		switch (fmt->type) {
541 		    case mmt_item:
542 			break;
543 		    case mmt_string:
544 			if (fmt->match.string != NULL)
545 				free(fmt->match.string);
546 			fmt->match.string = NULL;
547 			break;
548 		    case mmt_single:
549 			if (fmt->match.single.lo != NULL)
550 				free(fmt->match.single.lo);
551 			fmt->match.single.lo = NULL;
552 			if (fmt->match.single.hi != NULL)
553 				free(fmt->match.single.hi);
554 			fmt->match.single.hi = NULL;
555 			break;
556 		    case mmt_limit:
557 			break;
558 		    case mmt_any:
559 			break;
560 		    case mmt_berstring:
561 		    case mmt_berstring_null:
562 			if (fmt->match.berString != NULL)
563 				free(fmt->match.berString);
564 			fmt->match.berString = NULL;
565 			break;
566 		    case mmt_begin:
567 			break;
568 		    case mmt_end:
569 			break;
570 		}
571 		fmt++;
572 	}
573 	free(f);
574 }
575 
576 /*
577  * FUNCTION:	free_mapping_sub_element
578  *
579  *	Frees __nis_mapping_sub_element_t
580  *
581  * INPUT:		__nis_mapping_sub_element_t
582  */
583 
584 void
585 free_mapping_sub_element(__nis_mapping_sub_element_t *sub)
586 {
587 	int	i;
588 
589 	switch (sub->type) {
590 	    case me_item:
591 		free_mapping_item(&sub->element.item);
592 		break;
593 	    case me_print:
594 		if (sub->element.print.fmt != NULL)
595 			free_mapping_format(sub->element.print.fmt);
596 		sub->element.print.fmt = NULL;
597 		for (i = 0; i < sub->element.print.numItems; i++)
598 			free_mapping_item(&sub->element.print.item[i]);
599 		sub->element.print.numItems = 0;
600 		if (sub->element.print.item != NULL)
601 			free(sub->element.print.item);
602 		sub->element.print.item = NULL;
603 		break;
604 	    case me_split:
605 		free_mapping_item(&sub->element.split.item);
606 		break;
607 	    case me_extract:
608 		if (sub->element.extract.fmt != NULL)
609 			free_mapping_format(sub->element.extract.fmt);
610 		sub->element.extract.fmt = NULL;
611 		free_mapping_item(&sub->element.extract.item);
612 		break;
613 	}
614 }
615 
616 /*
617  * FUNCTION:	read_line
618  *
619  *	Gets next line in buffer - using '\' at end of line
620  *  to indicate continuation. Lines beginning with # are
621  *	ignored. start_line_num and start_line_num are
622  *	maintained to track the line number currently being
623  *	parsed.
624  *
625  * RETURN VALUE:	The number of characters read. 0 for
626  *                      eof, -1 for error
627  *
628  * INPUT:		file descriptor, buffer, and buffer size
629  */
630 
631 int
632 read_line(int fd, char *buffer, int buflen)
633 {
634 	int		linelen;
635 	int		rc;
636 	char		c;
637 	bool_t		skip_line	= FALSE;
638 	bool_t		begin_line	= TRUE;
639 	static bool_t	prev_cr		= FALSE;
640 
641 	start_line_num = cur_line_num;
642 	(void) memset(buffer, 0, buflen);
643 	for (; p_error == no_parse_error; ) {
644 		linelen = 0;
645 		while (linelen < buflen) {
646 			rc = read(fd, &c, 1);
647 			if (1 == rc) {
648 				if (c == '\n' || c == '\r') {
649 					if (c == '\n') {
650 						if (prev_cr) {
651 							prev_cr = FALSE;
652 							continue;
653 						} else {
654 							if (linelen == 0)
655 							    start_line_num =
656 								cur_line_num;
657 							else {
658 								if (
659 								is_string_ok(
660 								buffer,
661 								linelen)) {
662 								(void) memset(
663 								buffer, 0,
664 								linelen);
665 								linelen = 0;
666 								cur_line_num++;
667 								begin_line =
668 									TRUE;
669 								continue;
670 								}
671 							}
672 							cur_line_num++;
673 						}
674 						prev_cr = FALSE;
675 					} else {
676 						prev_cr = TRUE;
677 						if (linelen == 0)
678 						    start_line_num =
679 							cur_line_num;
680 						cur_line_num++;
681 					}
682 					if (skip_line) {
683 						skip_line = FALSE;
684 						if (linelen == 0)
685 						    start_line_num =
686 							cur_line_num;
687 					} else if (linelen > 0 &&
688 					    buffer[linelen - 1]
689 					    == ESCAPE_CHAR) {
690 						--linelen;
691 					} else if (linelen > 0) {
692 						buffer[linelen] = '\0';
693 						return (linelen);
694 					}
695 					begin_line = TRUE;
696 				} else {
697 					if (begin_line)
698 						skip_line = c == POUND_SIGN;
699 					begin_line = FALSE;
700 					if (!skip_line)
701 						buffer[linelen++] = c;
702 				}
703 			} else {
704 				if (linelen > 0 &&
705 				    buffer[linelen - 1] == ESCAPE_CHAR) {
706 					/* continuation on last line */
707 					p_error = parse_bad_continuation_error;
708 					return (-1);
709 				} else {
710 					buffer[linelen] = '\0';
711 					return (linelen);
712 				}
713 			}
714 		}
715 		p_error = parse_line_too_long;
716 	}
717 	return (-1);
718 }
719 
720 /*
721  * FUNCTION:	finish_parse
722  *
723  *	Adds any elements not configured, fully qualifies
724  *      names
725  *
726  * RETURN VALUE:	0 on success, -1 on failure
727  */
728 
729 int
730 finish_parse(
731 	__nis_ldap_proxy_info	*proxy_info,
732 	__nis_table_mapping_t	**table_mapping)
733 {
734 	__nis_table_mapping_t	*t;
735 	__nis_table_mapping_t	*t1;
736 	__nis_table_mapping_t	*t2;
737 	__nis_table_mapping_t	*t_del		= NULL;
738 	int			i;
739 	int			j;
740 	int			k;
741 	__nis_object_dn_t	*objectDN;
742 	__nis_mapping_rlhs_t	*lhs;
743 	__nis_mapping_element_t	*e;
744 	char			*s;
745 	int			errnum;
746 
747 	/* set to default those values yet set */
748 	if (proxy_info->auth_method ==
749 	    (auth_method_t)NO_VALUE_SET) {
750 		p_error = parse_no_proxy_auth_error;
751 		report_error(NULL, NULL);
752 		return (-1);
753 	}
754 
755 	if (proxy_info->default_servers == NULL) {
756 		p_error = parse_no_ldap_server_error;
757 		report_error(NULL, NULL);
758 		return (-1);
759 	}
760 
761 	if (proxy_info->tls_method == (tls_method_t)NO_VALUE_SET)
762 		proxy_info->tls_method = no_tls;
763 	else if (proxy_info->tls_method == ssl_tls &&
764 			(proxy_info->tls_cert_db == NULL ||
765 			*proxy_info->tls_cert_db == '\0')) {
766 		p_error = parse_no_cert_db;
767 		report_error(NULL, NULL);
768 		return (-1);
769 	}
770 
771 	if (proxy_info->default_nis_domain == NULL)
772 		proxy_info->default_nis_domain =
773 			s_strdup(__nis_rpc_domain());
774 	else if (*proxy_info->default_nis_domain == '\0') {
775 		free(proxy_info->default_nis_domain);
776 		proxy_info->default_nis_domain =
777 			s_strdup(__nis_rpc_domain());
778 	}
779 	if (proxy_info->default_nis_domain != NULL)
780 		append_dot(&proxy_info->default_nis_domain);
781 
782 	if (proxy_info->tls_method == ssl_tls) {
783 		if ((errnum = ldapssl_client_init(
784 				proxy_info->tls_cert_db, NULL)) < 0) {
785 			p_error = parse_ldapssl_client_init_error;
786 			report_error(ldapssl_err2string(errnum), NULL);
787 			return (-1);
788 		}
789 	}
790 
791 	if (proxy_info->default_search_base == NULL)
792 	    proxy_info->default_search_base =
793 		get_default_ldap_base(proxy_info->default_nis_domain);
794 
795 	/* convert a relative dn to a fullly qualified dn */
796 	(void) make_full_dn(&proxy_info->proxy_dn,
797 		proxy_info->default_search_base);
798 
799 	if (p_error != no_parse_error) {
800 		report_error(NULL, NULL);
801 		return (-1);
802 	}
803 
804 	/*
805 	 * Create a list of potential delete mappings
806 	 * those have NULL objectDNs, but badly also rules
807 	 * that are missing object dn's will be included.
808 	 * We will use the ttl field to determine if the
809 	 * delete rule is actually used
810 	 */
811 	t2 = NULL;
812 	for (t = *table_mapping; t != NULL; t = t1) {
813 		t1 = t->next;
814 		if (t->objectDN == NULL) {
815 			if (t2 == NULL)
816 				*table_mapping = t1;
817 			else
818 				t2->next = t1;
819 			t->next = t_del;
820 			t_del = t;
821 			t->ttl = 0;
822 		} else
823 			t2 = t;
824 	}
825 
826 	for (t = *table_mapping; t != NULL; t = t->next) {
827 	    objectDN = t->objectDN;
828 	    while (objectDN != NULL) {
829 		if (objectDN->dbIdName != NULL) {
830 			s = objectDN->dbIdName;
831 			t1 = find_table_mapping(s, strlen(s), t_del);
832 			if (t1 == NULL) {
833 				p_error = parse_no_db_del_mapping_rule;
834 				report_error2(objectDN->dbIdName, t->dbId);
835 				return (-1);
836 			} else if (t1->objName != NULL ||
837 			    t1->numRulesToLDAP == 0 ||
838 			    t1->numRulesFromLDAP != 0) {
839 				p_error = parse_invalid_db_del_mapping_rule;
840 				report_error(t1->dbId, NULL);
841 				return (-1);
842 			}
843 			objectDN->dbId =
844 				dup_mapping_rules(t1->ruleToLDAP,
845 					t1->numRulesToLDAP);
846 			if (objectDN->dbId == NULL) {
847 				break;
848 			}
849 			objectDN->numDbIds = t1->numRulesToLDAP;
850 			t1->ttl++;
851 		}
852 		objectDN = objectDN->next;
853 	    }
854 	}
855 
856 	for (t = t_del; t != NULL; t = t1) {
857 		t1 = t->next;
858 		if (t->ttl == 0) {
859 			p_error = parse_no_object_dn;
860 			report_error(t->dbId, NULL);
861 		}
862 		free_table_mapping(t);
863 	}
864 
865 	if (p_error != no_parse_error)
866 		return (-1);
867 
868 	/* set to default those table mapping values yet set */
869 	for (t = *table_mapping; t != NULL; t = t->next) {
870 		if (t->objName == 0) {
871 			p_error = parse_no_object_dn;
872 			report_error(t->dbId, NULL);
873 			return (-1);
874 		}
875 		if (!yp2ldap) {
876 			if (!add_domain(&t->objName,
877 					proxy_info->default_nis_domain)) {
878 				report_error(NULL, NULL);
879 				return (-1);
880 			}
881 		}
882 		if (t->initTtlHi == (time_t)NO_VALUE_SET)
883 			t->initTtlHi = DEFAULT_TTL_HIGH;
884 		if (t->initTtlLo == (time_t)NO_VALUE_SET)
885 			t->initTtlLo = DEFAULT_TTL_LOW;
886 		if (t->ttl == (time_t)NO_VALUE_SET)
887 			t->ttl = DEFAULT_TTL;
888 		objectDN = t->objectDN;
889 
890 		/* fixup relative dn's */
891 		while (objectDN != NULL) {
892 			if (!yp2ldap) {
893 				if (!make_full_dn(&objectDN->read.base,
894 					proxy_info->default_search_base))
895 						break;
896 			}
897 			if (objectDN->write.scope != LDAP_SCOPE_UNKNOWN) {
898 				if (objectDN->write.base != NULL &&
899 					!make_full_dn(&objectDN->write.base,
900 					proxy_info->default_search_base))
901 						break;
902 				if (objectDN->write.base == NULL) {
903 				    objectDN->write.base =
904 					s_strdup(objectDN->read.base);
905 				    if (objectDN->write.base == NULL)
906 					break;
907 				}
908 			}
909 			objectDN = objectDN->next;
910 		}
911 
912 		if (p_error != no_parse_error) {
913 			report_error(NULL, NULL);
914 			return (-1);
915 		}
916 
917 		/* Check for ruleToLDAP with no rhs */
918 		for (i = 0; i < t->numRulesToLDAP; i++) {
919 		    if (t->ruleToLDAP[i]->rhs.numElements == 0) {
920 			p_error = parse_unexpected_data_end_rule;
921 			report_error(t->dbId, NULL);
922 			return (-1);
923 		    }
924 		}
925 
926 		/* populate cols field */
927 		if (!yp2ldap) {
928 			for (i = 0; i < t->numRulesFromLDAP; i++) {
929 				lhs = &t->ruleFromLDAP[i]->lhs;
930 				for (j = 0; j < lhs->numElements; j++) {
931 					e = &lhs->element[j];
932 					switch (e->type) {
933 						case me_item:
934 						if (!add_column(t,
935 						e->element.item.name)) {
936 							report_error(
937 							NULL, NULL);
938 							return (-1);
939 						}
940 						break;
941 						case me_match:
942 						for (k = 0;
943 						k < e->element.match.numItems;
944 						k++)
945 							if (!add_column(t,
946 					e->element.match.item[k].name)) {
947 								report_error(
948 								NULL, NULL);
949 								return (-1);
950 							}
951 						break;
952 					}
953 				}
954 			}
955 		}
956 	}
957 	return (0);
958 }
959 
960 /*
961  * FUNCTION:	set_default_values
962  *
963  *	Sets unconfigured values to their default value
964  */
965 
966 void
967 set_default_values(__nis_ldap_proxy_info *proxy_info,
968     __nis_config_t *config_info, __nisdb_table_mapping_t *table_info)
969 {
970 	if (proxy_info->bind_timeout.tv_sec == (time_t)NO_VALUE_SET)
971 		proxy_info->bind_timeout.tv_sec = DEFAULT_BIND_TIMEOUT;
972 	if (proxy_info->search_timeout.tv_sec == (time_t)NO_VALUE_SET)
973 		proxy_info->search_timeout.tv_sec =
974 			(yp2ldap)?DEFAULT_YP_SEARCH_TIMEOUT:
975 				DEFAULT_SEARCH_TIMEOUT;
976 	if (proxy_info->modify_timeout.tv_sec == (time_t)NO_VALUE_SET)
977 		proxy_info->modify_timeout.tv_sec = DEFAULT_MODIFY_TIMEOUT;
978 	if (proxy_info->add_timeout.tv_sec == (time_t)NO_VALUE_SET)
979 		proxy_info->add_timeout.tv_sec = DEFAULT_ADD_TIMEOUT;
980 	if (proxy_info->delete_timeout.tv_sec == (time_t)NO_VALUE_SET)
981 		proxy_info->delete_timeout.tv_sec = DEFAULT_DELETE_TIMEOUT;
982 
983 	if (proxy_info->search_time_limit == (int)NO_VALUE_SET)
984 		proxy_info->search_time_limit = DEFAULT_SEARCH_TIME_LIMIT;
985 	if (proxy_info->search_size_limit == (int)NO_VALUE_SET)
986 		proxy_info->search_size_limit = DEFAULT_SEARCH_SIZE_LIMIT;
987 
988 	if (proxy_info->follow_referral == (follow_referral_t)NO_VALUE_SET)
989 		proxy_info->follow_referral = no_follow;
990 
991 	switch (config_info->initialUpdate) {
992 		case (__nis_initial_update_t)NO_VALUE_SET:
993 		case (__nis_initial_update_t)INITIAL_UPDATE_NO_ACTION:
994 		case (__nis_initial_update_t)NO_INITIAL_UPDATE_NO_ACTION:
995 			config_info->initialUpdate = ini_none;
996 			break;
997 		case (__nis_initial_update_t)FROM_NO_INITIAL_UPDATE:
998 			config_info->initialUpdate = from_ldap;
999 			break;
1000 		case (__nis_initial_update_t)TO_NO_INITIAL_UPDATE:
1001 			config_info->initialUpdate = to_ldap;
1002 			break;
1003 	}
1004 	if (config_info->threadCreationError ==
1005 	    (__nis_thread_creation_error_t)NO_VALUE_SET)
1006 		config_info->threadCreationError = pass_error;
1007 	if (config_info->threadCreationErrorTimeout.attempts == NO_VALUE_SET)
1008 		config_info->threadCreationErrorTimeout.attempts =
1009 			DEFAULT_THREAD_ERROR_ATTEMPTS;
1010 	if (config_info->threadCreationErrorTimeout.timeout ==
1011 			(time_t)NO_VALUE_SET)
1012 		config_info->threadCreationErrorTimeout.timeout =
1013 			DEFAULT_THREAD_ERROR_TIME_OUT;
1014 	if (config_info->dumpError ==
1015 	    (__nis_dump_error_t)NO_VALUE_SET)
1016 		config_info->dumpError = de_retry;
1017 	if (config_info->dumpErrorTimeout.attempts == NO_VALUE_SET)
1018 		config_info->dumpErrorTimeout.attempts =
1019 			DEFAULT_DUMP_ERROR_ATTEMPTS;
1020 	if (config_info->dumpErrorTimeout.timeout == (time_t)NO_VALUE_SET)
1021 		config_info->dumpErrorTimeout.timeout =
1022 			DEFAULT_DUMP_ERROR_TIME_OUT;
1023 	if (config_info->resyncService ==
1024 	    (__nis_resync_service_t)NO_VALUE_SET)
1025 		config_info->resyncService = from_copy;
1026 	if (config_info->updateBatching ==
1027 	    (__nis_update_batching_t)NO_VALUE_SET)
1028 		config_info->updateBatching = accumulate;
1029 	if (config_info->updateBatchingTimeout.timeout == (time_t)NO_VALUE_SET)
1030 		config_info->updateBatchingTimeout.timeout =
1031 			DEFAULT_BATCHING_TIME_OUT;
1032 	if (config_info->numberOfServiceThreads == (int)NO_VALUE_SET)
1033 		config_info->numberOfServiceThreads =
1034 			DEFAULT_NUMBER_OF_THREADS;
1035 	if (config_info->emulate_yp == (int)NO_VALUE_SET)
1036 		config_info->emulate_yp =
1037 			DEFAULT_YP_EMULATION;
1038 	if (config_info->maxRPCRecordSize == (int)NO_VALUE_SET)
1039 		config_info->maxRPCRecordSize = RPC_MAXDATASIZE;
1040 
1041 	if (table_info->retrieveError ==
1042 	    (__nis_retrieve_error_t)NO_VALUE_SET)
1043 		table_info->retrieveError = use_cached;
1044 	if (table_info->retrieveErrorRetry.attempts == NO_VALUE_SET)
1045 		table_info->retrieveErrorRetry.attempts =
1046 			DEFAULT_RETRIEVE_ERROR_ATTEMPTS;
1047 	if (table_info->retrieveErrorRetry.timeout == (time_t)NO_VALUE_SET)
1048 		table_info->retrieveErrorRetry.timeout =
1049 			DEFAULT_RETRIEVE_ERROR_TIME_OUT;
1050 	if (table_info->storeError ==
1051 	    (__nis_store_error_t)NO_VALUE_SET)
1052 		table_info->storeError = sto_retry;
1053 	if (table_info->storeErrorRetry.attempts == NO_VALUE_SET)
1054 		table_info->storeErrorRetry.attempts =
1055 			DEFAULT_STORE_ERROR_ATTEMPTS;
1056 	if (table_info->storeErrorRetry.timeout == (time_t)NO_VALUE_SET)
1057 		table_info->storeErrorRetry.timeout =
1058 			DEFAULT_STORE_ERROR_TIME_OUT;
1059 	if (table_info->refreshError ==
1060 	    (__nis_refresh_error_t)NO_VALUE_SET)
1061 		table_info->refreshError = continue_using;
1062 	if (table_info->refreshErrorRetry.attempts == NO_VALUE_SET)
1063 		table_info->refreshErrorRetry.attempts =
1064 			DEFAULT_REFRESH_ERROR_ATTEMPTS;
1065 	if (table_info->refreshErrorRetry.timeout == (time_t)NO_VALUE_SET)
1066 		table_info->refreshErrorRetry.timeout =
1067 			DEFAULT_REFRESH_ERROR_TIME_OUT;
1068 	if (table_info->matchFetch ==
1069 	    (__nis_match_fetch_t)NO_VALUE_SET)
1070 		table_info->matchFetch = no_match_only;
1071 }
1072 
1073 __nis_table_mapping_t *
1074 find_table_mapping(const char *s, int len, __nis_table_mapping_t *table_mapping)
1075 {
1076 	__nis_table_mapping_t *t;
1077 
1078 	for (t = table_mapping; t != NULL; t = t->next)
1079 		if (strlen(t->dbId) == len &&
1080 		    strncasecmp(t->dbId, s, len) == 0)
1081 			break;
1082 	return (t);
1083 }
1084 
1085 void
1086 append_dot(char **str)
1087 {
1088 	char	*s	= *str;
1089 	int	len	= strlen(s);
1090 
1091 	if (len == 0 || s[len - 1] != PERIOD_CHAR) {
1092 		s = s_realloc(s, len + 2);
1093 		if (s != NULL) {
1094 			s[len] = PERIOD_CHAR;
1095 			s[len+1] = '\0';
1096 			*str = s;
1097 		}
1098 	}
1099 }
1100 
1101 void
1102 append_comma(char **str)
1103 {
1104 
1105 	char    *s  = *str;
1106 	int len = strlen(s);
1107 
1108 	if (len == 0 || s[len - 1] != COMMA_CHAR) {
1109 		s = s_realloc(s, len + 2);
1110 		if (s != NULL) {
1111 			s[len] = COMMA_CHAR;
1112 			s[len+1] = '\0';
1113 			*str = s;
1114 		}
1115 	}
1116 }
1117 
1118 /*
1119  * FUNCTION:	make_full_dn
1120  *
1121  *	Appends the base dn if a relative ldap dn
1122  *	(invoked only for LDAP write cycle)
1123  *
1124  * RETURN VALUE:	FALSE if error
1125  *			TRUE if __nis_index_t returned
1126  *
1127  * INPUT:		the relative dn and ldap base
1128  */
1129 
1130 bool_t
1131 make_full_dn(char **dn, const char *base)
1132 {
1133 	int len;
1134 	int len1;
1135 
1136 	if (*dn == NULL) {
1137 		*dn = s_strdup(base);
1138 	} else {
1139 		len = strlen(*dn);
1140 		if (len > 0 && (*dn)[len-1] == COMMA_CHAR) {
1141 			len1 = strlen(base) + 1;
1142 			*dn = s_realloc(*dn, len + len1);
1143 			if (*dn != NULL)
1144 				(void) strcpy(*dn + len, base);
1145 		}
1146 	}
1147 	return (*dn != NULL);
1148 }
1149 
1150 /*
1151  * FUNCTION:	make_fqdn
1152  *
1153  *	Appends the base dn if a relative ldap dn
1154  *	(invoked only for LDAP read cycle)
1155  *
1156  * RETURN VALUE:	FALSE if error
1157  *			TRUE if success
1158  *
1159  * INPUT:		the relative dn and ldap base
1160  */
1161 bool_t
1162 make_fqdn(__nis_object_dn_t *dn, const char *base)
1163 {
1164 	int len;
1165 	int len1;
1166 
1167 	if (dn == NULL) {
1168 		return (FALSE);
1169 	} else {
1170 		while (dn != NULL && dn->read.base != NULL) {
1171 			len = strlen(dn->read.base);
1172 			if (len > 0 && (dn->read.base)[len-1] == COMMA_CHAR) {
1173 				len1 = strlen(base) + 1;
1174 				dn->read.base =
1175 					s_realloc(dn->read.base, len + len1);
1176 				if (dn->read.base != NULL)
1177 					(void) strlcpy(dn->read.base + len,
1178 							base, len1);
1179 				else
1180 					return (FALSE);
1181 			}
1182 			dn = dn->next;
1183 		}
1184 	}
1185 	return (TRUE);
1186 }
1187 
1188 /*
1189  * FUNCTION:	get_default_ldap_base
1190  *
1191  *	Gets the default LDAP search base from the
1192  *	nis+ default domain
1193  *
1194  * RETURN VALUE:	NULL if error
1195  *			the default base
1196  *
1197  * INPUT:		the nis domain
1198  */
1199 
1200 char *
1201 get_default_ldap_base(const char *domain)
1202 {
1203 
1204 	int		len	= strlen(domain);
1205 	int		i;
1206 	int		count	= len + 4;
1207 	char		*base;
1208 
1209 	for (i = 0; i < len - 1; i++)
1210 		if (domain[i] == PERIOD_CHAR)
1211 			count += 4;
1212 	if ((base = malloc(count)) == NULL) {
1213 		p_error = parse_no_mem_error;
1214 	} else {
1215 		(void) strcpy(base, "dc=");
1216 		count = 3;
1217 		for (i = 0; i < len - 1; i++) {
1218 			if (domain[i] == PERIOD_CHAR) {
1219 				(void) strcpy(base + count, ",dc=");
1220 				count += 4;
1221 			} else {
1222 				base[count++] = domain[i];
1223 			}
1224 		}
1225 		base[count] = '\0';
1226 	}
1227 	return (base);
1228 }
1229 
1230 /*
1231  * FUNCTION:	add_domain
1232  *
1233  *	Appends the base domain if a relative object name
1234  *
1235  * RETURN VALUE:	FALSE if error
1236  *			TRUE if OK
1237  *
1238  * INPUT:		the relative object name and base domain
1239  *			name
1240  */
1241 
1242 bool_t
1243 add_domain(char **objName, const char *domain)
1244 {
1245 	int	len;
1246 	int	len1;
1247 	bool_t	trailing_dot;
1248 	char	*obj_name;
1249 
1250 	if (domain == NULL || *objName == NULL) {
1251 		p_error = parse_internal_error;
1252 		return (FALSE);
1253 	}
1254 	len1 = strlen(domain);
1255 	trailing_dot = (len1 > 0 && domain[len1 - 1] == PERIOD_CHAR) ?
1256 		0 : 1;
1257 	len = strlen(*objName);
1258 	if (len == 0 || (*objName)[len - 1] != PERIOD_CHAR) {
1259 		obj_name = s_realloc(*objName,
1260 			len + len1 + 2 + trailing_dot);
1261 		if (obj_name != NULL) {
1262 			obj_name[len++] = PERIOD_CHAR;
1263 			(void) strcpy(obj_name + len, domain);
1264 			if (trailing_dot != 0) {
1265 				obj_name[len + len1] = PERIOD_CHAR;
1266 				obj_name[len + len1 + 1] = '\0';
1267 			}
1268 			*objName = obj_name;
1269 		}
1270 	}
1271 
1272 	return (*objName != NULL);
1273 }
1274 
1275 bool_t
1276 dup_index(__nis_index_t *in, __nis_index_t *out)
1277 {
1278 	int i;
1279 	int j;
1280 
1281 	out->name = (char **)s_calloc(in->numIndexes, sizeof (char *));
1282 	if (out->name == NULL)
1283 		return (FALSE);
1284 	out->value = (__nis_mapping_format_t **)
1285 		s_calloc(in->numIndexes, sizeof (__nis_mapping_format_t *));
1286 	if (out->value == NULL) {
1287 		free(out->name);
1288 		out->name = NULL;
1289 		return (FALSE);
1290 	}
1291 
1292 	for (i = 0; i < in->numIndexes; i++) {
1293 		out->name[i] = s_strdup(in->name[i]);
1294 		if (out->name[i] == NULL)
1295 			break;
1296 		out->value[i] = dup_format_mapping(in->value[i]);
1297 		if (out->value[i] == NULL)
1298 			break;
1299 	}
1300 	if (i < in->numIndexes) {
1301 		for (j = 0; j <= i; j++) {
1302 			if (out->name[j] != NULL)
1303 				free(out->name[j]);
1304 			if (out->value[j] != NULL)
1305 				free_mapping_format(out->value[j]);
1306 		}
1307 		free(out->name);
1308 		out->name = NULL;
1309 		free(out->value);
1310 		out->value = NULL;
1311 	} else {
1312 		out->numIndexes = in->numIndexes;
1313 	}
1314 	return (i == in->numIndexes);
1315 }
1316 
1317 bool_t
1318 dup_mapping_item(__nis_mapping_item_t *in, __nis_mapping_item_t *out)
1319 {
1320 	bool_t	ret;
1321 
1322 	if (in->type == mit_nisplus) {
1323 		ret = dup_index(&in->searchSpec.obj.index,
1324 			&out->searchSpec.obj.index);
1325 		if (!ret)
1326 			return (ret);
1327 		if (in->searchSpec.obj.name != NULL) {
1328 		    out->searchSpec.obj.name =
1329 			s_strdup(in->searchSpec.obj.name);
1330 			if (out->searchSpec.obj.name == NULL)
1331 				return (FALSE);
1332 		} else
1333 			out->searchSpec.obj.name = NULL;
1334 	} else if (in->type == mit_ldap) {
1335 		if (in->searchSpec.triple.base != NULL) {
1336 		    out->searchSpec.triple.base =
1337 			s_strdup(in->searchSpec.triple.base);
1338 			if (out->searchSpec.triple.base == NULL)
1339 				return (FALSE);
1340 		} else
1341 			out->searchSpec.triple.base = NULL;
1342 		out->searchSpec.triple.scope =
1343 			in->searchSpec.triple.scope;
1344 		if (in->searchSpec.triple.attrs != NULL) {
1345 		    out->searchSpec.triple.attrs =
1346 			s_strdup(in->searchSpec.triple.attrs);
1347 			if (out->searchSpec.triple.attrs == NULL)
1348 				return (FALSE);
1349 		} else
1350 			out->searchSpec.triple.attrs = NULL;
1351 		if (in->searchSpec.triple.element != NULL) {
1352 			out->searchSpec.triple.element =
1353 				(__nis_mapping_element_t *)
1354 				s_calloc(1, sizeof (__nis_mapping_element_t));
1355 			if (out->searchSpec.triple.element != NULL)
1356 				dup_mapping_element(
1357 					in->searchSpec.triple.element,
1358 					out->searchSpec.triple.element);
1359 			if (out->searchSpec.triple.element == NULL)
1360 				return (FALSE);
1361 		} else
1362 			out->searchSpec.triple.element = NULL;
1363 	}
1364 
1365 	if (in->name != NULL) {
1366 		out->name = s_strdup(in->name);
1367 		if (out->name == NULL)
1368 			return (FALSE);
1369 	} else
1370 		out->name = NULL;
1371 	out->type = in->type;
1372 	out->repeat = in->repeat;
1373 	if (in->exItem) {
1374 		out->exItem = (__nis_mapping_item_t *)s_malloc
1375 			(sizeof (__nis_mapping_item_t));
1376 		if (out->exItem == NULL)
1377 			return (FALSE);
1378 		else {
1379 			(void) memset
1380 				(out->exItem, 0, sizeof (out->exItem[0]));
1381 			if (!dup_mapping_item
1382 				(in->exItem, out->exItem))
1383 				p_error = parse_internal_error;
1384 		}
1385 	} else
1386 		out->exItem = NULL;
1387 
1388 	return (p_error == no_parse_error);
1389 }
1390 
1391 __nis_mapping_format_t *
1392 dup_format_mapping(__nis_mapping_format_t *in)
1393 {
1394 	int			i;
1395 	__nis_mapping_format_t	*out;
1396 	bool_t			got_end;
1397 
1398 	i = 0;
1399 	while (in[i].type != mmt_end)
1400 		i++;
1401 	out = (__nis_mapping_format_t *)s_calloc(
1402 		i + 1, sizeof (__nis_mapping_format_t));
1403 	if (out != NULL) {
1404 		got_end = FALSE;
1405 		for (i = 0; !got_end; i++) {
1406 		    switch (in[i].type) {
1407 			case mmt_item:
1408 				break;
1409 			case mmt_string:
1410 				out[i].match.string =
1411 					s_strdup(in[i].match.string);
1412 				break;
1413 			case mmt_single:
1414 				out[i].match.single.numRange =
1415 					in[i].match.single.numRange;
1416 				out[i].match.single.lo =
1417 					s_malloc(in[i].match.single.numRange);
1418 				if (out[i].match.single.lo == NULL)
1419 					break;
1420 				out[i].match.single.hi =
1421 					s_malloc(in[i].match.single.numRange);
1422 				if (out[i].match.single.hi == NULL)
1423 					break;
1424 				memcpy(out[i].match.single.lo,
1425 					in[i].match.single.lo,
1426 					in[i].match.single.numRange);
1427 				memcpy(out[i].match.single.hi,
1428 					in[i].match.single.hi,
1429 					in[i].match.single.numRange);
1430 				break;
1431 			case mmt_limit:
1432 				out[i].match.limit = in[i].match.limit;
1433 				break;
1434 			case mmt_any:
1435 				break;
1436 			case mmt_berstring:
1437 				out[i].match.berString =
1438 					s_strdup(in[i].match.berString);
1439 				break;
1440 			case mmt_begin:
1441 				break;
1442 			case mmt_end:
1443 				got_end = TRUE;
1444 				break;
1445 			default:
1446 				p_error = parse_internal_error;
1447 		    }
1448 		    if (p_error != no_parse_error)
1449 			break;
1450 		    out[i].type = in[i].type;
1451 		}
1452 		if (p_error != no_parse_error) {
1453 			free_mapping_format(out);
1454 			out = NULL;
1455 		}
1456 	}
1457 
1458 	return (out);
1459 }
1460 
1461 bool_t
1462 dup_mapping_sub_element(
1463 	__nis_mapping_sub_element_t	*in,
1464 	__nis_mapping_sub_element_t	*out)
1465 {
1466 	bool_t	ret = FALSE;
1467 	int	i;
1468 
1469 	switch (in->type) {
1470 		case me_item:
1471 			ret = dup_mapping_item(&in->element.item,
1472 				&out->element.item);
1473 			break;
1474 		case me_print:
1475 			out->element.print.fmt =
1476 				dup_format_mapping(in->element.print.fmt);
1477 			if (out->element.print.fmt == NULL)
1478 				break;
1479 			out->element.print.numItems =
1480 				in->element.print.numItems;
1481 			out->element.print.item = (__nis_mapping_item_t *)
1482 				s_calloc(in->element.print.numItems,
1483 					sizeof (__nis_mapping_item_t));
1484 			if (out->element.print.item == NULL)
1485 				break;
1486 			for (i = 0; i < in->element.print.numItems; i++)
1487 				if (!dup_mapping_item(
1488 					&in->element.print.item[i],
1489 					&out->element.print.item[i]))
1490 						break;
1491 			if (i < in->element.print.numItems)
1492 				break;
1493 			ret = TRUE;
1494 			out->element.print.doElide = in->element.print.doElide;
1495 			out->element.print.elide = in->element.print.elide;
1496 			break;
1497 		case me_split:
1498 			ret = dup_mapping_item(&in->element.split.item,
1499 				&out->element.split.item);
1500 			out->element.split.delim = in->element.split.delim;
1501 			break;
1502 		case me_extract:
1503 			out->element.extract.fmt =
1504 				dup_format_mapping(in->element.extract.fmt);
1505 			if (out->element.extract.fmt == NULL)
1506 				break;
1507 			ret = dup_mapping_item(&in->element.extract.item,
1508 				&out->element.extract.item);
1509 			break;
1510 		default:
1511 			p_error = parse_internal_error;
1512 	}
1513 	out->type = in->type;
1514 
1515 	return (ret);
1516 }
1517 
1518 bool_t
1519 dup_mapping_element(
1520 	__nis_mapping_element_t *in,
1521 	__nis_mapping_element_t *out)
1522 {
1523 	bool_t	ret = FALSE;
1524 	int	i;
1525 
1526 	if (in == NULL)
1527 		return (ret);
1528 
1529 	switch (in->type) {
1530 		case me_item:
1531 			ret = dup_mapping_item(&in->element.item,
1532 				&out->element.item);
1533 			break;
1534 		case me_print:
1535 			out->element.print.fmt =
1536 				dup_format_mapping(in->element.print.fmt);
1537 			if (out->element.print.fmt == NULL)
1538 				break;
1539 			out->element.print.numSubElements =
1540 				in->element.print.numSubElements;
1541 			out->element.print.subElement =
1542 				(__nis_mapping_sub_element_t *)
1543 				s_calloc(in->element.print.numSubElements,
1544 					sizeof (__nis_mapping_sub_element_t));
1545 			if (out->element.print.subElement == NULL)
1546 				break;
1547 			for (i = 0; i < in->element.print.numSubElements; i++)
1548 				if (!dup_mapping_sub_element(
1549 					&in->element.print.subElement[i],
1550 					&out->element.print.subElement[i]))
1551 						break;
1552 			if (i < in->element.print.numSubElements)
1553 				break;
1554 			ret = TRUE;
1555 			out->element.print.doElide = in->element.print.doElide;
1556 			out->element.print.elide = in->element.print.elide;
1557 			break;
1558 		case me_split:
1559 			ret = dup_mapping_item(&in->element.split.item,
1560 				&out->element.split.item);
1561 			out->element.split.delim = in->element.split.delim;
1562 			break;
1563 		case me_match:
1564 			out->element.match.fmt =
1565 				dup_format_mapping(in->element.match.fmt);
1566 			if (out->element.match.fmt == NULL)
1567 				break;
1568 			out->element.match.numItems =
1569 				in->element.match.numItems;
1570 			out->element.match.item = (__nis_mapping_item_t *)
1571 				s_calloc(in->element.match.numItems,
1572 					sizeof (__nis_mapping_item_t));
1573 			if (out->element.match.item == NULL)
1574 				break;
1575 			for (i = 0; i < in->element.match.numItems; i++)
1576 				if (!dup_mapping_item(
1577 					&in->element.match.item[i],
1578 					&out->element.match.item[i]))
1579 						break;
1580 			if (i < in->element.match.numItems)
1581 				break;
1582 			ret = TRUE;
1583 			break;
1584 		case me_extract:
1585 			out->element.extract.fmt =
1586 				dup_format_mapping(in->element.extract.fmt);
1587 			if (out->element.extract.fmt == NULL)
1588 				break;
1589 			ret = dup_mapping_item(&in->element.extract.item,
1590 				&out->element.extract.item);
1591 			break;
1592 		default:
1593 			p_error = parse_internal_error;
1594 	}
1595 	out->type = in->type;
1596 
1597 	return (ret);
1598 }
1599 
1600 __nis_mapping_rule_t *
1601 dup_mapping_rule(__nis_mapping_rule_t *in)
1602 {
1603 	int			i;
1604 	__nis_mapping_rlhs_t	*r_in;
1605 	__nis_mapping_rlhs_t	*r_out;
1606 	__nis_mapping_rule_t	*out;
1607 
1608 	out = (__nis_mapping_rule_t *)
1609 		s_calloc(1, sizeof (__nis_mapping_rule_t));
1610 	if (out != NULL) {
1611 		r_in = &in->lhs;
1612 		r_out = &out->lhs;
1613 		r_out->numElements = r_in->numElements;
1614 		r_out->element = (__nis_mapping_element_t *)s_calloc
1615 			(r_in->numElements, sizeof (__nis_mapping_element_t));
1616 		if (r_out->element == NULL) {
1617 			free_mapping_rule(out);
1618 			return (NULL);
1619 		}
1620 		for (i = 0; i < r_in->numElements; i++) {
1621 		    if (!dup_mapping_element(&r_in->element[i],
1622 			&r_out->element[i]))
1623 				break;
1624 		}
1625 		if (i < r_in->numElements) {
1626 			free_mapping_rule(out);
1627 			return (NULL);
1628 		}
1629 
1630 		r_in = &in->rhs;
1631 		r_out = &out->rhs;
1632 		r_out->numElements = r_in->numElements;
1633 		r_out->element = (__nis_mapping_element_t *)s_calloc
1634 			(r_in->numElements, sizeof (__nis_mapping_element_t));
1635 		if (r_out->element == NULL) {
1636 			free_mapping_rule(out);
1637 			return (NULL);
1638 		}
1639 		for (i = 0; i < r_in->numElements; i++) {
1640 		    if (!dup_mapping_element(&r_in->element[i],
1641 			&r_out->element[i]))
1642 				break;
1643 		}
1644 		if (i < r_in->numElements) {
1645 			free_mapping_rule(out);
1646 			return (NULL);
1647 		}
1648 	}
1649 	return (out);
1650 }
1651 
1652 __nis_mapping_rule_t **
1653 dup_mapping_rules(__nis_mapping_rule_t **rules, int n_rules)
1654 {
1655 	int			i, j;
1656 	__nis_mapping_rule_t	**r;
1657 
1658 	r = (__nis_mapping_rule_t **)s_calloc(n_rules,
1659 		sizeof (__nis_mapping_rule_t *));
1660 	if (r != NULL) {
1661 		for (i = 0; i < n_rules; i++) {
1662 			r[i] = dup_mapping_rule(rules[i]);
1663 			if (r[i] == NULL) {
1664 				for (j = 0; j < i; j++)
1665 					free_mapping_rule(r[j]);
1666 				free(r);
1667 				r = NULL;
1668 				break;
1669 			}
1670 		}
1671 	}
1672 	return (r);
1673 }
1674 
1675 /*
1676  * FUNCTION:	add_column
1677  *
1678  *	Adds a column name to the column list in __nis_table_mapping_t
1679  *
1680  * RETURN VALUE:	FALSE if error
1681  *			TRUE if __nis_index_t returned
1682  *
1683  * INPUT:		the __nis_table_mapping_t and column name
1684  */
1685 
1686 bool_t
1687 add_column(__nis_table_mapping_t *t, const char *col_name)
1688 {
1689 	int i;
1690 	char **cols = NULL;
1691 
1692 	if (!yp2ldap) {
1693 		for (i = 0; i < t->numColumns; i++) {
1694 			if (strcasecmp(col_name, t->column[i]) == 0)
1695 				return (TRUE);
1696 		}
1697 	}
1698 	cols = (char **)s_realloc(t->column, (t->numColumns + 1) *
1699 		sizeof (char *));
1700 	if (cols == NULL)
1701 		return (FALSE);
1702 	t->column = cols;
1703 	cols[t->numColumns] = s_strdup(col_name);
1704 	if (cols[t->numColumns] == NULL)
1705 		return (FALSE);
1706 	t->numColumns++;
1707 	return (TRUE);
1708 }
1709 
1710 /*
1711  * FUNCTION:	add_element
1712  *
1713  *	Adds a __nis_mapping_element_t to __nis_mapping_rlhs_t
1714  *
1715  * RETURN VALUE:	FALSE if error
1716  *			TRUE if __nis_index_t returned
1717  *
1718  * INPUT:		the __nis_mapping_element_t and
1719  *			__nis_mapping_rlhs_t
1720  */
1721 
1722 bool_t
1723 add_element(
1724 	__nis_mapping_element_t	*e,
1725 	__nis_mapping_rlhs_t	*m)
1726 {
1727 	__nis_mapping_element_t *e1;
1728 	int			i;
1729 	int			n	= m->numElements;
1730 
1731 	e1 = (__nis_mapping_element_t *)s_realloc(m->element,
1732 		(n + 1) * sizeof (__nis_mapping_element_t));
1733 	if (e1 == NULL) {
1734 		e1 = m->element;
1735 		for (i = 0; i < n; i++)
1736 			free_mapping_element(e1++);
1737 		if (m->element != NULL)
1738 			free(m->element);
1739 		m->element = NULL;
1740 		m->numElements = 0;
1741 	} else {
1742 		e1[m->numElements++] = *e;
1743 		free(e);
1744 		m->element = (__nis_mapping_element_t *)e1;
1745 	}
1746 	return (e1 != NULL);
1747 }
1748 
1749 /*
1750  * FUNCTION:	get_next_object_dn_token
1751  *
1752  *	Get the next token in parsing object_dn
1753  *
1754  * RETURN VALUE:	NULL if error
1755  *			position of beginning next token after
1756  *			token
1757  *
1758  * INPUT:		the attribute value
1759  */
1760 
1761 const char *
1762 get_next_object_dn_token(
1763 	const char	**begin_ret,
1764 	const char	**end_ret,
1765 	object_dn_token	*token)
1766 {
1767 	object_dn_token	t		= dn_no_token;
1768 	const char	*s		= *begin_ret;
1769 	const char	*begin;
1770 	const char	*end		= *end_ret;
1771 	const char	*s1;
1772 	bool_t		in_quotes;
1773 
1774 	while (s < end && is_whitespace(*s))
1775 		s++;
1776 	if (s >= end) {
1777 		/* EMPTY */
1778 	} else if (*s == SEMI_COLON_CHAR) {
1779 		t = dn_semi_token;
1780 		s++;
1781 	} else if (*s == QUESTION_MARK) {
1782 		t = dn_ques_token;
1783 		s++;
1784 	} else if (*s == COLON_CHAR) {
1785 		t = dn_colon_token;
1786 		s++;
1787 	} else if (*s == OPEN_PAREN_CHAR) {
1788 		begin = s;
1789 		s = get_ldap_filter(&begin, &end);
1790 		if (s != NULL) {
1791 			t = dn_text_token;
1792 			*begin_ret = begin;
1793 			*end_ret = end;
1794 		}
1795 	} else {
1796 		begin = s;
1797 		in_quotes = FALSE;
1798 		while (s < end) {
1799 			if (*s == ESCAPE_CHAR) {
1800 			    if (s + 2 > end) {
1801 				p_error = parse_unmatched_escape;
1802 				s = NULL;
1803 				break;
1804 			    }
1805 			    s++;
1806 			} else if (*s == DOUBLE_QUOTE_CHAR) {
1807 				in_quotes = ! in_quotes;
1808 			} else if (in_quotes)
1809 				;
1810 			else if (*s == SEMI_COLON_CHAR ||
1811 				*s == QUESTION_MARK ||
1812 				*s == COLON_CHAR)
1813 					break;
1814 			s++;
1815 		}
1816 		if (s != NULL) {
1817 			s1 = s - 1;
1818 			while (is_whitespace(*s1))
1819 				s1--;
1820 			s1++;
1821 			if (same_string("base", begin, s1 - begin))
1822 				t = dn_base_token;
1823 			else if (same_string("one", begin, s1 - begin))
1824 				t = dn_one_token;
1825 			else if (same_string("sub", begin, s1 - begin))
1826 				t = dn_sub_token;
1827 			else
1828 				t = dn_text_token;
1829 			*begin_ret = begin;
1830 			*end_ret = s1;
1831 		}
1832 	}
1833 	*token = t;
1834 	return (s);
1835 }
1836 
1837 /*
1838  * FUNCTION:	get_next_token
1839  *
1840  *	Get the next token in parsing mapping attribute
1841  *
1842  * RETURN VALUE:	NULL if error
1843  *			position of beginning next token after
1844  *			token
1845  *
1846  * INPUT:		the attribute value
1847  */
1848 
1849 const char *
1850 get_next_token(const char **begin_token, const char **end_token, token_type *t)
1851 {
1852 	const char	*s		= *begin_token;
1853 	const char	*end_s		= *end_token;
1854 	const char	*s_begin;
1855 
1856 	while (s < end_s && is_whitespace(*s))
1857 		s++;
1858 	if (s == end_s) {
1859 		*t = no_token;
1860 		return (s);
1861 	}
1862 
1863 	s_begin = s;
1864 
1865 	if (*s == OPEN_PAREN_CHAR) {
1866 		*begin_token = s;
1867 		s++;
1868 		*end_token = s;
1869 		while (s < end_s && is_whitespace(*s))
1870 			s++;
1871 		*t = open_paren_token;
1872 	} else if (*s == DOUBLE_QUOTE_CHAR) {
1873 		s++;
1874 		while (s < end_s) {
1875 			if (*s == ESCAPE_CHAR)
1876 				s += 2;
1877 			else if (*s == DOUBLE_QUOTE_CHAR)
1878 				break;
1879 			else
1880 				s++;
1881 		}
1882 		if (s >= end_s) {
1883 			p_error = parse_unmatched_escape;
1884 			return (NULL);
1885 		}
1886 
1887 		*t = quoted_string_token;
1888 		*begin_token = s_begin + 1;
1889 		*end_token = s++;
1890 	} else if (*s == EQUAL_CHAR || *s == COMMA_CHAR ||
1891 	    *s == CLOSE_PAREN_CHAR || *s == COLON_CHAR) {
1892 		if (*s == EQUAL_CHAR)
1893 			*t = equal_token;
1894 		else if (*s == COMMA_CHAR)
1895 			*t = comma_token;
1896 		else if (*s == CLOSE_PAREN_CHAR)
1897 			*t = close_paren_token;
1898 		else
1899 			*t = colon_token;
1900 		*begin_token = s;
1901 		*end_token = ++s;
1902 	} else {
1903 		s_begin = s;
1904 		while (s < end_s && !is_whitespace(*s)) {
1905 			if (*s == ESCAPE_CHAR)
1906 				s += 2;
1907 			else if (*s == EQUAL_CHAR || *s == CLOSE_PAREN_CHAR ||
1908 			    *s == OPEN_PAREN_CHAR || *s == COMMA_CHAR ||
1909 			    *s == COLON_CHAR || *s == OPEN_BRACKET ||
1910 			    *s == CLOSE_BRACKET)
1911 				break;
1912 			else
1913 				s++;
1914 		}
1915 		if (s > end_s) {
1916 			p_error = parse_unmatched_escape;
1917 			return (NULL);
1918 		}
1919 		*t = string_token;
1920 		*end_token = s;
1921 		*begin_token = s_begin;
1922 	}
1923 	if (s) {
1924 		while (s < end_s && is_whitespace(*s))
1925 			s++;
1926 	}
1927 	return (s);
1928 }
1929 
1930 /*
1931  * FUNCTION:	skip_token
1932  *
1933  *	Skip over the specified token - An error is set if
1934  *	next token does not match expected token
1935  *
1936  * RETURN VALUE:	NULL if error
1937  *			position of beginning next token after
1938  *			token
1939  *
1940  * INPUT:		the attribute value
1941  */
1942 
1943 const char *
1944 skip_token(const char *s, const char *end_s, token_type t)
1945 {
1946 	bool_t	match;
1947 	char	c	= 0;
1948 
1949 	if (s == NULL)
1950 		return (s);
1951 	while (s < end_s && is_whitespace(*s))
1952 		s++;
1953 	c = (s == end_s) ? 0 : *s;
1954 	switch (t) {
1955 		case equal_token:
1956 			match = c == EQUAL_CHAR;
1957 			if (!match)
1958 				p_error = parse_equal_expected_error;
1959 			break;
1960 		case comma_token:
1961 			match = c == COMMA_CHAR;
1962 			if (!match)
1963 				p_error = parse_comma_expected_error;
1964 			break;
1965 		case close_paren_token:
1966 			match = c == CLOSE_PAREN_CHAR;
1967 			if (!match)
1968 				p_error = parse_close_paren_expected_error;
1969 			break;
1970 		default:
1971 			match = FALSE;
1972 			break;
1973 	}
1974 	if (match) {
1975 		s++;
1976 		while (s < end_s && is_whitespace(*s))
1977 			s++;
1978 	} else {
1979 		s = NULL;
1980 	}
1981 	return (s);
1982 }
1983 
1984 /*
1985  * FUNCTION:	get_next_extract_format_item
1986  *
1987  *	Get the next format token from the string. Note that
1988  *	get_next_extract_format_item may change the input string.
1989  *
1990  * RETURN VALUE:	NULL if error
1991  *			position of beginning next token after
1992  *			token
1993  *
1994  * INPUT:		the format string
1995  */
1996 
1997 const char *
1998 get_next_extract_format_item(
1999 	const char		*begin_fmt,
2000 	const char		*end_fmt,
2001 	__nis_mapping_format_t	*fmt)
2002 {
2003 	const char	*s		= begin_fmt;
2004 	const char	*s_end		= end_fmt;
2005 	bool_t		escape;
2006 	bool_t		in_range;
2007 	bool_t		got_char;
2008 	bool_t		done;
2009 	int		numRange;
2010 	char		*lo		= NULL;
2011 	char		*hi		= NULL;
2012 	bool_t		skip_ber;
2013 
2014 	for (; p_error == no_parse_error; ) {
2015 		if (s >= s_end)
2016 			break;
2017 
2018 		if (*s == PERCENT_SIGN) {
2019 			s++;
2020 			/*
2021 			 * If the format is %s, it is interpreted
2022 			 * as a string.
2023 			 */
2024 			if (s >= s_end) {
2025 				p_error = parse_unsupported_format;
2026 				break;
2027 			}
2028 			skip_ber = FALSE;
2029 			switch (*s) {
2030 				case 's':
2031 					fmt->type = mmt_item;
2032 					break;
2033 				case 'n':	/* null */
2034 				case 'x':	/* skip the next element */
2035 					skip_ber = TRUE;
2036 					/* FALLTHRU */
2037 				case 'b':	/* boolean */
2038 				case 'e':	/* enumerated */
2039 				case 'i':	/* int */
2040 				case 'o':	/* octet string */
2041 				case 'B':	/* bit string */
2042 					fmt->match.berString = s_strndup(s, 1);
2043 					fmt->type = skip_ber ?
2044 						mmt_berstring_null :
2045 						mmt_berstring;
2046 					break;
2047 				case 'a':	/* octet string */
2048 					if (yp2ldap) {
2049 						fmt->match.berString =
2050 							s_strndup(s, 1);
2051 						fmt->type = skip_ber ?
2052 							mmt_berstring_null :
2053 							mmt_berstring;
2054 						break;
2055 					}
2056 					/* FALLTHROUGH */
2057 				case '{':	/* begin sequence */
2058 				case '[':	/* begin set */
2059 				case '}':	/* end sequence */
2060 				case ']':	/* end set */
2061 				case 'l':	/* length of next item */
2062 				case 'O':	/* octet string */
2063 				case 't':	/* tag of next item */
2064 				case 'T':	/* skip tag of next item */
2065 				case 'v':	/* seq of strings */
2066 				case 'V':	/* seq of strings + lengths */
2067 				default:
2068 					p_error = parse_bad_ber_format;
2069 					break;
2070 			}
2071 			s++;
2072 		} else if (*s == ASTERIX_CHAR) {
2073 			fmt->type = mmt_any;
2074 			s++;
2075 			while (s < s_end && *s == ASTERIX_CHAR)
2076 				s++;
2077 
2078 		} else if (*s == OPEN_BRACKET) {
2079 			escape = FALSE;
2080 			in_range = FALSE;
2081 			got_char = FALSE;
2082 			numRange = 0;
2083 			done = FALSE;
2084 			s++;
2085 			for (; s < s_end; s++) {
2086 				if (escape) {
2087 					escape = FALSE;
2088 				} else if (*s == DASH_CHAR) {
2089 					if (in_range || !got_char) {
2090 						p_error = parse_unexpected_dash;
2091 						break;
2092 					}
2093 					in_range = TRUE;
2094 					got_char = FALSE;
2095 					continue;
2096 				} else if (*s == CLOSE_BRACKET) {
2097 					if (in_range) {
2098 						p_error = parse_unexpected_dash;
2099 					}
2100 					done = TRUE;
2101 					break;
2102 				} else if (*s == ESCAPE_CHAR) {
2103 					escape = TRUE;
2104 					continue;
2105 				}
2106 				if (in_range) {
2107 					hi[numRange - 1] = *s;
2108 					in_range = FALSE;
2109 				} else {
2110 					lo = s_realloc(lo, numRange + 1);
2111 					hi = s_realloc(hi, numRange + 1);
2112 					if (lo == NULL || hi == NULL)
2113 						break;
2114 					lo[numRange] = *s;
2115 					hi[numRange] = *s;
2116 					numRange++;
2117 					got_char = TRUE;
2118 				}
2119 			}
2120 			if (p_error != no_parse_error) {
2121 				break;
2122 			} else if (!done) {
2123 				p_error = parse_mismatched_brackets;
2124 				break;
2125 			}
2126 			s++;
2127 			fmt->type = mmt_single;
2128 			fmt->match.single.numRange = numRange;
2129 			fmt->match.single.lo = (unsigned char *)lo;
2130 			fmt->match.single.hi = (unsigned char *)hi;
2131 		} else {
2132 			/* go to next key symbol - copy escaped key symbols */
2133 			escape = FALSE;
2134 			done = FALSE;
2135 			while (s < s_end) {
2136 				if (escape)
2137 					escape = FALSE;
2138 				else {
2139 				    switch (*s) {
2140 					case OPEN_BRACKET:
2141 					case ASTERIX_CHAR:
2142 					case PERCENT_SIGN:
2143 						done = TRUE;
2144 						break;
2145 					case ESCAPE_CHAR:
2146 						escape = !escape;
2147 						break;
2148 					default:
2149 						break;
2150 				    }
2151 				}
2152 				if (done)
2153 					break;
2154 				s++;
2155 			}
2156 			if (escape) {
2157 				p_error = parse_unmatched_escape;
2158 				break;
2159 			}
2160 			fmt->type = mmt_string;
2161 			fmt->match.string =
2162 				s_strndup_esc(begin_fmt, s - begin_fmt);
2163 			if (fmt->match.string == NULL)
2164 				break;
2165 		}
2166 
2167 		if (p_error == no_parse_error)
2168 			return (s);
2169 	}
2170 	if (lo != NULL)
2171 		free(lo);
2172 	if (hi != NULL)
2173 		free(hi);
2174 	return (NULL);
2175 }
2176 
2177 /*
2178  * FUNCTION:	get_next_print_format_item
2179  *
2180  *	Get the next format token from the string
2181  *
2182  * RETURN VALUE:	NULL if error
2183  *			position of beginning next token after
2184  *			token
2185  *
2186  * INPUT:		the format string
2187  */
2188 
2189 const char *
2190 get_next_print_format_item(
2191 	const char		*begin_fmt,
2192 	const char		*end_fmt,
2193 	__nis_mapping_format_t	*fmt)
2194 {
2195 	const char		*s	= begin_fmt;
2196 	const char		*s_end	= end_fmt;
2197 	bool_t			skip_ber;
2198 
2199 	for (; p_error == no_parse_error; ) {
2200 		if (s >= s_end) {
2201 			p_error = parse_internal_error;
2202 			break;
2203 		}
2204 
2205 		if (*s == PERCENT_SIGN) {
2206 			s++;
2207 			if (s >= s_end) {
2208 				p_error = parse_unsupported_format;
2209 				break;
2210 			}
2211 			skip_ber = FALSE;
2212 			/*
2213 			 * If the format is %s, it is interpretted
2214 			 * as a string.
2215 			 */
2216 			switch (*s) {
2217 				case 's':
2218 					fmt->type = mmt_item;
2219 					break;
2220 				case 'n':	/* null */
2221 				case 'x':	/* skip the next element */
2222 					skip_ber = TRUE;
2223 					/* FALLTHRU */
2224 				case 'b':	/* boolean */
2225 				case 'e':	/* enumerated */
2226 				case 'i':	/* int */
2227 				case 'o':	/* octet string */
2228 				case 'B':	/* bit string */
2229 					fmt->match.berString = s_strndup(s, 1);
2230 					fmt->type = skip_ber ?
2231 						mmt_berstring_null :
2232 						mmt_berstring;
2233 					break;
2234 				case '{':	/* begin sequence */
2235 				case '[':	/* begin set */
2236 				case '}':	/* end sequence */
2237 				case ']':	/* end set */
2238 				case 'a':	/* octet string */
2239 				case 'l':	/* length of next item */
2240 				case 'O':	/* octet string */
2241 				case 't':	/* tag of next item */
2242 				case 'T':	/* skip tag of next item */
2243 				case 'v':	/* seq of strings */
2244 				case 'V':	/* seq of strings + lengths */
2245 				default:
2246 					p_error = parse_bad_ber_format;
2247 					break;
2248 			}
2249 			s++;
2250 		} else {
2251 			while (s < s_end) {
2252 				if (*s == PERCENT_SIGN)
2253 					break;
2254 				else if (*s == ESCAPE_CHAR)
2255 					s++;
2256 				s++;
2257 			}
2258 			if (s > s_end) {
2259 				p_error = parse_unmatched_escape;
2260 				break;
2261 			}
2262 			fmt->match.string =
2263 				s_strndup_esc(begin_fmt, s - begin_fmt);
2264 			if (fmt->match.string == NULL)
2265 				break;
2266 			fmt->type = mmt_string;
2267 		}
2268 		if (p_error == no_parse_error)
2269 			return (s);
2270 	}
2271 	return (NULL);
2272 }
2273 
2274 /*
2275  * FUNCTION:	get_ldap_filter
2276  *
2277  *	Gets an LDAP filter - see RFC 2254. Note that this does not
2278  *	determine if the ldap filter is valid. This only determines
2279  *	that the parentheses are balanced.
2280  *
2281  * RETURN VALUE:	NULL if error
2282  *			position of beginning next token after
2283  *			filter
2284  *
2285  * INPUT:		the begin and end of string
2286  *
2287  * OUTPUT:		the begin and end of LDAP filter
2288  *
2289  */
2290 
2291 const char *
2292 get_ldap_filter(const char **begin, const char **end)
2293 {
2294 	const char	*s		= *begin;
2295 	const char	*s_begin;
2296 	const char	*s_end		= *end;
2297 	int		nParen;
2298 
2299 	for (; p_error == no_parse_error; ) {
2300 		while (s < s_end && is_whitespace(*s))
2301 			s++;
2302 		if (s == s_end) {
2303 			s = NULL;
2304 			break;
2305 		}
2306 
2307 		s_begin = s;
2308 		if (*s == OPEN_PAREN_CHAR) {
2309 			nParen = 1;
2310 			s++;
2311 			while (s < s_end && nParen > 0) {
2312 				if (*s == ESCAPE_CHAR)
2313 					s++;
2314 				else if (*s == OPEN_PAREN_CHAR)
2315 					nParen++;
2316 				else if (*s == CLOSE_PAREN_CHAR)
2317 					nParen--;
2318 				s++;
2319 			}
2320 			if (nParen == 0) {
2321 				*begin = s_begin;
2322 				*end = s;
2323 				while (s < s_end && is_whitespace(*s))
2324 					s++;
2325 			} else
2326 				s = NULL;
2327 		} else
2328 			s = NULL;
2329 		if (p_error == no_parse_error)
2330 			break;
2331 	}
2332 	if (s == NULL)
2333 		p_error = parse_invalid_ldap_search_filter;
2334 
2335 	return (s);
2336 }
2337 
2338 /*
2339  * FUNCTION:	get_ava_list
2340  *
2341  *	Gets an attribute value assertion list
2342  *
2343  * RETURN VALUE:	NULL if error
2344  *			position of beginning next token after
2345  *			after attribute assertion
2346  *
2347  * INPUT:		the begin and end of string
2348  *			Indicator if ava list is part of a nisplus
2349  *			item
2350  *
2351  * OUTPUT:		the begin and end of LDAP filter
2352  *
2353  */
2354 
2355 const char *
2356 get_ava_list(const char **begin, const char **end, bool_t end_nisplus)
2357 {
2358 	const char	*s		= *begin;
2359 	const char	*s_begin;
2360 	const char	*s_end		= *end;
2361 	bool_t		in_quote;
2362 	bool_t		got_equal;
2363 	bool_t		got_data;
2364 
2365 	for (; p_error == no_parse_error; ) {
2366 		while (s < s_end && is_whitespace(*s))
2367 			s++;
2368 		if (s == s_end) {
2369 			s = NULL;
2370 			break;
2371 		}
2372 
2373 		in_quote = FALSE;
2374 		got_equal = FALSE;
2375 		got_data = FALSE;
2376 		s_begin = s;
2377 		while (s < s_end) {
2378 			if (*s == ESCAPE_CHAR) {
2379 			    s++;
2380 			    got_data = TRUE;
2381 			} else if (*s == DOUBLE_QUOTE_CHAR) {
2382 			    in_quote = !in_quote;
2383 			    got_data = TRUE;
2384 			} else if (in_quote)
2385 				;
2386 			else if (*s == EQUAL_CHAR) {
2387 			    if (end_nisplus && got_data && got_equal)
2388 				break;
2389 			    if (!got_data || got_equal) {
2390 				got_equal = FALSE;
2391 				break;
2392 			    }
2393 			    got_equal = TRUE;
2394 			    got_data = FALSE;
2395 			} else if (*s == COMMA_CHAR) {
2396 			    if (!got_data || !got_equal)
2397 				break;
2398 			    got_data = FALSE;
2399 			    got_equal = FALSE;
2400 			} else if (is_whitespace(*s))
2401 				;
2402 			else
2403 				got_data = TRUE;
2404 			s++;
2405 		}
2406 		if (!got_data || !got_equal || in_quote)
2407 			s = NULL;
2408 		else {
2409 			*begin = s_begin;
2410 			*end = s;
2411 			while (s < s_end && is_whitespace(*s))
2412 				s++;
2413 		}
2414 		if (p_error == no_parse_error)
2415 			break;
2416 	}
2417 	if (s == NULL)
2418 		p_error = parse_invalid_ldap_search_filter;
2419 
2420 	return (s);
2421 }
2422 
2423 /* Utility functions */
2424 bool_t
2425 validate_dn(const char *s, int len)
2426 {
2427 	const char *end = s + len;
2428 	bool_t	valid;
2429 
2430 	valid = skip_get_dn(s, end) == end;
2431 
2432 	if (!valid)
2433 		p_error = parse_bad_dn;
2434 	return (valid);
2435 }
2436 
2437 bool_t
2438 validate_ldap_filter(const char *s, const char *end)
2439 {
2440 	const char	*s_begin;
2441 	const char	*s_end;
2442 
2443 	s_begin = s;
2444 	s_end = end;
2445 
2446 	if (*s == OPEN_PAREN_CHAR) {
2447 		s = get_ldap_filter(&s_begin, &s_end);
2448 	} else {
2449 		/* Assume an attribute value list */
2450 		s = get_ava_list(&s_begin, &s_end, FALSE);
2451 	}
2452 	if (s == NULL || s_end != end)
2453 		p_error = parse_invalid_ldap_search_filter;
2454 
2455 	return (p_error == no_parse_error);
2456 }
2457 
2458 char *
2459 s_strndup(const char *s, int n)
2460 {
2461 	char *d = (char *)malloc(n + 1);
2462 
2463 	if (d != NULL) {
2464 		(void) memcpy(d, s, n);
2465 		d[n] = '\0';
2466 	} else {
2467 		p_error = parse_no_mem_error;
2468 	}
2469 
2470 	return (d);
2471 }
2472 
2473 char *
2474 s_strndup_esc(const char *s, int n)
2475 {
2476 	char	*d	= (char *)malloc(n + 1);
2477 	int	i;
2478 	int	j;
2479 
2480 	if (d != NULL) {
2481 		for (i = 0, j = 0; i < n; i++) {
2482 			if (s[i] == ESCAPE_CHAR)
2483 				i++;
2484 			d[j++] = s[i];
2485 		}
2486 		d[j] = '\0';
2487 	} else {
2488 		p_error = parse_no_mem_error;
2489 	}
2490 
2491 	return (d);
2492 }
2493 
2494 void *
2495 s_calloc(size_t n, size_t size)
2496 {
2497 	void *d = (char *)calloc(n, size);
2498 
2499 	if (d == NULL) {
2500 		p_error = parse_no_mem_error;
2501 	}
2502 
2503 	return (d);
2504 }
2505 
2506 void *
2507 s_malloc(size_t size)
2508 {
2509 	void *d = malloc(size);
2510 	if (d == NULL)
2511 		p_error = parse_no_mem_error;
2512 	return (d);
2513 }
2514 
2515 void *
2516 s_realloc(void *s, size_t size)
2517 {
2518 	s = realloc(s, size);
2519 	if (s == NULL)
2520 		p_error = parse_no_mem_error;
2521 	return (s);
2522 }
2523 
2524 char *
2525 s_strdup(const char *s)
2526 {
2527 	return (s != NULL ? s_strndup(s, strlen(s)) : NULL);
2528 }
2529 
2530 bool_t
2531 is_whitespace(int c)
2532 {
2533 	return (c == ' ' || c == '\t');
2534 }
2535 
2536 bool_t
2537 is_string_ok(char *buffer, int buflen)
2538 {
2539 	int i;
2540 
2541 	if (buffer == NULL)
2542 		return (FALSE);
2543 
2544 	for (i = 0; i < buflen; i++) {
2545 		if (!is_whitespace(buffer[i])) {
2546 			if (buffer[i] == POUND_SIGN)
2547 				return (TRUE);
2548 			else
2549 				return (FALSE);
2550 		}
2551 	}
2552 	return (TRUE);
2553 }
2554 
2555 /*
2556  * Returns true if the first string is contained at the beginning of the
2557  * second string. Otherwise returns false.
2558  */
2559 
2560 bool_t
2561 contains_string(const char *s1, const char *s2)
2562 {
2563 	return (strncasecmp(s1, s2, strlen(s1)) == 0);
2564 }
2565 
2566 /*
2567  * Returns the next character position in the second string, if the first
2568  * string is contained at the beginning of the second string. Otherwise
2569  * returns NULL.
2570  */
2571 
2572 const char *
2573 skip_string(const char *s1, const char *s2, int len)
2574 {
2575 	int len1 = strlen(s1);
2576 
2577 	if (len >= len1 && strncasecmp(s1, s2, strlen(s1)) == 0)
2578 		return (s2 + len1);
2579 	else
2580 		return (NULL);
2581 }
2582 
2583 /*
2584  * The second string is not necessarily null terminated.
2585  * same_string returns true if the second string matches the first.
2586  * Otherwise returns false.
2587  */
2588 
2589 bool_t
2590 same_string(const char *s1, const char *s2, int len)
2591 {
2592 	int len1 = strlen(s1);
2593 
2594 	return (len1 == len && strncasecmp(s1, s2, len1) == 0);
2595 }
2596 
2597 void
2598 report_error(const char	*str, const char *attr)
2599 {
2600 	char	fmt_buf[1024];
2601 	int	pos		= 0;
2602 
2603 	if (command_line_source != NULL) {
2604 		snprintf(fmt_buf, sizeof (fmt_buf), "Error parsing %s: ",
2605 			command_line_source);
2606 		pos = strlen(fmt_buf);
2607 	} else if (file_source != NULL) {
2608 		snprintf(fmt_buf, sizeof (fmt_buf), "Error parsing file '%s': ",
2609 			file_source);
2610 		pos = strlen(fmt_buf);
2611 	} else if (ldap_source != NULL) {
2612 		snprintf(fmt_buf, sizeof (fmt_buf), "Error for LDAP dn '%s': ",
2613 			ldap_source);
2614 		pos = strlen(fmt_buf);
2615 	}
2616 
2617 	if (start_line_num != 0) {
2618 		snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, "at line %d: ",
2619 			start_line_num);
2620 		pos += strlen(fmt_buf + pos);
2621 	}
2622 
2623 	if (attr != NULL) {
2624 		snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos,
2625 			"for attribute %s: ", attr);
2626 		pos += strlen(fmt_buf + pos);
2627 	}
2628 
2629 	if (cons != NULL) {
2630 		snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, "%s\n",
2631 			parse_error_msg[p_error]);
2632 		fprintf(cons, fmt_buf, str == NULL ? "" : str);
2633 	} else {
2634 		snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, "%s",
2635 			parse_error_msg[p_error]);
2636 		syslog(LOG_ERR, fmt_buf, str == NULL ? "" : str);
2637 	}
2638 }
2639 
2640 void
2641 report_error2(
2642 	const char	*str1,
2643 	const char	*str2)
2644 {
2645 	char	fmt_buf[1024];
2646 
2647 	if (cons != NULL) {
2648 		snprintf(fmt_buf, sizeof (fmt_buf),
2649 			"%s\n",  parse_error_msg[p_error]);
2650 		fprintf(cons, fmt_buf, str1, str2);
2651 	} else {
2652 		syslog(LOG_ERR, parse_error_msg[p_error], str1, str2);
2653 	}
2654 }
2655 
2656 void
2657 report_conn_error(
2658 	conn_error	e,
2659 	const char	*str1,
2660 	const char	*str2)
2661 {
2662 	char	fmt_buf[1024];
2663 
2664 	if (cons != NULL) {
2665 		snprintf(fmt_buf, sizeof (fmt_buf),
2666 			"%s\n",  conn_error_msg[e]);
2667 		fprintf(cons, fmt_buf,
2668 			str1 == NULL ? "" : str1,
2669 			str2 == NULL ? "" : str2);
2670 	} else {
2671 		syslog(LOG_ERR,
2672 			conn_error_msg[e],
2673 			str1 == NULL ? "" : str1,
2674 			str2 == NULL ? "" : str2);
2675 	}
2676 }
2677 
2678 void
2679 report_info(
2680 	const char	*str,
2681 	const char	*arg)
2682 {
2683 	if (cons != NULL) {
2684 		fputs(str, cons);
2685 		if (arg != NULL)
2686 			fputs(arg, cons);
2687 		fputs("\n", cons);
2688 	} else
2689 		syslog(LOG_INFO, str, arg);
2690 }
2691