1 /*
2  *  Copyright (C) 2004, 2005  James Antill
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  *  email: james@and.org
19  */
20 /* conditionally compliant HTTP/1.1 server. */
21 #define _GNU_SOURCE 1 /* strsignal() / posix_fadvise64 */
22 #include <vstr.h>
23 
24 #include <socket_poll.h>
25 #include <timer_q.h>
26 
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <errno.h>
36 #include <err.h>
37 #include <netinet/in.h>
38 #include <netinet/tcp.h>
39 #include <arpa/inet.h>
40 
41 #include <grp.h>
42 
43 #define EX_UTILS_NO_USE_INIT  1
44 #define EX_UTILS_NO_USE_EXIT  1
45 #define EX_UTILS_NO_USE_LIMIT 1
46 #define EX_UTILS_NO_USE_OPEN  1
47 #define EX_UTILS_NO_USE_GET   1
48 #define EX_UTILS_NO_USE_IO_FD 1
49 #define EX_UTILS_RET_FAIL     1
50 #include "ex_utils.h"
51 
52 #include "mk.h"
53 
54 MALLOC_CHECK_DECL();
55 
56 #include "cntl.h"
57 #include "date.h"
58 
59 #define HTTPD_HAVE_GLOBAL_OPTS 1
60 
61 #include "httpd.h"
62 #include "httpd_policy.h"
63 
64 #define CLEN VSTR__AT_COMPILE_STRLEN
65 
66 /* is the cstr a prefix of the vstr */
67 #define VPREFIX(vstr, p, l, cstr)                                       \
68     (((l) >= CLEN(cstr)) &&                                             \
69      vstr_cmp_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
70 /* is the cstr a suffix of the vstr */
71 #define VSUFFIX(vstr, p, l, cstr)                                       \
72     (((l) >= CLEN(cstr)) &&                                             \
73      vstr_cmp_eod_buf_eq(vstr, p, l, cstr, CLEN(cstr)))
74 
75 /* is the cstr a prefix of the vstr, no case */
76 #define VIPREFIX(vstr, p, l, cstr)                                      \
77     (((l) >= CLEN(cstr)) &&                                             \
78      vstr_cmp_case_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
79 
80 /* for simplicity */
81 #define VEQ(vstr, p, l, cstr) vstr_cmp_cstr_eq(vstr, p, l, cstr)
82 
83 static Vlg *vlg = NULL;
84 
usage(const char * program_name,int ret,const char * prefix)85 static void usage(const char *program_name, int ret, const char *prefix)
86 {
87   Vstr_base *out = vstr_make_base(NULL);
88 
89   if (!out)
90     errno = ENOMEM, err(EXIT_FAILURE, "usage");
91 
92   vstr_add_fmt(out, 0, "%s\n\
93  Format: %s [options] <dir>\n\
94   Daemon options\n\
95     --daemon          - Toggle becoming a daemon%s.\n\
96     --chroot          - Change root.\n\
97     --drop-privs      - Toggle droping privilages%s.\n\
98     --priv-uid        - Drop privilages to this uid.\n\
99     --priv-gid        - Drop privilages to this gid.\n\
100     --pid-file        - Log pid to file.\n\
101     --cntl-file       - Create control file.\n\
102     --accept-filter-file\n\
103                       - Load Linux Socket Filter code for accept().\n\
104     --processes       - Number of processes to use (default: 1).\n\
105     --debug -d        - Raise debug level (can be used upto 3 times).\n\
106     --host -H         - IPv4 address to bind (default: \"all\").\n\
107     --help -h         - Print this message.\n\
108     --max-connections\n\
109                   -M  - Max connections allowed (0 = no limit).\n\
110     --nagle -n        - Toggle usage of nagle TCP option%s.\n\
111     --port -P         - Port to bind to.\n\
112     --idle-timeout -t - Timeout (usecs) for connections that are idle.\n\
113     --defer-accept    - Time to defer dataless connections (default: 8s)\n\
114     --version -V      - Print the version string.\n\
115 \n\
116   HTTPD options\n\
117     --mmap            - Toggle use of mmap() to load files%s.\n\
118     --sendfile        - Toggle use of sendfile() to load files%s.\n\
119     --keep-alive      - Toggle use of Keep-Alive handling%s.\n\
120     --keep-alive-1.0  - Toggle use of Keep-Alive handling for HTTP/1.0%s.\n\
121     --virtual-hosts\n\
122     --vhosts          - Toggle use of directory virtual hostnames%s.\n\
123     --range           - Toggle use of partial responces%s.\n\
124     --range-1.0       - Toggle use of partial responces for HTTP/1.0%s.\n\
125     --public-only     - Toggle use of public only privilages%s.\n\
126     --directory-filename\n\
127     --dir-filename    - Filename to use when requesting directories.\n\
128     --server-name     - Contents of server header used in replies.\n\
129     --gzip-content-replacement\n\
130                       - Toggle use of gzip content replacement%s.\n\
131     --mime-types-main - Main mime types filename (default: /etc/mime.types).\n\
132     --mime-types-xtra - Additional mime types filename.\n\
133     --error-406       - Toggle sending 406 responses%s.\n\
134     --canonize-host   - Strip leading 'www.', strip trailing '.'%s.\n\
135     --error-host-400  - Give an 400 error for a bad host%s.\n\
136     --check-host      - Whether we check host headers at all%s.\n\
137     --unspecified-hostname\n\
138                       - Used for req with no Host header (default is hostname).\n\
139     --max-header-sz   - Max size of http header (0 = no limit).\n\
140 ",
141                prefix, program_name,
142                opt_def_toggle(FALSE), opt_def_toggle(FALSE),
143                opt_def_toggle(EVNT_CONF_NAGLE),
144                opt_def_toggle(HTTPD_CONF_USE_MMAP),
145                opt_def_toggle(HTTPD_CONF_USE_SENDFILE),
146                opt_def_toggle(HTTPD_CONF_USE_KEEPA),
147                opt_def_toggle(HTTPD_CONF_USE_KEEPA_1_0),
148                opt_def_toggle(HTTPD_CONF_USE_VHOSTS_NAME),
149                opt_def_toggle(HTTPD_CONF_USE_RANGE),
150                opt_def_toggle(HTTPD_CONF_USE_RANGE_1_0),
151                opt_def_toggle(HTTPD_CONF_USE_PUBLIC_ONLY),
152                opt_def_toggle(HTTPD_CONF_USE_ENC_CONTENT_REPLACEMENT),
153                opt_def_toggle(HTTPD_CONF_USE_ERR_406),
154                opt_def_toggle(HTTPD_CONF_USE_CANONIZE_HOST),
155                opt_def_toggle(HTTPD_CONF_USE_HOST_ERR_400),
156                opt_def_toggle(HTTPD_CONF_USE_HOST_ERR_CHK));
157 
158   if (io_put_all(out, ret ? STDERR_FILENO : STDOUT_FILENO) == IO_FAIL)
159     err(EXIT_FAILURE, "write");
160 
161   exit (ret);
162 }
163 
serv_init(void)164 static void serv_init(void)
165 {
166   if (!vstr_init()) /* init the library */
167     errno = ENOMEM, err(EXIT_FAILURE, "init");
168 
169   vlg_init();
170 
171   if (!vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE,
172                       VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR))
173     errno = ENOMEM, err(EXIT_FAILURE, "init");
174 
175   if (!vstr_cntl_conf(NULL,
176                       VSTR_CNTL_CONF_SET_NUM_BUF_SZ, OPT_SERV_CONF_BUF_SZ))
177     errno = ENOMEM, err(EXIT_FAILURE, "init");
178 
179   /* no passing of conf to evnt */
180   if (!vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '$') ||
181       !vstr_sc_fmt_add_all(NULL) ||
182       !vlg_sc_fmt_add_all(NULL) ||
183       !VSTR_SC_FMT_ADD(NULL, http_fmt_add_vstr_add_vstr,
184                        "<http-esc.vstr", "p%zu%zu", ">") ||
185       !VSTR_SC_FMT_ADD(NULL, http_fmt_add_vstr_add_sect_vstr,
186                        "<http-esc.vstr.sect", "p%p%u", ">"))
187     errno = ENOMEM, err(EXIT_FAILURE, "init");
188 
189   if (!(vlg = vlg_make()))
190     errno = ENOMEM, err(EXIT_FAILURE, "init");
191 
192   if (!VSTR_SC_FMT_ADD(vlg->out_vstr->conf, http_fmt_add_vstr_add_vstr,
193                        "<http-esc.vstr", "p%zu%zu", ">") ||
194       !VSTR_SC_FMT_ADD(vlg->out_vstr->conf, http_fmt_add_vstr_add_sect_vstr,
195                        "<http-esc.vstr.sect", "p%p%u", ">"))
196     errno = ENOMEM, err(EXIT_FAILURE, "init");
197   if (!VSTR_SC_FMT_ADD(vlg->sig_out_vstr->conf, http_fmt_add_vstr_add_vstr,
198                        "<http-esc.vstr", "p%zu%zu", ">") ||
199       !VSTR_SC_FMT_ADD(vlg->sig_out_vstr->conf, http_fmt_add_vstr_add_sect_vstr,
200                        "<http-esc.vstr.sect", "p%p%u", ">"))
201     errno = ENOMEM, err(EXIT_FAILURE, "init");
202 
203   if (!socket_poll_init(0, SOCKET_POLL_TYPE_MAP_DIRECT))
204       errno = ENOMEM, err(EXIT_FAILURE, "init");
205 
206   evnt_logger(vlg);
207   evnt_poll_init();
208   evnt_timeout_init();
209 
210   vlg_time_set(vlg, evnt_sc_time);
211 
212   opt_serv_logger(vlg);
213 
214   httpd_init(vlg);
215 
216   opt_serv_sc_signals();
217 }
218 
serv_cb_func_send(struct Evnt * evnt)219 static int serv_cb_func_send(struct Evnt *evnt)
220 {
221   struct Con *con = (struct Con *)evnt;
222 
223   assert(HTTPD_CONF_SEND_CALL_LIMIT >= 1);
224   con->io_limit_num = HTTPD_CONF_SEND_CALL_LIMIT;
225   return (httpd_serv_send(con));
226 }
227 
serv_cb_func_recv(struct Evnt * evnt)228 static int serv_cb_func_recv(struct Evnt *evnt)
229 {
230   struct Con *con = (struct Con *)evnt;
231 
232   assert(HTTPD_CONF_RECV_CALL_LIMIT >= 1);
233   con->io_limit_num = HTTPD_CONF_RECV_CALL_LIMIT;
234   return (httpd_serv_recv(con));
235 }
236 
serv_cb_func_free(struct Evnt * evnt)237 static void serv_cb_func_free(struct Evnt *evnt)
238 {
239   struct Con *con = (struct Con *)evnt;
240 
241   httpd_fin_fd_close(con);
242 
243   opt_serv_sc_free_beg(evnt, con->acpt_sa_ref);
244 
245   ASSERT(con->fs && !con->fs_num && !con->fs_off && (con->fs->fd == -1));
246 
247   vstr_free_base(con->mpbr_ct);
248 
249   if (con->fs_sz > 1)
250   {
251     ASSERT(con->fs != con->fs_store);
252     F(con->fs);
253   }
254   else
255     ASSERT(con->fs == con->fs_store);
256 
257   F(con);
258 }
259 
serv_cb_func_accept(struct Evnt * from_evnt,int fd,struct sockaddr * sa,socklen_t len)260 static struct Evnt *serv_cb_func_accept(struct Evnt *from_evnt, int fd,
261                                         struct sockaddr *sa, socklen_t len)
262 {
263   struct Acpt_listener *acpt_listener = (struct Acpt_listener *)from_evnt;
264   struct Con *con = MK(sizeof(struct Con));
265 
266   if (sa->sa_family != AF_INET) /* only support IPv4 atm. */
267     goto sa_fail;
268 
269   if (!con || !evnt_make_acpt_dup(con->evnt, fd, sa, len))
270     goto make_acpt_fail;
271 
272   con->evnt->cbs->cb_func_recv       = serv_cb_func_recv;
273   con->evnt->cbs->cb_func_send       = serv_cb_func_send;
274   con->evnt->cbs->cb_func_free       = serv_cb_func_free;
275 
276   if (!httpd_con_init(con, acpt_listener))
277     goto evnt_fail;
278 
279   if (!evnt_sc_timeout_via_mtime(con->evnt,
280                                  con->policy->s->idle_timeout * 1000))
281     VLG_WARNNOMEM_GOTO(evnt_fail, (vlg, "timeout: %m\n"));
282 
283   if (!opt_serv_sc_acpt_end(con->policy->s, from_evnt, con->evnt))
284     goto evnt_fail;
285 
286   ASSERT(!con->evnt->flag_q_closed);
287 
288   return (con->evnt);
289 
290  evnt_fail:
291   evnt_close(con->evnt);
292   return (con->evnt);
293 
294  make_acpt_fail:
295   F(con);
296   VLG_WARNNOMEM_RET(NULL, (vlg, "%s: %m\n", "accept"));
297 
298  sa_fail:
299   F(con);
300   VLG_WARNNOMEM_RET(NULL, (vlg, "%s: HTTPD sa == ipv4 fail\n", "accept"));
301 }
302 
serv_make_bind(const char * program_name)303 static void serv_make_bind(const char *program_name)
304 {
305   Opt_serv_addr_opts *addr = httpd_opts->s->addr_beg;
306 
307   while (addr)
308   {
309     const char *ipv4_address = NULL;
310     const char *acpt_filter_file = NULL;
311     struct Evnt *evnt = NULL;
312 
313     OPT_SC_EXPORT_CSTR(ipv4_address,     addr->ipv4_address,     FALSE,
314                        "ipv4 address");
315     OPT_SC_EXPORT_CSTR(acpt_filter_file, addr->acpt_filter_file, FALSE,
316                        "accept filter file");
317 
318     evnt = evnt_sc_serv_make_bind(ipv4_address, addr->tcp_port,
319                                   addr->q_listen_len,
320                                   addr->max_connections,
321                                   addr->defer_accept,
322                                   acpt_filter_file);
323 
324     evnt->cbs->cb_func_accept = serv_cb_func_accept;
325 
326     addr = addr->next;
327   }
328 }
329 
330 #define VCMP_MT_EQ_ALL(x, y, z)               \
331     vstr_cmp_eq(x -> mime_types_ ## z, 1, x -> mime_types_ ## z ->len,  \
332                 y -> mime_types_ ## z, 1, y -> mime_types_ ## z ->len)
serv__mime_types_eq(Httpd_policy_opts * node)333 static Httpd_policy_opts *serv__mime_types_eq(Httpd_policy_opts *node)
334 { /* compares both mime filenames ... */
335   Opt_serv_policy_opts *scan = httpd_opts->s->def_policy;
336 
337   ASSERT(node);
338 
339   while (scan != node->s)
340   {
341     Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
342 
343     if (VCMP_MT_EQ_ALL(tmp, node, main) && VCMP_MT_EQ_ALL(tmp, node, xtra))
344       return (tmp);
345 
346     scan = scan->next;
347   }
348 
349   return (NULL);
350 }
351 #undef VCMP_MT_EQ_ALL
352 
serv_mime_types(const char * program_name)353 static void serv_mime_types(const char *program_name)
354 {
355   Opt_serv_policy_opts *scan = httpd_opts->s->def_policy;
356 
357   while (scan)
358   {
359     Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
360     Httpd_policy_opts *prev = NULL;
361 
362     if (!mime_types_init(tmp->mime_types,
363                          tmp->mime_types_def_ct, 1,
364                          tmp->mime_types_def_ct->len))
365       errno = ENOMEM, err(EXIT_FAILURE, "init");
366 
367     if ((prev = serv__mime_types_eq(tmp)))
368       mime_types_combine_filedata(tmp->mime_types, prev->mime_types);
369     else
370     {
371       const char *mime_types_main = NULL;
372       const char *mime_types_xtra = NULL;
373 
374       OPT_SC_EXPORT_CSTR(mime_types_main, tmp->mime_types_main, FALSE,
375                          "MIME types main file");
376       OPT_SC_EXPORT_CSTR(mime_types_xtra, tmp->mime_types_xtra, FALSE,
377                          "MIME types extra file");
378 
379       if (!mime_types_load_simple(tmp->mime_types, mime_types_main))
380         err(EXIT_FAILURE, "load_mime(%s)", mime_types_main);
381 
382       if (!mime_types_load_simple(tmp->mime_types, mime_types_xtra))
383         err(EXIT_FAILURE, "load_mime(%s)", mime_types_xtra);
384     }
385 
386     scan = scan->next;
387   }
388 
389   /* we don't need the filenames after we've loaded... */
390   scan = httpd_opts->s->def_policy;
391   while (scan)
392   {
393     Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
394 
395     vstr_free_base(tmp->mime_types_main); tmp->mime_types_main = NULL;
396     vstr_free_base(tmp->mime_types_xtra); tmp->mime_types_xtra = NULL;
397 
398     scan = scan->next;
399   }
400 }
401 
serv_canon_policies(void)402 static void serv_canon_policies(void)
403 {
404   Opt_serv_policy_opts *scan = httpd_opts->s->def_policy;
405 
406   while (scan)
407   { /* check variables for things which will screw us too much */
408     Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
409     Vstr_base *s1 = NULL;
410 
411     ASSERT(scan->beg == httpd_opts->s);
412 
413     s1 = tmp->document_root;
414     if (!httpd_canon_dir_path(s1))
415       VLG_ERRNOMEM((vlg, EXIT_FAILURE, "canon_dir_path($<vstr.all:%p>): %m\n",
416                     s1));
417 
418     s1 = tmp->req_conf_dir;
419     if (!httpd_canon_dir_path(s1))
420       VLG_ERRNOMEM((vlg, EXIT_FAILURE, "canon_dir_path($<vstr.all:%p>): %m\n",
421                     s1));
422 
423     s1 = tmp->req_err_dir;
424     if (!httpd_canon_abs_dir_path(s1))
425       VLG_ERRNOMEM((vlg, EXIT_FAILURE,
426                     "canon_abs_dir_path($<vstr.all:%p>): %m\n", s1));
427 
428     if (!httpd_init_default_hostname(scan))
429       VLG_ERRNOMEM((vlg, EXIT_FAILURE, "hostname(): %m\n"));
430 
431     s1 = tmp->dir_filename;
432     if (!httpd_valid_url_filename(s1, 1, s1->len) &&
433         !vstr_sub_cstr_ptr(s1, 1, s1->len, HTTPD_CONF_DEF_DIR_FILENAME))
434       VLG_ERRNOMEM((vlg, EXIT_FAILURE, "dir_filename(): %m\n"));
435 
436     scan = scan->next;
437   }
438 }
439 
serv_cmd_line(int argc,char * argv[])440 static void serv_cmd_line(int argc, char *argv[])
441 {
442   int optchar = 0;
443   const char *program_name = NULL;
444   struct option long_options[] =
445   {
446    OPT_SERV_DECL_GETOPTS(),
447 
448    {"configuration-file", required_argument, NULL, 'C'},
449    {"config-file",        required_argument, NULL, 'C'},
450    {"configuration-data-daemon", required_argument, NULL, 143},
451    {"config-data-daemon",        required_argument, NULL, 143},
452    {"configuration-data-jhttpd", required_argument, NULL, 144},
453    {"config-data-jhttpd",        required_argument, NULL, 144},
454 
455    {"sendfile", optional_argument, NULL, 31},
456    {"mmap", optional_argument, NULL, 30},
457 
458    {"max-header-sz", required_argument, NULL, 128},
459    {"keep-alive", optional_argument, NULL, 129},
460    {"keep-alive-1.0", optional_argument, NULL, 130},
461    {"vhosts", optional_argument, NULL, 131},
462    {"virtual-hosts", optional_argument, NULL, 131},
463    {"range", optional_argument, NULL, 132},
464    {"range-1.0", optional_argument, NULL, 133},
465    {"public-only", optional_argument, NULL, 134}, /* FIXME: rm ? */
466    {"dir-filename", required_argument, NULL, 135},
467    {"server-name", required_argument, NULL, 136},
468    {"gzip-content-replacement", optional_argument, NULL, 137},
469    /* 138 */
470    {"error-406", optional_argument, NULL, 139},
471    /* 140 */
472    {"mime-types-main", required_argument, NULL, 141},
473    {"mime-types-extra", required_argument, NULL, 142},
474    {"mime-types-xtra", required_argument, NULL, 142},
475    /* 143 -- config data above */
476    /* 144 -- config data above */
477    {"unspecified-hostname", required_argument, NULL, 145},
478    {"canonize-host", optional_argument, NULL, 146},
479    {"error-host-400", optional_argument, NULL, 147},
480    {"check-host", optional_argument, NULL, 148},
481    /* {"404-file", required_argument, NULL, 0}, */
482    {NULL, 0, NULL, 0}
483   };
484   const char *chroot_dir = NULL;
485   const char *document_root = NULL;
486   Vstr_base *out = vstr_make_base(NULL);
487   Httpd_policy_opts *popts = NULL;
488 
489   if (!out)
490     errno = ENOMEM, err(EXIT_FAILURE, "command line");
491 
492   evnt_opt_nagle = TRUE;
493 
494   program_name = opt_program_name(argv[0], HTTPD_CONF_PROG_NAME);
495   httpd_opts->s->name_cstr = program_name;
496   httpd_opts->s->name_len  = strlen(program_name);
497 
498   httpd_opts->s->make_policy = httpd_policy_make;
499   httpd_opts->s->copy_policy = httpd_policy_copy;
500 
501   if (!httpd_conf_main_init(httpd_opts))
502     errno = ENOMEM, err(EXIT_FAILURE, "options");
503 
504   if (!geteuid()) /* If root */
505     httpd_opts->s->addr_beg->tcp_port = HTTPD_CONF_SERV_DEF_PORT;
506   else /* somewhat common unprived port */
507     httpd_opts->s->addr_beg->tcp_port = 8008;
508 
509   popts = (Httpd_policy_opts *)httpd_opts->s->def_policy;
510   while ((optchar = getopt_long(argc, argv, "C:dhH:M:nP:t:V",
511                                 long_options, NULL)) != -1)
512   {
513     switch (optchar)
514     {
515       case '?': usage(program_name, EXIT_FAILURE, "");
516       case 'h': usage(program_name, EXIT_SUCCESS, "");
517 
518       case 'V':
519         vstr_add_fmt(out, 0, " %s version %s.\n",
520                      program_name, HTTPD_CONF_VERSION);
521 
522         if (io_put_all(out, STDOUT_FILENO) == IO_FAIL)
523           err(EXIT_FAILURE, "write");
524 
525         exit (EXIT_SUCCESS);
526 
527       OPT_SERV_GETOPTS(httpd_opts->s);
528 
529       case 'C':
530         if (!httpd_conf_main_parse_file(out, httpd_opts, optarg))
531           goto out_err_conf_msg;
532         break;
533       case 143: /* FIXME: ... need to integrate */
534         if (!opt_serv_conf_parse_cstr(out, httpd_opts->s, optarg))
535           goto out_err_conf_msg;
536       break;
537       case 144:
538         if (!httpd_conf_main_parse_cstr(out, httpd_opts, optarg))
539           goto out_err_conf_msg;
540         break;
541 
542       case 128: OPT_NUM_NR_ARG(popts->max_header_sz, "max header size"); break;
543 
544       case  31: OPT_TOGGLE_ARG(popts->use_sendfile);                 break;
545       case  30: OPT_TOGGLE_ARG(popts->use_mmap);                     break;
546 
547       case 129: OPT_TOGGLE_ARG(popts->use_keep_alive);               break;
548       case 130: OPT_TOGGLE_ARG(popts->use_keep_alive_1_0);           break;
549       case 131: OPT_TOGGLE_ARG(popts->use_vhosts_name);              break;
550       case 132: OPT_TOGGLE_ARG(popts->use_range);                    break;
551       case 133: OPT_TOGGLE_ARG(popts->use_range_1_0);                break;
552       case 134: OPT_TOGGLE_ARG(popts->use_public_only);              break;
553       case 135: OPT_VSTR_ARG(popts->dir_filename);                   break;
554       case 136: OPT_VSTR_ARG(popts->server_name);                    break;
555       case 137: OPT_TOGGLE_ARG(popts->use_enc_content_replacement);  break;
556       case 139: OPT_TOGGLE_ARG(popts->use_err_406);                  break;
557         /* case 140: */
558       case 141: OPT_VSTR_ARG(popts->mime_types_main);                break;
559       case 142: OPT_VSTR_ARG(popts->mime_types_xtra);                break;
560         /* case 143: */
561         /* case 144: */
562       case 145: OPT_VSTR_ARG(popts->default_hostname);               break;
563       case 146: OPT_TOGGLE_ARG(popts->use_canonize_host);            break;
564       case 147: OPT_TOGGLE_ARG(popts->use_host_err_400);             break;
565       case 148: OPT_TOGGLE_ARG(popts->use_host_err_chk);
566 
567 
568       ASSERT_NO_SWITCH_DEF();
569     }
570   }
571   vstr_free_base(out); out = NULL;
572 
573   argc -= optind;
574   argv += optind;
575 
576   if (argc > 1)
577     usage(program_name, EXIT_FAILURE, " Too many arguments.\n");
578 
579   if (argc == 1)
580   {
581     Vstr_base *tmp = popts->document_root;
582     vstr_sub_cstr_ptr(tmp, 1, tmp->len, argv[0]);
583   }
584 
585   if (!popts->document_root->len)
586     usage(program_name, EXIT_FAILURE, " Not specified a document root.\n");
587 
588   if (httpd_opts->s->become_daemon)
589   {
590     if (daemon(FALSE, FALSE) == -1)
591       err(EXIT_FAILURE, "daemon");
592     vlg_daemon(vlg, program_name);
593   }
594 
595   if (httpd_opts->s->rlim_core_call)
596     opt_serv_sc_rlim_core_num(httpd_opts->s->rlim_core_num);
597   if (httpd_opts->s->rlim_file_call)
598     opt_serv_sc_rlim_file_num(httpd_opts->s->rlim_file_num);
599 
600   {
601     const char *pid_file = NULL;
602     const char *cntl_file = NULL;
603     Opt_serv_opts *opts = httpd_opts->s;
604 
605     OPT_SC_EXPORT_CSTR(pid_file,   opts->pid_file,   FALSE, "pid file");
606     OPT_SC_EXPORT_CSTR(cntl_file,  opts->cntl_file,  FALSE, "control file");
607     OPT_SC_EXPORT_CSTR(chroot_dir, opts->chroot_dir, FALSE, "chroot directory");
608 
609     serv_make_bind(program_name);
610 
611     if (!httpd_init_default_hostname(httpd_opts->s->def_policy))
612       errno = ENOMEM, err(EXIT_FAILURE, "default_hostname");
613 
614     if (pid_file)
615       vlg_pid_file(vlg, pid_file);
616 
617     if (cntl_file)
618       cntl_make_file(vlg, cntl_file);
619 
620     serv_canon_policies();
621 
622     OPT_SC_EXPORT_CSTR(document_root, popts->document_root, TRUE,
623                        "document root");
624 
625     serv_mime_types(program_name);
626 
627     if (chroot_dir)
628       vlg_sc_bind_mount(chroot_dir);
629 
630     /* after daemon so syslog works */
631     if (chroot_dir && ((chroot(chroot_dir) == -1) || (chdir("/") == -1)))
632       vlg_err(vlg, EXIT_FAILURE, "chroot(%s): %m\n", chroot_dir);
633 
634     if (opts->drop_privs)
635     {
636       OPT_SC_RESOLVE_UID(opts);
637       OPT_SC_RESOLVE_GID(opts);
638       opt_serv_sc_drop_privs(opts);
639     }
640 
641     if (opts->num_procs > 1)
642       cntl_sc_multiproc(vlg, opts->num_procs, !!cntl_file, opts->use_pdeathsig);
643   }
644 
645   httpd_opts->beg_time = time(NULL);
646 
647   /*  if (make_dumpable && (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1))
648    *    vlg_warn(vlg, "prctl(SET_DUMPABLE, TRUE): %m\n"); */
649 
650   {
651     struct Evnt *evnt = evnt_queue("accept");
652 
653     while (evnt)
654     {
655       vlg_info(vlg, "READY [$<sa:%p>]: %s%s%s\n", EVNT_SA(evnt),
656                chroot_dir ? chroot_dir : "",
657                chroot_dir ?        "/" : "",
658                document_root);
659       evnt = evnt->next;
660     }
661   }
662 
663   opt_serv_conf_free(httpd_opts->s);
664   return;
665 
666  out_err_conf_msg:
667   vstr_add_cstr_ptr(out, out->len, "\n");
668   if (io_put_all(out, STDERR_FILENO) == IO_FAIL)
669     err(EXIT_FAILURE, "write");
670   exit (EXIT_FAILURE);
671 }
672 
main(int argc,char * argv[])673 int main(int argc, char *argv[])
674 {
675   serv_init();
676 
677   serv_cmd_line(argc, argv);
678 
679   while (evnt_waiting())
680   {
681     evnt_sc_main_loop(HTTPD_CONF_MAX_WAIT_SEND);
682     opt_serv_sc_check_children();
683     opt_serv_sc_cntl_resources(httpd_opts->s);
684   }
685   evnt_out_dbg3("E");
686 
687   evnt_timeout_exit();
688   cntl_child_free();
689   evnt_close_all();
690 
691   httpd_exit();
692 
693   http_req_exit();
694 
695   vlg_free(vlg);
696   vlg_exit();
697 
698   httpd_conf_main_free(httpd_opts);
699 
700   vstr_exit();
701 
702   MALLOC_CHECK_EMPTY();
703 
704   exit (EXIT_SUCCESS);
705 }
706