xref: /openbsd-src/usr.sbin/httpd/server.c (revision 76ed904538b7966e735c4736a6e2cf7222ad67cf)
1*76ed9045Smillert /*	$OpenBSD: server.c,v 1.129 2023/11/08 19:19:10 millert Exp $	*/
2b7b6a941Sreyk 
3b7b6a941Sreyk /*
405c2c945Sreyk  * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
5b7b6a941Sreyk  *
6b7b6a941Sreyk  * Permission to use, copy, modify, and distribute this software for any
7b7b6a941Sreyk  * purpose with or without fee is hereby granted, provided that the above
8b7b6a941Sreyk  * copyright notice and this permission notice appear in all copies.
9b7b6a941Sreyk  *
10b7b6a941Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11b7b6a941Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12b7b6a941Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13b7b6a941Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14b7b6a941Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15b7b6a941Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16b7b6a941Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17b7b6a941Sreyk  */
18b7b6a941Sreyk 
19b7b6a941Sreyk #include <sys/types.h>
20b7b6a941Sreyk #include <sys/queue.h>
21b7b6a941Sreyk #include <sys/time.h>
22b7b6a941Sreyk #include <sys/stat.h>
23b7b6a941Sreyk #include <sys/socket.h>
24cf605f40Sreyk #include <sys/uio.h>
25b7b6a941Sreyk #include <sys/tree.h>
26b7b6a941Sreyk 
27b7b6a941Sreyk #include <netinet/in.h>
28b7b6a941Sreyk #include <netinet/tcp.h>
2986f952e4Sreyk #include <arpa/inet.h>
30b7b6a941Sreyk 
3186f952e4Sreyk #include <stdio.h>
3286f952e4Sreyk #include <stdlib.h>
3386f952e4Sreyk #include <stdarg.h>
3486f952e4Sreyk #include <limits.h>
35b7b6a941Sreyk #include <errno.h>
36b7b6a941Sreyk #include <fcntl.h>
37b7b6a941Sreyk #include <string.h>
38cf605f40Sreyk #include <syslog.h>
39b7b6a941Sreyk #include <unistd.h>
40b7b6a941Sreyk #include <event.h>
4186f952e4Sreyk #include <imsg.h>
420e3bc1d9Sjsing #include <tls.h>
43ba87bb65Sreyk #include <vis.h>
44b7b6a941Sreyk 
45b7b6a941Sreyk #include "httpd.h"
46b7b6a941Sreyk 
47b9fc9a72Sderaadt #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
48b9fc9a72Sderaadt 
49b7b6a941Sreyk int		 server_dispatch_parent(int, struct privsep_proc *,
50b7b6a941Sreyk 		    struct imsg *);
51844c3615Sreyk int		 server_dispatch_logger(int, struct privsep_proc *,
52844c3615Sreyk 		    struct imsg *);
53b7b6a941Sreyk void		 server_shutdown(void);
54b7b6a941Sreyk 
55b7b6a941Sreyk void		 server_init(struct privsep *, struct privsep_proc *p, void *);
56b7b6a941Sreyk void		 server_launch(void);
57b7b6a941Sreyk int		 server_socket(struct sockaddr_storage *, in_port_t,
58eb242fe1Sreyk 		    struct server_config *, int, int);
59b7b6a941Sreyk int		 server_socket_listen(struct sockaddr_storage *, in_port_t,
60eb242fe1Sreyk 		    struct server_config *);
61fe006a11Sclaudio struct server	*server_byid(uint32_t);
62b7b6a941Sreyk 
63a760b3d3Sreyk int		 server_tls_init(struct server *);
64a760b3d3Sreyk void		 server_tls_readcb(int, short, void *);
65a760b3d3Sreyk void		 server_tls_writecb(int, short, void *);
669211a933Sreyk void		 server_tls_handshake(int, short, void *);
673fe67476Sreyk 
68b7b6a941Sreyk void		 server_accept(int, short, void *);
69b7b6a941Sreyk void		 server_input(struct client *);
7028569998Sflorian void		 server_inflight_dec(struct client *, const char *);
71b7b6a941Sreyk 
72b7b6a941Sreyk extern void	 bufferevent_read_pressure_cb(struct evbuffer *, size_t,
73b7b6a941Sreyk 		    size_t, void *);
74b7b6a941Sreyk 
75b7b6a941Sreyk volatile int server_clients;
76b7b6a941Sreyk volatile int server_inflight = 0;
774703e0faSreyk uint32_t server_cltid;
78b7b6a941Sreyk 
79b7b6a941Sreyk static struct privsep_proc procs[] = {
80844c3615Sreyk 	{ "parent",	PROC_PARENT,	server_dispatch_parent },
81844c3615Sreyk 	{ "logger",	PROC_LOGGER,	server_dispatch_logger }
82b7b6a941Sreyk };
83b7b6a941Sreyk 
845811a22aSrzalamena void
server(struct privsep * ps,struct privsep_proc * p)85b7b6a941Sreyk server(struct privsep *ps, struct privsep_proc *p)
86b7b6a941Sreyk {
875811a22aSrzalamena 	proc_run(ps, p, procs, nitems(procs), server_init, NULL);
88781985a7Srzalamena 	server_http();
89b7b6a941Sreyk }
90b7b6a941Sreyk 
91b7b6a941Sreyk void
server_shutdown(void)92b7b6a941Sreyk server_shutdown(void)
93b7b6a941Sreyk {
94781985a7Srzalamena 	config_purge(httpd_env, CONFIG_ALL);
95b7b6a941Sreyk 	usleep(200);	/* XXX server needs to shutdown last */
96b7b6a941Sreyk }
97b7b6a941Sreyk 
98b7b6a941Sreyk int
server_privinit(struct server * srv)99b7b6a941Sreyk server_privinit(struct server *srv)
100b7b6a941Sreyk {
10127fb06b4Sreyk 	struct server	*s;
10227fb06b4Sreyk 
103a916ec37Sreyk 	if (srv->srv_conf.flags & SRVFLAG_LOCATION)
104a916ec37Sreyk 		return (0);
105a916ec37Sreyk 
106b7b6a941Sreyk 	log_debug("%s: adding server %s", __func__, srv->srv_conf.name);
107b7b6a941Sreyk 
10827fb06b4Sreyk 	/*
10927fb06b4Sreyk 	 * There's no need to open a new socket if a server with the
11027fb06b4Sreyk 	 * same address already exists.
11127fb06b4Sreyk 	 */
112781985a7Srzalamena 	TAILQ_FOREACH(s, httpd_env->sc_servers, srv_entry) {
11327fb06b4Sreyk 		if (s != srv && s->srv_s != -1 &&
11427fb06b4Sreyk 		    s->srv_conf.port == srv->srv_conf.port &&
11527fb06b4Sreyk 		    sockaddr_cmp((struct sockaddr *)&s->srv_conf.ss,
11627fb06b4Sreyk 		    (struct sockaddr *)&srv->srv_conf.ss,
11727fb06b4Sreyk 		    s->srv_conf.prefixlen) == 0)
11827fb06b4Sreyk 			return (0);
11927fb06b4Sreyk 	}
12027fb06b4Sreyk 
12127fb06b4Sreyk 	/* Open listening socket in the privileged process */
122b7b6a941Sreyk 	if ((srv->srv_s = server_socket_listen(&srv->srv_conf.ss,
123eb242fe1Sreyk 	    srv->srv_conf.port, &srv->srv_conf)) == -1)
124b7b6a941Sreyk 		return (-1);
125b7b6a941Sreyk 
126b7b6a941Sreyk 	return (0);
127b7b6a941Sreyk }
128b7b6a941Sreyk 
12945767b45Sjsing int
server_tls_cmp(struct server * s1,struct server * s2)130d587572fSclaudio server_tls_cmp(struct server *s1, struct server *s2)
131e1f28ec9Sjsing {
132e1f28ec9Sjsing 	struct server_config	*sc1, *sc2;
133e1f28ec9Sjsing 
134e1f28ec9Sjsing 	sc1 = &s1->srv_conf;
135e1f28ec9Sjsing 	sc2 = &s2->srv_conf;
136e1f28ec9Sjsing 
1371d0dc528Sjsing 	if (sc1->tls_flags != sc2->tls_flags)
1381d0dc528Sjsing 		return (-1);
139e1f28ec9Sjsing 	if (sc1->tls_protocols != sc2->tls_protocols)
140e1f28ec9Sjsing 		return (-1);
141fe006a11Sclaudio 	if (sc1->tls_ticket_lifetime != sc2->tls_ticket_lifetime)
142fe006a11Sclaudio 		return (-1);
143e1f28ec9Sjsing 	if (strcmp(sc1->tls_ciphers, sc2->tls_ciphers) != 0)
144e1f28ec9Sjsing 		return (-1);
145e1f28ec9Sjsing 	if (strcmp(sc1->tls_dhe_params, sc2->tls_dhe_params) != 0)
146e1f28ec9Sjsing 		return (-1);
14789f7e997Sjsing 	if (strcmp(sc1->tls_ecdhe_curves, sc2->tls_ecdhe_curves) != 0)
148e1f28ec9Sjsing 		return (-1);
149e1f28ec9Sjsing 
150e1f28ec9Sjsing 	return (0);
151e1f28ec9Sjsing }
152e1f28ec9Sjsing 
153e1f28ec9Sjsing int
server_tls_load_keypair(struct server * srv)154a760b3d3Sreyk server_tls_load_keypair(struct server *srv)
15545767b45Sjsing {
156a760b3d3Sreyk 	if ((srv->srv_conf.flags & SRVFLAG_TLS) == 0)
15745767b45Sjsing 		return (0);
15845767b45Sjsing 
15988f25489Sjsing 	if ((srv->srv_conf.tls_cert = tls_load_file(srv->srv_conf.tls_cert_file,
16088f25489Sjsing 	    &srv->srv_conf.tls_cert_len, NULL)) == NULL)
16145767b45Sjsing 		return (-1);
16245767b45Sjsing 	log_debug("%s: using certificate %s", __func__,
163a760b3d3Sreyk 	    srv->srv_conf.tls_cert_file);
16445767b45Sjsing 
1659ed68474Sreyk 	/* XXX allow to specify password for encrypted key */
16688f25489Sjsing 	if ((srv->srv_conf.tls_key = tls_load_file(srv->srv_conf.tls_key_file,
16788f25489Sjsing 	    &srv->srv_conf.tls_key_len, NULL)) == NULL)
16845767b45Sjsing 		return (-1);
16945767b45Sjsing 	log_debug("%s: using private key %s", __func__,
170a760b3d3Sreyk 	    srv->srv_conf.tls_key_file);
17145767b45Sjsing 
17288f25489Sjsing 	return (0);
17388f25489Sjsing }
17488f25489Sjsing 
17588f25489Sjsing int
server_tls_load_ocsp(struct server * srv)17688f25489Sjsing server_tls_load_ocsp(struct server *srv)
17788f25489Sjsing {
17888f25489Sjsing 	if ((srv->srv_conf.flags & SRVFLAG_TLS) == 0)
17988f25489Sjsing 		return (0);
18088f25489Sjsing 
18188f25489Sjsing 	if (srv->srv_conf.tls_ocsp_staple_file == NULL)
18288f25489Sjsing 		return (0);
18388f25489Sjsing 
184e80948e2Sbeck 	if ((srv->srv_conf.tls_ocsp_staple = tls_load_file(
185e80948e2Sbeck 	    srv->srv_conf.tls_ocsp_staple_file,
1865e7d9bbdSbeck 	    &srv->srv_conf.tls_ocsp_staple_len, NULL)) == NULL) {
18734538e77Sbeck 		log_warnx("%s: Failed to load ocsp staple from %s", __func__,
1885e7d9bbdSbeck 		    srv->srv_conf.tls_ocsp_staple_file);
18934538e77Sbeck 		return (-1);
1905e7d9bbdSbeck 	}
1915e7d9bbdSbeck 
1925e7d9bbdSbeck 	if (srv->srv_conf.tls_ocsp_staple_len == 0) {
1935e7d9bbdSbeck 		log_warnx("%s: ignoring 0 length ocsp staple from %s", __func__,
1945e7d9bbdSbeck 		    srv->srv_conf.tls_ocsp_staple_file);
1955e7d9bbdSbeck 		return (0);
1965e7d9bbdSbeck 	}
1975e7d9bbdSbeck 
198e80948e2Sbeck 	log_debug("%s: using ocsp staple from %s", __func__,
199e80948e2Sbeck 	    srv->srv_conf.tls_ocsp_staple_file);
200e80948e2Sbeck 
20145767b45Sjsing 	return (0);
20245767b45Sjsing }
20345767b45Sjsing 
2043fe67476Sreyk int
server_tls_load_ca(struct server * srv)2051d0dc528Sjsing server_tls_load_ca(struct server *srv)
2061d0dc528Sjsing {
2071d0dc528Sjsing 	if ((srv->srv_conf.tls_flags & TLSFLAG_CA) == 0 ||
2081d0dc528Sjsing 	    srv->srv_conf.tls_ca_file == NULL)
2091d0dc528Sjsing 		return (0);
2101d0dc528Sjsing 
2111d0dc528Sjsing 	if ((srv->srv_conf.tls_ca = tls_load_file(
2121d0dc528Sjsing 	    srv->srv_conf.tls_ca_file,
2131d0dc528Sjsing 	    &srv->srv_conf.tls_ca_len, NULL)) == NULL)
2141d0dc528Sjsing 		return (-1);
2151d0dc528Sjsing 	log_debug("%s: using ca cert(s) from %s", __func__,
2161d0dc528Sjsing 	    srv->srv_conf.tls_ca_file);
2171d0dc528Sjsing 
2181d0dc528Sjsing 	return (0);
2191d0dc528Sjsing }
2201d0dc528Sjsing 
2211d0dc528Sjsing int
server_tls_load_crl(struct server * srv)2221d0dc528Sjsing server_tls_load_crl(struct server *srv)
2231d0dc528Sjsing {
2241d0dc528Sjsing 	if ((srv->srv_conf.tls_flags & TLSFLAG_CA) == 0 ||
2251d0dc528Sjsing 	    srv->srv_conf.tls_crl_file == NULL)
2261d0dc528Sjsing 		return (0);
2271d0dc528Sjsing 
2281d0dc528Sjsing 	if ((srv->srv_conf.tls_crl = tls_load_file(
2291d0dc528Sjsing 	    srv->srv_conf.tls_crl_file,
2301d0dc528Sjsing 	    &srv->srv_conf.tls_crl_len, NULL)) == NULL)
2311d0dc528Sjsing 		return (-1);
2321d0dc528Sjsing 	log_debug("%s: using crl(s) from %s", __func__,
2331d0dc528Sjsing 	    srv->srv_conf.tls_crl_file);
2341d0dc528Sjsing 
2351d0dc528Sjsing 	return (0);
2361d0dc528Sjsing }
2371d0dc528Sjsing 
2381d0dc528Sjsing int
server_tls_init(struct server * srv)239a760b3d3Sreyk server_tls_init(struct server *srv)
2403fe67476Sreyk {
2411851096aSjsing 	struct server_config *srv_conf;
2421851096aSjsing 
243a760b3d3Sreyk 	if ((srv->srv_conf.flags & SRVFLAG_TLS) == 0)
2443fe67476Sreyk 		return (0);
2453fe67476Sreyk 
24690ddef02Sjsing 	log_debug("%s: setting up tls for %s", __func__, srv->srv_conf.name);
2473fe67476Sreyk 
2480e3bc1d9Sjsing 	if ((srv->srv_tls_config = tls_config_new()) == NULL) {
2497a44fc4eSjsing 		log_warnx("%s: failed to get tls config", __func__);
2503fe67476Sreyk 		return (-1);
2513fe67476Sreyk 	}
2520e3bc1d9Sjsing 	if ((srv->srv_tls_ctx = tls_server()) == NULL) {
2537a44fc4eSjsing 		log_warnx("%s: failed to get tls server", __func__);
2543fe67476Sreyk 		return (-1);
2553fe67476Sreyk 	}
2563fe67476Sreyk 
257be6225deSjsing 	if (tls_config_set_protocols(srv->srv_tls_config,
258be6225deSjsing 	    srv->srv_conf.tls_protocols) != 0) {
259be6225deSjsing 		log_warnx("%s: failed to set tls protocols: %s",
260be6225deSjsing 		    __func__, tls_config_error(srv->srv_tls_config));
261be6225deSjsing 		return (-1);
262be6225deSjsing 	}
2630e3bc1d9Sjsing 	if (tls_config_set_ciphers(srv->srv_tls_config,
264a760b3d3Sreyk 	    srv->srv_conf.tls_ciphers) != 0) {
2655f07e4daSjsing 		log_warnx("%s: failed to set tls ciphers: %s",
2665f07e4daSjsing 		    __func__, tls_config_error(srv->srv_tls_config));
26784299187Sjsing 		return (-1);
26884299187Sjsing 	}
269051776c0Sjsing 	if (tls_config_set_dheparams(srv->srv_tls_config,
270051776c0Sjsing 	    srv->srv_conf.tls_dhe_params) != 0) {
2715f07e4daSjsing 		log_warnx("%s: failed to set tls dhe params: %s",
2725f07e4daSjsing 		    __func__, tls_config_error(srv->srv_tls_config));
273051776c0Sjsing 		return (-1);
274051776c0Sjsing 	}
27589f7e997Sjsing 	if (tls_config_set_ecdhecurves(srv->srv_tls_config,
27689f7e997Sjsing 	    srv->srv_conf.tls_ecdhe_curves) != 0) {
27789f7e997Sjsing 		log_warnx("%s: failed to set tls ecdhe curves: %s",
2785f07e4daSjsing 		    __func__, tls_config_error(srv->srv_tls_config));
279051776c0Sjsing 		return (-1);
280051776c0Sjsing 	}
281051776c0Sjsing 
282ef012c23Sbeck 	if (tls_config_set_keypair_ocsp_mem(srv->srv_tls_config,
2835f07e4daSjsing 	    srv->srv_conf.tls_cert, srv->srv_conf.tls_cert_len,
284ef012c23Sbeck 	    srv->srv_conf.tls_key, srv->srv_conf.tls_key_len,
2854222661eSbeck 	    srv->srv_conf.tls_ocsp_staple,
2864222661eSbeck 	    srv->srv_conf.tls_ocsp_staple_len) != 0) {
2875f07e4daSjsing 		log_warnx("%s: failed to set tls certificate/key: %s",
2885f07e4daSjsing 		    __func__, tls_config_error(srv->srv_tls_config));
28984299187Sjsing 		return (-1);
29084299187Sjsing 	}
2913fe67476Sreyk 
2921d0dc528Sjsing 	if (srv->srv_conf.tls_ca != NULL) {
2931d0dc528Sjsing 		if (tls_config_set_ca_mem(srv->srv_tls_config,
2941d0dc528Sjsing 		    srv->srv_conf.tls_ca, srv->srv_conf.tls_ca_len) != 0) {
2951d0dc528Sjsing 			log_warnx("%s: failed to add ca cert(s)", __func__);
2961d0dc528Sjsing 			return (-1);
2971d0dc528Sjsing 		}
2981d0dc528Sjsing 		if (tls_config_set_crl_mem(srv->srv_tls_config,
2991d0dc528Sjsing 		    srv->srv_conf.tls_crl, srv->srv_conf.tls_crl_len) != 0) {
3001d0dc528Sjsing 			log_warnx("%s: failed to add crl(s)", __func__);
3011d0dc528Sjsing 			return (-1);
3021d0dc528Sjsing 		}
3031d0dc528Sjsing 		if (srv->srv_conf.tls_flags & TLSFLAG_OPTIONAL)
3041d0dc528Sjsing 			tls_config_verify_client_optional(srv->srv_tls_config);
3051d0dc528Sjsing 		else
3061d0dc528Sjsing 			tls_config_verify_client(srv->srv_tls_config);
3071d0dc528Sjsing 	}
3081d0dc528Sjsing 
3091851096aSjsing 	TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
3101851096aSjsing 		if (srv_conf->tls_cert == NULL || srv_conf->tls_key == NULL)
3111851096aSjsing 			continue;
3121851096aSjsing 		log_debug("%s: adding keypair for server %s", __func__,
3131851096aSjsing 		    srv->srv_conf.name);
314ef012c23Sbeck 		if (tls_config_add_keypair_ocsp_mem(srv->srv_tls_config,
3151851096aSjsing 		    srv_conf->tls_cert, srv_conf->tls_cert_len,
316ef012c23Sbeck 		    srv_conf->tls_key, srv_conf->tls_key_len,
317ef012c23Sbeck 		    srv_conf->tls_ocsp_staple,
318ef012c23Sbeck 		    srv_conf->tls_ocsp_staple_len) != 0) {
3191851096aSjsing 			log_warnx("%s: failed to add tls keypair", __func__);
3201851096aSjsing 			return (-1);
3211851096aSjsing 		}
3221851096aSjsing 	}
3231851096aSjsing 
324fe006a11Sclaudio 	/* set common session ID among all processes */
325fe006a11Sclaudio 	if (tls_config_set_session_id(srv->srv_tls_config,
326fe006a11Sclaudio 	    httpd_env->sc_tls_sid, sizeof(httpd_env->sc_tls_sid)) == -1) {
327fe006a11Sclaudio 		log_warnx("%s: could not set the TLS session ID: %s",
328fe006a11Sclaudio 		    __func__, tls_config_error(srv->srv_tls_config));
329fe006a11Sclaudio 		return (-1);
330fe006a11Sclaudio 	}
331fe006a11Sclaudio 
332fe006a11Sclaudio 	/* ticket support */
333fe006a11Sclaudio 	if (srv->srv_conf.tls_ticket_lifetime) {
334fe006a11Sclaudio 		if (tls_config_set_session_lifetime(srv->srv_tls_config,
335fe006a11Sclaudio 		    srv->srv_conf.tls_ticket_lifetime) == -1) {
336fe006a11Sclaudio 			log_warnx("%s: could not set the TLS session lifetime: "
337fe006a11Sclaudio 			    "%s", __func__,
338fe006a11Sclaudio 			    tls_config_error(srv->srv_tls_config));
339fe006a11Sclaudio 			return (-1);
340fe006a11Sclaudio 		}
341fe006a11Sclaudio 		tls_config_add_ticket_key(srv->srv_tls_config,
342fe006a11Sclaudio 		    srv->srv_conf.tls_ticket_key.tt_keyrev,
343fe006a11Sclaudio 		    srv->srv_conf.tls_ticket_key.tt_key,
344fe006a11Sclaudio 		    sizeof(srv->srv_conf.tls_ticket_key.tt_key));
345fe006a11Sclaudio 		explicit_bzero(&srv->srv_conf.tls_ticket_key,
346fe006a11Sclaudio 		    sizeof(srv->srv_conf.tls_ticket_key));
347fe006a11Sclaudio 	}
348fe006a11Sclaudio 
3490e3bc1d9Sjsing 	if (tls_configure(srv->srv_tls_ctx, srv->srv_tls_config) != 0) {
35090ddef02Sjsing 		log_warnx("%s: failed to configure tls - %s", __func__,
3510e3bc1d9Sjsing 		    tls_error(srv->srv_tls_ctx));
3523fe67476Sreyk 		return (-1);
3533fe67476Sreyk 	}
3543fe67476Sreyk 
3551d0dc528Sjsing 	/* We're now done with the public/private key & ca/crl... */
3560e3bc1d9Sjsing 	tls_config_clear_keys(srv->srv_tls_config);
35751deda34Sderaadt 	freezero(srv->srv_conf.tls_cert, srv->srv_conf.tls_cert_len);
35851deda34Sderaadt 	freezero(srv->srv_conf.tls_key, srv->srv_conf.tls_key_len);
3591d0dc528Sjsing 	free(srv->srv_conf.tls_ca);
3601d0dc528Sjsing 	free(srv->srv_conf.tls_crl);
3611d0dc528Sjsing 	srv->srv_conf.tls_ca = NULL;
362a760b3d3Sreyk 	srv->srv_conf.tls_cert = NULL;
3631d0dc528Sjsing 	srv->srv_conf.tls_crl = NULL;
364a760b3d3Sreyk 	srv->srv_conf.tls_key = NULL;
3651d0dc528Sjsing 	srv->srv_conf.tls_ca_len = 0;
366a760b3d3Sreyk 	srv->srv_conf.tls_cert_len = 0;
3671d0dc528Sjsing 	srv->srv_conf.tls_crl_len = 0;
368a760b3d3Sreyk 	srv->srv_conf.tls_key_len = 0;
36945767b45Sjsing 
3703fe67476Sreyk 	return (0);
3713fe67476Sreyk }
3723fe67476Sreyk 
373b7b6a941Sreyk void
server_generate_ticket_key(struct server_config * srv_conf)374fe006a11Sclaudio server_generate_ticket_key(struct server_config *srv_conf)
375fe006a11Sclaudio {
376fe006a11Sclaudio 	struct server_tls_ticket *key = &srv_conf->tls_ticket_key;
377fe006a11Sclaudio 
378fe006a11Sclaudio 	key->tt_id = srv_conf->id;
379fe006a11Sclaudio 	key->tt_keyrev = arc4random();
380fe006a11Sclaudio 	arc4random_buf(key->tt_key, sizeof(key->tt_key));
381fe006a11Sclaudio }
382fe006a11Sclaudio 
383fe006a11Sclaudio void
server_init(struct privsep * ps,struct privsep_proc * p,void * arg)384b7b6a941Sreyk server_init(struct privsep *ps, struct privsep_proc *p, void *arg)
385b7b6a941Sreyk {
386781985a7Srzalamena 	server_http();
387b7b6a941Sreyk 
388b7b6a941Sreyk 	if (config_init(ps->ps_env) == -1)
389b7b6a941Sreyk 		fatal("failed to initialize configuration");
390b7b6a941Sreyk 
391b7b6a941Sreyk 	/* We use a custom shutdown callback */
392b7b6a941Sreyk 	p->p_shutdown = server_shutdown;
393b7b6a941Sreyk 
394b7b6a941Sreyk 	/* Unlimited file descriptors (use system limits) */
395b7b6a941Sreyk 	socket_rlimit(-1);
396b7b6a941Sreyk 
3971019da98Sflorian 	if (pledge("stdio rpath inet unix recvfd", NULL) == -1)
3981019da98Sflorian 		fatal("pledge");
3991019da98Sflorian 
400b7b6a941Sreyk #if 0
401b7b6a941Sreyk 	/* Schedule statistics timer */
402781985a7Srzalamena 	evtimer_set(&ps->ps_env->sc_statev, server_statistics, NULL);
403781985a7Srzalamena 	memcpy(&tv, &ps->ps_env->sc_statinterval, sizeof(tv));
404781985a7Srzalamena 	evtimer_add(&ps->ps_env->sc_statev, &tv);
405b7b6a941Sreyk #endif
406b7b6a941Sreyk }
407b7b6a941Sreyk 
408b7b6a941Sreyk void
server_launch(void)409b7b6a941Sreyk server_launch(void)
410b7b6a941Sreyk {
411b7b6a941Sreyk 	struct server		*srv;
412b7b6a941Sreyk 
413781985a7Srzalamena 	TAILQ_FOREACH(srv, httpd_env->sc_servers, srv_entry) {
4141851096aSjsing 		log_debug("%s: configuring server %s", __func__,
4151851096aSjsing 		    srv->srv_conf.name);
4161851096aSjsing 
417a760b3d3Sreyk 		server_tls_init(srv);
418b7b6a941Sreyk 		server_http_init(srv);
419b7b6a941Sreyk 
420b7b6a941Sreyk 		log_debug("%s: running server %s", __func__,
421b7b6a941Sreyk 		    srv->srv_conf.name);
422b7b6a941Sreyk 
423b7b6a941Sreyk 		event_set(&srv->srv_ev, srv->srv_s, EV_READ,
424b7b6a941Sreyk 		    server_accept, srv);
425b7b6a941Sreyk 		event_add(&srv->srv_ev, NULL);
426b7b6a941Sreyk 		evtimer_set(&srv->srv_evt, server_accept, srv);
427b7b6a941Sreyk 	}
428b7b6a941Sreyk }
429b7b6a941Sreyk 
430b4ec2d25Sreyk void
server_purge(struct server * srv)431b4ec2d25Sreyk server_purge(struct server *srv)
432b4ec2d25Sreyk {
433b4ec2d25Sreyk 	struct client		*clt;
434d9bba0abSreyk 	struct server_config	*srv_conf;
435b4ec2d25Sreyk 
436b4ec2d25Sreyk 	/* shutdown and remove server */
437b4ec2d25Sreyk 	if (event_initialized(&srv->srv_ev))
438b4ec2d25Sreyk 		event_del(&srv->srv_ev);
439b4ec2d25Sreyk 	if (evtimer_initialized(&srv->srv_evt))
440b4ec2d25Sreyk 		evtimer_del(&srv->srv_evt);
441b4ec2d25Sreyk 
44227fb06b4Sreyk 	if (srv->srv_s != -1)
443b4ec2d25Sreyk 		close(srv->srv_s);
444781985a7Srzalamena 	TAILQ_REMOVE(httpd_env->sc_servers, srv, srv_entry);
445b4ec2d25Sreyk 
446b4ec2d25Sreyk 	/* cleanup sessions */
447b4ec2d25Sreyk 	while ((clt =
448b4ec2d25Sreyk 	    SPLAY_ROOT(&srv->srv_clients)) != NULL)
449b4ec2d25Sreyk 		server_close(clt, NULL);
450b4ec2d25Sreyk 
451d9bba0abSreyk 	/* cleanup hosts */
452d9bba0abSreyk 	while ((srv_conf =
453d9bba0abSreyk 	    TAILQ_FIRST(&srv->srv_hosts)) != NULL) {
454d9bba0abSreyk 		TAILQ_REMOVE(&srv->srv_hosts, srv_conf, entry);
455d9bba0abSreyk 
456d9bba0abSreyk 		/* It might point to our own "default" entry */
45745767b45Sjsing 		if (srv_conf != &srv->srv_conf) {
458bd1bab2fSreyk 			serverconfig_free(srv_conf);
459d9bba0abSreyk 			free(srv_conf);
460d9bba0abSreyk 		}
46145767b45Sjsing 	}
462d9bba0abSreyk 
4630e3bc1d9Sjsing 	tls_config_free(srv->srv_tls_config);
4640e3bc1d9Sjsing 	tls_free(srv->srv_tls_ctx);
4653fe67476Sreyk 
466b4ec2d25Sreyk 	free(srv);
467b4ec2d25Sreyk }
468b4ec2d25Sreyk 
469bd1bab2fSreyk void
serverconfig_free(struct server_config * srv_conf)470bd1bab2fSreyk serverconfig_free(struct server_config *srv_conf)
471bd1bab2fSreyk {
47203cb893cSpirofti 	struct fastcgi_param	*param, *tparam;
47303cb893cSpirofti 
474f8932becSreyk 	free(srv_conf->return_uri);
4751d0dc528Sjsing 	free(srv_conf->tls_ca_file);
4761d0dc528Sjsing 	free(srv_conf->tls_ca);
477a760b3d3Sreyk 	free(srv_conf->tls_cert_file);
4781d0dc528Sjsing 	free(srv_conf->tls_crl_file);
4791d0dc528Sjsing 	free(srv_conf->tls_crl);
480a760b3d3Sreyk 	free(srv_conf->tls_key_file);
481e80948e2Sbeck 	free(srv_conf->tls_ocsp_staple_file);
482e80948e2Sbeck 	free(srv_conf->tls_ocsp_staple);
48351deda34Sderaadt 	freezero(srv_conf->tls_cert, srv_conf->tls_cert_len);
48451deda34Sderaadt 	freezero(srv_conf->tls_key, srv_conf->tls_key_len);
48503cb893cSpirofti 
48603cb893cSpirofti 	TAILQ_FOREACH_SAFE(param, &srv_conf->fcgiparams, entry, tparam)
48703cb893cSpirofti 		free(param);
488587aaf48Sjsing }
489bd1bab2fSreyk 
490bd1bab2fSreyk void
serverconfig_reset(struct server_config * srv_conf)491bd1bab2fSreyk serverconfig_reset(struct server_config *srv_conf)
492bd1bab2fSreyk {
493602531d9Sreyk 	srv_conf->auth = NULL;
494587aaf48Sjsing 	srv_conf->return_uri = NULL;
4951d0dc528Sjsing 	srv_conf->tls_ca = NULL;
4961d0dc528Sjsing 	srv_conf->tls_ca_file = NULL;
497587aaf48Sjsing 	srv_conf->tls_cert = NULL;
498587aaf48Sjsing 	srv_conf->tls_cert_file = NULL;
4991d0dc528Sjsing 	srv_conf->tls_crl = NULL;
5001d0dc528Sjsing 	srv_conf->tls_crl_file = NULL;
501587aaf48Sjsing 	srv_conf->tls_key = NULL;
502587aaf48Sjsing 	srv_conf->tls_key_file = NULL;
503e80948e2Sbeck 	srv_conf->tls_ocsp_staple = NULL;
504e80948e2Sbeck 	srv_conf->tls_ocsp_staple_file = NULL;
50503cb893cSpirofti 	TAILQ_INIT(&srv_conf->fcgiparams);
506bd1bab2fSreyk }
507bd1bab2fSreyk 
508d9bba0abSreyk struct server *
server_byaddr(struct sockaddr * addr,in_port_t port)5090bac6c35Sreyk server_byaddr(struct sockaddr *addr, in_port_t port)
510d9bba0abSreyk {
511d9bba0abSreyk 	struct server	*srv;
512d9bba0abSreyk 
513781985a7Srzalamena 	TAILQ_FOREACH(srv, httpd_env->sc_servers, srv_entry) {
5140bac6c35Sreyk 		if (port == srv->srv_conf.port &&
5150bac6c35Sreyk 		    sockaddr_cmp((struct sockaddr *)&srv->srv_conf.ss,
516d9bba0abSreyk 		    addr, srv->srv_conf.prefixlen) == 0)
517d9bba0abSreyk 			return (srv);
518d9bba0abSreyk 	}
519d9bba0abSreyk 
520d9bba0abSreyk 	return (NULL);
521d9bba0abSreyk }
522d9bba0abSreyk 
523cf605f40Sreyk struct server_config *
serverconfig_byid(uint32_t id)5244703e0faSreyk serverconfig_byid(uint32_t id)
525cf605f40Sreyk {
526cf605f40Sreyk 	struct server		*srv;
527cf605f40Sreyk 	struct server_config	*srv_conf;
528cf605f40Sreyk 
529781985a7Srzalamena 	TAILQ_FOREACH(srv, httpd_env->sc_servers, srv_entry) {
530cf605f40Sreyk 		if (srv->srv_conf.id == id)
531cf605f40Sreyk 			return (&srv->srv_conf);
532cf605f40Sreyk 		TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
533cf605f40Sreyk 			if (srv_conf->id == id)
534cf605f40Sreyk 				return (srv_conf);
535cf605f40Sreyk 		}
536cf605f40Sreyk 	}
537cf605f40Sreyk 
538cf605f40Sreyk 	return (NULL);
539cf605f40Sreyk }
540cf605f40Sreyk 
541fe006a11Sclaudio struct server *
server_byid(uint32_t id)542fe006a11Sclaudio server_byid(uint32_t id)
543fe006a11Sclaudio {
544fe006a11Sclaudio 	struct server	*srv;
545fe006a11Sclaudio 
546fe006a11Sclaudio 	TAILQ_FOREACH(srv, httpd_env->sc_servers, srv_entry) {
547fe006a11Sclaudio 		if (srv->srv_conf.id == id)
548fe006a11Sclaudio 			return (srv);
549fe006a11Sclaudio 	}
550fe006a11Sclaudio 	return (NULL);
551fe006a11Sclaudio }
552fe006a11Sclaudio 
553cf605f40Sreyk int
server_foreach(int (* srv_cb)(struct server *,struct server_config *,void *),void * arg)554cf605f40Sreyk server_foreach(int (*srv_cb)(struct server *,
555cf605f40Sreyk     struct server_config *, void *), void *arg)
556cf605f40Sreyk {
557cf605f40Sreyk 	struct server		*srv;
558cf605f40Sreyk 	struct server_config	*srv_conf;
559cf605f40Sreyk 
560781985a7Srzalamena 	TAILQ_FOREACH(srv, httpd_env->sc_servers, srv_entry) {
561cf605f40Sreyk 		if ((srv_cb)(srv, &srv->srv_conf, arg) == -1)
562cf605f40Sreyk 			return (-1);
563cf605f40Sreyk 		TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
564cf605f40Sreyk 			if ((srv_cb)(srv, srv_conf, arg) == -1)
565cf605f40Sreyk 				return (-1);
566cf605f40Sreyk 		}
567cf605f40Sreyk 	}
568cf605f40Sreyk 
569cf605f40Sreyk 	return (0);
570cf605f40Sreyk }
571cf605f40Sreyk 
572ceaea836Sjsing struct server *
server_match(struct server * s2,int match_name)573ceaea836Sjsing server_match(struct server *s2, int match_name)
574ceaea836Sjsing {
575ceaea836Sjsing 	struct server	*s1;
576ceaea836Sjsing 
577ceaea836Sjsing 	/* Attempt to find matching server. */
578781985a7Srzalamena 	TAILQ_FOREACH(s1, httpd_env->sc_servers, srv_entry) {
579ceaea836Sjsing 		if ((s1->srv_conf.flags & SRVFLAG_LOCATION) != 0)
580ceaea836Sjsing 			continue;
581ceaea836Sjsing 		if (match_name) {
582ceaea836Sjsing 			if (strcmp(s1->srv_conf.name, s2->srv_conf.name) != 0)
583ceaea836Sjsing 				continue;
584ceaea836Sjsing 		}
585ceaea836Sjsing 		if (s1->srv_conf.port != s2->srv_conf.port)
586ceaea836Sjsing 			continue;
587ceaea836Sjsing 		if (sockaddr_cmp(
588ceaea836Sjsing 		    (struct sockaddr *)&s1->srv_conf.ss,
589ceaea836Sjsing 		    (struct sockaddr *)&s2->srv_conf.ss,
590ceaea836Sjsing 		    s1->srv_conf.prefixlen) != 0)
591ceaea836Sjsing 			continue;
592ceaea836Sjsing 
593ceaea836Sjsing 		return (s1);
594ceaea836Sjsing 	}
595ceaea836Sjsing 
596ceaea836Sjsing 	return (NULL);
597ceaea836Sjsing }
598ceaea836Sjsing 
599b7b6a941Sreyk int
server_socket_af(struct sockaddr_storage * ss,in_port_t port)600b7b6a941Sreyk server_socket_af(struct sockaddr_storage *ss, in_port_t port)
601b7b6a941Sreyk {
602b7b6a941Sreyk 	switch (ss->ss_family) {
603b7b6a941Sreyk 	case AF_INET:
604b7b6a941Sreyk 		((struct sockaddr_in *)ss)->sin_port = port;
605b7b6a941Sreyk 		((struct sockaddr_in *)ss)->sin_len =
606b7b6a941Sreyk 		    sizeof(struct sockaddr_in);
607b7b6a941Sreyk 		break;
608b7b6a941Sreyk 	case AF_INET6:
609b7b6a941Sreyk 		((struct sockaddr_in6 *)ss)->sin6_port = port;
610b7b6a941Sreyk 		((struct sockaddr_in6 *)ss)->sin6_len =
611b7b6a941Sreyk 		    sizeof(struct sockaddr_in6);
612b7b6a941Sreyk 		break;
613b7b6a941Sreyk 	default:
614b7b6a941Sreyk 		return (-1);
615b7b6a941Sreyk 	}
616b7b6a941Sreyk 
617b7b6a941Sreyk 	return (0);
618b7b6a941Sreyk }
619b7b6a941Sreyk 
620b7b6a941Sreyk in_port_t
server_socket_getport(struct sockaddr_storage * ss)621b7b6a941Sreyk server_socket_getport(struct sockaddr_storage *ss)
622b7b6a941Sreyk {
623b7b6a941Sreyk 	switch (ss->ss_family) {
624b7b6a941Sreyk 	case AF_INET:
625b7b6a941Sreyk 		return (((struct sockaddr_in *)ss)->sin_port);
626b7b6a941Sreyk 	case AF_INET6:
627b7b6a941Sreyk 		return (((struct sockaddr_in6 *)ss)->sin6_port);
628b7b6a941Sreyk 	default:
629b7b6a941Sreyk 		return (0);
630b7b6a941Sreyk 	}
631b7b6a941Sreyk 
632b7b6a941Sreyk 	/* NOTREACHED */
633b7b6a941Sreyk 	return (0);
634b7b6a941Sreyk }
635b7b6a941Sreyk 
636b7b6a941Sreyk int
server_socket(struct sockaddr_storage * ss,in_port_t port,struct server_config * srv_conf,int fd,int reuseport)637b7b6a941Sreyk server_socket(struct sockaddr_storage *ss, in_port_t port,
638eb242fe1Sreyk     struct server_config *srv_conf, int fd, int reuseport)
639b7b6a941Sreyk {
640b7b6a941Sreyk 	struct linger	lng;
641b7b6a941Sreyk 	int		s = -1, val;
642b7b6a941Sreyk 
643b7b6a941Sreyk 	if (server_socket_af(ss, port) == -1)
644b7b6a941Sreyk 		goto bad;
645b7b6a941Sreyk 
646838637bcSreyk 	s = fd == -1 ? socket(ss->ss_family, SOCK_STREAM | SOCK_NONBLOCK,
647838637bcSreyk 	    IPPROTO_TCP) : fd;
648b7b6a941Sreyk 	if (s == -1)
649b7b6a941Sreyk 		goto bad;
650b7b6a941Sreyk 
651b7b6a941Sreyk 	/*
652b7b6a941Sreyk 	 * Socket options
653b7b6a941Sreyk 	 */
654b7b6a941Sreyk 	memset(&lng, 0, sizeof(lng));
655b7b6a941Sreyk 	if (setsockopt(s, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1)
656b7b6a941Sreyk 		goto bad;
657b7b6a941Sreyk 	if (reuseport) {
658b7b6a941Sreyk 		val = 1;
659b7b6a941Sreyk 		if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &val,
660b7b6a941Sreyk 		    sizeof(int)) == -1)
661b7b6a941Sreyk 			goto bad;
662b7b6a941Sreyk 	}
663eb242fe1Sreyk 	if (srv_conf->tcpflags & TCPFLAG_BUFSIZ) {
664eb242fe1Sreyk 		val = srv_conf->tcpbufsiz;
665b7b6a941Sreyk 		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
666b7b6a941Sreyk 		    &val, sizeof(val)) == -1)
667b7b6a941Sreyk 			goto bad;
668eb242fe1Sreyk 		val = srv_conf->tcpbufsiz;
669b7b6a941Sreyk 		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
670b7b6a941Sreyk 		    &val, sizeof(val)) == -1)
671b7b6a941Sreyk 			goto bad;
672b7b6a941Sreyk 	}
673b7b6a941Sreyk 
674b7b6a941Sreyk 	/*
675b7b6a941Sreyk 	 * IP options
676b7b6a941Sreyk 	 */
677eb242fe1Sreyk 	if (srv_conf->tcpflags & TCPFLAG_IPTTL) {
678eb242fe1Sreyk 		val = (int)srv_conf->tcpipttl;
679829b7945Sjca 		switch (ss->ss_family) {
680829b7945Sjca 		case AF_INET:
681b7b6a941Sreyk 			if (setsockopt(s, IPPROTO_IP, IP_TTL,
682b7b6a941Sreyk 			    &val, sizeof(val)) == -1)
683b7b6a941Sreyk 				goto bad;
684829b7945Sjca 			break;
685829b7945Sjca 		case AF_INET6:
686829b7945Sjca 			if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
687829b7945Sjca 			    &val, sizeof(val)) == -1)
688829b7945Sjca 				goto bad;
689829b7945Sjca 			break;
690829b7945Sjca 		}
691b7b6a941Sreyk 	}
692eb242fe1Sreyk 	if (srv_conf->tcpflags & TCPFLAG_IPMINTTL) {
693eb242fe1Sreyk 		val = (int)srv_conf->tcpipminttl;
694829b7945Sjca 		switch (ss->ss_family) {
695829b7945Sjca 		case AF_INET:
696b7b6a941Sreyk 			if (setsockopt(s, IPPROTO_IP, IP_MINTTL,
697b7b6a941Sreyk 			    &val, sizeof(val)) == -1)
698b7b6a941Sreyk 				goto bad;
699829b7945Sjca 			break;
700829b7945Sjca 		case AF_INET6:
701829b7945Sjca 			if (setsockopt(s, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
702829b7945Sjca 			    &val, sizeof(val)) == -1)
703829b7945Sjca 				goto bad;
704829b7945Sjca 			break;
705829b7945Sjca 		}
706b7b6a941Sreyk 	}
707b7b6a941Sreyk 
708b7b6a941Sreyk 	/*
709b7b6a941Sreyk 	 * TCP options
710b7b6a941Sreyk 	 */
711eb242fe1Sreyk 	if (srv_conf->tcpflags & (TCPFLAG_NODELAY|TCPFLAG_NNODELAY)) {
712eb242fe1Sreyk 		if (srv_conf->tcpflags & TCPFLAG_NNODELAY)
713b7b6a941Sreyk 			val = 0;
714b7b6a941Sreyk 		else
715b7b6a941Sreyk 			val = 1;
716b7b6a941Sreyk 		if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
717b7b6a941Sreyk 		    &val, sizeof(val)) == -1)
718b7b6a941Sreyk 			goto bad;
719b7b6a941Sreyk 	}
720eb242fe1Sreyk 	if (srv_conf->tcpflags & (TCPFLAG_SACK|TCPFLAG_NSACK)) {
721eb242fe1Sreyk 		if (srv_conf->tcpflags & TCPFLAG_NSACK)
722b7b6a941Sreyk 			val = 0;
723b7b6a941Sreyk 		else
724b7b6a941Sreyk 			val = 1;
725b7b6a941Sreyk 		if (setsockopt(s, IPPROTO_TCP, TCP_SACK_ENABLE,
726b7b6a941Sreyk 		    &val, sizeof(val)) == -1)
727b7b6a941Sreyk 			goto bad;
728b7b6a941Sreyk 	}
729b7b6a941Sreyk 
730b7b6a941Sreyk 	return (s);
731b7b6a941Sreyk 
732b7b6a941Sreyk  bad:
733b7b6a941Sreyk 	if (s != -1)
734b7b6a941Sreyk 		close(s);
735b7b6a941Sreyk 	return (-1);
736b7b6a941Sreyk }
737b7b6a941Sreyk 
738b7b6a941Sreyk int
server_socket_listen(struct sockaddr_storage * ss,in_port_t port,struct server_config * srv_conf)739b7b6a941Sreyk server_socket_listen(struct sockaddr_storage *ss, in_port_t port,
740eb242fe1Sreyk     struct server_config *srv_conf)
741b7b6a941Sreyk {
742b7b6a941Sreyk 	int s;
743b7b6a941Sreyk 
744eb242fe1Sreyk 	if ((s = server_socket(ss, port, srv_conf, -1, 1)) == -1)
745b7b6a941Sreyk 		return (-1);
746b7b6a941Sreyk 
747b7b6a941Sreyk 	if (bind(s, (struct sockaddr *)ss, ss->ss_len) == -1)
748b7b6a941Sreyk 		goto bad;
749eb242fe1Sreyk 	if (listen(s, srv_conf->tcpbacklog) == -1)
750b7b6a941Sreyk 		goto bad;
751b7b6a941Sreyk 
752b7b6a941Sreyk 	return (s);
753b7b6a941Sreyk 
754b7b6a941Sreyk  bad:
755b7b6a941Sreyk 	close(s);
756b7b6a941Sreyk 	return (-1);
757b7b6a941Sreyk }
758b7b6a941Sreyk 
75922049912Sreyk int
server_socket_connect(struct sockaddr_storage * ss,in_port_t port,struct server_config * srv_conf)76022049912Sreyk server_socket_connect(struct sockaddr_storage *ss, in_port_t port,
76122049912Sreyk     struct server_config *srv_conf)
76222049912Sreyk {
76322049912Sreyk 	int	s;
76422049912Sreyk 
76522049912Sreyk 	if ((s = server_socket(ss, port, srv_conf, -1, 0)) == -1)
76622049912Sreyk 		return (-1);
76722049912Sreyk 
76822049912Sreyk 	if (connect(s, (struct sockaddr *)ss, ss->ss_len) == -1) {
76922049912Sreyk 		if (errno != EINPROGRESS)
77022049912Sreyk 			goto bad;
77122049912Sreyk 	}
77222049912Sreyk 
77322049912Sreyk 	return (s);
77422049912Sreyk 
77522049912Sreyk  bad:
77622049912Sreyk 	close(s);
77722049912Sreyk 	return (-1);
77822049912Sreyk }
77922049912Sreyk 
780b7b6a941Sreyk void
server_tls_readcb(int fd,short event,void * arg)781a760b3d3Sreyk server_tls_readcb(int fd, short event, void *arg)
7823fe67476Sreyk {
7833fe67476Sreyk 	struct bufferevent	*bufev = arg;
7843fe67476Sreyk 	struct client		*clt = bufev->cbarg;
7853fe67476Sreyk 	char			 rbuf[IBUF_READ_SIZE];
7863fe67476Sreyk 	int			 what = EVBUFFER_READ;
7873fe67476Sreyk 	int			 howmuch = IBUF_READ_SIZE;
788ffd81ea8Sbeck 	ssize_t			 ret;
7893fe67476Sreyk 	size_t			 len;
7903fe67476Sreyk 
7913fe67476Sreyk 	if (event == EV_TIMEOUT) {
7923fe67476Sreyk 		what |= EVBUFFER_TIMEOUT;
7933fe67476Sreyk 		goto err;
7943fe67476Sreyk 	}
7953fe67476Sreyk 
7963fe67476Sreyk 	if (bufev->wm_read.high != 0)
797b9fc9a72Sderaadt 		howmuch = MINIMUM(sizeof(rbuf), bufev->wm_read.high);
7983fe67476Sreyk 
799a7250ab5Sbeck 	ret = tls_read(clt->clt_tls_ctx, rbuf, howmuch);
800a7250ab5Sbeck 	if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) {
8013fe67476Sreyk 		goto retry;
802df69c215Sderaadt 	} else if (ret == -1) {
8033fe67476Sreyk 		what |= EVBUFFER_ERROR;
8043fe67476Sreyk 		goto err;
8053fe67476Sreyk 	}
806a7250ab5Sbeck 	len = ret;
8073fe67476Sreyk 
808349d1103Sjsing 	if (len == 0) {
809349d1103Sjsing 		what |= EVBUFFER_EOF;
810349d1103Sjsing 		goto err;
811349d1103Sjsing 	}
812349d1103Sjsing 
8133fe67476Sreyk 	if (evbuffer_add(bufev->input, rbuf, len) == -1) {
8143fe67476Sreyk 		what |= EVBUFFER_ERROR;
8153fe67476Sreyk 		goto err;
8163fe67476Sreyk 	}
8173fe67476Sreyk 
8183fe67476Sreyk 	server_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
8193fe67476Sreyk 
8203fe67476Sreyk 	len = EVBUFFER_LENGTH(bufev->input);
8213fe67476Sreyk 	if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
8223fe67476Sreyk 		return;
8233fe67476Sreyk 	if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) {
8243fe67476Sreyk 		struct evbuffer *buf = bufev->input;
8253fe67476Sreyk 		event_del(&bufev->ev_read);
8263fe67476Sreyk 		evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
8273fe67476Sreyk 		return;
8283fe67476Sreyk 	}
8293fe67476Sreyk 
8303fe67476Sreyk 	if (bufev->readcb != NULL)
8313fe67476Sreyk 		(*bufev->readcb)(bufev, bufev->cbarg);
8323fe67476Sreyk 	return;
8333fe67476Sreyk 
8343fe67476Sreyk  retry:
8353fe67476Sreyk 	server_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
8363fe67476Sreyk 	return;
8373fe67476Sreyk 
8383fe67476Sreyk  err:
8393fe67476Sreyk 	(*bufev->errorcb)(bufev, what, bufev->cbarg);
8403fe67476Sreyk }
8413fe67476Sreyk 
8423fe67476Sreyk void
server_tls_writecb(int fd,short event,void * arg)843a760b3d3Sreyk server_tls_writecb(int fd, short event, void *arg)
8443fe67476Sreyk {
8453fe67476Sreyk 	struct bufferevent	*bufev = arg;
8463fe67476Sreyk 	struct client		*clt = bufev->cbarg;
847ffd81ea8Sbeck 	ssize_t			 ret;
8483fe67476Sreyk 	short			 what = EVBUFFER_WRITE;
8493fe67476Sreyk 	size_t			 len;
8503fe67476Sreyk 
8513fe67476Sreyk 	if (event == EV_TIMEOUT) {
8523fe67476Sreyk 		what |= EVBUFFER_TIMEOUT;
8533fe67476Sreyk 		goto err;
8543fe67476Sreyk 	}
8553fe67476Sreyk 
8563fe67476Sreyk 	if (EVBUFFER_LENGTH(bufev->output)) {
857e68b7a5aSreyk 		ret = tls_write(clt->clt_tls_ctx,
858e68b7a5aSreyk 		    EVBUFFER_DATA(bufev->output),
859a7250ab5Sbeck 		    EVBUFFER_LENGTH(bufev->output));
860a7250ab5Sbeck 		if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) {
8613fe67476Sreyk 			goto retry;
862df69c215Sderaadt 		} else if (ret == -1) {
8633fe67476Sreyk 			what |= EVBUFFER_ERROR;
8643fe67476Sreyk 			goto err;
8653fe67476Sreyk 		}
866a7250ab5Sbeck 		len = ret;
8673fe67476Sreyk 		evbuffer_drain(bufev->output, len);
8683fe67476Sreyk 	}
8693fe67476Sreyk 
8703fe67476Sreyk 	if (EVBUFFER_LENGTH(bufev->output) != 0)
8713fe67476Sreyk 		server_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
8723fe67476Sreyk 
8733fe67476Sreyk 	if (bufev->writecb != NULL &&
8743fe67476Sreyk 	    EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
8753fe67476Sreyk 		(*bufev->writecb)(bufev, bufev->cbarg);
8763fe67476Sreyk 	return;
8773fe67476Sreyk 
8783fe67476Sreyk  retry:
8793fe67476Sreyk 	server_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
8803fe67476Sreyk 	return;
8813fe67476Sreyk 
8823fe67476Sreyk  err:
8833fe67476Sreyk 	(*bufev->errorcb)(bufev, what, bufev->cbarg);
8843fe67476Sreyk }
8853fe67476Sreyk 
8863fe67476Sreyk void
server_input(struct client * clt)887b7b6a941Sreyk server_input(struct client *clt)
888b7b6a941Sreyk {
8899fb8351aSreyk 	struct server_config	*srv_conf = clt->clt_srv_conf;
890b7b6a941Sreyk 	evbuffercb		 inrd = server_read;
891b7b6a941Sreyk 	evbuffercb		 inwr = server_write;
892720c14e5Sreyk 	socklen_t		 slen;
893b7b6a941Sreyk 
894b7b6a941Sreyk 	if (server_httpdesc_init(clt) == -1) {
8953fe67476Sreyk 		server_close(clt, "failed to allocate http descriptor");
896b7b6a941Sreyk 		return;
897b7b6a941Sreyk 	}
898b7b6a941Sreyk 
899833d1df9Sbenno 	clt->clt_toread = TOREAD_HTTP_HEADER;
900b7b6a941Sreyk 	inrd = server_read_http;
901b7b6a941Sreyk 
902720c14e5Sreyk 	slen = sizeof(clt->clt_sndbufsiz);
903720c14e5Sreyk 	if (getsockopt(clt->clt_s, SOL_SOCKET, SO_SNDBUF,
904720c14e5Sreyk 	    &clt->clt_sndbufsiz, &slen) == -1) {
905720c14e5Sreyk 		server_close(clt, "failed to get send buffer size");
906720c14e5Sreyk 		return;
907720c14e5Sreyk 	}
908720c14e5Sreyk 
909b7b6a941Sreyk 	/*
910b7b6a941Sreyk 	 * Client <-> Server
911b7b6a941Sreyk 	 */
912b7b6a941Sreyk 	clt->clt_bev = bufferevent_new(clt->clt_s, inrd, inwr,
913b7b6a941Sreyk 	    server_error, clt);
914b7b6a941Sreyk 	if (clt->clt_bev == NULL) {
915b7b6a941Sreyk 		server_close(clt, "failed to allocate input buffer event");
916b7b6a941Sreyk 		return;
917b7b6a941Sreyk 	}
918b7b6a941Sreyk 
919a760b3d3Sreyk 	if (srv_conf->flags & SRVFLAG_TLS) {
9203fe67476Sreyk 		event_set(&clt->clt_bev->ev_read, clt->clt_s, EV_READ,
921a760b3d3Sreyk 		    server_tls_readcb, clt->clt_bev);
9223fe67476Sreyk 		event_set(&clt->clt_bev->ev_write, clt->clt_s, EV_WRITE,
923a760b3d3Sreyk 		    server_tls_writecb, clt->clt_bev);
9243fe67476Sreyk 	}
9253fe67476Sreyk 
926720c14e5Sreyk 	/* Adjust write watermark to the socket buffer output size */
927720c14e5Sreyk 	bufferevent_setwatermark(clt->clt_bev, EV_WRITE,
928e62aeaeeSflorian 	    SERVER_MIN_PREFETCHED * clt->clt_sndbufsiz, 0);
929b6a65335Sflorian 	/* Read at most amount of data that fits in one fcgi record. */
930b6a65335Sflorian 	bufferevent_setwatermark(clt->clt_bev, EV_READ, 0, FCGI_CONTENT_SIZE);
931720c14e5Sreyk 
932b7b6a941Sreyk 	bufferevent_settimeout(clt->clt_bev,
933da1a1214Sreyk 	    srv_conf->requesttimeout.tv_sec, srv_conf->requesttimeout.tv_sec);
934b7b6a941Sreyk 	bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE);
935b7b6a941Sreyk }
936b7b6a941Sreyk 
937b7b6a941Sreyk void
server_write(struct bufferevent * bev,void * arg)938b7b6a941Sreyk server_write(struct bufferevent *bev, void *arg)
939b7b6a941Sreyk {
940b7b6a941Sreyk 	struct client		*clt = arg;
9415fa30660Sreyk 	struct evbuffer		*dst = EVBUFFER_OUTPUT(bev);
9425fa30660Sreyk 
9435fa30660Sreyk 	if (EVBUFFER_LENGTH(dst) == 0 &&
9445fa30660Sreyk 	    clt->clt_toread == TOREAD_HTTP_NONE)
9455fa30660Sreyk 		goto done;
946b7b6a941Sreyk 
947b7b6a941Sreyk 	getmonotime(&clt->clt_tv_last);
948b7b6a941Sreyk 
949b7b6a941Sreyk 	if (clt->clt_done)
950b7b6a941Sreyk 		goto done;
9512cadac13Sreyk 
952f3e6e694Sflorian 	if (clt->clt_srvbev && clt->clt_srvbev_throttled) {
953e62aeaeeSflorian 		bufferevent_enable(clt->clt_srvbev, EV_READ);
954f3e6e694Sflorian 		clt->clt_srvbev_throttled = 0;
955f3e6e694Sflorian 	}
956e62aeaeeSflorian 
957b7b6a941Sreyk 	return;
958b7b6a941Sreyk  done:
959d523c5c7Sreyk 	(*bev->errorcb)(bev, EVBUFFER_WRITE, bev->cbarg);
960b7b6a941Sreyk 	return;
961b7b6a941Sreyk }
962b7b6a941Sreyk 
963b7b6a941Sreyk void
server_dump(struct client * clt,const void * buf,size_t len)964b7b6a941Sreyk server_dump(struct client *clt, const void *buf, size_t len)
965b7b6a941Sreyk {
966b7b6a941Sreyk 	if (!len)
967b7b6a941Sreyk 		return;
968b7b6a941Sreyk 
969b7b6a941Sreyk 	/*
970b7b6a941Sreyk 	 * This function will dump the specified message directly
971b7b6a941Sreyk 	 * to the underlying client, without waiting for success
972b7b6a941Sreyk 	 * of non-blocking events etc. This is useful to print an
973b7b6a941Sreyk 	 * error message before gracefully closing the client.
974b7b6a941Sreyk 	 */
9750e3bc1d9Sjsing 	if (clt->clt_tls_ctx != NULL)
976a7250ab5Sbeck 		(void)tls_write(clt->clt_tls_ctx, buf, len);
977b7b6a941Sreyk 	else
978b7b6a941Sreyk 		(void)write(clt->clt_s, buf, len);
979b7b6a941Sreyk }
980b7b6a941Sreyk 
981b7b6a941Sreyk void
server_read(struct bufferevent * bev,void * arg)982b7b6a941Sreyk server_read(struct bufferevent *bev, void *arg)
983b7b6a941Sreyk {
984b7b6a941Sreyk 	struct client		*clt = arg;
985b7b6a941Sreyk 	struct evbuffer		*src = EVBUFFER_INPUT(bev);
986b7b6a941Sreyk 
987b7b6a941Sreyk 	getmonotime(&clt->clt_tv_last);
988b7b6a941Sreyk 
989b7b6a941Sreyk 	if (!EVBUFFER_LENGTH(src))
990b7b6a941Sreyk 		return;
991b7b6a941Sreyk 	if (server_bufferevent_write_buffer(clt, src) == -1)
992b7b6a941Sreyk 		goto fail;
993b7b6a941Sreyk 	if (clt->clt_done)
994b7b6a941Sreyk 		goto done;
995e62aeaeeSflorian 
996e62aeaeeSflorian 	if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(clt->clt_bev)) > (size_t)
997f3e6e694Sflorian 	    SERVER_MAX_PREFETCH * clt->clt_sndbufsiz) {
998f3e6e694Sflorian 		bufferevent_disable(clt->clt_srvbev, EV_READ);
999f3e6e694Sflorian 		clt->clt_srvbev_throttled = 1;
1000f3e6e694Sflorian 	}
1001e62aeaeeSflorian 
1002b7b6a941Sreyk 	return;
1003b7b6a941Sreyk  done:
1004d523c5c7Sreyk 	(*bev->errorcb)(bev, EVBUFFER_READ, bev->cbarg);
1005b7b6a941Sreyk 	return;
1006b7b6a941Sreyk  fail:
1007b7b6a941Sreyk 	server_close(clt, strerror(errno));
1008b7b6a941Sreyk }
1009b7b6a941Sreyk 
1010b7b6a941Sreyk void
server_error(struct bufferevent * bev,short error,void * arg)1011b7b6a941Sreyk server_error(struct bufferevent *bev, short error, void *arg)
1012b7b6a941Sreyk {
1013b7b6a941Sreyk 	struct client		*clt = arg;
101430109be5Sreyk 	struct evbuffer		*dst;
1015b7b6a941Sreyk 
1016b7b6a941Sreyk 	if (error & EVBUFFER_TIMEOUT) {
10174995d90aSflorian 		if (!clt->clt_headersdone && clt->clt_line > 0)
1018da1a1214Sreyk 			server_abort_http(clt, 408, "timeout");
10194995d90aSflorian 		else
10204995d90aSflorian 			server_close(clt, "timeout");
1021b7b6a941Sreyk 		return;
1022b7b6a941Sreyk 	}
102318b6a227Sreyk 	if (error & EVBUFFER_ERROR) {
102418b6a227Sreyk 		if (errno == EFBIG) {
102518b6a227Sreyk 			bufferevent_enable(bev, EV_READ);
102618b6a227Sreyk 			return;
102718b6a227Sreyk 		}
102818b6a227Sreyk 		server_close(clt, "buffer event error");
102918b6a227Sreyk 		return;
103018b6a227Sreyk 	}
1031d523c5c7Sreyk 	if (error & EVBUFFER_EOF) {
1032d523c5c7Sreyk 		server_close(clt, "closed");
1033d523c5c7Sreyk 		return;
1034d523c5c7Sreyk 	}
1035d523c5c7Sreyk 	if (error & (EVBUFFER_READ|EVBUFFER_WRITE)) {
1036b7b6a941Sreyk 		bufferevent_disable(bev, EV_READ|EV_WRITE);
1037b7b6a941Sreyk 
1038b7b6a941Sreyk 		clt->clt_done = 1;
103930109be5Sreyk 
104030109be5Sreyk 		dst = EVBUFFER_OUTPUT(clt->clt_bev);
104130109be5Sreyk 		if (EVBUFFER_LENGTH(dst)) {
104230109be5Sreyk 			/* Finish writing all data first */
104330109be5Sreyk 			bufferevent_enable(clt->clt_bev, EV_WRITE);
104430109be5Sreyk 			return;
104530109be5Sreyk 		}
104630109be5Sreyk 
104720a974a2Sreyk 		server_close(clt, "done");
1048b7b6a941Sreyk 		return;
1049b7b6a941Sreyk 	}
105018b6a227Sreyk 	server_close(clt, "unknown event error");
1051b7b6a941Sreyk 	return;
1052b7b6a941Sreyk }
1053b7b6a941Sreyk 
1054b7b6a941Sreyk void
server_accept(int fd,short event,void * arg)1055b7b6a941Sreyk server_accept(int fd, short event, void *arg)
1056b7b6a941Sreyk {
1057b7b6a941Sreyk 	struct server		*srv = arg;
1058b7b6a941Sreyk 	struct client		*clt = NULL;
1059b7b6a941Sreyk 	socklen_t		 slen;
1060b7b6a941Sreyk 	struct sockaddr_storage	 ss;
1061b7b6a941Sreyk 	int			 s = -1;
1062b7b6a941Sreyk 
1063b7b6a941Sreyk 	event_add(&srv->srv_ev, NULL);
1064b7b6a941Sreyk 	if ((event & EV_TIMEOUT))
1065b7b6a941Sreyk 		return;
1066b7b6a941Sreyk 
1067b7b6a941Sreyk 	slen = sizeof(ss);
1068b7b6a941Sreyk 	if ((s = accept_reserve(fd, (struct sockaddr *)&ss,
1069b7b6a941Sreyk 	    &slen, FD_RESERVE, &server_inflight)) == -1) {
1070b7b6a941Sreyk 		/*
1071b7b6a941Sreyk 		 * Pause accept if we are out of file descriptors, or
1072b7b6a941Sreyk 		 * libevent will haunt us here too.
1073b7b6a941Sreyk 		 */
1074b7b6a941Sreyk 		if (errno == ENFILE || errno == EMFILE) {
1075b7b6a941Sreyk 			struct timeval evtpause = { 1, 0 };
1076b7b6a941Sreyk 
1077b7b6a941Sreyk 			event_del(&srv->srv_ev);
1078b7b6a941Sreyk 			evtimer_add(&srv->srv_evt, &evtpause);
1079b7b6a941Sreyk 			log_debug("%s: deferring connections", __func__);
1080b7b6a941Sreyk 		}
1081b7b6a941Sreyk 		return;
1082b7b6a941Sreyk 	}
1083b7b6a941Sreyk 	if (server_clients >= SERVER_MAX_CLIENTS)
1084b7b6a941Sreyk 		goto err;
1085b7b6a941Sreyk 
1086b7b6a941Sreyk 	if ((clt = calloc(1, sizeof(*clt))) == NULL)
1087b7b6a941Sreyk 		goto err;
1088b7b6a941Sreyk 
108949b1a9b1Sflorian 	/* Pre-allocate log buffer */
109049b1a9b1Sflorian 	clt->clt_log = evbuffer_new();
109149b1a9b1Sflorian 	if (clt->clt_log == NULL)
109249b1a9b1Sflorian 		goto err;
109349b1a9b1Sflorian 
1094b7b6a941Sreyk 	clt->clt_s = s;
1095b7b6a941Sreyk 	clt->clt_fd = -1;
1096b7b6a941Sreyk 	clt->clt_toread = TOREAD_UNLIMITED;
10971940bab6Sreyk 	clt->clt_srv = srv;
10989fb8351aSreyk 	clt->clt_srv_conf = &srv->srv_conf;
1099b7b6a941Sreyk 	clt->clt_id = ++server_cltid;
11001940bab6Sreyk 	clt->clt_srv_id = srv->srv_conf.id;
1101b7b6a941Sreyk 	clt->clt_pid = getpid();
110212312c27Sreyk 	clt->clt_inflight = 1;
11036af43371Sreyk 
11046af43371Sreyk 	/* get local address */
11056af43371Sreyk 	slen = sizeof(clt->clt_srv_ss);
11066af43371Sreyk 	if (getsockname(s, (struct sockaddr *)&clt->clt_srv_ss,
11076af43371Sreyk 	    &slen) == -1) {
11086af43371Sreyk 		server_close(clt, "listen address lookup failed");
11096af43371Sreyk 		return;
11106af43371Sreyk 	}
11116af43371Sreyk 
11126af43371Sreyk 	/* get client address */
11136af43371Sreyk 	memcpy(&clt->clt_ss, &ss, sizeof(clt->clt_ss));
11146af43371Sreyk 
11156af43371Sreyk 	/* get ports */
1116b7b6a941Sreyk 	switch (ss.ss_family) {
1117b7b6a941Sreyk 	case AF_INET:
1118b7b6a941Sreyk 		clt->clt_port = ((struct sockaddr_in *)&ss)->sin_port;
1119b7b6a941Sreyk 		break;
1120b7b6a941Sreyk 	case AF_INET6:
1121b7b6a941Sreyk 		clt->clt_port = ((struct sockaddr_in6 *)&ss)->sin6_port;
1122b7b6a941Sreyk 		break;
1123b7b6a941Sreyk 	}
1124b7b6a941Sreyk 
1125b7b6a941Sreyk 	getmonotime(&clt->clt_tv_start);
1126b7b6a941Sreyk 	memcpy(&clt->clt_tv_last, &clt->clt_tv_start, sizeof(clt->clt_tv_last));
1127b7b6a941Sreyk 
1128b7b6a941Sreyk 	server_clients++;
1129b7b6a941Sreyk 	SPLAY_INSERT(client_tree, &srv->srv_clients, clt);
1130b7b6a941Sreyk 
1131b7b6a941Sreyk 	/* Pre-allocate output buffer */
1132b7b6a941Sreyk 	clt->clt_output = evbuffer_new();
1133b7b6a941Sreyk 	if (clt->clt_output == NULL) {
1134b7b6a941Sreyk 		server_close(clt, "failed to allocate output buffer");
1135b7b6a941Sreyk 		return;
1136b7b6a941Sreyk 	}
1137b7b6a941Sreyk 
1138a760b3d3Sreyk 	if (srv->srv_conf.flags & SRVFLAG_TLS) {
113998ba4714Sjsing 		if (tls_accept_socket(srv->srv_tls_ctx, &clt->clt_tls_ctx,
114098ba4714Sjsing 		    clt->clt_s) != 0) {
114160348d93Stb 			server_close(clt, "failed to accept tls socket");
114298ba4714Sjsing 			return;
114398ba4714Sjsing 		}
11443fe67476Sreyk 		event_again(&clt->clt_ev, clt->clt_s, EV_TIMEOUT|EV_READ,
11459211a933Sreyk 		    server_tls_handshake, &clt->clt_tv_start,
11463fe67476Sreyk 		    &srv->srv_conf.timeout, clt);
11473fe67476Sreyk 		return;
11483fe67476Sreyk 	}
11493fe67476Sreyk 
1150b7b6a941Sreyk 	server_input(clt);
1151b7b6a941Sreyk 	return;
1152b7b6a941Sreyk 
1153b7b6a941Sreyk  err:
1154b7b6a941Sreyk 	if (s != -1) {
1155b7b6a941Sreyk 		close(s);
1156b7b6a941Sreyk 		free(clt);
1157b7b6a941Sreyk 		/*
11587fc69e4aSjsing 		 * the client struct was not completely set up, but still
1159b7b6a941Sreyk 		 * counted as an inflight client. account for this.
1160b7b6a941Sreyk 		 */
116128569998Sflorian 		server_inflight_dec(NULL, __func__);
1162b7b6a941Sreyk 	}
1163b7b6a941Sreyk }
1164b7b6a941Sreyk 
1165b7b6a941Sreyk void
server_tls_handshake(int fd,short event,void * arg)11669211a933Sreyk server_tls_handshake(int fd, short event, void *arg)
11673fe67476Sreyk {
11683fe67476Sreyk 	struct client *clt = (struct client *)arg;
11693fe67476Sreyk 	struct server *srv = (struct server *)clt->clt_srv;
11703fe67476Sreyk 	int ret;
11713fe67476Sreyk 
11723fe67476Sreyk 	if (event == EV_TIMEOUT) {
117390ddef02Sjsing 		server_close(clt, "tls handshake timeout");
11743fe67476Sreyk 		return;
11753fe67476Sreyk 	}
11763fe67476Sreyk 
117790a4b04eSjsing 	if (srv->srv_tls_ctx == NULL || clt->clt_tls_ctx == NULL)
11780e3bc1d9Sjsing 		fatalx("NULL tls context");
11793fe67476Sreyk 
118098ba4714Sjsing 	ret = tls_handshake(clt->clt_tls_ctx);
118190a4b04eSjsing 	if (ret == 0) {
118290a4b04eSjsing 		server_input(clt);
118390a4b04eSjsing 	} else if (ret == TLS_WANT_POLLIN) {
11843fe67476Sreyk 		event_again(&clt->clt_ev, clt->clt_s, EV_TIMEOUT|EV_READ,
11859211a933Sreyk 		    server_tls_handshake, &clt->clt_tv_start,
11863fe67476Sreyk 		    &srv->srv_conf.timeout, clt);
1187a7250ab5Sbeck 	} else if (ret == TLS_WANT_POLLOUT) {
11883fe67476Sreyk 		event_again(&clt->clt_ev, clt->clt_s, EV_TIMEOUT|EV_WRITE,
11899211a933Sreyk 		    server_tls_handshake, &clt->clt_tv_start,
11903fe67476Sreyk 		    &srv->srv_conf.timeout, clt);
119190a4b04eSjsing 	} else {
1192cc3b04ccSreyk 		log_debug("%s: tls handshake failed - %s", __func__,
119398ba4714Sjsing 		    tls_error(clt->clt_tls_ctx));
119490ddef02Sjsing 		server_close(clt, "tls handshake failed");
11953fe67476Sreyk 	}
11963fe67476Sreyk }
11973fe67476Sreyk 
11983fe67476Sreyk void
server_inflight_dec(struct client * clt,const char * why)119912312c27Sreyk server_inflight_dec(struct client *clt, const char *why)
120012312c27Sreyk {
120112312c27Sreyk 	if (clt != NULL) {
120212312c27Sreyk 		/* the flight already left inflight mode. */
120312312c27Sreyk 		if (clt->clt_inflight == 0)
120412312c27Sreyk 			return;
120512312c27Sreyk 		clt->clt_inflight = 0;
120612312c27Sreyk 	}
120712312c27Sreyk 
120812312c27Sreyk 	/* the file was never opened, thus this was an inflight client. */
120912312c27Sreyk 	server_inflight--;
121031d279f7Sreyk 	DPRINTF("%s: inflight decremented, now %d, %s",
121112312c27Sreyk 	    __func__, server_inflight, why);
121212312c27Sreyk }
121312312c27Sreyk 
121412312c27Sreyk void
server_sendlog(struct server_config * srv_conf,int cmd,const char * emsg,...)1215cf605f40Sreyk server_sendlog(struct server_config *srv_conf, int cmd, const char *emsg, ...)
1216844c3615Sreyk {
1217844c3615Sreyk 	va_list		 ap;
1218844c3615Sreyk 	char		*msg;
1219844c3615Sreyk 	int		 ret;
1220cf605f40Sreyk 	struct iovec	 iov[2];
1221cf605f40Sreyk 
1222cf605f40Sreyk 	if (srv_conf->flags & SRVFLAG_SYSLOG) {
1223b8117a0aSjsg 		va_start(ap, emsg);
1224cf605f40Sreyk 		if (cmd == IMSG_LOG_ACCESS)
1225cf605f40Sreyk 			vlog(LOG_INFO, emsg, ap);
1226cf605f40Sreyk 		else
1227cf605f40Sreyk 			vlog(LOG_DEBUG, emsg, ap);
1228b8117a0aSjsg 		va_end(ap);
1229cf605f40Sreyk 		return;
1230cf605f40Sreyk 	}
1231844c3615Sreyk 
1232844c3615Sreyk 	va_start(ap, emsg);
1233844c3615Sreyk 	ret = vasprintf(&msg, emsg, ap);
1234844c3615Sreyk 	va_end(ap);
1235844c3615Sreyk 	if (ret == -1) {
1236844c3615Sreyk 		log_warn("%s: vasprintf", __func__);
1237844c3615Sreyk 		return;
1238844c3615Sreyk 	}
1239844c3615Sreyk 
1240cf605f40Sreyk 	iov[0].iov_base = &srv_conf->id;
1241cf605f40Sreyk 	iov[0].iov_len = sizeof(srv_conf->id);
1242cf605f40Sreyk 	iov[1].iov_base = msg;
124375e9e6e5Stb 	iov[1].iov_len = ret + 1;
1244844c3615Sreyk 
1245781985a7Srzalamena 	if (proc_composev(httpd_env->sc_ps, PROC_LOGGER, cmd, iov, 2) != 0) {
124659ac4ec7Sjsing 		log_warn("%s: failed to compose imsg", __func__);
124775e9e6e5Stb 		free(msg);
124859ac4ec7Sjsing 		return;
124959ac4ec7Sjsing 	}
125075e9e6e5Stb 	free(msg);
1251844c3615Sreyk }
1252844c3615Sreyk 
1253844c3615Sreyk void
server_log(struct client * clt,const char * msg)1254944a3fefSreyk server_log(struct client *clt, const char *msg)
125527b71aedSreyk {
1256b9fc9a72Sderaadt 	char			 ibuf[HOST_NAME_MAX+1], obuf[HOST_NAME_MAX+1];
1257944a3fefSreyk 	struct server_config	*srv_conf = clt->clt_srv_conf;
1258ba87bb65Sreyk 	char			*ptr = NULL, *vmsg = NULL;
1259cf605f40Sreyk 	int			 debug_cmd = -1;
1260844c3615Sreyk 
1261944a3fefSreyk 	switch (srv_conf->logformat) {
1262944a3fefSreyk 	case LOG_FORMAT_CONNECTION:
1263cf605f40Sreyk 		debug_cmd = IMSG_LOG_ACCESS;
1264944a3fefSreyk 		break;
1265944a3fefSreyk 	default:
1266871fc12cSreyk 		if (log_getverbose() > 1)
1267cf605f40Sreyk 			debug_cmd = IMSG_LOG_ERROR;
1268944a3fefSreyk 		if (EVBUFFER_LENGTH(clt->clt_log)) {
1269944a3fefSreyk 			while ((ptr =
1270944a3fefSreyk 			    evbuffer_readline(clt->clt_log)) != NULL) {
1271cf605f40Sreyk 				server_sendlog(srv_conf,
1272cf605f40Sreyk 				    IMSG_LOG_ACCESS, "%s", ptr);
127327b71aedSreyk 				free(ptr);
127427b71aedSreyk 			}
127527b71aedSreyk 		}
1276944a3fefSreyk 		break;
1277944a3fefSreyk 	}
1278944a3fefSreyk 
1279cf605f40Sreyk 	if (debug_cmd != -1 && msg != NULL) {
1280876a82a2Sreyk 		memset(ibuf, 0, sizeof(ibuf));
1281876a82a2Sreyk 		memset(obuf, 0, sizeof(obuf));
1282944a3fefSreyk 		(void)print_host(&clt->clt_ss, ibuf, sizeof(ibuf));
1283944a3fefSreyk 		(void)server_http_host(&clt->clt_srv_ss, obuf, sizeof(obuf));
1284944a3fefSreyk 		if (EVBUFFER_LENGTH(clt->clt_log) &&
1285944a3fefSreyk 		    evbuffer_add_printf(clt->clt_log, "\n") != -1)
1286944a3fefSreyk 			ptr = evbuffer_readline(clt->clt_log);
1287ba87bb65Sreyk 		(void)stravis(&vmsg, msg, HTTPD_LOGVIS);
1288cf605f40Sreyk 		server_sendlog(srv_conf, debug_cmd, "server %s, "
1289944a3fefSreyk 		    "client %d (%d active), %s:%u -> %s, "
1290944a3fefSreyk 		    "%s%s%s", srv_conf->name, clt->clt_id, server_clients,
1291ba87bb65Sreyk 		    ibuf, ntohs(clt->clt_port), obuf, vmsg == NULL ? "" : vmsg,
1292944a3fefSreyk 		    ptr == NULL ? "" : ",", ptr == NULL ? "" : ptr);
1293ba87bb65Sreyk 		free(vmsg);
1294944a3fefSreyk 		free(ptr);
1295944a3fefSreyk 	}
1296944a3fefSreyk }
129727b71aedSreyk 
129827b71aedSreyk void
server_close(struct client * clt,const char * msg)1299b7b6a941Sreyk server_close(struct client *clt, const char *msg)
1300b7b6a941Sreyk {
13011940bab6Sreyk 	struct server		*srv = clt->clt_srv;
1302b7b6a941Sreyk 
1303*76ed9045Smillert 	if (clt->clt_fcgi_count-- > 0) {
1304ebfb0322Stb 		clt->clt_fcgi_error = msg;
1305ebfb0322Stb 		return;
1306ebfb0322Stb 	}
1307ebfb0322Stb 
1308b7b6a941Sreyk 	SPLAY_REMOVE(client_tree, &srv->srv_clients, clt);
1309b7b6a941Sreyk 
131044ed0680Sreyk 	/* free the HTTP descriptors incl. headers */
131144ed0680Sreyk 	server_close_http(clt);
131244ed0680Sreyk 
13130ef1049eStb 	/* tls_close must be called before the underlying socket is closed. */
13140ef1049eStb 	if (clt->clt_tls_ctx != NULL)
13150ef1049eStb 		tls_close(clt->clt_tls_ctx); /* XXX - error handling */
13160ef1049eStb 	tls_free(clt->clt_tls_ctx);
13170ef1049eStb 
1318b7b6a941Sreyk 	event_del(&clt->clt_ev);
1319b7b6a941Sreyk 	if (clt->clt_bev != NULL)
1320b7b6a941Sreyk 		bufferevent_disable(clt->clt_bev, EV_READ|EV_WRITE);
1321151a32cfSreyk 	if (clt->clt_srvbev != NULL)
1322151a32cfSreyk 		bufferevent_disable(clt->clt_srvbev, EV_READ|EV_WRITE);
1323b7b6a941Sreyk 
1324944a3fefSreyk 	server_log(clt, msg);
1325b7b6a941Sreyk 
1326b7b6a941Sreyk 	if (clt->clt_bev != NULL)
1327b7b6a941Sreyk 		bufferevent_free(clt->clt_bev);
132844ed0680Sreyk 	if (clt->clt_output != NULL)
1329b7b6a941Sreyk 		evbuffer_free(clt->clt_output);
133019d2af9eSflorian 	if (clt->clt_srvevb != NULL)
133119d2af9eSflorian 		evbuffer_free(clt->clt_srvevb);
1332b7b6a941Sreyk 
1333151a32cfSreyk 	if (clt->clt_srvbev != NULL)
1334151a32cfSreyk 		bufferevent_free(clt->clt_srvbev);
13354a4801beStb 
1336b7b6a941Sreyk 	if (clt->clt_fd != -1)
1337b7b6a941Sreyk 		close(clt->clt_fd);
133812312c27Sreyk 	if (clt->clt_s != -1)
1339b7b6a941Sreyk 		close(clt->clt_s);
134012312c27Sreyk 
134112312c27Sreyk 	server_inflight_dec(clt, __func__);
1342b7b6a941Sreyk 
1343b7b6a941Sreyk 	if (clt->clt_log != NULL)
1344b7b6a941Sreyk 		evbuffer_free(clt->clt_log);
1345b7b6a941Sreyk 
1346b7b6a941Sreyk 	free(clt);
1347b7b6a941Sreyk 	server_clients--;
1348b7b6a941Sreyk }
1349b7b6a941Sreyk 
1350b7b6a941Sreyk int
server_dispatch_parent(int fd,struct privsep_proc * p,struct imsg * imsg)1351b7b6a941Sreyk server_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
1352b7b6a941Sreyk {
1353fe006a11Sclaudio 	struct server			*srv;
1354fe006a11Sclaudio 	struct server_tls_ticket	 key;
1355fe006a11Sclaudio 
1356b7b6a941Sreyk 	switch (imsg->hdr.type) {
13579b9ff8ecSreyk 	case IMSG_CFG_MEDIA:
1358781985a7Srzalamena 		config_getmedia(httpd_env, imsg);
13599b9ff8ecSreyk 		break;
1360602531d9Sreyk 	case IMSG_CFG_AUTH:
1361781985a7Srzalamena 		config_getauth(httpd_env, imsg);
1362602531d9Sreyk 		break;
1363b7b6a941Sreyk 	case IMSG_CFG_SERVER:
1364781985a7Srzalamena 		config_getserver(httpd_env, imsg);
1365b7b6a941Sreyk 		break;
13666f8bdc86Sjsing 	case IMSG_CFG_TLS:
136788ad1069Sjsing 		config_getserver_tls(httpd_env, imsg);
13686f8bdc86Sjsing 		break;
136903cb893cSpirofti 	case IMSG_CFG_FCGI:
137003cb893cSpirofti 		config_getserver_fcgiparams(httpd_env, imsg);
137103cb893cSpirofti 		break;
1372b7b6a941Sreyk 	case IMSG_CFG_DONE:
1373781985a7Srzalamena 		config_getcfg(httpd_env, imsg);
1374b7b6a941Sreyk 		break;
1375b7b6a941Sreyk 	case IMSG_CTL_START:
1376b7b6a941Sreyk 		server_launch();
1377b7b6a941Sreyk 		break;
1378b7b6a941Sreyk 	case IMSG_CTL_RESET:
1379781985a7Srzalamena 		config_getreset(httpd_env, imsg);
1380b7b6a941Sreyk 		break;
1381fe006a11Sclaudio 	case IMSG_TLSTICKET_REKEY:
1382fe006a11Sclaudio 		IMSG_SIZE_CHECK(imsg, (&key));
1383fe006a11Sclaudio 		memcpy(&key, imsg->data, sizeof(key));
1384fe006a11Sclaudio 		/* apply to the right server */
1385fe006a11Sclaudio 		srv = server_byid(key.tt_id);
1386fe006a11Sclaudio 		if (srv) {
1387fe006a11Sclaudio 			tls_config_add_ticket_key(srv->srv_tls_config,
1388fe006a11Sclaudio 			    key.tt_keyrev, key.tt_key, sizeof(key.tt_key));
1389fe006a11Sclaudio 		}
1390fe006a11Sclaudio 		break;
1391b7b6a941Sreyk 	default:
1392b7b6a941Sreyk 		return (-1);
1393b7b6a941Sreyk 	}
1394b7b6a941Sreyk 
1395b7b6a941Sreyk 	return (0);
1396b7b6a941Sreyk }
1397b7b6a941Sreyk 
1398b7b6a941Sreyk int
server_dispatch_logger(int fd,struct privsep_proc * p,struct imsg * imsg)1399844c3615Sreyk server_dispatch_logger(int fd, struct privsep_proc *p, struct imsg *imsg)
1400844c3615Sreyk {
1401844c3615Sreyk 	switch (imsg->hdr.type) {
1402844c3615Sreyk 	default:
1403844c3615Sreyk 		return (-1);
1404844c3615Sreyk 	}
1405844c3615Sreyk 
1406844c3615Sreyk 	return (0);
1407844c3615Sreyk }
1408844c3615Sreyk 
1409844c3615Sreyk int
server_bufferevent_add(struct event * ev,int timeout)1410b7b6a941Sreyk server_bufferevent_add(struct event *ev, int timeout)
1411b7b6a941Sreyk {
1412b7b6a941Sreyk 	struct timeval tv, *ptv = NULL;
1413b7b6a941Sreyk 
1414b7b6a941Sreyk 	if (timeout) {
1415b7b6a941Sreyk 		timerclear(&tv);
1416b7b6a941Sreyk 		tv.tv_sec = timeout;
1417b7b6a941Sreyk 		ptv = &tv;
1418b7b6a941Sreyk 	}
1419b7b6a941Sreyk 
1420b7b6a941Sreyk 	return (event_add(ev, ptv));
1421b7b6a941Sreyk }
1422b7b6a941Sreyk 
1423b7b6a941Sreyk int
server_bufferevent_printf(struct client * clt,const char * fmt,...)14242e7af781Sreyk server_bufferevent_printf(struct client *clt, const char *fmt, ...)
14252e7af781Sreyk {
14262e7af781Sreyk 	int	 ret;
14272e7af781Sreyk 	va_list	 ap;
14282e7af781Sreyk 	char	*str;
14292e7af781Sreyk 
14302e7af781Sreyk 	va_start(ap, fmt);
14312e7af781Sreyk 	ret = vasprintf(&str, fmt, ap);
14322e7af781Sreyk 	va_end(ap);
14332e7af781Sreyk 
14342e7af781Sreyk 	if (ret == -1)
14352e7af781Sreyk 		return (ret);
14362e7af781Sreyk 
14372e7af781Sreyk 	ret = server_bufferevent_print(clt, str);
14382e7af781Sreyk 	free(str);
14392e7af781Sreyk 
14402e7af781Sreyk 	return (ret);
14412e7af781Sreyk }
14422e7af781Sreyk 
14432e7af781Sreyk int
server_bufferevent_print(struct client * clt,const char * str)1444b7b6a941Sreyk server_bufferevent_print(struct client *clt, const char *str)
1445b7b6a941Sreyk {
1446b7b6a941Sreyk 	if (clt->clt_bev == NULL)
1447b7b6a941Sreyk 		return (evbuffer_add(clt->clt_output, str, strlen(str)));
1448b7b6a941Sreyk 	return (bufferevent_write(clt->clt_bev, str, strlen(str)));
1449b7b6a941Sreyk }
1450b7b6a941Sreyk 
1451b7b6a941Sreyk int
server_bufferevent_write_buffer(struct client * clt,struct evbuffer * buf)1452b7b6a941Sreyk server_bufferevent_write_buffer(struct client *clt, struct evbuffer *buf)
1453b7b6a941Sreyk {
1454b7b6a941Sreyk 	if (clt->clt_bev == NULL)
1455b7b6a941Sreyk 		return (evbuffer_add_buffer(clt->clt_output, buf));
1456b7b6a941Sreyk 	return (bufferevent_write_buffer(clt->clt_bev, buf));
1457b7b6a941Sreyk }
1458b7b6a941Sreyk 
1459b7b6a941Sreyk int
server_bufferevent_write_chunk(struct client * clt,struct evbuffer * buf,size_t size)1460b7b6a941Sreyk server_bufferevent_write_chunk(struct client *clt,
1461b7b6a941Sreyk     struct evbuffer *buf, size_t size)
1462b7b6a941Sreyk {
1463b7b6a941Sreyk 	int ret;
1464d7c13c3fSnicm 	ret = server_bufferevent_write(clt, EVBUFFER_DATA(buf), size);
1465b7b6a941Sreyk 	if (ret != -1)
1466b7b6a941Sreyk 		evbuffer_drain(buf, size);
1467b7b6a941Sreyk 	return (ret);
1468b7b6a941Sreyk }
1469b7b6a941Sreyk 
1470b7b6a941Sreyk int
server_bufferevent_write(struct client * clt,void * data,size_t size)1471b7b6a941Sreyk server_bufferevent_write(struct client *clt, void *data, size_t size)
1472b7b6a941Sreyk {
1473b7b6a941Sreyk 	if (clt->clt_bev == NULL)
1474b7b6a941Sreyk 		return (evbuffer_add(clt->clt_output, data, size));
1475b7b6a941Sreyk 	return (bufferevent_write(clt->clt_bev, data, size));
1476b7b6a941Sreyk }
1477b7b6a941Sreyk 
1478b7b6a941Sreyk int
server_client_cmp(struct client * a,struct client * b)1479b7b6a941Sreyk server_client_cmp(struct client *a, struct client *b)
1480b7b6a941Sreyk {
1481b7b6a941Sreyk 	return ((int)a->clt_id - b->clt_id);
1482b7b6a941Sreyk }
1483b7b6a941Sreyk 
1484b7b6a941Sreyk SPLAY_GENERATE(client_tree, client, clt_nodes, server_client_cmp);
1485