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