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