xref: /openbsd-src/usr.sbin/ypldap/parse.y (revision 73492e0c7abc13d0fcf5a83c7f5cd157534d380a)
1*73492e0cSclaudio /*	$OpenBSD: parse.y,v 1.37 2023/07/18 13:06:33 claudio Exp $	*/
2f6242408Spyr 
3f6242408Spyr /*
4f6242408Spyr  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5f6242408Spyr  * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
6f6242408Spyr  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7f6242408Spyr  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
8f6242408Spyr  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
9f6242408Spyr  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
10f6242408Spyr  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
11f6242408Spyr  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
12f6242408Spyr  *
13f6242408Spyr  * Permission to use, copy, modify, and distribute this software for any
14f6242408Spyr  * purpose with or without fee is hereby granted, provided that the above
15f6242408Spyr  * copyright notice and this permission notice appear in all copies.
16f6242408Spyr  *
17f6242408Spyr  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
18f6242408Spyr  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
19f6242408Spyr  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
20f6242408Spyr  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21f6242408Spyr  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22f6242408Spyr  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
23f6242408Spyr  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24f6242408Spyr  */
25f6242408Spyr 
26f6242408Spyr %{
27f6242408Spyr #include <sys/types.h>
28f6242408Spyr #include <sys/time.h>
29f6242408Spyr #include <sys/queue.h>
30f6242408Spyr #include <sys/tree.h>
31f6242408Spyr #include <sys/socket.h>
32f6242408Spyr #include <sys/stat.h>
33f6242408Spyr 
34f6242408Spyr #include <netinet/in.h>
35f6242408Spyr #include <arpa/inet.h>
36f6242408Spyr 
37f6242408Spyr #include <ctype.h>
38f6242408Spyr #include <err.h>
39f6242408Spyr #include <errno.h>
40f6242408Spyr #include <event.h>
41f6242408Spyr #include <fcntl.h>
42f6242408Spyr #include <limits.h>
43f6242408Spyr #include <netdb.h>
44f6242408Spyr #include <pwd.h>
45f6242408Spyr #include <stdarg.h>
46f6242408Spyr #include <stdio.h>
47f6242408Spyr #include <stdlib.h>
48f6242408Spyr #include <string.h>
494a1d3eaaSsthen #include <syslog.h>
5085f89112Sjsing #include <tls.h>
51f6242408Spyr #include <unistd.h>
52f6242408Spyr 
53f6242408Spyr #include "ypldap.h"
54*73492e0cSclaudio #include "log.h"
55f6242408Spyr 
56f6242408Spyr TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
57f6242408Spyr static struct file {
58f6242408Spyr 	TAILQ_ENTRY(file)	 entry;
59f6242408Spyr 	FILE			*stream;
60f6242408Spyr 	char			*name;
61b83b389fSdenis 	size_t			 ungetpos;
62b83b389fSdenis 	size_t			 ungetsize;
63b83b389fSdenis 	u_char			*ungetbuf;
64b83b389fSdenis 	int			 eof_reached;
65f6242408Spyr 	int			 lineno;
66f6242408Spyr 	int			 errors;
67f6242408Spyr } *file, *topfile;
68f6242408Spyr struct file	*pushfile(const char *, int);
69f6242408Spyr int		 popfile(void);
70f6242408Spyr int		 check_file_secrecy(int, const char *);
71f6242408Spyr int		 yyparse(void);
72f6242408Spyr int		 yylex(void);
730f79392cSdoug int		 yyerror(const char *, ...)
740f79392cSdoug     __attribute__((__format__ (printf, 1, 2)))
750f79392cSdoug     __attribute__((__nonnull__ (1)));
76f6242408Spyr int		 kw_cmp(const void *, const void *);
77f6242408Spyr int		 lookup(char *);
78b83b389fSdenis int		 igetc(void);
79f6242408Spyr int		 lgetc(int);
80b83b389fSdenis void		 lungetc(int);
81f6242408Spyr int		 findeol(void);
82f6242408Spyr 
83f6242408Spyr TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
84f6242408Spyr struct sym {
85f6242408Spyr 	TAILQ_ENTRY(sym)	 entry;
86f6242408Spyr 	int			 used;
87f6242408Spyr 	int			 persist;
88f6242408Spyr 	char			*nam;
89f6242408Spyr 	char			*val;
90f6242408Spyr };
91f6242408Spyr int		 symset(const char *, const char *, int);
92f6242408Spyr char		*symget(const char *);
93f6242408Spyr 
94f6242408Spyr struct env		*conf = NULL;
95f6242408Spyr struct idm		*idm = NULL;
96f6242408Spyr static int		 errors = 0;
97f6242408Spyr 
98f6242408Spyr typedef struct {
99f6242408Spyr 	union {
100f6242408Spyr 		int64_t		 number;
101f6242408Spyr 		char		*string;
102f6242408Spyr 	} v;
103f6242408Spyr 	int lineno;
104f6242408Spyr } YYSTYPE;
105f6242408Spyr 
106f6242408Spyr %}
107f6242408Spyr 
108b8ccc478Sjmatthew %token	SERVER FILTER ATTRIBUTE BASEDN BINDDN GROUPDN BINDCRED MAPS CHANGE DOMAIN PROVIDE
109f6242408Spyr %token	USER GROUP TO EXPIRE HOME SHELL GECOS UID GID INTERVAL
110ec4ad443Saschrijver %token	PASSWD NAME FIXED LIST GROUPNAME GROUPPASSWD GROUPGID MAP
11132814761Sjmatthew %token	INCLUDE DIRECTORY CLASS PORT ERROR GROUPMEMBERS LDAPS TLS CAFILE
11240c94266Sjmatthew %token	BIND LOCAL PORTMAP BINDEXT CERTFILE KEYFILE
113f6242408Spyr %token	<v.string>	STRING
114f6242408Spyr %token  <v.number>	NUMBER
1156106e71cSaschrijver %type	<v.number>	opcode attribute
11632814761Sjmatthew %type	<v.number>	port
11732814761Sjmatthew %type	<v.number>	ssl
118f6242408Spyr 
119f6242408Spyr %%
120f6242408Spyr 
121f6242408Spyr grammar		: /* empty */
122f6242408Spyr 		| grammar '\n'
123f6242408Spyr 		| grammar include '\n'
124f6242408Spyr 		| grammar varset '\n'
125f6242408Spyr 		| grammar directory '\n'
126f6242408Spyr 		| grammar main '\n'
127f6242408Spyr 		| grammar error '\n'			{ file->errors++; }
128f6242408Spyr 		;
129f6242408Spyr 
130f6242408Spyr nl		: '\n' optnl
131f6242408Spyr 		;
132f6242408Spyr 
133f6242408Spyr optnl		: '\n' optnl
134f6242408Spyr 		| /* empty */
135f6242408Spyr 		;
136f6242408Spyr 
1376106e71cSaschrijver 
138f6242408Spyr include		: INCLUDE STRING			{
139f6242408Spyr 			struct file	*nfile;
140f6242408Spyr 
141b83b389fSdenis 			if ((nfile = pushfile($2, 1)) == NULL) {
142f6242408Spyr 				yyerror("failed to include file %s", $2);
143f6242408Spyr 				free($2);
144f6242408Spyr 				YYERROR;
145f6242408Spyr 			}
146f6242408Spyr 			free($2);
147f6242408Spyr 
148f6242408Spyr 			file = nfile;
149f6242408Spyr 			lungetc('\n');
150f6242408Spyr 		}
151f6242408Spyr 		;
152f6242408Spyr 
153f6242408Spyr varset		: STRING '=' STRING			{
1540c7b4ca6Sbenno 			char *s = $1;
1550c7b4ca6Sbenno 			while (*s++) {
1560c7b4ca6Sbenno 				if (isspace((unsigned char)*s)) {
1570c7b4ca6Sbenno 					yyerror("macro name cannot contain "
1580c7b4ca6Sbenno 					    "whitespace");
15916a0a906Skrw 					free($1);
16016a0a906Skrw 					free($3);
1610c7b4ca6Sbenno 					YYERROR;
1620c7b4ca6Sbenno 				}
1630c7b4ca6Sbenno 			}
164f6242408Spyr 			if (symset($1, $3, 0) == -1)
165f6242408Spyr 				fatal("cannot store variable");
166f6242408Spyr 			free($1);
167f6242408Spyr 			free($3);
168f6242408Spyr 		}
169f6242408Spyr 		;
170f6242408Spyr 
17132814761Sjmatthew port		: PORT STRING				{
17232814761Sjmatthew 			struct servent *servent;
17332814761Sjmatthew 
17432814761Sjmatthew 			servent = getservbyname($2, "tcp");
17532814761Sjmatthew 			if (servent == NULL) {
17632814761Sjmatthew 				yyerror("port %s is invalid", $2);
17732814761Sjmatthew 				free($2);
17832814761Sjmatthew 				YYERROR;
17932814761Sjmatthew 			}
18032814761Sjmatthew 			$$ = ntohs(servent->s_port);
18132814761Sjmatthew 			free($2);
18232814761Sjmatthew 		}
18332814761Sjmatthew 		| PORT NUMBER				{
1840ead3a23Sflorian 			if ($2 <= 0 || $2 > (int)USHRT_MAX) {
18532814761Sjmatthew 				yyerror("invalid port: %lld", $2);
18632814761Sjmatthew 				YYERROR;
18732814761Sjmatthew 			}
18832814761Sjmatthew 			$$ = $2;
18932814761Sjmatthew 		}
19032814761Sjmatthew 		| /* empty */				{
19132814761Sjmatthew 			$$ = 0;
19232814761Sjmatthew 		}
193f6242408Spyr 		;
194f6242408Spyr 
195f6242408Spyr opcode		: GROUP					{ $$ = 0; }
196f6242408Spyr 		| PASSWD				{ $$ = 1; }
197f6242408Spyr 		;
198f6242408Spyr 
1996106e71cSaschrijver 
200f6242408Spyr attribute	: NAME					{ $$ = 0; }
201f6242408Spyr 		| PASSWD				{ $$ = 1; }
202f6242408Spyr 		| UID					{ $$ = 2; }
203f6242408Spyr 		| GID					{ $$ = 3; }
204f6242408Spyr 		| CLASS					{ $$ = 4; }
205f6242408Spyr 		| CHANGE				{ $$ = 5; }
206f6242408Spyr 		| EXPIRE				{ $$ = 6; }
207f6242408Spyr 		| GECOS					{ $$ = 7; }
208f6242408Spyr 		| HOME					{ $$ = 8; }
209f6242408Spyr 		| SHELL					{ $$ = 9; }
210f6242408Spyr 		| GROUPNAME				{ $$ = 10; }
211f6242408Spyr 		| GROUPPASSWD				{ $$ = 11; }
212f6242408Spyr 		| GROUPGID				{ $$ = 12; }
213f6242408Spyr 		| GROUPMEMBERS				{ $$ = 13; }
214f6242408Spyr 		;
215f6242408Spyr 
216f6242408Spyr diropt		: BINDDN STRING				{
21740c94266Sjmatthew 			if (idm->idm_bindext != 0) {
21840c94266Sjmatthew 				yyerror("can't specify multiple bind types");
21940c94266Sjmatthew 				free($2);
22040c94266Sjmatthew 				YYERROR;
22140c94266Sjmatthew 			}
222f6242408Spyr 			idm->idm_flags |= F_NEEDAUTH;
223f6242408Spyr 			if (strlcpy(idm->idm_binddn, $2,
224f6242408Spyr 			    sizeof(idm->idm_binddn)) >=
225f6242408Spyr 			    sizeof(idm->idm_binddn)) {
226f6242408Spyr 				yyerror("directory binddn truncated");
227f6242408Spyr 				free($2);
228f6242408Spyr 				YYERROR;
229f6242408Spyr 			}
230f6242408Spyr 			free($2);
231f6242408Spyr 		}
232af720893Saschrijver 		| BINDCRED STRING			{
23340c94266Sjmatthew 			if (idm->idm_bindext != 0) {
23440c94266Sjmatthew 				yyerror("can't specify multiple bind types");
23540c94266Sjmatthew 				free($2);
23640c94266Sjmatthew 				YYERROR;
23740c94266Sjmatthew 			}
238af720893Saschrijver 			idm->idm_flags |= F_NEEDAUTH;
239af720893Saschrijver 			if (strlcpy(idm->idm_bindcred, $2,
240af720893Saschrijver 			    sizeof(idm->idm_bindcred)) >=
241af720893Saschrijver 			    sizeof(idm->idm_bindcred)) {
242af720893Saschrijver 				yyerror("directory bindcred truncated");
243af720893Saschrijver 				free($2);
244af720893Saschrijver 				YYERROR;
245af720893Saschrijver 			}
246af720893Saschrijver 			free($2);
247af720893Saschrijver 		}
24840c94266Sjmatthew 		| BINDEXT STRING			{
24940c94266Sjmatthew 			if (idm->idm_flags & F_NEEDAUTH) {
25040c94266Sjmatthew 				yyerror("can't specify multiple bind types");
25140c94266Sjmatthew 				free($2);
25240c94266Sjmatthew 				YYERROR;
25340c94266Sjmatthew 			}
25440c94266Sjmatthew 			idm->idm_flags |= F_NEEDAUTH;
25540c94266Sjmatthew 			idm->idm_bindext = 1;
25640c94266Sjmatthew 			if (strlcpy(idm->idm_bindextid, $2,
25740c94266Sjmatthew 			    sizeof(idm->idm_bindextid)) >=
25840c94266Sjmatthew 			    sizeof(idm->idm_bindextid)) {
25940c94266Sjmatthew 				yyerror("directory bindext truncated");
26040c94266Sjmatthew 				free($2);
26140c94266Sjmatthew 				YYERROR;
26240c94266Sjmatthew 			}
26340c94266Sjmatthew 			free($2);
26440c94266Sjmatthew 		}
26540c94266Sjmatthew 		| BINDEXT				{
26640c94266Sjmatthew 			if (idm->idm_flags & F_NEEDAUTH) {
26740c94266Sjmatthew 				yyerror("can't specify multiple bind types");
26840c94266Sjmatthew 				YYERROR;
26940c94266Sjmatthew 			}
27040c94266Sjmatthew 			idm->idm_flags |= F_NEEDAUTH;
27140c94266Sjmatthew 			idm->idm_bindext = 1;
27240c94266Sjmatthew 			idm->idm_bindextid[0] = '\0';
27340c94266Sjmatthew 		}
27440c94266Sjmatthew 		| CERTFILE STRING			{
27540c94266Sjmatthew 			if (idm->idm_tls_config == NULL) {
27640c94266Sjmatthew 				yyerror("can't set cert file without tls"
27740c94266Sjmatthew 				    " enabled");
27840c94266Sjmatthew 				free($2);
27940c94266Sjmatthew 				YYERROR;
28040c94266Sjmatthew 			}
28140c94266Sjmatthew 			if (tls_config_set_cert_file(idm->idm_tls_config, $2)
28240c94266Sjmatthew 			    == -1) {
28340c94266Sjmatthew 				yyerror("tls set cert file failed: %s",
28440c94266Sjmatthew 				    tls_config_error(
28540c94266Sjmatthew 				    idm->idm_tls_config));
28640c94266Sjmatthew 				free($2);
28740c94266Sjmatthew 				YYERROR;
28840c94266Sjmatthew 			}
28940c94266Sjmatthew 		}
29040c94266Sjmatthew 		| KEYFILE STRING			{
29140c94266Sjmatthew 			if (idm->idm_tls_config == NULL) {
29240c94266Sjmatthew 				yyerror("can't set key file without tls"
29340c94266Sjmatthew 				    " enabled");
29440c94266Sjmatthew 				free($2);
29540c94266Sjmatthew 				YYERROR;
29640c94266Sjmatthew 			}
29740c94266Sjmatthew 			if (tls_config_set_key_file(idm->idm_tls_config, $2)
29840c94266Sjmatthew 			    == -1) {
29940c94266Sjmatthew 				yyerror("tls set key file failed: %s",
30040c94266Sjmatthew 				    tls_config_error(
30140c94266Sjmatthew 				    idm->idm_tls_config));
30240c94266Sjmatthew 				free($2);
30340c94266Sjmatthew 				YYERROR;
30440c94266Sjmatthew 			}
30540c94266Sjmatthew 		}
306af720893Saschrijver 		| BASEDN STRING			{
307af720893Saschrijver 			if (strlcpy(idm->idm_basedn, $2,
308af720893Saschrijver 			    sizeof(idm->idm_basedn)) >=
309af720893Saschrijver 			    sizeof(idm->idm_basedn)) {
310ec4ad443Saschrijver 				yyerror("directory basedn truncated");
311af720893Saschrijver 				free($2);
312af720893Saschrijver 				YYERROR;
313af720893Saschrijver 			}
314af720893Saschrijver 			free($2);
315af720893Saschrijver 		}
316b8ccc478Sjmatthew 		| GROUPDN STRING		{
317b8ccc478Sjmatthew 			if(strlcpy(idm->idm_groupdn, $2,
318b8ccc478Sjmatthew 			    sizeof(idm->idm_groupdn)) >=
319b8ccc478Sjmatthew 			    sizeof(idm->idm_groupdn)) {
320b8ccc478Sjmatthew 				yyerror("directory groupdn truncated");
321b8ccc478Sjmatthew 				free($2);
322b8ccc478Sjmatthew 				YYERROR;
323b8ccc478Sjmatthew 			}
324b8ccc478Sjmatthew 			free($2);
325b8ccc478Sjmatthew 		}
326f6242408Spyr 		| opcode FILTER STRING			{
327f6242408Spyr 			if (strlcpy(idm->idm_filters[$1], $3,
328f6242408Spyr 			    sizeof(idm->idm_filters[$1])) >=
329f6242408Spyr 			    sizeof(idm->idm_filters[$1])) {
330f6242408Spyr 				yyerror("filter truncated");
331f6242408Spyr 				free($3);
332f6242408Spyr 				YYERROR;
333f6242408Spyr 			}
334f6242408Spyr 			free($3);
335f6242408Spyr 		}
336f6242408Spyr 		| ATTRIBUTE attribute MAPS TO STRING	{
337f6242408Spyr 			if (strlcpy(idm->idm_attrs[$2], $5,
338f6242408Spyr 			    sizeof(idm->idm_attrs[$2])) >=
339f6242408Spyr 			    sizeof(idm->idm_attrs[$2])) {
340f6242408Spyr 				yyerror("attribute truncated");
341f6242408Spyr 				free($5);
342f6242408Spyr 				YYERROR;
343f6242408Spyr 			}
344f6242408Spyr 			free($5);
345f6242408Spyr 		}
346f6242408Spyr 		| FIXED ATTRIBUTE attribute STRING	{
347f6242408Spyr 			if (strlcpy(idm->idm_attrs[$3], $4,
348f6242408Spyr 			    sizeof(idm->idm_attrs[$3])) >=
349f6242408Spyr 			    sizeof(idm->idm_attrs[$3])) {
350f6242408Spyr 				yyerror("attribute truncated");
351f6242408Spyr 				free($4);
352f6242408Spyr 				YYERROR;
353f6242408Spyr 			}
354f6242408Spyr 			idm->idm_flags |= F_FIXED_ATTR($3);
355f6242408Spyr 			free($4);
356f6242408Spyr 		}
357ec4ad443Saschrijver 		| LIST attribute MAPS TO STRING	{
358ec4ad443Saschrijver 			if (strlcpy(idm->idm_attrs[$2], $5,
359ec4ad443Saschrijver 			    sizeof(idm->idm_attrs[$2])) >=
360ec4ad443Saschrijver 			    sizeof(idm->idm_attrs[$2])) {
361ec4ad443Saschrijver 				yyerror("attribute truncated");
362ec4ad443Saschrijver 				free($5);
363ec4ad443Saschrijver 				YYERROR;
364ec4ad443Saschrijver 			}
365ec4ad443Saschrijver 			idm->idm_list |= F_LIST($2);
366ec4ad443Saschrijver 			free($5);
367ec4ad443Saschrijver 		}
368f6242408Spyr 		;
369f6242408Spyr 
37032814761Sjmatthew ssl		: /* empty */				{ $$ = 0; }
37132814761Sjmatthew 		| LDAPS					{ $$ = F_SSL; }
37232814761Sjmatthew 		| TLS					{ $$ = F_STARTTLS; }
37332814761Sjmatthew 		;
37432814761Sjmatthew 
37532814761Sjmatthew directory	: DIRECTORY STRING port ssl {
376f6242408Spyr 			if ((idm = calloc(1, sizeof(*idm))) == NULL)
377f6242408Spyr 				fatal(NULL);
378db474592Saschrijver 			idm->idm_id = conf->sc_maxid++;
379f6242408Spyr 
380db474592Saschrijver 			if (strlcpy(idm->idm_name, $2,
381db474592Saschrijver 			    sizeof(idm->idm_name)) >=
382db474592Saschrijver 			    sizeof(idm->idm_name)) {
383db474592Saschrijver 				yyerror("attribute truncated");
384f6242408Spyr 				free($2);
385f6242408Spyr 				YYERROR;
386f6242408Spyr 			}
387f6242408Spyr 			free($2);
38832814761Sjmatthew 
38932814761Sjmatthew 			idm->idm_port = $3;
39032814761Sjmatthew 
39132814761Sjmatthew 			if ($4 != 0) {
39232814761Sjmatthew 				if (tls_init()) {
39332814761Sjmatthew 					yyerror("tls init failed");
39432814761Sjmatthew 					YYERROR;
39532814761Sjmatthew 				}
39632814761Sjmatthew 
39732814761Sjmatthew 				idm->idm_flags |= $4;
39832814761Sjmatthew 				idm->idm_tls_config = tls_config_new();
39932814761Sjmatthew 				if (idm->idm_tls_config == NULL) {
40032814761Sjmatthew 					yyerror("tls config failed");
40132814761Sjmatthew 					YYERROR;
40232814761Sjmatthew 				}
40332814761Sjmatthew 
40432814761Sjmatthew 				if (tls_config_set_protocols(
40532814761Sjmatthew 				    idm->idm_tls_config,
40632814761Sjmatthew 				    TLS_PROTOCOLS_ALL) == -1) {
40732814761Sjmatthew 					yyerror("tls set protocols failed: %s",
40832814761Sjmatthew 					    tls_config_error(
40932814761Sjmatthew 					    idm->idm_tls_config));
41032814761Sjmatthew 					tls_config_free(idm->idm_tls_config);
41132814761Sjmatthew 					idm->idm_tls_config = NULL;
41232814761Sjmatthew 					YYERROR;
41332814761Sjmatthew 				}
41432814761Sjmatthew 				if (tls_config_set_ciphers(idm->idm_tls_config,
41532814761Sjmatthew 				    "compat") == -1) {
41632814761Sjmatthew 					yyerror("tls set ciphers failed: %s",
41732814761Sjmatthew 					    tls_config_error(
41832814761Sjmatthew 					    idm->idm_tls_config));
41932814761Sjmatthew 					tls_config_free(idm->idm_tls_config);
42032814761Sjmatthew 					idm->idm_tls_config = NULL;
42132814761Sjmatthew 					YYERROR;
42232814761Sjmatthew 				}
42332814761Sjmatthew 
42432814761Sjmatthew 				if (tls_config_set_ca_file(idm->idm_tls_config,
42532814761Sjmatthew 				    conf->sc_cafile) == -1) {
42632814761Sjmatthew 					yyerror("tls set CA bundle failed: %s",
42732814761Sjmatthew 					    tls_config_error(
42832814761Sjmatthew 					    idm->idm_tls_config));
42932814761Sjmatthew 					tls_config_free(idm->idm_tls_config);
43032814761Sjmatthew 					idm->idm_tls_config = NULL;
43132814761Sjmatthew 					YYERROR;
43232814761Sjmatthew 				}
43332814761Sjmatthew 			}
43432814761Sjmatthew 
435f6242408Spyr 		} '{' optnl diropts '}'			{
436f6242408Spyr 			TAILQ_INSERT_TAIL(&conf->sc_idms, idm, idm_entry);
437f6242408Spyr 			idm = NULL;
438f6242408Spyr 		}
439f6242408Spyr 		;
440f6242408Spyr 
441f6242408Spyr main		: INTERVAL NUMBER			{
442f6242408Spyr 			conf->sc_conf_tv.tv_sec = $2;
443f6242408Spyr 			conf->sc_conf_tv.tv_usec = 0;
444f6242408Spyr 		}
445f6242408Spyr 		| DOMAIN STRING				{
446f6242408Spyr 			if (strlcpy(conf->sc_domainname, $2,
447f6242408Spyr 			    sizeof(conf->sc_domainname)) >=
448f6242408Spyr 			    sizeof(conf->sc_domainname)) {
449f6242408Spyr 				yyerror("domainname truncated");
450f6242408Spyr 				free($2);
451f6242408Spyr 				YYERROR;
452f6242408Spyr 			}
453f6242408Spyr 			free($2);
454f6242408Spyr 		}
455f6242408Spyr 		| PROVIDE MAP STRING			{
456f6242408Spyr 			if (strcmp($3, "passwd.byname") == 0)
457f6242408Spyr 				conf->sc_flags |= YPMAP_PASSWD_BYNAME;
458f6242408Spyr 			else if (strcmp($3, "passwd.byuid") == 0)
459f6242408Spyr 				conf->sc_flags |= YPMAP_PASSWD_BYUID;
460f6242408Spyr 			else if (strcmp($3, "master.passwd.byname") == 0)
461f6242408Spyr 				conf->sc_flags |= YPMAP_MASTER_PASSWD_BYNAME;
462f6242408Spyr 			else if (strcmp($3, "master.passwd.byuid") == 0)
463f6242408Spyr 				conf->sc_flags |= YPMAP_MASTER_PASSWD_BYUID;
464f6242408Spyr 			else if (strcmp($3, "group.byname") == 0)
465f6242408Spyr 				conf->sc_flags |= YPMAP_GROUP_BYNAME;
466f6242408Spyr 			else if (strcmp($3, "group.bygid") == 0)
467f6242408Spyr 				conf->sc_flags |= YPMAP_GROUP_BYGID;
46833318bf8Saschrijver 			else if (strcmp($3, "netid.byname") == 0)
46933318bf8Saschrijver 				conf->sc_flags |= YPMAP_NETID_BYNAME;
470f6242408Spyr 			else {
471f6242408Spyr 				yyerror("unsupported map type: %s", $3);
472f6242408Spyr 				free($3);
473f6242408Spyr 				YYERROR;
474f6242408Spyr 			}
475f6242408Spyr 			free($3);
476f6242408Spyr 		}
47732814761Sjmatthew 		| CAFILE STRING				{
47832814761Sjmatthew 			free(conf->sc_cafile);
47932814761Sjmatthew 			conf->sc_cafile = $2;
48032814761Sjmatthew 		}
48156f45a56Sjmatthew 		| BIND LOCAL				{
48256f45a56Sjmatthew 			conf->sc_bind_mode = BIND_MODE_LOCAL;
48356f45a56Sjmatthew 		}
48456f45a56Sjmatthew 		| BIND PORTMAP				{
48556f45a56Sjmatthew 			conf->sc_bind_mode = BIND_MODE_PORTMAP;
48656f45a56Sjmatthew 		}
487f6242408Spyr 		;
488f6242408Spyr 
489f6242408Spyr diropts		: diropts diropt nl
490f6242408Spyr 		| diropt optnl
491f6242408Spyr 		;
4926106e71cSaschrijver 
493f6242408Spyr %%
494f6242408Spyr 
495f6242408Spyr struct keywords {
496f6242408Spyr 	const char	*k_name;
497f6242408Spyr 	int		 k_val;
498f6242408Spyr };
499f6242408Spyr 
500f6242408Spyr int
yyerror(const char * fmt,...)501f6242408Spyr yyerror(const char *fmt, ...)
502f6242408Spyr {
503f6242408Spyr 	va_list		 ap;
504cd8337bcSbluhm 	char		*msg;
505f6242408Spyr 
506f6242408Spyr 	file->errors++;
507f6242408Spyr 	va_start(ap, fmt);
508cd8337bcSbluhm 	if (vasprintf(&msg, fmt, ap) == -1)
509cd8337bcSbluhm 		fatalx("yyerror vasprintf");
510f6242408Spyr 	va_end(ap);
511cd8337bcSbluhm 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
512cd8337bcSbluhm 	free(msg);
513f6242408Spyr 	return (0);
514f6242408Spyr }
515f6242408Spyr 
516f6242408Spyr int
kw_cmp(const void * k,const void * e)517f6242408Spyr kw_cmp(const void *k, const void *e)
518f6242408Spyr {
519f6242408Spyr 	return (strcmp(k, ((const struct keywords *)e)->k_name));
520f6242408Spyr }
521f6242408Spyr 
522f6242408Spyr int
lookup(char * s)523f6242408Spyr lookup(char *s)
524f6242408Spyr {
525f6242408Spyr 	/* this has to be sorted always */
526f6242408Spyr 	static const struct keywords keywords[] = {
527f6242408Spyr 		{ "attribute",		ATTRIBUTE },
528af720893Saschrijver 		{ "basedn",		BASEDN },
52956f45a56Sjmatthew 		{ "bind",		BIND },
530af720893Saschrijver 		{ "bindcred",		BINDCRED },
531f6242408Spyr 		{ "binddn",		BINDDN },
53240c94266Sjmatthew 		{ "bindext",		BINDEXT },
53332814761Sjmatthew 		{ "cafile",		CAFILE },
53440c94266Sjmatthew 		{ "certfile",		CERTFILE },
535f6242408Spyr 		{ "change",		CHANGE },
536f6242408Spyr 		{ "class",		CLASS },
537f6242408Spyr 		{ "directory",		DIRECTORY },
538f6242408Spyr 		{ "domain",		DOMAIN },
539f6242408Spyr 		{ "expire",		EXPIRE },
540f6242408Spyr 		{ "filter",		FILTER },
541f6242408Spyr 		{ "fixed",		FIXED },
542f6242408Spyr 		{ "gecos",		GECOS },
543f6242408Spyr 		{ "gid",		GID },
544f6242408Spyr 		{ "group",		GROUP },
545b8ccc478Sjmatthew 		{ "groupdn",		GROUPDN },
546f6242408Spyr 		{ "groupgid",		GROUPGID },
547f6242408Spyr 		{ "groupmembers",	GROUPMEMBERS },
548f6242408Spyr 		{ "groupname",		GROUPNAME },
549f6242408Spyr 		{ "grouppasswd",	GROUPPASSWD },
550f6242408Spyr 		{ "home",		HOME },
551f6242408Spyr 		{ "include",		INCLUDE },
552f6242408Spyr 		{ "interval",		INTERVAL },
55340c94266Sjmatthew 		{ "keyfile",		KEYFILE },
55432814761Sjmatthew 		{ "ldaps",		LDAPS },
555ec4ad443Saschrijver 		{ "list",		LIST },
55656f45a56Sjmatthew 		{ "local",		LOCAL },
557f6242408Spyr 		{ "map",		MAP },
558f6242408Spyr 		{ "maps",		MAPS },
559f6242408Spyr 		{ "name",		NAME },
560f6242408Spyr 		{ "passwd",		PASSWD },
561f6242408Spyr 		{ "port",		PORT },
56256f45a56Sjmatthew 		{ "portmap",		PORTMAP },
563f6242408Spyr 		{ "provide",		PROVIDE },
564f6242408Spyr 		{ "server",		SERVER },
565f6242408Spyr 		{ "shell",		SHELL },
56632814761Sjmatthew 		{ "tls",		TLS },
567f6242408Spyr 		{ "to",			TO },
568f6242408Spyr 		{ "uid",		UID },
569f6242408Spyr 		{ "user",		USER },
570f6242408Spyr 	};
571f6242408Spyr 	const struct keywords	*p;
572f6242408Spyr 
573f6242408Spyr 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
574f6242408Spyr 	    sizeof(keywords[0]), kw_cmp);
575f6242408Spyr 
576f6242408Spyr 	if (p)
577f6242408Spyr 		return (p->k_val);
578f6242408Spyr 	else
579f6242408Spyr 		return (STRING);
580f6242408Spyr }
581f6242408Spyr 
582b83b389fSdenis #define START_EXPAND	1
583b83b389fSdenis #define DONE_EXPAND	2
584f6242408Spyr 
585b83b389fSdenis static int	expanding;
586b83b389fSdenis 
587b83b389fSdenis int
igetc(void)588b83b389fSdenis igetc(void)
589b83b389fSdenis {
590b83b389fSdenis 	int	c;
591b83b389fSdenis 
592b83b389fSdenis 	while (1) {
593b83b389fSdenis 		if (file->ungetpos > 0)
594b83b389fSdenis 			c = file->ungetbuf[--file->ungetpos];
595b83b389fSdenis 		else
596b83b389fSdenis 			c = getc(file->stream);
597b83b389fSdenis 
598b83b389fSdenis 		if (c == START_EXPAND)
599b83b389fSdenis 			expanding = 1;
600b83b389fSdenis 		else if (c == DONE_EXPAND)
601b83b389fSdenis 			expanding = 0;
602b83b389fSdenis 		else
603b83b389fSdenis 			break;
604b83b389fSdenis 	}
605b83b389fSdenis 	return (c);
606b83b389fSdenis }
607f6242408Spyr 
608f6242408Spyr int
lgetc(int quotec)609f6242408Spyr lgetc(int quotec)
610f6242408Spyr {
611f6242408Spyr 	int		c, next;
612f6242408Spyr 
613f6242408Spyr 	if (quotec) {
614b83b389fSdenis 		if ((c = igetc()) == EOF) {
615f6242408Spyr 			yyerror("reached end of file while parsing "
616f6242408Spyr 			    "quoted string");
617f6242408Spyr 			if (file == topfile || popfile() == EOF)
618f6242408Spyr 				return (EOF);
619f6242408Spyr 			return (quotec);
620f6242408Spyr 		}
621f6242408Spyr 		return (c);
622f6242408Spyr 	}
623f6242408Spyr 
624b83b389fSdenis 	while ((c = igetc()) == '\\') {
625b83b389fSdenis 		next = igetc();
626f6242408Spyr 		if (next != '\n') {
627f6242408Spyr 			c = next;
628f6242408Spyr 			break;
629f6242408Spyr 		}
630f6242408Spyr 		yylval.lineno = file->lineno;
631f6242408Spyr 		file->lineno++;
632f6242408Spyr 	}
633f6242408Spyr 
634b83b389fSdenis 	if (c == EOF) {
635b83b389fSdenis 		/*
636b83b389fSdenis 		 * Fake EOL when hit EOF for the first time. This gets line
637b83b389fSdenis 		 * count right if last line in included file is syntactically
638b83b389fSdenis 		 * invalid and has no newline.
639b83b389fSdenis 		 */
640b83b389fSdenis 		if (file->eof_reached == 0) {
641b83b389fSdenis 			file->eof_reached = 1;
642b83b389fSdenis 			return ('\n');
643b83b389fSdenis 		}
644f6242408Spyr 		while (c == EOF) {
645f6242408Spyr 			if (file == topfile || popfile() == EOF)
646f6242408Spyr 				return (EOF);
647b83b389fSdenis 			c = igetc();
648b83b389fSdenis 		}
649f6242408Spyr 	}
650f6242408Spyr 	return (c);
651f6242408Spyr }
652f6242408Spyr 
653b83b389fSdenis void
lungetc(int c)654f6242408Spyr lungetc(int c)
655f6242408Spyr {
656f6242408Spyr 	if (c == EOF)
657b83b389fSdenis 		return;
658b83b389fSdenis 
659b83b389fSdenis 	if (file->ungetpos >= file->ungetsize) {
660b83b389fSdenis 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
661b83b389fSdenis 		if (p == NULL)
662b83b389fSdenis 			err(1, "lungetc");
663b83b389fSdenis 		file->ungetbuf = p;
664b83b389fSdenis 		file->ungetsize *= 2;
665f6242408Spyr 	}
666b83b389fSdenis 	file->ungetbuf[file->ungetpos++] = c;
667f6242408Spyr }
668f6242408Spyr 
669f6242408Spyr int
findeol(void)670f6242408Spyr findeol(void)
671f6242408Spyr {
672f6242408Spyr 	int	c;
673f6242408Spyr 
674f6242408Spyr 	/* skip to either EOF or the first real EOL */
675f6242408Spyr 	while (1) {
676f6242408Spyr 		c = lgetc(0);
677f6242408Spyr 		if (c == '\n') {
678f6242408Spyr 			file->lineno++;
679f6242408Spyr 			break;
680f6242408Spyr 		}
681f6242408Spyr 		if (c == EOF)
682f6242408Spyr 			break;
683f6242408Spyr 	}
684f6242408Spyr 	return (ERROR);
685f6242408Spyr }
686f6242408Spyr 
687f6242408Spyr int
yylex(void)688f6242408Spyr yylex(void)
689f6242408Spyr {
69008f6ba19Snaddy 	char	 buf[8096];
69108f6ba19Snaddy 	char	*p, *val;
692f6242408Spyr 	int	 quotec, next, c;
693f6242408Spyr 	int	 token;
694f6242408Spyr 
695f6242408Spyr top:
696f6242408Spyr 	p = buf;
697f6242408Spyr 	while ((c = lgetc(0)) == ' ' || c == '\t')
698f6242408Spyr 		; /* nothing */
699f6242408Spyr 
700f6242408Spyr 	yylval.lineno = file->lineno;
701f6242408Spyr 	if (c == '#')
702f6242408Spyr 		while ((c = lgetc(0)) != '\n' && c != EOF)
703f6242408Spyr 			; /* nothing */
704b83b389fSdenis 	if (c == '$' && !expanding) {
705f6242408Spyr 		while (1) {
706f6242408Spyr 			if ((c = lgetc(0)) == EOF)
707f6242408Spyr 				return (0);
708f6242408Spyr 
709f6242408Spyr 			if (p + 1 >= buf + sizeof(buf) - 1) {
710f6242408Spyr 				yyerror("string too long");
711f6242408Spyr 				return (findeol());
712f6242408Spyr 			}
713f6242408Spyr 			if (isalnum(c) || c == '_') {
714015d7b4dSbenno 				*p++ = c;
715f6242408Spyr 				continue;
716f6242408Spyr 			}
717f6242408Spyr 			*p = '\0';
718f6242408Spyr 			lungetc(c);
719f6242408Spyr 			break;
720f6242408Spyr 		}
721f6242408Spyr 		val = symget(buf);
722f6242408Spyr 		if (val == NULL) {
723f6242408Spyr 			yyerror("macro '%s' not defined", buf);
724f6242408Spyr 			return (findeol());
725f6242408Spyr 		}
726b83b389fSdenis 		p = val + strlen(val) - 1;
727b83b389fSdenis 		lungetc(DONE_EXPAND);
728b83b389fSdenis 		while (p >= val) {
72908f6ba19Snaddy 			lungetc((unsigned char)*p);
730b83b389fSdenis 			p--;
731b83b389fSdenis 		}
732b83b389fSdenis 		lungetc(START_EXPAND);
733f6242408Spyr 		goto top;
734f6242408Spyr 	}
735f6242408Spyr 
736f6242408Spyr 	switch (c) {
737f6242408Spyr 	case '\'':
738f6242408Spyr 	case '"':
739f6242408Spyr 		quotec = c;
740f6242408Spyr 		while (1) {
741f6242408Spyr 			if ((c = lgetc(quotec)) == EOF)
742f6242408Spyr 				return (0);
743f6242408Spyr 			if (c == '\n') {
744f6242408Spyr 				file->lineno++;
745f6242408Spyr 				continue;
746f6242408Spyr 			} else if (c == '\\') {
747f6242408Spyr 				if ((next = lgetc(quotec)) == EOF)
748f6242408Spyr 					return (0);
749a1533359Ssashan 				if (next == quotec || next == ' ' ||
750a1533359Ssashan 				    next == '\t')
751f6242408Spyr 					c = next;
752daf24110Shenning 				else if (next == '\n') {
753daf24110Shenning 					file->lineno++;
754f6242408Spyr 					continue;
755daf24110Shenning 				} else
756f6242408Spyr 					lungetc(next);
757f6242408Spyr 			} else if (c == quotec) {
758f6242408Spyr 				*p = '\0';
759f6242408Spyr 				break;
76041eef22fSjsg 			} else if (c == '\0') {
76141eef22fSjsg 				yyerror("syntax error");
76241eef22fSjsg 				return (findeol());
763f6242408Spyr 			}
764f6242408Spyr 			if (p + 1 >= buf + sizeof(buf) - 1) {
765f6242408Spyr 				yyerror("string too long");
766f6242408Spyr 				return (findeol());
767f6242408Spyr 			}
768015d7b4dSbenno 			*p++ = c;
769f6242408Spyr 		}
770f6242408Spyr 		yylval.v.string = strdup(buf);
771f6242408Spyr 		if (yylval.v.string == NULL)
772a062aa9dSkrw 			err(1, "%s", __func__);
773f6242408Spyr 		return (STRING);
774f6242408Spyr 	}
775f6242408Spyr 
776f6242408Spyr #define allowed_to_end_number(x) \
777f6242408Spyr 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
778f6242408Spyr 
779f6242408Spyr 	if (c == '-' || isdigit(c)) {
780f6242408Spyr 		do {
781f6242408Spyr 			*p++ = c;
782915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
783f6242408Spyr 				yyerror("string too long");
784f6242408Spyr 				return (findeol());
785f6242408Spyr 			}
786f6242408Spyr 		} while ((c = lgetc(0)) != EOF && isdigit(c));
787f6242408Spyr 		lungetc(c);
788f6242408Spyr 		if (p == buf + 1 && buf[0] == '-')
789f6242408Spyr 			goto nodigits;
790f6242408Spyr 		if (c == EOF || allowed_to_end_number(c)) {
791f6242408Spyr 			const char *errstr = NULL;
792f6242408Spyr 
793f6242408Spyr 			*p = '\0';
794f6242408Spyr 			yylval.v.number = strtonum(buf, LLONG_MIN,
795f6242408Spyr 			    LLONG_MAX, &errstr);
796f6242408Spyr 			if (errstr) {
797f6242408Spyr 				yyerror("\"%s\" invalid number: %s",
798f6242408Spyr 				    buf, errstr);
799f6242408Spyr 				return (findeol());
800f6242408Spyr 			}
801f6242408Spyr 			return (NUMBER);
802f6242408Spyr 		} else {
803f6242408Spyr nodigits:
804f6242408Spyr 			while (p > buf + 1)
80508f6ba19Snaddy 				lungetc((unsigned char)*--p);
80608f6ba19Snaddy 			c = (unsigned char)*--p;
807f6242408Spyr 			if (c == '-')
808f6242408Spyr 				return (c);
809f6242408Spyr 		}
810f6242408Spyr 	}
811f6242408Spyr 
812f6242408Spyr #define allowed_in_string(x) \
813f6242408Spyr 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
814f6242408Spyr 	x != '{' && x != '}' && x != '<' && x != '>' && \
815f6242408Spyr 	x != '!' && x != '=' && x != '#' && \
816f6242408Spyr 	x != ','))
817f6242408Spyr 
818f6242408Spyr 	if (isalnum(c) || c == ':' || c == '_') {
819f6242408Spyr 		do {
820f6242408Spyr 			*p++ = c;
821915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
822f6242408Spyr 				yyerror("string too long");
823f6242408Spyr 				return (findeol());
824f6242408Spyr 			}
825f6242408Spyr 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
826f6242408Spyr 		lungetc(c);
827f6242408Spyr 		*p = '\0';
828f6242408Spyr 		if ((token = lookup(buf)) == STRING)
829f6242408Spyr 			if ((yylval.v.string = strdup(buf)) == NULL)
830a062aa9dSkrw 				err(1, "%s", __func__);
831f6242408Spyr 		return (token);
832f6242408Spyr 	}
833f6242408Spyr 	if (c == '\n') {
834f6242408Spyr 		yylval.lineno = file->lineno;
835f6242408Spyr 		file->lineno++;
836f6242408Spyr 	}
837f6242408Spyr 	if (c == EOF)
838f6242408Spyr 		return (0);
839f6242408Spyr 	return (c);
840f6242408Spyr }
841f6242408Spyr 
842f6242408Spyr int
check_file_secrecy(int fd,const char * fname)843f6242408Spyr check_file_secrecy(int fd, const char *fname)
844f6242408Spyr {
845f6242408Spyr 	struct stat	st;
846f6242408Spyr 
847f6242408Spyr 	if (fstat(fd, &st)) {
848f6242408Spyr 		log_warn("cannot stat %s", fname);
849f6242408Spyr 		return (-1);
850f6242408Spyr 	}
851f6242408Spyr 	if (st.st_uid != 0 && st.st_uid != getuid()) {
852f6242408Spyr 		log_warnx("%s: owner not root or current user", fname);
853f6242408Spyr 		return (-1);
854f6242408Spyr 	}
8557140c133Shenning 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
8567140c133Shenning 		log_warnx("%s: group writable or world read/writable", fname);
857f6242408Spyr 		return (-1);
858f6242408Spyr 	}
859f6242408Spyr 	return (0);
860f6242408Spyr }
861f6242408Spyr 
862f6242408Spyr struct file *
pushfile(const char * name,int secret)863f6242408Spyr pushfile(const char *name, int secret)
864f6242408Spyr {
865f6242408Spyr 	struct file	*nfile;
866f6242408Spyr 
8677fc93de0Stobias 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
8686a3d55f9Skrw 		log_warn("%s", __func__);
869f6242408Spyr 		return (NULL);
870f6242408Spyr 	}
8717fc93de0Stobias 	if ((nfile->name = strdup(name)) == NULL) {
8726a3d55f9Skrw 		log_warn("%s", __func__);
8737fc93de0Stobias 		free(nfile);
8747fc93de0Stobias 		return (NULL);
8757fc93de0Stobias 	}
876f6242408Spyr 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
8776a3d55f9Skrw 		log_warn("%s: %s", __func__, nfile->name);
878f6242408Spyr 		free(nfile->name);
879f6242408Spyr 		free(nfile);
880f6242408Spyr 		return (NULL);
881f6242408Spyr 	} else if (secret &&
882f6242408Spyr 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
883f6242408Spyr 		fclose(nfile->stream);
884f6242408Spyr 		free(nfile->name);
885f6242408Spyr 		free(nfile);
886f6242408Spyr 		return (NULL);
887f6242408Spyr 	}
888b83b389fSdenis 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
889b83b389fSdenis 	nfile->ungetsize = 16;
890b83b389fSdenis 	nfile->ungetbuf = malloc(nfile->ungetsize);
891b83b389fSdenis 	if (nfile->ungetbuf == NULL) {
8926a3d55f9Skrw 		log_warn("%s", __func__);
893b83b389fSdenis 		fclose(nfile->stream);
894b83b389fSdenis 		free(nfile->name);
895b83b389fSdenis 		free(nfile);
896b83b389fSdenis 		return (NULL);
897b83b389fSdenis 	}
898f6242408Spyr 	TAILQ_INSERT_TAIL(&files, nfile, entry);
899f6242408Spyr 	return (nfile);
900f6242408Spyr }
901f6242408Spyr 
902f6242408Spyr int
popfile(void)903f6242408Spyr popfile(void)
904f6242408Spyr {
905f6242408Spyr 	struct file	*prev;
906f6242408Spyr 
907f6242408Spyr 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
908f6242408Spyr 		prev->errors += file->errors;
909f6242408Spyr 
910f6242408Spyr 	TAILQ_REMOVE(&files, file, entry);
911f6242408Spyr 	fclose(file->stream);
912f6242408Spyr 	free(file->name);
913b83b389fSdenis 	free(file->ungetbuf);
914f6242408Spyr 	free(file);
915f6242408Spyr 	file = prev;
916f6242408Spyr 	return (file ? 0 : EOF);
917f6242408Spyr }
918f6242408Spyr 
919f6242408Spyr int
parse_config(struct env * x_conf,const char * filename,int opts)920f6242408Spyr parse_config(struct env *x_conf, const char *filename, int opts)
921f6242408Spyr {
922f6242408Spyr 	struct sym	*sym, *next;
923f6242408Spyr 
924f6242408Spyr 	conf = x_conf;
925f6242408Spyr 	bzero(conf, sizeof(*conf));
926f6242408Spyr 
927f6242408Spyr 	TAILQ_INIT(&conf->sc_idms);
928f6242408Spyr 	conf->sc_conf_tv.tv_sec = DEFAULT_INTERVAL;
929f6242408Spyr 	conf->sc_conf_tv.tv_usec = 0;
930fb0a89eeStedu 	conf->sc_cafile = strdup(tls_default_ca_cert_file());
93132814761Sjmatthew 	if (conf->sc_cafile == NULL) {
9326a3d55f9Skrw 		log_warn("%s", __func__);
93332814761Sjmatthew 		return (-1);
93432814761Sjmatthew 	}
93556f45a56Sjmatthew 	conf->sc_bind_mode = BIND_MODE_PORTMAP;
936f6242408Spyr 
937f6242408Spyr 	errors = 0;
938f6242408Spyr 
939385f9e8cSdlg 	if ((file = pushfile(filename, 1)) == NULL) {
940f6242408Spyr 		return (-1);
941f6242408Spyr 	}
942f6242408Spyr 	topfile = file;
943f6242408Spyr 
944f6242408Spyr 	/*
945f6242408Spyr 	 * parse configuration
946f6242408Spyr 	 */
947f6242408Spyr 	setservent(1);
948f6242408Spyr 	yyparse();
949f6242408Spyr 	endservent();
950f6242408Spyr 	errors = file->errors;
951f6242408Spyr 	popfile();
952f6242408Spyr 
953f6242408Spyr 	/* Free macros and check which have not been used. */
95446bca67bSkrw 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
955f6242408Spyr 		if ((opts & YPLDAP_OPT_VERBOSE) && !sym->used)
956f6242408Spyr 			fprintf(stderr, "warning: macro '%s' not "
957f6242408Spyr 			    "used\n", sym->nam);
958f6242408Spyr 		if (!sym->persist) {
959f6242408Spyr 			free(sym->nam);
960f6242408Spyr 			free(sym->val);
961f6242408Spyr 			TAILQ_REMOVE(&symhead, sym, entry);
962f6242408Spyr 			free(sym);
963f6242408Spyr 		}
964f6242408Spyr 	}
965f6242408Spyr 
966f6242408Spyr 	if (errors) {
967f6242408Spyr 		return (-1);
968f6242408Spyr 	}
969f6242408Spyr 
970f6242408Spyr 	return (0);
971f6242408Spyr }
972f6242408Spyr 
973f6242408Spyr int
symset(const char * nam,const char * val,int persist)974f6242408Spyr symset(const char *nam, const char *val, int persist)
975f6242408Spyr {
976f6242408Spyr 	struct sym	*sym;
977f6242408Spyr 
97854c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
97954c95b7aSkrw 		if (strcmp(nam, sym->nam) == 0)
98054c95b7aSkrw 			break;
98154c95b7aSkrw 	}
982f6242408Spyr 
983f6242408Spyr 	if (sym != NULL) {
984f6242408Spyr 		if (sym->persist == 1)
985f6242408Spyr 			return (0);
986f6242408Spyr 		else {
987f6242408Spyr 			free(sym->nam);
988f6242408Spyr 			free(sym->val);
989f6242408Spyr 			TAILQ_REMOVE(&symhead, sym, entry);
990f6242408Spyr 			free(sym);
991f6242408Spyr 		}
992f6242408Spyr 	}
993f6242408Spyr 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
994f6242408Spyr 		return (-1);
995f6242408Spyr 
996f6242408Spyr 	sym->nam = strdup(nam);
997f6242408Spyr 	if (sym->nam == NULL) {
998f6242408Spyr 		free(sym);
999f6242408Spyr 		return (-1);
1000f6242408Spyr 	}
1001f6242408Spyr 	sym->val = strdup(val);
1002f6242408Spyr 	if (sym->val == NULL) {
1003f6242408Spyr 		free(sym->nam);
1004f6242408Spyr 		free(sym);
1005f6242408Spyr 		return (-1);
1006f6242408Spyr 	}
1007f6242408Spyr 	sym->used = 0;
1008f6242408Spyr 	sym->persist = persist;
1009f6242408Spyr 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1010f6242408Spyr 	return (0);
1011f6242408Spyr }
1012f6242408Spyr 
1013f6242408Spyr int
cmdline_symset(char * s)1014f6242408Spyr cmdline_symset(char *s)
1015f6242408Spyr {
1016f6242408Spyr 	char	*sym, *val;
1017f6242408Spyr 	int	ret;
1018f6242408Spyr 
1019f6242408Spyr 	if ((val = strrchr(s, '=')) == NULL)
1020f6242408Spyr 		return (-1);
1021ed1b9eb8Smiko 	sym = strndup(s, val - s);
1022ed1b9eb8Smiko 	if (sym == NULL)
1023ed1b9eb8Smiko 		errx(1, "%s: strndup", __func__);
1024f6242408Spyr 	ret = symset(sym, val + 1, 1);
1025f6242408Spyr 	free(sym);
1026f6242408Spyr 
1027f6242408Spyr 	return (ret);
1028f6242408Spyr }
1029f6242408Spyr 
1030f6242408Spyr char *
symget(const char * nam)1031f6242408Spyr symget(const char *nam)
1032f6242408Spyr {
1033f6242408Spyr 	struct sym	*sym;
1034f6242408Spyr 
103554c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
1036f6242408Spyr 		if (strcmp(nam, sym->nam) == 0) {
1037f6242408Spyr 			sym->used = 1;
1038f6242408Spyr 			return (sym->val);
1039f6242408Spyr 		}
104054c95b7aSkrw 	}
1041f6242408Spyr 	return (NULL);
1042f6242408Spyr }
1043