1 /* $OpenBSD: parse.y,v 1.127 2021/10/24 16:01:04 ian Exp $ */
2
3 /*
4 * Copyright (c) 2020 Matthias Pressfreund <mpfr@fn.de>
5 * Copyright (c) 2007 - 2015 Reyk Floeter <reyk@openbsd.org>
6 * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
7 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
8 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
9 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
10 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
11 * Copyright (c) 2001 Markus Friedl. All rights reserved.
12 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
13 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
14 *
15 * Permission to use, copy, modify, and distribute this software for any
16 * purpose with or without fee is hereby granted, provided that the above
17 * copyright notice and this permission notice appear in all copies.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
20 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
22 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
24 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
25 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 */
27
28 %{
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <sys/stat.h>
33 #include <sys/queue.h>
34 #include <sys/tree.h>
35 #include <sys/ioctl.h>
36 #include <sys/sockio.h>
37 #include <sys/time.h>
38
39 #include <net/if.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42
43 #include <ctype.h>
44 #include <unistd.h>
45 #include <err.h>
46 #include <errno.h>
47 #include <limits.h>
48 #include <stdint.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <netdb.h>
52 #include <string.h>
53 #include <ifaddrs.h>
54 #include <syslog.h>
55
56 #include "httpd.h"
57 #include "http.h"
58
59 #ifndef __OpenBSD__
60 #include <stdlib.h>
61 #endif
62
63 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
64 static struct file {
65 TAILQ_ENTRY(file) entry;
66 FILE *stream;
67 char *name;
68 size_t ungetpos;
69 size_t ungetsize;
70 u_char *ungetbuf;
71 int eof_reached;
72 int lineno;
73 int errors;
74 } *file, *topfile;
75 struct file *pushfile(const char *, int);
76 int popfile(void);
77 int check_file_secrecy(int, const char *);
78 int yyparse(void);
79 int yylex(void);
80 int yyerror(const char *, ...)
81 __attribute__((__format__ (printf, 1, 2)))
82 __attribute__((__nonnull__ (1)));
83 int kw_cmp(const void *, const void *);
84 int lookup(char *);
85 int igetc(void);
86 int lgetc(int);
87 void lungetc(int);
88 int findeol(void);
89
90 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
91 struct sym {
92 TAILQ_ENTRY(sym) entry;
93 int used;
94 int persist;
95 char *nam;
96 char *val;
97 };
98 int symset(const char *, const char *, int);
99 char *symget(const char *);
100
101 struct httpd *conf = NULL;
102 static int errors = 0;
103 static int loadcfg = 0;
104 uint32_t last_server_id = 0;
105 uint32_t last_auth_id = 0;
106
107 static struct server *srv = NULL, *parentsrv = NULL;
108 static struct server_config *srv_conf = NULL;
109 struct serverlist servers;
110 struct media_type media;
111
112 struct address *host_v4(const char *);
113 struct address *host_v6(const char *);
114 int host_dns(const char *, struct addresslist *,
115 int, struct portrange *, const char *, int);
116 int host_if(const char *, struct addresslist *,
117 int, struct portrange *, const char *, int);
118 int host(const char *, struct addresslist *,
119 int, struct portrange *, const char *, int);
120 struct server *server_inherit(struct server *, struct server_config *,
121 struct server_config *);
122 int listen_on(const char *, int, struct portrange *);
123 int getservice(char *);
124 int is_if_in_group(const char *, const char *);
125 int get_fastcgi_dest(struct server_config *, const char *, char *);
126 void remove_locations(struct server_config *);
127
128 typedef struct {
129 union {
130 int64_t number;
131 char *string;
132 struct timeval tv;
133 struct portrange port;
134 struct auth auth;
135 } v;
136 int lineno;
137 } YYSTYPE;
138
139 %}
140
141 %token ACCESS ALIAS AUTO BACKLOG BODY BUFFER CERTIFICATE CHROOT CIPHERS COMMON
142 %token COMBINED CONNECTION DHE DIRECTORY ECDHE ERR FCGI INDEX IP KEY LIFETIME
143 %token LISTEN LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY OCSP ON PORT PREFORK
144 %token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TICKET
145 %token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
146 %token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE
147 %token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT
148 %token ERRDOCS
149 %token <v.string> STRING
150 %token <v.number> NUMBER
151 %type <v.port> port
152 %type <v.string> fcgiport
153 %type <v.number> opttls optmatch optfound
154 %type <v.tv> timeout
155 %type <v.string> numberstring optstring
156 %type <v.auth> authopts
157
158 %%
159
160 grammar : /* empty */
161 | grammar include '\n'
162 | grammar '\n'
163 | grammar varset '\n'
164 | grammar main '\n'
165 | grammar server '\n'
166 | grammar types '\n'
167 | grammar error '\n' { file->errors++; }
168 ;
169
170 include : INCLUDE STRING {
171 struct file *nfile;
172
173 if ((nfile = pushfile($2, 0)) == NULL) {
174 yyerror("failed to include file %s", $2);
175 free($2);
176 YYERROR;
177 }
178 free($2);
179
180 file = nfile;
181 lungetc('\n');
182 }
183 ;
184
185 varset : STRING '=' STRING {
186 char *s = $1;
187 while (*s++) {
188 if (isspace((unsigned char)*s)) {
189 yyerror("macro name cannot contain "
190 "whitespace");
191 free($1);
192 free($3);
193 YYERROR;
194 }
195 }
196 if (symset($1, $3, 0) == -1)
197 fatal("cannot store variable");
198 free($1);
199 free($3);
200 }
201 ;
202
203 opttls : /*empty*/ { $$ = 0; }
204 | TLS { $$ = 1; }
205 ;
206
207 main : PREFORK NUMBER {
208 if (loadcfg)
209 break;
210 if ($2 <= 0 || $2 > PROC_MAX_INSTANCES) {
211 yyerror("invalid number of preforked "
212 "servers: %lld", $2);
213 YYERROR;
214 }
215 conf->sc_prefork_server = $2;
216 }
217 | CHROOT STRING {
218 conf->sc_chroot = $2;
219 }
220 | ERRDOCS STRING {
221 if ($2 != NULL && strlcpy(conf->sc_errdocroot, $2,
222 sizeof(conf->sc_errdocroot)) >=
223 sizeof(conf->sc_errdocroot)) {
224 yyerror("errdoc root path too long");
225 free($2);
226 YYERROR;
227 }
228 free($2);
229 conf->sc_custom_errdocs = 1;
230 }
231 | LOGDIR STRING {
232 conf->sc_logdir = $2;
233 }
234 | DEFAULT TYPE mediastring {
235 memcpy(&conf->sc_default_type, &media,
236 sizeof(struct media_type));
237 }
238 ;
239
240 server : SERVER optmatch STRING {
241 struct server *s;
242 struct sockaddr_un *sun;
243
244 if (!loadcfg) {
245 free($3);
246 YYACCEPT;
247 }
248
249 if ((s = calloc(1, sizeof (*s))) == NULL)
250 fatal("out of memory");
251
252 if (strlcpy(s->srv_conf.name, $3,
253 sizeof(s->srv_conf.name)) >=
254 sizeof(s->srv_conf.name)) {
255 yyerror("server name truncated");
256 free($3);
257 free(s);
258 YYERROR;
259 }
260 free($3);
261
262 strlcpy(s->srv_conf.root, HTTPD_DOCROOT,
263 sizeof(s->srv_conf.root));
264 strlcpy(s->srv_conf.index, HTTPD_INDEX,
265 sizeof(s->srv_conf.index));
266 strlcpy(s->srv_conf.accesslog, HTTPD_ACCESS_LOG,
267 sizeof(s->srv_conf.accesslog));
268 strlcpy(s->srv_conf.errorlog, HTTPD_ERROR_LOG,
269 sizeof(s->srv_conf.errorlog));
270 s->srv_conf.id = ++last_server_id;
271 s->srv_conf.parent_id = s->srv_conf.id;
272 s->srv_s = -1;
273 s->srv_conf.timeout.tv_sec = SERVER_TIMEOUT;
274 s->srv_conf.requesttimeout.tv_sec =
275 SERVER_REQUESTTIMEOUT;
276 s->srv_conf.maxrequests = SERVER_MAXREQUESTS;
277 s->srv_conf.maxrequestbody = SERVER_MAXREQUESTBODY;
278 s->srv_conf.flags = SRVFLAG_LOG;
279 if ($2)
280 s->srv_conf.flags |= SRVFLAG_SERVER_MATCH;
281 s->srv_conf.logformat = LOG_FORMAT_COMMON;
282 s->srv_conf.tls_protocols = TLS_PROTOCOLS_DEFAULT;
283 if ((s->srv_conf.tls_cert_file =
284 strdup(HTTPD_TLS_CERT)) == NULL)
285 fatal("out of memory");
286 if ((s->srv_conf.tls_key_file =
287 strdup(HTTPD_TLS_KEY)) == NULL)
288 fatal("out of memory");
289 strlcpy(s->srv_conf.tls_ciphers,
290 HTTPD_TLS_CIPHERS,
291 sizeof(s->srv_conf.tls_ciphers));
292 strlcpy(s->srv_conf.tls_dhe_params,
293 HTTPD_TLS_DHE_PARAMS,
294 sizeof(s->srv_conf.tls_dhe_params));
295 strlcpy(s->srv_conf.tls_ecdhe_curves,
296 HTTPD_TLS_ECDHE_CURVES,
297 sizeof(s->srv_conf.tls_ecdhe_curves));
298
299 sun = (struct sockaddr_un *)&s->srv_conf.fastcgi_ss;
300 sun->sun_family = AF_UNIX;
301 (void)strlcpy(sun->sun_path, HTTPD_FCGI_SOCKET,
302 sizeof(sun->sun_path));
303 sun->sun_len = sizeof(struct sockaddr_un);
304
305 s->srv_conf.hsts_max_age = SERVER_HSTS_DEFAULT_AGE;
306
307 (void)strlcpy(s->srv_conf.errdocroot,
308 conf->sc_errdocroot,
309 sizeof(s->srv_conf.errdocroot));
310 if (conf->sc_custom_errdocs)
311 s->srv_conf.flags |= SRVFLAG_ERRDOCS;
312
313 if (last_server_id == INT_MAX) {
314 yyerror("too many servers defined");
315 free(s);
316 YYERROR;
317 }
318 srv = s;
319 srv_conf = &srv->srv_conf;
320
321 SPLAY_INIT(&srv->srv_clients);
322 TAILQ_INIT(&srv->srv_hosts);
323 TAILQ_INIT(&srv_conf->fcgiparams);
324
325 TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry);
326 } '{' optnl serveropts_l '}' {
327 struct server *s, *sn;
328 struct server_config *a, *b;
329
330 srv_conf = &srv->srv_conf;
331
332 /* Check if the new server already exists. */
333 if (server_match(srv, 1) != NULL) {
334 yyerror("server \"%s\" defined twice",
335 srv->srv_conf.name);
336 serverconfig_free(srv_conf);
337 free(srv);
338 YYABORT;
339 }
340
341 if (srv->srv_conf.ss.ss_family == AF_UNSPEC) {
342 yyerror("listen address not specified");
343 serverconfig_free(srv_conf);
344 free(srv);
345 YYERROR;
346 }
347
348 if ((s = server_match(srv, 0)) != NULL) {
349 if ((s->srv_conf.flags & SRVFLAG_TLS) !=
350 (srv->srv_conf.flags & SRVFLAG_TLS)) {
351 yyerror("server \"%s\": tls and "
352 "non-tls on same address/port",
353 srv->srv_conf.name);
354 serverconfig_free(srv_conf);
355 free(srv);
356 YYERROR;
357 }
358 if (srv->srv_conf.flags & SRVFLAG_TLS &&
359 server_tls_cmp(s, srv) != 0) {
360 yyerror("server \"%s\": tls "
361 "configuration mismatch on same "
362 "address/port",
363 srv->srv_conf.name);
364 serverconfig_free(srv_conf);
365 free(srv);
366 YYERROR;
367 }
368 }
369
370 if ((srv->srv_conf.flags & SRVFLAG_TLS) &&
371 srv->srv_conf.tls_protocols == 0) {
372 yyerror("server \"%s\": no tls protocols",
373 srv->srv_conf.name);
374 serverconfig_free(srv_conf);
375 free(srv);
376 YYERROR;
377 }
378
379 if (server_tls_load_keypair(srv) == -1) {
380 /* Soft fail as there may be no certificate. */
381 log_warnx("%s:%d: server \"%s\": failed to "
382 "load public/private keys", file->name,
383 yylval.lineno, srv->srv_conf.name);
384
385 remove_locations(srv_conf);
386 serverconfig_free(srv_conf);
387 srv_conf = NULL;
388 free(srv);
389 srv = NULL;
390 break;
391 }
392
393 if (server_tls_load_ca(srv) == -1) {
394 yyerror("server \"%s\": failed to load "
395 "ca cert(s)", srv->srv_conf.name);
396 serverconfig_free(srv_conf);
397 free(srv);
398 YYERROR;
399 }
400
401 if (server_tls_load_crl(srv) == -1) {
402 yyerror("server \"%s\": failed to load crl(s)",
403 srv->srv_conf.name);
404 serverconfig_free(srv_conf);
405 free(srv);
406 YYERROR;
407 }
408
409 if (server_tls_load_ocsp(srv) == -1) {
410 yyerror("server \"%s\": failed to load "
411 "ocsp staple", srv->srv_conf.name);
412 serverconfig_free(srv_conf);
413 free(srv);
414 YYERROR;
415 }
416
417 DPRINTF("adding server \"%s[%u]\"",
418 srv->srv_conf.name, srv->srv_conf.id);
419
420 TAILQ_INSERT_TAIL(conf->sc_servers, srv, srv_entry);
421
422 /*
423 * Add aliases and additional listen addresses as
424 * individual servers.
425 */
426 TAILQ_FOREACH(a, &srv->srv_hosts, entry) {
427 /* listen address */
428 if (a->ss.ss_family == AF_UNSPEC)
429 continue;
430 TAILQ_FOREACH(b, &srv->srv_hosts, entry) {
431 /* alias name */
432 if (*b->name == '\0' ||
433 (b == &srv->srv_conf && b == a))
434 continue;
435
436 if ((sn = server_inherit(srv,
437 b, a)) == NULL) {
438 serverconfig_free(srv_conf);
439 free(srv);
440 YYABORT;
441 }
442
443 DPRINTF("adding server \"%s[%u]\"",
444 sn->srv_conf.name, sn->srv_conf.id);
445
446 TAILQ_INSERT_TAIL(conf->sc_servers,
447 sn, srv_entry);
448 }
449 }
450
451 /* Remove temporary aliases */
452 TAILQ_FOREACH_MUTABLE(a, &srv->srv_hosts, entry, b) {
453 TAILQ_REMOVE(&srv->srv_hosts, a, entry);
454 if (a == &srv->srv_conf)
455 continue;
456 serverconfig_free(a);
457 free(a);
458 }
459
460 srv = NULL;
461 srv_conf = NULL;
462 }
463 ;
464
465 serveropts_l : serveropts_l serveroptsl nl
466 | serveroptsl optnl
467 ;
468
469 serveroptsl : LISTEN ON STRING opttls port {
470 if (listen_on($3, $4, &$5) == -1) {
471 free($3);
472 YYERROR;
473 }
474 free($3);
475 }
476 | ALIAS optmatch STRING {
477 struct server_config *alias;
478
479 if (parentsrv != NULL) {
480 yyerror("alias inside location");
481 free($3);
482 YYERROR;
483 }
484
485 if ((alias = calloc(1, sizeof(*alias))) == NULL)
486 fatal("out of memory");
487
488 if (strlcpy(alias->name, $3, sizeof(alias->name)) >=
489 sizeof(alias->name)) {
490 yyerror("server alias truncated");
491 free($3);
492 free(alias);
493 YYERROR;
494 }
495 free($3);
496
497 if ($2)
498 alias->flags |= SRVFLAG_SERVER_MATCH;
499
500 TAILQ_INSERT_TAIL(&srv->srv_hosts, alias, entry);
501 }
502 | ERRDOCS STRING {
503 if (parentsrv != NULL) {
504 yyerror("errdocs inside location");
505 YYERROR;
506 }
507 if ($2 != NULL && strlcpy(srv->srv_conf.errdocroot, $2,
508 sizeof(srv->srv_conf.errdocroot)) >=
509 sizeof(srv->srv_conf.errdocroot)) {
510 yyerror("errdoc root path too long");
511 free($2);
512 YYERROR;
513 }
514 free($2);
515 srv->srv_conf.flags |= SRVFLAG_ERRDOCS;
516 }
517 | NO ERRDOCS {
518 if (parentsrv != NULL) {
519 yyerror("errdocs inside location");
520 YYERROR;
521 }
522 srv->srv_conf.flags &= ~SRVFLAG_ERRDOCS;
523 }
524 | tcpip {
525 if (parentsrv != NULL) {
526 yyerror("tcp flags inside location");
527 YYERROR;
528 }
529 }
530 | connection {
531 if (parentsrv != NULL) {
532 yyerror("connection options inside location");
533 YYERROR;
534 }
535 }
536 | tls {
537 struct server_config *sc;
538 int tls_flag = 0;
539
540 if (parentsrv != NULL) {
541 yyerror("tls configuration inside location");
542 YYERROR;
543 }
544
545 /* Ensure that at least one server has TLS enabled. */
546 TAILQ_FOREACH(sc, &srv->srv_hosts, entry) {
547 tls_flag |= (sc->flags & SRVFLAG_TLS);
548 }
549 if (tls_flag == 0) {
550 yyerror("tls options without tls listener");
551 YYERROR;
552 }
553 }
554 | request
555 | root
556 | directory
557 | logformat
558 | fastcgi
559 | authenticate
560 | filter
561 | LOCATION optfound optmatch STRING {
562 struct server *s;
563 struct sockaddr_un *sun;
564
565 if (srv->srv_conf.ss.ss_family == AF_UNSPEC) {
566 yyerror("listen address not specified");
567 free($4);
568 YYERROR;
569 }
570
571 if (parentsrv != NULL) {
572 yyerror("location %s inside location", $4);
573 free($4);
574 YYERROR;
575 }
576
577 if (!loadcfg) {
578 free($4);
579 YYACCEPT;
580 }
581
582 if ((s = calloc(1, sizeof (*s))) == NULL)
583 fatal("out of memory");
584
585 if (strlcpy(s->srv_conf.location, $4,
586 sizeof(s->srv_conf.location)) >=
587 sizeof(s->srv_conf.location)) {
588 yyerror("server location truncated");
589 free($4);
590 free(s);
591 YYERROR;
592 }
593 free($4);
594
595 if (strlcpy(s->srv_conf.name, srv->srv_conf.name,
596 sizeof(s->srv_conf.name)) >=
597 sizeof(s->srv_conf.name)) {
598 yyerror("server name truncated");
599 free(s);
600 YYERROR;
601 }
602
603 sun = (struct sockaddr_un *)&s->srv_conf.fastcgi_ss;
604 sun->sun_family = AF_UNIX;
605 (void)strlcpy(sun->sun_path, HTTPD_FCGI_SOCKET,
606 sizeof(sun->sun_path));
607 sun->sun_len = sizeof(struct sockaddr_un);
608
609 s->srv_conf.id = ++last_server_id;
610 /* A location entry uses the parent id */
611 s->srv_conf.parent_id = srv->srv_conf.id;
612 s->srv_conf.flags = SRVFLAG_LOCATION;
613 if ($2 == 1) {
614 s->srv_conf.flags &=
615 ~SRVFLAG_LOCATION_NOT_FOUND;
616 s->srv_conf.flags |=
617 SRVFLAG_LOCATION_FOUND;
618 } else if ($2 == -1) {
619 s->srv_conf.flags &=
620 ~SRVFLAG_LOCATION_FOUND;
621 s->srv_conf.flags |=
622 SRVFLAG_LOCATION_NOT_FOUND;
623 }
624 if ($3)
625 s->srv_conf.flags |= SRVFLAG_LOCATION_MATCH;
626 s->srv_s = -1;
627 memcpy(&s->srv_conf.ss, &srv->srv_conf.ss,
628 sizeof(s->srv_conf.ss));
629 s->srv_conf.port = srv->srv_conf.port;
630 s->srv_conf.prefixlen = srv->srv_conf.prefixlen;
631 s->srv_conf.tls_flags = srv->srv_conf.tls_flags;
632
633 if (last_server_id == INT_MAX) {
634 yyerror("too many servers/locations defined");
635 free(s);
636 YYERROR;
637 }
638 parentsrv = srv;
639 srv = s;
640 srv_conf = &srv->srv_conf;
641 SPLAY_INIT(&srv->srv_clients);
642 } '{' optnl serveropts_l '}' {
643 struct server *s = NULL;
644 uint32_t f;
645
646 f = SRVFLAG_LOCATION_FOUND |
647 SRVFLAG_LOCATION_NOT_FOUND;
648
649 TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
650 /* Compare locations of same parent server */
651 if ((s->srv_conf.flags & SRVFLAG_LOCATION) &&
652 s->srv_conf.parent_id ==
653 srv_conf->parent_id &&
654 (s->srv_conf.flags & f) ==
655 (srv_conf->flags & f) &&
656 strcmp(s->srv_conf.location,
657 srv_conf->location) == 0)
658 break;
659 }
660 if (s != NULL) {
661 yyerror("location \"%s\" defined twice",
662 srv->srv_conf.location);
663 serverconfig_free(srv_conf);
664 free(srv);
665 YYABORT;
666 }
667
668 DPRINTF("adding location \"%s\" for \"%s[%u]\"",
669 srv->srv_conf.location,
670 srv->srv_conf.name, srv->srv_conf.id);
671
672 TAILQ_INSERT_TAIL(conf->sc_servers, srv, srv_entry);
673
674 srv = parentsrv;
675 srv_conf = &parentsrv->srv_conf;
676 parentsrv = NULL;
677 }
678 | DEFAULT TYPE mediastring {
679 srv_conf->flags |= SRVFLAG_DEFAULT_TYPE;
680 memcpy(&srv_conf->default_type, &media,
681 sizeof(struct media_type));
682 }
683 | include
684 | hsts {
685 if (parentsrv != NULL) {
686 yyerror("hsts inside location");
687 YYERROR;
688 }
689 srv->srv_conf.flags |= SRVFLAG_SERVER_HSTS;
690 }
691 ;
692
693 optfound : /* empty */ { $$ = 0; }
694 | FOUND { $$ = 1; }
695 | NOT FOUND { $$ = -1; }
696 ;
697
698 hsts : HSTS '{' optnl hstsflags_l '}'
699 | HSTS hstsflags
700 | HSTS
701 ;
702
703 hstsflags_l : hstsflags optcommanl hstsflags_l
704 | hstsflags optnl
705 ;
706
707 hstsflags : MAXAGE NUMBER {
708 if ($2 < 0 || $2 > INT_MAX) {
709 yyerror("invalid number of seconds: %lld", $2);
710 YYERROR;
711 }
712 srv_conf->hsts_max_age = $2;
713 }
714 | SUBDOMAINS {
715 srv->srv_conf.hsts_flags |= HSTSFLAG_SUBDOMAINS;
716 }
717 | PRELOAD {
718 srv->srv_conf.hsts_flags |= HSTSFLAG_PRELOAD;
719 }
720 ;
721
722 fastcgi : NO FCGI {
723 srv_conf->flags &= ~SRVFLAG_FCGI;
724 srv_conf->flags |= SRVFLAG_NO_FCGI;
725 }
726 | FCGI {
727 srv_conf->flags &= ~SRVFLAG_NO_FCGI;
728 srv_conf->flags |= SRVFLAG_FCGI;
729 }
730 | FCGI {
731 srv_conf->flags &= ~SRVFLAG_NO_FCGI;
732 srv_conf->flags |= SRVFLAG_FCGI;
733 } '{' optnl fcgiflags_l '}'
734 | FCGI {
735 srv_conf->flags &= ~SRVFLAG_NO_FCGI;
736 srv_conf->flags |= SRVFLAG_FCGI;
737 } fcgiflags
738 ;
739
740 fcgiflags_l : fcgiflags optcommanl fcgiflags_l
741 | fcgiflags optnl
742 ;
743
744 fcgiflags : SOCKET STRING {
745 struct sockaddr_un *sun;
746 sun = (struct sockaddr_un *)&srv_conf->fastcgi_ss;
747 memset(sun, 0, sizeof(*sun));
748 sun->sun_family = AF_UNIX;
749 if (strlcpy(sun->sun_path, $2, sizeof(sun->sun_path))
750 >= sizeof(sun->sun_path)) {
751 yyerror("socket path too long");
752 free($2);
753 YYERROR;
754 }
755 srv_conf->fastcgi_ss.ss_len =
756 sizeof(struct sockaddr_un);
757 free($2);
758 }
759 | SOCKET TCP STRING {
760 if (get_fastcgi_dest(srv_conf, $3, FCGI_DEFAULT_PORT)
761 == -1) {
762 free($3);
763 YYERROR;
764 }
765 free($3);
766 }
767 | SOCKET TCP STRING fcgiport {
768 if (get_fastcgi_dest(srv_conf, $3, $4) == -1) {
769 free($3);
770 free($4);
771 YYERROR;
772 }
773 free($3);
774 free($4);
775 }
776 | PARAM STRING STRING {
777 struct fastcgi_param *param;
778
779 if ((param = calloc(1, sizeof(*param))) == NULL)
780 fatal("out of memory");
781
782 if (strlcpy(param->name, $2, sizeof(param->name)) >=
783 sizeof(param->name)) {
784 yyerror("fastcgi_param name truncated");
785 free($2);
786 free($3);
787 free(param);
788 YYERROR;
789 }
790 if (strlcpy(param->value, $3, sizeof(param->value)) >=
791 sizeof(param->value)) {
792 yyerror("fastcgi_param value truncated");
793 free($2);
794 free($3);
795 free(param);
796 YYERROR;
797 }
798 free($2);
799 free($3);
800
801 DPRINTF("[%s,%s,%d]: adding param \"%s\" value \"%s\"",
802 srv_conf->location, srv_conf->name, srv_conf->id,
803 param->name, param->value);
804 TAILQ_INSERT_HEAD(&srv_conf->fcgiparams, param, entry);
805 }
806 | STRIP NUMBER {
807 if ($2 < 0 || $2 > INT_MAX) {
808 yyerror("invalid fastcgi strip number");
809 YYERROR;
810 }
811 srv_conf->fcgistrip = $2;
812 }
813 ;
814
815 connection : CONNECTION '{' optnl conflags_l '}'
816 | CONNECTION conflags
817 ;
818
819 conflags_l : conflags optcommanl conflags_l
820 | conflags optnl
821 ;
822
823 conflags : TIMEOUT timeout {
824 memcpy(&srv_conf->timeout, &$2,
825 sizeof(struct timeval));
826 }
827 | REQUEST TIMEOUT timeout {
828 memcpy(&srv_conf->requesttimeout, &$3,
829 sizeof(struct timeval));
830 }
831 | MAXIMUM REQUESTS NUMBER {
832 srv_conf->maxrequests = $3;
833 }
834 | MAXIMUM REQUEST BODY NUMBER {
835 srv_conf->maxrequestbody = $4;
836 }
837 ;
838
839 tls : TLS '{' optnl tlsopts_l '}'
840 | TLS tlsopts
841 ;
842
843 tlsopts_l : tlsopts optcommanl tlsopts_l
844 | tlsopts optnl
845 ;
846
847 tlsopts : CERTIFICATE STRING {
848 free(srv_conf->tls_cert_file);
849 if ((srv_conf->tls_cert_file = strdup($2)) == NULL)
850 fatal("out of memory");
851 free($2);
852 }
853 | KEY STRING {
854 free(srv_conf->tls_key_file);
855 if ((srv_conf->tls_key_file = strdup($2)) == NULL)
856 fatal("out of memory");
857 free($2);
858 }
859 | OCSP STRING {
860 free(srv_conf->tls_ocsp_staple_file);
861 if ((srv_conf->tls_ocsp_staple_file = strdup($2))
862 == NULL)
863 fatal("out of memory");
864 free($2);
865 }
866 | CIPHERS STRING {
867 if (strlcpy(srv_conf->tls_ciphers, $2,
868 sizeof(srv_conf->tls_ciphers)) >=
869 sizeof(srv_conf->tls_ciphers)) {
870 yyerror("ciphers too long");
871 free($2);
872 YYERROR;
873 }
874 free($2);
875 }
876 | CLIENT CA STRING tlsclientopt {
877 srv_conf->tls_flags |= TLSFLAG_CA;
878 free(srv_conf->tls_ca_file);
879 if ((srv_conf->tls_ca_file = strdup($3)) == NULL)
880 fatal("out of memory");
881 free($3);
882 }
883 | DHE STRING {
884 if (strlcpy(srv_conf->tls_dhe_params, $2,
885 sizeof(srv_conf->tls_dhe_params)) >=
886 sizeof(srv_conf->tls_dhe_params)) {
887 yyerror("dhe too long");
888 free($2);
889 YYERROR;
890 }
891 free($2);
892 }
893 | ECDHE STRING {
894 if (strlcpy(srv_conf->tls_ecdhe_curves, $2,
895 sizeof(srv_conf->tls_ecdhe_curves)) >=
896 sizeof(srv_conf->tls_ecdhe_curves)) {
897 yyerror("ecdhe too long");
898 free($2);
899 YYERROR;
900 }
901 free($2);
902 }
903 | PROTOCOLS STRING {
904 if (tls_config_parse_protocols(
905 &srv_conf->tls_protocols, $2) != 0) {
906 yyerror("invalid tls protocols");
907 free($2);
908 YYERROR;
909 }
910 free($2);
911 }
912 | TICKET LIFETIME DEFAULT {
913 srv_conf->tls_ticket_lifetime = SERVER_DEF_TLS_LIFETIME;
914 }
915 | TICKET LIFETIME NUMBER {
916 if ($3 != 0 && $3 < SERVER_MIN_TLS_LIFETIME) {
917 yyerror("ticket lifetime too small");
918 YYERROR;
919 }
920 if ($3 > SERVER_MAX_TLS_LIFETIME) {
921 yyerror("ticket lifetime too large");
922 YYERROR;
923 }
924 srv_conf->tls_ticket_lifetime = $3;
925 }
926 | NO TICKET {
927 srv_conf->tls_ticket_lifetime = 0;
928 }
929 ;
930
931 tlsclientopt : /* empty */
932 | tlsclientopt CRL STRING {
933 srv_conf->tls_flags = TLSFLAG_CRL;
934 free(srv_conf->tls_crl_file);
935 if ((srv_conf->tls_crl_file = strdup($3)) == NULL)
936 fatal("out of memory");
937 free($3);
938 }
939 | tlsclientopt OPTIONAL {
940 srv_conf->tls_flags |= TLSFLAG_OPTIONAL;
941 }
942 ;
943 root : ROOT rootflags
944 | ROOT '{' optnl rootflags_l '}'
945 ;
946
947 rootflags_l : rootflags optcommanl rootflags_l
948 | rootflags optnl
949 ;
950
951 rootflags : STRING {
952 if (strlcpy(srv->srv_conf.root, $1,
953 sizeof(srv->srv_conf.root)) >=
954 sizeof(srv->srv_conf.root)) {
955 yyerror("document root too long");
956 free($1);
957 YYERROR;
958 }
959 free($1);
960 srv->srv_conf.flags |= SRVFLAG_ROOT;
961 }
962 ;
963
964 request : REQUEST requestflags
965 | REQUEST '{' optnl requestflags_l '}'
966 ;
967
968 requestflags_l : requestflags optcommanl requestflags_l
969 | requestflags optnl
970 ;
971
972 requestflags : REWRITE STRING {
973 if (strlcpy(srv->srv_conf.path, $2,
974 sizeof(srv->srv_conf.path)) >=
975 sizeof(srv->srv_conf.path)) {
976 yyerror("request path too long");
977 free($2);
978 YYERROR;
979 }
980 free($2);
981 srv->srv_conf.flags |= SRVFLAG_PATH_REWRITE;
982 srv->srv_conf.flags &= ~SRVFLAG_NO_PATH_REWRITE;
983 }
984 | NO REWRITE {
985 srv->srv_conf.flags |= SRVFLAG_NO_PATH_REWRITE;
986 srv->srv_conf.flags &= ~SRVFLAG_PATH_REWRITE;
987 }
988 | STRIP NUMBER {
989 if ($2 < 0 || $2 > INT_MAX) {
990 yyerror("invalid strip number");
991 YYERROR;
992 }
993 srv->srv_conf.strip = $2;
994 }
995 ;
996
997 authenticate : NO AUTHENTICATE {
998 srv->srv_conf.flags |= SRVFLAG_NO_AUTH;
999 }
1000 | AUTHENTICATE authopts {
1001 struct auth *auth;
1002
1003 if ((auth = auth_add(conf->sc_auth, &$2)) == NULL) {
1004 yyerror("failed to add auth");
1005 YYERROR;
1006 }
1007
1008 if (auth->auth_id == 0) {
1009 /* New htpasswd, get new Id */
1010 auth->auth_id = ++last_auth_id;
1011 if (last_auth_id == INT_MAX) {
1012 yyerror("too many auth ids defined");
1013 auth_free(conf->sc_auth, auth);
1014 YYERROR;
1015 }
1016 }
1017
1018 srv->srv_conf.auth_id = auth->auth_id;
1019 srv->srv_conf.flags |= SRVFLAG_AUTH;
1020 }
1021 ;
1022
1023 authopts : STRING WITH STRING {
1024 if (strlcpy(srv->srv_conf.auth_realm, $1,
1025 sizeof(srv->srv_conf.auth_realm)) >=
1026 sizeof(srv->srv_conf.auth_realm)) {
1027 yyerror("basic auth realm name too long");
1028 free($1);
1029 YYERROR;
1030 }
1031 free($1);
1032 if (strlcpy($$.auth_htpasswd, $3,
1033 sizeof($$.auth_htpasswd)) >=
1034 sizeof($$.auth_htpasswd)) {
1035 yyerror("password file name too long");
1036 free($3);
1037 YYERROR;
1038 }
1039 free($3);
1040
1041 }
1042 | WITH STRING {
1043 if (strlcpy($$.auth_htpasswd, $2,
1044 sizeof($$.auth_htpasswd)) >=
1045 sizeof($$.auth_htpasswd)) {
1046 yyerror("password file name too long");
1047 free($2);
1048 YYERROR;
1049 }
1050 free($2);
1051 };
1052
1053 directory : DIRECTORY dirflags
1054 | DIRECTORY '{' optnl dirflags_l '}'
1055 ;
1056
1057 dirflags_l : dirflags optcommanl dirflags_l
1058 | dirflags optnl
1059 ;
1060
1061 dirflags : INDEX STRING {
1062 if (strlcpy(srv_conf->index, $2,
1063 sizeof(srv_conf->index)) >=
1064 sizeof(srv_conf->index)) {
1065 yyerror("index file too long");
1066 free($2);
1067 YYERROR;
1068 }
1069 srv_conf->flags &= ~SRVFLAG_NO_INDEX;
1070 srv_conf->flags |= SRVFLAG_INDEX;
1071 free($2);
1072 }
1073 | NO INDEX {
1074 srv_conf->flags &= ~SRVFLAG_INDEX;
1075 srv_conf->flags |= SRVFLAG_NO_INDEX;
1076 }
1077 | AUTO INDEX {
1078 srv_conf->flags &= ~SRVFLAG_NO_AUTO_INDEX;
1079 srv_conf->flags |= SRVFLAG_AUTO_INDEX;
1080 }
1081 | NO AUTO INDEX {
1082 srv_conf->flags &= ~SRVFLAG_AUTO_INDEX;
1083 srv_conf->flags |= SRVFLAG_NO_AUTO_INDEX;
1084 }
1085 ;
1086
1087
1088 logformat : LOG logflags
1089 | LOG '{' optnl logflags_l '}'
1090 | NO LOG {
1091 srv_conf->flags &= ~SRVFLAG_LOG;
1092 srv_conf->flags |= SRVFLAG_NO_LOG;
1093 }
1094 ;
1095
1096 logflags_l : logflags optcommanl logflags_l
1097 | logflags optnl
1098 ;
1099
1100 logflags : STYLE logstyle
1101 | SYSLOG {
1102 srv_conf->flags &= ~SRVFLAG_NO_SYSLOG;
1103 srv_conf->flags |= SRVFLAG_SYSLOG;
1104 }
1105 | NO SYSLOG {
1106 srv_conf->flags &= ~SRVFLAG_SYSLOG;
1107 srv_conf->flags |= SRVFLAG_NO_SYSLOG;
1108 }
1109 | ACCESS STRING {
1110 if (strlcpy(srv_conf->accesslog, $2,
1111 sizeof(srv_conf->accesslog)) >=
1112 sizeof(srv_conf->accesslog)) {
1113 yyerror("access log name too long");
1114 free($2);
1115 YYERROR;
1116 }
1117 free($2);
1118 srv_conf->flags |= SRVFLAG_ACCESS_LOG;
1119 }
1120 | ERR STRING {
1121 if (strlcpy(srv_conf->errorlog, $2,
1122 sizeof(srv_conf->errorlog)) >=
1123 sizeof(srv_conf->errorlog)) {
1124 yyerror("error log name too long");
1125 free($2);
1126 YYERROR;
1127 }
1128 free($2);
1129 srv_conf->flags |= SRVFLAG_ERROR_LOG;
1130 }
1131 ;
1132
1133 logstyle : COMMON {
1134 srv_conf->flags &= ~SRVFLAG_NO_LOG;
1135 srv_conf->flags |= SRVFLAG_LOG;
1136 srv_conf->logformat = LOG_FORMAT_COMMON;
1137 }
1138 | COMBINED {
1139 srv_conf->flags &= ~SRVFLAG_NO_LOG;
1140 srv_conf->flags |= SRVFLAG_LOG;
1141 srv_conf->logformat = LOG_FORMAT_COMBINED;
1142 }
1143 | CONNECTION {
1144 srv_conf->flags &= ~SRVFLAG_NO_LOG;
1145 srv_conf->flags |= SRVFLAG_LOG;
1146 srv_conf->logformat = LOG_FORMAT_CONNECTION;
1147 }
1148 | FORWARDED {
1149 srv_conf->flags &= ~SRVFLAG_NO_LOG;
1150 srv_conf->flags |= SRVFLAG_LOG;
1151 srv_conf->logformat = LOG_FORMAT_FORWARDED;
1152 }
1153 ;
1154
1155 filter : block RETURN NUMBER optstring {
1156 if ($3 <= 0 || server_httperror_byid($3) == NULL) {
1157 yyerror("invalid return code: %lld", $3);
1158 free($4);
1159 YYERROR;
1160 }
1161 srv_conf->return_code = $3;
1162
1163 if ($4 != NULL) {
1164 /* Only for 3xx redirection headers */
1165 if ($3 < 300 || $3 > 399) {
1166 yyerror("invalid return code for "
1167 "location URI");
1168 free($4);
1169 YYERROR;
1170 }
1171 srv_conf->return_uri = $4;
1172 srv_conf->return_uri_len = strlen($4) + 1;
1173 }
1174 }
1175 | block DROP {
1176 /* No return code, silently drop the connection */
1177 srv_conf->return_code = 0;
1178 }
1179 | block {
1180 /* Forbidden */
1181 srv_conf->return_code = 403;
1182 }
1183 | PASS {
1184 srv_conf->flags &= ~SRVFLAG_BLOCK;
1185 srv_conf->flags |= SRVFLAG_NO_BLOCK;
1186 }
1187 ;
1188
1189 block : BLOCK {
1190 srv_conf->flags &= ~SRVFLAG_NO_BLOCK;
1191 srv_conf->flags |= SRVFLAG_BLOCK;
1192 }
1193 ;
1194
1195 optmatch : /* empty */ { $$ = 0; }
1196 | MATCH { $$ = 1; }
1197 ;
1198
1199 optstring : /* empty */ { $$ = NULL; }
1200 | STRING { $$ = $1; }
1201 ;
1202
1203 fcgiport : NUMBER {
1204 if ($1 <= 0 || $1 > (int)USHRT_MAX) {
1205 yyerror("invalid port: %lld", $1);
1206 YYERROR;
1207 }
1208 if (asprintf(&$$, "%lld", $1) == -1) {
1209 yyerror("out of memory");
1210 YYERROR;
1211 }
1212 }
1213 | STRING {
1214 if (getservice($1) <= 0) {
1215 yyerror("invalid port: %s", $1);
1216 free($1);
1217 YYERROR;
1218 }
1219
1220 $$ = $1;
1221 }
1222 ;
1223
1224 tcpip : TCP '{' optnl tcpflags_l '}'
1225 | TCP tcpflags
1226 ;
1227
1228 tcpflags_l : tcpflags optcommanl tcpflags_l
1229 | tcpflags optnl
1230 ;
1231
1232 tcpflags : SACK { srv_conf->tcpflags |= TCPFLAG_SACK; }
1233 | NO SACK { srv_conf->tcpflags |= TCPFLAG_NSACK; }
1234 | NODELAY {
1235 srv_conf->tcpflags |= TCPFLAG_NODELAY;
1236 }
1237 | NO NODELAY {
1238 srv_conf->tcpflags |= TCPFLAG_NNODELAY;
1239 }
1240 | BACKLOG NUMBER {
1241 if ($2 < 0 || $2 > SERVER_MAX_CLIENTS) {
1242 yyerror("invalid backlog: %lld", $2);
1243 YYERROR;
1244 }
1245 srv_conf->tcpbacklog = $2;
1246 }
1247 | SOCKET BUFFER NUMBER {
1248 srv_conf->tcpflags |= TCPFLAG_BUFSIZ;
1249 if ((srv_conf->tcpbufsiz = $3) < 0) {
1250 yyerror("invalid socket buffer size: %lld", $3);
1251 YYERROR;
1252 }
1253 }
1254 | IP STRING NUMBER {
1255 if ($3 < 0) {
1256 yyerror("invalid ttl: %lld", $3);
1257 free($2);
1258 YYERROR;
1259 }
1260 if (strcasecmp("ttl", $2) == 0) {
1261 srv_conf->tcpflags |= TCPFLAG_IPTTL;
1262 srv_conf->tcpipttl = $3;
1263 } else if (strcasecmp("minttl", $2) == 0) {
1264 srv_conf->tcpflags |= TCPFLAG_IPMINTTL;
1265 srv_conf->tcpipminttl = $3;
1266 } else {
1267 yyerror("invalid TCP/IP flag: %s", $2);
1268 free($2);
1269 YYERROR;
1270 }
1271 free($2);
1272 }
1273 ;
1274
1275 types : TYPES '{' optnl mediaopts_l '}'
1276 ;
1277
1278 mediaopts_l : mediaopts_l mediaoptsl nl
1279 | mediaoptsl nl
1280 ;
1281
1282 mediaoptsl : mediastring medianames_l optsemicolon
1283 | include
1284 ;
1285
1286 mediastring : STRING '/' STRING {
1287 if (strlcpy(media.media_type, $1,
1288 sizeof(media.media_type)) >=
1289 sizeof(media.media_type) ||
1290 strlcpy(media.media_subtype, $3,
1291 sizeof(media.media_subtype)) >=
1292 sizeof(media.media_subtype)) {
1293 yyerror("media type too long");
1294 free($1);
1295 free($3);
1296 YYERROR;
1297 }
1298 free($1);
1299 free($3);
1300 }
1301 ;
1302
1303 medianames_l : medianames_l medianamesl
1304 | medianamesl
1305 ;
1306
1307 medianamesl : numberstring {
1308 if (strlcpy(media.media_name, $1,
1309 sizeof(media.media_name)) >=
1310 sizeof(media.media_name)) {
1311 yyerror("media name too long");
1312 free($1);
1313 YYERROR;
1314 }
1315 free($1);
1316
1317 if (!loadcfg)
1318 break;
1319
1320 if (media_add(conf->sc_mediatypes, &media) == NULL) {
1321 yyerror("failed to add media type");
1322 YYERROR;
1323 }
1324 }
1325 ;
1326
1327 port : PORT NUMBER {
1328 if ($2 <= 0 || $2 > (int)USHRT_MAX) {
1329 yyerror("invalid port: %lld", $2);
1330 YYERROR;
1331 }
1332 $$.val[0] = htons($2);
1333 $$.op = 1;
1334 }
1335 | PORT STRING {
1336 int val;
1337
1338 if ((val = getservice($2)) == -1) {
1339 yyerror("invalid port: %s", $2);
1340 free($2);
1341 YYERROR;
1342 }
1343 free($2);
1344
1345 $$.val[0] = val;
1346 $$.op = 1;
1347 }
1348 ;
1349
1350 timeout : NUMBER
1351 {
1352 if ($1 < 0) {
1353 yyerror("invalid timeout: %lld", $1);
1354 YYERROR;
1355 }
1356 $$.tv_sec = $1;
1357 $$.tv_usec = 0;
1358 }
1359 ;
1360
1361 numberstring : NUMBER {
1362 char *s;
1363 if (asprintf(&s, "%lld", $1) == -1) {
1364 yyerror("asprintf: number");
1365 YYERROR;
1366 }
1367 $$ = s;
1368 }
1369 | STRING
1370 ;
1371
1372 optsemicolon : ';'
1373 |
1374 ;
1375
1376 optnl : '\n' optnl
1377 |
1378 ;
1379
1380 optcommanl : ',' optnl
1381 | nl
1382 ;
1383
1384 nl : '\n' optnl
1385 ;
1386
1387 %%
1388
1389 struct keywords {
1390 const char *k_name;
1391 int k_val;
1392 };
1393
1394 int
yyerror(const char * fmt,...)1395 yyerror(const char *fmt, ...)
1396 {
1397 va_list ap;
1398 char *msg;
1399
1400 file->errors++;
1401 va_start(ap, fmt);
1402 if (vasprintf(&msg, fmt, ap) == -1)
1403 fatalx("yyerror vasprintf");
1404 va_end(ap);
1405 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
1406 free(msg);
1407 return (0);
1408 }
1409
1410 int
kw_cmp(const void * k,const void * e)1411 kw_cmp(const void *k, const void *e)
1412 {
1413 return (strcmp(k, ((const struct keywords *)e)->k_name));
1414 }
1415
1416 int
lookup(char * s)1417 lookup(char *s)
1418 {
1419 /* this has to be sorted always */
1420 static const struct keywords keywords[] = {
1421 { "access", ACCESS },
1422 { "alias", ALIAS },
1423 { "authenticate", AUTHENTICATE},
1424 { "auto", AUTO },
1425 { "backlog", BACKLOG },
1426 { "block", BLOCK },
1427 { "body", BODY },
1428 { "buffer", BUFFER },
1429 { "ca", CA },
1430 { "certificate", CERTIFICATE },
1431 { "chroot", CHROOT },
1432 { "ciphers", CIPHERS },
1433 { "client", CLIENT },
1434 { "combined", COMBINED },
1435 { "common", COMMON },
1436 { "connection", CONNECTION },
1437 { "crl", CRL },
1438 { "default", DEFAULT },
1439 { "dhe", DHE },
1440 { "directory", DIRECTORY },
1441 { "drop", DROP },
1442 { "ecdhe", ECDHE },
1443 { "errdocs", ERRDOCS },
1444 { "error", ERR },
1445 { "fastcgi", FCGI },
1446 { "forwarded", FORWARDED },
1447 { "found", FOUND },
1448 { "hsts", HSTS },
1449 { "include", INCLUDE },
1450 { "index", INDEX },
1451 { "ip", IP },
1452 { "key", KEY },
1453 { "lifetime", LIFETIME },
1454 { "listen", LISTEN },
1455 { "location", LOCATION },
1456 { "log", LOG },
1457 { "logdir", LOGDIR },
1458 { "match", MATCH },
1459 { "max", MAXIMUM },
1460 { "max-age", MAXAGE },
1461 { "no", NO },
1462 { "nodelay", NODELAY },
1463 { "not", NOT },
1464 { "ocsp", OCSP },
1465 { "on", ON },
1466 { "optional", OPTIONAL },
1467 { "param", PARAM },
1468 { "pass", PASS },
1469 { "port", PORT },
1470 { "prefork", PREFORK },
1471 { "preload", PRELOAD },
1472 { "protocols", PROTOCOLS },
1473 { "request", REQUEST },
1474 { "requests", REQUESTS },
1475 { "return", RETURN },
1476 { "rewrite", REWRITE },
1477 { "root", ROOT },
1478 { "sack", SACK },
1479 { "server", SERVER },
1480 { "socket", SOCKET },
1481 { "strip", STRIP },
1482 { "style", STYLE },
1483 { "subdomains", SUBDOMAINS },
1484 { "syslog", SYSLOG },
1485 { "tcp", TCP },
1486 { "ticket", TICKET },
1487 { "timeout", TIMEOUT },
1488 { "tls", TLS },
1489 { "type", TYPE },
1490 { "types", TYPES },
1491 { "with", WITH }
1492 };
1493 const struct keywords *p;
1494
1495 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
1496 sizeof(keywords[0]), kw_cmp);
1497
1498 if (p)
1499 return (p->k_val);
1500 else
1501 return (STRING);
1502 }
1503
1504 #define START_EXPAND 1
1505 #define DONE_EXPAND 2
1506
1507 static int expanding;
1508
1509 int
igetc(void)1510 igetc(void)
1511 {
1512 int c;
1513
1514 while (1) {
1515 if (file->ungetpos > 0)
1516 c = file->ungetbuf[--file->ungetpos];
1517 else
1518 c = getc(file->stream);
1519
1520 if (c == START_EXPAND)
1521 expanding = 1;
1522 else if (c == DONE_EXPAND)
1523 expanding = 0;
1524 else
1525 break;
1526 }
1527 return (c);
1528 }
1529
1530 int
lgetc(int quotec)1531 lgetc(int quotec)
1532 {
1533 int c, next;
1534
1535 if (quotec) {
1536 if ((c = igetc()) == EOF) {
1537 yyerror("reached end of file while parsing "
1538 "quoted string");
1539 if (file == topfile || popfile() == EOF)
1540 return (EOF);
1541 return (quotec);
1542 }
1543 return (c);
1544 }
1545
1546 while ((c = igetc()) == '\\') {
1547 next = igetc();
1548 if (next != '\n') {
1549 c = next;
1550 break;
1551 }
1552 yylval.lineno = file->lineno;
1553 file->lineno++;
1554 }
1555
1556 if (c == EOF) {
1557 /*
1558 * Fake EOL when hit EOF for the first time. This gets line
1559 * count right if last line in included file is syntactically
1560 * invalid and has no newline.
1561 */
1562 if (file->eof_reached == 0) {
1563 file->eof_reached = 1;
1564 return ('\n');
1565 }
1566 while (c == EOF) {
1567 if (file == topfile || popfile() == EOF)
1568 return (EOF);
1569 c = igetc();
1570 }
1571 }
1572 return (c);
1573 }
1574
1575 void
lungetc(int c)1576 lungetc(int c)
1577 {
1578 if (c == EOF)
1579 return;
1580
1581 if (file->ungetpos >= file->ungetsize) {
1582 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
1583 if (p == NULL)
1584 err(1, "%s", __func__);
1585 file->ungetbuf = p;
1586 file->ungetsize *= 2;
1587 }
1588 file->ungetbuf[file->ungetpos++] = c;
1589 }
1590
1591 int
findeol(void)1592 findeol(void)
1593 {
1594 int c;
1595
1596 /* skip to either EOF or the first real EOL */
1597 while (1) {
1598 c = lgetc(0);
1599 if (c == '\n') {
1600 file->lineno++;
1601 break;
1602 }
1603 if (c == EOF)
1604 break;
1605 }
1606 return (ERROR);
1607 }
1608
1609 int
yylex(void)1610 yylex(void)
1611 {
1612 char buf[8096];
1613 char *p, *val;
1614 int quotec, next, c;
1615 int token;
1616
1617 top:
1618 p = buf;
1619 while ((c = lgetc(0)) == ' ' || c == '\t')
1620 ; /* nothing */
1621
1622 yylval.lineno = file->lineno;
1623 if (c == '#')
1624 while ((c = lgetc(0)) != '\n' && c != EOF)
1625 ; /* nothing */
1626 if (c == '$' && !expanding) {
1627 while (1) {
1628 if ((c = lgetc(0)) == EOF)
1629 return (0);
1630
1631 if (p + 1 >= buf + sizeof(buf) - 1) {
1632 yyerror("string too long");
1633 return (findeol());
1634 }
1635 if (isalnum(c) || c == '_') {
1636 *p++ = c;
1637 continue;
1638 }
1639 *p = '\0';
1640 lungetc(c);
1641 break;
1642 }
1643 val = symget(buf);
1644 if (val == NULL) {
1645 yyerror("macro '%s' not defined", buf);
1646 return (findeol());
1647 }
1648 p = val + strlen(val) - 1;
1649 lungetc(DONE_EXPAND);
1650 while (p >= val) {
1651 lungetc((unsigned char)*p);
1652 p--;
1653 }
1654 lungetc(START_EXPAND);
1655 goto top;
1656 }
1657
1658 switch (c) {
1659 case '\'':
1660 case '"':
1661 quotec = c;
1662 while (1) {
1663 if ((c = lgetc(quotec)) == EOF)
1664 return (0);
1665 if (c == '\n') {
1666 file->lineno++;
1667 continue;
1668 } else if (c == '\\') {
1669 if ((next = lgetc(quotec)) == EOF)
1670 return (0);
1671 if (next == quotec || next == ' ' ||
1672 next == '\t')
1673 c = next;
1674 else if (next == '\n') {
1675 file->lineno++;
1676 continue;
1677 } else
1678 lungetc(next);
1679 } else if (c == quotec) {
1680 *p = '\0';
1681 break;
1682 } else if (c == '\0') {
1683 yyerror("syntax error");
1684 return (findeol());
1685 }
1686 if (p + 1 >= buf + sizeof(buf) - 1) {
1687 yyerror("string too long");
1688 return (findeol());
1689 }
1690 *p++ = c;
1691 }
1692 yylval.v.string = strdup(buf);
1693 if (yylval.v.string == NULL)
1694 err(1, "%s", __func__);
1695 return (STRING);
1696 }
1697
1698 #define allowed_to_end_number(x) \
1699 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
1700
1701 if (c == '-' || isdigit(c)) {
1702 do {
1703 *p++ = c;
1704 if ((size_t)(p-buf) >= sizeof(buf)) {
1705 yyerror("string too long");
1706 return (findeol());
1707 }
1708 } while ((c = lgetc(0)) != EOF && isdigit(c));
1709 lungetc(c);
1710 if (p == buf + 1 && buf[0] == '-')
1711 goto nodigits;
1712 if (c == EOF || allowed_to_end_number(c)) {
1713 const char *errstr = NULL;
1714
1715 *p = '\0';
1716 yylval.v.number = strtonum(buf, LLONG_MIN,
1717 LLONG_MAX, &errstr);
1718 if (errstr) {
1719 yyerror("\"%s\" invalid number: %s",
1720 buf, errstr);
1721 return (findeol());
1722 }
1723 return (NUMBER);
1724 } else {
1725 nodigits:
1726 while (p > buf + 1)
1727 lungetc((unsigned char)*--p);
1728 c = (unsigned char)*--p;
1729 if (c == '-')
1730 return (c);
1731 }
1732 }
1733
1734 #define allowed_in_string(x) \
1735 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
1736 x != '{' && x != '}' && x != '<' && x != '>' && \
1737 x != '!' && x != '=' && x != '#' && \
1738 x != ',' && x != ';' && x != '/'))
1739
1740 if (isalnum(c) || c == ':' || c == '_' || c == '*') {
1741 do {
1742 *p++ = c;
1743 if ((size_t)(p-buf) >= sizeof(buf)) {
1744 yyerror("string too long");
1745 return (findeol());
1746 }
1747 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
1748 lungetc(c);
1749 *p = '\0';
1750 if ((token = lookup(buf)) == STRING)
1751 if ((yylval.v.string = strdup(buf)) == NULL)
1752 err(1, "%s", __func__);
1753 return (token);
1754 }
1755 if (c == '\n') {
1756 yylval.lineno = file->lineno;
1757 file->lineno++;
1758 }
1759 if (c == EOF)
1760 return (0);
1761 return (c);
1762 }
1763
1764 int
check_file_secrecy(int fd,const char * fname)1765 check_file_secrecy(int fd, const char *fname)
1766 {
1767 struct stat st;
1768
1769 if (fstat(fd, &st)) {
1770 log_warn("cannot stat %s", fname);
1771 return (-1);
1772 }
1773 if (st.st_uid != 0 && st.st_uid != getuid()) {
1774 log_warnx("%s: owner not root or current user", fname);
1775 return (-1);
1776 }
1777 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
1778 log_warnx("%s: group writable or world read/writable", fname);
1779 return (-1);
1780 }
1781 return (0);
1782 }
1783
1784 struct file *
pushfile(const char * name,int secret)1785 pushfile(const char *name, int secret)
1786 {
1787 struct file *nfile;
1788
1789 if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
1790 log_warn("%s", __func__);
1791 return (NULL);
1792 }
1793 if ((nfile->name = strdup(name)) == NULL) {
1794 log_warn("%s", __func__);
1795 free(nfile);
1796 return (NULL);
1797 }
1798 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
1799 log_warn("%s: %s", __func__, nfile->name);
1800 free(nfile->name);
1801 free(nfile);
1802 return (NULL);
1803 } else if (secret &&
1804 check_file_secrecy(fileno(nfile->stream), nfile->name)) {
1805 fclose(nfile->stream);
1806 free(nfile->name);
1807 free(nfile);
1808 return (NULL);
1809 }
1810 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
1811 nfile->ungetsize = 16;
1812 nfile->ungetbuf = malloc(nfile->ungetsize);
1813 if (nfile->ungetbuf == NULL) {
1814 log_warn("%s", __func__);
1815 fclose(nfile->stream);
1816 free(nfile->name);
1817 free(nfile);
1818 return (NULL);
1819 }
1820 TAILQ_INSERT_TAIL(&files, nfile, entry);
1821 return (nfile);
1822 }
1823
1824 int
popfile(void)1825 popfile(void)
1826 {
1827 struct file *prev;
1828
1829 if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
1830 prev->errors += file->errors;
1831
1832 TAILQ_REMOVE(&files, file, entry);
1833 fclose(file->stream);
1834 free(file->name);
1835 free(file->ungetbuf);
1836 free(file);
1837 file = prev;
1838 return (file ? 0 : EOF);
1839 }
1840
1841 int
parse_config(const char * filename,struct httpd * x_conf)1842 parse_config(const char *filename, struct httpd *x_conf)
1843 {
1844 struct sym *sym, *next;
1845 struct media_type dflt = HTTPD_DEFAULT_TYPE;
1846
1847 conf = x_conf;
1848 if (config_init(conf) == -1) {
1849 log_warn("%s: cannot initialize configuration", __func__);
1850 return (-1);
1851 }
1852
1853 /* Set default media type */
1854 memcpy(&conf->sc_default_type, &dflt, sizeof(struct media_type));
1855
1856 errors = 0;
1857
1858 if ((file = pushfile(filename, 0)) == NULL)
1859 return (-1);
1860
1861 topfile = file;
1862 setservent(1);
1863
1864 yyparse();
1865 errors = file->errors;
1866 while (popfile() != EOF)
1867 ;
1868
1869 endservent();
1870 endprotoent();
1871
1872 /* Free macros */
1873 TAILQ_FOREACH_MUTABLE(sym, &symhead, entry, next) {
1874 if (!sym->persist) {
1875 free(sym->nam);
1876 free(sym->val);
1877 TAILQ_REMOVE(&symhead, sym, entry);
1878 free(sym);
1879 }
1880 }
1881
1882 return (errors ? -1 : 0);
1883 }
1884
1885 int
load_config(const char * filename,struct httpd * x_conf)1886 load_config(const char *filename, struct httpd *x_conf)
1887 {
1888 struct sym *sym, *next;
1889 struct http_mediatype mediatypes[] = MEDIA_TYPES;
1890 struct media_type m;
1891 int i;
1892
1893 conf = x_conf;
1894 conf->sc_flags = 0;
1895
1896 loadcfg = 1;
1897 errors = 0;
1898 last_server_id = 0;
1899 last_auth_id = 0;
1900
1901 srv = NULL;
1902
1903 if ((file = pushfile(filename, 0)) == NULL)
1904 return (-1);
1905
1906 topfile = file;
1907 setservent(1);
1908
1909 yyparse();
1910 errors = file->errors;
1911 popfile();
1912
1913 endservent();
1914 endprotoent();
1915
1916 /* Free macros and check which have not been used. */
1917 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
1918 next = TAILQ_NEXT(sym, entry);
1919 if ((conf->sc_opts & HTTPD_OPT_VERBOSE) && !sym->used)
1920 fprintf(stderr, "warning: macro '%s' not "
1921 "used\n", sym->nam);
1922 if (!sym->persist) {
1923 free(sym->nam);
1924 free(sym->val);
1925 TAILQ_REMOVE(&symhead, sym, entry);
1926 free(sym);
1927 }
1928 }
1929
1930 if (TAILQ_EMPTY(conf->sc_servers)) {
1931 log_warnx("no actions, nothing to do");
1932 errors++;
1933 }
1934
1935 if (RB_EMPTY(conf->sc_mediatypes)) {
1936 /* Add default media types */
1937 for (i = 0; mediatypes[i].media_name != NULL; i++) {
1938 (void)strlcpy(m.media_name, mediatypes[i].media_name,
1939 sizeof(m.media_name));
1940 (void)strlcpy(m.media_type, mediatypes[i].media_type,
1941 sizeof(m.media_type));
1942 (void)strlcpy(m.media_subtype,
1943 mediatypes[i].media_subtype,
1944 sizeof(m.media_subtype));
1945 m.media_encoding = NULL;
1946
1947 if (media_add(conf->sc_mediatypes, &m) == NULL) {
1948 log_warnx("failed to add default media \"%s\"",
1949 m.media_name);
1950 errors++;
1951 }
1952 }
1953 }
1954
1955 return (errors ? -1 : 0);
1956 }
1957
1958 int
symset(const char * nam,const char * val,int persist)1959 symset(const char *nam, const char *val, int persist)
1960 {
1961 struct sym *sym;
1962
1963 TAILQ_FOREACH(sym, &symhead, entry) {
1964 if (strcmp(nam, sym->nam) == 0)
1965 break;
1966 }
1967
1968 if (sym != NULL) {
1969 if (sym->persist == 1)
1970 return (0);
1971 else {
1972 free(sym->nam);
1973 free(sym->val);
1974 TAILQ_REMOVE(&symhead, sym, entry);
1975 free(sym);
1976 }
1977 }
1978 if ((sym = calloc(1, sizeof(*sym))) == NULL)
1979 return (-1);
1980
1981 sym->nam = strdup(nam);
1982 if (sym->nam == NULL) {
1983 free(sym);
1984 return (-1);
1985 }
1986 sym->val = strdup(val);
1987 if (sym->val == NULL) {
1988 free(sym->nam);
1989 free(sym);
1990 return (-1);
1991 }
1992 sym->used = 0;
1993 sym->persist = persist;
1994 TAILQ_INSERT_TAIL(&symhead, sym, entry);
1995 return (0);
1996 }
1997
1998 int
cmdline_symset(char * s)1999 cmdline_symset(char *s)
2000 {
2001 char *sym, *val;
2002 int ret;
2003
2004 if ((val = strrchr(s, '=')) == NULL)
2005 return (-1);
2006 sym = strndup(s, val - s);
2007 if (sym == NULL)
2008 errx(1, "%s: strndup", __func__);
2009 ret = symset(sym, val + 1, 1);
2010 free(sym);
2011
2012 return (ret);
2013 }
2014
2015 char *
symget(const char * nam)2016 symget(const char *nam)
2017 {
2018 struct sym *sym;
2019
2020 TAILQ_FOREACH(sym, &symhead, entry) {
2021 if (strcmp(nam, sym->nam) == 0) {
2022 sym->used = 1;
2023 return (sym->val);
2024 }
2025 }
2026 return (NULL);
2027 }
2028
2029 struct address *
host_v4(const char * s)2030 host_v4(const char *s)
2031 {
2032 struct in_addr ina;
2033 struct sockaddr_in *sain;
2034 struct address *h;
2035
2036 memset(&ina, 0, sizeof(ina));
2037 if (inet_pton(AF_INET, s, &ina) != 1)
2038 return (NULL);
2039
2040 if ((h = calloc(1, sizeof(*h))) == NULL)
2041 fatal(__func__);
2042 sain = (struct sockaddr_in *)&h->ss;
2043 sain->sin_len = sizeof(struct sockaddr_in);
2044 sain->sin_family = AF_INET;
2045 sain->sin_addr.s_addr = ina.s_addr;
2046 if (sain->sin_addr.s_addr == INADDR_ANY)
2047 h->prefixlen = 0; /* 0.0.0.0 address */
2048 else
2049 h->prefixlen = -1; /* host address */
2050 return (h);
2051 }
2052
2053 struct address *
host_v6(const char * s)2054 host_v6(const char *s)
2055 {
2056 struct addrinfo hints, *res;
2057 struct sockaddr_in6 *sa_in6;
2058 struct address *h = NULL;
2059
2060 memset(&hints, 0, sizeof(hints));
2061 hints.ai_family = AF_INET6;
2062 hints.ai_socktype = SOCK_DGRAM; /* dummy */
2063 hints.ai_flags = AI_NUMERICHOST;
2064 if (getaddrinfo(s, "0", &hints, &res) == 0) {
2065 if ((h = calloc(1, sizeof(*h))) == NULL)
2066 fatal(__func__);
2067 sa_in6 = (struct sockaddr_in6 *)&h->ss;
2068 sa_in6->sin6_len = sizeof(struct sockaddr_in6);
2069 sa_in6->sin6_family = AF_INET6;
2070 memcpy(&sa_in6->sin6_addr,
2071 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
2072 sizeof(sa_in6->sin6_addr));
2073 sa_in6->sin6_scope_id =
2074 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
2075 if (memcmp(&sa_in6->sin6_addr, &in6addr_any,
2076 sizeof(sa_in6->sin6_addr)) == 0)
2077 h->prefixlen = 0; /* any address */
2078 else
2079 h->prefixlen = -1; /* host address */
2080 freeaddrinfo(res);
2081 }
2082
2083 return (h);
2084 }
2085
2086 int
host_dns(const char * s,struct addresslist * al,int max,struct portrange * port,const char * ifname,int ipproto)2087 host_dns(const char *s, struct addresslist *al, int max,
2088 struct portrange *port, const char *ifname, int ipproto)
2089 {
2090 struct addrinfo hints, *res0, *res;
2091 int error, cnt = 0;
2092 struct sockaddr_in *sain;
2093 struct sockaddr_in6 *sin6;
2094 struct address *h;
2095
2096 if ((cnt = host_if(s, al, max, port, ifname, ipproto)) != 0)
2097 return (cnt);
2098
2099 memset(&hints, 0, sizeof(hints));
2100 hints.ai_family = PF_UNSPEC;
2101 hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
2102 hints.ai_flags = AI_ADDRCONFIG;
2103 error = getaddrinfo(s, NULL, &hints, &res0);
2104 #ifdef __OpenBSD__
2105 if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
2106 #else
2107 if (error == EAI_AGAIN || error == EAI_NONAME)
2108 #endif
2109 return (0);
2110 if (error) {
2111 log_warnx("%s: could not parse \"%s\": %s", __func__, s,
2112 gai_strerror(error));
2113 return (-1);
2114 }
2115
2116 for (res = res0; res && cnt < max; res = res->ai_next) {
2117 if (res->ai_family != AF_INET &&
2118 res->ai_family != AF_INET6)
2119 continue;
2120 if ((h = calloc(1, sizeof(*h))) == NULL)
2121 fatal(__func__);
2122
2123 if (port != NULL)
2124 memcpy(&h->port, port, sizeof(h->port));
2125 if (ifname != NULL) {
2126 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
2127 sizeof(h->ifname))
2128 log_warnx("%s: interface name truncated",
2129 __func__);
2130 freeaddrinfo(res0);
2131 free(h);
2132 return (-1);
2133 }
2134 if (ipproto != -1)
2135 h->ipproto = ipproto;
2136 h->ss.ss_family = res->ai_family;
2137 h->prefixlen = -1; /* host address */
2138
2139 if (res->ai_family == AF_INET) {
2140 sain = (struct sockaddr_in *)&h->ss;
2141 sain->sin_len = sizeof(struct sockaddr_in);
2142 sain->sin_addr.s_addr = ((struct sockaddr_in *)
2143 res->ai_addr)->sin_addr.s_addr;
2144 } else {
2145 sin6 = (struct sockaddr_in6 *)&h->ss;
2146 sin6->sin6_len = sizeof(struct sockaddr_in6);
2147 memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
2148 res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
2149 }
2150
2151 TAILQ_INSERT_HEAD(al, h, entry);
2152 cnt++;
2153 }
2154 if (cnt == max && res) {
2155 log_warnx("%s: %s resolves to more than %d hosts", __func__,
2156 s, max);
2157 }
2158 freeaddrinfo(res0);
2159 return (cnt);
2160 }
2161
2162 int
host_if(const char * s,struct addresslist * al,int max,struct portrange * port,const char * ifname,int ipproto)2163 host_if(const char *s, struct addresslist *al, int max,
2164 struct portrange *port, const char *ifname, int ipproto)
2165 {
2166 struct ifaddrs *ifap, *p;
2167 struct sockaddr_in *sain;
2168 struct sockaddr_in6 *sin6;
2169 struct address *h;
2170 int cnt = 0, af;
2171
2172 if (getifaddrs(&ifap) == -1)
2173 fatal("getifaddrs");
2174
2175 /* First search for IPv4 addresses */
2176 af = AF_INET;
2177
2178 nextaf:
2179 for (p = ifap; p != NULL && cnt < max; p = p->ifa_next) {
2180 if (p->ifa_addr == NULL ||
2181 p->ifa_addr->sa_family != af ||
2182 (strcmp(s, p->ifa_name) != 0 &&
2183 !is_if_in_group(p->ifa_name, s)))
2184 continue;
2185 if ((h = calloc(1, sizeof(*h))) == NULL)
2186 fatal("calloc");
2187
2188 if (port != NULL)
2189 memcpy(&h->port, port, sizeof(h->port));
2190 if (ifname != NULL) {
2191 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
2192 sizeof(h->ifname))
2193 log_warnx("%s: interface name truncated",
2194 __func__);
2195 freeifaddrs(ifap);
2196 free(h);
2197 return (-1);
2198 }
2199 if (ipproto != -1)
2200 h->ipproto = ipproto;
2201 h->ss.ss_family = af;
2202 h->prefixlen = -1; /* host address */
2203
2204 if (af == AF_INET) {
2205 sain = (struct sockaddr_in *)&h->ss;
2206 sain->sin_len = sizeof(struct sockaddr_in);
2207 sain->sin_addr.s_addr = ((struct sockaddr_in *)
2208 p->ifa_addr)->sin_addr.s_addr;
2209 } else {
2210 sin6 = (struct sockaddr_in6 *)&h->ss;
2211 sin6->sin6_len = sizeof(struct sockaddr_in6);
2212 memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
2213 p->ifa_addr)->sin6_addr, sizeof(struct in6_addr));
2214 sin6->sin6_scope_id = ((struct sockaddr_in6 *)
2215 p->ifa_addr)->sin6_scope_id;
2216 }
2217
2218 TAILQ_INSERT_HEAD(al, h, entry);
2219 cnt++;
2220 }
2221 if (af == AF_INET) {
2222 /* Next search for IPv6 addresses */
2223 af = AF_INET6;
2224 goto nextaf;
2225 }
2226
2227 if (cnt > max) {
2228 log_warnx("%s: %s resolves to more than %d hosts", __func__,
2229 s, max);
2230 }
2231 freeifaddrs(ifap);
2232 return (cnt);
2233 }
2234
2235 int
host(const char * s,struct addresslist * al,int max,struct portrange * port,const char * ifname,int ipproto)2236 host(const char *s, struct addresslist *al, int max,
2237 struct portrange *port, const char *ifname, int ipproto)
2238 {
2239 struct address *h;
2240
2241 h = host_v4(s);
2242
2243 /* IPv6 address? */
2244 if (h == NULL)
2245 h = host_v6(s);
2246
2247 if (h != NULL) {
2248 if (port != NULL)
2249 memcpy(&h->port, port, sizeof(h->port));
2250 if (ifname != NULL) {
2251 if (strlcpy(h->ifname, ifname, sizeof(h->ifname)) >=
2252 sizeof(h->ifname)) {
2253 log_warnx("%s: interface name truncated",
2254 __func__);
2255 free(h);
2256 return (-1);
2257 }
2258 }
2259 if (ipproto != -1)
2260 h->ipproto = ipproto;
2261
2262 TAILQ_INSERT_HEAD(al, h, entry);
2263 return (1);
2264 }
2265
2266 return (host_dns(s, al, max, port, ifname, ipproto));
2267 }
2268
2269 struct server *
server_inherit(struct server * src,struct server_config * alias,struct server_config * addr)2270 server_inherit(struct server *src, struct server_config *alias,
2271 struct server_config *addr)
2272 {
2273 struct server *dst, *s, *dstl;
2274
2275 if ((dst = calloc(1, sizeof(*dst))) == NULL)
2276 fatal("out of memory");
2277
2278 /* Copy the source server and assign a new Id */
2279 memcpy(&dst->srv_conf, &src->srv_conf, sizeof(dst->srv_conf));
2280 if ((dst->srv_conf.tls_cert_file =
2281 strdup(src->srv_conf.tls_cert_file)) == NULL)
2282 fatal("out of memory");
2283 if ((dst->srv_conf.tls_key_file =
2284 strdup(src->srv_conf.tls_key_file)) == NULL)
2285 fatal("out of memory");
2286 if (src->srv_conf.tls_ocsp_staple_file != NULL) {
2287 if ((dst->srv_conf.tls_ocsp_staple_file =
2288 strdup(src->srv_conf.tls_ocsp_staple_file)) == NULL)
2289 fatal("out of memory");
2290 }
2291
2292 if (src->srv_conf.return_uri != NULL &&
2293 (dst->srv_conf.return_uri =
2294 strdup(src->srv_conf.return_uri)) == NULL)
2295 fatal("out of memory");
2296
2297 dst->srv_conf.id = ++last_server_id;
2298 dst->srv_conf.parent_id = dst->srv_conf.id;
2299 dst->srv_s = -1;
2300
2301 if (last_server_id == INT_MAX) {
2302 yyerror("too many servers defined");
2303 serverconfig_free(&dst->srv_conf);
2304 free(dst);
2305 return (NULL);
2306 }
2307
2308 /* Now set alias and listen address */
2309 strlcpy(dst->srv_conf.name, alias->name, sizeof(dst->srv_conf.name));
2310 memcpy(&dst->srv_conf.ss, &addr->ss, sizeof(dst->srv_conf.ss));
2311 dst->srv_conf.port = addr->port;
2312 dst->srv_conf.prefixlen = addr->prefixlen;
2313 if (addr->flags & SRVFLAG_TLS)
2314 dst->srv_conf.flags |= SRVFLAG_TLS;
2315 else
2316 dst->srv_conf.flags &= ~SRVFLAG_TLS;
2317
2318 /* Don't inherit the "match" option, use it from the alias */
2319 dst->srv_conf.flags &= ~SRVFLAG_SERVER_MATCH;
2320 dst->srv_conf.flags |= (alias->flags & SRVFLAG_SERVER_MATCH);
2321
2322 if (server_tls_load_keypair(dst) == -1)
2323 log_warnx("%s:%d: server \"%s\": failed to "
2324 "load public/private keys", file->name,
2325 yylval.lineno, dst->srv_conf.name);
2326
2327 if (server_tls_load_ca(dst) == -1) {
2328 yyerror("failed to load ca cert(s) for server %s",
2329 dst->srv_conf.name);
2330 serverconfig_free(&dst->srv_conf);
2331 return NULL;
2332 }
2333
2334 if (server_tls_load_crl(dst) == -1) {
2335 yyerror("failed to load crl(s) for server %s",
2336 dst->srv_conf.name);
2337 serverconfig_free(&dst->srv_conf);
2338 free(dst);
2339 return NULL;
2340 }
2341
2342 if (server_tls_load_ocsp(dst) == -1) {
2343 yyerror("failed to load ocsp staple "
2344 "for server %s", dst->srv_conf.name);
2345 serverconfig_free(&dst->srv_conf);
2346 free(dst);
2347 return (NULL);
2348 }
2349
2350 /* Check if the new server already exists */
2351 if (server_match(dst, 1) != NULL) {
2352 yyerror("server \"%s\" defined twice",
2353 dst->srv_conf.name);
2354 serverconfig_free(&dst->srv_conf);
2355 free(dst);
2356 return (NULL);
2357 }
2358
2359 /* Copy all the locations of the source server */
2360 TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
2361 if (!(s->srv_conf.flags & SRVFLAG_LOCATION &&
2362 s->srv_conf.parent_id == src->srv_conf.parent_id))
2363 continue;
2364
2365 if ((dstl = calloc(1, sizeof(*dstl))) == NULL)
2366 fatal("out of memory");
2367
2368 memcpy(&dstl->srv_conf, &s->srv_conf, sizeof(dstl->srv_conf));
2369 strlcpy(dstl->srv_conf.name, alias->name,
2370 sizeof(dstl->srv_conf.name));
2371
2372 /* Copy the new Id and listen address */
2373 dstl->srv_conf.id = ++last_server_id;
2374 dstl->srv_conf.parent_id = dst->srv_conf.id;
2375 memcpy(&dstl->srv_conf.ss, &addr->ss,
2376 sizeof(dstl->srv_conf.ss));
2377 dstl->srv_conf.port = addr->port;
2378 dstl->srv_conf.prefixlen = addr->prefixlen;
2379 dstl->srv_s = -1;
2380
2381 DPRINTF("adding location \"%s\" for \"%s[%u]\"",
2382 dstl->srv_conf.location,
2383 dstl->srv_conf.name, dstl->srv_conf.id);
2384
2385 TAILQ_INSERT_TAIL(conf->sc_servers, dstl, srv_entry);
2386 }
2387
2388 return (dst);
2389 }
2390
2391 int
listen_on(const char * addr,int tls,struct portrange * port)2392 listen_on(const char *addr, int tls, struct portrange *port)
2393 {
2394 struct addresslist al;
2395 struct address *h;
2396 struct server_config *s_conf, *alias = NULL;
2397
2398 if (parentsrv != NULL) {
2399 yyerror("listen %s inside location", addr);
2400 return (-1);
2401 }
2402
2403 TAILQ_INIT(&al);
2404 if (strcmp("*", addr) == 0) {
2405 if (host("0.0.0.0", &al, 1, port, NULL, -1) <= 0) {
2406 yyerror("invalid listen ip: %s",
2407 "0.0.0.0");
2408 return (-1);
2409 }
2410 if (host("::", &al, 1, port, NULL, -1) <= 0) {
2411 yyerror("invalid listen ip: %s", "::");
2412 return (-1);
2413 }
2414 } else {
2415 if (host(addr, &al, HTTPD_MAX_ALIAS_IP, port, NULL,
2416 -1) <= 0) {
2417 yyerror("invalid listen ip: %s", addr);
2418 return (-1);
2419 }
2420 }
2421
2422 while ((h = TAILQ_FIRST(&al)) != NULL) {
2423 if (srv->srv_conf.ss.ss_family != AF_UNSPEC) {
2424 if ((alias = calloc(1,
2425 sizeof(*alias))) == NULL)
2426 fatal("out of memory");
2427 /* Add as an IP-based alias. */
2428 s_conf = alias;
2429 } else
2430 s_conf = &srv->srv_conf;
2431 memcpy(&s_conf->ss, &h->ss, sizeof(s_conf->ss));
2432 s_conf->prefixlen = h->prefixlen;
2433 /* Set the default port to 80 or 443 */
2434 if (!h->port.op)
2435 s_conf->port = htons(tls ?
2436 HTTPS_PORT : HTTP_PORT);
2437 else
2438 s_conf->port = h->port.val[0];
2439
2440 if (tls)
2441 s_conf->flags |= SRVFLAG_TLS;
2442
2443 if (alias != NULL) {
2444 /*
2445 * IP-based; use name match flags from
2446 * parent
2447 */
2448 alias->flags &= ~SRVFLAG_SERVER_MATCH;
2449 alias->flags |= srv->srv_conf.flags &
2450 SRVFLAG_SERVER_MATCH;
2451 TAILQ_INSERT_TAIL(&srv->srv_hosts,
2452 alias, entry);
2453 }
2454 TAILQ_REMOVE(&al, h, entry);
2455 free(h);
2456 }
2457
2458 return (0);
2459 }
2460
2461 int
getservice(char * n)2462 getservice(char *n)
2463 {
2464 struct servent *s;
2465 const char *errstr;
2466 long long llval;
2467
2468 llval = strtonum(n, 0, UINT16_MAX, &errstr);
2469 if (errstr) {
2470 s = getservbyname(n, "tcp");
2471 if (s == NULL)
2472 s = getservbyname(n, "udp");
2473 if (s == NULL)
2474 return (-1);
2475 return (s->s_port);
2476 }
2477
2478 return (htons((unsigned short)llval));
2479 }
2480
2481 int
is_if_in_group(const char * ifname,const char * groupname)2482 is_if_in_group(const char *ifname, const char *groupname)
2483 {
2484 unsigned int len;
2485 struct ifgroupreq ifgr;
2486 struct ifg_req *ifg;
2487 int s;
2488 int ret = 0;
2489
2490 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
2491 err(1, "socket");
2492
2493 memset(&ifgr, 0, sizeof(ifgr));
2494 if (strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ) >= IFNAMSIZ)
2495 err(1, "IFNAMSIZ");
2496 if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
2497 if (errno == EINVAL || errno == ENOTTY)
2498 goto end;
2499 err(1, "SIOCGIFGROUP");
2500 }
2501
2502 len = ifgr.ifgr_len;
2503 ifgr.ifgr_groups = calloc(len / sizeof(struct ifg_req),
2504 sizeof(struct ifg_req));
2505 if (ifgr.ifgr_groups == NULL)
2506 err(1, "getifgroups");
2507 if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
2508 err(1, "SIOCGIFGROUP");
2509
2510 ifg = ifgr.ifgr_groups;
2511 for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
2512 len -= sizeof(struct ifg_req);
2513 if (strcmp(ifg->ifgrq_group, groupname) == 0) {
2514 ret = 1;
2515 break;
2516 }
2517 }
2518 free(ifgr.ifgr_groups);
2519
2520 end:
2521 close(s);
2522 return (ret);
2523 }
2524
2525 int
get_fastcgi_dest(struct server_config * xsrv_conf,const char * node,char * port)2526 get_fastcgi_dest(struct server_config *xsrv_conf, const char *node, char *port)
2527 {
2528 struct addrinfo hints, *res;
2529 int s;
2530
2531 memset(&hints, 0, sizeof(hints));
2532 hints.ai_family = AF_UNSPEC;
2533 hints.ai_socktype = SOCK_STREAM;
2534
2535 if ((s = getaddrinfo(node, port, &hints, &res)) != 0) {
2536 yyerror("getaddrinfo: %s\n", gai_strerror(s));
2537 return -1;
2538 }
2539
2540 memset(&(xsrv_conf)->fastcgi_ss, 0, sizeof(xsrv_conf->fastcgi_ss));
2541 memcpy(&(xsrv_conf)->fastcgi_ss, res->ai_addr, res->ai_addrlen);
2542
2543 freeaddrinfo(res);
2544
2545 return (0);
2546 }
2547
2548 void
remove_locations(struct server_config * xsrv_conf)2549 remove_locations(struct server_config *xsrv_conf)
2550 {
2551 struct server *s, *next;
2552
2553 TAILQ_FOREACH_MUTABLE(s, conf->sc_servers, srv_entry, next) {
2554 if (!(s->srv_conf.flags & SRVFLAG_LOCATION &&
2555 s->srv_conf.parent_id == xsrv_conf->parent_id))
2556 continue;
2557 TAILQ_REMOVE(conf->sc_servers, s, srv_entry);
2558 serverconfig_free(&s->srv_conf);
2559 free(s);
2560 }
2561 }
2562