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 */
58 BOZO_DEAD static void
usage(bozohttpd_t * httpd,char * progname)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_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 
142 int
main(int argc,char ** argv)143 main(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