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