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