xref: /openbsd-src/usr.sbin/httpd/parse.y (revision 8e3d8d5a1b748224c8b53fc9b8845e030ee31e12)
1*8e3d8d5aSbluhm /*	$OpenBSD: parse.y,v 1.128 2022/02/27 20:30:30 bluhm Exp $	*/
2b7b6a941Sreyk 
3b7b6a941Sreyk /*
480eb95f5Sdenis  * Copyright (c) 2020 Matthias Pressfreund <mpfr@fn.de>
505c2c945Sreyk  * Copyright (c) 2007 - 2015 Reyk Floeter <reyk@openbsd.org>
6b7b6a941Sreyk  * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
7b7b6a941Sreyk  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
8b7b6a941Sreyk  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
9b7b6a941Sreyk  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
10b7b6a941Sreyk  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
11b7b6a941Sreyk  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
12b7b6a941Sreyk  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
13b7b6a941Sreyk  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
14b7b6a941Sreyk  *
15b7b6a941Sreyk  * Permission to use, copy, modify, and distribute this software for any
16b7b6a941Sreyk  * purpose with or without fee is hereby granted, provided that the above
17b7b6a941Sreyk  * copyright notice and this permission notice appear in all copies.
18b7b6a941Sreyk  *
19b7b6a941Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
20b7b6a941Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
21b7b6a941Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
22b7b6a941Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23b7b6a941Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
24b7b6a941Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
25b7b6a941Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26b7b6a941Sreyk  */
27b7b6a941Sreyk 
28b7b6a941Sreyk %{
29b7b6a941Sreyk #include <sys/types.h>
30b7b6a941Sreyk #include <sys/socket.h>
319ea72f95Stracey #include <sys/un.h>
32b7b6a941Sreyk #include <sys/stat.h>
33b7b6a941Sreyk #include <sys/queue.h>
3486f952e4Sreyk #include <sys/tree.h>
35b7b6a941Sreyk #include <sys/ioctl.h>
3686f952e4Sreyk #include <sys/sockio.h>
3786f952e4Sreyk #include <sys/time.h>
38b7b6a941Sreyk 
39b7b6a941Sreyk #include <net/if.h>
40b7b6a941Sreyk #include <netinet/in.h>
41b7b6a941Sreyk #include <arpa/inet.h>
42b7b6a941Sreyk 
43b7b6a941Sreyk #include <ctype.h>
44b7b6a941Sreyk #include <unistd.h>
45b7b6a941Sreyk #include <err.h>
46b7b6a941Sreyk #include <errno.h>
47b7b6a941Sreyk #include <limits.h>
48b7b6a941Sreyk #include <stdint.h>
49b7b6a941Sreyk #include <stdarg.h>
50b7b6a941Sreyk #include <stdio.h>
51b7b6a941Sreyk #include <netdb.h>
52b7b6a941Sreyk #include <string.h>
53b7b6a941Sreyk #include <ifaddrs.h>
54b7b6a941Sreyk #include <syslog.h>
55b7b6a941Sreyk 
56b7b6a941Sreyk #include "httpd.h"
57b7b6a941Sreyk #include "http.h"
58b7b6a941Sreyk 
59b7b6a941Sreyk TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
60b7b6a941Sreyk static struct file {
61b7b6a941Sreyk 	TAILQ_ENTRY(file)	 entry;
62b7b6a941Sreyk 	FILE			*stream;
63b7b6a941Sreyk 	char			*name;
64cc380947Sdenis 	size_t			 ungetpos;
65cc380947Sdenis 	size_t			 ungetsize;
66cc380947Sdenis 	u_char			*ungetbuf;
67cc380947Sdenis 	int			 eof_reached;
68b7b6a941Sreyk 	int			 lineno;
69b7b6a941Sreyk 	int			 errors;
70b7b6a941Sreyk } *file, *topfile;
71b7b6a941Sreyk struct file	*pushfile(const char *, int);
72b7b6a941Sreyk int		 popfile(void);
73b7b6a941Sreyk int		 check_file_secrecy(int, const char *);
74b7b6a941Sreyk int		 yyparse(void);
75b7b6a941Sreyk int		 yylex(void);
76260af8fcSdoug int		 yyerror(const char *, ...)
77260af8fcSdoug     __attribute__((__format__ (printf, 1, 2)))
78260af8fcSdoug     __attribute__((__nonnull__ (1)));
79b7b6a941Sreyk int		 kw_cmp(const void *, const void *);
80b7b6a941Sreyk int		 lookup(char *);
81cc380947Sdenis int		 igetc(void);
82b7b6a941Sreyk int		 lgetc(int);
83cc380947Sdenis void		 lungetc(int);
84b7b6a941Sreyk int		 findeol(void);
85b7b6a941Sreyk 
86b7b6a941Sreyk TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
87b7b6a941Sreyk struct sym {
88b7b6a941Sreyk 	TAILQ_ENTRY(sym)	 entry;
89b7b6a941Sreyk 	int			 used;
90b7b6a941Sreyk 	int			 persist;
91b7b6a941Sreyk 	char			*nam;
92b7b6a941Sreyk 	char			*val;
93b7b6a941Sreyk };
94b7b6a941Sreyk int		 symset(const char *, const char *, int);
95b7b6a941Sreyk char		*symget(const char *);
96b7b6a941Sreyk 
97b7b6a941Sreyk struct httpd		*conf = NULL;
98b7b6a941Sreyk static int		 errors = 0;
99b7b6a941Sreyk static int		 loadcfg = 0;
100b7b6a941Sreyk uint32_t		 last_server_id = 0;
101602531d9Sreyk uint32_t		 last_auth_id = 0;
102b7b6a941Sreyk 
103a916ec37Sreyk static struct server	*srv = NULL, *parentsrv = NULL;
104412a80baSreyk static struct server_config *srv_conf = NULL;
105b7b6a941Sreyk struct serverlist	 servers;
1069b9ff8ecSreyk struct media_type	 media;
107b7b6a941Sreyk 
108b7b6a941Sreyk struct address	*host_v4(const char *);
109b7b6a941Sreyk struct address	*host_v6(const char *);
110b7b6a941Sreyk int		 host_dns(const char *, struct addresslist *,
111b7b6a941Sreyk 		    int, struct portrange *, const char *, int);
112b7b6a941Sreyk int		 host_if(const char *, struct addresslist *,
113b7b6a941Sreyk 		    int, struct portrange *, const char *, int);
114b7b6a941Sreyk int		 host(const char *, struct addresslist *,
115b7b6a941Sreyk 		    int, struct portrange *, const char *, int);
11659355b5aSreyk struct server	*server_inherit(struct server *, struct server_config *,
117be4c70f0Sreyk 		    struct server_config *);
118fdc19e0cSreyk int		 listen_on(const char *, int, struct portrange *);
119b7b6a941Sreyk int		 getservice(char *);
120b7b6a941Sreyk int		 is_if_in_group(const char *, const char *);
1219ea72f95Stracey int		 get_fastcgi_dest(struct server_config *, const char *, char *);
12235afa99fStb void		 remove_locations(struct server_config *);
123b7b6a941Sreyk 
124b7b6a941Sreyk typedef struct {
125b7b6a941Sreyk 	union {
126b7b6a941Sreyk 		int64_t			 number;
127b7b6a941Sreyk 		char			*string;
128b7b6a941Sreyk 		struct timeval		 tv;
129b7b6a941Sreyk 		struct portrange	 port;
130602531d9Sreyk 		struct auth		 auth;
131b7b6a941Sreyk 	} v;
132b7b6a941Sreyk 	int lineno;
133b7b6a941Sreyk } YYSTYPE;
134b7b6a941Sreyk 
135b7b6a941Sreyk %}
136b7b6a941Sreyk 
137be4c70f0Sreyk %token	ACCESS ALIAS AUTO BACKLOG BODY BUFFER CERTIFICATE CHROOT CIPHERS COMMON
138fe006a11Sclaudio %token	COMBINED CONNECTION DHE DIRECTORY ECDHE ERR FCGI INDEX IP KEY LIFETIME
139fe006a11Sclaudio %token	LISTEN LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY OCSP ON PORT PREFORK
140fe006a11Sclaudio %token	PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TICKET
141fe006a11Sclaudio %token	TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
14293038d14Sreyk %token	ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE
143e96b74b9Sdenis %token	CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT
144*8e3d8d5aSbluhm %token	ERRDOCS GZIPSTATIC
145b7b6a941Sreyk %token	<v.string>	STRING
146b7b6a941Sreyk %token  <v.number>	NUMBER
147f90e0272Sreyk %type	<v.port>	port
1489ea72f95Stracey %type	<v.string>	fcgiport
149e96b74b9Sdenis %type	<v.number>	opttls optmatch optfound
1507a5a4a11Sreyk %type	<v.tv>		timeout
151f8932becSreyk %type	<v.string>	numberstring optstring
152602531d9Sreyk %type	<v.auth>	authopts
153b7b6a941Sreyk 
154b7b6a941Sreyk %%
155b7b6a941Sreyk 
156b7b6a941Sreyk grammar		: /* empty */
157b7b6a941Sreyk 		| grammar include '\n'
158b7b6a941Sreyk 		| grammar '\n'
159b7b6a941Sreyk 		| grammar varset '\n'
160b7b6a941Sreyk 		| grammar main '\n'
161b7b6a941Sreyk 		| grammar server '\n'
1629b9ff8ecSreyk 		| grammar types '\n'
163b7b6a941Sreyk 		| grammar error '\n'		{ file->errors++; }
164b7b6a941Sreyk 		;
165b7b6a941Sreyk 
166b7b6a941Sreyk include		: INCLUDE STRING		{
167b7b6a941Sreyk 			struct file	*nfile;
168b7b6a941Sreyk 
169b7b6a941Sreyk 			if ((nfile = pushfile($2, 0)) == NULL) {
170b7b6a941Sreyk 				yyerror("failed to include file %s", $2);
171b7b6a941Sreyk 				free($2);
172b7b6a941Sreyk 				YYERROR;
173b7b6a941Sreyk 			}
174b7b6a941Sreyk 			free($2);
175b7b6a941Sreyk 
176b7b6a941Sreyk 			file = nfile;
177b7b6a941Sreyk 			lungetc('\n');
178b7b6a941Sreyk 		}
179b7b6a941Sreyk 		;
180b7b6a941Sreyk 
181b7b6a941Sreyk varset		: STRING '=' STRING	{
1820c7b4ca6Sbenno 			char *s = $1;
1830c7b4ca6Sbenno 			while (*s++) {
1840c7b4ca6Sbenno 				if (isspace((unsigned char)*s)) {
1850c7b4ca6Sbenno 					yyerror("macro name cannot contain "
1860c7b4ca6Sbenno 					    "whitespace");
18716a0a906Skrw 					free($1);
18816a0a906Skrw 					free($3);
1890c7b4ca6Sbenno 					YYERROR;
1900c7b4ca6Sbenno 				}
1910c7b4ca6Sbenno 			}
192b7b6a941Sreyk 			if (symset($1, $3, 0) == -1)
193b7b6a941Sreyk 				fatal("cannot store variable");
194b7b6a941Sreyk 			free($1);
195b7b6a941Sreyk 			free($3);
196b7b6a941Sreyk 		}
197b7b6a941Sreyk 		;
198b7b6a941Sreyk 
199a760b3d3Sreyk opttls		: /*empty*/	{ $$ = 0; }
200a760b3d3Sreyk 		| TLS		{ $$ = 1; }
2013fe67476Sreyk 		;
2023fe67476Sreyk 
203346191dfSreyk main		: PREFORK NUMBER	{
204b7b6a941Sreyk 			if (loadcfg)
205b7b6a941Sreyk 				break;
2068e01c6e3Sreyk 			if ($2 <= 0 || $2 > PROC_MAX_INSTANCES) {
207b7b6a941Sreyk 				yyerror("invalid number of preforked "
208260af8fcSdoug 				    "servers: %lld", $2);
209b7b6a941Sreyk 				YYERROR;
210b7b6a941Sreyk 			}
211b7b6a941Sreyk 			conf->sc_prefork_server = $2;
212b7b6a941Sreyk 		}
213bde157a8Sjsg 		| CHROOT STRING		{
214bde157a8Sjsg 			conf->sc_chroot = $2;
215bde157a8Sjsg 		}
216cbced0bdSian 		| ERRDOCS STRING	{
217cbced0bdSian 			if ($2 != NULL && strlcpy(conf->sc_errdocroot, $2,
218cbced0bdSian 			    sizeof(conf->sc_errdocroot)) >=
219cbced0bdSian 			    sizeof(conf->sc_errdocroot)) {
220cbced0bdSian 				yyerror("errdoc root path too long");
221cbced0bdSian 				free($2);
222cbced0bdSian 				YYERROR;
223cbced0bdSian 			}
224cbced0bdSian 			free($2);
225cbced0bdSian 			conf->sc_custom_errdocs = 1;
226cbced0bdSian 		}
227032d2b93Sbeck 		| LOGDIR STRING		{
228032d2b93Sbeck 			conf->sc_logdir = $2;
229032d2b93Sbeck 		}
230d24f6b1eSreyk 		| DEFAULT TYPE mediastring	{
231d24f6b1eSreyk 			memcpy(&conf->sc_default_type, &media,
232d24f6b1eSreyk 			    sizeof(struct media_type));
233d24f6b1eSreyk 		}
234b7b6a941Sreyk 		;
235b7b6a941Sreyk 
23659355b5aSreyk server		: SERVER optmatch STRING	{
237b7b6a941Sreyk 			struct server		*s;
23852ef30a3Sflorian 			struct sockaddr_un	*sun;
239b7b6a941Sreyk 
240b7b6a941Sreyk 			if (!loadcfg) {
24159355b5aSreyk 				free($3);
242b7b6a941Sreyk 				YYACCEPT;
243b7b6a941Sreyk 			}
244b7b6a941Sreyk 
245b7b6a941Sreyk 			if ((s = calloc(1, sizeof (*s))) == NULL)
246b7b6a941Sreyk 				fatal("out of memory");
247b7b6a941Sreyk 
24859355b5aSreyk 			if (strlcpy(s->srv_conf.name, $3,
249b7b6a941Sreyk 			    sizeof(s->srv_conf.name)) >=
250b7b6a941Sreyk 			    sizeof(s->srv_conf.name)) {
251b7b6a941Sreyk 				yyerror("server name truncated");
25259355b5aSreyk 				free($3);
253b7b6a941Sreyk 				free(s);
254b7b6a941Sreyk 				YYERROR;
255b7b6a941Sreyk 			}
25659355b5aSreyk 			free($3);
257b7b6a941Sreyk 
258e46d51a0Sreyk 			strlcpy(s->srv_conf.root, HTTPD_DOCROOT,
259e46d51a0Sreyk 			    sizeof(s->srv_conf.root));
26043d7585dSreyk 			strlcpy(s->srv_conf.index, HTTPD_INDEX,
26143d7585dSreyk 			    sizeof(s->srv_conf.index));
262cf605f40Sreyk 			strlcpy(s->srv_conf.accesslog, HTTPD_ACCESS_LOG,
263cf605f40Sreyk 			    sizeof(s->srv_conf.accesslog));
264cf605f40Sreyk 			strlcpy(s->srv_conf.errorlog, HTTPD_ERROR_LOG,
265cf605f40Sreyk 			    sizeof(s->srv_conf.errorlog));
266b7b6a941Sreyk 			s->srv_conf.id = ++last_server_id;
267c145f9a8Sreyk 			s->srv_conf.parent_id = s->srv_conf.id;
26827fb06b4Sreyk 			s->srv_s = -1;
269b7b6a941Sreyk 			s->srv_conf.timeout.tv_sec = SERVER_TIMEOUT;
270da1a1214Sreyk 			s->srv_conf.requesttimeout.tv_sec =
271da1a1214Sreyk 			    SERVER_REQUESTTIMEOUT;
2727a5a4a11Sreyk 			s->srv_conf.maxrequests = SERVER_MAXREQUESTS;
2734dd188b5Sreyk 			s->srv_conf.maxrequestbody = SERVER_MAXREQUESTBODY;
27459355b5aSreyk 			s->srv_conf.flags = SRVFLAG_LOG;
27559355b5aSreyk 			if ($2)
27659355b5aSreyk 				s->srv_conf.flags |= SRVFLAG_SERVER_MATCH;
277af3cfad1Sdoug 			s->srv_conf.logformat = LOG_FORMAT_COMMON;
2789fa2a900Sreyk 			s->srv_conf.tls_protocols = TLS_PROTOCOLS_DEFAULT;
279a760b3d3Sreyk 			if ((s->srv_conf.tls_cert_file =
280a760b3d3Sreyk 			    strdup(HTTPD_TLS_CERT)) == NULL)
28196d01691Sjsing 				fatal("out of memory");
282a760b3d3Sreyk 			if ((s->srv_conf.tls_key_file =
283a760b3d3Sreyk 			    strdup(HTTPD_TLS_KEY)) == NULL)
28496d01691Sjsing 				fatal("out of memory");
285051776c0Sjsing 			strlcpy(s->srv_conf.tls_ciphers,
286051776c0Sjsing 			    HTTPD_TLS_CIPHERS,
287a760b3d3Sreyk 			    sizeof(s->srv_conf.tls_ciphers));
288051776c0Sjsing 			strlcpy(s->srv_conf.tls_dhe_params,
289051776c0Sjsing 			    HTTPD_TLS_DHE_PARAMS,
290051776c0Sjsing 			    sizeof(s->srv_conf.tls_dhe_params));
29189f7e997Sjsing 			strlcpy(s->srv_conf.tls_ecdhe_curves,
29289f7e997Sjsing 			    HTTPD_TLS_ECDHE_CURVES,
29389f7e997Sjsing 			    sizeof(s->srv_conf.tls_ecdhe_curves));
294b7b6a941Sreyk 
29552ef30a3Sflorian 			sun = (struct sockaddr_un *)&s->srv_conf.fastcgi_ss;
29652ef30a3Sflorian 			sun->sun_family = AF_UNIX;
29752ef30a3Sflorian 			(void)strlcpy(sun->sun_path, HTTPD_FCGI_SOCKET,
29852ef30a3Sflorian 			    sizeof(sun->sun_path));
29952ef30a3Sflorian 			sun->sun_len = sizeof(struct sockaddr_un);
30052ef30a3Sflorian 
301f5d55328Sflorian 			s->srv_conf.hsts_max_age = SERVER_HSTS_DEFAULT_AGE;
302f5d55328Sflorian 
303cbced0bdSian 			(void)strlcpy(s->srv_conf.errdocroot,
304cbced0bdSian 			    conf->sc_errdocroot,
305cbced0bdSian 			    sizeof(s->srv_conf.errdocroot));
306cbced0bdSian 			if (conf->sc_custom_errdocs)
307cbced0bdSian 				s->srv_conf.flags |= SRVFLAG_ERRDOCS;
308cbced0bdSian 
309b7b6a941Sreyk 			if (last_server_id == INT_MAX) {
310b7b6a941Sreyk 				yyerror("too many servers defined");
311b7b6a941Sreyk 				free(s);
312b7b6a941Sreyk 				YYERROR;
313b7b6a941Sreyk 			}
314b7b6a941Sreyk 			srv = s;
315412a80baSreyk 			srv_conf = &srv->srv_conf;
316a916ec37Sreyk 
317b7b6a941Sreyk 			SPLAY_INIT(&srv->srv_clients);
318be4c70f0Sreyk 			TAILQ_INIT(&srv->srv_hosts);
31903cb893cSpirofti 			TAILQ_INIT(&srv_conf->fcgiparams);
320be4c70f0Sreyk 
321be4c70f0Sreyk 			TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry);
322a916ec37Sreyk 		} '{' optnl serveropts_l '}'	{
323e1f28ec9Sjsing 			struct server		*s, *sn;
324be4c70f0Sreyk 			struct server_config	*a, *b;
325be4c70f0Sreyk 
326be4c70f0Sreyk 			srv_conf = &srv->srv_conf;
327bd1bab2fSreyk 
328e1f28ec9Sjsing 			/* Check if the new server already exists. */
329e1f28ec9Sjsing 			if (server_match(srv, 1) != NULL) {
330bd1bab2fSreyk 				yyerror("server \"%s\" defined twice",
331bd1bab2fSreyk 				    srv->srv_conf.name);
332bd1bab2fSreyk 				serverconfig_free(srv_conf);
333bd1bab2fSreyk 				free(srv);
334bd1bab2fSreyk 				YYABORT;
335bd1bab2fSreyk 			}
336bd1bab2fSreyk 
3374f194ec8Sreyk 			if (srv->srv_conf.ss.ss_family == AF_UNSPEC) {
3384f194ec8Sreyk 				yyerror("listen address not specified");
339bd1bab2fSreyk 				serverconfig_free(srv_conf);
340bd1bab2fSreyk 				free(srv);
3414f194ec8Sreyk 				YYERROR;
3424f194ec8Sreyk 			}
343bd1bab2fSreyk 
344e1f28ec9Sjsing 			if ((s = server_match(srv, 0)) != NULL) {
345e1f28ec9Sjsing 				if ((s->srv_conf.flags & SRVFLAG_TLS) !=
346e1f28ec9Sjsing 				    (srv->srv_conf.flags & SRVFLAG_TLS)) {
347e1f28ec9Sjsing 					yyerror("server \"%s\": tls and "
348e1f28ec9Sjsing 					    "non-tls on same address/port",
349e1f28ec9Sjsing 					    srv->srv_conf.name);
350e1f28ec9Sjsing 					serverconfig_free(srv_conf);
351e1f28ec9Sjsing 					free(srv);
352e1f28ec9Sjsing 					YYERROR;
353e1f28ec9Sjsing 				}
354d587572fSclaudio 				if (srv->srv_conf.flags & SRVFLAG_TLS &&
355d587572fSclaudio 				    server_tls_cmp(s, srv) != 0) {
356e1f28ec9Sjsing 					yyerror("server \"%s\": tls "
357e1f28ec9Sjsing 					    "configuration mismatch on same "
358e1f28ec9Sjsing 					    "address/port",
359e1f28ec9Sjsing 					    srv->srv_conf.name);
360e1f28ec9Sjsing 					serverconfig_free(srv_conf);
361e1f28ec9Sjsing 					free(srv);
362e1f28ec9Sjsing 					YYERROR;
363e1f28ec9Sjsing 				}
364e1f28ec9Sjsing 			}
365e1f28ec9Sjsing 
3663fb73497Sjsing 			if ((srv->srv_conf.flags & SRVFLAG_TLS) &&
3673fb73497Sjsing 			    srv->srv_conf.tls_protocols == 0) {
368e1f28ec9Sjsing 				yyerror("server \"%s\": no tls protocols",
369e1f28ec9Sjsing 				    srv->srv_conf.name);
370e1f28ec9Sjsing 				serverconfig_free(srv_conf);
3713fb73497Sjsing 				free(srv);
3723fb73497Sjsing 				YYERROR;
3733fb73497Sjsing 			}
3743fb73497Sjsing 
37560348d93Stb 			if (server_tls_load_keypair(srv) == -1) {
37660348d93Stb 				/* Soft fail as there may be no certificate. */
3778f2f1969Sflorian 				log_warnx("%s:%d: server \"%s\": failed to "
3788f2f1969Sflorian 				    "load public/private keys", file->name,
3798f2f1969Sflorian 				    yylval.lineno, srv->srv_conf.name);
38035afa99fStb 
38135afa99fStb 				remove_locations(srv_conf);
38260348d93Stb 				serverconfig_free(srv_conf);
38360348d93Stb 				srv_conf = NULL;
38460348d93Stb 				free(srv);
38560348d93Stb 				srv = NULL;
38660348d93Stb 				break;
38760348d93Stb 			}
388bd1bab2fSreyk 
3891d0dc528Sjsing 			if (server_tls_load_ca(srv) == -1) {
3901d0dc528Sjsing 				yyerror("server \"%s\": failed to load "
3911d0dc528Sjsing 				    "ca cert(s)", srv->srv_conf.name);
3921d0dc528Sjsing 				serverconfig_free(srv_conf);
3931d0dc528Sjsing 				free(srv);
3941d0dc528Sjsing 				YYERROR;
3951d0dc528Sjsing 			}
3961d0dc528Sjsing 
3971d0dc528Sjsing 			if (server_tls_load_crl(srv) == -1) {
3981d0dc528Sjsing 				yyerror("server \"%s\": failed to load crl(s)",
3991d0dc528Sjsing 				    srv->srv_conf.name);
4001d0dc528Sjsing 				serverconfig_free(srv_conf);
4011d0dc528Sjsing 				free(srv);
4021d0dc528Sjsing 				YYERROR;
4031d0dc528Sjsing 			}
4041d0dc528Sjsing 
40588f25489Sjsing 			if (server_tls_load_ocsp(srv) == -1) {
40688f25489Sjsing 				yyerror("server \"%s\": failed to load "
407757ef573Stom 				    "ocsp staple", srv->srv_conf.name);
40888f25489Sjsing 				serverconfig_free(srv_conf);
40988f25489Sjsing 				free(srv);
41088f25489Sjsing 				YYERROR;
41188f25489Sjsing 			}
41288f25489Sjsing 
413bd1bab2fSreyk 			DPRINTF("adding server \"%s[%u]\"",
414bd1bab2fSreyk 			    srv->srv_conf.name, srv->srv_conf.id);
415bd1bab2fSreyk 
416bd1bab2fSreyk 			TAILQ_INSERT_TAIL(conf->sc_servers, srv, srv_entry);
417bd1bab2fSreyk 
418be4c70f0Sreyk 			/*
419be4c70f0Sreyk 			 * Add aliases and additional listen addresses as
420be4c70f0Sreyk 			 * individual servers.
421be4c70f0Sreyk 			 */
422be4c70f0Sreyk 			TAILQ_FOREACH(a, &srv->srv_hosts, entry) {
423be4c70f0Sreyk 				/* listen address */
424be4c70f0Sreyk 				if (a->ss.ss_family == AF_UNSPEC)
425be4c70f0Sreyk 					continue;
426be4c70f0Sreyk 				TAILQ_FOREACH(b, &srv->srv_hosts, entry) {
427be4c70f0Sreyk 					/* alias name */
428be4c70f0Sreyk 					if (*b->name == '\0' ||
429be4c70f0Sreyk 					    (b == &srv->srv_conf && b == a))
430be4c70f0Sreyk 						continue;
431be4c70f0Sreyk 
432be4c70f0Sreyk 					if ((sn = server_inherit(srv,
43359355b5aSreyk 					    b, a)) == NULL) {
434be4c70f0Sreyk 						serverconfig_free(srv_conf);
435be4c70f0Sreyk 						free(srv);
436be4c70f0Sreyk 						YYABORT;
437be4c70f0Sreyk 					}
438be4c70f0Sreyk 
439be4c70f0Sreyk 					DPRINTF("adding server \"%s[%u]\"",
440be4c70f0Sreyk 					    sn->srv_conf.name, sn->srv_conf.id);
441be4c70f0Sreyk 
442be4c70f0Sreyk 					TAILQ_INSERT_TAIL(conf->sc_servers,
443be4c70f0Sreyk 					    sn, srv_entry);
444be4c70f0Sreyk 				}
445be4c70f0Sreyk 			}
446be4c70f0Sreyk 
447be4c70f0Sreyk 			/* Remove temporary aliases */
448be4c70f0Sreyk 			TAILQ_FOREACH_SAFE(a, &srv->srv_hosts, entry, b) {
449be4c70f0Sreyk 				TAILQ_REMOVE(&srv->srv_hosts, a, entry);
450be4c70f0Sreyk 				if (a == &srv->srv_conf)
451be4c70f0Sreyk 					continue;
452be4c70f0Sreyk 				serverconfig_free(a);
453be4c70f0Sreyk 				free(a);
454be4c70f0Sreyk 			}
455be4c70f0Sreyk 
456a916ec37Sreyk 			srv = NULL;
457412a80baSreyk 			srv_conf = NULL;
458b7b6a941Sreyk 		}
459b7b6a941Sreyk 		;
460b7b6a941Sreyk 
461b7b6a941Sreyk serveropts_l	: serveropts_l serveroptsl nl
462b7b6a941Sreyk 		| serveroptsl optnl
463b7b6a941Sreyk 		;
464b7b6a941Sreyk 
465f90e0272Sreyk serveroptsl	: LISTEN ON STRING opttls port	{
466fdc19e0cSreyk 			if (listen_on($3, $4, &$5) == -1) {
467a916ec37Sreyk 				free($3);
468a916ec37Sreyk 				YYERROR;
469a916ec37Sreyk 			}
470108ab390Sflorian 			free($3);
471be4c70f0Sreyk 		}
47259355b5aSreyk 		| ALIAS optmatch STRING		{
473be4c70f0Sreyk 			struct server_config	*alias;
474be4c70f0Sreyk 
475be4c70f0Sreyk 			if (parentsrv != NULL) {
476be4c70f0Sreyk 				yyerror("alias inside location");
47759355b5aSreyk 				free($3);
478be4c70f0Sreyk 				YYERROR;
479be4c70f0Sreyk 			}
480be4c70f0Sreyk 
481be4c70f0Sreyk 			if ((alias = calloc(1, sizeof(*alias))) == NULL)
482be4c70f0Sreyk 				fatal("out of memory");
483be4c70f0Sreyk 
48459355b5aSreyk 			if (strlcpy(alias->name, $3, sizeof(alias->name)) >=
485be4c70f0Sreyk 			    sizeof(alias->name)) {
486be4c70f0Sreyk 				yyerror("server alias truncated");
48759355b5aSreyk 				free($3);
488be4c70f0Sreyk 				free(alias);
489be4c70f0Sreyk 				YYERROR;
490be4c70f0Sreyk 			}
49159355b5aSreyk 			free($3);
49259355b5aSreyk 
49359355b5aSreyk 			if ($2)
49459355b5aSreyk 				alias->flags |= SRVFLAG_SERVER_MATCH;
495be4c70f0Sreyk 
496be4c70f0Sreyk 			TAILQ_INSERT_TAIL(&srv->srv_hosts, alias, entry);
497b7b6a941Sreyk 		}
498cbced0bdSian 		| ERRDOCS STRING	{
499cbced0bdSian 			if (parentsrv != NULL) {
500cbced0bdSian 				yyerror("errdocs inside location");
501cbced0bdSian 				YYERROR;
502cbced0bdSian 			}
503cbced0bdSian 			if ($2 != NULL && strlcpy(srv->srv_conf.errdocroot, $2,
504cbced0bdSian 			    sizeof(srv->srv_conf.errdocroot)) >=
505cbced0bdSian 			    sizeof(srv->srv_conf.errdocroot)) {
506cbced0bdSian 				yyerror("errdoc root path too long");
507cbced0bdSian 				free($2);
508cbced0bdSian 				YYERROR;
509cbced0bdSian 			}
510cbced0bdSian 			free($2);
511cbced0bdSian 			srv->srv_conf.flags |= SRVFLAG_ERRDOCS;
512cbced0bdSian 		}
513cbced0bdSian 		| NO ERRDOCS		{
514cbced0bdSian 			if (parentsrv != NULL) {
515cbced0bdSian 				yyerror("errdocs inside location");
516cbced0bdSian 				YYERROR;
517cbced0bdSian 			}
518cbced0bdSian 			srv->srv_conf.flags &= ~SRVFLAG_ERRDOCS;
519cbced0bdSian 		}
52053c118d9Sreyk 		| tcpip			{
521dd598c8dSreyk 			if (parentsrv != NULL) {
522dd598c8dSreyk 				yyerror("tcp flags inside location");
523dd598c8dSreyk 				YYERROR;
524dd598c8dSreyk 			}
52553c118d9Sreyk 		}
52653c118d9Sreyk 		| connection		{
527dd598c8dSreyk 			if (parentsrv != NULL) {
5287a5a4a11Sreyk 				yyerror("connection options inside location");
529dd598c8dSreyk 				YYERROR;
530dd598c8dSreyk 			}
53153c118d9Sreyk 		}
53253c118d9Sreyk 		| tls			{
533e1f28ec9Sjsing 			struct server_config	*sc;
534e1f28ec9Sjsing 			int			 tls_flag = 0;
535e1f28ec9Sjsing 
53696d01691Sjsing 			if (parentsrv != NULL) {
537a760b3d3Sreyk 				yyerror("tls configuration inside location");
53896d01691Sjsing 				YYERROR;
53996d01691Sjsing 			}
540e1f28ec9Sjsing 
541e1f28ec9Sjsing 			/* Ensure that at least one server has TLS enabled. */
542e1f28ec9Sjsing 			TAILQ_FOREACH(sc, &srv->srv_hosts, entry) {
543e1f28ec9Sjsing 				tls_flag |= (sc->flags & SRVFLAG_TLS);
544e1f28ec9Sjsing 			}
545e1f28ec9Sjsing 			if (tls_flag == 0) {
546e1f28ec9Sjsing 				yyerror("tls options without tls listener");
547e1f28ec9Sjsing 				YYERROR;
548e1f28ec9Sjsing 			}
54953c118d9Sreyk 		}
550de6c234aSreyk 		| request
55153c118d9Sreyk 		| root
55253c118d9Sreyk 		| directory
553ea62a379Sdoug 		| logformat
554af5adad1Sreyk 		| fastcgi
555e286121aSflorian 		| authenticate
556*8e3d8d5aSbluhm 		| gzip_static
557f8932becSreyk 		| filter
558e96b74b9Sdenis 		| LOCATION optfound optmatch STRING	{
559a916ec37Sreyk 			struct server		*s;
56052ef30a3Sflorian 			struct sockaddr_un	*sun;
561a916ec37Sreyk 
5624f194ec8Sreyk 			if (srv->srv_conf.ss.ss_family == AF_UNSPEC) {
5634f194ec8Sreyk 				yyerror("listen address not specified");
564e96b74b9Sdenis 				free($4);
5654f194ec8Sreyk 				YYERROR;
5664f194ec8Sreyk 			}
5674f194ec8Sreyk 
568a916ec37Sreyk 			if (parentsrv != NULL) {
569e96b74b9Sdenis 				yyerror("location %s inside location", $4);
570e96b74b9Sdenis 				free($4);
571a916ec37Sreyk 				YYERROR;
572a916ec37Sreyk 			}
573a916ec37Sreyk 
574a916ec37Sreyk 			if (!loadcfg) {
575e96b74b9Sdenis 				free($4);
576a916ec37Sreyk 				YYACCEPT;
577a916ec37Sreyk 			}
578a916ec37Sreyk 
579a916ec37Sreyk 			if ((s = calloc(1, sizeof (*s))) == NULL)
580a916ec37Sreyk 				fatal("out of memory");
581a916ec37Sreyk 
582e96b74b9Sdenis 			if (strlcpy(s->srv_conf.location, $4,
583a916ec37Sreyk 			    sizeof(s->srv_conf.location)) >=
584a916ec37Sreyk 			    sizeof(s->srv_conf.location)) {
585a916ec37Sreyk 				yyerror("server location truncated");
586e96b74b9Sdenis 				free($4);
587a916ec37Sreyk 				free(s);
588a916ec37Sreyk 				YYERROR;
589a916ec37Sreyk 			}
590e96b74b9Sdenis 			free($4);
591a916ec37Sreyk 
592a916ec37Sreyk 			if (strlcpy(s->srv_conf.name, srv->srv_conf.name,
593a916ec37Sreyk 			    sizeof(s->srv_conf.name)) >=
594a916ec37Sreyk 			    sizeof(s->srv_conf.name)) {
595a916ec37Sreyk 				yyerror("server name truncated");
596a916ec37Sreyk 				free(s);
597a916ec37Sreyk 				YYERROR;
598a916ec37Sreyk 			}
599a916ec37Sreyk 
60052ef30a3Sflorian 			sun = (struct sockaddr_un *)&s->srv_conf.fastcgi_ss;
60152ef30a3Sflorian 			sun->sun_family = AF_UNIX;
60252ef30a3Sflorian 			(void)strlcpy(sun->sun_path, HTTPD_FCGI_SOCKET,
60352ef30a3Sflorian 			    sizeof(sun->sun_path));
60452ef30a3Sflorian 			sun->sun_len = sizeof(struct sockaddr_un);
60552ef30a3Sflorian 
606c145f9a8Sreyk 			s->srv_conf.id = ++last_server_id;
6074f194ec8Sreyk 			/* A location entry uses the parent id */
608c145f9a8Sreyk 			s->srv_conf.parent_id = srv->srv_conf.id;
609a916ec37Sreyk 			s->srv_conf.flags = SRVFLAG_LOCATION;
610e96b74b9Sdenis 			if ($2 == 1) {
611e96b74b9Sdenis 				s->srv_conf.flags &=
612e96b74b9Sdenis 				    ~SRVFLAG_LOCATION_NOT_FOUND;
613e96b74b9Sdenis 				s->srv_conf.flags |=
614e96b74b9Sdenis 				    SRVFLAG_LOCATION_FOUND;
615e96b74b9Sdenis 			} else if ($2 == -1) {
616e96b74b9Sdenis 				s->srv_conf.flags &=
617e96b74b9Sdenis 				    ~SRVFLAG_LOCATION_FOUND;
618e96b74b9Sdenis 				s->srv_conf.flags |=
619e96b74b9Sdenis 				    SRVFLAG_LOCATION_NOT_FOUND;
620e96b74b9Sdenis 			}
621e96b74b9Sdenis 			if ($3)
62259355b5aSreyk 				s->srv_conf.flags |= SRVFLAG_LOCATION_MATCH;
62327fb06b4Sreyk 			s->srv_s = -1;
6244f194ec8Sreyk 			memcpy(&s->srv_conf.ss, &srv->srv_conf.ss,
6254f194ec8Sreyk 			    sizeof(s->srv_conf.ss));
6264f194ec8Sreyk 			s->srv_conf.port = srv->srv_conf.port;
6274f194ec8Sreyk 			s->srv_conf.prefixlen = srv->srv_conf.prefixlen;
6281d0dc528Sjsing 			s->srv_conf.tls_flags = srv->srv_conf.tls_flags;
629a916ec37Sreyk 
630a916ec37Sreyk 			if (last_server_id == INT_MAX) {
631a916ec37Sreyk 				yyerror("too many servers/locations defined");
632a916ec37Sreyk 				free(s);
633a916ec37Sreyk 				YYERROR;
634a916ec37Sreyk 			}
635a916ec37Sreyk 			parentsrv = srv;
636a916ec37Sreyk 			srv = s;
637412a80baSreyk 			srv_conf = &srv->srv_conf;
638a916ec37Sreyk 			SPLAY_INIT(&srv->srv_clients);
639a916ec37Sreyk 		} '{' optnl serveropts_l '}'	{
640bd1bab2fSreyk 			struct server	*s = NULL;
641e96b74b9Sdenis 			uint32_t	 f;
642e96b74b9Sdenis 
643e96b74b9Sdenis 			f = SRVFLAG_LOCATION_FOUND |
644e96b74b9Sdenis 			    SRVFLAG_LOCATION_NOT_FOUND;
645bd1bab2fSreyk 
646bd1bab2fSreyk 			TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
64780eb95f5Sdenis 				/* Compare locations of same parent server */
648bd1bab2fSreyk 				if ((s->srv_conf.flags & SRVFLAG_LOCATION) &&
64980eb95f5Sdenis 				    s->srv_conf.parent_id ==
65080eb95f5Sdenis 				    srv_conf->parent_id &&
651e96b74b9Sdenis 				    (s->srv_conf.flags & f) ==
652e96b74b9Sdenis 				    (srv_conf->flags & f) &&
653bd1bab2fSreyk 				    strcmp(s->srv_conf.location,
654bd1bab2fSreyk 				    srv_conf->location) == 0)
655bd1bab2fSreyk 					break;
656bd1bab2fSreyk 			}
657bd1bab2fSreyk 			if (s != NULL) {
658bd1bab2fSreyk 				yyerror("location \"%s\" defined twice",
659bd1bab2fSreyk 				    srv->srv_conf.location);
660bd1bab2fSreyk 				serverconfig_free(srv_conf);
661bd1bab2fSreyk 				free(srv);
662bd1bab2fSreyk 				YYABORT;
663bd1bab2fSreyk 			}
664bd1bab2fSreyk 
665bd1bab2fSreyk 			DPRINTF("adding location \"%s\" for \"%s[%u]\"",
666bd1bab2fSreyk 			    srv->srv_conf.location,
667bd1bab2fSreyk 			    srv->srv_conf.name, srv->srv_conf.id);
668bd1bab2fSreyk 
669bd1bab2fSreyk 			TAILQ_INSERT_TAIL(conf->sc_servers, srv, srv_entry);
670bd1bab2fSreyk 
671a916ec37Sreyk 			srv = parentsrv;
672412a80baSreyk 			srv_conf = &parentsrv->srv_conf;
673a916ec37Sreyk 			parentsrv = NULL;
674a916ec37Sreyk 		}
675d24f6b1eSreyk 		| DEFAULT TYPE mediastring	{
676d24f6b1eSreyk 			srv_conf->flags |= SRVFLAG_DEFAULT_TYPE;
677d24f6b1eSreyk 			memcpy(&srv_conf->default_type, &media,
678d24f6b1eSreyk 			    sizeof(struct media_type));
679d24f6b1eSreyk 		}
6802fc6bb1cSreyk 		| include
681f5d55328Sflorian 		| hsts				{
682f5d55328Sflorian 			if (parentsrv != NULL) {
683f5d55328Sflorian 				yyerror("hsts inside location");
684f5d55328Sflorian 				YYERROR;
685f5d55328Sflorian 			}
686f5d55328Sflorian 			srv->srv_conf.flags |= SRVFLAG_SERVER_HSTS;
687f5d55328Sflorian 		}
688f5d55328Sflorian 		;
689f5d55328Sflorian 
690e96b74b9Sdenis optfound	: /* empty */	{ $$ = 0; }
691e96b74b9Sdenis 		| FOUND		{ $$ = 1; }
692e96b74b9Sdenis 		| NOT FOUND	{ $$ = -1; }
693e96b74b9Sdenis 		;
694e96b74b9Sdenis 
695f5d55328Sflorian hsts		: HSTS '{' optnl hstsflags_l '}'
696f5d55328Sflorian 		| HSTS hstsflags
697f5d55328Sflorian 		| HSTS
698f5d55328Sflorian 		;
699f5d55328Sflorian 
700f5d55328Sflorian hstsflags_l	: hstsflags optcommanl hstsflags_l
701f5d55328Sflorian 		| hstsflags optnl
702f5d55328Sflorian 		;
703f5d55328Sflorian 
704f5d55328Sflorian hstsflags	: MAXAGE NUMBER		{
705f5d55328Sflorian 			if ($2 < 0 || $2 > INT_MAX) {
706f5d55328Sflorian 				yyerror("invalid number of seconds: %lld", $2);
707f5d55328Sflorian 				YYERROR;
708f5d55328Sflorian 			}
709f5d55328Sflorian 			srv_conf->hsts_max_age = $2;
710f5d55328Sflorian 		}
711f5d55328Sflorian 		| SUBDOMAINS		{
71252f7cd50Sreyk 			srv->srv_conf.hsts_flags |= HSTSFLAG_SUBDOMAINS;
71352f7cd50Sreyk 		}
71452f7cd50Sreyk 		| PRELOAD		{
71552f7cd50Sreyk 			srv->srv_conf.hsts_flags |= HSTSFLAG_PRELOAD;
716f5d55328Sflorian 		}
71743d7585dSreyk 		;
71843d7585dSreyk 
719af5adad1Sreyk fastcgi		: NO FCGI		{
720412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_FCGI;
721412a80baSreyk 			srv_conf->flags |= SRVFLAG_NO_FCGI;
722af5adad1Sreyk 		}
723af5adad1Sreyk 		| FCGI			{
724412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_NO_FCGI;
725412a80baSreyk 			srv_conf->flags |= SRVFLAG_FCGI;
726af5adad1Sreyk 		}
727af5adad1Sreyk 		| FCGI			{
728412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_NO_FCGI;
729412a80baSreyk 			srv_conf->flags |= SRVFLAG_FCGI;
73053c118d9Sreyk 		} '{' optnl fcgiflags_l '}'
731af5adad1Sreyk 		| FCGI			{
732412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_NO_FCGI;
733412a80baSreyk 			srv_conf->flags |= SRVFLAG_FCGI;
734af5adad1Sreyk 		} fcgiflags
735af5adad1Sreyk 		;
736af5adad1Sreyk 
73753c118d9Sreyk fcgiflags_l	: fcgiflags optcommanl fcgiflags_l
73853c118d9Sreyk 		| fcgiflags optnl
739af5adad1Sreyk 		;
740af5adad1Sreyk 
741af5adad1Sreyk fcgiflags	: SOCKET STRING {
7429ea72f95Stracey 			struct sockaddr_un *sun;
7439ea72f95Stracey 			sun = (struct sockaddr_un *)&srv_conf->fastcgi_ss;
7449ea72f95Stracey 			memset(sun, 0, sizeof(*sun));
7459ea72f95Stracey 			sun->sun_family = AF_UNIX;
7469ea72f95Stracey 			if (strlcpy(sun->sun_path, $2, sizeof(sun->sun_path))
7479ea72f95Stracey 			    >= sizeof(sun->sun_path)) {
7489ea72f95Stracey 				yyerror("socket path too long");
749af5adad1Sreyk 				free($2);
750af5adad1Sreyk 				YYERROR;
751af5adad1Sreyk 			}
7529ea72f95Stracey 			srv_conf->fastcgi_ss.ss_len =
7539ea72f95Stracey 			    sizeof(struct sockaddr_un);
754af5adad1Sreyk 			free($2);
755af5adad1Sreyk 		}
7569ea72f95Stracey 		| SOCKET TCP STRING {
7579ea72f95Stracey 			if (get_fastcgi_dest(srv_conf, $3, FCGI_DEFAULT_PORT)
7589ea72f95Stracey 			    == -1) {
7599ea72f95Stracey 				free($3);
7609ea72f95Stracey 				YYERROR;
7619ea72f95Stracey 			}
7629ea72f95Stracey 			free($3);
7639ea72f95Stracey 		}
7649ea72f95Stracey 		| SOCKET TCP STRING fcgiport {
7659ea72f95Stracey 			if (get_fastcgi_dest(srv_conf, $3, $4) == -1) {
7669ea72f95Stracey 				free($3);
7679ea72f95Stracey 				free($4);
7689ea72f95Stracey 				YYERROR;
7699ea72f95Stracey 			}
7709ea72f95Stracey 			free($3);
7719ea72f95Stracey 			free($4);
7729ea72f95Stracey 		}
77303cb893cSpirofti 		| PARAM STRING STRING	{
77403cb893cSpirofti 			struct fastcgi_param	*param;
77503cb893cSpirofti 
77603cb893cSpirofti 			if ((param = calloc(1, sizeof(*param))) == NULL)
77703cb893cSpirofti 				fatal("out of memory");
77803cb893cSpirofti 
77903cb893cSpirofti 			if (strlcpy(param->name, $2, sizeof(param->name)) >=
78003cb893cSpirofti 			    sizeof(param->name)) {
78103cb893cSpirofti 				yyerror("fastcgi_param name truncated");
78203cb893cSpirofti 				free($2);
78303cb893cSpirofti 				free($3);
78403cb893cSpirofti 				free(param);
78503cb893cSpirofti 				YYERROR;
78603cb893cSpirofti 			}
78703cb893cSpirofti 			if (strlcpy(param->value, $3, sizeof(param->value)) >=
78803cb893cSpirofti 			    sizeof(param->value)) {
78903cb893cSpirofti 				yyerror("fastcgi_param value truncated");
79003cb893cSpirofti 				free($2);
79103cb893cSpirofti 				free($3);
79203cb893cSpirofti 				free(param);
79303cb893cSpirofti 				YYERROR;
79403cb893cSpirofti 			}
79503cb893cSpirofti 			free($2);
79603cb893cSpirofti 			free($3);
79703cb893cSpirofti 
79803cb893cSpirofti 			DPRINTF("[%s,%s,%d]: adding param \"%s\" value \"%s\"",
79903cb893cSpirofti 			    srv_conf->location, srv_conf->name, srv_conf->id,
80003cb893cSpirofti 			    param->name, param->value);
80103cb893cSpirofti 			TAILQ_INSERT_HEAD(&srv_conf->fcgiparams, param, entry);
80203cb893cSpirofti 		}
8032cf74b7fSflorian 		| STRIP NUMBER			{
8042cf74b7fSflorian 			if ($2 < 0 || $2 > INT_MAX) {
8052cf74b7fSflorian 				yyerror("invalid fastcgi strip number");
8062cf74b7fSflorian 				YYERROR;
8072cf74b7fSflorian 			}
8082cf74b7fSflorian 			srv_conf->fcgistrip = $2;
8092cf74b7fSflorian 		}
810af5adad1Sreyk 		;
811af5adad1Sreyk 
81253c118d9Sreyk connection	: CONNECTION '{' optnl conflags_l '}'
81353c118d9Sreyk 		| CONNECTION conflags
8147a5a4a11Sreyk 		;
8157a5a4a11Sreyk 
81653c118d9Sreyk conflags_l	: conflags optcommanl conflags_l
81753c118d9Sreyk 		| conflags optnl
8187a5a4a11Sreyk 		;
8197a5a4a11Sreyk 
8207a5a4a11Sreyk conflags	: TIMEOUT timeout		{
8217a5a4a11Sreyk 			memcpy(&srv_conf->timeout, &$2,
8227a5a4a11Sreyk 			    sizeof(struct timeval));
8237a5a4a11Sreyk 		}
824da1a1214Sreyk 		| REQUEST TIMEOUT timeout	{
825da1a1214Sreyk 			memcpy(&srv_conf->requesttimeout, &$3,
826da1a1214Sreyk 			    sizeof(struct timeval));
827da1a1214Sreyk 		}
8287a5a4a11Sreyk 		| MAXIMUM REQUESTS NUMBER	{
8297a5a4a11Sreyk 			srv_conf->maxrequests = $3;
8307a5a4a11Sreyk 		}
8314dd188b5Sreyk 		| MAXIMUM REQUEST BODY NUMBER	{
8324dd188b5Sreyk 			srv_conf->maxrequestbody = $4;
8334dd188b5Sreyk 		}
8347a5a4a11Sreyk 		;
8357a5a4a11Sreyk 
83653c118d9Sreyk tls		: TLS '{' optnl tlsopts_l '}'
83753c118d9Sreyk 		| TLS tlsopts
83896d01691Sjsing 		;
83996d01691Sjsing 
84053c118d9Sreyk tlsopts_l	: tlsopts optcommanl tlsopts_l
84153c118d9Sreyk 		| tlsopts optnl
84296d01691Sjsing 		;
84396d01691Sjsing 
844a760b3d3Sreyk tlsopts		: CERTIFICATE STRING		{
845a760b3d3Sreyk 			free(srv_conf->tls_cert_file);
846a760b3d3Sreyk 			if ((srv_conf->tls_cert_file = strdup($2)) == NULL)
84796d01691Sjsing 				fatal("out of memory");
84896d01691Sjsing 			free($2);
84996d01691Sjsing 		}
85096d01691Sjsing 		| KEY STRING			{
851a760b3d3Sreyk 			free(srv_conf->tls_key_file);
852a760b3d3Sreyk 			if ((srv_conf->tls_key_file = strdup($2)) == NULL)
85396d01691Sjsing 				fatal("out of memory");
85496d01691Sjsing 			free($2);
85596d01691Sjsing 		}
856e80948e2Sbeck 		| OCSP STRING			{
857e80948e2Sbeck 			free(srv_conf->tls_ocsp_staple_file);
858e80948e2Sbeck 			if ((srv_conf->tls_ocsp_staple_file = strdup($2))
859e80948e2Sbeck 			    == NULL)
860e80948e2Sbeck 				fatal("out of memory");
861e80948e2Sbeck 			free($2);
862e80948e2Sbeck 		}
86396d01691Sjsing 		| CIPHERS STRING		{
864a760b3d3Sreyk 			if (strlcpy(srv_conf->tls_ciphers, $2,
865a760b3d3Sreyk 			    sizeof(srv_conf->tls_ciphers)) >=
866a760b3d3Sreyk 			    sizeof(srv_conf->tls_ciphers)) {
86796d01691Sjsing 				yyerror("ciphers too long");
86896d01691Sjsing 				free($2);
86996d01691Sjsing 				YYERROR;
87096d01691Sjsing 			}
87196d01691Sjsing 			free($2);
87296d01691Sjsing 		}
8731d0dc528Sjsing 		| CLIENT CA STRING tlsclientopt {
8741d0dc528Sjsing 			srv_conf->tls_flags |= TLSFLAG_CA;
8751d0dc528Sjsing 			free(srv_conf->tls_ca_file);
8761d0dc528Sjsing 			if ((srv_conf->tls_ca_file = strdup($3)) == NULL)
8771d0dc528Sjsing 				fatal("out of memory");
8781d0dc528Sjsing 			free($3);
8791d0dc528Sjsing 		}
880051776c0Sjsing 		| DHE STRING			{
881051776c0Sjsing 			if (strlcpy(srv_conf->tls_dhe_params, $2,
882051776c0Sjsing 			    sizeof(srv_conf->tls_dhe_params)) >=
883051776c0Sjsing 			    sizeof(srv_conf->tls_dhe_params)) {
884051776c0Sjsing 				yyerror("dhe too long");
885051776c0Sjsing 				free($2);
886051776c0Sjsing 				YYERROR;
887051776c0Sjsing 			}
888051776c0Sjsing 			free($2);
889051776c0Sjsing 		}
890051776c0Sjsing 		| ECDHE STRING			{
89189f7e997Sjsing 			if (strlcpy(srv_conf->tls_ecdhe_curves, $2,
89289f7e997Sjsing 			    sizeof(srv_conf->tls_ecdhe_curves)) >=
89389f7e997Sjsing 			    sizeof(srv_conf->tls_ecdhe_curves)) {
894051776c0Sjsing 				yyerror("ecdhe too long");
895051776c0Sjsing 				free($2);
896051776c0Sjsing 				YYERROR;
897051776c0Sjsing 			}
898051776c0Sjsing 			free($2);
899051776c0Sjsing 		}
9003fb73497Sjsing 		| PROTOCOLS STRING		{
9013fb73497Sjsing 			if (tls_config_parse_protocols(
9023fb73497Sjsing 			    &srv_conf->tls_protocols, $2) != 0) {
903e1f28ec9Sjsing 				yyerror("invalid tls protocols");
9043fb73497Sjsing 				free($2);
9053fb73497Sjsing 				YYERROR;
9063fb73497Sjsing 			}
9073fb73497Sjsing 			free($2);
9083fb73497Sjsing 		}
909fe006a11Sclaudio 		| TICKET LIFETIME DEFAULT	{
910fe006a11Sclaudio 			srv_conf->tls_ticket_lifetime = SERVER_DEF_TLS_LIFETIME;
911fe006a11Sclaudio 		}
912fe006a11Sclaudio 		| TICKET LIFETIME NUMBER	{
913fe006a11Sclaudio 			if ($3 != 0 && $3 < SERVER_MIN_TLS_LIFETIME) {
914fe006a11Sclaudio 				yyerror("ticket lifetime too small");
915fe006a11Sclaudio 				YYERROR;
916fe006a11Sclaudio 			}
917fe006a11Sclaudio 			if ($3 > SERVER_MAX_TLS_LIFETIME) {
918fe006a11Sclaudio 				yyerror("ticket lifetime too large");
919fe006a11Sclaudio 				YYERROR;
920fe006a11Sclaudio 			}
921fe006a11Sclaudio 			srv_conf->tls_ticket_lifetime = $3;
922fe006a11Sclaudio 		}
923fe006a11Sclaudio 		| NO TICKET			{
924fe006a11Sclaudio 			srv_conf->tls_ticket_lifetime = 0;
925fe006a11Sclaudio 		}
92696d01691Sjsing 		;
92796d01691Sjsing 
9281d0dc528Sjsing tlsclientopt	: /* empty */
9291d0dc528Sjsing 		| tlsclientopt CRL STRING	{
9301d0dc528Sjsing 			srv_conf->tls_flags = TLSFLAG_CRL;
9311d0dc528Sjsing 			free(srv_conf->tls_crl_file);
9321d0dc528Sjsing 			if ((srv_conf->tls_crl_file = strdup($3)) == NULL)
9331d0dc528Sjsing 				fatal("out of memory");
9341d0dc528Sjsing 			free($3);
9351d0dc528Sjsing 		}
9361d0dc528Sjsing 		| tlsclientopt OPTIONAL		{
9371d0dc528Sjsing 			srv_conf->tls_flags |= TLSFLAG_OPTIONAL;
9381d0dc528Sjsing 		}
9391d0dc528Sjsing 		;
94053c118d9Sreyk root		: ROOT rootflags
94153c118d9Sreyk 		| ROOT '{' optnl rootflags_l '}'
94253c118d9Sreyk 		;
94353c118d9Sreyk 
94453c118d9Sreyk rootflags_l	: rootflags optcommanl rootflags_l
94553c118d9Sreyk 		| rootflags optnl
9464624b10aSchrisz 		;
9474624b10aSchrisz 
9484624b10aSchrisz rootflags	: STRING		{
9494624b10aSchrisz 			if (strlcpy(srv->srv_conf.root, $1,
9504624b10aSchrisz 			    sizeof(srv->srv_conf.root)) >=
9514624b10aSchrisz 			    sizeof(srv->srv_conf.root)) {
9524624b10aSchrisz 				yyerror("document root too long");
9534624b10aSchrisz 				free($1);
9544624b10aSchrisz 				YYERROR;
9554624b10aSchrisz 			}
9564624b10aSchrisz 			free($1);
9574624b10aSchrisz 			srv->srv_conf.flags |= SRVFLAG_ROOT;
9584624b10aSchrisz 		}
959de6c234aSreyk 		;
960de6c234aSreyk 
961de6c234aSreyk request		: REQUEST requestflags
962de6c234aSreyk 		| REQUEST '{' optnl requestflags_l '}'
963de6c234aSreyk 		;
964de6c234aSreyk 
965de6c234aSreyk requestflags_l	: requestflags optcommanl requestflags_l
966de6c234aSreyk 		| requestflags optnl
967de6c234aSreyk 		;
968de6c234aSreyk 
96993038d14Sreyk requestflags	: REWRITE STRING		{
97093038d14Sreyk 			if (strlcpy(srv->srv_conf.path, $2,
97193038d14Sreyk 			    sizeof(srv->srv_conf.path)) >=
97293038d14Sreyk 			    sizeof(srv->srv_conf.path)) {
97393038d14Sreyk 				yyerror("request path too long");
97493038d14Sreyk 				free($2);
97593038d14Sreyk 				YYERROR;
97693038d14Sreyk 			}
97793038d14Sreyk 			free($2);
97893038d14Sreyk 			srv->srv_conf.flags |= SRVFLAG_PATH_REWRITE;
97993038d14Sreyk 			srv->srv_conf.flags &= ~SRVFLAG_NO_PATH_REWRITE;
98093038d14Sreyk 		}
98193038d14Sreyk 		| NO REWRITE			{
98293038d14Sreyk 			srv->srv_conf.flags |= SRVFLAG_NO_PATH_REWRITE;
98393038d14Sreyk 			srv->srv_conf.flags &= ~SRVFLAG_PATH_REWRITE;
98493038d14Sreyk 		}
98593038d14Sreyk 		| STRIP NUMBER			{
9864624b10aSchrisz 			if ($2 < 0 || $2 > INT_MAX) {
9874624b10aSchrisz 				yyerror("invalid strip number");
9884624b10aSchrisz 				YYERROR;
9894624b10aSchrisz 			}
9904624b10aSchrisz 			srv->srv_conf.strip = $2;
9914624b10aSchrisz 		}
9924624b10aSchrisz 		;
9934624b10aSchrisz 
994602531d9Sreyk authenticate	: NO AUTHENTICATE		{
995602531d9Sreyk 			srv->srv_conf.flags |= SRVFLAG_NO_AUTH;
996602531d9Sreyk 		}
997602531d9Sreyk 		| AUTHENTICATE authopts		{
998602531d9Sreyk 			struct auth	*auth;
999602531d9Sreyk 
1000602531d9Sreyk 			if ((auth = auth_add(conf->sc_auth, &$2)) == NULL) {
1001602531d9Sreyk 				yyerror("failed to add auth");
1002602531d9Sreyk 				YYERROR;
1003602531d9Sreyk 			}
1004602531d9Sreyk 
1005602531d9Sreyk 			if (auth->auth_id == 0) {
1006602531d9Sreyk 				/* New htpasswd, get new Id */
1007602531d9Sreyk 				auth->auth_id = ++last_auth_id;
1008602531d9Sreyk 				if (last_auth_id == INT_MAX) {
1009602531d9Sreyk 					yyerror("too many auth ids defined");
1010602531d9Sreyk 					auth_free(conf->sc_auth, auth);
1011602531d9Sreyk 					YYERROR;
1012602531d9Sreyk 				}
1013602531d9Sreyk 			}
1014602531d9Sreyk 
1015602531d9Sreyk 			srv->srv_conf.auth_id = auth->auth_id;
1016602531d9Sreyk 			srv->srv_conf.flags |= SRVFLAG_AUTH;
1017602531d9Sreyk 		}
1018602531d9Sreyk 		;
1019602531d9Sreyk 
1020602531d9Sreyk authopts	: STRING WITH STRING	{
1021602531d9Sreyk 			if (strlcpy(srv->srv_conf.auth_realm, $1,
1022e286121aSflorian 			    sizeof(srv->srv_conf.auth_realm)) >=
1023e286121aSflorian 			    sizeof(srv->srv_conf.auth_realm)) {
1024e286121aSflorian 				yyerror("basic auth realm name too long");
1025602531d9Sreyk 				free($1);
1026e286121aSflorian 				YYERROR;
1027e286121aSflorian 			}
1028602531d9Sreyk 			free($1);
1029602531d9Sreyk 			if (strlcpy($$.auth_htpasswd, $3,
1030602531d9Sreyk 			    sizeof($$.auth_htpasswd)) >=
1031602531d9Sreyk 			    sizeof($$.auth_htpasswd)) {
1032e286121aSflorian 				yyerror("password file name too long");
1033e286121aSflorian 				free($3);
1034e286121aSflorian 				YYERROR;
1035e286121aSflorian 			}
1036e286121aSflorian 			free($3);
1037602531d9Sreyk 
1038602531d9Sreyk 		}
1039602531d9Sreyk 		| WITH STRING		{
1040602531d9Sreyk 			if (strlcpy($$.auth_htpasswd, $2,
1041602531d9Sreyk 			    sizeof($$.auth_htpasswd)) >=
1042602531d9Sreyk 			    sizeof($$.auth_htpasswd)) {
1043602531d9Sreyk 				yyerror("password file name too long");
1044602531d9Sreyk 				free($2);
1045602531d9Sreyk 				YYERROR;
1046602531d9Sreyk 			}
1047602531d9Sreyk 			free($2);
1048e286121aSflorian 		};
1049e286121aSflorian 
105053c118d9Sreyk directory	: DIRECTORY dirflags
105153c118d9Sreyk 		| DIRECTORY '{' optnl dirflags_l '}'
105253c118d9Sreyk 		;
105353c118d9Sreyk 
105453c118d9Sreyk dirflags_l	: dirflags optcommanl dirflags_l
105553c118d9Sreyk 		| dirflags optnl
105643d7585dSreyk 		;
105743d7585dSreyk 
105843d7585dSreyk dirflags	: INDEX STRING		{
1059412a80baSreyk 			if (strlcpy(srv_conf->index, $2,
1060412a80baSreyk 			    sizeof(srv_conf->index)) >=
1061412a80baSreyk 			    sizeof(srv_conf->index)) {
106243d7585dSreyk 				yyerror("index file too long");
106343d7585dSreyk 				free($2);
106443d7585dSreyk 				YYERROR;
106543d7585dSreyk 			}
1066412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_NO_INDEX;
1067412a80baSreyk 			srv_conf->flags |= SRVFLAG_INDEX;
106843d7585dSreyk 			free($2);
106943d7585dSreyk 		}
107043d7585dSreyk 		| NO INDEX		{
1071412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_INDEX;
1072412a80baSreyk 			srv_conf->flags |= SRVFLAG_NO_INDEX;
107343d7585dSreyk 		}
107443d7585dSreyk 		| AUTO INDEX		{
1075412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_NO_AUTO_INDEX;
1076412a80baSreyk 			srv_conf->flags |= SRVFLAG_AUTO_INDEX;
107743d7585dSreyk 		}
107843d7585dSreyk 		| NO AUTO INDEX		{
1079412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_AUTO_INDEX;
1080412a80baSreyk 			srv_conf->flags |= SRVFLAG_NO_AUTO_INDEX;
108143d7585dSreyk 		}
1082b7b6a941Sreyk 		;
1083b7b6a941Sreyk 
1084844c3615Sreyk 
1085844c3615Sreyk logformat	: LOG logflags
108653c118d9Sreyk 		| LOG '{' optnl logflags_l '}'
1087844c3615Sreyk 		| NO LOG		{
1088412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_LOG;
1089412a80baSreyk 			srv_conf->flags |= SRVFLAG_NO_LOG;
1090844c3615Sreyk 		}
1091844c3615Sreyk 		;
1092844c3615Sreyk 
109353c118d9Sreyk logflags_l	: logflags optcommanl logflags_l
109453c118d9Sreyk 		| logflags optnl
1095844c3615Sreyk 		;
1096844c3615Sreyk 
1097cef70b14Sreyk logflags	: STYLE logstyle
1098cef70b14Sreyk 		| SYSLOG		{
1099412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_NO_SYSLOG;
1100412a80baSreyk 			srv_conf->flags |= SRVFLAG_SYSLOG;
1101cef70b14Sreyk 		}
1102cef70b14Sreyk 		| NO SYSLOG		{
1103412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_SYSLOG;
1104412a80baSreyk 			srv_conf->flags |= SRVFLAG_NO_SYSLOG;
1105cef70b14Sreyk 		}
1106cf605f40Sreyk 		| ACCESS STRING		{
1107412a80baSreyk 			if (strlcpy(srv_conf->accesslog, $2,
1108412a80baSreyk 			    sizeof(srv_conf->accesslog)) >=
1109412a80baSreyk 			    sizeof(srv_conf->accesslog)) {
1110cf605f40Sreyk 				yyerror("access log name too long");
1111cf605f40Sreyk 				free($2);
1112cf605f40Sreyk 				YYERROR;
1113cf605f40Sreyk 			}
1114cf605f40Sreyk 			free($2);
1115412a80baSreyk 			srv_conf->flags |= SRVFLAG_ACCESS_LOG;
1116cf605f40Sreyk 		}
1117cf605f40Sreyk 		| ERR STRING		{
1118412a80baSreyk 			if (strlcpy(srv_conf->errorlog, $2,
1119412a80baSreyk 			    sizeof(srv_conf->errorlog)) >=
1120412a80baSreyk 			    sizeof(srv_conf->errorlog)) {
1121cf605f40Sreyk 				yyerror("error log name too long");
1122cf605f40Sreyk 				free($2);
1123cf605f40Sreyk 				YYERROR;
1124cf605f40Sreyk 			}
1125cf605f40Sreyk 			free($2);
1126412a80baSreyk 			srv_conf->flags |= SRVFLAG_ERROR_LOG;
1127cf605f40Sreyk 		}
1128cef70b14Sreyk 		;
1129cef70b14Sreyk 
1130cef70b14Sreyk logstyle	: COMMON		{
1131412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_NO_LOG;
1132412a80baSreyk 			srv_conf->flags |= SRVFLAG_LOG;
1133412a80baSreyk 			srv_conf->logformat = LOG_FORMAT_COMMON;
1134ea62a379Sdoug 		}
1135844c3615Sreyk 		| COMBINED		{
1136412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_NO_LOG;
1137412a80baSreyk 			srv_conf->flags |= SRVFLAG_LOG;
1138412a80baSreyk 			srv_conf->logformat = LOG_FORMAT_COMBINED;
1139ea62a379Sdoug 		}
1140844c3615Sreyk 		| CONNECTION		{
1141412a80baSreyk 			srv_conf->flags &= ~SRVFLAG_NO_LOG;
1142412a80baSreyk 			srv_conf->flags |= SRVFLAG_LOG;
1143412a80baSreyk 			srv_conf->logformat = LOG_FORMAT_CONNECTION;
1144944a3fefSreyk 		}
114534ff7cffStb 		| FORWARDED		{
114634ff7cffStb 			srv_conf->flags &= ~SRVFLAG_NO_LOG;
114734ff7cffStb 			srv_conf->flags |= SRVFLAG_LOG;
114834ff7cffStb 			srv_conf->logformat = LOG_FORMAT_FORWARDED;
114934ff7cffStb 		}
1150ea62a379Sdoug 		;
1151ea62a379Sdoug 
1152f8932becSreyk filter		: block RETURN NUMBER optstring	{
1153f8932becSreyk 			if ($3 <= 0 || server_httperror_byid($3) == NULL) {
1154f8932becSreyk 				yyerror("invalid return code: %lld", $3);
1155f8932becSreyk 				free($4);
1156f8932becSreyk 				YYERROR;
1157f8932becSreyk 			}
1158f8932becSreyk 			srv_conf->return_code = $3;
1159f8932becSreyk 
1160f8932becSreyk 			if ($4 != NULL) {
1161f8932becSreyk 				/* Only for 3xx redirection headers */
1162f8932becSreyk 				if ($3 < 300 || $3 > 399) {
1163f8932becSreyk 					yyerror("invalid return code for "
1164f8932becSreyk 					    "location URI");
1165f8932becSreyk 					free($4);
1166f8932becSreyk 					YYERROR;
1167f8932becSreyk 				}
1168f8932becSreyk 				srv_conf->return_uri = $4;
1169f8932becSreyk 				srv_conf->return_uri_len = strlen($4) + 1;
1170f8932becSreyk 			}
1171f8932becSreyk 		}
1172f8932becSreyk 		| block DROP			{
1173f8932becSreyk 			/* No return code, silently drop the connection */
1174f8932becSreyk 			srv_conf->return_code = 0;
1175f8932becSreyk 		}
1176f8932becSreyk 		| block				{
1177f8932becSreyk 			/* Forbidden */
1178f8932becSreyk 			srv_conf->return_code = 403;
1179f8932becSreyk 		}
1180f8932becSreyk 		| PASS				{
1181f8932becSreyk 			srv_conf->flags &= ~SRVFLAG_BLOCK;
1182f8932becSreyk 			srv_conf->flags |= SRVFLAG_NO_BLOCK;
1183f8932becSreyk 		}
1184f8932becSreyk 		;
1185f8932becSreyk 
1186f8932becSreyk block		: BLOCK				{
1187f8932becSreyk 			srv_conf->flags &= ~SRVFLAG_NO_BLOCK;
1188f8932becSreyk 			srv_conf->flags |= SRVFLAG_BLOCK;
1189f8932becSreyk 		}
1190f8932becSreyk 		;
1191f8932becSreyk 
119259355b5aSreyk optmatch	: /* empty */		{ $$ = 0; }
119359355b5aSreyk 		| MATCH			{ $$ = 1; }
119459355b5aSreyk 		;
119559355b5aSreyk 
1196f8932becSreyk optstring	: /* empty */		{ $$ = NULL; }
1197f8932becSreyk 		| STRING		{ $$ = $1; }
1198f8932becSreyk 		;
1199f8932becSreyk 
12009ea72f95Stracey fcgiport	: NUMBER		{
12019ea72f95Stracey 			if ($1 <= 0 || $1 > (int)USHRT_MAX) {
12029ea72f95Stracey 				yyerror("invalid port: %lld", $1);
12039ea72f95Stracey 				YYERROR;
12049ea72f95Stracey 			}
12059ea72f95Stracey 			if (asprintf(&$$, "%lld", $1) == -1) {
12069ea72f95Stracey 				yyerror("out of memory");
12079ea72f95Stracey 				YYERROR;
12089ea72f95Stracey 			}
12099ea72f95Stracey 		}
1210b9cb0b4fStracey 		| STRING		{
1211b9cb0b4fStracey 			if (getservice($1) <= 0) {
1212b9cb0b4fStracey 				yyerror("invalid port: %s", $1);
1213b9cb0b4fStracey 				free($1);
1214b9cb0b4fStracey 				YYERROR;
1215b9cb0b4fStracey 			}
1216b9cb0b4fStracey 
1217b9cb0b4fStracey 			$$ = $1;
1218b9cb0b4fStracey 		}
12199ea72f95Stracey 		;
12209ea72f95Stracey 
1221*8e3d8d5aSbluhm gzip_static	: NO GZIPSTATIC		{
1222*8e3d8d5aSbluhm 			srv->srv_conf.flags &= ~SRVFLAG_GZIP_STATIC;
1223*8e3d8d5aSbluhm 		}
1224*8e3d8d5aSbluhm 		| GZIPSTATIC		{
1225*8e3d8d5aSbluhm 			srv->srv_conf.flags |= SRVFLAG_GZIP_STATIC;
1226*8e3d8d5aSbluhm 		}
1227*8e3d8d5aSbluhm 		;
1228*8e3d8d5aSbluhm 
122953c118d9Sreyk tcpip		: TCP '{' optnl tcpflags_l '}'
123053c118d9Sreyk 		| TCP tcpflags
12317a5a4a11Sreyk 		;
12327a5a4a11Sreyk 
123353c118d9Sreyk tcpflags_l	: tcpflags optcommanl tcpflags_l
123453c118d9Sreyk 		| tcpflags optnl
1235dd598c8dSreyk 		;
1236dd598c8dSreyk 
1237dd598c8dSreyk tcpflags	: SACK			{ srv_conf->tcpflags |= TCPFLAG_SACK; }
1238dd598c8dSreyk 		| NO SACK		{ srv_conf->tcpflags |= TCPFLAG_NSACK; }
1239dd598c8dSreyk 		| NODELAY		{
1240dd598c8dSreyk 			srv_conf->tcpflags |= TCPFLAG_NODELAY;
1241dd598c8dSreyk 		}
1242dd598c8dSreyk 		| NO NODELAY		{
1243dd598c8dSreyk 			srv_conf->tcpflags |= TCPFLAG_NNODELAY;
1244dd598c8dSreyk 		}
1245dd598c8dSreyk 		| BACKLOG NUMBER	{
1246dd598c8dSreyk 			if ($2 < 0 || $2 > SERVER_MAX_CLIENTS) {
1247260af8fcSdoug 				yyerror("invalid backlog: %lld", $2);
1248dd598c8dSreyk 				YYERROR;
1249dd598c8dSreyk 			}
1250dd598c8dSreyk 			srv_conf->tcpbacklog = $2;
1251dd598c8dSreyk 		}
1252dd598c8dSreyk 		| SOCKET BUFFER NUMBER	{
1253dd598c8dSreyk 			srv_conf->tcpflags |= TCPFLAG_BUFSIZ;
1254dd598c8dSreyk 			if ((srv_conf->tcpbufsiz = $3) < 0) {
1255260af8fcSdoug 				yyerror("invalid socket buffer size: %lld", $3);
1256dd598c8dSreyk 				YYERROR;
1257dd598c8dSreyk 			}
1258dd598c8dSreyk 		}
1259dd598c8dSreyk 		| IP STRING NUMBER	{
1260dd598c8dSreyk 			if ($3 < 0) {
1261260af8fcSdoug 				yyerror("invalid ttl: %lld", $3);
1262dd598c8dSreyk 				free($2);
1263dd598c8dSreyk 				YYERROR;
1264dd598c8dSreyk 			}
1265dd598c8dSreyk 			if (strcasecmp("ttl", $2) == 0) {
1266dd598c8dSreyk 				srv_conf->tcpflags |= TCPFLAG_IPTTL;
1267dd598c8dSreyk 				srv_conf->tcpipttl = $3;
1268dd598c8dSreyk 			} else if (strcasecmp("minttl", $2) == 0) {
1269dd598c8dSreyk 				srv_conf->tcpflags |= TCPFLAG_IPMINTTL;
1270dd598c8dSreyk 				srv_conf->tcpipminttl = $3;
1271dd598c8dSreyk 			} else {
1272dd598c8dSreyk 				yyerror("invalid TCP/IP flag: %s", $2);
1273dd598c8dSreyk 				free($2);
1274dd598c8dSreyk 				YYERROR;
1275dd598c8dSreyk 			}
1276dd598c8dSreyk 			free($2);
1277dd598c8dSreyk 		}
1278dd598c8dSreyk 		;
1279dd598c8dSreyk 
12809b9ff8ecSreyk types		: TYPES	'{' optnl mediaopts_l '}'
12819b9ff8ecSreyk 		;
12829b9ff8ecSreyk 
12839b9ff8ecSreyk mediaopts_l	: mediaopts_l mediaoptsl nl
1284bb431cfaSreyk 		| mediaoptsl nl
12859b9ff8ecSreyk 		;
12869b9ff8ecSreyk 
1287d24f6b1eSreyk mediaoptsl	: mediastring medianames_l optsemicolon
1288d24f6b1eSreyk 		| include
1289d24f6b1eSreyk 		;
1290d24f6b1eSreyk 
1291d24f6b1eSreyk mediastring	: STRING '/' STRING	{
12929b9ff8ecSreyk 			if (strlcpy(media.media_type, $1,
12939b9ff8ecSreyk 			    sizeof(media.media_type)) >=
12949b9ff8ecSreyk 			    sizeof(media.media_type) ||
12959b9ff8ecSreyk 			    strlcpy(media.media_subtype, $3,
12969b9ff8ecSreyk 			    sizeof(media.media_subtype)) >=
12979b9ff8ecSreyk 			    sizeof(media.media_subtype)) {
12989b9ff8ecSreyk 				yyerror("media type too long");
12999b9ff8ecSreyk 				free($1);
13009b9ff8ecSreyk 				free($3);
13019b9ff8ecSreyk 				YYERROR;
13029b9ff8ecSreyk 			}
13039b9ff8ecSreyk 			free($1);
13049b9ff8ecSreyk 			free($3);
1305d24f6b1eSreyk 		}
13069b9ff8ecSreyk 		;
13079b9ff8ecSreyk 
13089b9ff8ecSreyk medianames_l	: medianames_l medianamesl
13099b9ff8ecSreyk 		| medianamesl
13109b9ff8ecSreyk 		;
13119b9ff8ecSreyk 
1312bb431cfaSreyk medianamesl	: numberstring				{
13139b9ff8ecSreyk 			if (strlcpy(media.media_name, $1,
13149b9ff8ecSreyk 			    sizeof(media.media_name)) >=
13159b9ff8ecSreyk 			    sizeof(media.media_name)) {
13169b9ff8ecSreyk 				yyerror("media name too long");
13179b9ff8ecSreyk 				free($1);
13189b9ff8ecSreyk 				YYERROR;
13199b9ff8ecSreyk 			}
13209b9ff8ecSreyk 			free($1);
13219b9ff8ecSreyk 
1322a0774621Sreyk 			if (!loadcfg)
1323a0774621Sreyk 				break;
1324a0774621Sreyk 
13259b9ff8ecSreyk 			if (media_add(conf->sc_mediatypes, &media) == NULL) {
13269b9ff8ecSreyk 				yyerror("failed to add media type");
13279b9ff8ecSreyk 				YYERROR;
13289b9ff8ecSreyk 			}
13299b9ff8ecSreyk 		}
13309b9ff8ecSreyk 		;
13319b9ff8ecSreyk 
1332f90e0272Sreyk port		: PORT NUMBER {
13330ead3a23Sflorian 			if ($2 <= 0 || $2 > (int)USHRT_MAX) {
1334260af8fcSdoug 				yyerror("invalid port: %lld", $2);
1335b7b6a941Sreyk 				YYERROR;
1336b7b6a941Sreyk 			}
1337b7b6a941Sreyk 			$$.val[0] = htons($2);
1338fbb03ccdSbluhm 			$$.op = 1;
1339b7b6a941Sreyk 		}
1340551bd022Sreyk 		| PORT STRING {
1341551bd022Sreyk 			int	 val;
1342551bd022Sreyk 
1343551bd022Sreyk 			if ((val = getservice($2)) == -1) {
1344551bd022Sreyk 				yyerror("invalid port: %s", $2);
1345551bd022Sreyk 				free($2);
1346551bd022Sreyk 				YYERROR;
1347551bd022Sreyk 			}
1348551bd022Sreyk 			free($2);
1349551bd022Sreyk 
1350551bd022Sreyk 			$$.val[0] = val;
1351fbb03ccdSbluhm 			$$.op = 1;
1352551bd022Sreyk 		}
1353b7b6a941Sreyk 		;
1354b7b6a941Sreyk 
13557a5a4a11Sreyk timeout		: NUMBER
13567a5a4a11Sreyk 		{
13577a5a4a11Sreyk 			if ($1 < 0) {
1358260af8fcSdoug 				yyerror("invalid timeout: %lld", $1);
13597a5a4a11Sreyk 				YYERROR;
13607a5a4a11Sreyk 			}
13617a5a4a11Sreyk 			$$.tv_sec = $1;
13627a5a4a11Sreyk 			$$.tv_usec = 0;
13637a5a4a11Sreyk 		}
13647a5a4a11Sreyk 		;
13657a5a4a11Sreyk 
1366bb431cfaSreyk numberstring	: NUMBER		{
1367bb431cfaSreyk 			char *s;
1368bb431cfaSreyk 			if (asprintf(&s, "%lld", $1) == -1) {
1369bb431cfaSreyk 				yyerror("asprintf: number");
1370bb431cfaSreyk 				YYERROR;
1371bb431cfaSreyk 			}
1372bb431cfaSreyk 			$$ = s;
1373bb431cfaSreyk 		}
1374bb431cfaSreyk 		| STRING
1375bb431cfaSreyk 		;
1376bb431cfaSreyk 
1377bb431cfaSreyk optsemicolon	: ';'
1378bb431cfaSreyk 		|
1379bb431cfaSreyk 		;
1380bb431cfaSreyk 
1381b7b6a941Sreyk optnl		: '\n' optnl
1382b7b6a941Sreyk 		|
1383b7b6a941Sreyk 		;
1384b7b6a941Sreyk 
138553c118d9Sreyk optcommanl	: ',' optnl
138653c118d9Sreyk 		| nl
138753c118d9Sreyk 		;
138853c118d9Sreyk 
1389b7b6a941Sreyk nl		: '\n' optnl
1390b7b6a941Sreyk 		;
1391b7b6a941Sreyk 
1392b7b6a941Sreyk %%
1393b7b6a941Sreyk 
1394b7b6a941Sreyk struct keywords {
1395b7b6a941Sreyk 	const char	*k_name;
1396b7b6a941Sreyk 	int		 k_val;
1397b7b6a941Sreyk };
1398b7b6a941Sreyk 
1399b7b6a941Sreyk int
yyerror(const char * fmt,...)1400b7b6a941Sreyk yyerror(const char *fmt, ...)
1401b7b6a941Sreyk {
1402b7b6a941Sreyk 	va_list		 ap;
14037d191ae9Sbluhm 	char		*msg;
1404b7b6a941Sreyk 
1405b7b6a941Sreyk 	file->errors++;
1406b7b6a941Sreyk 	va_start(ap, fmt);
14077d191ae9Sbluhm 	if (vasprintf(&msg, fmt, ap) == -1)
14087d191ae9Sbluhm 		fatalx("yyerror vasprintf");
1409b7b6a941Sreyk 	va_end(ap);
14107d191ae9Sbluhm 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
14117d191ae9Sbluhm 	free(msg);
1412b7b6a941Sreyk 	return (0);
1413b7b6a941Sreyk }
1414b7b6a941Sreyk 
1415b7b6a941Sreyk int
kw_cmp(const void * k,const void * e)1416b7b6a941Sreyk kw_cmp(const void *k, const void *e)
1417b7b6a941Sreyk {
1418b7b6a941Sreyk 	return (strcmp(k, ((const struct keywords *)e)->k_name));
1419b7b6a941Sreyk }
1420b7b6a941Sreyk 
1421b7b6a941Sreyk int
lookup(char * s)1422b7b6a941Sreyk lookup(char *s)
1423b7b6a941Sreyk {
1424b7b6a941Sreyk 	/* this has to be sorted always */
1425b7b6a941Sreyk 	static const struct keywords keywords[] = {
1426cf605f40Sreyk 		{ "access",		ACCESS },
1427be4c70f0Sreyk 		{ "alias",		ALIAS },
1428e286121aSflorian 		{ "authenticate",	AUTHENTICATE},
142943d7585dSreyk 		{ "auto",		AUTO },
1430dd598c8dSreyk 		{ "backlog",		BACKLOG },
1431f8932becSreyk 		{ "block",		BLOCK },
14324dd188b5Sreyk 		{ "body",		BODY },
1433dd598c8dSreyk 		{ "buffer",		BUFFER },
14341d0dc528Sjsing 		{ "ca",			CA },
143596d01691Sjsing 		{ "certificate",	CERTIFICATE },
1436bde157a8Sjsg 		{ "chroot",		CHROOT },
143796d01691Sjsing 		{ "ciphers",		CIPHERS },
14381d0dc528Sjsing 		{ "client",		CLIENT },
1439ea62a379Sdoug 		{ "combined",		COMBINED },
1440ea62a379Sdoug 		{ "common",		COMMON },
1441944a3fefSreyk 		{ "connection",		CONNECTION },
14421d0dc528Sjsing 		{ "crl",		CRL },
1443d24f6b1eSreyk 		{ "default",		DEFAULT },
1444051776c0Sjsing 		{ "dhe",		DHE },
144543d7585dSreyk 		{ "directory",		DIRECTORY },
1446f8932becSreyk 		{ "drop",		DROP },
1447051776c0Sjsing 		{ "ecdhe",		ECDHE },
1448cbced0bdSian 		{ "errdocs",		ERRDOCS },
1449cf605f40Sreyk 		{ "error",		ERR },
1450435dc7cdSreyk 		{ "fastcgi",		FCGI },
145134ff7cffStb 		{ "forwarded",		FORWARDED },
1452e96b74b9Sdenis 		{ "found",		FOUND },
1453*8e3d8d5aSbluhm 		{ "gzip-static",	GZIPSTATIC },
1454f5d55328Sflorian 		{ "hsts",		HSTS },
1455b7b6a941Sreyk 		{ "include",		INCLUDE },
145643d7585dSreyk 		{ "index",		INDEX },
1457dd598c8dSreyk 		{ "ip",			IP },
145896d01691Sjsing 		{ "key",		KEY },
1459fe006a11Sclaudio 		{ "lifetime",		LIFETIME },
1460b7b6a941Sreyk 		{ "listen",		LISTEN },
1461a916ec37Sreyk 		{ "location",		LOCATION },
1462b7b6a941Sreyk 		{ "log",		LOG },
1463032d2b93Sbeck 		{ "logdir",		LOGDIR },
146459355b5aSreyk 		{ "match",		MATCH },
14657a5a4a11Sreyk 		{ "max",		MAXIMUM },
1466f5d55328Sflorian 		{ "max-age",		MAXAGE },
146743d7585dSreyk 		{ "no",			NO },
1468dd598c8dSreyk 		{ "nodelay",		NODELAY },
1469e96b74b9Sdenis 		{ "not",		NOT },
1470e80948e2Sbeck 		{ "ocsp",		OCSP },
1471b7b6a941Sreyk 		{ "on",			ON },
14721d0dc528Sjsing 		{ "optional",		OPTIONAL },
147303cb893cSpirofti 		{ "param",		PARAM },
1474f8932becSreyk 		{ "pass",		PASS },
1475b7b6a941Sreyk 		{ "port",		PORT },
1476b7b6a941Sreyk 		{ "prefork",		PREFORK },
147752f7cd50Sreyk 		{ "preload",		PRELOAD },
14783fb73497Sjsing 		{ "protocols",		PROTOCOLS },
14794dd188b5Sreyk 		{ "request",		REQUEST },
14807a5a4a11Sreyk 		{ "requests",		REQUESTS },
1481f8932becSreyk 		{ "return",		RETURN },
148293038d14Sreyk 		{ "rewrite",		REWRITE },
14836feb7b3fSreyk 		{ "root",		ROOT },
1484dd598c8dSreyk 		{ "sack",		SACK },
1485b7b6a941Sreyk 		{ "server",		SERVER },
1486af5adad1Sreyk 		{ "socket",		SOCKET },
14874624b10aSchrisz 		{ "strip",		STRIP },
1488cef70b14Sreyk 		{ "style",		STYLE },
1489f5d55328Sflorian 		{ "subdomains",		SUBDOMAINS },
1490844c3615Sreyk 		{ "syslog",		SYSLOG },
1491dd598c8dSreyk 		{ "tcp",		TCP },
1492fe006a11Sclaudio 		{ "ticket",		TICKET },
14937a5a4a11Sreyk 		{ "timeout",		TIMEOUT },
1494a760b3d3Sreyk 		{ "tls",		TLS },
1495d24f6b1eSreyk 		{ "type",		TYPE },
1496e286121aSflorian 		{ "types",		TYPES },
1497e286121aSflorian 		{ "with",		WITH }
1498b7b6a941Sreyk 	};
1499b7b6a941Sreyk 	const struct keywords	*p;
1500b7b6a941Sreyk 
1501b7b6a941Sreyk 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
1502b7b6a941Sreyk 	    sizeof(keywords[0]), kw_cmp);
1503b7b6a941Sreyk 
1504b7b6a941Sreyk 	if (p)
1505b7b6a941Sreyk 		return (p->k_val);
1506b7b6a941Sreyk 	else
1507b7b6a941Sreyk 		return (STRING);
1508b7b6a941Sreyk }
1509b7b6a941Sreyk 
1510cc380947Sdenis #define START_EXPAND	1
1511cc380947Sdenis #define DONE_EXPAND	2
1512b7b6a941Sreyk 
1513cc380947Sdenis static int	expanding;
1514cc380947Sdenis 
1515cc380947Sdenis int
igetc(void)1516cc380947Sdenis igetc(void)
1517cc380947Sdenis {
1518cc380947Sdenis 	int	c;
1519cc380947Sdenis 
1520cc380947Sdenis 	while (1) {
1521cc380947Sdenis 		if (file->ungetpos > 0)
1522cc380947Sdenis 			c = file->ungetbuf[--file->ungetpos];
1523cc380947Sdenis 		else
1524cc380947Sdenis 			c = getc(file->stream);
1525cc380947Sdenis 
1526cc380947Sdenis 		if (c == START_EXPAND)
1527cc380947Sdenis 			expanding = 1;
1528cc380947Sdenis 		else if (c == DONE_EXPAND)
1529cc380947Sdenis 			expanding = 0;
1530cc380947Sdenis 		else
1531cc380947Sdenis 			break;
1532cc380947Sdenis 	}
1533cc380947Sdenis 	return (c);
1534cc380947Sdenis }
1535b7b6a941Sreyk 
1536b7b6a941Sreyk int
lgetc(int quotec)1537b7b6a941Sreyk lgetc(int quotec)
1538b7b6a941Sreyk {
1539b7b6a941Sreyk 	int		c, next;
1540b7b6a941Sreyk 
1541b7b6a941Sreyk 	if (quotec) {
1542cc380947Sdenis 		if ((c = igetc()) == EOF) {
1543b7b6a941Sreyk 			yyerror("reached end of file while parsing "
1544b7b6a941Sreyk 			    "quoted string");
1545b7b6a941Sreyk 			if (file == topfile || popfile() == EOF)
1546b7b6a941Sreyk 				return (EOF);
1547b7b6a941Sreyk 			return (quotec);
1548b7b6a941Sreyk 		}
1549b7b6a941Sreyk 		return (c);
1550b7b6a941Sreyk 	}
1551b7b6a941Sreyk 
1552cc380947Sdenis 	while ((c = igetc()) == '\\') {
1553cc380947Sdenis 		next = igetc();
1554b7b6a941Sreyk 		if (next != '\n') {
1555b7b6a941Sreyk 			c = next;
1556b7b6a941Sreyk 			break;
1557b7b6a941Sreyk 		}
1558b7b6a941Sreyk 		yylval.lineno = file->lineno;
1559b7b6a941Sreyk 		file->lineno++;
1560b7b6a941Sreyk 	}
1561b7b6a941Sreyk 
1562cc380947Sdenis 	if (c == EOF) {
1563cc380947Sdenis 		/*
1564cc380947Sdenis 		 * Fake EOL when hit EOF for the first time. This gets line
1565cc380947Sdenis 		 * count right if last line in included file is syntactically
1566cc380947Sdenis 		 * invalid and has no newline.
1567cc380947Sdenis 		 */
1568cc380947Sdenis 		if (file->eof_reached == 0) {
1569cc380947Sdenis 			file->eof_reached = 1;
1570cc380947Sdenis 			return ('\n');
1571cc380947Sdenis 		}
1572b7b6a941Sreyk 		while (c == EOF) {
1573b7b6a941Sreyk 			if (file == topfile || popfile() == EOF)
1574b7b6a941Sreyk 				return (EOF);
1575cc380947Sdenis 			c = igetc();
1576cc380947Sdenis 		}
1577b7b6a941Sreyk 	}
1578b7b6a941Sreyk 	return (c);
1579b7b6a941Sreyk }
1580b7b6a941Sreyk 
1581cc380947Sdenis void
lungetc(int c)1582b7b6a941Sreyk lungetc(int c)
1583b7b6a941Sreyk {
1584b7b6a941Sreyk 	if (c == EOF)
1585cc380947Sdenis 		return;
1586cc380947Sdenis 
1587cc380947Sdenis 	if (file->ungetpos >= file->ungetsize) {
1588cc380947Sdenis 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
1589cc380947Sdenis 		if (p == NULL)
1590a062aa9dSkrw 			err(1, "%s", __func__);
1591cc380947Sdenis 		file->ungetbuf = p;
1592cc380947Sdenis 		file->ungetsize *= 2;
1593b7b6a941Sreyk 	}
1594cc380947Sdenis 	file->ungetbuf[file->ungetpos++] = c;
1595b7b6a941Sreyk }
1596b7b6a941Sreyk 
1597b7b6a941Sreyk int
findeol(void)1598b7b6a941Sreyk findeol(void)
1599b7b6a941Sreyk {
1600b7b6a941Sreyk 	int	c;
1601b7b6a941Sreyk 
1602b7b6a941Sreyk 	/* skip to either EOF or the first real EOL */
1603b7b6a941Sreyk 	while (1) {
1604b7b6a941Sreyk 		c = lgetc(0);
1605b7b6a941Sreyk 		if (c == '\n') {
1606b7b6a941Sreyk 			file->lineno++;
1607b7b6a941Sreyk 			break;
1608b7b6a941Sreyk 		}
1609b7b6a941Sreyk 		if (c == EOF)
1610b7b6a941Sreyk 			break;
1611b7b6a941Sreyk 	}
1612b7b6a941Sreyk 	return (ERROR);
1613b7b6a941Sreyk }
1614b7b6a941Sreyk 
1615b7b6a941Sreyk int
yylex(void)1616b7b6a941Sreyk yylex(void)
1617b7b6a941Sreyk {
161808f6ba19Snaddy 	char	 buf[8096];
161908f6ba19Snaddy 	char	*p, *val;
1620b7b6a941Sreyk 	int	 quotec, next, c;
1621b7b6a941Sreyk 	int	 token;
1622b7b6a941Sreyk 
1623b7b6a941Sreyk top:
1624b7b6a941Sreyk 	p = buf;
1625b7b6a941Sreyk 	while ((c = lgetc(0)) == ' ' || c == '\t')
1626b7b6a941Sreyk 		; /* nothing */
1627b7b6a941Sreyk 
1628b7b6a941Sreyk 	yylval.lineno = file->lineno;
1629b7b6a941Sreyk 	if (c == '#')
1630b7b6a941Sreyk 		while ((c = lgetc(0)) != '\n' && c != EOF)
1631b7b6a941Sreyk 			; /* nothing */
1632cc380947Sdenis 	if (c == '$' && !expanding) {
1633b7b6a941Sreyk 		while (1) {
1634b7b6a941Sreyk 			if ((c = lgetc(0)) == EOF)
1635b7b6a941Sreyk 				return (0);
1636b7b6a941Sreyk 
1637b7b6a941Sreyk 			if (p + 1 >= buf + sizeof(buf) - 1) {
1638b7b6a941Sreyk 				yyerror("string too long");
1639b7b6a941Sreyk 				return (findeol());
1640b7b6a941Sreyk 			}
1641b7b6a941Sreyk 			if (isalnum(c) || c == '_') {
1642b7b6a941Sreyk 				*p++ = c;
1643b7b6a941Sreyk 				continue;
1644b7b6a941Sreyk 			}
1645b7b6a941Sreyk 			*p = '\0';
1646b7b6a941Sreyk 			lungetc(c);
1647b7b6a941Sreyk 			break;
1648b7b6a941Sreyk 		}
1649b7b6a941Sreyk 		val = symget(buf);
1650b7b6a941Sreyk 		if (val == NULL) {
1651b7b6a941Sreyk 			yyerror("macro '%s' not defined", buf);
1652b7b6a941Sreyk 			return (findeol());
1653b7b6a941Sreyk 		}
1654cc380947Sdenis 		p = val + strlen(val) - 1;
1655cc380947Sdenis 		lungetc(DONE_EXPAND);
1656cc380947Sdenis 		while (p >= val) {
165708f6ba19Snaddy 			lungetc((unsigned char)*p);
1658cc380947Sdenis 			p--;
1659cc380947Sdenis 		}
1660cc380947Sdenis 		lungetc(START_EXPAND);
1661b7b6a941Sreyk 		goto top;
1662b7b6a941Sreyk 	}
1663b7b6a941Sreyk 
1664b7b6a941Sreyk 	switch (c) {
1665b7b6a941Sreyk 	case '\'':
1666b7b6a941Sreyk 	case '"':
1667b7b6a941Sreyk 		quotec = c;
1668b7b6a941Sreyk 		while (1) {
1669b7b6a941Sreyk 			if ((c = lgetc(quotec)) == EOF)
1670b7b6a941Sreyk 				return (0);
1671b7b6a941Sreyk 			if (c == '\n') {
1672b7b6a941Sreyk 				file->lineno++;
1673b7b6a941Sreyk 				continue;
1674b7b6a941Sreyk 			} else if (c == '\\') {
1675b7b6a941Sreyk 				if ((next = lgetc(quotec)) == EOF)
1676b7b6a941Sreyk 					return (0);
1677a1533359Ssashan 				if (next == quotec || next == ' ' ||
1678a1533359Ssashan 				    next == '\t')
1679b7b6a941Sreyk 					c = next;
1680b7b6a941Sreyk 				else if (next == '\n') {
1681b7b6a941Sreyk 					file->lineno++;
1682b7b6a941Sreyk 					continue;
1683b7b6a941Sreyk 				} else
1684b7b6a941Sreyk 					lungetc(next);
1685b7b6a941Sreyk 			} else if (c == quotec) {
1686b7b6a941Sreyk 				*p = '\0';
1687b7b6a941Sreyk 				break;
168841eef22fSjsg 			} else if (c == '\0') {
168941eef22fSjsg 				yyerror("syntax error");
169041eef22fSjsg 				return (findeol());
1691b7b6a941Sreyk 			}
1692b7b6a941Sreyk 			if (p + 1 >= buf + sizeof(buf) - 1) {
1693b7b6a941Sreyk 				yyerror("string too long");
1694b7b6a941Sreyk 				return (findeol());
1695b7b6a941Sreyk 			}
1696b7b6a941Sreyk 			*p++ = c;
1697b7b6a941Sreyk 		}
1698b7b6a941Sreyk 		yylval.v.string = strdup(buf);
1699b7b6a941Sreyk 		if (yylval.v.string == NULL)
1700a062aa9dSkrw 			err(1, "%s", __func__);
1701b7b6a941Sreyk 		return (STRING);
1702b7b6a941Sreyk 	}
1703b7b6a941Sreyk 
1704b7b6a941Sreyk #define allowed_to_end_number(x) \
1705b7b6a941Sreyk 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
1706b7b6a941Sreyk 
1707b7b6a941Sreyk 	if (c == '-' || isdigit(c)) {
1708b7b6a941Sreyk 		do {
1709b7b6a941Sreyk 			*p++ = c;
1710915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
1711b7b6a941Sreyk 				yyerror("string too long");
1712b7b6a941Sreyk 				return (findeol());
1713b7b6a941Sreyk 			}
1714b7b6a941Sreyk 		} while ((c = lgetc(0)) != EOF && isdigit(c));
1715b7b6a941Sreyk 		lungetc(c);
1716b7b6a941Sreyk 		if (p == buf + 1 && buf[0] == '-')
1717b7b6a941Sreyk 			goto nodigits;
1718b7b6a941Sreyk 		if (c == EOF || allowed_to_end_number(c)) {
1719b7b6a941Sreyk 			const char *errstr = NULL;
1720b7b6a941Sreyk 
1721b7b6a941Sreyk 			*p = '\0';
1722b7b6a941Sreyk 			yylval.v.number = strtonum(buf, LLONG_MIN,
1723b7b6a941Sreyk 			    LLONG_MAX, &errstr);
1724b7b6a941Sreyk 			if (errstr) {
1725b7b6a941Sreyk 				yyerror("\"%s\" invalid number: %s",
1726b7b6a941Sreyk 				    buf, errstr);
1727b7b6a941Sreyk 				return (findeol());
1728b7b6a941Sreyk 			}
1729b7b6a941Sreyk 			return (NUMBER);
1730b7b6a941Sreyk 		} else {
1731b7b6a941Sreyk nodigits:
1732b7b6a941Sreyk 			while (p > buf + 1)
173308f6ba19Snaddy 				lungetc((unsigned char)*--p);
173408f6ba19Snaddy 			c = (unsigned char)*--p;
1735b7b6a941Sreyk 			if (c == '-')
1736b7b6a941Sreyk 				return (c);
1737b7b6a941Sreyk 		}
1738b7b6a941Sreyk 	}
1739b7b6a941Sreyk 
1740b7b6a941Sreyk #define allowed_in_string(x) \
1741b7b6a941Sreyk 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
1742b7b6a941Sreyk 	x != '{' && x != '}' && x != '<' && x != '>' && \
1743b7b6a941Sreyk 	x != '!' && x != '=' && x != '#' && \
17449b9ff8ecSreyk 	x != ',' && x != ';' && x != '/'))
1745b7b6a941Sreyk 
1746e33b5192Sreyk 	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
1747b7b6a941Sreyk 		do {
1748b7b6a941Sreyk 			*p++ = c;
1749915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
1750b7b6a941Sreyk 				yyerror("string too long");
1751b7b6a941Sreyk 				return (findeol());
1752b7b6a941Sreyk 			}
1753b7b6a941Sreyk 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
1754b7b6a941Sreyk 		lungetc(c);
1755b7b6a941Sreyk 		*p = '\0';
1756b7b6a941Sreyk 		if ((token = lookup(buf)) == STRING)
1757b7b6a941Sreyk 			if ((yylval.v.string = strdup(buf)) == NULL)
1758a062aa9dSkrw 				err(1, "%s", __func__);
1759b7b6a941Sreyk 		return (token);
1760b7b6a941Sreyk 	}
1761b7b6a941Sreyk 	if (c == '\n') {
1762b7b6a941Sreyk 		yylval.lineno = file->lineno;
1763b7b6a941Sreyk 		file->lineno++;
1764b7b6a941Sreyk 	}
1765b7b6a941Sreyk 	if (c == EOF)
1766b7b6a941Sreyk 		return (0);
1767b7b6a941Sreyk 	return (c);
1768b7b6a941Sreyk }
1769b7b6a941Sreyk 
1770b7b6a941Sreyk int
check_file_secrecy(int fd,const char * fname)1771b7b6a941Sreyk check_file_secrecy(int fd, const char *fname)
1772b7b6a941Sreyk {
1773b7b6a941Sreyk 	struct stat	st;
1774b7b6a941Sreyk 
1775b7b6a941Sreyk 	if (fstat(fd, &st)) {
1776b7b6a941Sreyk 		log_warn("cannot stat %s", fname);
1777b7b6a941Sreyk 		return (-1);
1778b7b6a941Sreyk 	}
1779b7b6a941Sreyk 	if (st.st_uid != 0 && st.st_uid != getuid()) {
1780b7b6a941Sreyk 		log_warnx("%s: owner not root or current user", fname);
1781b7b6a941Sreyk 		return (-1);
1782b7b6a941Sreyk 	}
1783b7b6a941Sreyk 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
1784b7b6a941Sreyk 		log_warnx("%s: group writable or world read/writable", fname);
1785b7b6a941Sreyk 		return (-1);
1786b7b6a941Sreyk 	}
1787b7b6a941Sreyk 	return (0);
1788b7b6a941Sreyk }
1789b7b6a941Sreyk 
1790b7b6a941Sreyk struct file *
pushfile(const char * name,int secret)1791b7b6a941Sreyk pushfile(const char *name, int secret)
1792b7b6a941Sreyk {
1793b7b6a941Sreyk 	struct file	*nfile;
1794b7b6a941Sreyk 
1795b7b6a941Sreyk 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
17966a3d55f9Skrw 		log_warn("%s", __func__);
1797b7b6a941Sreyk 		return (NULL);
1798b7b6a941Sreyk 	}
1799b7b6a941Sreyk 	if ((nfile->name = strdup(name)) == NULL) {
18006a3d55f9Skrw 		log_warn("%s", __func__);
1801b7b6a941Sreyk 		free(nfile);
1802b7b6a941Sreyk 		return (NULL);
1803b7b6a941Sreyk 	}
1804b7b6a941Sreyk 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
1805b7b6a941Sreyk 		log_warn("%s: %s", __func__, nfile->name);
1806b7b6a941Sreyk 		free(nfile->name);
1807b7b6a941Sreyk 		free(nfile);
1808b7b6a941Sreyk 		return (NULL);
1809b7b6a941Sreyk 	} else if (secret &&
1810b7b6a941Sreyk 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
1811b7b6a941Sreyk 		fclose(nfile->stream);
1812b7b6a941Sreyk 		free(nfile->name);
1813b7b6a941Sreyk 		free(nfile);
1814b7b6a941Sreyk 		return (NULL);
1815b7b6a941Sreyk 	}
1816cc380947Sdenis 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
1817cc380947Sdenis 	nfile->ungetsize = 16;
1818cc380947Sdenis 	nfile->ungetbuf = malloc(nfile->ungetsize);
1819cc380947Sdenis 	if (nfile->ungetbuf == NULL) {
18206a3d55f9Skrw 		log_warn("%s", __func__);
1821cc380947Sdenis 		fclose(nfile->stream);
1822cc380947Sdenis 		free(nfile->name);
1823cc380947Sdenis 		free(nfile);
1824cc380947Sdenis 		return (NULL);
1825cc380947Sdenis 	}
1826b7b6a941Sreyk 	TAILQ_INSERT_TAIL(&files, nfile, entry);
1827b7b6a941Sreyk 	return (nfile);
1828b7b6a941Sreyk }
1829b7b6a941Sreyk 
1830b7b6a941Sreyk int
popfile(void)1831b7b6a941Sreyk popfile(void)
1832b7b6a941Sreyk {
1833b7b6a941Sreyk 	struct file	*prev;
1834b7b6a941Sreyk 
1835b7b6a941Sreyk 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
1836b7b6a941Sreyk 		prev->errors += file->errors;
1837b7b6a941Sreyk 
1838b7b6a941Sreyk 	TAILQ_REMOVE(&files, file, entry);
1839b7b6a941Sreyk 	fclose(file->stream);
1840b7b6a941Sreyk 	free(file->name);
1841cc380947Sdenis 	free(file->ungetbuf);
1842b7b6a941Sreyk 	free(file);
1843b7b6a941Sreyk 	file = prev;
1844b7b6a941Sreyk 	return (file ? 0 : EOF);
1845b7b6a941Sreyk }
1846b7b6a941Sreyk 
1847b7b6a941Sreyk int
parse_config(const char * filename,struct httpd * x_conf)1848b7b6a941Sreyk parse_config(const char *filename, struct httpd *x_conf)
1849b7b6a941Sreyk {
1850b7b6a941Sreyk 	struct sym		*sym, *next;
1851d24f6b1eSreyk 	struct media_type	 dflt = HTTPD_DEFAULT_TYPE;
1852b7b6a941Sreyk 
1853b7b6a941Sreyk 	conf = x_conf;
1854b7b6a941Sreyk 	if (config_init(conf) == -1) {
1855b7b6a941Sreyk 		log_warn("%s: cannot initialize configuration", __func__);
1856b7b6a941Sreyk 		return (-1);
1857b7b6a941Sreyk 	}
1858b7b6a941Sreyk 
1859d24f6b1eSreyk 	/* Set default media type */
1860d24f6b1eSreyk 	memcpy(&conf->sc_default_type, &dflt, sizeof(struct media_type));
1861d24f6b1eSreyk 
1862b7b6a941Sreyk 	errors = 0;
1863b7b6a941Sreyk 
1864b7b6a941Sreyk 	if ((file = pushfile(filename, 0)) == NULL)
1865b7b6a941Sreyk 		return (-1);
1866b7b6a941Sreyk 
1867b7b6a941Sreyk 	topfile = file;
1868b7b6a941Sreyk 	setservent(1);
1869b7b6a941Sreyk 
1870b7b6a941Sreyk 	yyparse();
1871b7b6a941Sreyk 	errors = file->errors;
1872cc380947Sdenis 	while (popfile() != EOF)
1873cc380947Sdenis 		;
1874b7b6a941Sreyk 
1875b7b6a941Sreyk 	endservent();
1876b7b6a941Sreyk 	endprotoent();
1877b7b6a941Sreyk 
1878b7b6a941Sreyk 	/* Free macros */
187946bca67bSkrw 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
1880b7b6a941Sreyk 		if (!sym->persist) {
1881b7b6a941Sreyk 			free(sym->nam);
1882b7b6a941Sreyk 			free(sym->val);
1883b7b6a941Sreyk 			TAILQ_REMOVE(&symhead, sym, entry);
1884b7b6a941Sreyk 			free(sym);
1885b7b6a941Sreyk 		}
1886b7b6a941Sreyk 	}
1887b7b6a941Sreyk 
1888b7b6a941Sreyk 	return (errors ? -1 : 0);
1889b7b6a941Sreyk }
1890b7b6a941Sreyk 
1891b7b6a941Sreyk int
load_config(const char * filename,struct httpd * x_conf)1892b7b6a941Sreyk load_config(const char *filename, struct httpd *x_conf)
1893b7b6a941Sreyk {
1894b7b6a941Sreyk 	struct sym		*sym, *next;
18959b9ff8ecSreyk 	struct http_mediatype	 mediatypes[] = MEDIA_TYPES;
18969b9ff8ecSreyk 	struct media_type	 m;
18979b9ff8ecSreyk 	int			 i;
1898b7b6a941Sreyk 
1899b7b6a941Sreyk 	conf = x_conf;
1900b7b6a941Sreyk 	conf->sc_flags = 0;
1901b7b6a941Sreyk 
1902b7b6a941Sreyk 	loadcfg = 1;
1903b7b6a941Sreyk 	errors = 0;
1904b7b6a941Sreyk 	last_server_id = 0;
1905602531d9Sreyk 	last_auth_id = 0;
1906b7b6a941Sreyk 
1907b7b6a941Sreyk 	srv = NULL;
1908b7b6a941Sreyk 
1909b7b6a941Sreyk 	if ((file = pushfile(filename, 0)) == NULL)
1910b7b6a941Sreyk 		return (-1);
1911b7b6a941Sreyk 
1912b7b6a941Sreyk 	topfile = file;
1913b7b6a941Sreyk 	setservent(1);
1914b7b6a941Sreyk 
1915b7b6a941Sreyk 	yyparse();
1916b7b6a941Sreyk 	errors = file->errors;
1917b7b6a941Sreyk 	popfile();
1918b7b6a941Sreyk 
1919b7b6a941Sreyk 	endservent();
1920b7b6a941Sreyk 	endprotoent();
1921b7b6a941Sreyk 
1922b7b6a941Sreyk 	/* Free macros and check which have not been used. */
1923b7b6a941Sreyk 	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
1924b7b6a941Sreyk 		next = TAILQ_NEXT(sym, entry);
1925b7b6a941Sreyk 		if ((conf->sc_opts & HTTPD_OPT_VERBOSE) && !sym->used)
1926b7b6a941Sreyk 			fprintf(stderr, "warning: macro '%s' not "
1927b7b6a941Sreyk 			    "used\n", sym->nam);
1928b7b6a941Sreyk 		if (!sym->persist) {
1929b7b6a941Sreyk 			free(sym->nam);
1930b7b6a941Sreyk 			free(sym->val);
1931b7b6a941Sreyk 			TAILQ_REMOVE(&symhead, sym, entry);
1932b7b6a941Sreyk 			free(sym);
1933b7b6a941Sreyk 		}
1934b7b6a941Sreyk 	}
1935b7b6a941Sreyk 
1936b7b6a941Sreyk 	if (TAILQ_EMPTY(conf->sc_servers)) {
1937b7b6a941Sreyk 		log_warnx("no actions, nothing to do");
1938b7b6a941Sreyk 		errors++;
1939b7b6a941Sreyk 	}
1940b7b6a941Sreyk 
19419b9ff8ecSreyk 	if (RB_EMPTY(conf->sc_mediatypes)) {
19429b9ff8ecSreyk 		/* Add default media types */
19439b9ff8ecSreyk 		for (i = 0; mediatypes[i].media_name != NULL; i++) {
19449b9ff8ecSreyk 			(void)strlcpy(m.media_name, mediatypes[i].media_name,
19459b9ff8ecSreyk 			    sizeof(m.media_name));
19469b9ff8ecSreyk 			(void)strlcpy(m.media_type, mediatypes[i].media_type,
19479b9ff8ecSreyk 			    sizeof(m.media_type));
19489b9ff8ecSreyk 			(void)strlcpy(m.media_subtype,
19499b9ff8ecSreyk 			    mediatypes[i].media_subtype,
19509b9ff8ecSreyk 			    sizeof(m.media_subtype));
1951ff70ca31Sreyk 			m.media_encoding = NULL;
19529b9ff8ecSreyk 
19539b9ff8ecSreyk 			if (media_add(conf->sc_mediatypes, &m) == NULL) {
19549b9ff8ecSreyk 				log_warnx("failed to add default media \"%s\"",
19559b9ff8ecSreyk 				    m.media_name);
19569b9ff8ecSreyk 				errors++;
19579b9ff8ecSreyk 			}
19589b9ff8ecSreyk 		}
19599b9ff8ecSreyk 	}
19609b9ff8ecSreyk 
1961b7b6a941Sreyk 	return (errors ? -1 : 0);
1962b7b6a941Sreyk }
1963b7b6a941Sreyk 
1964b7b6a941Sreyk int
symset(const char * nam,const char * val,int persist)1965b7b6a941Sreyk symset(const char *nam, const char *val, int persist)
1966b7b6a941Sreyk {
1967b7b6a941Sreyk 	struct sym	*sym;
1968b7b6a941Sreyk 
196954c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
197054c95b7aSkrw 		if (strcmp(nam, sym->nam) == 0)
197154c95b7aSkrw 			break;
197254c95b7aSkrw 	}
1973b7b6a941Sreyk 
1974b7b6a941Sreyk 	if (sym != NULL) {
1975b7b6a941Sreyk 		if (sym->persist == 1)
1976b7b6a941Sreyk 			return (0);
1977b7b6a941Sreyk 		else {
1978b7b6a941Sreyk 			free(sym->nam);
1979b7b6a941Sreyk 			free(sym->val);
1980b7b6a941Sreyk 			TAILQ_REMOVE(&symhead, sym, entry);
1981b7b6a941Sreyk 			free(sym);
1982b7b6a941Sreyk 		}
1983b7b6a941Sreyk 	}
1984b7b6a941Sreyk 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
1985b7b6a941Sreyk 		return (-1);
1986b7b6a941Sreyk 
1987b7b6a941Sreyk 	sym->nam = strdup(nam);
1988b7b6a941Sreyk 	if (sym->nam == NULL) {
1989b7b6a941Sreyk 		free(sym);
1990b7b6a941Sreyk 		return (-1);
1991b7b6a941Sreyk 	}
1992b7b6a941Sreyk 	sym->val = strdup(val);
1993b7b6a941Sreyk 	if (sym->val == NULL) {
1994b7b6a941Sreyk 		free(sym->nam);
1995b7b6a941Sreyk 		free(sym);
1996b7b6a941Sreyk 		return (-1);
1997b7b6a941Sreyk 	}
1998b7b6a941Sreyk 	sym->used = 0;
1999b7b6a941Sreyk 	sym->persist = persist;
2000b7b6a941Sreyk 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
2001b7b6a941Sreyk 	return (0);
2002b7b6a941Sreyk }
2003b7b6a941Sreyk 
2004b7b6a941Sreyk int
cmdline_symset(char * s)2005b7b6a941Sreyk cmdline_symset(char *s)
2006b7b6a941Sreyk {
2007b7b6a941Sreyk 	char	*sym, *val;
2008b7b6a941Sreyk 	int	ret;
2009b7b6a941Sreyk 
2010b7b6a941Sreyk 	if ((val = strrchr(s, '=')) == NULL)
2011b7b6a941Sreyk 		return (-1);
2012ed1b9eb8Smiko 	sym = strndup(s, val - s);
2013ed1b9eb8Smiko 	if (sym == NULL)
2014ed1b9eb8Smiko 		errx(1, "%s: strndup", __func__);
2015b7b6a941Sreyk 	ret = symset(sym, val + 1, 1);
2016b7b6a941Sreyk 	free(sym);
2017b7b6a941Sreyk 
2018b7b6a941Sreyk 	return (ret);
2019b7b6a941Sreyk }
2020b7b6a941Sreyk 
2021b7b6a941Sreyk char *
symget(const char * nam)2022b7b6a941Sreyk symget(const char *nam)
2023b7b6a941Sreyk {
2024b7b6a941Sreyk 	struct sym	*sym;
2025b7b6a941Sreyk 
202654c95b7aSkrw 	TAILQ_FOREACH(sym, &symhead, entry) {
2027b7b6a941Sreyk 		if (strcmp(nam, sym->nam) == 0) {
2028b7b6a941Sreyk 			sym->used = 1;
2029b7b6a941Sreyk 			return (sym->val);
2030b7b6a941Sreyk 		}
203154c95b7aSkrw 	}
2032b7b6a941Sreyk 	return (NULL);
2033b7b6a941Sreyk }
2034b7b6a941Sreyk 
2035b7b6a941Sreyk struct address *
host_v4(const char * s)2036b7b6a941Sreyk host_v4(const char *s)
2037b7b6a941Sreyk {
2038b7b6a941Sreyk 	struct in_addr		 ina;
2039b7b6a941Sreyk 	struct sockaddr_in	*sain;
2040b7b6a941Sreyk 	struct address		*h;
2041b7b6a941Sreyk 
2042b7b6a941Sreyk 	memset(&ina, 0, sizeof(ina));
2043b7b6a941Sreyk 	if (inet_pton(AF_INET, s, &ina) != 1)
2044b7b6a941Sreyk 		return (NULL);
2045b7b6a941Sreyk 
2046b7b6a941Sreyk 	if ((h = calloc(1, sizeof(*h))) == NULL)
20470f12961aSreyk 		fatal(__func__);
2048b7b6a941Sreyk 	sain = (struct sockaddr_in *)&h->ss;
2049b7b6a941Sreyk 	sain->sin_len = sizeof(struct sockaddr_in);
2050b7b6a941Sreyk 	sain->sin_family = AF_INET;
2051b7b6a941Sreyk 	sain->sin_addr.s_addr = ina.s_addr;
2052d9bba0abSreyk 	if (sain->sin_addr.s_addr == INADDR_ANY)
2053d9bba0abSreyk 		h->prefixlen = 0; /* 0.0.0.0 address */
2054d9bba0abSreyk 	else
2055d9bba0abSreyk 		h->prefixlen = -1; /* host address */
2056b7b6a941Sreyk 	return (h);
2057b7b6a941Sreyk }
2058b7b6a941Sreyk 
2059b7b6a941Sreyk struct address *
host_v6(const char * s)2060b7b6a941Sreyk host_v6(const char *s)
2061b7b6a941Sreyk {
2062b7b6a941Sreyk 	struct addrinfo		 hints, *res;
2063b7b6a941Sreyk 	struct sockaddr_in6	*sa_in6;
2064b7b6a941Sreyk 	struct address		*h = NULL;
2065b7b6a941Sreyk 
2066b7b6a941Sreyk 	memset(&hints, 0, sizeof(hints));
2067b7b6a941Sreyk 	hints.ai_family = AF_INET6;
2068b7b6a941Sreyk 	hints.ai_socktype = SOCK_DGRAM; /* dummy */
2069b7b6a941Sreyk 	hints.ai_flags = AI_NUMERICHOST;
2070b7b6a941Sreyk 	if (getaddrinfo(s, "0", &hints, &res) == 0) {
2071b7b6a941Sreyk 		if ((h = calloc(1, sizeof(*h))) == NULL)
20720f12961aSreyk 			fatal(__func__);
2073b7b6a941Sreyk 		sa_in6 = (struct sockaddr_in6 *)&h->ss;
2074b7b6a941Sreyk 		sa_in6->sin6_len = sizeof(struct sockaddr_in6);
2075b7b6a941Sreyk 		sa_in6->sin6_family = AF_INET6;
2076b7b6a941Sreyk 		memcpy(&sa_in6->sin6_addr,
2077b7b6a941Sreyk 		    &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
2078b7b6a941Sreyk 		    sizeof(sa_in6->sin6_addr));
2079b7b6a941Sreyk 		sa_in6->sin6_scope_id =
2080b7b6a941Sreyk 		    ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
2081d9bba0abSreyk 		if (memcmp(&sa_in6->sin6_addr, &in6addr_any,
2082d9bba0abSreyk 		    sizeof(sa_in6->sin6_addr)) == 0)
2083d9bba0abSreyk 			h->prefixlen = 0; /* any address */
2084d9bba0abSreyk 		else
2085d9bba0abSreyk 			h->prefixlen = -1; /* host address */
2086b7b6a941Sreyk 		freeaddrinfo(res);
2087b7b6a941Sreyk 	}
2088b7b6a941Sreyk 
2089b7b6a941Sreyk 	return (h);
2090b7b6a941Sreyk }
2091b7b6a941Sreyk 
2092b7b6a941Sreyk int
host_dns(const char * s,struct addresslist * al,int max,struct portrange * port,const char * ifname,int ipproto)2093b7b6a941Sreyk host_dns(const char *s, struct addresslist *al, int max,
2094b7b6a941Sreyk     struct portrange *port, const char *ifname, int ipproto)
2095b7b6a941Sreyk {
2096b7b6a941Sreyk 	struct addrinfo		 hints, *res0, *res;
2097b7b6a941Sreyk 	int			 error, cnt = 0;
2098b7b6a941Sreyk 	struct sockaddr_in	*sain;
2099b7b6a941Sreyk 	struct sockaddr_in6	*sin6;
2100b7b6a941Sreyk 	struct address		*h;
2101b7b6a941Sreyk 
2102b7b6a941Sreyk 	if ((cnt = host_if(s, al, max, port, ifname, ipproto)) != 0)
2103b7b6a941Sreyk 		return (cnt);
2104b7b6a941Sreyk 
2105b7b6a941Sreyk 	memset(&hints, 0, sizeof(hints));
2106b7b6a941Sreyk 	hints.ai_family = PF_UNSPEC;
2107b7b6a941Sreyk 	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
2108ea230c89Sreyk 	hints.ai_flags = AI_ADDRCONFIG;
2109b7b6a941Sreyk 	error = getaddrinfo(s, NULL, &hints, &res0);
2110b7b6a941Sreyk 	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
2111b7b6a941Sreyk 		return (0);
2112b7b6a941Sreyk 	if (error) {
2113b7b6a941Sreyk 		log_warnx("%s: could not parse \"%s\": %s", __func__, s,
2114b7b6a941Sreyk 		    gai_strerror(error));
2115b7b6a941Sreyk 		return (-1);
2116b7b6a941Sreyk 	}
2117b7b6a941Sreyk 
2118b7b6a941Sreyk 	for (res = res0; res && cnt < max; res = res->ai_next) {
2119b7b6a941Sreyk 		if (res->ai_family != AF_INET &&
2120b7b6a941Sreyk 		    res->ai_family != AF_INET6)
2121b7b6a941Sreyk 			continue;
2122b7b6a941Sreyk 		if ((h = calloc(1, sizeof(*h))) == NULL)
21230f12961aSreyk 			fatal(__func__);
2124b7b6a941Sreyk 
2125b7b6a941Sreyk 		if (port != NULL)
2126b7b6a941Sreyk 			memcpy(&h->port, port, sizeof(h->port));
2127b7b6a941Sreyk 		if (ifname != NULL) {
2128b7b6a941Sreyk 			if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
2129b7b6a941Sreyk 			    sizeof(h->ifname))
2130b7b6a941Sreyk 				log_warnx("%s: interface name truncated",
2131b7b6a941Sreyk 				    __func__);
2132b7b6a941Sreyk 			freeaddrinfo(res0);
2133b7b6a941Sreyk 			free(h);
2134b7b6a941Sreyk 			return (-1);
2135b7b6a941Sreyk 		}
2136b7b6a941Sreyk 		if (ipproto != -1)
2137b7b6a941Sreyk 			h->ipproto = ipproto;
2138b7b6a941Sreyk 		h->ss.ss_family = res->ai_family;
2139d9bba0abSreyk 		h->prefixlen = -1; /* host address */
2140b7b6a941Sreyk 
2141b7b6a941Sreyk 		if (res->ai_family == AF_INET) {
2142b7b6a941Sreyk 			sain = (struct sockaddr_in *)&h->ss;
2143b7b6a941Sreyk 			sain->sin_len = sizeof(struct sockaddr_in);
2144b7b6a941Sreyk 			sain->sin_addr.s_addr = ((struct sockaddr_in *)
2145b7b6a941Sreyk 			    res->ai_addr)->sin_addr.s_addr;
2146b7b6a941Sreyk 		} else {
2147b7b6a941Sreyk 			sin6 = (struct sockaddr_in6 *)&h->ss;
2148b7b6a941Sreyk 			sin6->sin6_len = sizeof(struct sockaddr_in6);
2149b7b6a941Sreyk 			memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
2150b7b6a941Sreyk 			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
2151b7b6a941Sreyk 		}
2152b7b6a941Sreyk 
2153b7b6a941Sreyk 		TAILQ_INSERT_HEAD(al, h, entry);
2154b7b6a941Sreyk 		cnt++;
2155b7b6a941Sreyk 	}
2156b7b6a941Sreyk 	if (cnt == max && res) {
2157b7b6a941Sreyk 		log_warnx("%s: %s resolves to more than %d hosts", __func__,
2158b7b6a941Sreyk 		    s, max);
2159b7b6a941Sreyk 	}
2160b7b6a941Sreyk 	freeaddrinfo(res0);
2161b7b6a941Sreyk 	return (cnt);
2162b7b6a941Sreyk }
2163b7b6a941Sreyk 
2164b7b6a941Sreyk int
host_if(const char * s,struct addresslist * al,int max,struct portrange * port,const char * ifname,int ipproto)2165b7b6a941Sreyk host_if(const char *s, struct addresslist *al, int max,
2166b7b6a941Sreyk     struct portrange *port, const char *ifname, int ipproto)
2167b7b6a941Sreyk {
2168b7b6a941Sreyk 	struct ifaddrs		*ifap, *p;
2169b7b6a941Sreyk 	struct sockaddr_in	*sain;
2170b7b6a941Sreyk 	struct sockaddr_in6	*sin6;
2171b7b6a941Sreyk 	struct address		*h;
2172b7b6a941Sreyk 	int			 cnt = 0, af;
2173b7b6a941Sreyk 
2174b7b6a941Sreyk 	if (getifaddrs(&ifap) == -1)
2175b7b6a941Sreyk 		fatal("getifaddrs");
2176b7b6a941Sreyk 
2177b7b6a941Sreyk 	/* First search for IPv4 addresses */
2178b7b6a941Sreyk 	af = AF_INET;
2179b7b6a941Sreyk 
2180b7b6a941Sreyk  nextaf:
2181b7b6a941Sreyk 	for (p = ifap; p != NULL && cnt < max; p = p->ifa_next) {
21825e1df7efSbenno 		if (p->ifa_addr == NULL ||
21835e1df7efSbenno 		    p->ifa_addr->sa_family != af ||
2184b7b6a941Sreyk 		    (strcmp(s, p->ifa_name) != 0 &&
2185b7b6a941Sreyk 		    !is_if_in_group(p->ifa_name, s)))
2186b7b6a941Sreyk 			continue;
2187b7b6a941Sreyk 		if ((h = calloc(1, sizeof(*h))) == NULL)
2188b7b6a941Sreyk 			fatal("calloc");
2189b7b6a941Sreyk 
2190b7b6a941Sreyk 		if (port != NULL)
2191b7b6a941Sreyk 			memcpy(&h->port, port, sizeof(h->port));
2192b7b6a941Sreyk 		if (ifname != NULL) {
2193b7b6a941Sreyk 			if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
2194b7b6a941Sreyk 			    sizeof(h->ifname))
2195b7b6a941Sreyk 				log_warnx("%s: interface name truncated",
2196b7b6a941Sreyk 				    __func__);
2197b7b6a941Sreyk 			freeifaddrs(ifap);
219825f402c6Sbenno 			free(h);
2199b7b6a941Sreyk 			return (-1);
2200b7b6a941Sreyk 		}
2201b7b6a941Sreyk 		if (ipproto != -1)
2202b7b6a941Sreyk 			h->ipproto = ipproto;
2203b7b6a941Sreyk 		h->ss.ss_family = af;
2204d9bba0abSreyk 		h->prefixlen = -1; /* host address */
2205b7b6a941Sreyk 
2206b7b6a941Sreyk 		if (af == AF_INET) {
2207b7b6a941Sreyk 			sain = (struct sockaddr_in *)&h->ss;
2208b7b6a941Sreyk 			sain->sin_len = sizeof(struct sockaddr_in);
2209b7b6a941Sreyk 			sain->sin_addr.s_addr = ((struct sockaddr_in *)
2210b7b6a941Sreyk 			    p->ifa_addr)->sin_addr.s_addr;
2211b7b6a941Sreyk 		} else {
2212b7b6a941Sreyk 			sin6 = (struct sockaddr_in6 *)&h->ss;
2213b7b6a941Sreyk 			sin6->sin6_len = sizeof(struct sockaddr_in6);
2214b7b6a941Sreyk 			memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
2215b7b6a941Sreyk 			    p->ifa_addr)->sin6_addr, sizeof(struct in6_addr));
2216b7b6a941Sreyk 			sin6->sin6_scope_id = ((struct sockaddr_in6 *)
2217b7b6a941Sreyk 			    p->ifa_addr)->sin6_scope_id;
2218b7b6a941Sreyk 		}
2219b7b6a941Sreyk 
2220b7b6a941Sreyk 		TAILQ_INSERT_HEAD(al, h, entry);
2221b7b6a941Sreyk 		cnt++;
2222b7b6a941Sreyk 	}
2223b7b6a941Sreyk 	if (af == AF_INET) {
2224b7b6a941Sreyk 		/* Next search for IPv6 addresses */
2225b7b6a941Sreyk 		af = AF_INET6;
2226b7b6a941Sreyk 		goto nextaf;
2227b7b6a941Sreyk 	}
2228b7b6a941Sreyk 
2229b7b6a941Sreyk 	if (cnt > max) {
2230b7b6a941Sreyk 		log_warnx("%s: %s resolves to more than %d hosts", __func__,
2231b7b6a941Sreyk 		    s, max);
2232b7b6a941Sreyk 	}
2233b7b6a941Sreyk 	freeifaddrs(ifap);
2234b7b6a941Sreyk 	return (cnt);
2235b7b6a941Sreyk }
2236b7b6a941Sreyk 
2237b7b6a941Sreyk int
host(const char * s,struct addresslist * al,int max,struct portrange * port,const char * ifname,int ipproto)2238b7b6a941Sreyk host(const char *s, struct addresslist *al, int max,
2239b7b6a941Sreyk     struct portrange *port, const char *ifname, int ipproto)
2240b7b6a941Sreyk {
2241b7b6a941Sreyk 	struct address *h;
2242b7b6a941Sreyk 
2243b7b6a941Sreyk 	h = host_v4(s);
2244b7b6a941Sreyk 
2245b7b6a941Sreyk 	/* IPv6 address? */
2246b7b6a941Sreyk 	if (h == NULL)
2247b7b6a941Sreyk 		h = host_v6(s);
2248b7b6a941Sreyk 
2249b7b6a941Sreyk 	if (h != NULL) {
2250b7b6a941Sreyk 		if (port != NULL)
2251b7b6a941Sreyk 			memcpy(&h->port, port, sizeof(h->port));
2252b7b6a941Sreyk 		if (ifname != NULL) {
2253b7b6a941Sreyk 			if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
2254b7b6a941Sreyk 			    sizeof(h->ifname)) {
2255b7b6a941Sreyk 				log_warnx("%s: interface name truncated",
2256b7b6a941Sreyk 				    __func__);
2257b7b6a941Sreyk 				free(h);
2258b7b6a941Sreyk 				return (-1);
2259b7b6a941Sreyk 			}
2260b7b6a941Sreyk 		}
2261b7b6a941Sreyk 		if (ipproto != -1)
2262b7b6a941Sreyk 			h->ipproto = ipproto;
2263b7b6a941Sreyk 
2264b7b6a941Sreyk 		TAILQ_INSERT_HEAD(al, h, entry);
2265b7b6a941Sreyk 		return (1);
2266b7b6a941Sreyk 	}
2267b7b6a941Sreyk 
2268b7b6a941Sreyk 	return (host_dns(s, al, max, port, ifname, ipproto));
2269b7b6a941Sreyk }
2270b7b6a941Sreyk 
2271be4c70f0Sreyk struct server *
server_inherit(struct server * src,struct server_config * alias,struct server_config * addr)227259355b5aSreyk server_inherit(struct server *src, struct server_config *alias,
2273be4c70f0Sreyk     struct server_config *addr)
2274be4c70f0Sreyk {
2275be4c70f0Sreyk 	struct server	*dst, *s, *dstl;
2276be4c70f0Sreyk 
2277be4c70f0Sreyk 	if ((dst = calloc(1, sizeof(*dst))) == NULL)
2278be4c70f0Sreyk 		fatal("out of memory");
2279be4c70f0Sreyk 
2280be4c70f0Sreyk 	/* Copy the source server and assign a new Id */
2281be4c70f0Sreyk 	memcpy(&dst->srv_conf, &src->srv_conf, sizeof(dst->srv_conf));
2282be4c70f0Sreyk 	if ((dst->srv_conf.tls_cert_file =
2283be4c70f0Sreyk 	    strdup(src->srv_conf.tls_cert_file)) == NULL)
2284be4c70f0Sreyk 		fatal("out of memory");
2285be4c70f0Sreyk 	if ((dst->srv_conf.tls_key_file =
2286be4c70f0Sreyk 	    strdup(src->srv_conf.tls_key_file)) == NULL)
2287be4c70f0Sreyk 		fatal("out of memory");
2288c2773d5eSbeck 	if (src->srv_conf.tls_ocsp_staple_file != NULL) {
2289e80948e2Sbeck 		if ((dst->srv_conf.tls_ocsp_staple_file =
2290e80948e2Sbeck 		    strdup(src->srv_conf.tls_ocsp_staple_file)) == NULL)
2291e80948e2Sbeck 			fatal("out of memory");
2292c2773d5eSbeck 	}
2293be4c70f0Sreyk 
2294f8932becSreyk 	if (src->srv_conf.return_uri != NULL &&
2295f8932becSreyk 	    (dst->srv_conf.return_uri =
2296f8932becSreyk 	    strdup(src->srv_conf.return_uri)) == NULL)
2297f8932becSreyk 		fatal("out of memory");
2298f8932becSreyk 
2299be4c70f0Sreyk 	dst->srv_conf.id = ++last_server_id;
2300c145f9a8Sreyk 	dst->srv_conf.parent_id = dst->srv_conf.id;
230127fb06b4Sreyk 	dst->srv_s = -1;
230227fb06b4Sreyk 
2303be4c70f0Sreyk 	if (last_server_id == INT_MAX) {
2304be4c70f0Sreyk 		yyerror("too many servers defined");
230544e90ff3Sreyk 		serverconfig_free(&dst->srv_conf);
2306be4c70f0Sreyk 		free(dst);
2307be4c70f0Sreyk 		return (NULL);
2308be4c70f0Sreyk 	}
2309be4c70f0Sreyk 
2310be4c70f0Sreyk 	/* Now set alias and listen address */
231159355b5aSreyk 	strlcpy(dst->srv_conf.name, alias->name, sizeof(dst->srv_conf.name));
2312be4c70f0Sreyk 	memcpy(&dst->srv_conf.ss, &addr->ss, sizeof(dst->srv_conf.ss));
2313be4c70f0Sreyk 	dst->srv_conf.port = addr->port;
2314be4c70f0Sreyk 	dst->srv_conf.prefixlen = addr->prefixlen;
2315be4c70f0Sreyk 	if (addr->flags & SRVFLAG_TLS)
2316be4c70f0Sreyk 		dst->srv_conf.flags |= SRVFLAG_TLS;
2317be4c70f0Sreyk 	else
2318be4c70f0Sreyk 		dst->srv_conf.flags &= ~SRVFLAG_TLS;
2319be4c70f0Sreyk 
232059355b5aSreyk 	/* Don't inherit the "match" option, use it from the alias */
232159355b5aSreyk 	dst->srv_conf.flags &= ~SRVFLAG_SERVER_MATCH;
232259355b5aSreyk 	dst->srv_conf.flags |= (alias->flags & SRVFLAG_SERVER_MATCH);
232359355b5aSreyk 
23248f2f1969Sflorian 	if (server_tls_load_keypair(dst) == -1)
23258f2f1969Sflorian 		log_warnx("%s:%d: server \"%s\": failed to "
23268f2f1969Sflorian 		    "load public/private keys", file->name,
23278f2f1969Sflorian 		    yylval.lineno, dst->srv_conf.name);
2328be4c70f0Sreyk 
23291d0dc528Sjsing 	if (server_tls_load_ca(dst) == -1) {
23308f2f1969Sflorian 		yyerror("failed to load ca cert(s) for server %s",
23311d0dc528Sjsing 		    dst->srv_conf.name);
23321d0dc528Sjsing 		serverconfig_free(&dst->srv_conf);
23331d0dc528Sjsing 		return NULL;
23341d0dc528Sjsing 	}
23351d0dc528Sjsing 
23361d0dc528Sjsing 	if (server_tls_load_crl(dst) == -1) {
23371d0dc528Sjsing 		yyerror("failed to load crl(s) for server %s",
23381d0dc528Sjsing 		    dst->srv_conf.name);
23391d0dc528Sjsing 		serverconfig_free(&dst->srv_conf);
23401d0dc528Sjsing 		free(dst);
23411d0dc528Sjsing 		return NULL;
23421d0dc528Sjsing 	}
23431d0dc528Sjsing 
234488f25489Sjsing 	if (server_tls_load_ocsp(dst) == -1) {
2345757ef573Stom 		yyerror("failed to load ocsp staple "
234688f25489Sjsing 		    "for server %s", dst->srv_conf.name);
234788f25489Sjsing 		serverconfig_free(&dst->srv_conf);
234888f25489Sjsing 		free(dst);
234988f25489Sjsing 		return (NULL);
235088f25489Sjsing 	}
235188f25489Sjsing 
2352be4c70f0Sreyk 	/* Check if the new server already exists */
2353e1f28ec9Sjsing 	if (server_match(dst, 1) != NULL) {
2354be4c70f0Sreyk 		yyerror("server \"%s\" defined twice",
2355be4c70f0Sreyk 		    dst->srv_conf.name);
2356be4c70f0Sreyk 		serverconfig_free(&dst->srv_conf);
2357be4c70f0Sreyk 		free(dst);
2358be4c70f0Sreyk 		return (NULL);
2359be4c70f0Sreyk 	}
2360be4c70f0Sreyk 
2361be4c70f0Sreyk 	/* Copy all the locations of the source server */
2362be4c70f0Sreyk 	TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
2363be4c70f0Sreyk 		if (!(s->srv_conf.flags & SRVFLAG_LOCATION &&
2364c145f9a8Sreyk 		    s->srv_conf.parent_id == src->srv_conf.parent_id))
2365be4c70f0Sreyk 			continue;
2366be4c70f0Sreyk 
2367be4c70f0Sreyk 		if ((dstl = calloc(1, sizeof(*dstl))) == NULL)
2368be4c70f0Sreyk 			fatal("out of memory");
2369be4c70f0Sreyk 
2370be4c70f0Sreyk 		memcpy(&dstl->srv_conf, &s->srv_conf, sizeof(dstl->srv_conf));
237159355b5aSreyk 		strlcpy(dstl->srv_conf.name, alias->name,
237259355b5aSreyk 		    sizeof(dstl->srv_conf.name));
2373be4c70f0Sreyk 
2374be4c70f0Sreyk 		/* Copy the new Id and listen address */
2375c145f9a8Sreyk 		dstl->srv_conf.id = ++last_server_id;
2376c145f9a8Sreyk 		dstl->srv_conf.parent_id = dst->srv_conf.id;
2377be4c70f0Sreyk 		memcpy(&dstl->srv_conf.ss, &addr->ss,
2378be4c70f0Sreyk 		    sizeof(dstl->srv_conf.ss));
2379be4c70f0Sreyk 		dstl->srv_conf.port = addr->port;
2380be4c70f0Sreyk 		dstl->srv_conf.prefixlen = addr->prefixlen;
238127fb06b4Sreyk 		dstl->srv_s = -1;
2382be4c70f0Sreyk 
2383be4c70f0Sreyk 		DPRINTF("adding location \"%s\" for \"%s[%u]\"",
2384be4c70f0Sreyk 		    dstl->srv_conf.location,
2385be4c70f0Sreyk 		    dstl->srv_conf.name, dstl->srv_conf.id);
2386be4c70f0Sreyk 
2387be4c70f0Sreyk 		TAILQ_INSERT_TAIL(conf->sc_servers, dstl, srv_entry);
2388be4c70f0Sreyk 	}
2389be4c70f0Sreyk 
2390be4c70f0Sreyk 	return (dst);
2391be4c70f0Sreyk }
2392be4c70f0Sreyk 
2393b7b6a941Sreyk int
listen_on(const char * addr,int tls,struct portrange * port)2394fdc19e0cSreyk listen_on(const char *addr, int tls, struct portrange *port)
2395fdc19e0cSreyk {
2396fdc19e0cSreyk 	struct addresslist	 al;
2397fdc19e0cSreyk 	struct address		*h;
2398fdc19e0cSreyk 	struct server_config	*s_conf, *alias = NULL;
2399fdc19e0cSreyk 
2400fdc19e0cSreyk 	if (parentsrv != NULL) {
2401fdc19e0cSreyk 		yyerror("listen %s inside location", addr);
2402fdc19e0cSreyk 		return (-1);
2403fdc19e0cSreyk 	}
2404fdc19e0cSreyk 
2405fdc19e0cSreyk 	TAILQ_INIT(&al);
2406fdc19e0cSreyk 	if (strcmp("*", addr) == 0) {
2407fdc19e0cSreyk 		if (host("0.0.0.0", &al, 1, port, NULL, -1) <= 0) {
2408fdc19e0cSreyk 			yyerror("invalid listen ip: %s",
2409fdc19e0cSreyk 			    "0.0.0.0");
2410fdc19e0cSreyk 			return (-1);
2411fdc19e0cSreyk 		}
2412fdc19e0cSreyk 		if (host("::", &al, 1, port, NULL, -1) <= 0) {
2413fdc19e0cSreyk 			yyerror("invalid listen ip: %s", "::");
2414fdc19e0cSreyk 			return (-1);
2415fdc19e0cSreyk 		}
2416fdc19e0cSreyk 	} else {
2417fdc19e0cSreyk 		if (host(addr, &al, HTTPD_MAX_ALIAS_IP, port, NULL,
2418fdc19e0cSreyk 		    -1) <= 0) {
2419fdc19e0cSreyk 			yyerror("invalid listen ip: %s", addr);
2420fdc19e0cSreyk 			return (-1);
2421fdc19e0cSreyk 		}
2422fdc19e0cSreyk 	}
2423fdc19e0cSreyk 
2424fdc19e0cSreyk 	while ((h = TAILQ_FIRST(&al)) != NULL) {
2425fdc19e0cSreyk 		if (srv->srv_conf.ss.ss_family != AF_UNSPEC) {
2426fdc19e0cSreyk 			if ((alias = calloc(1,
2427fdc19e0cSreyk 			    sizeof(*alias))) == NULL)
2428fdc19e0cSreyk 				fatal("out of memory");
2429fdc19e0cSreyk 				/* Add as an IP-based alias. */
2430fdc19e0cSreyk 			s_conf = alias;
2431fdc19e0cSreyk 		} else
2432fdc19e0cSreyk 			s_conf = &srv->srv_conf;
2433fdc19e0cSreyk 		memcpy(&s_conf->ss, &h->ss, sizeof(s_conf->ss));
2434fdc19e0cSreyk 		s_conf->prefixlen = h->prefixlen;
2435fdc19e0cSreyk 		/* Set the default port to 80 or 443 */
2436fdc19e0cSreyk 		if (!h->port.op)
2437fdc19e0cSreyk 			s_conf->port = htons(tls ?
2438fdc19e0cSreyk 			    HTTPS_PORT : HTTP_PORT);
2439fdc19e0cSreyk 		else
2440fdc19e0cSreyk 			s_conf->port = h->port.val[0];
2441fdc19e0cSreyk 
2442fdc19e0cSreyk 		if (tls)
2443fdc19e0cSreyk 			s_conf->flags |= SRVFLAG_TLS;
2444fdc19e0cSreyk 
2445fdc19e0cSreyk 		if (alias != NULL) {
2446fdc19e0cSreyk 			/*
2447fdc19e0cSreyk 			 * IP-based; use name match flags from
2448fdc19e0cSreyk 			 * parent
2449fdc19e0cSreyk 			 */
2450fdc19e0cSreyk 			alias->flags &= ~SRVFLAG_SERVER_MATCH;
2451fdc19e0cSreyk 			alias->flags |= srv->srv_conf.flags &
2452fdc19e0cSreyk 			    SRVFLAG_SERVER_MATCH;
2453fdc19e0cSreyk 			TAILQ_INSERT_TAIL(&srv->srv_hosts,
2454fdc19e0cSreyk 			    alias, entry);
2455fdc19e0cSreyk 		}
2456fdc19e0cSreyk 		TAILQ_REMOVE(&al, h, entry);
2457fdc19e0cSreyk 		free(h);
2458fdc19e0cSreyk 	}
2459fdc19e0cSreyk 
2460fdc19e0cSreyk 	return (0);
2461fdc19e0cSreyk }
2462fdc19e0cSreyk 
2463fdc19e0cSreyk int
getservice(char * n)2464b7b6a941Sreyk getservice(char *n)
2465b7b6a941Sreyk {
2466b7b6a941Sreyk 	struct servent	*s;
2467b7b6a941Sreyk 	const char	*errstr;
2468b7b6a941Sreyk 	long long	 llval;
2469b7b6a941Sreyk 
2470b7b6a941Sreyk 	llval = strtonum(n, 0, UINT16_MAX, &errstr);
2471b7b6a941Sreyk 	if (errstr) {
2472b7b6a941Sreyk 		s = getservbyname(n, "tcp");
2473b7b6a941Sreyk 		if (s == NULL)
2474b7b6a941Sreyk 			s = getservbyname(n, "udp");
2475b9cb0b4fStracey 		if (s == NULL)
2476b7b6a941Sreyk 			return (-1);
2477b7b6a941Sreyk 		return (s->s_port);
2478b7b6a941Sreyk 	}
2479b7b6a941Sreyk 
24804703e0faSreyk 	return (htons((unsigned short)llval));
2481b7b6a941Sreyk }
2482b7b6a941Sreyk 
2483b7b6a941Sreyk int
is_if_in_group(const char * ifname,const char * groupname)2484b7b6a941Sreyk is_if_in_group(const char *ifname, const char *groupname)
2485b7b6a941Sreyk {
2486b7b6a941Sreyk 	unsigned int		 len;
2487b7b6a941Sreyk 	struct ifgroupreq	 ifgr;
2488b7b6a941Sreyk 	struct ifg_req		*ifg;
2489b7b6a941Sreyk 	int			 s;
2490b7b6a941Sreyk 	int			 ret = 0;
2491b7b6a941Sreyk 
2492df69c215Sderaadt 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
2493b7b6a941Sreyk 		err(1, "socket");
2494b7b6a941Sreyk 
2495b7b6a941Sreyk 	memset(&ifgr, 0, sizeof(ifgr));
2496b7b6a941Sreyk 	if (strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ) >= IFNAMSIZ)
2497b7b6a941Sreyk 		err(1, "IFNAMSIZ");
2498b7b6a941Sreyk 	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
2499b7b6a941Sreyk 		if (errno == EINVAL || errno == ENOTTY)
2500b7b6a941Sreyk 			goto end;
2501b7b6a941Sreyk 		err(1, "SIOCGIFGROUP");
2502b7b6a941Sreyk 	}
2503b7b6a941Sreyk 
2504b7b6a941Sreyk 	len = ifgr.ifgr_len;
250535de856eSderaadt 	ifgr.ifgr_groups = calloc(len / sizeof(struct ifg_req),
2506b7b6a941Sreyk 	    sizeof(struct ifg_req));
2507b7b6a941Sreyk 	if (ifgr.ifgr_groups == NULL)
2508b7b6a941Sreyk 		err(1, "getifgroups");
2509b7b6a941Sreyk 	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
2510b7b6a941Sreyk 		err(1, "SIOCGIFGROUP");
2511b7b6a941Sreyk 
2512b7b6a941Sreyk 	ifg = ifgr.ifgr_groups;
2513b7b6a941Sreyk 	for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
2514b7b6a941Sreyk 		len -= sizeof(struct ifg_req);
2515b7b6a941Sreyk 		if (strcmp(ifg->ifgrq_group, groupname) == 0) {
2516b7b6a941Sreyk 			ret = 1;
2517b7b6a941Sreyk 			break;
2518b7b6a941Sreyk 		}
2519b7b6a941Sreyk 	}
2520b7b6a941Sreyk 	free(ifgr.ifgr_groups);
2521b7b6a941Sreyk 
2522b7b6a941Sreyk end:
2523b7b6a941Sreyk 	close(s);
2524b7b6a941Sreyk 	return (ret);
2525b7b6a941Sreyk }
25269ea72f95Stracey 
25279ea72f95Stracey int
get_fastcgi_dest(struct server_config * xsrv_conf,const char * node,char * port)25289ea72f95Stracey get_fastcgi_dest(struct server_config *xsrv_conf, const char *node, char *port)
25299ea72f95Stracey {
25309ea72f95Stracey 	struct addrinfo		 hints, *res;
25319ea72f95Stracey 	int			 s;
25329ea72f95Stracey 
25339ea72f95Stracey 	memset(&hints, 0, sizeof(hints));
25349ea72f95Stracey 	hints.ai_family = AF_UNSPEC;
25359ea72f95Stracey 	hints.ai_socktype = SOCK_STREAM;
25369ea72f95Stracey 
25379ea72f95Stracey 	if ((s = getaddrinfo(node, port, &hints, &res)) != 0) {
25389ea72f95Stracey 		yyerror("getaddrinfo: %s\n", gai_strerror(s));
25399ea72f95Stracey 		return -1;
25409ea72f95Stracey 	}
25419ea72f95Stracey 
25429ea72f95Stracey 	memset(&(xsrv_conf)->fastcgi_ss, 0, sizeof(xsrv_conf->fastcgi_ss));
25439ea72f95Stracey 	memcpy(&(xsrv_conf)->fastcgi_ss, res->ai_addr, res->ai_addrlen);
25449ea72f95Stracey 
25459ea72f95Stracey 	freeaddrinfo(res);
25469ea72f95Stracey 
25479ea72f95Stracey 	return (0);
25489ea72f95Stracey }
254935afa99fStb 
255035afa99fStb void
remove_locations(struct server_config * xsrv_conf)255135afa99fStb remove_locations(struct server_config *xsrv_conf)
255235afa99fStb {
255335afa99fStb 	struct server *s, *next;
255435afa99fStb 
255535afa99fStb 	TAILQ_FOREACH_SAFE(s, conf->sc_servers, srv_entry, next) {
255635afa99fStb 		if (!(s->srv_conf.flags & SRVFLAG_LOCATION &&
255735afa99fStb 		    s->srv_conf.parent_id == xsrv_conf->parent_id))
255835afa99fStb 			continue;
255935afa99fStb 		TAILQ_REMOVE(conf->sc_servers, s, srv_entry);
256035afa99fStb 		serverconfig_free(&s->srv_conf);
256135afa99fStb 		free(s);
256235afa99fStb 	}
256335afa99fStb }
2564