| File: | src/usr.sbin/httpd/httpd.c |
| Warning: | line 533, column 6 Although the value stored to 'q' is used in the enclosing expression, the value is never actually read from 'q' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: httpd.c,v 1.71 2021/01/27 07:21:52 deraadt Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 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/queue.h> |
| 21 | #include <sys/socket.h> |
| 22 | #include <sys/stat.h> |
| 23 | #include <sys/resource.h> |
| 24 | |
| 25 | #include <netinet/in.h> |
| 26 | #include <arpa/inet.h> |
| 27 | |
| 28 | #include <stdio.h> |
| 29 | #include <stdlib.h> |
| 30 | #include <stdarg.h> |
| 31 | #include <string.h> |
| 32 | #include <signal.h> |
| 33 | #include <getopt.h> |
| 34 | #include <netdb.h> |
| 35 | #include <fnmatch.h> |
| 36 | #include <err.h> |
| 37 | #include <errno(*__errno()).h> |
| 38 | #include <event.h> |
| 39 | #include <syslog.h> |
| 40 | #include <unistd.h> |
| 41 | #include <ctype.h> |
| 42 | #include <pwd.h> |
| 43 | |
| 44 | #include "httpd.h" |
| 45 | |
| 46 | #define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b)) |
| 47 | |
| 48 | __dead__attribute__((__noreturn__)) void usage(void); |
| 49 | |
| 50 | int parent_configure(struct httpd *); |
| 51 | void parent_configure_done(struct httpd *); |
| 52 | void parent_reload(struct httpd *, unsigned int, const char *); |
| 53 | void parent_reopen(struct httpd *); |
| 54 | void parent_sig_handler(int, short, void *); |
| 55 | void parent_shutdown(struct httpd *); |
| 56 | int parent_dispatch_server(int, struct privsep_proc *, |
| 57 | struct imsg *); |
| 58 | int parent_dispatch_logger(int, struct privsep_proc *, |
| 59 | struct imsg *); |
| 60 | void parent_tls_ticket_rekey_start(struct server *); |
| 61 | void parent_tls_ticket_rekey(int, short, void *); |
| 62 | |
| 63 | struct httpd *httpd_env; |
| 64 | |
| 65 | static struct privsep_proc procs[] = { |
| 66 | { "server", PROC_SERVER, parent_dispatch_server, server }, |
| 67 | { "logger", PROC_LOGGER, parent_dispatch_logger, logger } |
| 68 | }; |
| 69 | |
| 70 | enum privsep_procid privsep_process; |
| 71 | |
| 72 | void |
| 73 | parent_sig_handler(int sig, short event, void *arg) |
| 74 | { |
| 75 | struct privsep *ps = arg; |
| 76 | |
| 77 | switch (sig) { |
| 78 | case SIGTERM15: |
| 79 | case SIGINT2: |
| 80 | parent_shutdown(ps->ps_env); |
| 81 | break; |
| 82 | case SIGHUP1: |
| 83 | log_info("%s: reload requested with SIGHUP", __func__); |
| 84 | |
| 85 | /* |
| 86 | * This is safe because libevent uses async signal handlers |
| 87 | * that run in the event loop and not in signal context. |
| 88 | */ |
| 89 | parent_reload(ps->ps_env, CONFIG_RELOAD0x00, NULL((void*)0)); |
| 90 | break; |
| 91 | case SIGPIPE13: |
| 92 | /* ignore */ |
| 93 | break; |
| 94 | case SIGUSR130: |
| 95 | log_info("%s: reopen requested with SIGUSR1", __func__); |
| 96 | |
| 97 | parent_reopen(ps->ps_env); |
| 98 | break; |
| 99 | default: |
| 100 | fatalx("unexpected signal"); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | __dead__attribute__((__noreturn__)) void |
| 105 | usage(void) |
| 106 | { |
| 107 | extern char *__progname; |
| 108 | |
| 109 | fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-D macro=value] [-f file]\n", |
| 110 | __progname); |
| 111 | exit(1); |
| 112 | } |
| 113 | |
| 114 | int |
| 115 | main(int argc, char *argv[]) |
| 116 | { |
| 117 | int c; |
| 118 | unsigned int proc; |
| 119 | int debug = 0, verbose = 0; |
| 120 | uint32_t opts = 0; |
| 121 | struct httpd *env; |
| 122 | struct privsep *ps; |
| 123 | const char *conffile = CONF_FILE"/etc/httpd.conf"; |
| 124 | enum privsep_procid proc_id = PROC_PARENT; |
| 125 | int proc_instance = 0; |
| 126 | const char *errp, *title = NULL((void*)0); |
| 127 | int argc0 = argc; |
| 128 | |
| 129 | while ((c = getopt(argc, argv, "dD:nf:I:P:v")) != -1) { |
| 130 | switch (c) { |
| 131 | case 'd': |
| 132 | debug = 2; |
| 133 | break; |
| 134 | case 'D': |
| 135 | if (cmdline_symset(optarg) < 0) |
| 136 | log_warnx("could not parse macro definition %s", |
| 137 | optarg); |
| 138 | break; |
| 139 | case 'n': |
| 140 | debug = 2; |
| 141 | opts |= HTTPD_OPT_NOACTION0x04; |
| 142 | break; |
| 143 | case 'f': |
| 144 | conffile = optarg; |
| 145 | break; |
| 146 | case 'v': |
| 147 | verbose++; |
| 148 | opts |= HTTPD_OPT_VERBOSE0x01; |
| 149 | break; |
| 150 | case 'P': |
| 151 | title = optarg; |
| 152 | proc_id = proc_getid(procs, nitems(procs)(sizeof((procs)) / sizeof((procs)[0])), title); |
| 153 | if (proc_id == PROC_MAX) |
| 154 | fatalx("invalid process name"); |
| 155 | break; |
| 156 | case 'I': |
| 157 | proc_instance = strtonum(optarg, 0, |
| 158 | PROC_MAX_INSTANCES32, &errp); |
| 159 | if (errp) |
| 160 | fatalx("invalid process instance"); |
| 161 | break; |
| 162 | default: |
| 163 | usage(); |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | /* log to stderr until daemonized */ |
| 168 | log_init(debug ? debug : 1, LOG_DAEMON(3<<3)); |
| 169 | |
| 170 | argc -= optind; |
| 171 | if (argc > 0) |
| 172 | usage(); |
| 173 | |
| 174 | if ((env = calloc(1, sizeof(*env))) == NULL((void*)0) || |
| 175 | (ps = calloc(1, sizeof(*ps))) == NULL((void*)0)) |
| 176 | exit(1); |
| 177 | |
| 178 | httpd_env = env; |
| 179 | env->sc_ps = ps; |
| 180 | ps->ps_env = env; |
| 181 | TAILQ_INIT(&ps->ps_rcsocks)do { (&ps->ps_rcsocks)->tqh_first = ((void*)0); (& ps->ps_rcsocks)->tqh_last = &(&ps->ps_rcsocks )->tqh_first; } while (0); |
| 182 | env->sc_conffile = conffile; |
| 183 | env->sc_opts = opts; |
| 184 | |
| 185 | if (parse_config(env->sc_conffile, env) == -1) |
| 186 | exit(1); |
| 187 | |
| 188 | if (geteuid()) |
| 189 | errx(1, "need root privileges"); |
| 190 | |
| 191 | if ((ps->ps_pw = getpwnam(HTTPD_USER"www")) == NULL((void*)0)) |
| 192 | errx(1, "unknown user %s", HTTPD_USER"www"); |
| 193 | |
| 194 | /* Configure the control socket */ |
| 195 | ps->ps_csock.cs_name = NULL((void*)0); |
| 196 | |
| 197 | log_init(debug, LOG_DAEMON(3<<3)); |
| 198 | log_setverbose(verbose); |
| 199 | |
| 200 | if (env->sc_opts & HTTPD_OPT_NOACTION0x04) |
| 201 | ps->ps_noaction = 1; |
| 202 | |
| 203 | ps->ps_instances[PROC_SERVER] = env->sc_prefork_server; |
| 204 | ps->ps_instance = proc_instance; |
| 205 | if (title != NULL((void*)0)) |
| 206 | ps->ps_title[proc_id] = title; |
| 207 | |
| 208 | if (env->sc_chroot == NULL((void*)0)) |
| 209 | env->sc_chroot = ps->ps_pw->pw_dir; |
| 210 | for (proc = 0; proc < nitems(procs)(sizeof((procs)) / sizeof((procs)[0])); proc++) |
| 211 | procs[proc].p_chroot = env->sc_chroot; |
| 212 | |
| 213 | if (env->sc_logdir == NULL((void*)0)) { |
| 214 | if (asprintf(&env->sc_logdir, "%s%s", env->sc_chroot, |
| 215 | HTTPD_LOGROOT"/logs") == -1) |
| 216 | errx(1, "malloc failed"); |
| 217 | } |
| 218 | |
| 219 | /* only the parent returns */ |
| 220 | proc_init(ps, procs, nitems(procs)(sizeof((procs)) / sizeof((procs)[0])), debug, argc0, argv, proc_id); |
| 221 | |
| 222 | log_procinit("parent"); |
| 223 | if (!debug && daemon(1, 0) == -1) |
| 224 | err(1, "failed to daemonize"); |
| 225 | |
| 226 | if (ps->ps_noaction == 0) |
| 227 | log_info("startup"); |
| 228 | |
| 229 | if (pledge("stdio rpath wpath cpath inet dns sendfd", NULL((void*)0)) == -1) |
| 230 | fatal("pledge"); |
| 231 | |
| 232 | event_init(); |
| 233 | |
| 234 | signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps)event_set(&ps->ps_evsigint, 2, 0x08|0x10, parent_sig_handler , ps); |
| 235 | signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps)event_set(&ps->ps_evsigterm, 15, 0x08|0x10, parent_sig_handler , ps); |
| 236 | signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps)event_set(&ps->ps_evsighup, 1, 0x08|0x10, parent_sig_handler , ps); |
| 237 | signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps)event_set(&ps->ps_evsigpipe, 13, 0x08|0x10, parent_sig_handler , ps); |
| 238 | signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps)event_set(&ps->ps_evsigusr1, 30, 0x08|0x10, parent_sig_handler , ps); |
| 239 | |
| 240 | signal_add(&ps->ps_evsigint, NULL)event_add(&ps->ps_evsigint, ((void*)0)); |
| 241 | signal_add(&ps->ps_evsigterm, NULL)event_add(&ps->ps_evsigterm, ((void*)0)); |
| 242 | signal_add(&ps->ps_evsighup, NULL)event_add(&ps->ps_evsighup, ((void*)0)); |
| 243 | signal_add(&ps->ps_evsigpipe, NULL)event_add(&ps->ps_evsigpipe, ((void*)0)); |
| 244 | signal_add(&ps->ps_evsigusr1, NULL)event_add(&ps->ps_evsigusr1, ((void*)0)); |
| 245 | |
| 246 | proc_connect(ps); |
| 247 | |
| 248 | if (load_config(env->sc_conffile, env) == -1) { |
| 249 | proc_kill(env->sc_ps); |
| 250 | exit(1); |
| 251 | } |
| 252 | |
| 253 | if (env->sc_opts & HTTPD_OPT_NOACTION0x04) { |
| 254 | fprintf(stderr(&__sF[2]), "configuration OK\n"); |
| 255 | proc_kill(env->sc_ps); |
| 256 | exit(0); |
| 257 | } |
| 258 | |
| 259 | /* initialize the TLS session id to a random key for all procs */ |
| 260 | arc4random_buf(env->sc_tls_sid, sizeof(env->sc_tls_sid)); |
| 261 | |
| 262 | if (parent_configure(env) == -1) |
| 263 | fatalx("configuration failed"); |
| 264 | |
| 265 | event_dispatch(); |
| 266 | |
| 267 | parent_shutdown(env); |
| 268 | /* NOTREACHED */ |
| 269 | |
| 270 | return (0); |
| 271 | } |
| 272 | |
| 273 | int |
| 274 | parent_configure(struct httpd *env) |
| 275 | { |
| 276 | int id; |
| 277 | struct ctl_flags cf; |
| 278 | int ret = -1; |
| 279 | struct server *srv; |
| 280 | struct media_type *media; |
| 281 | struct auth *auth; |
| 282 | |
| 283 | RB_FOREACH(media, mediatypes, env->sc_mediatypes)for ((media) = mediatypes_RB_MINMAX(env->sc_mediatypes, -1 ); (media) != ((void*)0); (media) = mediatypes_RB_NEXT(media) ) { |
| 284 | if (config_setmedia(env, media) == -1) |
| 285 | fatal("send media"); |
| 286 | } |
| 287 | |
| 288 | TAILQ_FOREACH(auth, env->sc_auth, auth_entry)for((auth) = ((env->sc_auth)->tqh_first); (auth) != ((void *)0); (auth) = ((auth)->auth_entry.tqe_next)) { |
| 289 | if (config_setauth(env, auth) == -1) |
| 290 | fatal("send auth"); |
| 291 | } |
| 292 | |
| 293 | /* First send the servers... */ |
| 294 | TAILQ_FOREACH(srv, env->sc_servers, srv_entry)for((srv) = ((env->sc_servers)->tqh_first); (srv) != (( void*)0); (srv) = ((srv)->srv_entry.tqe_next)) { |
| 295 | if (srv->srv_conf.flags & SRVFLAG_LOCATION0x00000020) |
| 296 | continue; |
| 297 | /* start the rekey of the tls ticket keys */ |
| 298 | if (srv->srv_conf.flags & SRVFLAG_TLS0x00002000 && |
| 299 | srv->srv_conf.tls_ticket_lifetime) |
| 300 | parent_tls_ticket_rekey_start(srv); |
| 301 | if (config_setserver(env, srv) == -1) |
| 302 | fatal("send server"); |
| 303 | } |
| 304 | /* ...and now send the locations */ |
| 305 | TAILQ_FOREACH(srv, env->sc_servers, srv_entry)for((srv) = ((env->sc_servers)->tqh_first); (srv) != (( void*)0); (srv) = ((srv)->srv_entry.tqe_next)) { |
| 306 | if ((srv->srv_conf.flags & SRVFLAG_LOCATION0x00000020) == 0) |
| 307 | continue; |
| 308 | if (config_setserver(env, srv) == -1) |
| 309 | fatal("send location"); |
| 310 | } |
| 311 | |
| 312 | /* The servers need to reload their config. */ |
| 313 | env->sc_reload = env->sc_prefork_server + 1; |
| 314 | |
| 315 | for (id = 0; id < PROC_MAX; id++) { |
| 316 | if (id == privsep_process) |
| 317 | continue; |
| 318 | cf.cf_opts = env->sc_opts; |
| 319 | cf.cf_flags = env->sc_flags; |
| 320 | memcpy(cf.cf_tls_sid, env->sc_tls_sid, sizeof(cf.cf_tls_sid)); |
| 321 | |
| 322 | proc_compose(env->sc_ps, id, IMSG_CFG_DONE, &cf, sizeof(cf)); |
| 323 | } |
| 324 | |
| 325 | ret = 0; |
| 326 | |
| 327 | config_purge(env, CONFIG_ALL0xff & ~CONFIG_SERVERS0x02); |
| 328 | return (ret); |
| 329 | } |
| 330 | |
| 331 | void |
| 332 | parent_reload(struct httpd *env, unsigned int reset, const char *filename) |
| 333 | { |
| 334 | if (env->sc_reload) { |
| 335 | log_debug("%s: already in progress: %d pending", |
| 336 | __func__, env->sc_reload); |
| 337 | return; |
| 338 | } |
| 339 | |
| 340 | /* Switch back to the default config file */ |
| 341 | if (filename == NULL((void*)0) || *filename == '\0') |
| 342 | filename = env->sc_conffile; |
| 343 | |
| 344 | log_debug("%s: level %d config file %s", __func__, reset, filename); |
| 345 | |
| 346 | config_purge(env, CONFIG_ALL0xff); |
| 347 | |
| 348 | if (reset == CONFIG_RELOAD0x00) { |
| 349 | if (load_config(filename, env) == -1) { |
| 350 | log_debug("%s: failed to load config file %s", |
| 351 | __func__, filename); |
| 352 | } |
| 353 | |
| 354 | config_setreset(env, CONFIG_ALL0xff); |
| 355 | |
| 356 | if (parent_configure(env) == -1) { |
| 357 | log_debug("%s: failed to commit config from %s", |
| 358 | __func__, filename); |
| 359 | } |
| 360 | } else |
| 361 | config_setreset(env, reset); |
| 362 | } |
| 363 | |
| 364 | void |
| 365 | parent_reopen(struct httpd *env) |
| 366 | { |
| 367 | proc_compose(env->sc_ps, PROC_LOGGER, IMSG_CTL_REOPEN, NULL((void*)0), 0); |
| 368 | } |
| 369 | |
| 370 | void |
| 371 | parent_configure_done(struct httpd *env) |
| 372 | { |
| 373 | int id; |
| 374 | |
| 375 | if (env->sc_reload == 0) { |
| 376 | log_warnx("%s: configuration already finished", __func__); |
| 377 | return; |
| 378 | } |
| 379 | |
| 380 | env->sc_reload--; |
| 381 | if (env->sc_reload == 0) { |
| 382 | for (id = 0; id < PROC_MAX; id++) { |
| 383 | if (id == privsep_process) |
| 384 | continue; |
| 385 | |
| 386 | proc_compose(env->sc_ps, id, IMSG_CTL_START, NULL((void*)0), 0); |
| 387 | } |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | void |
| 392 | parent_shutdown(struct httpd *env) |
| 393 | { |
| 394 | config_purge(env, CONFIG_ALL0xff); |
| 395 | |
| 396 | proc_kill(env->sc_ps); |
| 397 | control_cleanup(&env->sc_ps->ps_csock); |
| 398 | if (env->sc_ps->ps_csock.cs_name != NULL((void*)0)) |
| 399 | (void)unlink(env->sc_ps->ps_csock.cs_name); |
| 400 | |
| 401 | free(env->sc_ps); |
| 402 | free(env); |
| 403 | |
| 404 | log_info("parent terminating, pid %d", getpid()); |
| 405 | |
| 406 | exit(0); |
| 407 | } |
| 408 | |
| 409 | int |
| 410 | parent_dispatch_server(int fd, struct privsep_proc *p, struct imsg *imsg) |
| 411 | { |
| 412 | struct privsep *ps = p->p_ps; |
| 413 | struct httpd *env = ps->ps_env; |
| 414 | |
| 415 | switch (imsg->hdr.type) { |
| 416 | case IMSG_CFG_DONE: |
| 417 | parent_configure_done(env); |
| 418 | break; |
| 419 | default: |
| 420 | return (-1); |
| 421 | } |
| 422 | |
| 423 | return (0); |
| 424 | } |
| 425 | |
| 426 | int |
| 427 | parent_dispatch_logger(int fd, struct privsep_proc *p, struct imsg *imsg) |
| 428 | { |
| 429 | struct privsep *ps = p->p_ps; |
| 430 | struct httpd *env = ps->ps_env; |
| 431 | unsigned int v; |
| 432 | char *str = NULL((void*)0); |
| 433 | |
| 434 | switch (imsg->hdr.type) { |
| 435 | case IMSG_CTL_RESET: |
| 436 | IMSG_SIZE_CHECK(imsg, &v)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&v)) fatalx("bad length imsg received"); } while (0); |
| 437 | memcpy(&v, imsg->data, sizeof(v)); |
| 438 | parent_reload(env, v, NULL((void*)0)); |
| 439 | break; |
| 440 | case IMSG_CTL_RELOAD: |
| 441 | if (IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) > 0) |
| 442 | str = get_string(imsg->data, IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr))); |
| 443 | parent_reload(env, CONFIG_RELOAD0x00, str); |
| 444 | free(str); |
| 445 | break; |
| 446 | case IMSG_CTL_SHUTDOWN: |
| 447 | parent_shutdown(env); |
| 448 | break; |
| 449 | case IMSG_CTL_REOPEN: |
| 450 | parent_reopen(env); |
| 451 | break; |
| 452 | case IMSG_CFG_DONE: |
| 453 | parent_configure_done(env); |
| 454 | break; |
| 455 | case IMSG_LOG_OPEN: |
| 456 | if (logger_open_priv(imsg) == -1) |
| 457 | fatalx("failed to open log file"); |
| 458 | break; |
| 459 | default: |
| 460 | return (-1); |
| 461 | } |
| 462 | |
| 463 | return (0); |
| 464 | } |
| 465 | |
| 466 | void |
| 467 | parent_tls_ticket_rekey_start(struct server *srv) |
| 468 | { |
| 469 | struct timeval tv; |
| 470 | |
| 471 | server_generate_ticket_key(&srv->srv_conf); |
| 472 | |
| 473 | evtimer_set(&srv->srv_evt, parent_tls_ticket_rekey, srv)event_set(&srv->srv_evt, -1, 0, parent_tls_ticket_rekey , srv); |
| 474 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; |
| 475 | tv.tv_sec = srv->srv_conf.tls_ticket_lifetime / 4; |
| 476 | evtimer_add(&srv->srv_evt, &tv)event_add(&srv->srv_evt, &tv); |
| 477 | } |
| 478 | |
| 479 | void |
| 480 | parent_tls_ticket_rekey(int fd, short events, void *arg) |
| 481 | { |
| 482 | struct server *srv = arg; |
| 483 | struct timeval tv; |
| 484 | |
| 485 | server_generate_ticket_key(&srv->srv_conf); |
| 486 | proc_compose_imsg(httpd_env->sc_ps, PROC_SERVER, -1, |
| 487 | IMSG_TLSTICKET_REKEY, -1, -1, &srv->srv_conf.tls_ticket_key, |
| 488 | sizeof(srv->srv_conf.tls_ticket_key)); |
| 489 | explicit_bzero(&srv->srv_conf.tls_ticket_key, |
| 490 | sizeof(srv->srv_conf.tls_ticket_key)); |
| 491 | |
| 492 | evtimer_set(&srv->srv_evt, parent_tls_ticket_rekey, srv)event_set(&srv->srv_evt, -1, 0, parent_tls_ticket_rekey , srv); |
| 493 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; |
| 494 | tv.tv_sec = srv->srv_conf.tls_ticket_lifetime / 4; |
| 495 | evtimer_add(&srv->srv_evt, &tv)event_add(&srv->srv_evt, &tv); |
| 496 | } |
| 497 | |
| 498 | /* |
| 499 | * Utility functions |
| 500 | */ |
| 501 | |
| 502 | void |
| 503 | event_again(struct event *ev, int fd, short event, |
| 504 | void (*fn)(int, short, void *), |
| 505 | struct timeval *start, struct timeval *end, void *arg) |
| 506 | { |
| 507 | struct timeval tv_next, tv_now, tv; |
| 508 | |
| 509 | getmonotime(&tv_now); |
| 510 | memcpy(&tv_next, end, sizeof(tv_next)); |
| 511 | timersub(&tv_now, start, &tv_now)do { (&tv_now)->tv_sec = (&tv_now)->tv_sec - (start )->tv_sec; (&tv_now)->tv_usec = (&tv_now)->tv_usec - (start)->tv_usec; if ((&tv_now)->tv_usec < 0) { (&tv_now)->tv_sec--; (&tv_now)->tv_usec += 1000000 ; } } while (0); |
| 512 | timersub(&tv_next, &tv_now, &tv_next)do { (&tv_next)->tv_sec = (&tv_next)->tv_sec - ( &tv_now)->tv_sec; (&tv_next)->tv_usec = (&tv_next )->tv_usec - (&tv_now)->tv_usec; if ((&tv_next) ->tv_usec < 0) { (&tv_next)->tv_sec--; (&tv_next )->tv_usec += 1000000; } } while (0); |
| 513 | |
| 514 | memset(&tv, 0, sizeof(tv)); |
| 515 | if (timercmp(&tv_next, &tv, >)(((&tv_next)->tv_sec == (&tv)->tv_sec) ? ((& tv_next)->tv_usec > (&tv)->tv_usec) : ((&tv_next )->tv_sec > (&tv)->tv_sec))) |
| 516 | memcpy(&tv, &tv_next, sizeof(tv)); |
| 517 | |
| 518 | event_del(ev); |
| 519 | event_set(ev, fd, event, fn, arg); |
| 520 | event_add(ev, &tv); |
| 521 | } |
| 522 | |
| 523 | int |
| 524 | expand_string(char *label, size_t len, const char *srch, const char *repl) |
| 525 | { |
| 526 | char *tmp; |
| 527 | char *p, *q; |
| 528 | |
| 529 | if ((tmp = calloc(1, len)) == NULL((void*)0)) { |
| 530 | log_debug("%s: calloc", __func__); |
| 531 | return (-1); |
| 532 | } |
| 533 | p = q = label; |
Although the value stored to 'q' is used in the enclosing expression, the value is never actually read from 'q' | |
| 534 | while ((q = strstr(p, srch)) != NULL((void*)0)) { |
| 535 | *q = '\0'; |
| 536 | if ((strlcat(tmp, p, len) >= len) || |
| 537 | (strlcat(tmp, repl, len) >= len)) { |
| 538 | log_debug("%s: string too long", __func__); |
| 539 | free(tmp); |
| 540 | return (-1); |
| 541 | } |
| 542 | q += strlen(srch); |
| 543 | p = q; |
| 544 | } |
| 545 | if (strlcat(tmp, p, len) >= len) { |
| 546 | log_debug("%s: string too long", __func__); |
| 547 | free(tmp); |
| 548 | return (-1); |
| 549 | } |
| 550 | (void)strlcpy(label, tmp, len); /* always fits */ |
| 551 | free(tmp); |
| 552 | |
| 553 | return (0); |
| 554 | } |
| 555 | |
| 556 | const char * |
| 557 | url_decode(char *url) |
| 558 | { |
| 559 | char *p, *q; |
| 560 | char hex[3]; |
| 561 | unsigned long x; |
| 562 | |
| 563 | hex[2] = '\0'; |
| 564 | p = q = url; |
| 565 | |
| 566 | while (*p != '\0') { |
| 567 | switch (*p) { |
| 568 | case '%': |
| 569 | /* Encoding character is followed by two hex chars */ |
| 570 | if (!(isxdigit((unsigned char)p[1]) && |
| 571 | isxdigit((unsigned char)p[2]))) |
| 572 | return (NULL((void*)0)); |
| 573 | |
| 574 | hex[0] = p[1]; |
| 575 | hex[1] = p[2]; |
| 576 | |
| 577 | /* |
| 578 | * We don't have to validate "hex" because it is |
| 579 | * guaranteed to include two hex chars followed by nul. |
| 580 | */ |
| 581 | x = strtoul(hex, NULL((void*)0), 16); |
| 582 | *q = (char)x; |
| 583 | p += 2; |
| 584 | break; |
| 585 | default: |
| 586 | *q = *p; |
| 587 | break; |
| 588 | } |
| 589 | p++; |
| 590 | q++; |
| 591 | } |
| 592 | *q = '\0'; |
| 593 | |
| 594 | return (url); |
| 595 | } |
| 596 | |
| 597 | const char * |
| 598 | canonicalize_path(const char *input, char *path, size_t len) |
| 599 | { |
| 600 | const char *i; |
| 601 | char *p, *start, *end; |
| 602 | |
| 603 | /* assuming input starts with '/' and is nul-terminated */ |
| 604 | i = input; |
| 605 | p = path; |
| 606 | |
| 607 | if (*input != '/' || len < 3) |
| 608 | return (NULL((void*)0)); |
| 609 | |
| 610 | start = p; |
| 611 | end = p + (len - 1); |
| 612 | |
| 613 | while (*i != '\0') { |
| 614 | /* Detect truncation */ |
| 615 | if (p >= end) |
| 616 | return (NULL((void*)0)); |
| 617 | |
| 618 | /* 1. check for special path elements */ |
| 619 | if (i[0] == '/') { |
| 620 | if (i[1] == '/') { |
| 621 | /* a) skip repeating '//' slashes */ |
| 622 | while (i[1] == '/') |
| 623 | i++; |
| 624 | continue; |
| 625 | } else if (i[1] == '.' && i[2] == '.' && |
| 626 | (i[3] == '/' || i[3] == '\0')) { |
| 627 | /* b) revert '..' to previous directory */ |
| 628 | i += 3; |
| 629 | while (p > start && *p != '/') |
| 630 | p--; |
| 631 | *p = '\0'; |
| 632 | continue; |
| 633 | } else if (i[1] == '.' && |
| 634 | (i[2] == '/' || i[2] == '\0')) { |
| 635 | /* c) skip unnecessary '.' current dir */ |
| 636 | i += 2; |
| 637 | continue; |
| 638 | } |
| 639 | } |
| 640 | |
| 641 | /* 2. copy any other characters */ |
| 642 | *p++ = *i; |
| 643 | i++; |
| 644 | } |
| 645 | if (p == start) |
| 646 | *p++ = '/'; |
| 647 | *p++ = '\0'; |
| 648 | |
| 649 | return (path); |
| 650 | } |
| 651 | |
| 652 | size_t |
| 653 | path_info(char *path) |
| 654 | { |
| 655 | char *p, *start, *end, ch; |
| 656 | struct stat st; |
| 657 | int ret; |
| 658 | |
| 659 | start = path; |
| 660 | end = start + strlen(path); |
| 661 | |
| 662 | for (p = end; p > start; p--) { |
| 663 | /* Scan every path component from the end and at each '/' */ |
| 664 | if (p < end && *p != '/') |
| 665 | continue; |
| 666 | |
| 667 | /* Temporarily cut the path component out */ |
| 668 | ch = *p; |
| 669 | *p = '\0'; |
| 670 | ret = stat(path, &st); |
| 671 | *p = ch; |
| 672 | |
| 673 | /* Break if the initial path component was found */ |
| 674 | if (ret == 0) |
| 675 | break; |
| 676 | } |
| 677 | |
| 678 | return (p - start); |
| 679 | } |
| 680 | |
| 681 | char * |
| 682 | url_encode(const char *src) |
| 683 | { |
| 684 | static char hex[] = "0123456789ABCDEF"; |
| 685 | char *dp, *dst; |
| 686 | unsigned char c; |
| 687 | |
| 688 | /* We need 3 times the memory if every letter is encoded. */ |
| 689 | if ((dst = calloc(3, strlen(src) + 1)) == NULL((void*)0)) |
| 690 | return (NULL((void*)0)); |
| 691 | |
| 692 | for (dp = dst; *src != 0; src++) { |
| 693 | c = (unsigned char) *src; |
| 694 | if (c == ' ' || c == '#' || c == '%' || c == '?' || c == '"' || |
| 695 | c == '&' || c == '<' || c <= 0x1f || c >= 0x7f) { |
| 696 | *dp++ = '%'; |
| 697 | *dp++ = hex[c >> 4]; |
| 698 | *dp++ = hex[c & 0x0f]; |
| 699 | } else |
| 700 | *dp++ = *src; |
| 701 | } |
| 702 | return (dst); |
| 703 | } |
| 704 | |
| 705 | char* |
| 706 | escape_html(const char* src) |
| 707 | { |
| 708 | char *dp, *dst; |
| 709 | |
| 710 | /* We need 5 times the memory if every letter is "&" */ |
| 711 | if ((dst = calloc(5, strlen(src) + 1)) == NULL((void*)0)) |
| 712 | return NULL((void*)0); |
| 713 | |
| 714 | for (dp = dst; *src != 0; src++) { |
| 715 | if (*src == '<') { |
| 716 | *dp++ = '&'; |
| 717 | *dp++ = 'l'; |
| 718 | *dp++ = 't'; |
| 719 | *dp++ = ';'; |
| 720 | } else if (*src == '>') { |
| 721 | *dp++ = '&'; |
| 722 | *dp++ = 'g'; |
| 723 | *dp++ = 't'; |
| 724 | *dp++ = ';'; |
| 725 | } else if (*src == '&') { |
| 726 | *dp++ = '&'; |
| 727 | *dp++ = 'a'; |
| 728 | *dp++ = 'm'; |
| 729 | *dp++ = 'p'; |
| 730 | *dp++ = ';'; |
| 731 | } else |
| 732 | *dp++ = *src; |
| 733 | } |
| 734 | return (dst); |
| 735 | } |
| 736 | |
| 737 | void |
| 738 | socket_rlimit(int maxfd) |
| 739 | { |
| 740 | struct rlimit rl; |
| 741 | |
| 742 | if (getrlimit(RLIMIT_NOFILE8, &rl) == -1) |
| 743 | fatal("%s: failed to get resource limit", __func__); |
| 744 | log_debug("%s: max open files %llu", __func__, rl.rlim_max); |
| 745 | |
| 746 | /* |
| 747 | * Allow the maximum number of open file descriptors for this |
| 748 | * login class (which should be the class "daemon" by default). |
| 749 | */ |
| 750 | if (maxfd == -1) |
| 751 | rl.rlim_cur = rl.rlim_max; |
| 752 | else |
| 753 | rl.rlim_cur = MAXIMUM(rl.rlim_max, (rlim_t)maxfd)(((rl.rlim_max) > ((rlim_t)maxfd)) ? (rl.rlim_max) : ((rlim_t )maxfd)); |
| 754 | if (setrlimit(RLIMIT_NOFILE8, &rl) == -1) |
| 755 | fatal("%s: failed to set resource limit", __func__); |
| 756 | } |
| 757 | |
| 758 | char * |
| 759 | evbuffer_getline(struct evbuffer *evb) |
| 760 | { |
| 761 | uint8_t *ptr = EVBUFFER_DATA(evb)(evb)->buffer; |
| 762 | size_t len = EVBUFFER_LENGTH(evb)(evb)->off; |
| 763 | char *str; |
| 764 | size_t i; |
| 765 | |
| 766 | /* Safe version of evbuffer_readline() */ |
| 767 | if ((str = get_string(ptr, len)) == NULL((void*)0)) |
| 768 | return (NULL((void*)0)); |
| 769 | |
| 770 | for (i = 0; str[i] != '\0'; i++) { |
| 771 | if (str[i] == '\r' || str[i] == '\n') |
| 772 | break; |
| 773 | } |
| 774 | |
| 775 | if (i == len) { |
| 776 | free(str); |
| 777 | return (NULL((void*)0)); |
| 778 | } |
| 779 | |
| 780 | str[i] = '\0'; |
| 781 | |
| 782 | if ((i + 1) < len) { |
| 783 | if (ptr[i] == '\r' && ptr[i + 1] == '\n') |
| 784 | i++; |
| 785 | } |
| 786 | |
| 787 | evbuffer_drain(evb, ++i); |
| 788 | |
| 789 | return (str); |
| 790 | } |
| 791 | |
| 792 | char * |
| 793 | get_string(uint8_t *ptr, size_t len) |
| 794 | { |
| 795 | size_t i; |
| 796 | |
| 797 | for (i = 0; i < len; i++) |
| 798 | if (!(isprint((unsigned char)ptr[i]) || |
| 799 | isspace((unsigned char)ptr[i]))) |
| 800 | break; |
| 801 | |
| 802 | return strndup(ptr, i); |
| 803 | } |
| 804 | |
| 805 | void * |
| 806 | get_data(uint8_t *ptr, size_t len) |
| 807 | { |
| 808 | uint8_t *data; |
| 809 | |
| 810 | if ((data = malloc(len)) == NULL((void*)0)) |
| 811 | return (NULL((void*)0)); |
| 812 | memcpy(data, ptr, len); |
| 813 | |
| 814 | return (data); |
| 815 | } |
| 816 | |
| 817 | int |
| 818 | sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen) |
| 819 | { |
| 820 | struct sockaddr_in *a4, *b4; |
| 821 | struct sockaddr_in6 *a6, *b6; |
| 822 | uint32_t av[4], bv[4], mv[4]; |
| 823 | |
| 824 | if (a->sa_family == AF_UNSPEC0 || b->sa_family == AF_UNSPEC0) |
| 825 | return (0); |
| 826 | else if (a->sa_family > b->sa_family) |
| 827 | return (1); |
| 828 | else if (a->sa_family < b->sa_family) |
| 829 | return (-1); |
| 830 | |
| 831 | if (prefixlen == -1) |
| 832 | memset(&mv, 0xff, sizeof(mv)); |
| 833 | |
| 834 | switch (a->sa_family) { |
| 835 | case AF_INET2: |
| 836 | a4 = (struct sockaddr_in *)a; |
| 837 | b4 = (struct sockaddr_in *)b; |
| 838 | |
| 839 | av[0] = a4->sin_addr.s_addr; |
| 840 | bv[0] = b4->sin_addr.s_addr; |
| 841 | if (prefixlen != -1) |
| 842 | mv[0] = prefixlen2mask(prefixlen); |
| 843 | |
| 844 | if ((av[0] & mv[0]) > (bv[0] & mv[0])) |
| 845 | return (1); |
| 846 | if ((av[0] & mv[0]) < (bv[0] & mv[0])) |
| 847 | return (-1); |
| 848 | break; |
| 849 | case AF_INET624: |
| 850 | a6 = (struct sockaddr_in6 *)a; |
| 851 | b6 = (struct sockaddr_in6 *)b; |
| 852 | |
| 853 | memcpy(&av, &a6->sin6_addr.s6_addr__u6_addr.__u6_addr8, 16); |
| 854 | memcpy(&bv, &b6->sin6_addr.s6_addr__u6_addr.__u6_addr8, 16); |
| 855 | if (prefixlen != -1) |
| 856 | prefixlen2mask6(prefixlen, mv); |
| 857 | |
| 858 | if ((av[3] & mv[3]) > (bv[3] & mv[3])) |
| 859 | return (1); |
| 860 | if ((av[3] & mv[3]) < (bv[3] & mv[3])) |
| 861 | return (-1); |
| 862 | if ((av[2] & mv[2]) > (bv[2] & mv[2])) |
| 863 | return (1); |
| 864 | if ((av[2] & mv[2]) < (bv[2] & mv[2])) |
| 865 | return (-1); |
| 866 | if ((av[1] & mv[1]) > (bv[1] & mv[1])) |
| 867 | return (1); |
| 868 | if ((av[1] & mv[1]) < (bv[1] & mv[1])) |
| 869 | return (-1); |
| 870 | if ((av[0] & mv[0]) > (bv[0] & mv[0])) |
| 871 | return (1); |
| 872 | if ((av[0] & mv[0]) < (bv[0] & mv[0])) |
| 873 | return (-1); |
| 874 | break; |
| 875 | } |
| 876 | |
| 877 | return (0); |
| 878 | } |
| 879 | |
| 880 | uint32_t |
| 881 | prefixlen2mask(uint8_t prefixlen) |
| 882 | { |
| 883 | if (prefixlen == 0) |
| 884 | return (0); |
| 885 | |
| 886 | if (prefixlen > 32) |
| 887 | prefixlen = 32; |
| 888 | |
| 889 | return (htonl(0xffffffff << (32 - prefixlen))(__uint32_t)(__builtin_constant_p(0xffffffff << (32 - prefixlen )) ? (__uint32_t)(((__uint32_t)(0xffffffff << (32 - prefixlen )) & 0xff) << 24 | ((__uint32_t)(0xffffffff << (32 - prefixlen)) & 0xff00) << 8 | ((__uint32_t)(0xffffffff << (32 - prefixlen)) & 0xff0000) >> 8 | ((__uint32_t )(0xffffffff << (32 - prefixlen)) & 0xff000000) >> 24) : __swap32md(0xffffffff << (32 - prefixlen)))); |
| 890 | } |
| 891 | |
| 892 | struct in6_addr * |
| 893 | prefixlen2mask6(uint8_t prefixlen, uint32_t *mask) |
| 894 | { |
| 895 | static struct in6_addr s6; |
| 896 | int i; |
| 897 | |
| 898 | if (prefixlen > 128) |
| 899 | prefixlen = 128; |
| 900 | |
| 901 | memset(&s6, 0, sizeof(s6)); |
| 902 | for (i = 0; i < prefixlen / 8; i++) |
| 903 | s6.s6_addr__u6_addr.__u6_addr8[i] = 0xff; |
| 904 | i = prefixlen % 8; |
| 905 | if (i) |
| 906 | s6.s6_addr__u6_addr.__u6_addr8[prefixlen / 8] = 0xff00 >> i; |
| 907 | |
| 908 | memcpy(mask, &s6, sizeof(s6)); |
| 909 | |
| 910 | return (&s6); |
| 911 | } |
| 912 | |
| 913 | int |
| 914 | accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, |
| 915 | int reserve, volatile int *counter) |
| 916 | { |
| 917 | int ret; |
| 918 | if (getdtablecount() + reserve + |
| 919 | *counter >= getdtablesize()) { |
| 920 | errno(*__errno()) = EMFILE24; |
| 921 | return (-1); |
| 922 | } |
| 923 | |
| 924 | if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK0x4000)) > -1) { |
| 925 | (*counter)++; |
| 926 | DPRINTF("%s: inflight incremented, now %d",__func__, *counter)do {} while(0); |
| 927 | } |
| 928 | return (ret); |
| 929 | } |
| 930 | |
| 931 | struct kv * |
| 932 | kv_add(struct kvtree *keys, char *key, char *value) |
| 933 | { |
| 934 | struct kv *kv, *oldkv; |
| 935 | |
| 936 | if (key == NULL((void*)0)) |
| 937 | return (NULL((void*)0)); |
| 938 | if ((kv = calloc(1, sizeof(*kv))) == NULL((void*)0)) |
| 939 | return (NULL((void*)0)); |
| 940 | if ((kv->kv_key = strdup(key)) == NULL((void*)0)) { |
| 941 | free(kv); |
| 942 | return (NULL((void*)0)); |
| 943 | } |
| 944 | if (value != NULL((void*)0) && |
| 945 | (kv->kv_value = strdup(value)) == NULL((void*)0)) { |
| 946 | free(kv->kv_key); |
| 947 | free(kv); |
| 948 | return (NULL((void*)0)); |
| 949 | } |
| 950 | TAILQ_INIT(&kv->kv_children)do { (&kv->kv_children)->tqh_first = ((void*)0); (& kv->kv_children)->tqh_last = &(&kv->kv_children )->tqh_first; } while (0); |
| 951 | |
| 952 | if ((oldkv = RB_INSERT(kvtree, keys, kv)kvtree_RB_INSERT(keys, kv)) != NULL((void*)0)) { |
| 953 | TAILQ_INSERT_TAIL(&oldkv->kv_children, kv, kv_entry)do { (kv)->kv_entry.tqe_next = ((void*)0); (kv)->kv_entry .tqe_prev = (&oldkv->kv_children)->tqh_last; *(& oldkv->kv_children)->tqh_last = (kv); (&oldkv->kv_children )->tqh_last = &(kv)->kv_entry.tqe_next; } while (0); |
| 954 | kv->kv_parent = oldkv; |
| 955 | } |
| 956 | |
| 957 | return (kv); |
| 958 | } |
| 959 | |
| 960 | int |
| 961 | kv_set(struct kv *kv, char *fmt, ...) |
| 962 | { |
| 963 | va_list ap; |
| 964 | char *value = NULL((void*)0); |
| 965 | struct kv *ckv; |
| 966 | int ret; |
| 967 | |
| 968 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
| 969 | ret = vasprintf(&value, fmt, ap); |
| 970 | va_end(ap)__builtin_va_end(ap); |
| 971 | if (ret == -1) |
| 972 | return (-1); |
| 973 | |
| 974 | /* Remove all children */ |
| 975 | while ((ckv = TAILQ_FIRST(&kv->kv_children)((&kv->kv_children)->tqh_first)) != NULL((void*)0)) { |
| 976 | TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry)do { if (((ckv)->kv_entry.tqe_next) != ((void*)0)) (ckv)-> kv_entry.tqe_next->kv_entry.tqe_prev = (ckv)->kv_entry. tqe_prev; else (&kv->kv_children)->tqh_last = (ckv) ->kv_entry.tqe_prev; *(ckv)->kv_entry.tqe_prev = (ckv)-> kv_entry.tqe_next; ; ; } while (0); |
| 977 | kv_free(ckv); |
| 978 | free(ckv); |
| 979 | } |
| 980 | |
| 981 | /* Set the new value */ |
| 982 | free(kv->kv_value); |
| 983 | kv->kv_value = value; |
| 984 | |
| 985 | return (0); |
| 986 | } |
| 987 | |
| 988 | int |
| 989 | kv_setkey(struct kv *kv, char *fmt, ...) |
| 990 | { |
| 991 | va_list ap; |
| 992 | char *key = NULL((void*)0); |
| 993 | int ret; |
| 994 | |
| 995 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
| 996 | ret = vasprintf(&key, fmt, ap); |
| 997 | va_end(ap)__builtin_va_end(ap); |
| 998 | if (ret == -1) |
| 999 | return (-1); |
| 1000 | |
| 1001 | free(kv->kv_key); |
| 1002 | kv->kv_key = key; |
| 1003 | |
| 1004 | return (0); |
| 1005 | } |
| 1006 | |
| 1007 | void |
| 1008 | kv_delete(struct kvtree *keys, struct kv *kv) |
| 1009 | { |
| 1010 | struct kv *ckv; |
| 1011 | |
| 1012 | RB_REMOVE(kvtree, keys, kv)kvtree_RB_REMOVE(keys, kv); |
| 1013 | |
| 1014 | /* Remove all children */ |
| 1015 | while ((ckv = TAILQ_FIRST(&kv->kv_children)((&kv->kv_children)->tqh_first)) != NULL((void*)0)) { |
| 1016 | TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry)do { if (((ckv)->kv_entry.tqe_next) != ((void*)0)) (ckv)-> kv_entry.tqe_next->kv_entry.tqe_prev = (ckv)->kv_entry. tqe_prev; else (&kv->kv_children)->tqh_last = (ckv) ->kv_entry.tqe_prev; *(ckv)->kv_entry.tqe_prev = (ckv)-> kv_entry.tqe_next; ; ; } while (0); |
| 1017 | kv_free(ckv); |
| 1018 | free(ckv); |
| 1019 | } |
| 1020 | |
| 1021 | kv_free(kv); |
| 1022 | free(kv); |
| 1023 | } |
| 1024 | |
| 1025 | struct kv * |
| 1026 | kv_extend(struct kvtree *keys, struct kv *kv, char *value) |
| 1027 | { |
| 1028 | char *newvalue; |
| 1029 | |
| 1030 | if (kv == NULL((void*)0)) { |
| 1031 | return (NULL((void*)0)); |
| 1032 | } else if (kv->kv_value != NULL((void*)0)) { |
| 1033 | if (asprintf(&newvalue, "%s%s", kv->kv_value, value) == -1) |
| 1034 | return (NULL((void*)0)); |
| 1035 | |
| 1036 | free(kv->kv_value); |
| 1037 | kv->kv_value = newvalue; |
| 1038 | } else if ((kv->kv_value = strdup(value)) == NULL((void*)0)) |
| 1039 | return (NULL((void*)0)); |
| 1040 | |
| 1041 | return (kv); |
| 1042 | } |
| 1043 | |
| 1044 | void |
| 1045 | kv_purge(struct kvtree *keys) |
| 1046 | { |
| 1047 | struct kv *kv; |
| 1048 | |
| 1049 | while ((kv = RB_MIN(kvtree, keys)kvtree_RB_MINMAX(keys, -1)) != NULL((void*)0)) |
| 1050 | kv_delete(keys, kv); |
| 1051 | } |
| 1052 | |
| 1053 | void |
| 1054 | kv_free(struct kv *kv) |
| 1055 | { |
| 1056 | free(kv->kv_key); |
| 1057 | kv->kv_key = NULL((void*)0); |
| 1058 | free(kv->kv_value); |
| 1059 | kv->kv_value = NULL((void*)0); |
| 1060 | memset(kv, 0, sizeof(*kv)); |
| 1061 | } |
| 1062 | |
| 1063 | struct kv * |
| 1064 | kv_find(struct kvtree *keys, struct kv *kv) |
| 1065 | { |
| 1066 | struct kv *match; |
| 1067 | const char *key; |
| 1068 | |
| 1069 | if (kv->kv_flags & KV_FLAG_GLOBBING0x02) { |
| 1070 | /* Test header key using shell globbing rules */ |
| 1071 | key = kv->kv_key == NULL((void*)0) ? "" : kv->kv_key; |
| 1072 | RB_FOREACH(match, kvtree, keys)for ((match) = kvtree_RB_MINMAX(keys, -1); (match) != ((void* )0); (match) = kvtree_RB_NEXT(match)) { |
| 1073 | if (fnmatch(key, match->kv_key, FNM_CASEFOLD0x10) == 0) |
| 1074 | break; |
| 1075 | } |
| 1076 | } else { |
| 1077 | /* Fast tree-based lookup only works without globbing */ |
| 1078 | match = RB_FIND(kvtree, keys, kv)kvtree_RB_FIND(keys, kv); |
| 1079 | } |
| 1080 | |
| 1081 | return (match); |
| 1082 | } |
| 1083 | |
| 1084 | int |
| 1085 | kv_cmp(struct kv *a, struct kv *b) |
| 1086 | { |
| 1087 | return (strcasecmp(a->kv_key, b->kv_key)); |
| 1088 | } |
| 1089 | |
| 1090 | RB_GENERATE(kvtree, kv, kv_node, kv_cmp)void kvtree_RB_INSERT_COLOR(struct kvtree *head, struct kv *elm ) { struct kv *parent, *gparent, *tmp; while ((parent = (elm) ->kv_node.rbe_parent) && (parent)->kv_node.rbe_color == 1) { gparent = (parent)->kv_node.rbe_parent; if (parent == (gparent)->kv_node.rbe_left) { tmp = (gparent)->kv_node .rbe_right; if (tmp && (tmp)->kv_node.rbe_color == 1) { (tmp)->kv_node.rbe_color = 0; do { (parent)->kv_node .rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while ( 0); elm = gparent; continue; } if ((parent)->kv_node.rbe_right == elm) { do { (tmp) = (parent)->kv_node.rbe_right; if (( (parent)->kv_node.rbe_right = (tmp)->kv_node.rbe_left)) { ((tmp)->kv_node.rbe_left)->kv_node.rbe_parent = (parent ); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (parent )->kv_node.rbe_parent)) { if ((parent) == ((parent)->kv_node .rbe_parent)->kv_node.rbe_left) ((parent)->kv_node.rbe_parent )->kv_node.rbe_left = (tmp); else ((parent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_left = (parent); (parent)->kv_node .rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node. rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->kv_node.rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while (0); do { (tmp) = (gparent)->kv_node.rbe_left; if (((gparent)->kv_node .rbe_left = (tmp)->kv_node.rbe_right)) { ((tmp)->kv_node .rbe_right)->kv_node.rbe_parent = (gparent); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (gparent)->kv_node .rbe_parent)) { if ((gparent) == ((gparent)->kv_node.rbe_parent )->kv_node.rbe_left) ((gparent)->kv_node.rbe_parent)-> kv_node.rbe_left = (tmp); else ((gparent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = (gparent); (gparent)-> kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node .rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent )->kv_node.rbe_left; if (tmp && (tmp)->kv_node. rbe_color == 1) { (tmp)->kv_node.rbe_color = 0; do { (parent )->kv_node.rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)-> kv_node.rbe_left == elm) { do { (tmp) = (parent)->kv_node. rbe_left; if (((parent)->kv_node.rbe_left = (tmp)->kv_node .rbe_right)) { ((tmp)->kv_node.rbe_right)->kv_node.rbe_parent = (parent); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node.rbe_parent)) { if ((parent) == ((parent )->kv_node.rbe_parent)->kv_node.rbe_left) ((parent)-> kv_node.rbe_parent)->kv_node.rbe_left = (tmp); else ((parent )->kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = ( parent); (parent)->kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)-> kv_node.rbe_color = 0; (gparent)->kv_node.rbe_color = 1; } while (0); do { (tmp) = (gparent)->kv_node.rbe_right; if ( ((gparent)->kv_node.rbe_right = (tmp)->kv_node.rbe_left )) { ((tmp)->kv_node.rbe_left)->kv_node.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (gparent )->kv_node.rbe_parent)) { if ((gparent) == ((gparent)-> kv_node.rbe_parent)->kv_node.rbe_left) ((gparent)->kv_node .rbe_parent)->kv_node.rbe_left = (tmp); else ((gparent)-> kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head )->rbh_root = (tmp); (tmp)->kv_node.rbe_left = (gparent ); (gparent)->kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root)->kv_node.rbe_color = 0; } void kvtree_RB_REMOVE_COLOR(struct kvtree *head, struct kv *parent , struct kv *elm) { struct kv *tmp; while ((elm == ((void*)0) || (elm)->kv_node.rbe_color == 0) && elm != (head )->rbh_root) { if ((parent)->kv_node.rbe_left == elm) { tmp = (parent)->kv_node.rbe_right; if ((tmp)->kv_node. rbe_color == 1) { do { (tmp)->kv_node.rbe_color = 0; (parent )->kv_node.rbe_color = 1; } while (0); do { (tmp) = (parent )->kv_node.rbe_right; if (((parent)->kv_node.rbe_right = (tmp)->kv_node.rbe_left)) { ((tmp)->kv_node.rbe_left)-> kv_node.rbe_parent = (parent); } do {} while (0); if (((tmp)-> kv_node.rbe_parent = (parent)->kv_node.rbe_parent)) { if ( (parent) == ((parent)->kv_node.rbe_parent)->kv_node.rbe_left ) ((parent)->kv_node.rbe_parent)->kv_node.rbe_left = (tmp ); else ((parent)->kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node .rbe_left = (parent); (parent)->kv_node.rbe_parent = (tmp) ; do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->kv_node.rbe_right; } if (((tmp)->kv_node.rbe_left == ((void*)0) || ((tmp)->kv_node .rbe_left)->kv_node.rbe_color == 0) && ((tmp)-> kv_node.rbe_right == ((void*)0) || ((tmp)->kv_node.rbe_right )->kv_node.rbe_color == 0)) { (tmp)->kv_node.rbe_color = 1; elm = parent; parent = (elm)->kv_node.rbe_parent; } else { if ((tmp)->kv_node.rbe_right == ((void*)0) || ((tmp)-> kv_node.rbe_right)->kv_node.rbe_color == 0) { struct kv *oleft ; if ((oleft = (tmp)->kv_node.rbe_left)) (oleft)->kv_node .rbe_color = 0; (tmp)->kv_node.rbe_color = 1; do { (oleft) = (tmp)->kv_node.rbe_left; if (((tmp)->kv_node.rbe_left = (oleft)->kv_node.rbe_right)) { ((oleft)->kv_node.rbe_right )->kv_node.rbe_parent = (tmp); } do {} while (0); if (((oleft )->kv_node.rbe_parent = (tmp)->kv_node.rbe_parent)) { if ((tmp) == ((tmp)->kv_node.rbe_parent)->kv_node.rbe_left ) ((tmp)->kv_node.rbe_parent)->kv_node.rbe_left = (oleft ); else ((tmp)->kv_node.rbe_parent)->kv_node.rbe_right = (oleft); } else (head)->rbh_root = (oleft); (oleft)->kv_node .rbe_right = (tmp); (tmp)->kv_node.rbe_parent = (oleft); do {} while (0); if (((oleft)->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->kv_node.rbe_right; } (tmp )->kv_node.rbe_color = (parent)->kv_node.rbe_color; (parent )->kv_node.rbe_color = 0; if ((tmp)->kv_node.rbe_right) ((tmp)->kv_node.rbe_right)->kv_node.rbe_color = 0; do { (tmp) = (parent)->kv_node.rbe_right; if (((parent)->kv_node .rbe_right = (tmp)->kv_node.rbe_left)) { ((tmp)->kv_node .rbe_left)->kv_node.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node. rbe_parent)) { if ((parent) == ((parent)->kv_node.rbe_parent )->kv_node.rbe_left) ((parent)->kv_node.rbe_parent)-> kv_node.rbe_left = (tmp); else ((parent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_left = (parent); (parent)->kv_node .rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node. rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root ; break; } } else { tmp = (parent)->kv_node.rbe_left; if ( (tmp)->kv_node.rbe_color == 1) { do { (tmp)->kv_node.rbe_color = 0; (parent)->kv_node.rbe_color = 1; } while (0); do { ( tmp) = (parent)->kv_node.rbe_left; if (((parent)->kv_node .rbe_left = (tmp)->kv_node.rbe_right)) { ((tmp)->kv_node .rbe_right)->kv_node.rbe_parent = (parent); } do {} while ( 0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node. rbe_parent)) { if ((parent) == ((parent)->kv_node.rbe_parent )->kv_node.rbe_left) ((parent)->kv_node.rbe_parent)-> kv_node.rbe_left = (tmp); else ((parent)->kv_node.rbe_parent )->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = (parent); (parent)-> kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> kv_node.rbe_left; } if (((tmp)->kv_node.rbe_left == ((void *)0) || ((tmp)->kv_node.rbe_left)->kv_node.rbe_color == 0) && ((tmp)->kv_node.rbe_right == ((void*)0) || ( (tmp)->kv_node.rbe_right)->kv_node.rbe_color == 0)) { ( tmp)->kv_node.rbe_color = 1; elm = parent; parent = (elm)-> kv_node.rbe_parent; } else { if ((tmp)->kv_node.rbe_left == ((void*)0) || ((tmp)->kv_node.rbe_left)->kv_node.rbe_color == 0) { struct kv *oright; if ((oright = (tmp)->kv_node.rbe_right )) (oright)->kv_node.rbe_color = 0; (tmp)->kv_node.rbe_color = 1; do { (oright) = (tmp)->kv_node.rbe_right; if (((tmp) ->kv_node.rbe_right = (oright)->kv_node.rbe_left)) { (( oright)->kv_node.rbe_left)->kv_node.rbe_parent = (tmp); } do {} while (0); if (((oright)->kv_node.rbe_parent = (tmp )->kv_node.rbe_parent)) { if ((tmp) == ((tmp)->kv_node. rbe_parent)->kv_node.rbe_left) ((tmp)->kv_node.rbe_parent )->kv_node.rbe_left = (oright); else ((tmp)->kv_node.rbe_parent )->kv_node.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->kv_node.rbe_left = (tmp); (tmp)-> kv_node.rbe_parent = (oright); do {} while (0); if (((oright) ->kv_node.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->kv_node.rbe_left; } (tmp)->kv_node.rbe_color = (parent)->kv_node.rbe_color; (parent)->kv_node.rbe_color = 0; if ((tmp)->kv_node.rbe_left) ((tmp)->kv_node.rbe_left )->kv_node.rbe_color = 0; do { (tmp) = (parent)->kv_node .rbe_left; if (((parent)->kv_node.rbe_left = (tmp)->kv_node .rbe_right)) { ((tmp)->kv_node.rbe_right)->kv_node.rbe_parent = (parent); } do {} while (0); if (((tmp)->kv_node.rbe_parent = (parent)->kv_node.rbe_parent)) { if ((parent) == ((parent )->kv_node.rbe_parent)->kv_node.rbe_left) ((parent)-> kv_node.rbe_parent)->kv_node.rbe_left = (tmp); else ((parent )->kv_node.rbe_parent)->kv_node.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->kv_node.rbe_right = ( parent); (parent)->kv_node.rbe_parent = (tmp); do {} while (0); if (((tmp)->kv_node.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)-> kv_node.rbe_color = 0; } struct kv * kvtree_RB_REMOVE(struct kvtree *head, struct kv *elm) { struct kv *child, *parent, *old = elm ; int color; if ((elm)->kv_node.rbe_left == ((void*)0)) child = (elm)->kv_node.rbe_right; else if ((elm)->kv_node.rbe_right == ((void*)0)) child = (elm)->kv_node.rbe_left; else { struct kv *left; elm = (elm)->kv_node.rbe_right; while ((left = ( elm)->kv_node.rbe_left)) elm = left; child = (elm)->kv_node .rbe_right; parent = (elm)->kv_node.rbe_parent; color = (elm )->kv_node.rbe_color; if (child) (child)->kv_node.rbe_parent = parent; if (parent) { if ((parent)->kv_node.rbe_left == elm) (parent)->kv_node.rbe_left = child; else (parent)-> kv_node.rbe_right = child; do {} while (0); } else (head)-> rbh_root = child; if ((elm)->kv_node.rbe_parent == old) parent = elm; (elm)->kv_node = (old)->kv_node; if ((old)-> kv_node.rbe_parent) { if (((old)->kv_node.rbe_parent)-> kv_node.rbe_left == old) ((old)->kv_node.rbe_parent)->kv_node .rbe_left = elm; else ((old)->kv_node.rbe_parent)->kv_node .rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->kv_node.rbe_left)->kv_node.rbe_parent = elm; if ((old)->kv_node.rbe_right) ((old)->kv_node.rbe_right )->kv_node.rbe_parent = elm; if (parent) { left = parent; do { do {} while (0); } while ((left = (left)->kv_node.rbe_parent )); } goto color; } parent = (elm)->kv_node.rbe_parent; color = (elm)->kv_node.rbe_color; if (child) (child)->kv_node .rbe_parent = parent; if (parent) { if ((parent)->kv_node. rbe_left == elm) (parent)->kv_node.rbe_left = child; else ( parent)->kv_node.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) kvtree_RB_REMOVE_COLOR (head, parent, child); return (old); } struct kv * kvtree_RB_INSERT (struct kvtree *head, struct kv *elm) { struct kv *tmp; struct kv *parent = ((void*)0); int comp = 0; tmp = (head)->rbh_root ; while (tmp) { parent = tmp; comp = (kv_cmp)(elm, parent); if (comp < 0) tmp = (tmp)->kv_node.rbe_left; else if (comp > 0) tmp = (tmp)->kv_node.rbe_right; else return (tmp) ; } do { (elm)->kv_node.rbe_parent = parent; (elm)->kv_node .rbe_left = (elm)->kv_node.rbe_right = ((void*)0); (elm)-> kv_node.rbe_color = 1; } while (0); if (parent != ((void*)0)) { if (comp < 0) (parent)->kv_node.rbe_left = elm; else (parent)->kv_node.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; kvtree_RB_INSERT_COLOR(head, elm) ; return (((void*)0)); } struct kv * kvtree_RB_FIND(struct kvtree *head, struct kv *elm) { struct kv *tmp = (head)->rbh_root ; int comp; while (tmp) { comp = kv_cmp(elm, tmp); if (comp < 0) tmp = (tmp)->kv_node.rbe_left; else if (comp > 0) tmp = (tmp)->kv_node.rbe_right; else return (tmp); } return ( ((void*)0)); } struct kv * kvtree_RB_NFIND(struct kvtree *head , struct kv *elm) { struct kv *tmp = (head)->rbh_root; struct kv *res = ((void*)0); int comp; while (tmp) { comp = kv_cmp( elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->kv_node .rbe_left; } else if (comp > 0) tmp = (tmp)->kv_node.rbe_right ; else return (tmp); } return (res); } struct kv * kvtree_RB_NEXT (struct kv *elm) { if ((elm)->kv_node.rbe_right) { elm = ( elm)->kv_node.rbe_right; while ((elm)->kv_node.rbe_left ) elm = (elm)->kv_node.rbe_left; } else { if ((elm)->kv_node .rbe_parent && (elm == ((elm)->kv_node.rbe_parent) ->kv_node.rbe_left)) elm = (elm)->kv_node.rbe_parent; else { while ((elm)->kv_node.rbe_parent && (elm == ((elm )->kv_node.rbe_parent)->kv_node.rbe_right)) elm = (elm) ->kv_node.rbe_parent; elm = (elm)->kv_node.rbe_parent; } } return (elm); } struct kv * kvtree_RB_PREV(struct kv *elm) { if ((elm)->kv_node.rbe_left) { elm = (elm)->kv_node. rbe_left; while ((elm)->kv_node.rbe_right) elm = (elm)-> kv_node.rbe_right; } else { if ((elm)->kv_node.rbe_parent && (elm == ((elm)->kv_node.rbe_parent)->kv_node.rbe_right )) elm = (elm)->kv_node.rbe_parent; else { while ((elm)-> kv_node.rbe_parent && (elm == ((elm)->kv_node.rbe_parent )->kv_node.rbe_left)) elm = (elm)->kv_node.rbe_parent; elm = (elm)->kv_node.rbe_parent; } } return (elm); } struct kv * kvtree_RB_MINMAX(struct kvtree *head, int val) { struct kv *tmp = (head)->rbh_root; struct kv *parent = ((void*)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->kv_node .rbe_left; else tmp = (tmp)->kv_node.rbe_right; } return ( parent); }; |
| 1091 | |
| 1092 | struct media_type * |
| 1093 | media_add(struct mediatypes *types, struct media_type *media) |
| 1094 | { |
| 1095 | struct media_type *entry; |
| 1096 | |
| 1097 | if ((entry = RB_FIND(mediatypes, types, media)mediatypes_RB_FIND(types, media)) != NULL((void*)0)) { |
| 1098 | log_debug("%s: duplicated entry for \"%s\"", __func__, |
| 1099 | media->media_name); |
| 1100 | return (NULL((void*)0)); |
| 1101 | } |
| 1102 | |
| 1103 | if ((entry = malloc(sizeof(*media))) == NULL((void*)0)) |
| 1104 | return (NULL((void*)0)); |
| 1105 | |
| 1106 | memcpy(entry, media, sizeof(*entry)); |
| 1107 | if (media->media_encoding != NULL((void*)0) && |
| 1108 | (entry->media_encoding = strdup(media->media_encoding)) == NULL((void*)0)) { |
| 1109 | free(entry); |
| 1110 | return (NULL((void*)0)); |
| 1111 | } |
| 1112 | RB_INSERT(mediatypes, types, entry)mediatypes_RB_INSERT(types, entry); |
| 1113 | |
| 1114 | return (entry); |
| 1115 | } |
| 1116 | |
| 1117 | void |
| 1118 | media_delete(struct mediatypes *types, struct media_type *media) |
| 1119 | { |
| 1120 | RB_REMOVE(mediatypes, types, media)mediatypes_RB_REMOVE(types, media); |
| 1121 | |
| 1122 | free(media->media_encoding); |
| 1123 | free(media); |
| 1124 | } |
| 1125 | |
| 1126 | void |
| 1127 | media_purge(struct mediatypes *types) |
| 1128 | { |
| 1129 | struct media_type *media; |
| 1130 | |
| 1131 | while ((media = RB_MIN(mediatypes, types)mediatypes_RB_MINMAX(types, -1)) != NULL((void*)0)) |
| 1132 | media_delete(types, media); |
| 1133 | } |
| 1134 | |
| 1135 | struct media_type * |
| 1136 | media_find(struct mediatypes *types, const char *file) |
| 1137 | { |
| 1138 | struct media_type *match, media; |
| 1139 | char *p; |
| 1140 | |
| 1141 | /* Last component of the file name */ |
| 1142 | p = strchr(file, '\0'); |
| 1143 | while (p > file && p[-1] != '.' && p[-1] != '/') |
| 1144 | p--; |
| 1145 | if (*p == '\0') |
| 1146 | return (NULL((void*)0)); |
| 1147 | |
| 1148 | if (strlcpy(media.media_name, p, |
| 1149 | sizeof(media.media_name)) >= |
| 1150 | sizeof(media.media_name)) { |
| 1151 | return (NULL((void*)0)); |
| 1152 | } |
| 1153 | |
| 1154 | /* Find media type by extension name */ |
| 1155 | match = RB_FIND(mediatypes, types, &media)mediatypes_RB_FIND(types, &media); |
| 1156 | |
| 1157 | return (match); |
| 1158 | } |
| 1159 | |
| 1160 | struct media_type * |
| 1161 | media_find_config(struct httpd *env, struct server_config *srv_conf, |
| 1162 | const char *file) |
| 1163 | { |
| 1164 | struct media_type *match; |
| 1165 | |
| 1166 | if ((match = media_find(env->sc_mediatypes, file)) != NULL((void*)0)) |
| 1167 | return (match); |
| 1168 | else if (srv_conf->flags & SRVFLAG_DEFAULT_TYPE0x00800000) |
| 1169 | return (&srv_conf->default_type); |
| 1170 | |
| 1171 | /* fallback to the global default type */ |
| 1172 | return (&env->sc_default_type); |
| 1173 | } |
| 1174 | |
| 1175 | int |
| 1176 | media_cmp(struct media_type *a, struct media_type *b) |
| 1177 | { |
| 1178 | return (strcasecmp(a->media_name, b->media_name)); |
| 1179 | } |
| 1180 | |
| 1181 | RB_GENERATE(mediatypes, media_type, media_entry, media_cmp)void mediatypes_RB_INSERT_COLOR(struct mediatypes *head, struct media_type *elm) { struct media_type *parent, *gparent, *tmp ; while ((parent = (elm)->media_entry.rbe_parent) && (parent)->media_entry.rbe_color == 1) { gparent = (parent )->media_entry.rbe_parent; if (parent == (gparent)->media_entry .rbe_left) { tmp = (gparent)->media_entry.rbe_right; if (tmp && (tmp)->media_entry.rbe_color == 1) { (tmp)-> media_entry.rbe_color = 0; do { (parent)->media_entry.rbe_color = 0; (gparent)->media_entry.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)->media_entry.rbe_right == elm) { do { (tmp) = (parent)->media_entry.rbe_right; if (((parent)->media_entry.rbe_right = (tmp)->media_entry .rbe_left)) { ((tmp)->media_entry.rbe_left)->media_entry .rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry .rbe_parent = (parent)->media_entry.rbe_parent)) { if ((parent ) == ((parent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((parent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((parent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_left = (parent); (parent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->media_entry.rbe_color = 0; (gparent)->media_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->media_entry.rbe_left; if (((gparent)-> media_entry.rbe_left = (tmp)->media_entry.rbe_right)) { (( tmp)->media_entry.rbe_right)->media_entry.rbe_parent = ( gparent); } do {} while (0); if (((tmp)->media_entry.rbe_parent = (gparent)->media_entry.rbe_parent)) { if ((gparent) == ( (gparent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((gparent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((gparent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_right = (gparent); (gparent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent )->media_entry.rbe_left; if (tmp && (tmp)->media_entry .rbe_color == 1) { (tmp)->media_entry.rbe_color = 0; do { ( parent)->media_entry.rbe_color = 0; (gparent)->media_entry .rbe_color = 1; } while (0); elm = gparent; continue; } if (( parent)->media_entry.rbe_left == elm) { do { (tmp) = (parent )->media_entry.rbe_left; if (((parent)->media_entry.rbe_left = (tmp)->media_entry.rbe_right)) { ((tmp)->media_entry .rbe_right)->media_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry.rbe_parent = (parent)->media_entry .rbe_parent)) { if ((parent) == ((parent)->media_entry.rbe_parent )->media_entry.rbe_left) ((parent)->media_entry.rbe_parent )->media_entry.rbe_left = (tmp); else ((parent)->media_entry .rbe_parent)->media_entry.rbe_right = (tmp); } else (head) ->rbh_root = (tmp); (tmp)->media_entry.rbe_right = (parent ); (parent)->media_entry.rbe_parent = (tmp); do {} while ( 0); if (((tmp)->media_entry.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent )->media_entry.rbe_color = 0; (gparent)->media_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->media_entry.rbe_right ; if (((gparent)->media_entry.rbe_right = (tmp)->media_entry .rbe_left)) { ((tmp)->media_entry.rbe_left)->media_entry .rbe_parent = (gparent); } do {} while (0); if (((tmp)->media_entry .rbe_parent = (gparent)->media_entry.rbe_parent)) { if ((gparent ) == ((gparent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((gparent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((gparent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_left = (gparent); (gparent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root )->media_entry.rbe_color = 0; } void mediatypes_RB_REMOVE_COLOR (struct mediatypes *head, struct media_type *parent, struct media_type *elm) { struct media_type *tmp; while ((elm == ((void*)0) || (elm)->media_entry.rbe_color == 0) && elm != (head )->rbh_root) { if ((parent)->media_entry.rbe_left == elm ) { tmp = (parent)->media_entry.rbe_right; if ((tmp)->media_entry .rbe_color == 1) { do { (tmp)->media_entry.rbe_color = 0; ( parent)->media_entry.rbe_color = 1; } while (0); do { (tmp ) = (parent)->media_entry.rbe_right; if (((parent)->media_entry .rbe_right = (tmp)->media_entry.rbe_left)) { ((tmp)->media_entry .rbe_left)->media_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry.rbe_parent = (parent)->media_entry .rbe_parent)) { if ((parent) == ((parent)->media_entry.rbe_parent )->media_entry.rbe_left) ((parent)->media_entry.rbe_parent )->media_entry.rbe_left = (tmp); else ((parent)->media_entry .rbe_parent)->media_entry.rbe_right = (tmp); } else (head) ->rbh_root = (tmp); (tmp)->media_entry.rbe_left = (parent ); (parent)->media_entry.rbe_parent = (tmp); do {} while ( 0); if (((tmp)->media_entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->media_entry.rbe_right; } if (( (tmp)->media_entry.rbe_left == ((void*)0) || ((tmp)->media_entry .rbe_left)->media_entry.rbe_color == 0) && ((tmp)-> media_entry.rbe_right == ((void*)0) || ((tmp)->media_entry .rbe_right)->media_entry.rbe_color == 0)) { (tmp)->media_entry .rbe_color = 1; elm = parent; parent = (elm)->media_entry. rbe_parent; } else { if ((tmp)->media_entry.rbe_right == ( (void*)0) || ((tmp)->media_entry.rbe_right)->media_entry .rbe_color == 0) { struct media_type *oleft; if ((oleft = (tmp )->media_entry.rbe_left)) (oleft)->media_entry.rbe_color = 0; (tmp)->media_entry.rbe_color = 1; do { (oleft) = (tmp )->media_entry.rbe_left; if (((tmp)->media_entry.rbe_left = (oleft)->media_entry.rbe_right)) { ((oleft)->media_entry .rbe_right)->media_entry.rbe_parent = (tmp); } do {} while (0); if (((oleft)->media_entry.rbe_parent = (tmp)->media_entry .rbe_parent)) { if ((tmp) == ((tmp)->media_entry.rbe_parent )->media_entry.rbe_left) ((tmp)->media_entry.rbe_parent )->media_entry.rbe_left = (oleft); else ((tmp)->media_entry .rbe_parent)->media_entry.rbe_right = (oleft); } else (head )->rbh_root = (oleft); (oleft)->media_entry.rbe_right = (tmp); (tmp)->media_entry.rbe_parent = (oleft); do {} while (0); if (((oleft)->media_entry.rbe_parent)) do {} while ( 0); } while (0); tmp = (parent)->media_entry.rbe_right; } ( tmp)->media_entry.rbe_color = (parent)->media_entry.rbe_color ; (parent)->media_entry.rbe_color = 0; if ((tmp)->media_entry .rbe_right) ((tmp)->media_entry.rbe_right)->media_entry .rbe_color = 0; do { (tmp) = (parent)->media_entry.rbe_right ; if (((parent)->media_entry.rbe_right = (tmp)->media_entry .rbe_left)) { ((tmp)->media_entry.rbe_left)->media_entry .rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry .rbe_parent = (parent)->media_entry.rbe_parent)) { if ((parent ) == ((parent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((parent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((parent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_left = (parent); (parent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); elm = (head)-> rbh_root; break; } } else { tmp = (parent)->media_entry.rbe_left ; if ((tmp)->media_entry.rbe_color == 1) { do { (tmp)-> media_entry.rbe_color = 0; (parent)->media_entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->media_entry.rbe_left ; if (((parent)->media_entry.rbe_left = (tmp)->media_entry .rbe_right)) { ((tmp)->media_entry.rbe_right)->media_entry .rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry .rbe_parent = (parent)->media_entry.rbe_parent)) { if ((parent ) == ((parent)->media_entry.rbe_parent)->media_entry.rbe_left ) ((parent)->media_entry.rbe_parent)->media_entry.rbe_left = (tmp); else ((parent)->media_entry.rbe_parent)->media_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->media_entry.rbe_right = (parent); (parent)->media_entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->media_entry .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> media_entry.rbe_left; } if (((tmp)->media_entry.rbe_left == ((void*)0) || ((tmp)->media_entry.rbe_left)->media_entry .rbe_color == 0) && ((tmp)->media_entry.rbe_right == ((void*)0) || ((tmp)->media_entry.rbe_right)->media_entry .rbe_color == 0)) { (tmp)->media_entry.rbe_color = 1; elm = parent; parent = (elm)->media_entry.rbe_parent; } else { if ((tmp)->media_entry.rbe_left == ((void*)0) || ((tmp)-> media_entry.rbe_left)->media_entry.rbe_color == 0) { struct media_type *oright; if ((oright = (tmp)->media_entry.rbe_right )) (oright)->media_entry.rbe_color = 0; (tmp)->media_entry .rbe_color = 1; do { (oright) = (tmp)->media_entry.rbe_right ; if (((tmp)->media_entry.rbe_right = (oright)->media_entry .rbe_left)) { ((oright)->media_entry.rbe_left)->media_entry .rbe_parent = (tmp); } do {} while (0); if (((oright)->media_entry .rbe_parent = (tmp)->media_entry.rbe_parent)) { if ((tmp) == ((tmp)->media_entry.rbe_parent)->media_entry.rbe_left) ((tmp)->media_entry.rbe_parent)->media_entry.rbe_left = (oright); else ((tmp)->media_entry.rbe_parent)->media_entry .rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->media_entry.rbe_left = (tmp); (tmp)->media_entry .rbe_parent = (oright); do {} while (0); if (((oright)->media_entry .rbe_parent)) do {} while (0); } while (0); tmp = (parent)-> media_entry.rbe_left; } (tmp)->media_entry.rbe_color = (parent )->media_entry.rbe_color; (parent)->media_entry.rbe_color = 0; if ((tmp)->media_entry.rbe_left) ((tmp)->media_entry .rbe_left)->media_entry.rbe_color = 0; do { (tmp) = (parent )->media_entry.rbe_left; if (((parent)->media_entry.rbe_left = (tmp)->media_entry.rbe_right)) { ((tmp)->media_entry .rbe_right)->media_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->media_entry.rbe_parent = (parent)->media_entry .rbe_parent)) { if ((parent) == ((parent)->media_entry.rbe_parent )->media_entry.rbe_left) ((parent)->media_entry.rbe_parent )->media_entry.rbe_left = (tmp); else ((parent)->media_entry .rbe_parent)->media_entry.rbe_right = (tmp); } else (head) ->rbh_root = (tmp); (tmp)->media_entry.rbe_right = (parent ); (parent)->media_entry.rbe_parent = (tmp); do {} while ( 0); if (((tmp)->media_entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) ( elm)->media_entry.rbe_color = 0; } struct media_type * mediatypes_RB_REMOVE (struct mediatypes *head, struct media_type *elm) { struct media_type *child, *parent, *old = elm; int color; if ((elm)->media_entry .rbe_left == ((void*)0)) child = (elm)->media_entry.rbe_right ; else if ((elm)->media_entry.rbe_right == ((void*)0)) child = (elm)->media_entry.rbe_left; else { struct media_type * left; elm = (elm)->media_entry.rbe_right; while ((left = ( elm)->media_entry.rbe_left)) elm = left; child = (elm)-> media_entry.rbe_right; parent = (elm)->media_entry.rbe_parent ; color = (elm)->media_entry.rbe_color; if (child) (child) ->media_entry.rbe_parent = parent; if (parent) { if ((parent )->media_entry.rbe_left == elm) (parent)->media_entry.rbe_left = child; else (parent)->media_entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; if ((elm)-> media_entry.rbe_parent == old) parent = elm; (elm)->media_entry = (old)->media_entry; if ((old)->media_entry.rbe_parent ) { if (((old)->media_entry.rbe_parent)->media_entry.rbe_left == old) ((old)->media_entry.rbe_parent)->media_entry.rbe_left = elm; else ((old)->media_entry.rbe_parent)->media_entry .rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->media_entry.rbe_left)->media_entry.rbe_parent = elm; if ((old)->media_entry.rbe_right) ((old)->media_entry .rbe_right)->media_entry.rbe_parent = elm; if (parent) { left = parent; do { do {} while (0); } while ((left = (left)-> media_entry.rbe_parent)); } goto color; } parent = (elm)-> media_entry.rbe_parent; color = (elm)->media_entry.rbe_color ; if (child) (child)->media_entry.rbe_parent = parent; if ( parent) { if ((parent)->media_entry.rbe_left == elm) (parent )->media_entry.rbe_left = child; else (parent)->media_entry .rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) mediatypes_RB_REMOVE_COLOR(head , parent, child); return (old); } struct media_type * mediatypes_RB_INSERT (struct mediatypes *head, struct media_type *elm) { struct media_type *tmp; struct media_type *parent = ((void*)0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp; comp = (media_cmp )(elm, parent); if (comp < 0) tmp = (tmp)->media_entry. rbe_left; else if (comp > 0) tmp = (tmp)->media_entry.rbe_right ; else return (tmp); } do { (elm)->media_entry.rbe_parent = parent; (elm)->media_entry.rbe_left = (elm)->media_entry .rbe_right = ((void*)0); (elm)->media_entry.rbe_color = 1; } while (0); if (parent != ((void*)0)) { if (comp < 0) (parent )->media_entry.rbe_left = elm; else (parent)->media_entry .rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; mediatypes_RB_INSERT_COLOR(head, elm); return (((void *)0)); } struct media_type * mediatypes_RB_FIND(struct mediatypes *head, struct media_type *elm) { struct media_type *tmp = (head )->rbh_root; int comp; while (tmp) { comp = media_cmp(elm, tmp); if (comp < 0) tmp = (tmp)->media_entry.rbe_left; else if (comp > 0) tmp = (tmp)->media_entry.rbe_right; else return (tmp); } return (((void*)0)); } struct media_type * mediatypes_RB_NFIND(struct mediatypes *head, struct media_type *elm) { struct media_type *tmp = (head)->rbh_root; struct media_type *res = ((void*)0); int comp; while (tmp) { comp = media_cmp(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp )->media_entry.rbe_left; } else if (comp > 0) tmp = (tmp )->media_entry.rbe_right; else return (tmp); } return (res ); } struct media_type * mediatypes_RB_NEXT(struct media_type *elm) { if ((elm)->media_entry.rbe_right) { elm = (elm)-> media_entry.rbe_right; while ((elm)->media_entry.rbe_left) elm = (elm)->media_entry.rbe_left; } else { if ((elm)-> media_entry.rbe_parent && (elm == ((elm)->media_entry .rbe_parent)->media_entry.rbe_left)) elm = (elm)->media_entry .rbe_parent; else { while ((elm)->media_entry.rbe_parent && (elm == ((elm)->media_entry.rbe_parent)->media_entry.rbe_right )) elm = (elm)->media_entry.rbe_parent; elm = (elm)->media_entry .rbe_parent; } } return (elm); } struct media_type * mediatypes_RB_PREV (struct media_type *elm) { if ((elm)->media_entry.rbe_left ) { elm = (elm)->media_entry.rbe_left; while ((elm)->media_entry .rbe_right) elm = (elm)->media_entry.rbe_right; } else { if ((elm)->media_entry.rbe_parent && (elm == ((elm)-> media_entry.rbe_parent)->media_entry.rbe_right)) elm = (elm )->media_entry.rbe_parent; else { while ((elm)->media_entry .rbe_parent && (elm == ((elm)->media_entry.rbe_parent )->media_entry.rbe_left)) elm = (elm)->media_entry.rbe_parent ; elm = (elm)->media_entry.rbe_parent; } } return (elm); } struct media_type * mediatypes_RB_MINMAX(struct mediatypes * head, int val) { struct media_type *tmp = (head)->rbh_root ; struct media_type *parent = ((void*)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->media_entry.rbe_left; else tmp = (tmp)->media_entry.rbe_right; } return (parent ); }; |
| 1182 | |
| 1183 | struct auth * |
| 1184 | auth_add(struct serverauth *serverauth, struct auth *auth) |
| 1185 | { |
| 1186 | struct auth *entry; |
| 1187 | |
| 1188 | TAILQ_FOREACH(entry, serverauth, auth_entry)for((entry) = ((serverauth)->tqh_first); (entry) != ((void *)0); (entry) = ((entry)->auth_entry.tqe_next)) { |
| 1189 | if (strcmp(entry->auth_htpasswd, auth->auth_htpasswd) == 0) |
| 1190 | return (entry); |
| 1191 | } |
| 1192 | |
| 1193 | if ((entry = calloc(1, sizeof(*entry))) == NULL((void*)0)) |
| 1194 | return (NULL((void*)0)); |
| 1195 | |
| 1196 | memcpy(entry, auth, sizeof(*entry)); |
| 1197 | |
| 1198 | TAILQ_INSERT_TAIL(serverauth, entry, auth_entry)do { (entry)->auth_entry.tqe_next = ((void*)0); (entry)-> auth_entry.tqe_prev = (serverauth)->tqh_last; *(serverauth )->tqh_last = (entry); (serverauth)->tqh_last = &(entry )->auth_entry.tqe_next; } while (0); |
| 1199 | |
| 1200 | return (entry); |
| 1201 | } |
| 1202 | |
| 1203 | struct auth * |
| 1204 | auth_byid(struct serverauth *serverauth, uint32_t id) |
| 1205 | { |
| 1206 | struct auth *auth; |
| 1207 | |
| 1208 | TAILQ_FOREACH(auth, serverauth, auth_entry)for((auth) = ((serverauth)->tqh_first); (auth) != ((void*) 0); (auth) = ((auth)->auth_entry.tqe_next)) { |
| 1209 | if (auth->auth_id == id) |
| 1210 | return (auth); |
| 1211 | } |
| 1212 | |
| 1213 | return (NULL((void*)0)); |
| 1214 | } |
| 1215 | |
| 1216 | void |
| 1217 | auth_free(struct serverauth *serverauth, struct auth *auth) |
| 1218 | { |
| 1219 | TAILQ_REMOVE(serverauth, auth, auth_entry)do { if (((auth)->auth_entry.tqe_next) != ((void*)0)) (auth )->auth_entry.tqe_next->auth_entry.tqe_prev = (auth)-> auth_entry.tqe_prev; else (serverauth)->tqh_last = (auth)-> auth_entry.tqe_prev; *(auth)->auth_entry.tqe_prev = (auth) ->auth_entry.tqe_next; ; ; } while (0); |
| 1220 | } |
| 1221 | |
| 1222 | |
| 1223 | const char * |
| 1224 | print_host(struct sockaddr_storage *ss, char *buf, size_t len) |
| 1225 | { |
| 1226 | if (getnameinfo((struct sockaddr *)ss, ss->ss_len, |
| 1227 | buf, len, NULL((void*)0), 0, NI_NUMERICHOST1) != 0) { |
| 1228 | buf[0] = '\0'; |
| 1229 | return (NULL((void*)0)); |
| 1230 | } |
| 1231 | return (buf); |
| 1232 | } |
| 1233 | |
| 1234 | const char * |
| 1235 | printb_flags(const uint32_t v, const char *bits) |
| 1236 | { |
| 1237 | static char buf[2][BUFSIZ1024]; |
| 1238 | static int idx = 0; |
| 1239 | int i, any = 0; |
| 1240 | char c, *p, *r; |
| 1241 | |
| 1242 | p = r = buf[++idx % 2]; |
| 1243 | memset(p, 0, BUFSIZ1024); |
| 1244 | |
| 1245 | if (bits) { |
| 1246 | bits++; |
| 1247 | while ((i = *bits++)) { |
| 1248 | if (v & (1 << (i - 1))) { |
| 1249 | if (any) { |
| 1250 | *p++ = ','; |
| 1251 | *p++ = ' '; |
| 1252 | } |
| 1253 | any = 1; |
| 1254 | for (; (c = *bits) > 32; bits++) { |
| 1255 | if (c == '_') |
| 1256 | *p++ = ' '; |
| 1257 | else |
| 1258 | *p++ = |
| 1259 | tolower((unsigned char)c); |
| 1260 | } |
| 1261 | } else |
| 1262 | for (; *bits > 32; bits++) |
| 1263 | ; |
| 1264 | } |
| 1265 | } |
| 1266 | |
| 1267 | return (r); |
| 1268 | } |
| 1269 | |
| 1270 | void |
| 1271 | getmonotime(struct timeval *tv) |
| 1272 | { |
| 1273 | struct timespec ts; |
| 1274 | |
| 1275 | if (clock_gettime(CLOCK_MONOTONIC3, &ts)) |
| 1276 | fatal("clock_gettime"); |
| 1277 | |
| 1278 | TIMESPEC_TO_TIMEVAL(tv, &ts)do { (tv)->tv_sec = (&ts)->tv_sec; (tv)->tv_usec = (&ts)->tv_nsec / 1000; } while (0); |
| 1279 | } |