File: | src/usr.sbin/httpd/config.c |
Warning: | line 488, column 3 Value stored to 's' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: config.c,v 1.62 2021/10/24 16:01:04 ian Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2011 - 2015 Reyk Floeter <reyk@openbsd.org> |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include <sys/types.h> |
20 | #include <sys/queue.h> |
21 | #include <sys/socket.h> |
22 | #include <sys/un.h> |
23 | #include <sys/tree.h> |
24 | #include <sys/time.h> |
25 | #include <sys/uio.h> |
26 | |
27 | #include <unistd.h> |
28 | #include <stdlib.h> |
29 | #include <stdio.h> |
30 | #include <string.h> |
31 | #include <imsg.h> |
32 | |
33 | #include "httpd.h" |
34 | |
35 | int config_getserver_config(struct httpd *, struct server *, |
36 | struct imsg *); |
37 | int config_getserver_auth(struct httpd *, struct server_config *); |
38 | |
39 | int |
40 | config_init(struct httpd *env) |
41 | { |
42 | struct privsep *ps = env->sc_ps; |
43 | unsigned int what; |
44 | |
45 | /* Global configuration */ |
46 | if (privsep_process == PROC_PARENT) |
47 | env->sc_prefork_server = SERVER_NUMPROC3; |
48 | |
49 | ps->ps_what[PROC_PARENT] = CONFIG_ALL0xff; |
50 | ps->ps_what[PROC_SERVER] = |
51 | CONFIG_SERVERS0x02|CONFIG_MEDIA0x01|CONFIG_AUTH0x04; |
52 | ps->ps_what[PROC_LOGGER] = CONFIG_SERVERS0x02; |
53 | |
54 | (void)strlcpy(env->sc_errdocroot, "", |
55 | sizeof(env->sc_errdocroot)); |
56 | |
57 | /* Other configuration */ |
58 | what = ps->ps_what[privsep_process]; |
59 | |
60 | if (what & CONFIG_SERVERS0x02) { |
61 | if ((env->sc_servers = |
62 | calloc(1, sizeof(*env->sc_servers))) == NULL((void*)0)) |
63 | return (-1); |
64 | TAILQ_INIT(env->sc_servers)do { (env->sc_servers)->tqh_first = ((void*)0); (env-> sc_servers)->tqh_last = &(env->sc_servers)->tqh_first ; } while (0); |
65 | } |
66 | |
67 | if (what & CONFIG_MEDIA0x01) { |
68 | if ((env->sc_mediatypes = |
69 | calloc(1, sizeof(*env->sc_mediatypes))) == NULL((void*)0)) |
70 | return (-1); |
71 | RB_INIT(env->sc_mediatypes)do { (env->sc_mediatypes)->rbh_root = ((void*)0); } while (0); |
72 | } |
73 | |
74 | if (what & CONFIG_AUTH0x04) { |
75 | if ((env->sc_auth = |
76 | calloc(1, sizeof(*env->sc_auth))) == NULL((void*)0)) |
77 | return (-1); |
78 | TAILQ_INIT(env->sc_auth)do { (env->sc_auth)->tqh_first = ((void*)0); (env->sc_auth )->tqh_last = &(env->sc_auth)->tqh_first; } while (0); |
79 | } |
80 | |
81 | return (0); |
82 | } |
83 | |
84 | void |
85 | config_purge(struct httpd *env, unsigned int reset) |
86 | { |
87 | struct privsep *ps = env->sc_ps; |
88 | struct server *srv; |
89 | struct auth *auth; |
90 | unsigned int what; |
91 | |
92 | what = ps->ps_what[privsep_process] & reset; |
93 | |
94 | if (what & CONFIG_SERVERS0x02 && env->sc_servers != NULL((void*)0)) { |
95 | while ((srv = TAILQ_FIRST(env->sc_servers)((env->sc_servers)->tqh_first)) != NULL((void*)0)) |
96 | server_purge(srv); |
97 | } |
98 | |
99 | if (what & CONFIG_MEDIA0x01 && env->sc_mediatypes != NULL((void*)0)) |
100 | media_purge(env->sc_mediatypes); |
101 | |
102 | if (what & CONFIG_AUTH0x04 && env->sc_auth != NULL((void*)0)) { |
103 | while ((auth = TAILQ_FIRST(env->sc_auth)((env->sc_auth)->tqh_first)) != NULL((void*)0)) { |
104 | auth_free(env->sc_auth, auth); |
105 | free(auth); |
106 | } |
107 | } |
108 | } |
109 | |
110 | int |
111 | config_setreset(struct httpd *env, unsigned int reset) |
112 | { |
113 | struct privsep *ps = env->sc_ps; |
114 | int id; |
115 | |
116 | for (id = 0; id < PROC_MAX; id++) { |
117 | if ((reset & ps->ps_what[id]) == 0 || |
118 | id == privsep_process) |
119 | continue; |
120 | proc_compose(ps, id, IMSG_CTL_RESET, |
121 | &reset, sizeof(reset)); |
122 | } |
123 | |
124 | return (0); |
125 | } |
126 | |
127 | int |
128 | config_getreset(struct httpd *env, struct imsg *imsg) |
129 | { |
130 | unsigned int mode; |
131 | |
132 | IMSG_SIZE_CHECK(imsg, &mode)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&mode)) fatalx("bad length imsg received"); } while (0); |
133 | memcpy(&mode, imsg->data, sizeof(mode)); |
134 | |
135 | config_purge(env, mode); |
136 | |
137 | return (0); |
138 | } |
139 | |
140 | int |
141 | config_getcfg(struct httpd *env, struct imsg *imsg) |
142 | { |
143 | struct ctl_flags cf; |
144 | |
145 | if (IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) != sizeof(cf)) |
146 | return (0); /* ignore */ |
147 | |
148 | /* Update runtime flags */ |
149 | memcpy(&cf, imsg->data, sizeof(cf)); |
150 | env->sc_opts = cf.cf_opts; |
151 | env->sc_flags = cf.cf_flags; |
152 | memcpy(env->sc_tls_sid, cf.cf_tls_sid, sizeof(env->sc_tls_sid)); |
153 | |
154 | if (privsep_process != PROC_PARENT) |
155 | proc_compose(env->sc_ps, PROC_PARENT, |
156 | IMSG_CFG_DONE, NULL((void*)0), 0); |
157 | |
158 | return (0); |
159 | } |
160 | |
161 | int |
162 | config_setserver(struct httpd *env, struct server *srv) |
163 | { |
164 | struct privsep *ps = env->sc_ps; |
165 | struct server_config s; |
166 | int id; |
167 | int fd, n, m; |
168 | struct iovec iov[6]; |
169 | size_t c; |
170 | unsigned int what; |
171 | |
172 | /* opens listening sockets etc. */ |
173 | if (server_privinit(srv) == -1) |
174 | return (-1); |
175 | |
176 | for (id = 0; id < PROC_MAX; id++) { |
177 | what = ps->ps_what[id]; |
178 | |
179 | if ((what & CONFIG_SERVERS0x02) == 0 || id == privsep_process) |
180 | continue; |
181 | |
182 | DPRINTF("%s: sending %s \"%s[%u]\" to %s fd %d", __func__,do {} while(0) |
183 | (srv->srv_conf.flags & SRVFLAG_LOCATION) ?do {} while(0) |
184 | "location" : "server",do {} while(0) |
185 | srv->srv_conf.name, srv->srv_conf.id,do {} while(0) |
186 | ps->ps_title[id], srv->srv_s)do {} while(0); |
187 | |
188 | memcpy(&s, &srv->srv_conf, sizeof(s)); |
189 | |
190 | c = 0; |
191 | iov[c].iov_base = &s; |
192 | iov[c++].iov_len = sizeof(s); |
193 | if (srv->srv_conf.return_uri_len != 0) { |
194 | iov[c].iov_base = srv->srv_conf.return_uri; |
195 | iov[c++].iov_len = srv->srv_conf.return_uri_len; |
196 | } |
197 | |
198 | if (id == PROC_SERVER && |
199 | (srv->srv_conf.flags & SRVFLAG_LOCATION0x00000020) == 0) { |
200 | /* XXX imsg code will close the fd after 1st call */ |
201 | n = -1; |
202 | proc_range(ps, id, &n, &m); |
203 | for (n = 0; n < m; n++) { |
204 | if (srv->srv_s == -1) |
205 | fd = -1; |
206 | else if ((fd = dup(srv->srv_s)) == -1) |
207 | return (-1); |
208 | if (proc_composev_imsg(ps, id, n, |
209 | IMSG_CFG_SERVER, -1, fd, iov, c) != 0) { |
210 | log_warn("%s: failed to compose " |
211 | "IMSG_CFG_SERVER imsg for `%s'", |
212 | __func__, srv->srv_conf.name); |
213 | return (-1); |
214 | } |
215 | |
216 | /* Prevent fd exhaustion in the parent. */ |
217 | if (proc_flush_imsg(ps, id, n) == -1) { |
218 | log_warn("%s: failed to flush " |
219 | "IMSG_CFG_SERVER imsg for `%s'", |
220 | __func__, srv->srv_conf.name); |
221 | return (-1); |
222 | } |
223 | } |
224 | |
225 | /* Configure TLS if necessary. */ |
226 | config_setserver_tls(env, srv); |
227 | } else { |
228 | if (proc_composev(ps, id, IMSG_CFG_SERVER, |
229 | iov, c) != 0) { |
230 | log_warn("%s: failed to compose " |
231 | "IMSG_CFG_SERVER imsg for `%s'", |
232 | __func__, srv->srv_conf.name); |
233 | return (-1); |
234 | } |
235 | |
236 | /* Configure FCGI parmeters if necessary. */ |
237 | config_setserver_fcgiparams(env, srv); |
238 | } |
239 | } |
240 | |
241 | /* Close server socket early to prevent fd exhaustion in the parent. */ |
242 | if (srv->srv_s != -1) { |
243 | close(srv->srv_s); |
244 | srv->srv_s = -1; |
245 | } |
246 | |
247 | explicit_bzero(&srv->srv_conf.tls_ticket_key, |
248 | sizeof(srv->srv_conf.tls_ticket_key)); |
249 | |
250 | return (0); |
251 | } |
252 | |
253 | static int |
254 | config_settls(struct httpd *env, struct server *srv, enum tls_config_type type, |
255 | const char *label, uint8_t *data, size_t len) |
256 | { |
257 | struct privsep *ps = env->sc_ps; |
258 | struct server_config *srv_conf = &srv->srv_conf; |
259 | struct tls_config tls; |
260 | struct iovec iov[2]; |
261 | size_t c; |
262 | |
263 | if (data == NULL((void*)0) || len == 0) |
264 | return (0); |
265 | |
266 | DPRINTF("%s: sending tls %s for \"%s[%u]\" to %s fd %d", __func__,do {} while(0) |
267 | label, srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER],do {} while(0) |
268 | srv->srv_s)do {} while(0); |
269 | |
270 | memset(&tls, 0, sizeof(tls)); |
271 | tls.id = srv_conf->id; |
272 | tls.tls_type = type; |
273 | tls.tls_len = len; |
274 | tls.tls_chunk_offset = 0; |
275 | |
276 | while (len > 0) { |
277 | tls.tls_chunk_len = len; |
278 | if (tls.tls_chunk_len > (MAX_IMSG_DATA_SIZE(16384 - sizeof(struct imsg_hdr)) - sizeof(tls))) |
279 | tls.tls_chunk_len = MAX_IMSG_DATA_SIZE(16384 - sizeof(struct imsg_hdr)) - sizeof(tls); |
280 | |
281 | c = 0; |
282 | iov[c].iov_base = &tls; |
283 | iov[c++].iov_len = sizeof(tls); |
284 | iov[c].iov_base = data; |
285 | iov[c++].iov_len = tls.tls_chunk_len; |
286 | |
287 | if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) { |
288 | log_warn("%s: failed to compose IMSG_CFG_TLS imsg for " |
289 | "`%s'", __func__, srv_conf->name); |
290 | return (-1); |
291 | } |
292 | |
293 | tls.tls_chunk_offset += tls.tls_chunk_len; |
294 | data += tls.tls_chunk_len; |
295 | len -= tls.tls_chunk_len; |
296 | } |
297 | |
298 | return (0); |
299 | } |
300 | |
301 | int |
302 | config_getserver_fcgiparams(struct httpd *env, struct imsg *imsg) |
303 | { |
304 | struct server *srv; |
305 | struct server_config *srv_conf, *iconf; |
306 | struct fastcgi_param *fp; |
307 | uint32_t id; |
308 | size_t c, nc, len; |
309 | uint8_t *p = imsg->data; |
310 | |
311 | len = sizeof(nc) + sizeof(id); |
312 | if (IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) < len) { |
313 | log_debug("%s: invalid message length", __func__); |
314 | return (-1); |
315 | } |
316 | |
317 | memcpy(&nc, p, sizeof(nc)); /* number of params */ |
318 | p += sizeof(nc); |
319 | |
320 | memcpy(&id, p, sizeof(id)); /* server conf id */ |
321 | srv_conf = serverconfig_byid(id); |
322 | p += sizeof(id); |
323 | |
324 | len += nc*sizeof(*fp); |
325 | if (IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) < len) { |
326 | log_debug("%s: invalid message length", __func__); |
327 | return (-1); |
328 | } |
329 | |
330 | /* Find associated server config */ |
331 | TAILQ_FOREACH(srv, env->sc_servers, srv_entry)for((srv) = ((env->sc_servers)->tqh_first); (srv) != (( void*)0); (srv) = ((srv)->srv_entry.tqe_next)) { |
332 | if (srv->srv_conf.id == id) { |
333 | srv_conf = &srv->srv_conf; |
334 | break; |
335 | } |
336 | TAILQ_FOREACH(iconf, &srv->srv_hosts, entry)for((iconf) = ((&srv->srv_hosts)->tqh_first); (iconf ) != ((void*)0); (iconf) = ((iconf)->entry.tqe_next)) { |
337 | if (iconf->id == id) { |
338 | srv_conf = iconf; |
339 | break; |
340 | } |
341 | } |
342 | } |
343 | |
344 | /* Fetch FCGI parameters */ |
345 | for (c = 0; c < nc; c++) { |
346 | if ((fp = calloc(1, sizeof(*fp))) == NULL((void*)0)) |
347 | fatalx("fcgiparams out of memory"); |
348 | memcpy(fp, p, sizeof(*fp)); |
349 | TAILQ_INSERT_HEAD(&srv_conf->fcgiparams, fp, entry)do { if (((fp)->entry.tqe_next = (&srv_conf->fcgiparams )->tqh_first) != ((void*)0)) (&srv_conf->fcgiparams )->tqh_first->entry.tqe_prev = &(fp)->entry.tqe_next ; else (&srv_conf->fcgiparams)->tqh_last = &(fp )->entry.tqe_next; (&srv_conf->fcgiparams)->tqh_first = (fp); (fp)->entry.tqe_prev = &(&srv_conf->fcgiparams )->tqh_first; } while (0); |
350 | |
351 | p += sizeof(*fp); |
352 | } |
353 | |
354 | return (0); |
355 | } |
356 | |
357 | int |
358 | config_setserver_fcgiparams(struct httpd *env, struct server *srv) |
359 | { |
360 | struct privsep *ps = env->sc_ps; |
361 | struct server_config *srv_conf = &srv->srv_conf; |
362 | struct fastcgi_param *fp; |
363 | struct iovec *iov; |
364 | size_t c = 0, nc = 0; |
365 | |
366 | DPRINTF("%s: sending fcgiparam for \"%s[%u]\" to %s fd %d", __func__,do {} while(0) |
367 | srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER],do {} while(0) |
368 | srv->srv_s)do {} while(0); |
369 | |
370 | if (TAILQ_EMPTY(&srv_conf->fcgiparams)(((&srv_conf->fcgiparams)->tqh_first) == ((void*)0) )) /* nothing to do */ |
371 | return (0); |
372 | |
373 | TAILQ_FOREACH(fp, &srv_conf->fcgiparams, entry)for((fp) = ((&srv_conf->fcgiparams)->tqh_first); (fp ) != ((void*)0); (fp) = ((fp)->entry.tqe_next)) { |
374 | nc++; |
375 | } |
376 | if ((iov = calloc(nc + 2, sizeof(*iov))) == NULL((void*)0)) |
377 | return (-1); |
378 | |
379 | iov[c].iov_base = &nc; /* number of params */ |
380 | iov[c++].iov_len = sizeof(nc); |
381 | iov[c].iov_base = &srv_conf->id; /* server config id */ |
382 | iov[c++].iov_len = sizeof(srv_conf->id); |
383 | |
384 | TAILQ_FOREACH(fp, &srv_conf->fcgiparams, entry)for((fp) = ((&srv_conf->fcgiparams)->tqh_first); (fp ) != ((void*)0); (fp) = ((fp)->entry.tqe_next)) { /* push FCGI params */ |
385 | iov[c].iov_base = fp; |
386 | iov[c++].iov_len = sizeof(*fp); |
387 | } |
388 | if (proc_composev(ps, PROC_SERVER, IMSG_CFG_FCGI, iov, c) != 0) { |
389 | log_warn("%s: failed to compose IMSG_CFG_FCGI imsg for " |
390 | "`%s'", __func__, srv_conf->name); |
391 | free(iov); |
392 | return (-1); |
393 | } |
394 | free(iov); |
395 | |
396 | return (0); |
397 | } |
398 | |
399 | int |
400 | config_setserver_tls(struct httpd *env, struct server *srv) |
401 | { |
402 | struct server_config *srv_conf = &srv->srv_conf; |
403 | |
404 | if ((srv_conf->flags & SRVFLAG_TLS0x00002000) == 0) |
405 | return (0); |
406 | |
407 | log_debug("%s: configuring tls for %s", __func__, srv_conf->name); |
408 | |
409 | if (config_settls(env, srv, TLS_CFG_CA, "ca", srv_conf->tls_ca, |
410 | srv_conf->tls_ca_len) != 0) |
411 | return (-1); |
412 | |
413 | if (config_settls(env, srv, TLS_CFG_CERT, "cert", srv_conf->tls_cert, |
414 | srv_conf->tls_cert_len) != 0) |
415 | return (-1); |
416 | |
417 | if (config_settls(env, srv, TLS_CFG_CRL, "crl", srv_conf->tls_crl, |
418 | srv_conf->tls_crl_len) != 0) |
419 | return (-1); |
420 | |
421 | if (config_settls(env, srv, TLS_CFG_KEY, "key", srv_conf->tls_key, |
422 | srv_conf->tls_key_len) != 0) |
423 | return (-1); |
424 | |
425 | if (config_settls(env, srv, TLS_CFG_OCSP_STAPLE, "ocsp staple", |
426 | srv_conf->tls_ocsp_staple, srv_conf->tls_ocsp_staple_len) != 0) |
427 | return (-1); |
428 | |
429 | return (0); |
430 | } |
431 | |
432 | int |
433 | config_getserver_auth(struct httpd *env, struct server_config *srv_conf) |
434 | { |
435 | struct privsep *ps = env->sc_ps; |
436 | |
437 | if ((ps->ps_what[privsep_process] & CONFIG_AUTH0x04) == 0 || |
438 | (srv_conf->flags & SRVFLAG_AUTH0x00010000) == 0) |
439 | return (0); |
440 | |
441 | if ((srv_conf->auth = auth_byid(env->sc_auth, |
442 | srv_conf->auth_id)) == NULL((void*)0)) |
443 | return (-1); |
444 | |
445 | return (0); |
446 | } |
447 | |
448 | int |
449 | config_getserver_config(struct httpd *env, struct server *srv, |
450 | struct imsg *imsg) |
451 | { |
452 | #ifdef DEBUG |
453 | struct privsep *ps = env->sc_ps; |
454 | #endif |
455 | struct server_config *srv_conf, *parent; |
456 | uint8_t *p = imsg->data; |
457 | unsigned int f; |
458 | size_t s; |
459 | |
460 | if ((srv_conf = calloc(1, sizeof(*srv_conf))) == NULL((void*)0)) |
461 | return (-1); |
462 | |
463 | IMSG_SIZE_CHECK(imsg, srv_conf)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*srv_conf)) fatalx("bad length imsg received"); } while (0); |
464 | memcpy(srv_conf, p, sizeof(*srv_conf)); |
465 | s = sizeof(*srv_conf); |
466 | |
467 | /* Reset these variables to avoid free'ing invalid pointers */ |
468 | serverconfig_reset(srv_conf); |
469 | |
470 | TAILQ_FOREACH(parent, &srv->srv_hosts, entry)for((parent) = ((&srv->srv_hosts)->tqh_first); (parent ) != ((void*)0); (parent) = ((parent)->entry.tqe_next)) { |
471 | if (strcmp(parent->name, srv_conf->name) == 0) |
472 | break; |
473 | } |
474 | if (parent == NULL((void*)0)) |
475 | parent = &srv->srv_conf; |
476 | |
477 | if (config_getserver_auth(env, srv_conf) != 0) |
478 | goto fail; |
479 | |
480 | /* |
481 | * Get variable-length values for the virtual host. The tls_* ones |
482 | * aren't needed in the virtual hosts unless we implement SNI. |
483 | */ |
484 | if (srv_conf->return_uri_len != 0) { |
485 | if ((srv_conf->return_uri = get_data(p + s, |
486 | srv_conf->return_uri_len)) == NULL((void*)0)) |
487 | goto fail; |
488 | s += srv_conf->return_uri_len; |
Value stored to 's' is never read | |
489 | } |
490 | |
491 | if (srv_conf->flags & SRVFLAG_LOCATION0x00000020) { |
492 | /* Inherit configuration from the parent */ |
493 | f = SRVFLAG_INDEX0x00000001|SRVFLAG_NO_INDEX0x00000002; |
494 | if ((srv_conf->flags & f) == 0) { |
495 | srv_conf->flags |= parent->flags & f; |
496 | (void)strlcpy(srv_conf->index, parent->index, |
497 | sizeof(srv_conf->index)); |
498 | } |
499 | |
500 | f = SRVFLAG_AUTO_INDEX0x00000004|SRVFLAG_NO_AUTO_INDEX0x00000008; |
501 | if ((srv_conf->flags & f) == 0) |
502 | srv_conf->flags |= parent->flags & f; |
503 | |
504 | f = SRVFLAG_ROOT0x00000010; |
505 | if ((srv_conf->flags & f) == 0) { |
506 | srv_conf->flags |= parent->flags & f; |
507 | (void)strlcpy(srv_conf->root, parent->root, |
508 | sizeof(srv_conf->root)); |
509 | } |
510 | |
511 | f = SRVFLAG_FCGI0x00000040|SRVFLAG_NO_FCGI0x00000080; |
512 | if ((srv_conf->flags & f) == 0) |
513 | srv_conf->flags |= parent->flags & f; |
514 | |
515 | f = SRVFLAG_LOG0x00000100|SRVFLAG_NO_LOG0x00000200; |
516 | if ((srv_conf->flags & f) == 0) { |
517 | srv_conf->flags |= parent->flags & f; |
518 | srv_conf->logformat = parent->logformat; |
519 | } |
520 | |
521 | f = SRVFLAG_SYSLOG0x00000800|SRVFLAG_NO_SYSLOG0x00001000; |
522 | if ((srv_conf->flags & f) == 0) |
523 | srv_conf->flags |= parent->flags & f; |
524 | |
525 | f = SRVFLAG_AUTH0x00010000|SRVFLAG_NO_AUTH0x00020000; |
526 | if ((srv_conf->flags & f) == 0) { |
527 | srv_conf->flags |= parent->flags & f; |
528 | srv_conf->auth = parent->auth; |
529 | srv_conf->auth_id = parent->auth_id; |
530 | (void)strlcpy(srv_conf->auth_realm, |
531 | parent->auth_realm, |
532 | sizeof(srv_conf->auth_realm)); |
533 | } |
534 | |
535 | f = SRVFLAG_TLS0x00002000; |
536 | srv_conf->flags |= parent->flags & f; |
537 | srv_conf->tls_flags = parent->tls_flags; |
538 | |
539 | f = SRVFLAG_ACCESS_LOG0x00004000; |
540 | if ((srv_conf->flags & f) == 0) { |
541 | srv_conf->flags |= parent->flags & f; |
542 | (void)strlcpy(srv_conf->accesslog, |
543 | parent->accesslog, |
544 | sizeof(srv_conf->accesslog)); |
545 | } |
546 | |
547 | f = SRVFLAG_ERROR_LOG0x00008000; |
548 | if ((srv_conf->flags & f) == 0) { |
549 | srv_conf->flags |= parent->flags & f; |
550 | (void)strlcpy(srv_conf->errorlog, |
551 | parent->errorlog, |
552 | sizeof(srv_conf->errorlog)); |
553 | } |
554 | |
555 | f = SRVFLAG_BLOCK0x00040000|SRVFLAG_NO_BLOCK0x00080000; |
556 | if ((srv_conf->flags & f) == 0) { |
557 | free(srv_conf->return_uri); |
558 | srv_conf->flags |= parent->flags & f; |
559 | srv_conf->return_code = parent->return_code; |
560 | srv_conf->return_uri_len = parent->return_uri_len; |
561 | if (srv_conf->return_uri_len && |
562 | (srv_conf->return_uri = |
563 | strdup(parent->return_uri)) == NULL((void*)0)) |
564 | goto fail; |
565 | } |
566 | |
567 | f = SRVFLAG_DEFAULT_TYPE0x00800000; |
568 | if ((srv_conf->flags & f) == 0) { |
569 | srv_conf->flags |= parent->flags & f; |
570 | memcpy(&srv_conf->default_type, |
571 | &parent->default_type, sizeof(struct media_type)); |
572 | } |
573 | |
574 | f = SRVFLAG_PATH_REWRITE0x01000000|SRVFLAG_NO_PATH_REWRITE0x02000000; |
575 | if ((srv_conf->flags & f) == 0) { |
576 | srv_conf->flags |= parent->flags & f; |
577 | (void)strlcpy(srv_conf->path, parent->path, |
578 | sizeof(srv_conf->path)); |
579 | } |
580 | |
581 | f = SRVFLAG_SERVER_HSTS0x00400000; |
582 | srv_conf->flags |= parent->flags & f; |
583 | srv_conf->hsts_max_age = parent->hsts_max_age; |
584 | srv_conf->hsts_flags = parent->hsts_flags; |
585 | |
586 | memcpy(&srv_conf->timeout, &parent->timeout, |
587 | sizeof(srv_conf->timeout)); |
588 | srv_conf->maxrequests = parent->maxrequests; |
589 | srv_conf->maxrequestbody = parent->maxrequestbody; |
590 | |
591 | srv_conf->flags |= parent->flags & SRVFLAG_ERRDOCS0x00000400; |
592 | (void)strlcpy(srv_conf->errdocroot, parent->errdocroot, |
593 | sizeof(srv_conf->errdocroot)); |
594 | |
595 | DPRINTF("%s: %s %d location \"%s\", "do {} while(0) |
596 | "parent \"%s[%u]\", flags: %s",do {} while(0) |
597 | __func__, ps->ps_title[privsep_process], ps->ps_instance,do {} while(0) |
598 | srv_conf->location, parent->name, parent->id,do {} while(0) |
599 | printb_flags(srv_conf->flags, SRVFLAG_BITS))do {} while(0); |
600 | } else { |
601 | /* Add a new "virtual" server */ |
602 | DPRINTF("%s: %s %d server \"%s[%u]\", parent \"%s[%u]\", "do {} while(0) |
603 | "flags: %s", __func__,do {} while(0) |
604 | ps->ps_title[privsep_process], ps->ps_instance,do {} while(0) |
605 | srv_conf->name, srv_conf->id, parent->name, parent->id,do {} while(0) |
606 | printb_flags(srv_conf->flags, SRVFLAG_BITS))do {} while(0); |
607 | } |
608 | |
609 | TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry)do { (srv_conf)->entry.tqe_next = ((void*)0); (srv_conf)-> entry.tqe_prev = (&srv->srv_hosts)->tqh_last; *(& srv->srv_hosts)->tqh_last = (srv_conf); (&srv->srv_hosts )->tqh_last = &(srv_conf)->entry.tqe_next; } while ( 0); |
610 | |
611 | return (0); |
612 | |
613 | fail: |
614 | serverconfig_free(srv_conf); |
615 | free(srv_conf); |
616 | return (-1); |
617 | } |
618 | |
619 | int |
620 | config_getserver(struct httpd *env, struct imsg *imsg) |
621 | { |
622 | #ifdef DEBUG |
623 | struct privsep *ps = env->sc_ps; |
624 | #endif |
625 | struct server *srv = NULL((void*)0); |
626 | struct server_config srv_conf; |
627 | uint8_t *p = imsg->data; |
628 | size_t s; |
629 | |
630 | IMSG_SIZE_CHECK(imsg, &srv_conf)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&srv_conf)) fatalx("bad length imsg received"); } while (0); |
631 | memcpy(&srv_conf, p, sizeof(srv_conf)); |
632 | s = sizeof(srv_conf); |
633 | |
634 | /* Reset these variables to avoid free'ing invalid pointers */ |
635 | serverconfig_reset(&srv_conf); |
636 | |
637 | if ((IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) - s) < (size_t)srv_conf.return_uri_len) { |
638 | log_debug("%s: invalid message length", __func__); |
639 | goto fail; |
640 | } |
641 | |
642 | /* Check if server with matching listening socket already exists */ |
643 | if ((srv = server_byaddr((struct sockaddr *) |
644 | &srv_conf.ss, srv_conf.port)) != NULL((void*)0)) { |
645 | /* Add "host" to existing listening server */ |
646 | if (imsg->fd != -1) { |
647 | if (srv->srv_s == -1) |
648 | srv->srv_s = imsg->fd; |
649 | else |
650 | close(imsg->fd); |
651 | } |
652 | return (config_getserver_config(env, srv, imsg)); |
653 | } |
654 | |
655 | if (srv_conf.flags & SRVFLAG_LOCATION0x00000020) |
656 | fatalx("invalid location"); |
657 | |
658 | /* Otherwise create a new server */ |
659 | if ((srv = calloc(1, sizeof(*srv))) == NULL((void*)0)) |
660 | goto fail; |
661 | |
662 | memcpy(&srv->srv_conf, &srv_conf, sizeof(srv->srv_conf)); |
663 | srv->srv_s = imsg->fd; |
664 | |
665 | if (config_getserver_auth(env, &srv->srv_conf) != 0) |
666 | goto fail; |
667 | |
668 | SPLAY_INIT(&srv->srv_clients)do { (&srv->srv_clients)->sph_root = ((void*)0); } while (0); |
669 | TAILQ_INIT(&srv->srv_hosts)do { (&srv->srv_hosts)->tqh_first = ((void*)0); (& srv->srv_hosts)->tqh_last = &(&srv->srv_hosts )->tqh_first; } while (0); |
670 | |
671 | TAILQ_INSERT_TAIL(&srv->srv_hosts, &srv->srv_conf, entry)do { (&srv->srv_conf)->entry.tqe_next = ((void*)0); (&srv->srv_conf)->entry.tqe_prev = (&srv->srv_hosts )->tqh_last; *(&srv->srv_hosts)->tqh_last = (& srv->srv_conf); (&srv->srv_hosts)->tqh_last = & (&srv->srv_conf)->entry.tqe_next; } while (0); |
672 | TAILQ_INSERT_TAIL(env->sc_servers, srv, srv_entry)do { (srv)->srv_entry.tqe_next = ((void*)0); (srv)->srv_entry .tqe_prev = (env->sc_servers)->tqh_last; *(env->sc_servers )->tqh_last = (srv); (env->sc_servers)->tqh_last = & (srv)->srv_entry.tqe_next; } while (0); |
673 | |
674 | DPRINTF("%s: %s %d configuration \"%s[%u]\", flags: %s", __func__,do {} while(0) |
675 | ps->ps_title[privsep_process], ps->ps_instance,do {} while(0) |
676 | srv->srv_conf.name, srv->srv_conf.id,do {} while(0) |
677 | printb_flags(srv->srv_conf.flags, SRVFLAG_BITS))do {} while(0); |
678 | |
679 | /* |
680 | * Get all variable-length values for the parent server. |
681 | */ |
682 | if (srv->srv_conf.return_uri_len != 0) { |
683 | if ((srv->srv_conf.return_uri = get_data(p + s, |
684 | srv->srv_conf.return_uri_len)) == NULL((void*)0)) |
685 | goto fail; |
686 | } |
687 | |
688 | return (0); |
689 | |
690 | fail: |
691 | if (imsg->fd != -1) |
692 | close(imsg->fd); |
693 | if (srv != NULL((void*)0)) |
694 | serverconfig_free(&srv->srv_conf); |
695 | free(srv); |
696 | |
697 | return (-1); |
698 | } |
699 | |
700 | static int |
701 | config_gettls(struct httpd *env, struct server_config *srv_conf, |
702 | struct tls_config *tls_conf, const char *label, uint8_t *data, size_t len, |
703 | uint8_t **outdata, size_t *outlen) |
704 | { |
705 | #ifdef DEBUG |
706 | struct privsep *ps = env->sc_ps; |
707 | #endif |
708 | |
709 | DPRINTF("%s: %s %d getting tls %s (%zu:%zu@%zu) for \"%s[%u]\"",do {} while(0) |
710 | __func__, ps->ps_title[privsep_process], ps->ps_instance, label,do {} while(0) |
711 | tls_conf->tls_len, len, tls_conf->tls_chunk_offset, srv_conf->name,do {} while(0) |
712 | srv_conf->id)do {} while(0); |
713 | |
714 | if (tls_conf->tls_chunk_offset == 0) { |
715 | free(*outdata); |
716 | *outlen = 0; |
717 | if ((*outdata = calloc(1, tls_conf->tls_len)) == NULL((void*)0)) |
718 | goto fail; |
719 | *outlen = tls_conf->tls_len; |
720 | } |
721 | |
722 | if (*outdata == NULL((void*)0)) { |
723 | log_debug("%s: tls config invalid chunk sequence", __func__); |
724 | goto fail; |
725 | } |
726 | |
727 | if (*outlen != tls_conf->tls_len) { |
728 | log_debug("%s: tls config length mismatch (%zu != %zu)", |
729 | __func__, *outlen, tls_conf->tls_len); |
730 | goto fail; |
731 | } |
732 | |
733 | if (len > (tls_conf->tls_len - tls_conf->tls_chunk_offset)) { |
734 | log_debug("%s: tls config invalid chunk length", __func__); |
735 | goto fail; |
736 | } |
737 | |
738 | memcpy(*outdata + tls_conf->tls_chunk_offset, data, len); |
739 | |
740 | return (0); |
741 | |
742 | fail: |
743 | return (-1); |
744 | } |
745 | |
746 | int |
747 | config_getserver_tls(struct httpd *env, struct imsg *imsg) |
748 | { |
749 | struct server_config *srv_conf = NULL((void*)0); |
750 | struct tls_config tls_conf; |
751 | uint8_t *p = imsg->data; |
752 | size_t len; |
753 | |
754 | IMSG_SIZE_CHECK(imsg, &tls_conf)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&tls_conf)) fatalx("bad length imsg received"); } while (0); |
755 | memcpy(&tls_conf, p, sizeof(tls_conf)); |
756 | |
757 | len = tls_conf.tls_chunk_len; |
758 | |
759 | if ((IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) - sizeof(tls_conf)) < len) { |
760 | log_debug("%s: invalid message length", __func__); |
761 | goto fail; |
762 | } |
763 | |
764 | p += sizeof(tls_conf); |
765 | |
766 | if ((srv_conf = serverconfig_byid(tls_conf.id)) == NULL((void*)0)) { |
767 | log_debug("%s: server not found", __func__); |
768 | goto fail; |
769 | } |
770 | |
771 | switch (tls_conf.tls_type) { |
772 | case TLS_CFG_CA: |
773 | if (config_gettls(env, srv_conf, &tls_conf, "ca", p, len, |
774 | &srv_conf->tls_ca, &srv_conf->tls_ca_len) != 0) |
775 | goto fail; |
776 | break; |
777 | |
778 | case TLS_CFG_CERT: |
779 | if (config_gettls(env, srv_conf, &tls_conf, "cert", p, len, |
780 | &srv_conf->tls_cert, &srv_conf->tls_cert_len) != 0) |
781 | goto fail; |
782 | break; |
783 | |
784 | case TLS_CFG_CRL: |
785 | if (config_gettls(env, srv_conf, &tls_conf, "crl", p, len, |
786 | &srv_conf->tls_crl, &srv_conf->tls_crl_len) != 0) |
787 | goto fail; |
788 | break; |
789 | |
790 | case TLS_CFG_KEY: |
791 | if (config_gettls(env, srv_conf, &tls_conf, "key", p, len, |
792 | &srv_conf->tls_key, &srv_conf->tls_key_len) != 0) |
793 | goto fail; |
794 | break; |
795 | |
796 | case TLS_CFG_OCSP_STAPLE: |
797 | if (config_gettls(env, srv_conf, &tls_conf, "ocsp staple", |
798 | p, len, &srv_conf->tls_ocsp_staple, |
799 | &srv_conf->tls_ocsp_staple_len) != 0) |
800 | goto fail; |
801 | break; |
802 | |
803 | default: |
804 | log_debug("%s: unknown tls config type %i\n", |
805 | __func__, tls_conf.tls_type); |
806 | goto fail; |
807 | } |
808 | |
809 | return (0); |
810 | |
811 | fail: |
812 | return (-1); |
813 | } |
814 | |
815 | int |
816 | config_setmedia(struct httpd *env, struct media_type *media) |
817 | { |
818 | struct privsep *ps = env->sc_ps; |
819 | int id; |
820 | unsigned int what; |
821 | |
822 | for (id = 0; id < PROC_MAX; id++) { |
823 | what = ps->ps_what[id]; |
824 | |
825 | if ((what & CONFIG_MEDIA0x01) == 0 || id == privsep_process) |
826 | continue; |
827 | |
828 | DPRINTF("%s: sending media \"%s\" to %s", __func__,do {} while(0) |
829 | media->media_name, ps->ps_title[id])do {} while(0); |
830 | |
831 | proc_compose(ps, id, IMSG_CFG_MEDIA, media, sizeof(*media)); |
832 | } |
833 | |
834 | return (0); |
835 | } |
836 | |
837 | int |
838 | config_getmedia(struct httpd *env, struct imsg *imsg) |
839 | { |
840 | #ifdef DEBUG |
841 | struct privsep *ps = env->sc_ps; |
842 | #endif |
843 | struct media_type media; |
844 | uint8_t *p = imsg->data; |
845 | |
846 | IMSG_SIZE_CHECK(imsg, &media)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&media)) fatalx("bad length imsg received"); } while (0 ); |
847 | memcpy(&media, p, sizeof(media)); |
848 | |
849 | if (media_add(env->sc_mediatypes, &media) == NULL((void*)0)) { |
850 | log_debug("%s: failed to add media \"%s\"", |
851 | __func__, media.media_name); |
852 | return (-1); |
853 | } |
854 | |
855 | DPRINTF("%s: %s %d received media \"%s\"", __func__,do {} while(0) |
856 | ps->ps_title[privsep_process], ps->ps_instance,do {} while(0) |
857 | media.media_name)do {} while(0); |
858 | |
859 | return (0); |
860 | } |
861 | |
862 | int |
863 | config_setauth(struct httpd *env, struct auth *auth) |
864 | { |
865 | struct privsep *ps = env->sc_ps; |
866 | int id; |
867 | unsigned int what; |
868 | |
869 | for (id = 0; id < PROC_MAX; id++) { |
870 | what = ps->ps_what[id]; |
871 | |
872 | if ((what & CONFIG_AUTH0x04) == 0 || id == privsep_process) |
873 | continue; |
874 | |
875 | DPRINTF("%s: sending auth \"%s[%u]\" to %s", __func__,do {} while(0) |
876 | auth->auth_htpasswd, auth->auth_id, ps->ps_title[id])do {} while(0); |
877 | |
878 | proc_compose(ps, id, IMSG_CFG_AUTH, auth, sizeof(*auth)); |
879 | } |
880 | |
881 | return (0); |
882 | } |
883 | |
884 | int |
885 | config_getauth(struct httpd *env, struct imsg *imsg) |
886 | { |
887 | #ifdef DEBUG |
888 | struct privsep *ps = env->sc_ps; |
889 | #endif |
890 | struct auth auth; |
891 | uint8_t *p = imsg->data; |
892 | |
893 | IMSG_SIZE_CHECK(imsg, &auth)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&auth)) fatalx("bad length imsg received"); } while (0); |
894 | memcpy(&auth, p, sizeof(auth)); |
895 | |
896 | if (auth_add(env->sc_auth, &auth) == NULL((void*)0)) { |
897 | log_debug("%s: failed to add auth \"%s[%u]\"", |
898 | __func__, auth.auth_htpasswd, auth.auth_id); |
899 | return (-1); |
900 | } |
901 | |
902 | DPRINTF("%s: %s %d received auth \"%s[%u]\"", __func__,do {} while(0) |
903 | ps->ps_title[privsep_process], ps->ps_instance,do {} while(0) |
904 | auth.auth_htpasswd, auth.auth_id)do {} while(0); |
905 | |
906 | return (0); |
907 | } |