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
47void append_dot(char **str);
48void	append_comma(char **str);
49bool_t make_full_dn(char **dn, const char *base);
50bool_t make_fqdn(__nis_object_dn_t *dn, const char *base);
51char *get_default_ldap_base(const char *domain);
52bool_t add_domain(char **objName, const char *domain);
53bool_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);
58void *s_malloc(size_t size);
59__nis_mapping_format_t *dup_format_mapping(
60	__nis_mapping_format_t *in);
61bool_t dup_mapping_element(__nis_mapping_element_t *in,
62	__nis_mapping_element_t *out);
63bool_t is_string_ok(char *, int);
64
65extern FILE *cons;
66
67/*
68 * FUNCTION:	free_parse_structs
69 *
70 *	Release the resources in parse results
71 *
72 */
73
74void
75free_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
97void
98initialize_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
161void
162free_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
192void
193free_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
253void
254free_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
354void
355free_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
386void
387free_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
422void
423free_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
466void
467free_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
491void
492free_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
534void
535free_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
584void
585free_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
631int
632read_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
729int
730finish_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
966void
967set_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 *
1074find_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
1085void
1086append_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
1101void
1102append_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
1130bool_t
1131make_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 */
1161bool_t
1162make_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
1200char *
1201get_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
1242bool_t
1243add_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
1275bool_t
1276dup_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
1317bool_t
1318dup_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 *
1392dup_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
1461bool_t
1462dup_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
1518bool_t
1519dup_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 *
1601dup_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 **
1653dup_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
1686bool_t
1687add_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
1722bool_t
1723add_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
1761const char *
1762get_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
1849const char *
1850get_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
1943const char *
1944skip_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
1997const char *
1998get_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
2189const char *
2190get_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
2291const char *
2292get_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
2355const char *
2356get_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 */
2424bool_t
2425validate_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
2437bool_t
2438validate_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
2458char *
2459s_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
2473char *
2474s_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
2494void *
2495s_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
2506void *
2507s_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
2515void *
2516s_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
2524char *
2525s_strdup(const char *s)
2526{
2527	return (s != NULL ? s_strndup(s, strlen(s)) : NULL);
2528}
2529
2530bool_t
2531is_whitespace(int c)
2532{
2533	return (c == ' ' || c == '\t');
2534}
2535
2536bool_t
2537is_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
2560bool_t
2561contains_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
2572const char *
2573skip_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
2589bool_t
2590same_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
2597void
2598report_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
2640void
2641report_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
2656void
2657report_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
2678void
2679report_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