1 |
|
|
/* $OpenBSD: config.c,v 1.53 2017/07/19 17:36:25 jsing 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/tree.h> |
22 |
|
|
#include <sys/time.h> |
23 |
|
|
#include <sys/uio.h> |
24 |
|
|
|
25 |
|
|
#include <unistd.h> |
26 |
|
|
#include <stdlib.h> |
27 |
|
|
#include <stdio.h> |
28 |
|
|
#include <string.h> |
29 |
|
|
#include <imsg.h> |
30 |
|
|
|
31 |
|
|
#include "httpd.h" |
32 |
|
|
|
33 |
|
|
int config_getserver_config(struct httpd *, struct server *, |
34 |
|
|
struct imsg *); |
35 |
|
|
int config_getserver_auth(struct httpd *, struct server_config *); |
36 |
|
|
|
37 |
|
|
int |
38 |
|
|
config_init(struct httpd *env) |
39 |
|
|
{ |
40 |
|
144 |
struct privsep *ps = env->sc_ps; |
41 |
|
|
unsigned int what; |
42 |
|
|
|
43 |
|
|
/* Global configuration */ |
44 |
✓✗ |
72 |
if (privsep_process == PROC_PARENT) |
45 |
|
72 |
env->sc_prefork_server = SERVER_NUMPROC; |
46 |
|
|
|
47 |
|
72 |
ps->ps_what[PROC_PARENT] = CONFIG_ALL; |
48 |
|
72 |
ps->ps_what[PROC_SERVER] = |
49 |
|
|
CONFIG_SERVERS|CONFIG_MEDIA|CONFIG_AUTH; |
50 |
|
72 |
ps->ps_what[PROC_LOGGER] = CONFIG_SERVERS; |
51 |
|
|
|
52 |
|
|
/* Other configuration */ |
53 |
|
72 |
what = ps->ps_what[privsep_process]; |
54 |
|
|
|
55 |
✓✗ |
72 |
if (what & CONFIG_SERVERS) { |
56 |
✗✓ |
144 |
if ((env->sc_servers = |
57 |
|
144 |
calloc(1, sizeof(*env->sc_servers))) == NULL) |
58 |
|
|
return (-1); |
59 |
|
72 |
TAILQ_INIT(env->sc_servers); |
60 |
|
72 |
} |
61 |
|
|
|
62 |
✓✗ |
72 |
if (what & CONFIG_MEDIA) { |
63 |
✗✓ |
144 |
if ((env->sc_mediatypes = |
64 |
|
144 |
calloc(1, sizeof(*env->sc_mediatypes))) == NULL) |
65 |
|
|
return (-1); |
66 |
|
72 |
RB_INIT(env->sc_mediatypes); |
67 |
|
72 |
} |
68 |
|
|
|
69 |
✓✗ |
72 |
if (what & CONFIG_AUTH) { |
70 |
✗✓ |
144 |
if ((env->sc_auth = |
71 |
|
144 |
calloc(1, sizeof(*env->sc_auth))) == NULL) |
72 |
|
|
return (-1); |
73 |
|
72 |
TAILQ_INIT(env->sc_auth); |
74 |
|
72 |
} |
75 |
|
|
|
76 |
|
72 |
return (0); |
77 |
|
72 |
} |
78 |
|
|
|
79 |
|
|
void |
80 |
|
|
config_purge(struct httpd *env, unsigned int reset) |
81 |
|
|
{ |
82 |
|
288 |
struct privsep *ps = env->sc_ps; |
83 |
|
|
struct server *srv; |
84 |
|
|
struct auth *auth; |
85 |
|
|
unsigned int what; |
86 |
|
|
|
87 |
|
144 |
what = ps->ps_what[privsep_process] & reset; |
88 |
|
|
|
89 |
✓✓✓✗
|
216 |
if (what & CONFIG_SERVERS && env->sc_servers != NULL) { |
90 |
✓✓ |
216 |
while ((srv = TAILQ_FIRST(env->sc_servers)) != NULL) |
91 |
|
72 |
server_purge(srv); |
92 |
|
|
} |
93 |
|
|
|
94 |
✓✗✓✗
|
288 |
if (what & CONFIG_MEDIA && env->sc_mediatypes != NULL) |
95 |
|
144 |
media_purge(env->sc_mediatypes); |
96 |
|
|
|
97 |
✓✗✓✗
|
288 |
if (what & CONFIG_AUTH && env->sc_auth != NULL) { |
98 |
✗✓ |
144 |
while ((auth = TAILQ_FIRST(env->sc_auth)) != NULL) { |
99 |
|
|
auth_free(env->sc_auth, auth); |
100 |
|
|
free(auth); |
101 |
|
|
} |
102 |
|
|
} |
103 |
|
144 |
} |
104 |
|
|
|
105 |
|
|
int |
106 |
|
|
config_setreset(struct httpd *env, unsigned int reset) |
107 |
|
|
{ |
108 |
|
|
struct privsep *ps = env->sc_ps; |
109 |
|
|
int id; |
110 |
|
|
|
111 |
|
|
for (id = 0; id < PROC_MAX; id++) { |
112 |
|
|
if ((reset & ps->ps_what[id]) == 0 || |
113 |
|
|
id == privsep_process) |
114 |
|
|
continue; |
115 |
|
|
proc_compose(ps, id, IMSG_CTL_RESET, |
116 |
|
|
&reset, sizeof(reset)); |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
return (0); |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
int |
123 |
|
|
config_getreset(struct httpd *env, struct imsg *imsg) |
124 |
|
|
{ |
125 |
|
|
unsigned int mode; |
126 |
|
|
|
127 |
|
|
IMSG_SIZE_CHECK(imsg, &mode); |
128 |
|
|
memcpy(&mode, imsg->data, sizeof(mode)); |
129 |
|
|
|
130 |
|
|
config_purge(env, mode); |
131 |
|
|
|
132 |
|
|
return (0); |
133 |
|
|
} |
134 |
|
|
|
135 |
|
|
int |
136 |
|
|
config_getcfg(struct httpd *env, struct imsg *imsg) |
137 |
|
|
{ |
138 |
|
|
struct privsep *ps = env->sc_ps; |
139 |
|
|
struct ctl_flags cf; |
140 |
|
|
unsigned int what; |
141 |
|
|
|
142 |
|
|
if (IMSG_DATA_SIZE(imsg) != sizeof(cf)) |
143 |
|
|
return (0); /* ignore */ |
144 |
|
|
|
145 |
|
|
/* Update runtime flags */ |
146 |
|
|
memcpy(&cf, imsg->data, sizeof(cf)); |
147 |
|
|
env->sc_opts = cf.cf_opts; |
148 |
|
|
env->sc_flags = cf.cf_flags; |
149 |
|
|
memcpy(env->sc_tls_sid, cf.cf_tls_sid, sizeof(env->sc_tls_sid)); |
150 |
|
|
|
151 |
|
|
what = ps->ps_what[privsep_process]; |
152 |
|
|
|
153 |
|
|
if (privsep_process != PROC_PARENT) |
154 |
|
|
proc_compose(env->sc_ps, PROC_PARENT, |
155 |
|
|
IMSG_CFG_DONE, NULL, 0); |
156 |
|
|
|
157 |
|
|
return (0); |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
int |
161 |
|
|
config_setserver(struct httpd *env, struct server *srv) |
162 |
|
|
{ |
163 |
|
144 |
struct privsep *ps = env->sc_ps; |
164 |
|
72 |
struct server_config s; |
165 |
|
|
int id; |
166 |
|
72 |
int fd, n, m; |
167 |
|
72 |
struct iovec iov[6]; |
168 |
|
|
size_t c; |
169 |
|
|
unsigned int what; |
170 |
|
|
|
171 |
|
|
/* opens listening sockets etc. */ |
172 |
✗✓ |
72 |
if (server_privinit(srv) == -1) |
173 |
|
|
return (-1); |
174 |
|
|
|
175 |
✓✓ |
576 |
for (id = 0; id < PROC_MAX; id++) { |
176 |
|
216 |
what = ps->ps_what[id]; |
177 |
|
|
|
178 |
✓✗✓✓
|
432 |
if ((what & CONFIG_SERVERS) == 0 || id == privsep_process) |
179 |
|
|
continue; |
180 |
|
|
|
181 |
|
|
DPRINTF("%s: sending %s \"%s[%u]\" to %s fd %d", __func__, |
182 |
|
|
(srv->srv_conf.flags & SRVFLAG_LOCATION) ? |
183 |
|
|
"location" : "server", |
184 |
|
|
srv->srv_conf.name, srv->srv_conf.id, |
185 |
|
|
ps->ps_title[id], srv->srv_s); |
186 |
|
|
|
187 |
|
144 |
memcpy(&s, &srv->srv_conf, sizeof(s)); |
188 |
|
|
|
189 |
|
|
c = 0; |
190 |
|
144 |
iov[c].iov_base = &s; |
191 |
|
144 |
iov[c++].iov_len = sizeof(s); |
192 |
✗✓ |
144 |
if (srv->srv_conf.return_uri_len != 0) { |
193 |
|
|
iov[c].iov_base = srv->srv_conf.return_uri; |
194 |
|
|
iov[c++].iov_len = srv->srv_conf.return_uri_len; |
195 |
|
|
} |
196 |
|
|
|
197 |
✓✓✓✗
|
216 |
if (id == PROC_SERVER && |
198 |
|
72 |
(srv->srv_conf.flags & SRVFLAG_LOCATION) == 0) { |
199 |
|
|
/* XXX imsg code will close the fd after 1st call */ |
200 |
|
72 |
n = -1; |
201 |
|
72 |
proc_range(ps, id, &n, &m); |
202 |
✓✓ |
288 |
for (n = 0; n < m; n++) { |
203 |
✗✓ |
72 |
if (srv->srv_s == -1) |
204 |
|
|
fd = -1; |
205 |
✗✓ |
72 |
else if ((fd = dup(srv->srv_s)) == -1) |
206 |
|
|
return (-1); |
207 |
✗✓ |
216 |
if (proc_composev_imsg(ps, id, n, |
208 |
|
144 |
IMSG_CFG_SERVER, -1, fd, iov, c) != 0) { |
209 |
|
|
log_warn("%s: failed to compose " |
210 |
|
|
"IMSG_CFG_SERVER imsg for `%s'", |
211 |
|
|
__func__, srv->srv_conf.name); |
212 |
|
|
return (-1); |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
/* Prevent fd exhaustion in the parent. */ |
216 |
✗✓ |
72 |
if (proc_flush_imsg(ps, id, n) == -1) { |
217 |
|
|
log_warn("%s: failed to flush " |
218 |
|
|
"IMSG_CFG_SERVER imsg for `%s'", |
219 |
|
|
__func__, srv->srv_conf.name); |
220 |
|
|
return (-1); |
221 |
|
|
} |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
/* Configure TLS if necessary. */ |
225 |
|
72 |
config_setserver_tls(env, srv); |
226 |
|
72 |
} else { |
227 |
✗✓ |
144 |
if (proc_composev(ps, id, IMSG_CFG_SERVER, |
228 |
|
144 |
iov, c) != 0) { |
229 |
|
|
log_warn("%s: failed to compose " |
230 |
|
|
"IMSG_CFG_SERVER imsg for `%s'", |
231 |
|
|
__func__, srv->srv_conf.name); |
232 |
|
|
return (-1); |
233 |
|
|
} |
234 |
|
|
} |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
/* Close server socket early to prevent fd exhaustion in the parent. */ |
238 |
✓✗ |
72 |
if (srv->srv_s != -1) { |
239 |
|
72 |
close(srv->srv_s); |
240 |
|
72 |
srv->srv_s = -1; |
241 |
|
72 |
} |
242 |
|
|
|
243 |
|
72 |
explicit_bzero(&srv->srv_conf.tls_ticket_key, |
244 |
|
|
sizeof(srv->srv_conf.tls_ticket_key)); |
245 |
|
|
|
246 |
|
72 |
return (0); |
247 |
|
72 |
} |
248 |
|
|
|
249 |
|
|
static int |
250 |
|
|
config_settls(struct httpd *env, struct server *srv, enum tls_config_type type, |
251 |
|
|
const char *label, uint8_t *data, size_t len) |
252 |
|
|
{ |
253 |
|
144 |
struct privsep *ps = env->sc_ps; |
254 |
|
72 |
struct server_config *srv_conf = &srv->srv_conf; |
255 |
|
72 |
struct tls_config tls; |
256 |
|
72 |
struct iovec iov[2]; |
257 |
|
|
size_t c; |
258 |
|
|
|
259 |
✓✓ |
72 |
if (data == NULL || len == 0) |
260 |
|
24 |
return (0); |
261 |
|
|
|
262 |
|
|
DPRINTF("%s: sending tls %s for \"%s[%u]\" to %s fd %d", __func__, |
263 |
|
|
label, srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], |
264 |
|
|
srv->srv_s); |
265 |
|
|
|
266 |
|
48 |
memset(&tls, 0, sizeof(tls)); |
267 |
|
48 |
tls.id = srv_conf->id; |
268 |
|
48 |
tls.tls_type = type; |
269 |
|
48 |
tls.tls_len = len; |
270 |
|
48 |
tls.tls_chunk_offset = 0; |
271 |
|
|
|
272 |
✓✓ |
192 |
while (len > 0) { |
273 |
|
48 |
tls.tls_chunk_len = len; |
274 |
✗✓ |
48 |
if (tls.tls_chunk_len > (MAX_IMSG_DATA_SIZE - sizeof(tls))) |
275 |
|
|
tls.tls_chunk_len = MAX_IMSG_DATA_SIZE - sizeof(tls); |
276 |
|
|
|
277 |
|
|
c = 0; |
278 |
|
48 |
iov[c].iov_base = &tls; |
279 |
|
48 |
iov[c++].iov_len = sizeof(tls); |
280 |
|
48 |
iov[c].iov_base = data; |
281 |
|
48 |
iov[c++].iov_len = tls.tls_chunk_len; |
282 |
|
|
|
283 |
✗✓ |
48 |
if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) { |
284 |
|
|
log_warn("%s: failed to compose IMSG_CFG_TLS imsg for " |
285 |
|
|
"`%s'", __func__, srv_conf->name); |
286 |
|
|
return (-1); |
287 |
|
|
} |
288 |
|
|
|
289 |
|
48 |
tls.tls_chunk_offset += tls.tls_chunk_len; |
290 |
|
48 |
data += tls.tls_chunk_len; |
291 |
|
48 |
len -= tls.tls_chunk_len; |
292 |
|
|
} |
293 |
|
|
|
294 |
|
48 |
return (0); |
295 |
|
72 |
} |
296 |
|
|
|
297 |
|
|
int |
298 |
|
|
config_setserver_tls(struct httpd *env, struct server *srv) |
299 |
|
|
{ |
300 |
|
144 |
struct server_config *srv_conf = &srv->srv_conf; |
301 |
|
|
|
302 |
✓✓ |
72 |
if ((srv_conf->flags & SRVFLAG_TLS) == 0) |
303 |
|
48 |
return (0); |
304 |
|
|
|
305 |
|
24 |
log_debug("%s: configuring tls for %s", __func__, srv_conf->name); |
306 |
|
|
|
307 |
✗✓ |
72 |
if (config_settls(env, srv, TLS_CFG_CERT, "cert", srv_conf->tls_cert, |
308 |
|
48 |
srv_conf->tls_cert_len) != 0) |
309 |
|
|
return (-1); |
310 |
|
|
|
311 |
✗✓ |
72 |
if (config_settls(env, srv, TLS_CFG_KEY, "key", srv_conf->tls_key, |
312 |
|
48 |
srv_conf->tls_key_len) != 0) |
313 |
|
|
return (-1); |
314 |
|
|
|
315 |
✗✓ |
48 |
if (config_settls(env, srv, TLS_CFG_OCSP_STAPLE, "ocsp staple", |
316 |
|
48 |
srv_conf->tls_ocsp_staple, srv_conf->tls_ocsp_staple_len) != 0) |
317 |
|
|
return (-1); |
318 |
|
|
|
319 |
|
24 |
return (0); |
320 |
|
72 |
} |
321 |
|
|
|
322 |
|
|
int |
323 |
|
|
config_getserver_auth(struct httpd *env, struct server_config *srv_conf) |
324 |
|
|
{ |
325 |
|
|
struct privsep *ps = env->sc_ps; |
326 |
|
|
|
327 |
|
|
if ((ps->ps_what[privsep_process] & CONFIG_AUTH) == 0 || |
328 |
|
|
(srv_conf->flags & SRVFLAG_AUTH) == 0) |
329 |
|
|
return (0); |
330 |
|
|
|
331 |
|
|
if ((srv_conf->auth = auth_byid(env->sc_auth, |
332 |
|
|
srv_conf->auth_id)) == NULL) |
333 |
|
|
return (-1); |
334 |
|
|
|
335 |
|
|
return (0); |
336 |
|
|
} |
337 |
|
|
|
338 |
|
|
int |
339 |
|
|
config_getserver_config(struct httpd *env, struct server *srv, |
340 |
|
|
struct imsg *imsg) |
341 |
|
|
{ |
342 |
|
|
#ifdef DEBUG |
343 |
|
|
struct privsep *ps = env->sc_ps; |
344 |
|
|
#endif |
345 |
|
|
struct server_config *srv_conf, *parent; |
346 |
|
|
uint8_t *p = imsg->data; |
347 |
|
|
unsigned int f; |
348 |
|
|
size_t s; |
349 |
|
|
|
350 |
|
|
if ((srv_conf = calloc(1, sizeof(*srv_conf))) == NULL) |
351 |
|
|
return (-1); |
352 |
|
|
|
353 |
|
|
IMSG_SIZE_CHECK(imsg, srv_conf); |
354 |
|
|
memcpy(srv_conf, p, sizeof(*srv_conf)); |
355 |
|
|
s = sizeof(*srv_conf); |
356 |
|
|
|
357 |
|
|
/* Reset these variables to avoid free'ing invalid pointers */ |
358 |
|
|
serverconfig_reset(srv_conf); |
359 |
|
|
|
360 |
|
|
TAILQ_FOREACH(parent, &srv->srv_hosts, entry) { |
361 |
|
|
if (strcmp(parent->name, srv_conf->name) == 0) |
362 |
|
|
break; |
363 |
|
|
} |
364 |
|
|
if (parent == NULL) |
365 |
|
|
parent = &srv->srv_conf; |
366 |
|
|
|
367 |
|
|
if (config_getserver_auth(env, srv_conf) != 0) |
368 |
|
|
goto fail; |
369 |
|
|
|
370 |
|
|
/* |
371 |
|
|
* Get variable-length values for the virtual host. The tls_* ones |
372 |
|
|
* aren't needed in the virtual hosts unless we implement SNI. |
373 |
|
|
*/ |
374 |
|
|
if (srv_conf->return_uri_len != 0) { |
375 |
|
|
if ((srv_conf->return_uri = get_data(p + s, |
376 |
|
|
srv_conf->return_uri_len)) == NULL) |
377 |
|
|
goto fail; |
378 |
|
|
s += srv_conf->return_uri_len; |
379 |
|
|
} |
380 |
|
|
|
381 |
|
|
if (srv_conf->flags & SRVFLAG_LOCATION) { |
382 |
|
|
/* Inherit configuration from the parent */ |
383 |
|
|
f = SRVFLAG_INDEX|SRVFLAG_NO_INDEX; |
384 |
|
|
if ((srv_conf->flags & f) == 0) { |
385 |
|
|
srv_conf->flags |= parent->flags & f; |
386 |
|
|
(void)strlcpy(srv_conf->index, parent->index, |
387 |
|
|
sizeof(srv_conf->index)); |
388 |
|
|
} |
389 |
|
|
|
390 |
|
|
f = SRVFLAG_AUTO_INDEX|SRVFLAG_NO_AUTO_INDEX; |
391 |
|
|
if ((srv_conf->flags & f) == 0) |
392 |
|
|
srv_conf->flags |= parent->flags & f; |
393 |
|
|
|
394 |
|
|
f = SRVFLAG_SOCKET|SRVFLAG_FCGI; |
395 |
|
|
if ((srv_conf->flags & f) == SRVFLAG_FCGI) { |
396 |
|
|
srv_conf->flags |= f; |
397 |
|
|
(void)strlcpy(srv_conf->socket, HTTPD_FCGI_SOCKET, |
398 |
|
|
sizeof(srv_conf->socket)); |
399 |
|
|
} |
400 |
|
|
|
401 |
|
|
f = SRVFLAG_ROOT; |
402 |
|
|
if ((srv_conf->flags & f) == 0) { |
403 |
|
|
srv_conf->flags |= parent->flags & f; |
404 |
|
|
(void)strlcpy(srv_conf->root, parent->root, |
405 |
|
|
sizeof(srv_conf->root)); |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
f = SRVFLAG_FCGI|SRVFLAG_NO_FCGI; |
409 |
|
|
if ((srv_conf->flags & f) == 0) |
410 |
|
|
srv_conf->flags |= parent->flags & f; |
411 |
|
|
|
412 |
|
|
f = SRVFLAG_LOG|SRVFLAG_NO_LOG; |
413 |
|
|
if ((srv_conf->flags & f) == 0) { |
414 |
|
|
srv_conf->flags |= parent->flags & f; |
415 |
|
|
srv_conf->logformat = parent->logformat; |
416 |
|
|
} |
417 |
|
|
|
418 |
|
|
f = SRVFLAG_SYSLOG|SRVFLAG_NO_SYSLOG; |
419 |
|
|
if ((srv_conf->flags & f) == 0) |
420 |
|
|
srv_conf->flags |= parent->flags & f; |
421 |
|
|
|
422 |
|
|
f = SRVFLAG_AUTH|SRVFLAG_NO_AUTH; |
423 |
|
|
if ((srv_conf->flags & f) == 0) { |
424 |
|
|
srv_conf->flags |= parent->flags & f; |
425 |
|
|
srv_conf->auth = parent->auth; |
426 |
|
|
srv_conf->auth_id = parent->auth_id; |
427 |
|
|
(void)strlcpy(srv_conf->auth_realm, |
428 |
|
|
parent->auth_realm, |
429 |
|
|
sizeof(srv_conf->auth_realm)); |
430 |
|
|
} |
431 |
|
|
|
432 |
|
|
f = SRVFLAG_TLS; |
433 |
|
|
srv_conf->flags |= parent->flags & f; |
434 |
|
|
|
435 |
|
|
f = SRVFLAG_ACCESS_LOG; |
436 |
|
|
if ((srv_conf->flags & f) == 0) { |
437 |
|
|
srv_conf->flags |= parent->flags & f; |
438 |
|
|
(void)strlcpy(srv_conf->accesslog, |
439 |
|
|
parent->accesslog, |
440 |
|
|
sizeof(srv_conf->accesslog)); |
441 |
|
|
} |
442 |
|
|
|
443 |
|
|
f = SRVFLAG_ERROR_LOG; |
444 |
|
|
if ((srv_conf->flags & f) == 0) { |
445 |
|
|
srv_conf->flags |= parent->flags & f; |
446 |
|
|
(void)strlcpy(srv_conf->errorlog, |
447 |
|
|
parent->errorlog, |
448 |
|
|
sizeof(srv_conf->errorlog)); |
449 |
|
|
} |
450 |
|
|
|
451 |
|
|
f = SRVFLAG_BLOCK|SRVFLAG_NO_BLOCK; |
452 |
|
|
if ((srv_conf->flags & f) == 0) { |
453 |
|
|
free(srv_conf->return_uri); |
454 |
|
|
srv_conf->flags |= parent->flags & f; |
455 |
|
|
srv_conf->return_code = parent->return_code; |
456 |
|
|
srv_conf->return_uri_len = parent->return_uri_len; |
457 |
|
|
if (srv_conf->return_uri_len && |
458 |
|
|
(srv_conf->return_uri = |
459 |
|
|
strdup(parent->return_uri)) == NULL) |
460 |
|
|
goto fail; |
461 |
|
|
} |
462 |
|
|
|
463 |
|
|
f = SRVFLAG_DEFAULT_TYPE; |
464 |
|
|
if ((srv_conf->flags & f) == 0) { |
465 |
|
|
srv_conf->flags |= parent->flags & f; |
466 |
|
|
memcpy(&srv_conf->default_type, |
467 |
|
|
&parent->default_type, sizeof(struct media_type)); |
468 |
|
|
} |
469 |
|
|
|
470 |
|
|
f = SRVFLAG_SERVER_HSTS; |
471 |
|
|
srv_conf->flags |= parent->flags & f; |
472 |
|
|
srv_conf->hsts_max_age = parent->hsts_max_age; |
473 |
|
|
srv_conf->hsts_flags = parent->hsts_flags; |
474 |
|
|
|
475 |
|
|
memcpy(&srv_conf->timeout, &parent->timeout, |
476 |
|
|
sizeof(srv_conf->timeout)); |
477 |
|
|
srv_conf->maxrequests = parent->maxrequests; |
478 |
|
|
srv_conf->maxrequestbody = parent->maxrequestbody; |
479 |
|
|
|
480 |
|
|
DPRINTF("%s: %s %d location \"%s\", " |
481 |
|
|
"parent \"%s[%u]\", flags: %s", |
482 |
|
|
__func__, ps->ps_title[privsep_process], ps->ps_instance, |
483 |
|
|
srv_conf->location, parent->name, parent->id, |
484 |
|
|
printb_flags(srv_conf->flags, SRVFLAG_BITS)); |
485 |
|
|
} else { |
486 |
|
|
/* Add a new "virtual" server */ |
487 |
|
|
DPRINTF("%s: %s %d server \"%s[%u]\", parent \"%s[%u]\", " |
488 |
|
|
"flags: %s", __func__, |
489 |
|
|
ps->ps_title[privsep_process], ps->ps_instance, |
490 |
|
|
srv_conf->name, srv_conf->id, parent->name, parent->id, |
491 |
|
|
printb_flags(srv_conf->flags, SRVFLAG_BITS)); |
492 |
|
|
} |
493 |
|
|
|
494 |
|
|
TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry); |
495 |
|
|
|
496 |
|
|
return (0); |
497 |
|
|
|
498 |
|
|
fail: |
499 |
|
|
serverconfig_free(srv_conf); |
500 |
|
|
free(srv_conf); |
501 |
|
|
return (-1); |
502 |
|
|
} |
503 |
|
|
|
504 |
|
|
int |
505 |
|
|
config_getserver(struct httpd *env, struct imsg *imsg) |
506 |
|
|
{ |
507 |
|
|
#ifdef DEBUG |
508 |
|
|
struct privsep *ps = env->sc_ps; |
509 |
|
|
#endif |
510 |
|
|
struct server *srv = NULL; |
511 |
|
|
struct server_config srv_conf; |
512 |
|
|
uint8_t *p = imsg->data; |
513 |
|
|
size_t s; |
514 |
|
|
|
515 |
|
|
IMSG_SIZE_CHECK(imsg, &srv_conf); |
516 |
|
|
memcpy(&srv_conf, p, sizeof(srv_conf)); |
517 |
|
|
s = sizeof(srv_conf); |
518 |
|
|
|
519 |
|
|
/* Reset these variables to avoid free'ing invalid pointers */ |
520 |
|
|
serverconfig_reset(&srv_conf); |
521 |
|
|
|
522 |
|
|
if ((IMSG_DATA_SIZE(imsg) - s) < (size_t)srv_conf.return_uri_len) { |
523 |
|
|
log_debug("%s: invalid message length", __func__); |
524 |
|
|
goto fail; |
525 |
|
|
} |
526 |
|
|
|
527 |
|
|
/* Check if server with matching listening socket already exists */ |
528 |
|
|
if ((srv = server_byaddr((struct sockaddr *) |
529 |
|
|
&srv_conf.ss, srv_conf.port)) != NULL) { |
530 |
|
|
/* Add "host" to existing listening server */ |
531 |
|
|
if (imsg->fd != -1) { |
532 |
|
|
if (srv->srv_s == -1) |
533 |
|
|
srv->srv_s = imsg->fd; |
534 |
|
|
else |
535 |
|
|
close(imsg->fd); |
536 |
|
|
} |
537 |
|
|
return (config_getserver_config(env, srv, imsg)); |
538 |
|
|
} |
539 |
|
|
|
540 |
|
|
if (srv_conf.flags & SRVFLAG_LOCATION) |
541 |
|
|
fatalx("invalid location"); |
542 |
|
|
|
543 |
|
|
/* Otherwise create a new server */ |
544 |
|
|
if ((srv = calloc(1, sizeof(*srv))) == NULL) |
545 |
|
|
goto fail; |
546 |
|
|
|
547 |
|
|
memcpy(&srv->srv_conf, &srv_conf, sizeof(srv->srv_conf)); |
548 |
|
|
srv->srv_s = imsg->fd; |
549 |
|
|
|
550 |
|
|
if (config_getserver_auth(env, &srv->srv_conf) != 0) |
551 |
|
|
goto fail; |
552 |
|
|
|
553 |
|
|
SPLAY_INIT(&srv->srv_clients); |
554 |
|
|
TAILQ_INIT(&srv->srv_hosts); |
555 |
|
|
|
556 |
|
|
TAILQ_INSERT_TAIL(&srv->srv_hosts, &srv->srv_conf, entry); |
557 |
|
|
TAILQ_INSERT_TAIL(env->sc_servers, srv, srv_entry); |
558 |
|
|
|
559 |
|
|
DPRINTF("%s: %s %d configuration \"%s[%u]\", flags: %s", __func__, |
560 |
|
|
ps->ps_title[privsep_process], ps->ps_instance, |
561 |
|
|
srv->srv_conf.name, srv->srv_conf.id, |
562 |
|
|
printb_flags(srv->srv_conf.flags, SRVFLAG_BITS)); |
563 |
|
|
|
564 |
|
|
/* |
565 |
|
|
* Get all variable-length values for the parent server. |
566 |
|
|
*/ |
567 |
|
|
if (srv->srv_conf.return_uri_len != 0) { |
568 |
|
|
if ((srv->srv_conf.return_uri = get_data(p + s, |
569 |
|
|
srv->srv_conf.return_uri_len)) == NULL) |
570 |
|
|
goto fail; |
571 |
|
|
s += srv->srv_conf.return_uri_len; |
572 |
|
|
} |
573 |
|
|
|
574 |
|
|
return (0); |
575 |
|
|
|
576 |
|
|
fail: |
577 |
|
|
if (imsg->fd != -1) |
578 |
|
|
close(imsg->fd); |
579 |
|
|
if (srv != NULL) |
580 |
|
|
serverconfig_free(&srv->srv_conf); |
581 |
|
|
free(srv); |
582 |
|
|
|
583 |
|
|
return (-1); |
584 |
|
|
} |
585 |
|
|
|
586 |
|
|
static int |
587 |
|
|
config_gettls(struct httpd *env, struct server_config *srv_conf, |
588 |
|
|
struct tls_config *tls_conf, const char *label, uint8_t *data, size_t len, |
589 |
|
|
uint8_t **outdata, size_t *outlen) |
590 |
|
|
{ |
591 |
|
|
#ifdef DEBUG |
592 |
|
|
struct privsep *ps = env->sc_ps; |
593 |
|
|
#endif |
594 |
|
|
|
595 |
|
|
DPRINTF("%s: %s %d getting tls %s (%zu:%zu@%zu) for \"%s[%u]\"", |
596 |
|
|
__func__, ps->ps_title[privsep_process], ps->ps_instance, label, |
597 |
|
|
tls_conf->tls_len, len, tls_conf->tls_chunk_offset, srv_conf->name, |
598 |
|
|
srv_conf->id); |
599 |
|
|
|
600 |
|
|
if (tls_conf->tls_chunk_offset == 0) { |
601 |
|
|
free(*outdata); |
602 |
|
|
*outlen = 0; |
603 |
|
|
if ((*outdata = calloc(1, tls_conf->tls_len)) == NULL) |
604 |
|
|
goto fail; |
605 |
|
|
*outlen = tls_conf->tls_len; |
606 |
|
|
} |
607 |
|
|
|
608 |
|
|
if (*outdata == NULL) { |
609 |
|
|
log_debug("%s: tls config invalid chunk sequence", __func__); |
610 |
|
|
goto fail; |
611 |
|
|
} |
612 |
|
|
|
613 |
|
|
if (*outlen != tls_conf->tls_len) { |
614 |
|
|
log_debug("%s: tls config length mismatch (%zu != %zu)", |
615 |
|
|
__func__, *outlen, tls_conf->tls_len); |
616 |
|
|
goto fail; |
617 |
|
|
} |
618 |
|
|
|
619 |
|
|
if (len > (tls_conf->tls_len - tls_conf->tls_chunk_offset)) { |
620 |
|
|
log_debug("%s: tls config invalid chunk length", __func__); |
621 |
|
|
goto fail; |
622 |
|
|
} |
623 |
|
|
|
624 |
|
|
memcpy(*outdata + tls_conf->tls_chunk_offset, data, len); |
625 |
|
|
|
626 |
|
|
return (0); |
627 |
|
|
|
628 |
|
|
fail: |
629 |
|
|
return (-1); |
630 |
|
|
} |
631 |
|
|
|
632 |
|
|
int |
633 |
|
|
config_getserver_tls(struct httpd *env, struct imsg *imsg) |
634 |
|
|
{ |
635 |
|
|
struct server_config *srv_conf = NULL; |
636 |
|
|
struct tls_config tls_conf; |
637 |
|
|
uint8_t *p = imsg->data; |
638 |
|
|
size_t len; |
639 |
|
|
|
640 |
|
|
IMSG_SIZE_CHECK(imsg, &tls_conf); |
641 |
|
|
memcpy(&tls_conf, p, sizeof(tls_conf)); |
642 |
|
|
|
643 |
|
|
len = tls_conf.tls_chunk_len; |
644 |
|
|
|
645 |
|
|
if ((IMSG_DATA_SIZE(imsg) - sizeof(tls_conf)) < len) { |
646 |
|
|
log_debug("%s: invalid message length", __func__); |
647 |
|
|
goto fail; |
648 |
|
|
} |
649 |
|
|
|
650 |
|
|
p += sizeof(tls_conf); |
651 |
|
|
|
652 |
|
|
if ((srv_conf = serverconfig_byid(tls_conf.id)) == NULL) { |
653 |
|
|
log_debug("%s: server not found", __func__); |
654 |
|
|
goto fail; |
655 |
|
|
} |
656 |
|
|
|
657 |
|
|
switch (tls_conf.tls_type) { |
658 |
|
|
case TLS_CFG_CERT: |
659 |
|
|
if (config_gettls(env, srv_conf, &tls_conf, "cert", p, len, |
660 |
|
|
&srv_conf->tls_cert, &srv_conf->tls_cert_len) != 0) |
661 |
|
|
goto fail; |
662 |
|
|
break; |
663 |
|
|
|
664 |
|
|
case TLS_CFG_KEY: |
665 |
|
|
if (config_gettls(env, srv_conf, &tls_conf, "key", p, len, |
666 |
|
|
&srv_conf->tls_key, &srv_conf->tls_key_len) != 0) |
667 |
|
|
goto fail; |
668 |
|
|
break; |
669 |
|
|
|
670 |
|
|
case TLS_CFG_OCSP_STAPLE: |
671 |
|
|
if (config_gettls(env, srv_conf, &tls_conf, "ocsp staple", |
672 |
|
|
p, len, &srv_conf->tls_ocsp_staple, |
673 |
|
|
&srv_conf->tls_ocsp_staple_len) != 0) |
674 |
|
|
goto fail; |
675 |
|
|
break; |
676 |
|
|
|
677 |
|
|
default: |
678 |
|
|
log_debug("%s: unknown tls config type %i\n", |
679 |
|
|
__func__, tls_conf.tls_type); |
680 |
|
|
goto fail; |
681 |
|
|
} |
682 |
|
|
|
683 |
|
|
return (0); |
684 |
|
|
|
685 |
|
|
fail: |
686 |
|
|
return (-1); |
687 |
|
|
} |
688 |
|
|
|
689 |
|
|
int |
690 |
|
|
config_setmedia(struct httpd *env, struct media_type *media) |
691 |
|
|
{ |
692 |
|
1296 |
struct privsep *ps = env->sc_ps; |
693 |
|
|
int id; |
694 |
|
|
unsigned int what; |
695 |
|
|
|
696 |
✓✓ |
5184 |
for (id = 0; id < PROC_MAX; id++) { |
697 |
|
1944 |
what = ps->ps_what[id]; |
698 |
|
|
|
699 |
✓✓✓✓
|
3240 |
if ((what & CONFIG_MEDIA) == 0 || id == privsep_process) |
700 |
|
|
continue; |
701 |
|
|
|
702 |
|
|
DPRINTF("%s: sending media \"%s\" to %s", __func__, |
703 |
|
|
media->media_name, ps->ps_title[id]); |
704 |
|
|
|
705 |
|
648 |
proc_compose(ps, id, IMSG_CFG_MEDIA, media, sizeof(*media)); |
706 |
|
648 |
} |
707 |
|
|
|
708 |
|
648 |
return (0); |
709 |
|
|
} |
710 |
|
|
|
711 |
|
|
int |
712 |
|
|
config_getmedia(struct httpd *env, struct imsg *imsg) |
713 |
|
|
{ |
714 |
|
|
#ifdef DEBUG |
715 |
|
|
struct privsep *ps = env->sc_ps; |
716 |
|
|
#endif |
717 |
|
|
struct media_type media; |
718 |
|
|
uint8_t *p = imsg->data; |
719 |
|
|
|
720 |
|
|
IMSG_SIZE_CHECK(imsg, &media); |
721 |
|
|
memcpy(&media, p, sizeof(media)); |
722 |
|
|
|
723 |
|
|
if (media_add(env->sc_mediatypes, &media) == NULL) { |
724 |
|
|
log_debug("%s: failed to add media \"%s\"", |
725 |
|
|
__func__, media.media_name); |
726 |
|
|
return (-1); |
727 |
|
|
} |
728 |
|
|
|
729 |
|
|
DPRINTF("%s: %s %d received media \"%s\"", __func__, |
730 |
|
|
ps->ps_title[privsep_process], ps->ps_instance, |
731 |
|
|
media.media_name); |
732 |
|
|
|
733 |
|
|
return (0); |
734 |
|
|
} |
735 |
|
|
|
736 |
|
|
int |
737 |
|
|
config_setauth(struct httpd *env, struct auth *auth) |
738 |
|
|
{ |
739 |
|
|
struct privsep *ps = env->sc_ps; |
740 |
|
|
int id; |
741 |
|
|
unsigned int what; |
742 |
|
|
|
743 |
|
|
for (id = 0; id < PROC_MAX; id++) { |
744 |
|
|
what = ps->ps_what[id]; |
745 |
|
|
|
746 |
|
|
if ((what & CONFIG_AUTH) == 0 || id == privsep_process) |
747 |
|
|
continue; |
748 |
|
|
|
749 |
|
|
DPRINTF("%s: sending auth \"%s[%u]\" to %s", __func__, |
750 |
|
|
auth->auth_htpasswd, auth->auth_id, ps->ps_title[id]); |
751 |
|
|
|
752 |
|
|
proc_compose(ps, id, IMSG_CFG_AUTH, auth, sizeof(*auth)); |
753 |
|
|
} |
754 |
|
|
|
755 |
|
|
return (0); |
756 |
|
|
} |
757 |
|
|
|
758 |
|
|
int |
759 |
|
|
config_getauth(struct httpd *env, struct imsg *imsg) |
760 |
|
|
{ |
761 |
|
|
#ifdef DEBUG |
762 |
|
|
struct privsep *ps = env->sc_ps; |
763 |
|
|
#endif |
764 |
|
|
struct auth auth; |
765 |
|
|
uint8_t *p = imsg->data; |
766 |
|
|
|
767 |
|
|
IMSG_SIZE_CHECK(imsg, &auth); |
768 |
|
|
memcpy(&auth, p, sizeof(auth)); |
769 |
|
|
|
770 |
|
|
if (auth_add(env->sc_auth, &auth) == NULL) { |
771 |
|
|
log_debug("%s: failed to add auth \"%s[%u]\"", |
772 |
|
|
__func__, auth.auth_htpasswd, auth.auth_id); |
773 |
|
|
return (-1); |
774 |
|
|
} |
775 |
|
|
|
776 |
|
|
DPRINTF("%s: %s %d received auth \"%s[%u]\"", __func__, |
777 |
|
|
ps->ps_title[privsep_process], ps->ps_instance, |
778 |
|
|
auth.auth_htpasswd, auth.auth_id); |
779 |
|
|
|
780 |
|
|
return (0); |
781 |
|
|
} |