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