xref: /openbsd-src/usr.sbin/httpd/config.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: config.c,v 1.2 2014/07/13 14:17:37 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 2011 - 2014 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/socket.h>
21 #include <sys/stat.h>
22 #include <sys/queue.h>
23 #include <sys/uio.h>
24 
25 #include <net/if.h>
26 #include <net/pfvar.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <arpa/nameser.h>
30 #include <net/route.h>
31 
32 #include <ctype.h>
33 #include <unistd.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <event.h>
37 #include <limits.h>
38 #include <stdint.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <netdb.h>
42 #include <string.h>
43 #include <ifaddrs.h>
44 
45 #include <openssl/ssl.h>
46 
47 #include "httpd.h"
48 
49 int
50 config_init(struct httpd *env)
51 {
52 	struct privsep	*ps = env->sc_ps;
53 	u_int		 what;
54 
55 	/* Global configuration */
56 	if (privsep_process == PROC_PARENT) {
57 		env->sc_prefork_server = SERVER_NUMPROC;
58 
59 		ps->ps_what[PROC_PARENT] = CONFIG_ALL;
60 		ps->ps_what[PROC_SERVER] = CONFIG_SERVERS|CONFIG_MEDIA;
61 	}
62 
63 	/* Other configuration */
64 	what = ps->ps_what[privsep_process];
65 
66 	if (what & CONFIG_SERVERS) {
67 		if ((env->sc_servers =
68 		    calloc(1, sizeof(*env->sc_servers))) == NULL)
69 			return (-1);
70 		TAILQ_INIT(env->sc_servers);
71 	}
72 
73 	if (what & CONFIG_MEDIA) {
74 		if ((env->sc_mediatypes =
75 		    calloc(1, sizeof(*env->sc_mediatypes))) == NULL)
76 			return (-1);
77 		RB_INIT(env->sc_mediatypes);
78 	}
79 
80 	return (0);
81 }
82 
83 void
84 config_purge(struct httpd *env, u_int reset)
85 {
86 	struct privsep		*ps = env->sc_ps;
87 	struct server		*srv;
88 	u_int			 what;
89 
90 	what = ps->ps_what[privsep_process] & reset;
91 
92 	if (what & CONFIG_SERVERS && env->sc_servers != NULL) {
93 		while ((srv = TAILQ_FIRST(env->sc_servers)) != NULL) {
94 			TAILQ_REMOVE(env->sc_servers, srv, srv_entry);
95 			free(srv);
96 		}
97 	}
98 
99 	if (what & CONFIG_MEDIA && env->sc_mediatypes != NULL)
100 		media_purge(env->sc_mediatypes);
101 }
102 
103 int
104 config_setreset(struct httpd *env, u_int reset)
105 {
106 	struct privsep	*ps = env->sc_ps;
107 	int		 id;
108 
109 	for (id = 0; id < PROC_MAX; id++) {
110 		if ((reset & ps->ps_what[id]) == 0 ||
111 		    id == privsep_process)
112 			continue;
113 		proc_compose_imsg(ps, id, -1, IMSG_CTL_RESET, -1,
114 		    &reset, sizeof(reset));
115 	}
116 
117 	return (0);
118 }
119 
120 int
121 config_getreset(struct httpd *env, struct imsg *imsg)
122 {
123 	u_int		 mode;
124 
125 	IMSG_SIZE_CHECK(imsg, &mode);
126 	memcpy(&mode, imsg->data, sizeof(mode));
127 
128 	config_purge(env, mode);
129 
130 	return (0);
131 }
132 
133 int
134 config_getcfg(struct httpd *env, struct imsg *imsg)
135 {
136 	struct privsep		*ps = env->sc_ps;
137 	struct ctl_flags	 cf;
138 	u_int			 what;
139 
140 	if (IMSG_DATA_SIZE(imsg) != sizeof(cf))
141 		return (0); /* ignore */
142 
143 	/* Update runtime flags */
144 	memcpy(&cf, imsg->data, sizeof(cf));
145 	env->sc_opts = cf.cf_opts;
146 	env->sc_flags = cf.cf_flags;
147 
148 	what = ps->ps_what[privsep_process];
149 
150 	if (privsep_process != PROC_PARENT)
151 		proc_compose_imsg(env->sc_ps, PROC_PARENT, -1,
152 		    IMSG_CFG_DONE, -1, NULL, 0);
153 
154 	return (0);
155 }
156 
157 int
158 config_setserver(struct httpd *env, struct server *srv)
159 {
160 	struct privsep		*ps = env->sc_ps;
161 	struct server_config	 s;
162 	int			 id;
163 	int			 fd, n, m;
164 	struct iovec		 iov[6];
165 	size_t			 c;
166 	u_int			 what;
167 
168 	/* opens listening sockets etc. */
169 	if (server_privinit(srv) == -1)
170 		return (-1);
171 
172 	for (id = 0; id < PROC_MAX; id++) {
173 		what = ps->ps_what[id];
174 
175 		if ((what & CONFIG_SERVERS) == 0 || id == privsep_process)
176 			continue;
177 
178 		DPRINTF("%s: sending server %s to %s fd %d", __func__,
179 		    srv->srv_conf.name, ps->ps_title[id], srv->srv_s);
180 
181 		memcpy(&s, &srv->srv_conf, sizeof(s));
182 
183 		c = 0;
184 		iov[c].iov_base = &s;
185 		iov[c++].iov_len = sizeof(s);
186 
187 		if (id == PROC_SERVER) {
188 			/* XXX imsg code will close the fd after 1st call */
189 			n = -1;
190 			proc_range(ps, id, &n, &m);
191 			for (n = 0; n < m; n++) {
192 				if ((fd = dup(srv->srv_s)) == -1)
193 					return (-1);
194 				proc_composev_imsg(ps, id, n,
195 				    IMSG_CFG_SERVER, fd, iov, c);
196 			}
197 		} else {
198 			proc_composev_imsg(ps, id, -1, IMSG_CFG_SERVER, -1,
199 			    iov, c);
200 		}
201 	}
202 
203 	close(srv->srv_s);
204 	srv->srv_s = -1;
205 
206 	return (0);
207 }
208 
209 int
210 config_getserver(struct httpd *env, struct imsg *imsg)
211 {
212 #ifdef DEBUG
213 	struct privsep		*ps = env->sc_ps;
214 #endif
215 	struct server		*srv;
216 	u_int8_t		*p = imsg->data;
217 	size_t			 s;
218 
219 	if ((srv = calloc(1, sizeof(*srv))) == NULL) {
220 		close(imsg->fd);
221 		return (-1);
222 	}
223 
224 	IMSG_SIZE_CHECK(imsg, &srv->srv_conf);
225 	memcpy(&srv->srv_conf, p, sizeof(srv->srv_conf));
226 	s = sizeof(srv->srv_conf);
227 
228 	srv->srv_s = imsg->fd;
229 
230 	SPLAY_INIT(&srv->srv_clients);
231 	TAILQ_INSERT_TAIL(env->sc_servers, srv, srv_entry);
232 
233 	DPRINTF("%s: %s %d received configuration \"%s\"", __func__,
234 	    ps->ps_title[privsep_process], ps->ps_instance,
235 	    srv->srv_conf.name);
236 
237 	return (0);
238 }
239 
240 int
241 config_setmedia(struct httpd *env, struct media_type *media)
242 {
243 	struct privsep		*ps = env->sc_ps;
244 	int			 id;
245 	u_int			 what;
246 
247 	for (id = 0; id < PROC_MAX; id++) {
248 		what = ps->ps_what[id];
249 
250 		if ((what & CONFIG_MEDIA) == 0 || id == privsep_process)
251 			continue;
252 
253 		DPRINTF("%s: sending media \"%s\" to %s", __func__,
254 		    media->media_name, ps->ps_title[id]);
255 
256 		proc_compose_imsg(ps, id, -1, IMSG_CFG_MEDIA, -1,
257 		    media, sizeof(*media));
258 	}
259 
260 	return (0);
261 }
262 
263 int
264 config_getmedia(struct httpd *env, struct imsg *imsg)
265 {
266 #ifdef DEBUG
267 	struct privsep		*ps = env->sc_ps;
268 #endif
269 	struct media_type	 media;
270 	u_int8_t		*p = imsg->data;
271 
272 	IMSG_SIZE_CHECK(imsg, &media);
273 	memcpy(&media, p, sizeof(media));
274 
275 	if (media_add(env->sc_mediatypes, &media) == NULL) {
276 		log_debug("%s: failed to add media \"%s\"",
277 		    __func__, media.media_name);
278 		return (-1);
279 	}
280 
281 	DPRINTF("%s: %s %d received media \"%s\"", __func__,
282 	    ps->ps_title[privsep_process], ps->ps_instance,
283 	    media.media_name);
284 
285 	return (0);
286 }
287