Bug Summary

File:src/usr.sbin/httpd/config.c
Warning:line 488, column 3
Value stored to 's' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name config.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/httpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/httpd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/httpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/httpd/config.c
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
35int config_getserver_config(struct httpd *, struct server *,
36 struct imsg *);
37int config_getserver_auth(struct httpd *, struct server_config *);
38
39int
40config_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
84void
85config_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
110int
111config_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
127int
128config_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
140int
141config_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
161int
162config_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
253static int
254config_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
301int
302config_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
357int
358config_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
399int
400config_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
432int
433config_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
448int
449config_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
619int
620config_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
700static int
701config_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
746int
747config_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
815int
816config_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
837int
838config_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
862int
863config_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
884int
885config_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}