1 1.31 mrg /* $NetBSD: main.c,v 1.31 2023/06/07 20:12:31 mrg Exp $ */ 2 1.1 mrg 3 1.5 mrg /* $eterna: main.c,v 1.6 2011/11/18 09:21:15 mrg Exp $ */ 4 1.1 mrg /* from: eterna: bozohttpd.c,v 1.159 2009/05/23 02:14:30 mrg Exp */ 5 1.1 mrg 6 1.1 mrg /* 7 1.31 mrg * Copyright (c) 1997-2023 Matthew R. Green 8 1.1 mrg * All rights reserved. 9 1.1 mrg * 10 1.1 mrg * Redistribution and use in source and binary forms, with or without 11 1.1 mrg * modification, are permitted provided that the following conditions 12 1.1 mrg * are met: 13 1.1 mrg * 1. Redistributions of source code must retain the above copyright 14 1.1 mrg * notice, this list of conditions and the following disclaimer. 15 1.1 mrg * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 mrg * notice, this list of conditions and the following disclaimer and 17 1.1 mrg * dedication in the documentation and/or other materials provided 18 1.1 mrg * with the distribution. 19 1.1 mrg * 20 1.1 mrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 1.1 mrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 1.1 mrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 1.1 mrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 1.1 mrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 1.1 mrg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 1.1 mrg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 27 1.1 mrg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 1.1 mrg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 mrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 mrg * SUCH DAMAGE. 31 1.1 mrg * 32 1.1 mrg */ 33 1.1 mrg 34 1.1 mrg /* this program is dedicated to the Great God of Processed Cheese */ 35 1.1 mrg 36 1.1 mrg /* 37 1.1 mrg * main.c: C front end to bozohttpd 38 1.1 mrg */ 39 1.1 mrg 40 1.1 mrg #include <sys/types.h> 41 1.1 mrg #include <sys/param.h> 42 1.1 mrg 43 1.1 mrg #include <errno.h> 44 1.1 mrg #include <stdlib.h> 45 1.1 mrg #include <string.h> 46 1.1 mrg #include <syslog.h> 47 1.1 mrg #include <time.h> 48 1.1 mrg #include <unistd.h> 49 1.1 mrg 50 1.1 mrg #include "bozohttpd.h" 51 1.1 mrg 52 1.1 mrg /* variables and functions */ 53 1.1 mrg #ifndef LOG_FTP 54 1.1 mrg #define LOG_FTP LOG_DAEMON 55 1.1 mrg #endif 56 1.1 mrg 57 1.17 mrg /* print a usage message, and then exit */ 58 1.17 mrg BOZO_DEAD static void 59 1.17 mrg usage(bozohttpd_t *httpd, char *progname) 60 1.17 mrg { 61 1.17 mrg bozowarn(httpd, "usage: %s [options] slashdir [virtualhostname]", 62 1.17 mrg progname); 63 1.17 mrg bozowarn(httpd, "options:"); 64 1.17 mrg 65 1.17 mrg if (have_daemon_mode) 66 1.25 mrg bozowarn(httpd, " -b\t\t\tbackground in daemon mode"); 67 1.17 mrg if (have_cgibin && 68 1.17 mrg have_dynamic_content) 69 1.25 mrg bozowarn(httpd, " -C suffix handler\tadd this CGI handler " 70 1.25 mrg "for paths ending with `suffix'"); 71 1.17 mrg if (have_cgibin) 72 1.17 mrg bozowarn(httpd, " -c cgibin\t\tenable cgi-bin support in " 73 1.17 mrg "this directory"); 74 1.17 mrg if (have_debug) 75 1.17 mrg bozowarn(httpd, " -d\t\t\tenable debug support"); 76 1.17 mrg if (have_user && 77 1.17 mrg have_cgibin) 78 1.25 mrg bozowarn(httpd, " -E\t\t\tenable CGI support for user dirs"); 79 1.25 mrg if (have_core) 80 1.17 mrg bozowarn(httpd, " -e\t\t\tdon't clean the environment " 81 1.17 mrg "(-t and -U only)"); 82 1.17 mrg if (have_daemon_mode) 83 1.17 mrg bozowarn(httpd, " -f\t\t\tforeground in daemon mode"); 84 1.25 mrg if (have_core) 85 1.25 mrg bozowarn(httpd, " -G\t\t\tprint version number and exit"); 86 1.17 mrg if (have_dirindex) 87 1.17 mrg bozowarn(httpd, " -H\t\t\thide files starting with a period " 88 1.17 mrg "(.) in index mode"); 89 1.25 mrg if (have_core) 90 1.17 mrg bozowarn(httpd, " -I port\t\tbind or use on this port"); 91 1.17 mrg if (have_daemon_mode) 92 1.17 mrg bozowarn(httpd, " -i address\t\tbind on this address " 93 1.17 mrg "(daemon mode only)"); 94 1.17 mrg if (have_lua) 95 1.25 mrg bozowarn(httpd, " -L prefix script\tadd this Lua script for " 96 1.25 mrg "paths starting with `prefix'"); 97 1.17 mrg if (have_dynamic_content) 98 1.25 mrg bozowarn(httpd, " -M suffix t c c11\tadd this mime entry"); 99 1.25 mrg if (have_core) 100 1.25 mrg bozowarn(httpd, " -n\t\t\tdon't resolve host names"); 101 1.17 mrg if (have_daemon_mode) 102 1.17 mrg bozowarn(httpd, " -P pidfile\t\tpid file path"); 103 1.17 mrg if (have_user) 104 1.17 mrg bozowarn(httpd, " -p dir\t\t\"public_html\" directory name"); 105 1.30 martin if (have_core) 106 1.30 martin bozowarn(httpd, " -q\t\tquiet mode, no logging"); 107 1.28 mrg if (have_dirindex) 108 1.28 mrg bozowarn(httpd, " -R readme\t\tput readme file in footer " 109 1.28 mrg "of directory index"); 110 1.25 mrg if (have_core) { 111 1.17 mrg bozowarn(httpd, " -S version\t\tset server version string"); 112 1.17 mrg bozowarn(httpd, " -s\t\t\talways log to stderr"); 113 1.25 mrg bozowarn(httpd, " -T type timeout\t" 114 1.25 mrg "set <ssl|initial|header|request> timeout"); 115 1.17 mrg bozowarn(httpd, " -t dir\t\tchroot to `dir'"); 116 1.25 mrg bozowarn(httpd, " -U user\t\tchange user to `user'"); 117 1.17 mrg } 118 1.17 mrg if (have_user) 119 1.17 mrg bozowarn(httpd, " -u\t\t\tenable ~user/public_html support"); 120 1.25 mrg if (have_core) { 121 1.17 mrg bozowarn(httpd, " -V\t\t\tUnknown virtual hosts go to " 122 1.17 mrg "`slashdir'"); 123 1.17 mrg bozowarn(httpd, " -v virtualroot\tenable virtual host " 124 1.17 mrg "support in this directory"); 125 1.17 mrg } 126 1.17 mrg if (have_dirindex) 127 1.17 mrg bozowarn(httpd, " -X\t\t\tdirectory index support"); 128 1.25 mrg if (have_core) 129 1.17 mrg bozowarn(httpd, " -x index\t\tdefault \"index.html\" " 130 1.17 mrg "file name"); 131 1.17 mrg if (have_ssl) { 132 1.17 mrg bozowarn(httpd, " -Z cert privkey\tspecify path to server " 133 1.17 mrg "certificate and private key file\n" 134 1.17 mrg "\t\t\tin pem format and enable bozohttpd in " 135 1.17 mrg "SSL mode"); 136 1.17 mrg bozowarn(httpd, " -z ciphers\t\tspecify SSL ciphers"); 137 1.17 mrg } 138 1.17 mrg 139 1.13 mrg bozoerr(httpd, 1, "%s failed to start", progname); 140 1.1 mrg } 141 1.1 mrg 142 1.1 mrg int 143 1.1 mrg main(int argc, char **argv) 144 1.1 mrg { 145 1.1 mrg bozo_httpreq_t *request; 146 1.1 mrg bozohttpd_t httpd; 147 1.1 mrg bozoprefs_t prefs; 148 1.1 mrg char *progname; 149 1.12 mrg const char *val; 150 1.1 mrg int c; 151 1.1 mrg 152 1.1 mrg (void) memset(&httpd, 0x0, sizeof(httpd)); 153 1.1 mrg (void) memset(&prefs, 0x0, sizeof(prefs)); 154 1.1 mrg 155 1.1 mrg if ((progname = strrchr(argv[0], '/')) == NULL) 156 1.1 mrg progname = argv[0]; 157 1.1 mrg else 158 1.1 mrg progname++; 159 1.1 mrg 160 1.1 mrg openlog(progname, LOG_PID|LOG_NDELAY, LOG_FTP); 161 1.1 mrg 162 1.1 mrg bozo_set_defaults(&httpd, &prefs); 163 1.1 mrg 164 1.9 shm /* 165 1.9 shm * -r option was removed, do not reuse it for a while 166 1.9 shm */ 167 1.9 shm 168 1.1 mrg while ((c = getopt(argc, argv, 169 1.30 martin "C:EGHI:L:M:m:P:R:S:T:U:VXZ:bc:defhi:np:qst:uv:x:z:")) != -1) { 170 1.9 shm switch (c) { 171 1.1 mrg 172 1.20 mrg case 'b': 173 1.20 mrg if (!have_daemon_mode) 174 1.20 mrg no_daemon_mode: 175 1.20 mrg bozoerr(&httpd, 1, "Daemon mode not enabled"); 176 1.19 mrg 177 1.20 mrg /* 178 1.20 mrg * test suite support - undocumented 179 1.20 mrg * background == 2 (aka, -b -b) means to 180 1.20 mrg * only process 1 per kid 181 1.20 mrg */ 182 1.20 mrg val = bozo_get_pref(&prefs, "background") == NULL ? 183 1.20 mrg "1" : "2"; 184 1.20 mrg bozo_set_pref(&httpd, &prefs, "background", val); 185 1.6 mbalmer break; 186 1.19 mrg 187 1.20 mrg case 'C': 188 1.25 mrg if (!have_dynamic_content || 189 1.25 mrg !have_cgibin) 190 1.20 mrg bozoerr(&httpd, 1, 191 1.20 mrg "dynamic CGI handler support not enabled"); 192 1.19 mrg 193 1.1 mrg /* make sure there's two arguments */ 194 1.1 mrg if (argc - optind < 1) 195 1.1 mrg usage(&httpd, progname); 196 1.20 mrg bozo_add_content_map_cgi(&httpd, optarg, 197 1.20 mrg argv[optind++]); 198 1.1 mrg break; 199 1.11 christos 200 1.25 mrg case 'c': 201 1.25 mrg if (!have_cgibin) 202 1.25 mrg bozoerr(&httpd, 1, "CGI not enabled"); 203 1.25 mrg 204 1.25 mrg bozo_cgi_setbin(&httpd, optarg); 205 1.25 mrg break; 206 1.25 mrg 207 1.20 mrg case 'd': 208 1.20 mrg if (!have_debug) 209 1.20 mrg bozowarn(&httpd, "Debugging not enabled"); 210 1.20 mrg httpd.debug++; 211 1.11 christos break; 212 1.11 christos 213 1.20 mrg case 'E': 214 1.25 mrg if (!have_user || 215 1.25 mrg !have_cgibin) 216 1.20 mrg bozoerr(&httpd, 1, "CGI not enabled"); 217 1.1 mrg 218 1.20 mrg bozo_set_pref(&httpd, &prefs, "enable user cgibin", 219 1.20 mrg "true"); 220 1.1 mrg break; 221 1.1 mrg 222 1.1 mrg case 'e': 223 1.12 mrg bozo_set_pref(&httpd, &prefs, "dirty environment", 224 1.12 mrg "true"); 225 1.1 mrg break; 226 1.1 mrg 227 1.1 mrg case 'f': 228 1.19 mrg if (!have_daemon_mode) 229 1.19 mrg goto no_daemon_mode; 230 1.19 mrg 231 1.12 mrg bozo_set_pref(&httpd, &prefs, "foreground", "true"); 232 1.1 mrg break; 233 1.1 mrg 234 1.20 mrg case 'G': 235 1.20 mrg { 236 1.20 mrg char version[128]; 237 1.20 mrg 238 1.20 mrg bozo_get_version(version, sizeof(version)); 239 1.20 mrg printf("bozohttpd version %s\n", version); 240 1.20 mrg } 241 1.20 mrg return 0; 242 1.20 mrg 243 1.20 mrg case 'H': 244 1.20 mrg if (!have_dirindex) 245 1.20 mrg no_dirindex_support: 246 1.20 mrg bozoerr(&httpd, 1, 247 1.20 mrg "directory indexing not enabled"); 248 1.20 mrg 249 1.20 mrg bozo_set_pref(&httpd, &prefs, "hide dots", "true"); 250 1.20 mrg break; 251 1.20 mrg 252 1.20 mrg case 'I': 253 1.20 mrg bozo_set_pref(&httpd, &prefs, "port number", optarg); 254 1.20 mrg break; 255 1.20 mrg 256 1.1 mrg case 'i': 257 1.19 mrg if (!have_daemon_mode) 258 1.19 mrg goto no_daemon_mode; 259 1.19 mrg 260 1.21 mrg bozo_set_pref(&httpd, &prefs, "bind address", optarg); 261 1.21 mrg break; 262 1.21 mrg 263 1.20 mrg case 'L': 264 1.20 mrg if (!have_lua) 265 1.20 mrg bozoerr(&httpd, 1, "Lua support not enabled"); 266 1.20 mrg 267 1.20 mrg /* make sure there's two argument */ 268 1.20 mrg if (argc - optind < 1) 269 1.20 mrg usage(&httpd, progname); 270 1.20 mrg bozo_add_lua_map(&httpd, optarg, argv[optind]); 271 1.20 mrg optind++; 272 1.20 mrg break; 273 1.20 mrg 274 1.20 mrg case 'M': 275 1.20 mrg if (!have_dynamic_content) 276 1.20 mrg bozoerr(&httpd, 1, 277 1.20 mrg "dynamic mime content support not enabled"); 278 1.20 mrg 279 1.20 mrg /* make sure there're four arguments */ 280 1.20 mrg if (argc - optind < 3) 281 1.20 mrg usage(&httpd, progname); 282 1.20 mrg bozo_add_content_map_mime(&httpd, optarg, argv[optind], 283 1.20 mrg argv[optind+1], argv[optind+2]); 284 1.20 mrg optind += 3; 285 1.20 mrg break; 286 1.20 mrg 287 1.29 mrg case 'm': 288 1.29 mrg if (!have_ssl) 289 1.29 mrg goto no_ssl; 290 1.29 mrg 291 1.29 mrg httpd.ssl_min_proto = optarg; 292 1.29 mrg debug((&httpd, DEBUG_NORMAL, 293 1.29 mrg "using minimum protocol version: %s", optarg)); 294 1.29 mrg break; 295 1.29 mrg 296 1.20 mrg case 'n': 297 1.20 mrg bozo_set_pref(&httpd, &prefs, "numeric", "true"); 298 1.1 mrg break; 299 1.1 mrg 300 1.2 jmmv case 'P': 301 1.19 mrg if (!have_daemon_mode) 302 1.19 mrg goto no_daemon_mode; 303 1.19 mrg 304 1.12 mrg bozo_set_pref(&httpd, &prefs, "pid file", optarg); 305 1.2 jmmv break; 306 1.1 mrg 307 1.20 mrg case 'p': 308 1.20 mrg if (!have_user) 309 1.20 mrg no_user_support: 310 1.20 mrg bozoerr(&httpd, 1, "User support not enabled"); 311 1.20 mrg 312 1.20 mrg bozo_set_pref(&httpd, &prefs, "public_html", optarg); 313 1.20 mrg break; 314 1.19 mrg 315 1.30 martin case 'q': 316 1.30 martin bozo_set_pref(&httpd, &prefs, "no log", "true"); 317 1.30 martin break; 318 1.30 martin 319 1.23 jmcneill case 'R': 320 1.28 mrg if (!have_dirindex) 321 1.28 mrg goto no_dirindex_support; 322 1.28 mrg 323 1.23 jmcneill bozo_set_pref(&httpd, &prefs, "directory index readme", 324 1.23 jmcneill optarg); 325 1.23 jmcneill break; 326 1.23 jmcneill 327 1.20 mrg case 'S': 328 1.20 mrg bozo_set_pref(&httpd, &prefs, "server software", 329 1.20 mrg optarg); 330 1.1 mrg break; 331 1.1 mrg 332 1.20 mrg case 's': 333 1.20 mrg bozo_set_pref(&httpd, &prefs, "log to stderr", "true"); 334 1.20 mrg break; 335 1.19 mrg 336 1.20 mrg case 'T': 337 1.20 mrg /* make sure there're two arguments */ 338 1.1 mrg if (argc - optind < 1) 339 1.1 mrg usage(&httpd, progname); 340 1.20 mrg if (bozo_set_timeout(&httpd, &prefs, 341 1.20 mrg optarg, argv[optind])) { 342 1.20 mrg bozoerr(&httpd, 1, 343 1.20 mrg "invalid type '%s'", optarg); 344 1.20 mrg /* NOTREACHED */ 345 1.20 mrg } 346 1.20 mrg optind++; 347 1.1 mrg break; 348 1.1 mrg 349 1.8 mrg case 't': 350 1.12 mrg bozo_set_pref(&httpd, &prefs, "chroot dir", optarg); 351 1.8 mrg break; 352 1.8 mrg 353 1.20 mrg case 'U': 354 1.20 mrg bozo_set_pref(&httpd, &prefs, "username", optarg); 355 1.1 mrg break; 356 1.1 mrg 357 1.1 mrg case 'u': 358 1.19 mrg if (!have_user) 359 1.19 mrg goto no_user_support; 360 1.19 mrg 361 1.12 mrg bozo_set_pref(&httpd, &prefs, "enable users", "true"); 362 1.1 mrg break; 363 1.19 mrg 364 1.20 mrg case 'V': 365 1.20 mrg bozo_set_pref(&httpd, &prefs, "unknown slash", "true"); 366 1.20 mrg break; 367 1.19 mrg 368 1.20 mrg case 'v': 369 1.20 mrg bozo_set_pref(&httpd, &prefs, "virtual base", optarg); 370 1.1 mrg break; 371 1.1 mrg 372 1.1 mrg case 'X': 373 1.19 mrg if (!have_dirindex) 374 1.19 mrg goto no_dirindex_support; 375 1.19 mrg 376 1.22 mrg bozo_set_pref(&httpd, &prefs, "directory indexing", 377 1.22 mrg "true"); 378 1.22 mrg break; 379 1.22 mrg 380 1.20 mrg case 'x': 381 1.20 mrg bozo_set_pref(&httpd, &prefs, "index.html", optarg); 382 1.1 mrg break; 383 1.1 mrg 384 1.20 mrg case 'Z': 385 1.20 mrg if (!have_ssl) 386 1.20 mrg no_ssl: 387 1.20 mrg bozoerr(&httpd, 1, "ssl support not enabled"); 388 1.14 agc 389 1.20 mrg /* make sure there's two arguments */ 390 1.17 mrg if (argc - optind < 1) 391 1.17 mrg usage(&httpd, progname); 392 1.20 mrg bozo_ssl_set_opts(&httpd, optarg, argv[optind++]); 393 1.20 mrg break; 394 1.20 mrg 395 1.20 mrg case 'z': 396 1.20 mrg if (!have_ssl) 397 1.20 mrg goto no_ssl; 398 1.20 mrg 399 1.20 mrg bozo_ssl_set_ciphers(&httpd, optarg); 400 1.20 mrg break; 401 1.20 mrg 402 1.1 mrg default: 403 1.1 mrg usage(&httpd, progname); 404 1.1 mrg /* NOTREACHED */ 405 1.1 mrg } 406 1.1 mrg } 407 1.1 mrg 408 1.1 mrg argc -= optind; 409 1.1 mrg argv += optind; 410 1.1 mrg 411 1.1 mrg if (argc == 0 || argc > 2) { 412 1.1 mrg usage(&httpd, progname); 413 1.1 mrg } 414 1.1 mrg 415 1.1 mrg /* virtual host, and root of tree to serve */ 416 1.1 mrg bozo_setup(&httpd, &prefs, argv[1], argv[0]); 417 1.1 mrg 418 1.1 mrg /* 419 1.1 mrg * read and process the HTTP request. 420 1.1 mrg */ 421 1.1 mrg do { 422 1.1 mrg if ((request = bozo_read_request(&httpd)) != NULL) { 423 1.1 mrg bozo_process_request(request); 424 1.1 mrg bozo_clean_request(request); 425 1.1 mrg } 426 1.1 mrg } while (httpd.background); 427 1.1 mrg 428 1.26 mrg bozo_cleanup(&httpd, &prefs); 429 1.26 mrg 430 1.1 mrg return (0); 431 1.1 mrg } 432