1 /* $NetBSD: main.c,v 1.29 2021/08/24 09:47:36 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-2021 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 */ 58 BOZO_DEAD static void 59 usage(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_dirindex) 106 bozowarn(httpd, " -R readme\t\tput readme file in footer " 107 "of directory index"); 108 if (have_core) { 109 bozowarn(httpd, " -S version\t\tset server version string"); 110 bozowarn(httpd, " -s\t\t\talways log to stderr"); 111 bozowarn(httpd, " -T type timeout\t" 112 "set <ssl|initial|header|request> timeout"); 113 bozowarn(httpd, " -t dir\t\tchroot to `dir'"); 114 bozowarn(httpd, " -U user\t\tchange user to `user'"); 115 } 116 if (have_user) 117 bozowarn(httpd, " -u\t\t\tenable ~user/public_html support"); 118 if (have_core) { 119 bozowarn(httpd, " -V\t\t\tUnknown virtual hosts go to " 120 "`slashdir'"); 121 bozowarn(httpd, " -v virtualroot\tenable virtual host " 122 "support in this directory"); 123 } 124 if (have_dirindex) 125 bozowarn(httpd, " -X\t\t\tdirectory index support"); 126 if (have_core) 127 bozowarn(httpd, " -x index\t\tdefault \"index.html\" " 128 "file name"); 129 if (have_ssl) { 130 bozowarn(httpd, " -Z cert privkey\tspecify path to server " 131 "certificate and private key file\n" 132 "\t\t\tin pem format and enable bozohttpd in " 133 "SSL mode"); 134 bozowarn(httpd, " -z ciphers\t\tspecify SSL ciphers"); 135 } 136 137 bozoerr(httpd, 1, "%s failed to start", progname); 138 } 139 140 int 141 main(int argc, char **argv) 142 { 143 bozo_httpreq_t *request; 144 bozohttpd_t httpd; 145 bozoprefs_t prefs; 146 char *progname; 147 const char *val; 148 int c; 149 150 (void) memset(&httpd, 0x0, sizeof(httpd)); 151 (void) memset(&prefs, 0x0, sizeof(prefs)); 152 153 if ((progname = strrchr(argv[0], '/')) == NULL) 154 progname = argv[0]; 155 else 156 progname++; 157 158 openlog(progname, LOG_PID|LOG_NDELAY, LOG_FTP); 159 160 bozo_set_defaults(&httpd, &prefs); 161 162 /* 163 * -r option was removed, do not reuse it for a while 164 */ 165 166 while ((c = getopt(argc, argv, 167 "C:EGHI:L:M:m:P:R:S:T:U:VXZ:bc:defhi:np:st:uv:x:z:")) != -1) { 168 switch (c) { 169 170 case 'b': 171 if (!have_daemon_mode) 172 no_daemon_mode: 173 bozoerr(&httpd, 1, "Daemon mode not enabled"); 174 175 /* 176 * test suite support - undocumented 177 * background == 2 (aka, -b -b) means to 178 * only process 1 per kid 179 */ 180 val = bozo_get_pref(&prefs, "background") == NULL ? 181 "1" : "2"; 182 bozo_set_pref(&httpd, &prefs, "background", val); 183 break; 184 185 case 'C': 186 if (!have_dynamic_content || 187 !have_cgibin) 188 bozoerr(&httpd, 1, 189 "dynamic CGI handler support not enabled"); 190 191 /* make sure there's two arguments */ 192 if (argc - optind < 1) 193 usage(&httpd, progname); 194 bozo_add_content_map_cgi(&httpd, optarg, 195 argv[optind++]); 196 break; 197 198 case 'c': 199 if (!have_cgibin) 200 bozoerr(&httpd, 1, "CGI not enabled"); 201 202 bozo_cgi_setbin(&httpd, optarg); 203 break; 204 205 case 'd': 206 if (!have_debug) 207 bozowarn(&httpd, "Debugging not enabled"); 208 httpd.debug++; 209 break; 210 211 case 'E': 212 if (!have_user || 213 !have_cgibin) 214 bozoerr(&httpd, 1, "CGI not enabled"); 215 216 bozo_set_pref(&httpd, &prefs, "enable user cgibin", 217 "true"); 218 break; 219 220 case 'e': 221 bozo_set_pref(&httpd, &prefs, "dirty environment", 222 "true"); 223 break; 224 225 case 'f': 226 if (!have_daemon_mode) 227 goto no_daemon_mode; 228 229 bozo_set_pref(&httpd, &prefs, "foreground", "true"); 230 break; 231 232 case 'G': 233 { 234 char version[128]; 235 236 bozo_get_version(version, sizeof(version)); 237 printf("bozohttpd version %s\n", version); 238 } 239 return 0; 240 241 case 'H': 242 if (!have_dirindex) 243 no_dirindex_support: 244 bozoerr(&httpd, 1, 245 "directory indexing not enabled"); 246 247 bozo_set_pref(&httpd, &prefs, "hide dots", "true"); 248 break; 249 250 case 'I': 251 bozo_set_pref(&httpd, &prefs, "port number", optarg); 252 break; 253 254 case 'i': 255 if (!have_daemon_mode) 256 goto no_daemon_mode; 257 258 bozo_set_pref(&httpd, &prefs, "bind address", optarg); 259 break; 260 261 case 'L': 262 if (!have_lua) 263 bozoerr(&httpd, 1, "Lua support not enabled"); 264 265 /* make sure there's two argument */ 266 if (argc - optind < 1) 267 usage(&httpd, progname); 268 bozo_add_lua_map(&httpd, optarg, argv[optind]); 269 optind++; 270 break; 271 272 case 'M': 273 if (!have_dynamic_content) 274 bozoerr(&httpd, 1, 275 "dynamic mime content support not enabled"); 276 277 /* make sure there're four arguments */ 278 if (argc - optind < 3) 279 usage(&httpd, progname); 280 bozo_add_content_map_mime(&httpd, optarg, argv[optind], 281 argv[optind+1], argv[optind+2]); 282 optind += 3; 283 break; 284 285 case 'm': 286 if (!have_ssl) 287 goto no_ssl; 288 289 httpd.ssl_min_proto = optarg; 290 debug((&httpd, DEBUG_NORMAL, 291 "using minimum protocol version: %s", optarg)); 292 break; 293 294 case 'n': 295 bozo_set_pref(&httpd, &prefs, "numeric", "true"); 296 break; 297 298 case 'P': 299 if (!have_daemon_mode) 300 goto no_daemon_mode; 301 302 bozo_set_pref(&httpd, &prefs, "pid file", optarg); 303 break; 304 305 case 'p': 306 if (!have_user) 307 no_user_support: 308 bozoerr(&httpd, 1, "User support not enabled"); 309 310 bozo_set_pref(&httpd, &prefs, "public_html", optarg); 311 break; 312 313 case 'R': 314 if (!have_dirindex) 315 goto no_dirindex_support; 316 317 bozo_set_pref(&httpd, &prefs, "directory index readme", 318 optarg); 319 break; 320 321 case 'S': 322 bozo_set_pref(&httpd, &prefs, "server software", 323 optarg); 324 break; 325 326 case 's': 327 bozo_set_pref(&httpd, &prefs, "log to stderr", "true"); 328 break; 329 330 case 'T': 331 /* make sure there're two arguments */ 332 if (argc - optind < 1) 333 usage(&httpd, progname); 334 if (bozo_set_timeout(&httpd, &prefs, 335 optarg, argv[optind])) { 336 bozoerr(&httpd, 1, 337 "invalid type '%s'", optarg); 338 /* NOTREACHED */ 339 } 340 optind++; 341 break; 342 343 case 't': 344 bozo_set_pref(&httpd, &prefs, "chroot dir", optarg); 345 break; 346 347 case 'U': 348 bozo_set_pref(&httpd, &prefs, "username", optarg); 349 break; 350 351 case 'u': 352 if (!have_user) 353 goto no_user_support; 354 355 bozo_set_pref(&httpd, &prefs, "enable users", "true"); 356 break; 357 358 case 'V': 359 bozo_set_pref(&httpd, &prefs, "unknown slash", "true"); 360 break; 361 362 case 'v': 363 bozo_set_pref(&httpd, &prefs, "virtual base", optarg); 364 break; 365 366 case 'X': 367 if (!have_dirindex) 368 goto no_dirindex_support; 369 370 bozo_set_pref(&httpd, &prefs, "directory indexing", 371 "true"); 372 break; 373 374 case 'x': 375 bozo_set_pref(&httpd, &prefs, "index.html", optarg); 376 break; 377 378 case 'Z': 379 if (!have_ssl) 380 no_ssl: 381 bozoerr(&httpd, 1, "ssl support not enabled"); 382 383 /* make sure there's two arguments */ 384 if (argc - optind < 1) 385 usage(&httpd, progname); 386 bozo_ssl_set_opts(&httpd, optarg, argv[optind++]); 387 break; 388 389 case 'z': 390 if (!have_ssl) 391 goto no_ssl; 392 393 bozo_ssl_set_ciphers(&httpd, optarg); 394 break; 395 396 default: 397 usage(&httpd, progname); 398 /* NOTREACHED */ 399 } 400 } 401 402 argc -= optind; 403 argv += optind; 404 405 if (argc == 0 || argc > 2) { 406 usage(&httpd, progname); 407 } 408 409 /* virtual host, and root of tree to serve */ 410 bozo_setup(&httpd, &prefs, argv[1], argv[0]); 411 412 /* 413 * read and process the HTTP request. 414 */ 415 do { 416 if ((request = bozo_read_request(&httpd)) != NULL) { 417 bozo_process_request(request); 418 bozo_clean_request(request); 419 } 420 } while (httpd.background); 421 422 bozo_cleanup(&httpd, &prefs); 423 424 return (0); 425 } 426