1 /* mini_httpd - small HTTP server
2 **
3 ** Copyright � 1999,2000 by Jef Poskanzer <jef@mail.acme.com>.
4 ** All rights reserved.
5 **
6 ** Redistribution and use in source and binary forms, with or without
7 ** modification, are permitted provided that the following conditions
8 ** are met:
9 ** 1. Redistributions of source code must retain the above copyright
10 **    notice, this list of conditions and the following disclaimer.
11 ** 2. Redistributions in binary form must reproduce the above copyright
12 **    notice, this list of conditions and the following disclaimer in the
13 **    documentation and/or other materials provided with the distribution.
14 **
15 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 ** SUCH DAMAGE.
26 */
27 
28 
29 #include "version.h"
30 
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <syslog.h>
37 #include <limits.h>
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/mman.h>
42 #include <time.h>
43 #include <pwd.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <signal.h>
47 #include <ctype.h>
48 #include <sys/wait.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <netinet/tcp.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
54 #include <dirent.h>
55 
56 #include "port.h"
57 #include "match.h"
58 #include "tdate_parse.h"
59 
60 #ifdef HAVE_SENDFILE
61 # ifdef HAVE_LINUX_SENDFILE
62 #  include <sys/sendfile.h>
63 # else /* HAVE_LINUX_SENDFILE */
64 #  include <sys/uio.h>
65 # endif /* HAVE_LINUX_SENDFILE */
66 #endif /* HAVE_SENDFILE */
67 
68 #if defined(TCP_CORK) && !defined(TCP_NOPUSH)
69 #define TCP_NOPUSH TCP_CORK
70 /* (Linux's TCP_CORK is basically the same as BSD's TCP_NOPUSH.) */
71 #endif
72 
73 #ifdef USE_SSL
74 #include <openssl/ssl.h>
75 #include <openssl/err.h>
76 #endif /* USE_SSL */
77 
78 
79 #if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
80 #define USE_IPV6
81 #endif
82 
83 #ifndef STDIN_FILENO
84 #define STDIN_FILENO 0
85 #endif
86 #ifndef STDOUT_FILENO
87 #define STDOUT_FILENO 1
88 #endif
89 #ifndef STDERR_FILENO
90 #define STDERR_FILENO 2
91 #endif
92 
93 #ifndef SHUT_WR
94 #define SHUT_WR 1
95 #endif
96 
97 #ifndef SIZE_T_MAX
98 #define SIZE_T_MAX 2147483647L
99 #endif
100 
101 #ifndef HAVE_INT64T
102 typedef long long int64_t;
103 #endif
104 
105 #ifdef __CYGWIN__
106 #define timezone  _timezone
107 #endif
108 
109 #ifndef MAX
110 #define MAX(a,b) ((a) > (b) ? (a) : (b))
111 #endif
112 #ifndef MIN
113 #define MIN(a,b) ((a) < (b) ? (a) : (b))
114 #endif
115 
116 /* Do overlapping strcpy safely, by using memmove. */
117 #define ol_strcpy(dst,src) memmove(dst,src,strlen(src)+1)
118 
119 #ifndef ERR_DIR
120 #define ERR_DIR "errors"
121 #endif /* ERR_DIR */
122 #ifndef DEFAULT_HTTP_PORT
123 #define DEFAULT_HTTP_PORT 80
124 #endif /* DEFAULT_HTTP_PORT */
125 #ifdef USE_SSL
126 #ifndef DEFAULT_HTTPS_PORT
127 #define DEFAULT_HTTPS_PORT 443
128 #endif /* DEFAULT_HTTPS_PORT */
129 #ifndef DEFAULT_CERTFILE
130 #define DEFAULT_CERTFILE "mini_httpd.pem"
131 #endif /* DEFAULT_CERTFILE */
132 #endif /* USE_SSL */
133 #ifndef DEFAULT_USER
134 #define DEFAULT_USER "nobody"
135 #endif /* DEFAULT_USER */
136 #ifndef CGI_NICE
137 #define CGI_NICE 10
138 #endif /* CGI_NICE */
139 #ifndef CGI_PATH
140 #define CGI_PATH "/usr/local/bin:/usr/ucb:/bin:/usr/bin"
141 #endif /* CGI_PATH */
142 #ifndef CGI_LD_LIBRARY_PATH
143 #define CGI_LD_LIBRARY_PATH "/usr/local/lib:/usr/lib"
144 #endif /* CGI_LD_LIBRARY_PATH */
145 #ifndef AUTH_FILE
146 #define AUTH_FILE ".htpasswd"
147 #endif /* AUTH_FILE */
148 #ifndef READ_TIMEOUT
149 #define READ_TIMEOUT 60
150 #endif /* READ_TIMEOUT */
151 #ifndef WRITE_TIMEOUT
152 #define WRITE_TIMEOUT 300
153 #endif /* WRITE_TIMEOUT */
154 #ifndef DEFAULT_CHARSET
155 #define DEFAULT_CHARSET "UTF-8"
156 #endif /* DEFAULT_CHARSET */
157 #ifndef MAX_SEND_BUFFER_SIZE
158 #define MAX_SEND_BUFFER_SIZE 1048576
159 #endif /* MAX_SEND_BUFFER_SIZE */
160 
161 
162 #define METHOD_UNKNOWN 0
163 #define METHOD_GET 1
164 #define METHOD_HEAD 2
165 #define METHOD_POST 3
166 #define METHOD_PUT 4
167 #define METHOD_DELETE 5
168 #define METHOD_TRACE 6
169 
170 
171 /* A multi-family sockaddr. */
172 typedef union {
173     struct sockaddr sa;
174     struct sockaddr_in sa_in;
175 #ifdef USE_IPV6
176     struct sockaddr_in6 sa_in6;
177     struct sockaddr_storage sa_stor;
178 #endif /* USE_IPV6 */
179     } usockaddr;
180 
181 
182 static char* argv0;
183 static int debug;
184 static unsigned short port;
185 static char* dir;
186 static char* data_dir;
187 static int do_chroot;
188 static int vhost;
189 static char* user;
190 static char* cgi_pattern;
191 static char* url_pattern;
192 static int no_empty_referrers;
193 static char* local_pattern;
194 static char* hostname;
195 static char hostname_buf[500];
196 static char* logfile;
197 static char* pidfile;
198 static char* charset;
199 static char* p3p;
200 static int max_age;
201 static FILE* logfp;
202 static int listen4_fd, listen6_fd;
203 static int do_ssl;
204 #ifdef USE_SSL
205 static char* certfile;
206 static char* cipher;
207 static SSL_CTX* ssl_ctx;
208 #endif /* USE_SSL */
209 static char cwd[MAXPATHLEN];
210 static int got_hup;
211 
212 
213 /* Request variables. */
214 static int conn_fd;
215 #ifdef USE_SSL
216 static SSL* ssl;
217 #endif /* USE_SSL */
218 static usockaddr client_addr;
219 static char* request;
220 static size_t request_size, request_len, request_idx;
221 static int method;
222 static char* path;
223 static char* file;
224 static char* pathinfo;
225 struct stat sb;
226 static char* query;
227 static char* protocol;
228 static int status;
229 static off_t bytes;
230 static char* req_hostname;
231 
232 static char* authorization;
233 static size_t content_length;
234 static char* content_type;
235 static char* cookie;
236 static char* host;
237 static time_t if_modified_since;
238 static char* referrer;
239 static char* useragent;
240 
241 static char* remoteuser;
242 
243 
244 /* Forwards. */
245 static void usage( void );
246 static void read_config( char* filename );
247 static void value_required( char* name, char* value );
248 static void no_value_required( char* name, char* value );
249 static int initialize_listen_socket( usockaddr* usaP );
250 static void handle_request( void ) __attribute__((noreturn));
251 static void finish_request( int exitstatus ) __attribute__((noreturn));
252 static void de_dotdot( char* f );
253 static int get_pathinfo( void );
254 static void do_file( void );
255 static void do_dir( void );
256 #ifdef HAVE_SCANDIR
257 static char* file_details( const char* d, const char* name );
258 static void strencode( char* to, size_t tosize, const char* from );
259 #endif /* HAVE_SCANDIR */
260 static void do_cgi( void );
261 static void cgi_interpose_input( int wfd );
262 static void post_post_garbage_hack( void );
263 static void cgi_interpose_output( int rfd, int parse_headers );
264 static char** make_argp( void );
265 static char** make_envp( void );
266 static char* build_env( char* fmt, char* arg );
267 static void auth_check( char* dirname );
268 static void send_authenticate( char* realm );
269 static char* virtual_file( char* f );
270 static void send_error( int s, char* title, char* extra_header, char* text );
271 static void send_error_body( int s, char* title, char* text );
272 static int send_error_file( char* filename );
273 static void send_error_tail( void );
274 static void add_headers( int s, char* title, char* extra_header, char* me, char* mt, off_t b, time_t mod );
275 static void start_request( void );
276 static void add_to_request( char* str, size_t len );
277 static char* get_request_line( void );
278 static void start_response( void );
279 static void add_to_response( char* str );
280 static void send_response( void );
281 static void send_via_write( int fd, off_t size );
282 static void send_via_sendfile( int fd, int s, off_t size );
283 static ssize_t my_read( char* buf, size_t size );
284 static ssize_t my_write( void* buf, size_t size );
285 #ifdef HAVE_SENDFILE
286 static ssize_t my_sendfile( int fd, int s, off_t offset, size_t nbytes );
287 #endif /* HAVE_SENDFILE */
288 static void add_str( char** bufP, size_t* bufsizeP, size_t* buflenP, char* str );
289 static void add_data( char** bufP, size_t* bufsizeP, size_t* buflenP, char* str, size_t len );
290 static void make_log_entry( void );
291 static void check_referrer( void );
292 static int really_check_referrer( void );
293 static char* get_method_str( int m );
294 static void init_mime( void );
295 static const char* figure_mime( char* name, char* me, size_t me_size );
296 static void handle_sigterm( int sig );
297 static void handle_sighup( int sig );
298 static void handle_sigchld( int sig );
299 static void re_open_logfile( void );
300 static void handle_read_timeout( int sig );
301 static void handle_write_timeout( int sig );
302 static void lookup_hostname( usockaddr* usa4P, size_t sa4_len, int* gotv4P, usockaddr* usa6P, size_t sa6_len, int* gotv6P );
303 static char* ntoa( usockaddr* usaP );
304 static int sockaddr_check( usockaddr* usaP );
305 static size_t sockaddr_len( usockaddr* usaP );
306 static void strdecode( char* to, char* from );
307 static int hexit( char c );
308 static int b64_decode( const char* str, unsigned char* space, int size );
309 static void set_ndelay( int fd );
310 static void clear_ndelay( int fd );
311 static void* e_malloc( size_t size );
312 static void* e_realloc( void* optr, size_t size );
313 static char* e_strdup( char* ostr );
314 #ifdef NO_SNPRINTF
315 static int snprintf( char* str, size_t size, const char* format, ... );
316 #endif /* NO_SNPRINTF */
317 
318 
319 int
main(int argc,char ** argv)320 main( int argc, char** argv )
321     {
322     int argn;
323     struct passwd* pwd;
324     uid_t uid = 32767;
325     gid_t gid = 32767;
326     usockaddr host_addr4;
327     usockaddr host_addr6;
328     int gotv4, gotv6;
329     fd_set lfdset;
330     int maxfd;
331     usockaddr usa;
332     socklen_t sz;
333     int r;
334     char* cp;
335 
336     /* Parse args. */
337     argv0 = argv[0];
338     debug = 0;
339     port = 0;
340     dir = (char*) 0;
341     data_dir = (char*) 0;
342     do_chroot = 0;
343     vhost = 0;
344     cgi_pattern = (char*) 0;
345     url_pattern = (char*) 0;
346     no_empty_referrers = 0;
347     local_pattern = (char*) 0;
348     charset = DEFAULT_CHARSET;
349     p3p = (char*) 0;
350     max_age = -1;
351     user = DEFAULT_USER;
352     hostname = (char*) 0;
353     logfile = (char*) 0;
354     pidfile = (char*) 0;
355     logfp = (FILE*) 0;
356     do_ssl = 0;
357 #ifdef USE_SSL
358     certfile = DEFAULT_CERTFILE;
359     cipher = (char*) 0;
360 #endif /* USE_SSL */
361     argn = 1;
362     while ( argn < argc && argv[argn][0] == '-' )
363 	{
364 	if ( strcmp( argv[argn], "-V" ) == 0 )
365 	    {
366 	    (void) printf( "%s\n", SERVER_SOFTWARE );
367 	    exit( 0 );
368 	    }
369 	else if ( strcmp( argv[argn], "-C" ) == 0 && argn + 1 < argc )
370 	    {
371 	    ++argn;
372 	    read_config( argv[argn] );
373 	    }
374 	else if ( strcmp( argv[argn], "-D" ) == 0 )
375 	    debug = 1;
376 #ifdef USE_SSL
377 	else if ( strcmp( argv[argn], "-S" ) == 0 )
378 	    do_ssl = 1;
379 	else if ( strcmp( argv[argn], "-E" ) == 0 && argn + 1 < argc )
380 	    {
381 	    ++argn;
382 	    certfile = argv[argn];
383 	    }
384 	else if ( strcmp( argv[argn], "-Y" ) == 0 && argn + 1 < argc )
385 	    {
386 	    ++argn;
387 	    cipher = argv[argn];
388 	    }
389 #endif /* USE_SSL */
390 	else if ( strcmp( argv[argn], "-p" ) == 0 && argn + 1 < argc )
391 	    {
392 	    ++argn;
393 	    port = (unsigned short) atoi( argv[argn] );
394 	    }
395 	else if ( strcmp( argv[argn], "-d" ) == 0 && argn + 1 < argc )
396 	    {
397 	    ++argn;
398 	    dir = argv[argn];
399 	    }
400 	else if ( strcmp( argv[argn], "-dd" ) == 0 && argn + 1 < argc )
401 	    {
402 	    ++argn;
403 	    data_dir = argv[argn];
404 	    }
405 	else if ( strcmp( argv[argn], "-c" ) == 0 && argn + 1 < argc )
406 	    {
407 	    ++argn;
408 	    cgi_pattern = argv[argn];
409 	    }
410 	else if ( strcmp( argv[argn], "-u" ) == 0 && argn + 1 < argc )
411 	    {
412 	    ++argn;
413 	    user = argv[argn];
414 	    }
415 	else if ( strcmp( argv[argn], "-h" ) == 0 && argn + 1 < argc )
416 	    {
417 	    ++argn;
418 	    hostname = argv[argn];
419 	    }
420 	else if ( strcmp( argv[argn], "-r" ) == 0 )
421 	    do_chroot = 1;
422 	else if ( strcmp( argv[argn], "-v" ) == 0 )
423 	    vhost = 1;
424 	else if ( strcmp( argv[argn], "-l" ) == 0 && argn + 1 < argc )
425 	    {
426 	    ++argn;
427 	    logfile = argv[argn];
428 	    }
429 	else if ( strcmp( argv[argn], "-i" ) == 0 && argn + 1 < argc )
430 	    {
431 	    ++argn;
432 	    pidfile = argv[argn];
433 	    }
434 	else if ( strcmp( argv[argn], "-T" ) == 0 && argn + 1 < argc )
435 	    {
436 	    ++argn;
437 	    charset = argv[argn];
438 	    }
439 	else if ( strcmp( argv[argn], "-P" ) == 0 && argn + 1 < argc )
440 	    {
441 	    ++argn;
442 	    p3p = argv[argn];
443 	    }
444 	else if ( strcmp( argv[argn], "-M" ) == 0 && argn + 1 < argc )
445 	    {
446 	    ++argn;
447 	    max_age = atoi( argv[argn] );
448 	    }
449 	else
450 	    usage();
451 	++argn;
452 	}
453     if ( argn != argc )
454 	usage();
455 
456     cp = strrchr( argv0, '/' );
457     if ( cp != (char*) 0 )
458 	++cp;
459     else
460 	cp = argv0;
461     openlog( cp, LOG_NDELAY|LOG_PID, LOG_DAEMON );
462 
463     if ( port == 0 )
464 	{
465 #ifdef USE_SSL
466 	if ( do_ssl )
467 	    port = DEFAULT_HTTPS_PORT;
468 	else
469 	    port = DEFAULT_HTTP_PORT;
470 #else /* USE_SSL */
471 	port = DEFAULT_HTTP_PORT;
472 #endif /* USE_SSL */
473 	}
474 
475     /* If we're root and we're going to become another user, get the uid/gid
476     ** now.
477     */
478     if ( getuid() == 0 )
479 	{
480 	pwd = getpwnam( user );
481 	if ( pwd == (struct passwd*) 0 )
482 	    {
483 	    syslog( LOG_CRIT, "unknown user - '%s'", user );
484 	    (void) fprintf( stderr, "%s: unknown user - '%s'\n", argv0, user );
485 	    exit( 1 );
486 	    }
487 	uid = pwd->pw_uid;
488 	gid = pwd->pw_gid;
489 	}
490 
491     /* Log file. */
492     if ( logfile != (char*) 0 )
493 	{
494 	logfp = fopen( logfile, "a" );
495 	if ( logfp == (FILE*) 0 )
496 	    {
497 	    syslog( LOG_CRIT, "%s - %m", logfile );
498 	    perror( logfile );
499 	    exit( 1 );
500 	    }
501 	if ( logfile[0] != '/' )
502 	    {
503 	    syslog( LOG_WARNING, "logfile is not an absolute path, you may not be able to re-open it" );
504 	    (void) fprintf( stderr, "%s: logfile is not an absolute path, you may not be able to re-open it\n", argv0 );
505 	    }
506 	if ( getuid() == 0 )
507 	    {
508 	    /* If we are root then we chown the log file to the user we'll
509 	    ** be switching to.
510 	    */
511 	    if ( fchown( fileno( logfp ), uid, gid ) < 0 )
512 		{
513 		syslog( LOG_WARNING, "fchown logfile - %m" );
514 		perror( "fchown logfile" );
515 		}
516 	    }
517 	}
518 
519     /* Look up hostname. */
520     lookup_hostname(
521 	&host_addr4, sizeof(host_addr4), &gotv4,
522 	&host_addr6, sizeof(host_addr6), &gotv6 );
523     if ( hostname == (char*) 0 )
524 	{
525 	(void) gethostname( hostname_buf, sizeof(hostname_buf) );
526 	hostname = hostname_buf;
527 	}
528     if ( ! ( gotv4 || gotv6 ) )
529 	{
530 	syslog( LOG_CRIT, "can't find any valid address" );
531 	(void) fprintf( stderr, "%s: can't find any valid address\n", argv0 );
532 	exit( 1 );
533 	}
534 
535     /* Initialize listen sockets.  Try v6 first because of a Linux peculiarity;
536     ** like some other systems, it has magical v6 sockets that also listen for
537     ** v4, but in Linux if you bind a v4 socket first then the v6 bind fails.
538     */
539     if ( gotv6 )
540 	listen6_fd = initialize_listen_socket( &host_addr6 );
541     else
542 	listen6_fd = -1;
543     if ( gotv4 )
544 	listen4_fd = initialize_listen_socket( &host_addr4 );
545     else
546 	listen4_fd = -1;
547     /* If we didn't get any valid sockets, fail. */
548     if ( listen4_fd == -1 && listen6_fd == -1 )
549 	{
550 	syslog( LOG_CRIT, "can't bind to any address" );
551 	(void) fprintf( stderr, "%s: can't bind to any address\n", argv0 );
552 	exit( 1 );
553 	}
554 
555 #ifdef USE_SSL
556     if ( do_ssl )
557 	{
558 	SSL_load_error_strings();
559 	SSLeay_add_ssl_algorithms();
560 	ssl_ctx = SSL_CTX_new( SSLv23_server_method() );
561 	SSL_CTX_set_options( ssl_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3 );
562 	if ( certfile[0] != '\0' )
563 	    if ( SSL_CTX_use_certificate_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 ||
564 		 SSL_CTX_use_certificate_chain_file( ssl_ctx, certfile ) == 0 ||
565 		 SSL_CTX_use_PrivateKey_file( ssl_ctx, certfile, SSL_FILETYPE_PEM ) == 0 ||
566 		 SSL_CTX_check_private_key( ssl_ctx ) == 0 )
567 		{
568 		ERR_print_errors_fp( stderr );
569 		exit( 1 );
570 		}
571 	if ( cipher != (char*) 0 )
572 	    {
573 	    if ( SSL_CTX_set_cipher_list( ssl_ctx, cipher ) == 0 )
574 		{
575 		ERR_print_errors_fp( stderr );
576 		exit( 1 );
577 		}
578 	    }
579 	}
580 #endif /* USE_SSL */
581 
582     if ( ! debug )
583 	{
584 	/* Make ourselves a daemon. */
585 #ifdef HAVE_DAEMON
586 	if ( daemon( 1, 1 ) < 0 )
587 	    {
588 	    syslog( LOG_CRIT, "daemon - %m" );
589 	    perror( "daemon" );
590 	    exit( 1 );
591 	    }
592 #else
593 	switch ( fork() )
594 	    {
595 	    case 0:
596 	    break;
597 	    case -1:
598 	    syslog( LOG_CRIT, "fork - %m" );
599 	    perror( "fork" );
600 	    exit( 1 );
601 	    default:
602 	    exit( 0 );
603 	    }
604 #ifdef HAVE_SETSID
605 	(void) setsid();
606 #endif
607 #endif
608 	}
609     else
610 	{
611 	/* Even if we don't daemonize, we still want to disown our parent
612 	** process.
613 	*/
614 #ifdef HAVE_SETSID
615 	(void) setsid();
616 #endif /* HAVE_SETSID */
617 	}
618 
619     if ( pidfile != (char*) 0 )
620         {
621 	/* Write the PID file. */
622 	FILE* pidfp = fopen( pidfile, "w" );
623         if ( pidfp == (FILE*) 0 )
624             {
625 	    syslog( LOG_CRIT, "%s - %m", pidfile );
626 	    perror( pidfile );
627             exit( 1 );
628             }
629         (void) fprintf( pidfp, "%d\n", (int) getpid() );
630         (void) fclose( pidfp );
631         }
632 
633     /* Read zone info now, in case we chroot(). */
634     tzset();
635 
636     /* If we're root, start becoming someone else. */
637     if ( getuid() == 0 )
638 	{
639 	/* Set aux groups to null. */
640 	if ( setgroups( 0, (gid_t*) 0 ) < 0 )
641 	    {
642 	    syslog( LOG_CRIT, "setgroups - %m" );
643 	    perror( "setgroups" );
644 	    exit( 1 );
645 	    }
646 	/* Set primary group. */
647 	if ( setgid( gid ) < 0 )
648 	    {
649 	    syslog( LOG_CRIT, "setgid - %m" );
650 	    perror( "setgid" );
651 	    exit( 1 );
652 	    }
653 	/* Try setting aux groups correctly - not critical if this fails. */
654 	if ( initgroups( user, gid ) < 0 )
655 	    {
656 	    syslog( LOG_ERR, "initgroups - %m" );
657 	    perror( "initgroups" );
658 	    }
659 #ifdef HAVE_SETLOGIN
660 	/* Set login name. */
661 	(void) setlogin( user );
662 #endif /* HAVE_SETLOGIN */
663 	}
664 
665     /* Switch directories if requested. */
666     if ( dir != (char*) 0 )
667 	{
668 	if ( chdir( dir ) < 0 )
669 	    {
670 	    syslog( LOG_CRIT, "chdir - %m" );
671 	    perror( "chdir" );
672 	    exit( 1 );
673 	    }
674 	}
675 
676     /* Get current directory. */
677     (void) getcwd( cwd, sizeof(cwd) - 1 );
678     if ( cwd[strlen( cwd ) - 1] != '/' )
679 	(void) strcat( cwd, "/" );
680 
681     /* Chroot if requested. */
682     if ( do_chroot )
683 	{
684 	if ( chroot( cwd ) < 0 )
685 	    {
686 	    syslog( LOG_CRIT, "chroot - %m" );
687 	    perror( "chroot" );
688 	    exit( 1 );
689 	    }
690 	/* If we're logging and the logfile's pathname begins with the
691 	** chroot tree's pathname, then elide the chroot pathname so
692 	** that the logfile pathname still works from inside the chroot
693 	** tree.
694 	*/
695 	if ( logfile != (char*) 0 )
696 	    {
697 	    if ( strncmp( logfile, cwd, strlen( cwd ) ) == 0 )
698 		{
699 		(void) ol_strcpy( logfile, &logfile[strlen( cwd ) - 1] );
700 		/* (We already guaranteed that cwd ends with a slash, so leaving
701 		** that slash in logfile makes it an absolute pathname within
702 		** the chroot tree.)
703 		*/
704 		}
705 	    else
706 		{
707 		syslog( LOG_WARNING, "logfile is not within the chroot tree, you will not be able to re-open it" );
708 		(void) fprintf( stderr, "%s: logfile is not within the chroot tree, you will not be able to re-open it\n", argv0 );
709 		}
710 	    }
711 	(void) strcpy( cwd, "/" );
712 	/* Always chdir to / after a chroot. */
713 	if ( chdir( cwd ) < 0 )
714 	    {
715 	    syslog( LOG_CRIT, "chroot chdir - %m" );
716 	    perror( "chroot chdir" );
717 	    exit( 1 );
718 	    }
719 
720 	}
721 
722     /* Switch directories again if requested. */
723     if ( data_dir != (char*) 0 )
724 	{
725 	if ( chdir( data_dir ) < 0 )
726 	    {
727 	    syslog( LOG_CRIT, "data_dir chdir - %m" );
728 	    perror( "data_dir chdir" );
729 	    exit( 1 );
730 	    }
731 	}
732 
733     /* If we're root, become someone else. */
734     if ( getuid() == 0 )
735 	{
736 	/* Set uid. */
737 	if ( setuid( uid ) < 0 )
738 	    {
739 	    syslog( LOG_CRIT, "setuid - %m" );
740 	    perror( "setuid" );
741 	    exit( 1 );
742 	    }
743 	/* Check for unnecessary security exposure. */
744 	if ( ! do_chroot )
745 	    {
746 	    syslog( LOG_WARNING,
747 		"started as root without requesting chroot(), warning only" );
748 	    (void) fprintf( stderr,
749 		"%s: started as root without requesting chroot(), warning only\n", argv0 );
750 	    }
751 	}
752 
753     /* Catch various signals. */
754 #ifdef HAVE_SIGSET
755     (void) sigset( SIGTERM, handle_sigterm );
756     (void) sigset( SIGINT, handle_sigterm );
757     (void) sigset( SIGUSR1, handle_sigterm );
758     (void) sigset( SIGHUP, handle_sighup );
759     (void) sigset( SIGCHLD, handle_sigchld );
760     (void) sigset( SIGPIPE, SIG_IGN );
761 #else /* HAVE_SIGSET */
762     (void) signal( SIGTERM, handle_sigterm );
763     (void) signal( SIGINT, handle_sigterm );
764     (void) signal( SIGUSR1, handle_sigterm );
765     (void) signal( SIGHUP, handle_sighup );
766     (void) signal( SIGCHLD, handle_sigchld );
767     (void) signal( SIGPIPE, SIG_IGN );
768 #endif /* HAVE_SIGSET */
769     got_hup = 0;
770 
771     init_mime();
772 
773     if ( hostname == (char*) 0 )
774 	syslog(
775 	    LOG_NOTICE, "%.80s starting on port %d", SERVER_SOFTWARE,
776 	    (int) port );
777     else
778 	syslog(
779 	    LOG_NOTICE, "%.80s starting on %.80s, port %d", SERVER_SOFTWARE,
780 	    hostname, (int) port );
781 
782     /* Main loop. */
783     for (;;)
784 	{
785 	/* Do we need to re-open the log file? */
786 	if ( got_hup )
787 	    {
788 	    re_open_logfile();
789 	    got_hup = 0;
790 	    }
791 
792 	/* Do a select() on at least one and possibly two listen fds.
793 	** If there's only one listen fd then we could skip the select
794 	** and just do the (blocking) accept(), saving one system call;
795 	** that's what happened up through version 1.18.  However there
796 	** is one slight drawback to that method: the blocking accept()
797 	** is not interrupted by a signal call.  Since we definitely want
798 	** signals to interrupt a waiting server, we use select() even
799 	** if there's only one fd.
800 	*/
801 	FD_ZERO( &lfdset );
802 	maxfd = -1;
803 	if ( listen4_fd != -1 )
804 	    {
805 	    FD_SET( listen4_fd, &lfdset );
806 	    if ( listen4_fd > maxfd )
807 		maxfd = listen4_fd;
808 	    }
809 	if ( listen6_fd != -1 )
810 	    {
811 	    FD_SET( listen6_fd, &lfdset );
812 	    if ( listen6_fd > maxfd )
813 		maxfd = listen6_fd;
814 	    }
815 	if ( select( maxfd + 1, &lfdset, (fd_set*) 0, (fd_set*) 0, (struct timeval*) 0 ) < 0 )
816 	    {
817 	    if ( errno == EINTR || errno == EAGAIN )
818 		continue;	/* try again */
819 	    syslog( LOG_CRIT, "select - %m" );
820 	    perror( "select" );
821 	    exit( 1 );
822 	    }
823 
824 	/* Accept the new connection. */
825 	sz = sizeof(usa);
826 	if ( listen4_fd != -1 && FD_ISSET( listen4_fd, &lfdset ) )
827 	    conn_fd = accept( listen4_fd, &usa.sa, &sz );
828 	else if ( listen6_fd != -1 && FD_ISSET( listen6_fd, &lfdset ) )
829 	    conn_fd = accept( listen6_fd, &usa.sa, &sz );
830 	else
831 	    {
832 	    syslog( LOG_CRIT, "select failure" );
833 	    (void) fprintf( stderr, "%s: select failure\n", argv0 );
834 	    exit( 1 );
835 	    }
836 	if ( conn_fd < 0 )
837 	    {
838 	    if ( errno == EINTR || errno == EAGAIN || errno == ECONNABORTED )
839 		continue;	/* try again */
840 #ifdef EPROTO
841 	    if ( errno == EPROTO )
842 		continue;	/* try again */
843 #endif /* EPROTO */
844 	    syslog( LOG_CRIT, "accept - %m" );
845 	    perror( "accept" );
846 	    exit( 1 );
847 	    }
848 
849 	/* Fork a sub-process to handle the connection. */
850 	r = fork();
851 	if ( r < 0 )
852 	    {
853 	    syslog( LOG_CRIT, "fork - %m" );
854 	    perror( "fork" );
855 	    exit( 1 );
856 	    }
857 	if ( r == 0 )
858 	    {
859 	    /* Child process. */
860 	    client_addr = usa;
861 	    if ( listen4_fd != -1 )
862 		(void) close( listen4_fd );
863 	    if ( listen6_fd != -1 )
864 		(void) close( listen6_fd );
865 	    handle_request();
866 	    }
867 	(void) close( conn_fd );
868 	}
869     }
870 
871 
872 static void
usage(void)873 usage( void )
874     {
875 #ifdef USE_SSL
876     (void) fprintf( stderr, "usage:  %s [-C configfile] [-D] [-S] [-E certfile] [-Y cipher] [-p port] [-d dir] [-dd data_dir] [-c cgipat] [-u user] [-h hostname] [-r] [-v] [-l logfile] [-i pidfile] [-T charset] [-P P3P] [-M maxage]\n", argv0 );
877 #else /* USE_SSL */
878     (void) fprintf( stderr, "usage:  %s [-C configfile] [-D] [-p port] [-d dir] [-dd data_dir] [-c cgipat] [-u user] [-h hostname] [-r] [-v] [-l logfile] [-i pidfile] [-T charset] [-P P3P] [-M maxage]\n", argv0 );
879 #endif /* USE_SSL */
880     exit( 1 );
881     }
882 
883 
884 static void
read_config(char * filename)885 read_config( char* filename )
886     {
887     FILE* fp;
888     char line[10000];
889     char* cp;
890     char* cp2;
891     char* name;
892     char* value;
893 
894     fp = fopen( filename, "r" );
895     if ( fp == (FILE*) 0 )
896 	{
897 	syslog( LOG_CRIT, "%s - %m", filename );
898 	perror( filename );
899 	exit( 1 );
900 	}
901 
902     while ( fgets( line, sizeof(line), fp ) != (char*) 0 )
903 	{
904 	/* Trim comments. */
905 	if ( ( cp = strchr( line, '#' ) ) != (char*) 0 )
906 	    *cp = '\0';
907 
908 	/* Skip leading whitespace. */
909 	cp = line;
910 	cp += strspn( cp, " \t\012\015" );
911 
912 	/* Split line into words. */
913 	while ( *cp != '\0' )
914 	    {
915 	    /* Find next whitespace. */
916 	    cp2 = cp + strcspn( cp, " \t\012\015" );
917 	    /* Insert EOS and advance next-word pointer. */
918 	    while ( *cp2 == ' ' || *cp2 == '\t' || *cp2 == '\012' || *cp2 == '\015' )
919 		*cp2++ = '\0';
920 	    /* Split into name and value. */
921 	    name = cp;
922 	    value = strchr( name, '=' );
923 	    if ( value != (char*) 0 )
924 		*value++ = '\0';
925 	    /* Interpret. */
926 	    if ( strcasecmp( name, "debug" ) == 0 )
927 		{
928 		no_value_required( name, value );
929 		debug = 1;
930 		}
931 	    else if ( strcasecmp( name, "port" ) == 0 )
932 		{
933 		value_required( name, value );
934 		port = (unsigned short) atoi( value );
935 		}
936 	    else if ( strcasecmp( name, "dir" ) == 0 )
937 		{
938 		value_required( name, value );
939 		dir = e_strdup( value );
940 		}
941 	    else if ( strcasecmp( name, "data_dir" ) == 0 )
942 		{
943 		value_required( name, value );
944 		data_dir = e_strdup( value );
945 		}
946 	    else if ( strcasecmp( name, "chroot" ) == 0 )
947 		{
948 		no_value_required( name, value );
949 		do_chroot = 1;
950 		}
951 	    else if ( strcasecmp( name, "nochroot" ) == 0 )
952 		{
953 		no_value_required( name, value );
954 		do_chroot = 0;
955 		}
956 	    else if ( strcasecmp( name, "user" ) == 0 )
957 		{
958 		value_required( name, value );
959 		user = e_strdup( value );
960 		}
961 	    else if ( strcasecmp( name, "cgipat" ) == 0 )
962 		{
963 		value_required( name, value );
964 		cgi_pattern = e_strdup( value );
965 		}
966 	    else if ( strcasecmp( name, "urlpat" ) == 0 )
967 		{
968 		value_required( name, value );
969 		url_pattern = e_strdup( value );
970 		}
971 	    else if ( strcasecmp( name, "noemptyreferers" ) == 0 ||
972 	              strcasecmp( name, "noemptyreferrers" ) == 0 )
973 		{
974 		value_required( name, value );
975 		no_empty_referrers = 1;
976 		}
977 	    else if ( strcasecmp( name, "localpat" ) == 0 )
978 		{
979 		value_required( name, value );
980 		local_pattern = e_strdup( value );
981 		}
982 	    else if ( strcasecmp( name, "host" ) == 0 )
983 		{
984 		value_required( name, value );
985 		hostname = e_strdup( value );
986 		}
987 	    else if ( strcasecmp( name, "logfile" ) == 0 )
988 		{
989 		value_required( name, value );
990 		logfile = e_strdup( value );
991 		}
992 	    else if ( strcasecmp( name, "vhost" ) == 0 )
993 		{
994 		no_value_required( name, value );
995 		vhost = 1;
996 		}
997 	    else if ( strcasecmp( name, "pidfile" ) == 0 )
998 		{
999 		value_required( name, value );
1000 		pidfile = e_strdup( value );
1001 		}
1002 	    else if ( strcasecmp( name, "charset" ) == 0 )
1003 		{
1004 		value_required( name, value );
1005 		charset = e_strdup( value );
1006 		}
1007 	    else if ( strcasecmp( name, "p3p" ) == 0 )
1008 		{
1009 		value_required( name, value );
1010 		p3p = e_strdup( value );
1011 		}
1012 	    else if ( strcasecmp( name, "max_age" ) == 0 )
1013 		{
1014 		value_required( name, value );
1015 		max_age = atoi( value );
1016 		}
1017 #ifdef USE_SSL
1018 	    else if ( strcasecmp( name, "ssl" ) == 0 )
1019 		{
1020 		no_value_required( name, value );
1021 		do_ssl = 1;
1022 		}
1023 	    else if ( strcasecmp( name, "certfile" ) == 0 )
1024 		{
1025 		value_required( name, value );
1026 		certfile = e_strdup( value );
1027 		}
1028 	    else if ( strcasecmp( name, "cipher" ) == 0 )
1029 		{
1030 		value_required( name, value );
1031 		cipher = e_strdup( value );
1032 		}
1033 #endif /* USE_SSL */
1034 	    else
1035 		{
1036 		(void) fprintf(
1037 		    stderr, "%s: unknown config option '%s'\n", argv0, name );
1038 		exit( 1 );
1039 		}
1040 
1041 	    /* Advance to next word. */
1042 	    cp = cp2;
1043 	    cp += strspn( cp, " \t\012\015" );
1044 	    }
1045 	}
1046 
1047     (void) fclose( fp );
1048     }
1049 
1050 
1051 static void
value_required(char * name,char * value)1052 value_required( char* name, char* value )
1053     {
1054     if ( value == (char*) 0 )
1055 	{
1056 	(void) fprintf(
1057 	    stderr, "%s: value required for %s option\n", argv0, name );
1058 	exit( 1 );
1059 	}
1060     }
1061 
1062 
1063 static void
no_value_required(char * name,char * value)1064 no_value_required( char* name, char* value )
1065     {
1066     if ( value != (char*) 0 )
1067 	{
1068 	(void) fprintf(
1069 	    stderr, "%s: no value required for %s option\n",
1070 	    argv0, name );
1071 	exit( 1 );
1072 	}
1073     }
1074 
1075 
1076 static int
initialize_listen_socket(usockaddr * usaP)1077 initialize_listen_socket( usockaddr* usaP )
1078     {
1079     int listen_fd;
1080     int i;
1081 
1082     /* Check sockaddr. */
1083     if ( ! sockaddr_check( usaP ) )
1084 	{
1085 	syslog(
1086 	    LOG_ERR, "unknown sockaddr family on listen socket - %d",
1087 	    usaP->sa.sa_family );
1088 	(void) fprintf(
1089 	    stderr, "%s: unknown sockaddr family on listen socket - %d\n",
1090 	    argv0, usaP->sa.sa_family );
1091 	return -1;
1092 	}
1093 
1094     listen_fd = socket( usaP->sa.sa_family, SOCK_STREAM, 0 );
1095     if ( listen_fd < 0 )
1096 	{
1097 	syslog( LOG_CRIT, "socket %.80s - %m", ntoa( usaP ) );
1098 	perror( "socket" );
1099 	return -1;
1100 	}
1101 
1102     (void) fcntl( listen_fd, F_SETFD, 1 );
1103 
1104     i = 1;
1105     if ( setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*) &i, sizeof(i) ) < 0 )
1106 	{
1107 	syslog( LOG_CRIT, "setsockopt SO_REUSEADDR - %m" );
1108 	perror( "setsockopt SO_REUSEADDR" );
1109 	return -1;
1110 	}
1111 
1112     if ( bind( listen_fd, &usaP->sa, sockaddr_len( usaP ) ) < 0 )
1113 	{
1114 	syslog( LOG_CRIT, "bind %.80s - %m", ntoa( usaP ) );
1115 	perror( "bind" );
1116 	return -1;
1117 	}
1118 
1119     if ( listen( listen_fd, 1024 ) < 0 )
1120 	{
1121 	syslog( LOG_CRIT, "listen - %m" );
1122 	perror( "listen" );
1123 	return -1;
1124 	}
1125 
1126 #ifdef HAVE_ACCEPT_FILTERS
1127     {
1128     struct accept_filter_arg af;
1129     (void) bzero( &af, sizeof(af) );
1130     (void) strcpy( af.af_name, ACCEPT_FILTER_NAME );
1131     (void) setsockopt( listen_fd, SOL_SOCKET, SO_ACCEPTFILTER, (char*) &af, sizeof(af) );
1132     }
1133 #endif /* HAVE_ACCEPT_FILTERS */
1134 
1135     return listen_fd;
1136     }
1137 
1138 
1139 /* This runs in a child process, and exits when done, so cleanup is
1140 ** not needed.
1141 */
1142 static void
handle_request(void)1143 handle_request( void )
1144     {
1145     char* method_str;
1146     char* line;
1147     char* cp;
1148     int r, file_len, i;
1149     const char* index_names[] = {
1150 	"index.html", "index.htm", "index.xhtml", "index.xht", "Default.htm",
1151 	"index.cgi" };
1152 
1153     /* Set up the timeout for reading. */
1154 #ifdef HAVE_SIGSET
1155     (void) sigset( SIGALRM, handle_read_timeout );
1156 #else /* HAVE_SIGSET */
1157     (void) signal( SIGALRM, handle_read_timeout );
1158 #endif /* HAVE_SIGSET */
1159     (void) alarm( READ_TIMEOUT );
1160 
1161     /* Initialize the request variables. */
1162     remoteuser = (char*) 0;
1163     method = METHOD_UNKNOWN;
1164     path = (char*) 0;
1165     file = (char*) 0;
1166     pathinfo = (char*) 0;
1167     query = "";
1168     protocol = (char*) 0;
1169     status = 0;
1170     bytes = -1;
1171     req_hostname = (char*) 0;
1172 
1173     authorization = (char*) 0;
1174     content_type = (char*) 0;
1175     content_length = -1;
1176     cookie = (char*) 0;
1177     host = (char*) 0;
1178     if_modified_since = (time_t) -1;
1179     referrer = "";
1180     useragent = "";
1181 
1182 #ifdef TCP_NOPUSH
1183     if ( ! do_ssl )
1184 	{
1185 	/* Set the TCP_NOPUSH socket option, to try and avoid the 0.2 second
1186 	** delay between sending the headers and sending the data.  A better
1187 	** solution is writev() (as used in thttpd), or send the headers with
1188 	** send(MSG_MORE) (only available in Linux so far).
1189 	*/
1190 	r = 1;
1191 	(void) setsockopt(
1192 	    conn_fd, IPPROTO_TCP, TCP_NOPUSH, (void*) &r, sizeof(r) );
1193 	}
1194 #endif /* TCP_NOPUSH */
1195 
1196 #ifdef USE_SSL
1197     if ( do_ssl )
1198 	{
1199 	ssl = SSL_new( ssl_ctx );
1200 	SSL_set_fd( ssl, conn_fd );
1201 	if ( SSL_accept( ssl ) == 0 )
1202 	    {
1203 	    ERR_print_errors_fp( stderr );
1204 	    finish_request( 1 );
1205 	    }
1206 	}
1207 #endif /* USE_SSL */
1208 
1209     /* Read in the request. */
1210     start_request();
1211     for (;;)
1212 	{
1213 	char buf[50000];
1214 	int rr = my_read( buf, sizeof(buf) - 1 );
1215 	if ( rr < 0 && ( errno == EINTR || errno == EAGAIN ) )
1216 	    continue;
1217 	if ( rr <= 0 )
1218 	    break;
1219 	(void) alarm( READ_TIMEOUT );
1220 	add_to_request( buf, rr );
1221 	if ( strstr( request, "\015\012\015\012" ) != (char*) 0 ||
1222 	     strstr( request, "\012\012" ) != (char*) 0 )
1223 	    break;
1224 	}
1225 
1226     /* Parse the first line of the request. */
1227     method_str = get_request_line();
1228     if ( method_str == (char*) 0 )
1229 	send_error( 400, "Bad Request", "", "Can't parse request." );
1230     path = strpbrk( method_str, " \t\012\015" );
1231     if ( path == (char*) 0 )
1232 	send_error( 400, "Bad Request", "", "Can't parse request." );
1233     *path++ = '\0';
1234     path += strspn( path, " \t\012\015" );
1235     protocol = strpbrk( path, " \t\012\015" );
1236     if ( protocol == (char*) 0 )
1237 	send_error( 400, "Bad Request", "", "Can't parse request." );
1238     *protocol++ = '\0';
1239     protocol += strspn( protocol, " \t\012\015" );
1240     query = strchr( path, '?' );
1241     if ( query == (char*) 0 )
1242 	query = "";
1243     else
1244 	*query++ = '\0';
1245 
1246     /* Parse the rest of the request headers. */
1247     while ( ( line = get_request_line() ) != (char*) 0 )
1248 	{
1249 	if ( line[0] == '\0' )
1250 	    break;
1251 	else if ( strncasecmp( line, "Authorization:", 14 ) == 0 )
1252 	    {
1253 	    cp = &line[14];
1254 	    cp += strspn( cp, " \t" );
1255 	    authorization = cp;
1256 	    }
1257 	else if ( strncasecmp( line, "Content-Length:", 15 ) == 0 )
1258 	    {
1259 	    cp = &line[15];
1260 	    cp += strspn( cp, " \t" );
1261 	    content_length = atol( cp );
1262 	    }
1263 	else if ( strncasecmp( line, "Content-Type:", 13 ) == 0 )
1264 	    {
1265 	    cp = &line[13];
1266 	    cp += strspn( cp, " \t" );
1267 	    content_type = cp;
1268 	    }
1269 	else if ( strncasecmp( line, "Cookie:", 7 ) == 0 )
1270 	    {
1271 	    cp = &line[7];
1272 	    cp += strspn( cp, " \t" );
1273 	    cookie = cp;
1274 	    }
1275 	else if ( strncasecmp( line, "Host:", 5 ) == 0 )
1276 	    {
1277 	    cp = &line[5];
1278 	    cp += strspn( cp, " \t" );
1279 	    host = cp;
1280 	    if ( host[0] == '\0' || host[0] == '.' ||
1281 		 strchr( host, '/' ) != (char*) 0 )
1282 		send_error( 400, "Bad Request", "", "Can't parse request." );
1283 	    }
1284 	else if ( strncasecmp( line, "If-Modified-Since:", 18 ) == 0 )
1285 	    {
1286 	    cp = &line[18];
1287 	    cp += strspn( cp, " \t" );
1288 	    if_modified_since = tdate_parse( cp );
1289 	    }
1290 	else if ( strncasecmp( line, "Referer:", 8 ) == 0 )
1291 	    {
1292 	    cp = &line[8];
1293 	    cp += strspn( cp, " \t" );
1294 	    referrer = cp;
1295 	    }
1296 	else if ( strncasecmp( line, "Referrer:", 9 ) == 0 )
1297 	    {
1298 	    cp = &line[9];
1299 	    cp += strspn( cp, " \t" );
1300 	    referrer = cp;
1301 	    }
1302 	else if ( strncasecmp( line, "User-Agent:", 11 ) == 0 )
1303 	    {
1304 	    cp = &line[11];
1305 	    cp += strspn( cp, " \t" );
1306 	    useragent = cp;
1307 	    }
1308 	}
1309 
1310     if ( strcasecmp( method_str, get_method_str( METHOD_GET ) ) == 0 )
1311 	method = METHOD_GET;
1312     else if ( strcasecmp( method_str, get_method_str( METHOD_HEAD ) ) == 0 )
1313 	method = METHOD_HEAD;
1314     else if ( strcasecmp( method_str, get_method_str( METHOD_POST ) ) == 0 )
1315 	method = METHOD_POST;
1316     else if ( strcasecmp( method_str, get_method_str( METHOD_PUT ) ) == 0 )
1317 	method = METHOD_PUT;
1318     else if ( strcasecmp( method_str, get_method_str( METHOD_DELETE ) ) == 0 )
1319 	method = METHOD_DELETE;
1320     else if ( strcasecmp( method_str, get_method_str( METHOD_TRACE ) ) == 0 )
1321 	method = METHOD_TRACE;
1322     else
1323 	send_error( 501, "Not Implemented", "", "That method is not implemented." );
1324 
1325     strdecode( path, path );
1326     if ( path[0] != '/' )
1327 	send_error( 400, "Bad Request", "", "Bad filename." );
1328     file = &(path[1]);
1329     de_dotdot( file );
1330     if ( file[0] == '\0' )
1331 	file = "./";
1332     if ( file[0] == '/' ||
1333 	 ( file[0] == '.' && file[1] == '.' &&
1334 	   ( file[2] == '\0' || file[2] == '/' ) ) )
1335 	send_error( 400, "Bad Request", "", "Illegal filename." );
1336     if ( vhost )
1337 	file = virtual_file( file );
1338 
1339     /* Set up the timeout for writing. */
1340 #ifdef HAVE_SIGSET
1341     (void) sigset( SIGALRM, handle_write_timeout );
1342 #else /* HAVE_SIGSET */
1343     (void) signal( SIGALRM, handle_write_timeout );
1344 #endif /* HAVE_SIGSET */
1345     (void) alarm( WRITE_TIMEOUT );
1346 
1347     r = stat( file, &sb );
1348     if ( r < 0 )
1349 	r = get_pathinfo();
1350     if ( r < 0 )
1351 	send_error( 404, "Not Found", "", "File not found." );
1352     file_len = strlen( file );
1353     if ( ! S_ISDIR( sb.st_mode ) )
1354 	{
1355 	/* Not a directory. */
1356 	while ( file[file_len - 1] == '/' )
1357 	    {
1358 	    file[file_len - 1] = '\0';
1359 	    --file_len;
1360 	    }
1361 	do_file();
1362 	}
1363     else
1364 	{
1365 	char idx[10000];
1366 
1367 	/* The filename is a directory.  Is it missing the trailing slash? */
1368 	if ( file[file_len - 1] != '/' && pathinfo == (char*) 0 )
1369 	    {
1370 	    char location[10000];
1371 	    if ( query[0] != '\0' )
1372 		(void) snprintf(
1373 		    location, sizeof(location), "Location: %s/?%s", path,
1374 		    query );
1375 	    else
1376 		(void) snprintf(
1377 		    location, sizeof(location), "Location: %s/", path );
1378 	    send_error( 302, "Found", location, "Directories must end with a slash." );
1379 	    }
1380 
1381 	/* Check for an index file. */
1382 	for ( i = 0; i < sizeof(index_names) / sizeof(char*); ++i )
1383 	    {
1384 	    (void) snprintf( idx, sizeof(idx), "%s%s", file, index_names[i] );
1385 	    if ( stat( idx, &sb ) >= 0 )
1386 		{
1387 		file = idx;
1388 		do_file();
1389 		goto got_one;
1390 		}
1391 	    }
1392 
1393 	/* Nope, no index file, so it's an actual directory request. */
1394 	do_dir();
1395 
1396 	got_one: ;
1397 	}
1398 
1399 #ifdef USE_SSL
1400     SSL_free( ssl );
1401 #endif /* USE_SSL */
1402 
1403     finish_request( 0 );
1404     }
1405 
1406 
1407 static void
finish_request(int exitstatus)1408 finish_request( int exitstatus )
1409     {
1410 #undef LINGER_SOCKOPT
1411 #define LINGER_READ
1412 
1413 #define LINGER_SECS 5
1414 
1415 #ifdef LINGER_SOCKOPT
1416     /* The sockopt version of lingering close. Doesn't actually work. */
1417     struct linger lin;
1418 
1419     shutdown( conn_fd, SHUT_WR );
1420     lin.l_onoff = 1;
1421     lin.l_linger = LINGER_SECS;
1422     (void) setsockopt(
1423 	conn_fd, SOL_SOCKET, SO_LINGER, (void*) &lin, sizeof(lin) );
1424 #endif /* LINGER_SOCKOPT */
1425 
1426 #ifdef LINGER_READ
1427     /* The "non-blocking read until error/eof/timeout" version of
1428     ** lingering close.
1429     */
1430     int flags;
1431     fd_set rfds;
1432     struct timeval tv;
1433     int r;
1434     char* buf[1024];
1435 
1436     flags = fcntl( conn_fd, F_GETFL, 0 );
1437     if ( flags != -1 )
1438 	{
1439 	flags |= (int) O_NDELAY;
1440 	(void) fcntl( conn_fd, F_SETFL, flags );
1441 	}
1442     shutdown( conn_fd, SHUT_WR );
1443     for (;;)
1444 	{
1445 	FD_ZERO( &rfds );
1446 	FD_SET( conn_fd, &rfds );
1447 	tv.tv_sec = LINGER_SECS;
1448 	tv.tv_usec = 0;
1449 	r = select( conn_fd + 1, &rfds, (fd_set*) 0, (fd_set*) 0, &tv );
1450 	if ( r <= 0 )	/* timeout or error */
1451 	    break;
1452 	r = read( conn_fd, (void*) buf, sizeof(buf) );
1453 	if ( r <= 0 )	/* eof or error */
1454 	    break;
1455 	}
1456 #endif /* LINGER_READ */
1457 
1458     exit( exitstatus );
1459     }
1460 
1461 
1462 static void
de_dotdot(char * f)1463 de_dotdot( char* f )
1464     {
1465     char* cp;
1466     char* cp2;
1467     int l;
1468 
1469     /* Collapse any multiple / sequences. */
1470     while ( ( cp = strstr( f, "//") ) != (char*) 0 )
1471 	{
1472 	for ( cp2 = cp + 2; *cp2 == '/'; ++cp2 )
1473 	    continue;
1474 	(void) ol_strcpy( cp + 1, cp2 );
1475 	}
1476 
1477     /* Remove leading ./ and any /./ sequences. */
1478     while ( strncmp( f, "./", 2 ) == 0 )
1479 	(void) ol_strcpy( f, f + 2 );
1480     while ( ( cp = strstr( f, "/./") ) != (char*) 0 )
1481 	(void) ol_strcpy( cp, cp + 2 );
1482 
1483     /* Alternate between removing leading ../ and removing xxx/../ */
1484     for (;;)
1485 	{
1486 	while ( strncmp( f, "../", 3 ) == 0 )
1487 	    (void) ol_strcpy( f, f + 3 );
1488 	cp = strstr( f, "/../" );
1489 	if ( cp == (char*) 0 )
1490 	    break;
1491 	for ( cp2 = cp - 1; cp2 >= f && *cp2 != '/'; --cp2 )
1492 	    continue;
1493 	(void) ol_strcpy( cp2 + 1, cp + 4 );
1494 	}
1495 
1496     /* Also elide any xxx/.. at the end. */
1497     while ( ( l = strlen( f ) ) > 3 &&
1498 	    strcmp( ( cp = f + l - 3 ), "/.." ) == 0 )
1499 	{
1500 	for ( cp2 = cp - 1; cp2 >= f && *cp2 != '/'; --cp2 )
1501 	    continue;
1502 	if ( cp2 < f )
1503 	    break;
1504 	*cp2 = '\0';
1505 	}
1506     }
1507 
1508 
1509 static int
get_pathinfo(void)1510 get_pathinfo( void )
1511     {
1512     int r;
1513 
1514     pathinfo = &file[strlen(file)];
1515     for (;;)
1516 	{
1517 	do
1518 	    {
1519 	    --pathinfo;
1520 	    if ( pathinfo <= file )
1521 		{
1522 		pathinfo = (char*) 0;
1523 		return -1;
1524 		}
1525 	    }
1526 	while ( *pathinfo != '/' );
1527 	*pathinfo = '\0';
1528 	r = stat( file, &sb );
1529 	if ( r >= 0 )
1530 	    {
1531 	    ++pathinfo;
1532 	    return r;
1533 	    }
1534 	else
1535 	    *pathinfo = '/';
1536 	}
1537     }
1538 
1539 
1540 static void
do_file(void)1541 do_file( void )
1542     {
1543     char buf[10000];
1544     char mime_encodings[500];
1545     const char* mime_type;
1546     char fixed_mime_type[500];
1547     char* cp;
1548     int fd;
1549 
1550     /* Check authorization for this directory. */
1551     (void) strncpy( buf, file, sizeof(buf) );
1552     cp = strrchr( buf, '/' );
1553     if ( cp == (char*) 0 )
1554 	(void) strcpy( buf, "." );
1555     else
1556 	*cp = '\0';
1557     auth_check( buf );
1558 
1559     /* Check if the filename is the AUTH_FILE itself - that's verboten. */
1560     if ( strcmp( file, AUTH_FILE ) == 0 ||
1561 	 ( strcmp( &(file[strlen(file) - sizeof(AUTH_FILE) + 1]), AUTH_FILE ) == 0 &&
1562 	   file[strlen(file) - sizeof(AUTH_FILE)] == '/' ) )
1563 	{
1564 	syslog(
1565 	    LOG_NOTICE, "%.80s URL \"%.80s\" tried to retrieve an auth file",
1566 	    ntoa( &client_addr ), path );
1567 	send_error( 403, "Forbidden", "", "File is protected." );
1568 	}
1569 
1570     /* Referrer check. */
1571     check_referrer();
1572 
1573     /* Is it CGI? */
1574     if ( cgi_pattern != (char*) 0 && match( cgi_pattern, file ) )
1575 	{
1576 	do_cgi();
1577 	return;
1578 	}
1579     if ( pathinfo != (char*) 0 )
1580 	send_error( 404, "Not Found", "", "File not found." );
1581 
1582     if ( method != METHOD_GET && method != METHOD_HEAD )
1583 	send_error( 501, "Not Implemented", "", "That method is not implemented." );
1584 
1585     fd = open( file, O_RDONLY );
1586     if ( fd < 0 )
1587 	{
1588 	syslog(
1589 	    LOG_INFO, "%.80s File \"%.80s\" is protected",
1590 	    ntoa( &client_addr ), path );
1591 	send_error( 403, "Forbidden", "", "File is protected." );
1592 	}
1593     mime_type = figure_mime( file, mime_encodings, sizeof(mime_encodings) );
1594     (void) snprintf(
1595 	fixed_mime_type, sizeof(fixed_mime_type), mime_type, charset );
1596     if ( if_modified_since != (time_t) -1 &&
1597 	 if_modified_since >= sb.st_mtime )
1598 	{
1599 	add_headers(
1600 	    304, "Not Modified", "", mime_encodings, fixed_mime_type,
1601 	    (off_t) -1, sb.st_mtime );
1602 	send_response();
1603 	return;
1604 	}
1605     add_headers(
1606 	200, "Ok", "", mime_encodings, fixed_mime_type, sb.st_size,
1607 	sb.st_mtime );
1608     send_response();
1609     if ( method == METHOD_HEAD )
1610 	return;
1611 
1612     if ( sb.st_size > 0 )	/* ignore zero-length files */
1613 	{
1614 #ifdef HAVE_SENDFILE
1615 
1616 #ifndef USE_SSL
1617 	send_via_sendfile( fd, conn_fd, sb.st_size );
1618 #else /* USE_SSL */
1619 	if ( do_ssl )
1620 	    send_via_write( fd, sb.st_size );
1621 	else
1622 	    send_via_sendfile( fd, conn_fd, sb.st_size );
1623 #endif /* USE_SSL */
1624 
1625 #else /* HAVE_SENDFILE */
1626 
1627    	send_via_write( fd, sb.st_size );
1628 
1629 #endif /* HAVE_SENDFILE */
1630 	}
1631 
1632     (void) close( fd );
1633     }
1634 
1635 
1636 static void
do_dir(void)1637 do_dir( void )
1638     {
1639     char buf[10000];
1640     char* contents;
1641     size_t contents_size, contents_len;
1642 #ifdef HAVE_SCANDIR
1643     int n, i;
1644     struct dirent **dl;
1645     char* name_info;
1646 #else /* HAVE_SCANDIR */
1647     char command[10000];
1648     FILE* fp;
1649 #endif /* HAVE_SCANDIR */
1650 
1651     if ( pathinfo != (char*) 0 )
1652 	send_error( 404, "Not Found", "", "File not found." );
1653 
1654     /* Check authorization for this directory. */
1655     auth_check( file );
1656 
1657     /* Referrer check. */
1658     check_referrer();
1659 
1660 #ifdef HAVE_SCANDIR
1661     n = scandir( file, &dl, NULL, alphasort );
1662     if ( n < 0 )
1663 	{
1664 	syslog(
1665 	    LOG_INFO, "%.80s Directory \"%.80s\" is protected",
1666 	    ntoa( &client_addr ), path );
1667 	send_error( 403, "Forbidden", "", "Directory is protected." );
1668 	}
1669 #endif /* HAVE_SCANDIR */
1670 
1671     contents_size = 0;
1672     (void) snprintf( buf, sizeof(buf), "\
1673 <!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n\
1674 \n\
1675 <html>\n\
1676 \n\
1677   <head>\n\
1678     <meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\">\n\
1679     <title>Index of %s</title>\n\
1680   </head>\n\
1681 \n\
1682   <body bgcolor=\"#99cc99\" text=\"#000000\" link=\"#2020ff\" vlink=\"#4040cc\">\n\
1683     <h4>Index of %s</h4>\n\
1684     <pre>\n",
1685 	file, file );
1686     add_str( &contents, &contents_size, &contents_len, buf );
1687 
1688 #ifdef HAVE_SCANDIR
1689 
1690     for ( i = 0; i < n; ++i )
1691 	{
1692 	name_info = file_details( file, dl[i]->d_name );
1693 	add_str( &contents, &contents_size, &contents_len, name_info );
1694 	}
1695 
1696 #else /* HAVE_SCANDIR */
1697     /* Magic HTML ls command! */
1698     if ( strchr( file, '\'' ) == (char*) 0 )
1699 	{
1700 	(void) snprintf(
1701 	    command, sizeof(command),
1702 	    "ls -lgF '%s' | tail +2 | sed -e 's/^\\([^ ][^ ]*\\)\\(  *[^ ][^ ]*  *[^ ][^ ]*  *[^ ][^ ]*\\)\\(  *[^ ][^ ]*\\)  *\\([^ ][^ ]*  *[^ ][^ ]*  *[^ ][^ ]*\\)  *\\(.*\\)$/\\1 \\3  \\4  |\\5/' -e '/ -> /!s,|\\([^*]*\\)$,|<a href=\"\\1\">\\1</a>,' -e '/ -> /!s,|\\(.*\\)\\([*]\\)$,|<a href=\"\\1\">\\1</a>\\2,' -e '/ -> /s,|\\([^@]*\\)\\(@* -> \\),|<a href=\"\\1\">\\1</a>\\2,' -e 's/|//'",
1703 	    file );
1704 	fp = popen( command, "r" );
1705 	for (;;)
1706 	    {
1707 	    size_t r;
1708 	    r = fread( buf, 1, sizeof(buf) - 1, fp );
1709 	    if ( r == 0 )
1710 		break;
1711 	    buf[r] = '\0';
1712 	    add_str( &contents, &contents_size, &contents_len, buf );
1713 	    }
1714 	(void) pclose( fp );
1715 	}
1716 #endif /* HAVE_SCANDIR */
1717 
1718     (void) snprintf( buf, sizeof(buf), "\
1719     </pre>\n\
1720 \n\
1721     <hr>\n\
1722 \n\
1723     <address><a href=\"%s\">%s</a></address>\n\
1724   \n\
1725   </body>\n\
1726 \n\
1727 </html>\n",
1728 	SERVER_URL, SERVER_SOFTWARE );
1729     add_str( &contents, &contents_size, &contents_len, buf );
1730 
1731     add_headers( 200, "Ok", "", "", "text/html; charset=%s", contents_len, sb.st_mtime );
1732     if ( method != METHOD_HEAD )
1733 	{
1734 	contents[contents_len] = '\0';
1735 	add_to_response( contents );
1736 	}
1737     send_response();
1738     }
1739 
1740 
1741 #ifdef HAVE_SCANDIR
1742 
1743 static char*
file_details(const char * d,const char * name)1744 file_details( const char* d, const char* name )
1745     {
1746     struct stat sb2;
1747     char timestr[16];
1748     static char encname[1000];
1749     static char buf[2000];
1750 
1751     (void) snprintf( buf, sizeof(buf), "%s/%s", d, name );
1752     if ( lstat( buf, &sb2 ) < 0 )
1753 	return "???";
1754     (void) strftime( timestr, sizeof(timestr), "%d%b%Y %H:%M", localtime( &sb2.st_mtime ) );
1755     strencode( encname, sizeof(encname), name );
1756     (void) snprintf(
1757 	buf, sizeof( buf ), "<a href=\"%s\">%-32.32s</a>    %15s %14lld\n",
1758 	encname, name, timestr, (long long) sb2.st_size );
1759     return buf;
1760     }
1761 
1762 
1763 /* Copies and encodes a string. */
1764 static void
strencode(char * to,size_t tosize,const char * from)1765 strencode( char* to, size_t tosize, const char* from )
1766     {
1767     int tolen;
1768 
1769     for ( tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from )
1770 	{
1771 	if ( isalnum(*from) || strchr( "/_.-~", *from ) != (char*) 0 )
1772 	    {
1773 	    *to = *from;
1774 	    ++to;
1775 	    ++tolen;
1776 	    }
1777 	else
1778 	    {
1779 	    (void) sprintf( to, "%%%02x", (int) *from & 0xff );
1780 	    to += 3;
1781 	    tolen += 3;
1782 	    }
1783 	}
1784     *to = '\0';
1785     }
1786 
1787 #endif /* HAVE_SCANDIR */
1788 
1789 
1790 static void
do_cgi(void)1791 do_cgi( void )
1792     {
1793     char** argp;
1794     char** envp;
1795     int parse_headers;
1796     char* binary;
1797     char* directory;
1798 
1799     /* If the socket happens to be using one of the stdin/stdout/stderr
1800     ** descriptors, move it to another descriptor so that the dup2 calls
1801     ** below don't screw things up.  We arbitrarily pick fd 3 - if there
1802     ** was already something on it, we clobber it, but that doesn't matter
1803     ** since at this point the only fd of interest is the connection.
1804     ** All others will be closed on exec.
1805     */
1806     if ( conn_fd == STDIN_FILENO || conn_fd == STDOUT_FILENO || conn_fd == STDERR_FILENO )
1807 	{
1808 	int newfd = dup2( conn_fd, STDERR_FILENO + 1 );
1809 	if ( newfd >= 0 )
1810 	    conn_fd = newfd;
1811 	/* If the dup2 fails, shrug.  We'll just take our chances.
1812 	** Shouldn't happen though.
1813 	*/
1814 	}
1815 
1816     /* Make the environment vector. */
1817     envp = make_envp();
1818 
1819     /* Make the argument vector. */
1820     argp = make_argp();
1821 
1822     /* Set up stdin.  For POSTs we may have to set up a pipe from an
1823     ** interposer process, depending on if we've read some of the data
1824     ** into our buffer.  We also have to do this for all SSL CGIs.
1825     */
1826 #ifdef USE_SSL
1827     if ( ( method == METHOD_POST && request_len > request_idx ) || do_ssl )
1828 #else /* USE_SSL */
1829     if ( ( method == METHOD_POST && request_len > request_idx ) )
1830 #endif /* USE_SSL */
1831 	{
1832 	int p[2];
1833 	int r;
1834 
1835 	if ( pipe( p ) < 0 )
1836 	    send_error( 500, "Internal Error", "", "Something unexpected went wrong making a pipe." );
1837 	r = fork();
1838 	if ( r < 0 )
1839 	    send_error( 500, "Internal Error", "", "Something unexpected went wrong forking an interposer." );
1840 	if ( r == 0 )
1841 	    {
1842 	    /* Interposer process. */
1843 	    (void) close( p[0] );
1844 	    cgi_interpose_input( p[1] );
1845 	    finish_request( 0 );
1846 	    }
1847 	(void) close( p[1] );
1848 	if ( p[0] != STDIN_FILENO )
1849 	    {
1850 	    (void) dup2( p[0], STDIN_FILENO );
1851 	    (void) close( p[0] );
1852 	    }
1853 	}
1854     else
1855 	{
1856 	/* Otherwise, the request socket is stdin. */
1857 	if ( conn_fd != STDIN_FILENO )
1858 	    (void) dup2( conn_fd, STDIN_FILENO );
1859 	}
1860 
1861     /* Set up stdout/stderr.  For SSL, or if we're doing CGI header parsing,
1862     ** we need an output interposer too.
1863     */
1864     if ( strncmp( argp[0], "nph-", 4 ) == 0 )
1865 	parse_headers = 0;
1866     else
1867 	parse_headers = 1;
1868 #ifdef USE_SSL
1869     if ( parse_headers || do_ssl )
1870 #else /* USE_SSL */
1871     if ( parse_headers )
1872 #endif /* USE_SSL */
1873 	{
1874 	int p[2];
1875 	int r;
1876 
1877 	if ( pipe( p ) < 0 )
1878 	    send_error( 500, "Internal Error", "", "Something unexpected went wrong making a pipe." );
1879 	r = fork();
1880 	if ( r < 0 )
1881 	    send_error( 500, "Internal Error", "", "Something unexpected went wrong forking an interposer." );
1882 	if ( r == 0 )
1883 	    {
1884 	    /* Interposer process. */
1885 	    (void) close( p[1] );
1886 	    cgi_interpose_output( p[0], parse_headers );
1887 	    finish_request( 0 );
1888 	    }
1889 	(void) close( p[0] );
1890 	if ( p[1] != STDOUT_FILENO )
1891 	    (void) dup2( p[1], STDOUT_FILENO );
1892 	if ( p[1] != STDERR_FILENO )
1893 	    (void) dup2( p[1], STDERR_FILENO );
1894 	if ( p[1] != STDOUT_FILENO && p[1] != STDERR_FILENO )
1895 	    (void) close( p[1] );
1896 	}
1897     else
1898 	{
1899 	/* Otherwise, the request socket is stdout/stderr. */
1900 	if ( conn_fd != STDOUT_FILENO )
1901 	    (void) dup2( conn_fd, STDOUT_FILENO );
1902 	if ( conn_fd != STDERR_FILENO )
1903 	    (void) dup2( conn_fd, STDERR_FILENO );
1904 	}
1905 
1906     /* At this point we would like to set conn_fd to be close-on-exec.
1907     ** Unfortunately there seems to be a Linux problem here - if we
1908     ** do this close-on-exec in Linux, the socket stays open but stderr
1909     ** gets closed - the last fd duped from the socket.  What a mess.
1910     ** So we'll just leave the socket as is, which under other OSs means
1911     ** an extra file descriptor gets passed to the child process.  Since
1912     ** the child probably already has that file open via stdin stdout
1913     ** and/or stderr, this is not a problem.
1914     */
1915     /* (void) fcntl( conn_fd, F_SETFD, 1 ); */
1916 
1917     /* Close the log file. */
1918     if ( logfp != (FILE*) 0 )
1919 	(void) fclose( logfp );
1920 
1921     /* Close syslog. */
1922     closelog();
1923 
1924     /* Set priority. */
1925     (void) nice( CGI_NICE );
1926 
1927     /* Split the program into directory and binary, so we can chdir()
1928     ** to the program's own directory.  This isn't in the CGI 1.1
1929     ** spec, but it's what other HTTP servers do.
1930     */
1931     directory = e_strdup( file );
1932     binary = strrchr( directory, '/' );
1933     if ( binary == (char*) 0 )
1934 	binary = file;
1935     else
1936 	{
1937 	*binary++ = '\0';
1938 	(void) chdir( directory );	/* ignore errors */
1939 	}
1940 
1941     /* Default behavior for SIGPIPE. */
1942 #ifdef HAVE_SIGSET
1943     (void) sigset( SIGPIPE, SIG_DFL );
1944 #else /* HAVE_SIGSET */
1945     (void) signal( SIGPIPE, SIG_DFL );
1946 #endif /* HAVE_SIGSET */
1947 
1948     /* Run the program. */
1949     (void) execve( binary, argp, envp );
1950 
1951     /* Something went wrong. */
1952     send_error( 500, "Internal Error", "", "Something unexpected went wrong running a CGI program." );
1953     }
1954 
1955 
1956 /* This routine is used only for POST requests.  It reads the data
1957 ** from the request and sends it to the child process.  The only reason
1958 ** we need to do it this way instead of just letting the child read
1959 ** directly is that we have already read part of the data into our
1960 ** buffer.
1961 **
1962 ** Oh, and it's also used for all SSL CGIs.
1963 */
1964 static void
cgi_interpose_input(int wfd)1965 cgi_interpose_input( int wfd )
1966     {
1967     size_t c;
1968     ssize_t r, r2;
1969     char buf[1024];
1970 
1971     /* Set up the timeout for reading again, since we're in a sub-process. */
1972 #ifdef HAVE_SIGSET
1973     (void) sigset( SIGALRM, handle_read_timeout );
1974 #else /* HAVE_SIGSET */
1975     (void) signal( SIGALRM, handle_read_timeout );
1976 #endif /* HAVE_SIGSET */
1977     (void) alarm( READ_TIMEOUT );
1978 
1979     c = request_len - request_idx;
1980     if ( c > 0 )
1981 	{
1982 	if ( write( wfd, &(request[request_idx]), c ) != c )
1983 	    return;
1984 	}
1985     while ( c < content_length )
1986 	{
1987 	r = my_read( buf, MIN( sizeof(buf), content_length - c ) );
1988 	if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
1989 	    {
1990 	    sleep( 1 );
1991 	    continue;
1992 	    }
1993 	if ( r <= 0 )
1994 	    return;
1995 	for (;;)
1996 	    {
1997 	    r2 = write( wfd, buf, r );
1998 	    if ( r2 < 0 && ( errno == EINTR || errno == EAGAIN ) )
1999 		{
2000 		sleep( 1 );
2001 		continue;
2002 		}
2003 	    if ( r2 != r )
2004 		return;
2005 	    break;
2006 	    }
2007 	c += r;
2008 	(void) alarm( READ_TIMEOUT );
2009 	}
2010     post_post_garbage_hack();
2011     }
2012 
2013 
2014 /* Special hack to deal with broken browsers that send a LF or CRLF
2015 ** after POST data, causing TCP resets - we just read and discard up
2016 ** to 2 bytes.  Unfortunately this doesn't fix the problem for CGIs
2017 ** which avoid the interposer process due to their POST data being
2018 ** short.  Creating an interposer process for all POST CGIs is
2019 ** unacceptably expensive.
2020 */
2021 static void
post_post_garbage_hack(void)2022 post_post_garbage_hack( void )
2023     {
2024     char buf[2];
2025 
2026 #ifdef USE_SSL
2027     if ( do_ssl )
2028 	/* We don't need to do this for SSL, since the garbage has
2029 	** already been read.  Probably.
2030 	*/
2031 	return;
2032 #endif /* USE_SSL */
2033 
2034     set_ndelay( conn_fd );
2035     (void) read( conn_fd, buf, sizeof(buf) );
2036     clear_ndelay( conn_fd );
2037     }
2038 
2039 
2040 /* This routine is used for parsed-header CGIs and for all SSL CGIs. */
2041 static void
cgi_interpose_output(int rfd,int parse_headers)2042 cgi_interpose_output( int rfd, int parse_headers )
2043     {
2044     ssize_t r, r2;
2045     char buf[1024];
2046 
2047     /* Set up the timeout for writing again, since we're in a sub-process. */
2048 #ifdef HAVE_SIGSET
2049     (void) sigset( SIGALRM, handle_write_timeout );
2050 #else /* HAVE_SIGSET */
2051     (void) signal( SIGALRM, handle_write_timeout );
2052 #endif /* HAVE_SIGSET */
2053     (void) alarm( WRITE_TIMEOUT );
2054 
2055     if ( ! parse_headers )
2056 	{
2057 	/* If we're not parsing headers, write out the default status line
2058 	** and proceed to the echo phase.
2059 	*/
2060 	char http_head[] = "HTTP/1.0 200 OK\015\012";
2061 	(void) my_write( http_head, sizeof(http_head) );
2062 	}
2063     else
2064 	{
2065 	/* Header parsing.  The idea here is that the CGI can return special
2066 	** headers such as "Status:" and "Location:" which change the return
2067 	** status of the response.  Since the return status has to be the very
2068 	** first line written out, we have to accumulate all the headers
2069 	** and check for the special ones before writing the status.  Then
2070 	** we write out the saved headers and proceed to echo the rest of
2071 	** the response.
2072 	*/
2073 	size_t headers_size, headers_len;
2074 	char* headers;
2075 	char* br;
2076 	int s;
2077 	char* title;
2078 	char* cp;
2079 
2080 	/* Slurp in all headers. */
2081 	headers_size = 0;
2082 	add_data( &headers, &headers_size, &headers_len, (char*) 0, 0 );
2083 	for (;;)
2084 	    {
2085 	    r = read( rfd, buf, sizeof(buf) );
2086 	    if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
2087 		{
2088 		sleep( 1 );
2089 		continue;
2090 		}
2091 	    if ( r <= 0 )
2092 		{
2093 		br = &(headers[headers_len]);
2094 		break;
2095 		}
2096 	    add_data( &headers, &headers_size, &headers_len, buf, r );
2097 	    if ( ( br = strstr( headers, "\015\012\015\012" ) ) != (char*) 0 ||
2098 		 ( br = strstr( headers, "\012\012" ) ) != (char*) 0 )
2099 		break;
2100 	    }
2101 
2102 	/* If there were no headers, bail. */
2103 	if ( headers_len == 0 )
2104 	    return;
2105 
2106 	/* Figure out the status. */
2107 	s = 200;
2108 	if ( ( cp = strstr( headers, "Location:" ) ) != (char*) 0 &&
2109 	     cp < br &&
2110 	     ( cp == headers || *(cp-1) == '\012' ) )
2111 	    s = 302;
2112 	if ( ( cp = strstr( headers, "Status:" ) ) != (char*) 0 &&
2113 	     cp < br &&
2114 	     ( cp == headers || *(cp-1) == '\012' ) )
2115 	    {
2116 	    cp += 7;
2117 	    cp += strspn( cp, " \t" );
2118 	    s = atoi( cp );
2119 	    }
2120 
2121 	/* Write the status line. */
2122 	switch ( s )
2123 	    {
2124 	    case 200: title = "OK"; break;
2125 	    case 302: title = "Found"; break;
2126 	    case 304: title = "Not Modified"; break;
2127 	    case 400: title = "Bad Request"; break;
2128 	    case 401: title = "Unauthorized"; break;
2129 	    case 403: title = "Forbidden"; break;
2130 	    case 404: title = "Not Found"; break;
2131 	    case 408: title = "Request Timeout"; break;
2132 	    case 451: title = "Unavailable For Legal Reasons"; break;
2133 	    case 500: title = "Internal Error"; break;
2134 	    case 501: title = "Not Implemented"; break;
2135 	    case 503: title = "Service Temporarily Overloaded"; break;
2136 	    default: title = "Something"; break;
2137 	    }
2138 	(void) snprintf(
2139 	    buf, sizeof(buf), "HTTP/1.0 %d %s\015\012", s, title );
2140 	(void) my_write( buf, strlen( buf ) );
2141 
2142 	/* Write the saved headers. */
2143 	(void) my_write( headers, headers_len );
2144 	}
2145 
2146     /* Echo the rest of the output. */
2147     for (;;)
2148 	{
2149 	r = read( rfd, buf, sizeof(buf) );
2150 	if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
2151 	    {
2152 	    sleep( 1 );
2153 	    continue;
2154 	    }
2155 	if ( r <= 0 )
2156 	    return;
2157 	for (;;)
2158 	    {
2159 	    r2 = my_write( buf, r );
2160 	    if ( r2 < 0 && ( errno == EINTR || errno == EAGAIN ) )
2161 		{
2162 		sleep( 1 );
2163 		continue;
2164 		}
2165 	    if ( r2 != r )
2166 		return;
2167 	    break;
2168 	    }
2169 	(void) alarm( WRITE_TIMEOUT );
2170 	}
2171     }
2172 
2173 
2174 /* Set up CGI argument vector.  We don't have to worry about freeing
2175 ** stuff since we're a sub-process.  This gets done after make_envp() because
2176 ** we scribble on query.
2177 */
2178 static char**
make_argp(void)2179 make_argp( void )
2180     {
2181     char** argp;
2182     int argn;
2183     char* cp1;
2184     char* cp2;
2185 
2186     /* By allocating an arg slot for every character in the query, plus
2187     ** one for the filename and one for the NULL, we are guaranteed to
2188     ** have enough.  We could actually use strlen/2.
2189     */
2190     argp = (char**) malloc( ( strlen( query ) + 2 ) * sizeof(char*) );
2191     if ( argp == (char**) 0 )
2192 	return (char**) 0;
2193 
2194     argp[0] = strrchr( file, '/' );
2195     if ( argp[0] != (char*) 0 )
2196 	++argp[0];
2197     else
2198 	argp[0] = file;
2199 
2200     argn = 1;
2201     /* According to the CGI spec at http://hoohoo.ncsa.uiuc.edu/cgi/cl.html,
2202     ** "The server should search the query information for a non-encoded =
2203     ** character to determine if the command line is to be used, if it finds
2204     ** one, the command line is not to be used."
2205     */
2206     if ( strchr( query, '=' ) == (char*) 0 )
2207 	{
2208 	for ( cp1 = cp2 = query; *cp2 != '\0'; ++cp2 )
2209 	    {
2210 	    if ( *cp2 == '+' )
2211 		{
2212 		*cp2 = '\0';
2213 		strdecode( cp1, cp1 );
2214 		argp[argn++] = cp1;
2215 		cp1 = cp2 + 1;
2216 		}
2217 	    }
2218 	if ( cp2 != cp1 )
2219 	    {
2220 	    strdecode( cp1, cp1 );
2221 	    argp[argn++] = cp1;
2222 	    }
2223 	}
2224 
2225     argp[argn] = (char*) 0;
2226     return argp;
2227     }
2228 
2229 
2230 /* Set up CGI environment variables. Be real careful here to avoid
2231 ** letting malicious clients overrun a buffer.  We don't have
2232 ** to worry about freeing stuff since we're a sub-process.
2233 */
2234 static char**
make_envp(void)2235 make_envp( void )
2236     {
2237     static char* envp[50];
2238     int envn;
2239     char* cp;
2240     char buf[256];
2241 
2242     envn = 0;
2243     envp[envn++] = build_env( "PATH=%s", CGI_PATH );
2244     envp[envn++] = build_env( "LD_LIBRARY_PATH=%s", CGI_LD_LIBRARY_PATH );
2245     envp[envn++] = build_env( "SERVER_SOFTWARE=%s", SERVER_SOFTWARE );
2246     if ( vhost && req_hostname != (char*) 0 && req_hostname[0] != '\0' )
2247 	cp = req_hostname;	/* already computed by virtual_file() */
2248     else if ( host != (char*) 0 && host[0] != '\0' )
2249 	cp = host;
2250     else
2251 	cp = hostname;
2252     if ( cp != (char*) 0 )
2253 	envp[envn++] = build_env( "SERVER_NAME=%s", cp );
2254     envp[envn++] = "GATEWAY_INTERFACE=CGI/1.1";
2255     envp[envn++] = "SERVER_PROTOCOL=HTTP/1.0";
2256     (void) snprintf( buf, sizeof(buf), "%d", (int) port );
2257     envp[envn++] = build_env( "SERVER_PORT=%s", buf );
2258     envp[envn++] = build_env(
2259 	"REQUEST_METHOD=%s", get_method_str( method ) );
2260     envp[envn++] = build_env( "SCRIPT_NAME=%s", path );
2261     if ( pathinfo != (char*) 0 )
2262 	{
2263 	envp[envn++] = build_env( "PATH_INFO=/%s", pathinfo );
2264 	(void) snprintf( buf, sizeof(buf), "%s%s", cwd, pathinfo );
2265 	envp[envn++] = build_env( "PATH_TRANSLATED=%s", buf );
2266 	}
2267     if ( query[0] != '\0' )
2268 	envp[envn++] = build_env( "QUERY_STRING=%s", query );
2269     envp[envn++] = build_env( "REMOTE_ADDR=%s", ntoa( &client_addr ) );
2270     if ( referrer[0] != '\0' )
2271 	{
2272 	envp[envn++] = build_env( "HTTP_REFERER=%s", referrer );
2273 	envp[envn++] = build_env( "HTTP_REFERRER=%s", referrer );
2274 	}
2275     if ( useragent[0] != '\0' )
2276 	envp[envn++] = build_env( "HTTP_USER_AGENT=%s", useragent );
2277     if ( cookie != (char*) 0 )
2278 	envp[envn++] = build_env( "HTTP_COOKIE=%s", cookie );
2279     if ( host != (char*) 0 )
2280 	envp[envn++] = build_env( "HTTP_HOST=%s", host );
2281     if ( content_type != (char*) 0 )
2282 	envp[envn++] = build_env( "CONTENT_TYPE=%s", content_type );
2283     if ( content_length != -1 )
2284 	{
2285 	(void) snprintf(
2286 	    buf, sizeof(buf), "%lu", (unsigned long) content_length );
2287 	envp[envn++] = build_env( "CONTENT_LENGTH=%s", buf );
2288 	}
2289     if ( remoteuser != (char*) 0 )
2290 	envp[envn++] = build_env( "REMOTE_USER=%s", remoteuser );
2291     if ( authorization != (char*) 0 )
2292 	envp[envn++] = build_env( "AUTH_TYPE=%s", "Basic" );
2293     if ( getenv( "TZ" ) != (char*) 0 )
2294 	envp[envn++] = build_env( "TZ=%s", getenv( "TZ" ) );
2295 
2296     envp[envn] = (char*) 0;
2297     return envp;
2298     }
2299 
2300 
2301 static char*
build_env(char * fmt,char * arg)2302 build_env( char* fmt, char* arg )
2303     {
2304     char* cp;
2305     int size;
2306     static char* buf;
2307     static int maxbuf = 0;
2308 
2309     size = strlen( fmt ) + strlen( arg );
2310     if ( size > maxbuf )
2311 	{
2312 	if ( maxbuf == 0 )
2313 	    {
2314 	    maxbuf = MAX( 200, size + 100 );
2315 	    buf = (char*) e_malloc( maxbuf );
2316 	    }
2317 	else
2318 	    {
2319 	    maxbuf = MAX( maxbuf * 2, size * 5 / 4 );
2320 	    buf = (char*) e_realloc( (void*) buf, maxbuf );
2321 	    }
2322 	}
2323     (void) snprintf( buf, maxbuf, fmt, arg );
2324     cp = e_strdup( buf );
2325     return cp;
2326     }
2327 
2328 
2329 static void
auth_check(char * dirname)2330 auth_check( char* dirname )
2331     {
2332     char authpath[10000];
2333     struct stat sb2;
2334     char authinfo[500];
2335     char* authpass;
2336     char* colon;
2337     static char line[10000];
2338     int l;
2339     FILE* fp;
2340     char* cryp;
2341 
2342     /* Construct auth filename. */
2343     if ( dirname[strlen(dirname) - 1] == '/' )
2344 	(void) snprintf( authpath, sizeof(authpath), "%s%s", dirname, AUTH_FILE );
2345     else
2346 	(void) snprintf( authpath, sizeof(authpath), "%s/%s", dirname, AUTH_FILE );
2347 
2348     /* Does this directory have an auth file? */
2349     if ( stat( authpath, &sb2 ) < 0 )
2350 	/* Nope, let the request go through. */
2351 	return;
2352 
2353     /* Does this request contain authorization info? */
2354     if ( authorization == (char*) 0 )
2355 	/* Nope, return a 401 Unauthorized. */
2356 	send_authenticate( dirname );
2357 
2358     /* Basic authorization info? */
2359     if ( strncmp( authorization, "Basic ", 6 ) != 0 )
2360 	send_authenticate( dirname );
2361 
2362     /* Decode it. */
2363     l = b64_decode(
2364 	&(authorization[6]), (unsigned char*) authinfo, sizeof(authinfo) - 1 );
2365     authinfo[l] = '\0';
2366     /* Split into user and password. */
2367     authpass = strchr( authinfo, ':' );
2368     if ( authpass == (char*) 0 )
2369 	/* No colon?  Bogus auth info. */
2370 	send_authenticate( dirname );
2371     *authpass++ = '\0';
2372     /* If there are more fields, cut them off. */
2373     colon = strchr( authpass, ':' );
2374     if ( colon != (char*) 0 )
2375 	*colon = '\0';
2376 
2377     /* Open the password file. */
2378     fp = fopen( authpath, "r" );
2379     if ( fp == (FILE*) 0 )
2380 	{
2381 	/* The file exists but we can't open it?  Disallow access. */
2382 	syslog(
2383 	    LOG_ERR, "%.80s auth file %.80s could not be opened - %m",
2384 	    ntoa( &client_addr ), authpath );
2385 	send_error( 403, "Forbidden", "", "File is protected." );
2386 	}
2387 
2388     /* Read it. */
2389     while ( fgets( line, sizeof(line), fp ) != (char*) 0 )
2390 	{
2391 	/* Nuke newline. */
2392 	l = strlen( line );
2393 	if ( line[l - 1] == '\n' )
2394 	    line[l - 1] = '\0';
2395 	/* Split into user and encrypted password. */
2396 	cryp = strchr( line, ':' );
2397 	if ( cryp == (char*) 0 )
2398 	    continue;
2399 	*cryp++ = '\0';
2400 	/* Is this the right user? */
2401 	if ( strcmp( line, authinfo ) == 0 )
2402 	    {
2403 	    /* Yes. */
2404 	    (void) fclose( fp );
2405 	    /* So is the password right? */
2406 	    if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
2407 		{
2408 		/* Ok! */
2409 		remoteuser = line;
2410 		return;
2411 		}
2412 	    else
2413 		/* No. */
2414 		send_authenticate( dirname );
2415 	    }
2416 	}
2417 
2418     /* Didn't find that user.  Access denied. */
2419     (void) fclose( fp );
2420     send_authenticate( dirname );
2421     }
2422 
2423 
2424 static void
send_authenticate(char * realm)2425 send_authenticate( char* realm )
2426     {
2427     char header[10000];
2428 
2429     (void) snprintf(
2430 	header, sizeof(header), "WWW-Authenticate: Basic realm=\"%s\"", realm );
2431     send_error( 401, "Unauthorized", header, "Authorization required." );
2432     }
2433 
2434 
2435 static char*
virtual_file(char * f)2436 virtual_file( char* f )
2437     {
2438     char* cp;
2439     static char vfile[10000];
2440 
2441     /* Use the request's hostname, or fall back on the IP address. */
2442     if ( host != (char*) 0 )
2443 	req_hostname = host;
2444     else
2445 	{
2446 	usockaddr usa;
2447 	socklen_t sz = sizeof(usa);
2448 	if ( getsockname( conn_fd, &usa.sa, &sz ) < 0 )
2449 	    req_hostname = "UNKNOWN_HOST";
2450 	else
2451 	    req_hostname = ntoa( &usa );
2452 	}
2453     /* Pound it to lower case. */
2454     for ( cp = req_hostname; *cp != '\0'; ++cp )
2455 	if ( isupper( *cp ) )
2456 	    *cp = tolower( *cp );
2457     (void) snprintf( vfile, sizeof(vfile), "%s/%s", req_hostname, f );
2458     return vfile;
2459     }
2460 
2461 
2462 static void
send_error(int s,char * title,char * extra_header,char * text)2463 send_error( int s, char* title, char* extra_header, char* text )
2464     {
2465     add_headers(
2466 	s, title, extra_header, "", "text/html; charset=%s", (off_t) -1, (time_t) -1 );
2467 
2468     send_error_body( s, title, text );
2469 
2470     send_error_tail();
2471 
2472     send_response();
2473 
2474 #ifdef USE_SSL
2475     SSL_free( ssl );
2476 #endif /* USE_SSL */
2477     finish_request( 1 );
2478     }
2479 
2480 
2481 static void
send_error_body(int s,char * title,char * text)2482 send_error_body( int s, char* title, char* text )
2483     {
2484     char filename[1000];
2485     char buf[10000];
2486 
2487     if ( vhost && req_hostname != (char*) 0 )
2488 	{
2489 	/* Try virtual-host custom error page. */
2490 	(void) snprintf(
2491 	    filename, sizeof(filename), "%s/%s/err%d.html",
2492 	    req_hostname, ERR_DIR, s );
2493 	if ( send_error_file( filename ) )
2494 	    return;
2495 	}
2496 
2497     /* Try server-wide custom error page. */
2498     (void) snprintf(
2499 	filename, sizeof(filename), "%s/err%d.html", ERR_DIR, s );
2500     if ( send_error_file( filename ) )
2501 	return;
2502 
2503     /* Send built-in error page. */
2504     (void) snprintf(
2505 	buf, sizeof(buf), "\
2506 <!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n\
2507 \n\
2508 <html>\n\
2509 \n\
2510   <head>\n\
2511     <meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\">\n\
2512     <title>%d %s</title>\n\
2513   </head>\n\
2514 \n\
2515   <body bgcolor=\"#cc9999\" text=\"#000000\" link=\"#2020ff\" vlink=\"#4040cc\">\n\
2516 \n\
2517     <h4>%d %s</h4>\n",
2518 	s, title, s, title );
2519     add_to_response( buf );
2520     (void) snprintf( buf, sizeof(buf), "%s\n", text );
2521     add_to_response( buf );
2522     }
2523 
2524 
2525 static int
send_error_file(char * filename)2526 send_error_file( char* filename )
2527     {
2528     FILE* fp;
2529     char buf[1000];
2530     size_t r;
2531 
2532     fp = fopen( filename, "r" );
2533     if ( fp == (FILE*) 0 )
2534 	return 0;
2535     for (;;)
2536 	{
2537 	r = fread( buf, 1, sizeof(buf) - 1, fp );
2538 	if ( r == 0 )
2539 	    break;
2540 	buf[r] = '\0';
2541 	add_to_response( buf );
2542 	}
2543     (void) fclose( fp );
2544     return 1;
2545     }
2546 
2547 
2548 static void
send_error_tail(void)2549 send_error_tail( void )
2550     {
2551     char buf[500];
2552 
2553     if ( match( "**MSIE**", useragent ) )
2554 	{
2555 	int n;
2556 	(void) snprintf( buf, sizeof(buf), "<!--\n" );
2557 	add_to_response( buf );
2558 	for ( n = 0; n < 6; ++n )
2559 	    {
2560 	    (void) snprintf( buf, sizeof(buf), "Padding so that MSIE deigns to show this error instead of its own canned one.\n" );
2561 	    add_to_response( buf );
2562 	    }
2563 	(void) snprintf( buf, sizeof(buf), "-->\n" );
2564 	add_to_response( buf );
2565 	}
2566 
2567     (void) snprintf( buf, sizeof(buf), "\
2568     <hr>\n\
2569 \n\
2570     <address><a href=\"%s\">%s</a></address>\n\
2571 \n\
2572   </body>\n\
2573 \n\
2574 </html>\n",
2575 	SERVER_URL, SERVER_SOFTWARE );
2576     add_to_response( buf );
2577     }
2578 
2579 
2580 static void
add_headers(int s,char * title,char * extra_header,char * me,char * mt,off_t b,time_t mod)2581 add_headers( int s, char* title, char* extra_header, char* me, char* mt, off_t b, time_t mod )
2582     {
2583     time_t now, expires;
2584     char timebuf[100];
2585     char buf[10000];
2586     int s100;
2587     const char* rfc1123_fmt = "%a, %d %b %Y %H:%M:%S GMT";
2588 
2589     status = s;
2590     bytes = b;
2591     make_log_entry();
2592     start_response();
2593     (void) snprintf( buf, sizeof(buf), "%s %d %s\015\012", protocol, status, title );
2594     add_to_response( buf );
2595     (void) snprintf( buf, sizeof(buf), "Server: %s\015\012", SERVER_SOFTWARE );
2596     add_to_response( buf );
2597     now = time( (time_t*) 0 );
2598     (void) strftime( timebuf, sizeof(timebuf), rfc1123_fmt, gmtime( &now ) );
2599     (void) snprintf( buf, sizeof(buf), "Date: %s\015\012", timebuf );
2600     add_to_response( buf );
2601     s100 = status / 100;
2602     if ( s100 != 2 && s100 != 3 )
2603 	{
2604 	(void) snprintf( buf, sizeof(buf), "Cache-Control: no-cache,no-store\015\012" );
2605 	add_to_response( buf );
2606 	}
2607     if ( extra_header != (char*) 0 && extra_header[0] != '\0' )
2608 	{
2609 	(void) snprintf( buf, sizeof(buf), "%s\015\012", extra_header );
2610 	add_to_response( buf );
2611 	}
2612     if ( me != (char*) 0 && me[0] != '\0' )
2613 	{
2614 	(void) snprintf( buf, sizeof(buf), "Content-Encoding: %s\015\012", me );
2615 	add_to_response( buf );
2616 	}
2617     if ( mt != (char*) 0 && mt[0] != '\0' )
2618 	{
2619 	(void) snprintf( buf, sizeof(buf), "Content-Type: %s\015\012", mt );
2620 	add_to_response( buf );
2621 	}
2622     if ( bytes >= 0 )
2623 	{
2624 	(void) snprintf(
2625 	    buf, sizeof(buf), "Content-Length: %lld\015\012", (long long) bytes );
2626 	add_to_response( buf );
2627 	}
2628     if ( p3p != (char*) 0 && p3p[0] != '\0' )
2629 	{
2630 	(void) snprintf( buf, sizeof(buf), "P3P: %s\015\012", p3p );
2631 	add_to_response( buf );
2632 	}
2633     if ( max_age >= 0 )
2634 	{
2635 	expires = now + max_age;
2636 	(void) strftime(
2637 	    timebuf, sizeof(timebuf), rfc1123_fmt, gmtime( &expires ) );
2638 	(void) snprintf( buf, sizeof(buf),
2639 	    "Cache-Control: max-age=%d\015\012Expires: %s\015\012", max_age, timebuf );
2640 	add_to_response( buf );
2641 	}
2642     if ( mod != (time_t) -1 )
2643 	{
2644 	(void) strftime(
2645 	    timebuf, sizeof(timebuf), rfc1123_fmt, gmtime( &mod ) );
2646 	(void) snprintf( buf, sizeof(buf), "Last-Modified: %s\015\012", timebuf );
2647 	add_to_response( buf );
2648 	}
2649     (void) snprintf( buf, sizeof(buf), "Connection: close\015\012\015\012" );
2650     add_to_response( buf );
2651     }
2652 
2653 
2654 static void
start_request(void)2655 start_request( void )
2656     {
2657     request_size = 0;
2658     request_idx = 0;
2659     }
2660 
2661 static void
add_to_request(char * str,size_t len)2662 add_to_request( char* str, size_t len )
2663     {
2664     add_data( &request, &request_size, &request_len, str, len );
2665     }
2666 
2667 static char*
get_request_line(void)2668 get_request_line( void )
2669     {
2670     int i;
2671     char c;
2672 
2673     for ( i = request_idx; request_idx < request_len; ++request_idx )
2674 	{
2675 	c = request[request_idx];
2676 	if ( c == '\012' || c == '\015' )
2677 	    {
2678 	    request[request_idx] = '\0';
2679 	    ++request_idx;
2680 	    if ( c == '\015' && request_idx < request_len &&
2681 		 request[request_idx] == '\012' )
2682 		{
2683 		request[request_idx] = '\0';
2684 		++request_idx;
2685 		}
2686 	    return &(request[i]);
2687 	    }
2688 	}
2689     return (char*) 0;
2690     }
2691 
2692 
2693 static char* response;
2694 static size_t response_size, response_len;
2695 
2696 static void
start_response(void)2697 start_response( void )
2698     {
2699     response_size = 0;
2700     }
2701 
2702 static void
add_to_response(char * str)2703 add_to_response( char* str )
2704     {
2705     add_str( &response, &response_size, &response_len, str );
2706     }
2707 
2708 static void
send_response(void)2709 send_response( void )
2710     {
2711     (void) my_write( response, response_len );
2712     }
2713 
2714 
2715 static void
send_via_write(int fd,off_t size)2716 send_via_write( int fd, off_t size )
2717     {
2718     /* On some systems an off_t is 64 bits while a size_t is still only
2719     ** 32 bits.  The mmap() system call takes a size_t as the length argument,
2720     ** so we can only use mmap() if the size will fit into a size_t.
2721     */
2722     if ( size <= SIZE_T_MAX )
2723 	{
2724 	size_t size_size = (size_t) size;
2725 	unsigned char* ptr = mmap( 0, size_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2726 	if ( ptr != (unsigned char*) -1 )
2727 	    {
2728 	    unsigned char* p = ptr;
2729 	    size_t remaining_size = size_size;
2730 #ifdef MADV_SEQUENTIAL
2731 	    /* If we have madvise, might as well call it.  Although sequential
2732 	    ** access is probably already the default.
2733 	    */
2734 	    (void) madvise( ptr, size_size, MADV_SEQUENTIAL );
2735 #endif /* MADV_SEQUENTIAL */
2736 	    /* We could send the whole file in a single write, but if
2737 	    ** it's huge then we run the risk of hitting the timeout.
2738 	    ** So we do a loop writing large segments, and reseting the
2739 	    ** timeout each time through.
2740 	    */
2741 	    while ( remaining_size > 0 )
2742 		{
2743 		size_t buf_size = MIN( remaining_size, MAX_SEND_BUFFER_SIZE );
2744 		ssize_t r = my_write( p, buf_size );
2745 		if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
2746 		    {
2747 		    sleep( 1 );
2748 		    continue;
2749 		    }
2750 		if ( r != buf_size )
2751 		    return;
2752 		remaining_size -= r;
2753 		p += r;
2754 		(void) alarm( WRITE_TIMEOUT );
2755 		}
2756 	    (void) munmap( ptr, size_size );
2757 	    }
2758 	}
2759     else
2760 	{
2761 	/* The file is too big for mmap, so we'll send it via read & write
2762 	** instead.  This would be less efficient for small files because
2763 	** it bypasses the buffer cache, but with a file this huge the
2764 	** cache will get blown anyway.
2765 	*/
2766 	char buf[30000];
2767 
2768 	for (;;)
2769 	    {
2770 	    ssize_t r = read( fd, buf, sizeof(buf) );
2771 	    if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
2772 		{
2773 		sleep( 1 );
2774 		continue;
2775 		}
2776 	    if ( r <= 0 )
2777 		return;
2778 	    for (;;)
2779 		{
2780 		ssize_t r2 = my_write( buf, r );
2781 		if ( r2 < 0 && ( errno == EINTR || errno == EAGAIN ) )
2782 		    {
2783 		    sleep( 1 );
2784 		    continue;
2785 		    }
2786 		if ( r2 != r )
2787 		    return;
2788 		break;
2789 		}
2790 	    (void) alarm( WRITE_TIMEOUT );
2791 	    }
2792 	}
2793     }
2794 
2795 
2796 static void
send_via_sendfile(int fd,int s,off_t size)2797 send_via_sendfile( int fd, int s, off_t size )
2798     {
2799     /* We could send the whole file in a single sendfile, but if
2800     ** it's huge then we run the risk of hitting the timeout.
2801     ** So we do a loop writing large segments, and reseting the
2802     ** timeout each time through.
2803     **
2804     ** This also avoids the problem of using sendfile on a file larger
2805     ** than 2GB, since each segment size will now fit into a size_t.
2806     */
2807     off_t remaining_size = size;
2808     off_t off = 0;
2809     while ( remaining_size > 0 )
2810 	{
2811 	size_t buf_size = MIN( remaining_size, MAX_SEND_BUFFER_SIZE );
2812 	ssize_t r = my_sendfile( fd, s, off, buf_size );
2813 	if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
2814 	    {
2815 	    sleep( 1 );
2816 	    continue;
2817 	    }
2818 	if ( r != buf_size )
2819 	    return;
2820 	remaining_size -= r;
2821 	off += r;
2822 	(void) alarm( WRITE_TIMEOUT );
2823 	}
2824     }
2825 
2826 
2827 static ssize_t
my_read(char * buf,size_t size)2828 my_read( char* buf, size_t size )
2829     {
2830 #ifdef USE_SSL
2831     if ( do_ssl )
2832 	return SSL_read( ssl, buf, size );
2833     else
2834 	return read( conn_fd, buf, size );
2835 #else /* USE_SSL */
2836     return read( conn_fd, buf, size );
2837 #endif /* USE_SSL */
2838     }
2839 
2840 
2841 static ssize_t
my_write(void * buf,size_t size)2842 my_write( void* buf, size_t size )
2843     {
2844 #ifdef USE_SSL
2845     if ( do_ssl )
2846 	return SSL_write( ssl, buf, size );
2847     else
2848 	return write( conn_fd, buf, size );
2849 #else /* USE_SSL */
2850     return write( conn_fd, buf, size );
2851 #endif /* USE_SSL */
2852     }
2853 
2854 
2855 #ifdef HAVE_SENDFILE
2856 static ssize_t
my_sendfile(int fd,int s,off_t offset,size_t nbytes)2857 my_sendfile( int fd, int s, off_t offset, size_t nbytes )
2858     {
2859 #ifdef HAVE_LINUX_SENDFILE
2860     off_t lo = offset;
2861     return sendfile( s, fd, &lo, nbytes );
2862 #else /* HAVE_LINUX_SENDFILE */
2863     int r;
2864     r = sendfile( fd, s, offset, nbytes, (struct sf_hdtr*) 0, (off_t*) 0, 0 );
2865     if ( r == 0 )
2866 	return nbytes;
2867     else
2868 	return r;
2869 #endif /* HAVE_LINUX_SENDFILE */
2870     }
2871 #endif /* HAVE_SENDFILE */
2872 
2873 
2874 static void
add_str(char ** bufP,size_t * bufsizeP,size_t * buflenP,char * str)2875 add_str( char** bufP, size_t* bufsizeP, size_t* buflenP, char* str )
2876     {
2877     size_t len;
2878 
2879     if ( str == (char*) 0 )
2880 	len = 0;
2881     else
2882 	len = strlen( str );
2883     add_data( bufP, bufsizeP, buflenP, str, len );
2884     }
2885 
2886 
2887 static void
add_data(char ** bufP,size_t * bufsizeP,size_t * buflenP,char * str,size_t len)2888 add_data( char** bufP, size_t* bufsizeP, size_t* buflenP, char* str, size_t len )
2889     {
2890     if ( *bufsizeP == 0 )
2891 	{
2892 	*bufsizeP = len + 500;
2893 	*buflenP = 0;
2894 	*bufP = (char*) e_malloc( *bufsizeP );
2895 	}
2896     else if ( *buflenP + len >= *bufsizeP )	/* allow for NUL */
2897 	{
2898 	*bufsizeP = *buflenP + len + 500;
2899 	*bufP = (char*) e_realloc( (void*) *bufP, *bufsizeP );
2900 	}
2901 
2902     if ( len > 0 )
2903 	{
2904 	(void) memmove( &((*bufP)[*buflenP]), str, len );
2905 	*buflenP += len;
2906 	}
2907 
2908     (*bufP)[*buflenP] = '\0';
2909     }
2910 
2911 
2912 static void
make_log_entry(void)2913 make_log_entry( void )
2914     {
2915     char* ru;
2916     char url[500];
2917     char bytes_str[40];
2918     time_t now;
2919     struct tm* t;
2920     const char* cernfmt_nozone = "%d/%b/%Y:%H:%M:%S";
2921     char date_nozone[100];
2922     int zone;
2923     char sign;
2924     char date[100];
2925 
2926     if ( logfp == (FILE*) 0 )
2927 	return;
2928 
2929     /* Fill in some null values. */
2930     if ( protocol == (char*) 0 )
2931 	protocol = "UNKNOWN";
2932     if ( path == (char*) 0 )
2933 	path = "";
2934     if ( req_hostname == (char*) 0 )
2935 	req_hostname = hostname;
2936 
2937     /* Format the user. */
2938     if ( remoteuser != (char*) 0 )
2939 	ru = remoteuser;
2940     else
2941 	ru = "-";
2942     now = time( (time_t*) 0 );
2943     /* If we're vhosting, prepend the hostname to the url.  This is
2944     ** a little weird, perhaps writing separate log files for
2945     ** each vhost would make more sense.
2946     */
2947     if ( vhost )
2948 	(void) snprintf( url, sizeof(url), "/%s%s", req_hostname, path );
2949     else
2950 	(void) snprintf( url, sizeof(url), "%s", path );
2951     /* Format the bytes. */
2952     if ( bytes >= 0 )
2953 	(void) snprintf(
2954 	    bytes_str, sizeof(bytes_str), "%lld", (long long) bytes );
2955     else
2956 	(void) strcpy( bytes_str, "-" );
2957     /* Format the time, forcing a numeric timezone (some log analyzers
2958     ** are stoooopid about this).
2959     */
2960     t = localtime( &now );
2961     (void) strftime( date_nozone, sizeof(date_nozone), cernfmt_nozone, t );
2962 #ifdef HAVE_TM_GMTOFF
2963     zone = t->tm_gmtoff / 60L;
2964 #else
2965     zone = - ( timezone / 60L );
2966     /* Probably have to add something about daylight time here. */
2967 #endif
2968     if ( zone >= 0 )
2969 	sign = '+';
2970     else
2971 	{
2972 	sign = '-';
2973 	zone = -zone;
2974 	}
2975     zone = ( zone / 60 ) * 100 + zone % 60;
2976     (void) snprintf( date, sizeof(date), "%s %c%04d", date_nozone, sign, zone );
2977     /* And write the log entry. */
2978     (void) fprintf( logfp,
2979 	"%.80s - %.80s [%s] \"%.80s %.200s %.80s\" %d %s \"%.200s\" \"%.200s\"\n",
2980 	ntoa( &client_addr ), ru, date, get_method_str( method ), url,
2981 	protocol, status, bytes_str, referrer, useragent );
2982     (void) fflush( logfp );
2983     }
2984 
2985 
2986 /* Returns if it's ok to serve the url, otherwise generates an error
2987 ** and exits.
2988 */
2989 static void
check_referrer(void)2990 check_referrer( void )
2991     {
2992     char* cp;
2993 
2994     /* Are we doing referrer checking at all? */
2995     if ( url_pattern == (char*) 0 )
2996 	return;
2997 
2998     /* Is it ok? */
2999     if ( really_check_referrer() )
3000 	return;
3001 
3002     /* Lose. */
3003     if ( vhost && req_hostname != (char*) 0 )
3004 	cp = req_hostname;
3005     else
3006 	cp = hostname;
3007     if ( cp == (char*) 0 )
3008 	cp = "";
3009     syslog(
3010 	LOG_INFO, "%.80s non-local referrer \"%.80s%.80s\" \"%.80s\"",
3011 	ntoa( &client_addr ), cp, path, referrer );
3012     send_error( 403, "Forbidden", "", "You must supply a local referrer." );
3013     }
3014 
3015 
3016 /* Returns 1 if ok to serve the url, 0 if not. */
3017 static int
really_check_referrer(void)3018 really_check_referrer( void )
3019     {
3020     char* cp1;
3021     char* cp2;
3022     char* cp3;
3023     char* refhost;
3024     char *lp;
3025 
3026     /* Check for an empty referrer. */
3027     if ( referrer == (char*) 0 || referrer[0] == '\0' ||
3028 	 ( cp1 = strstr( referrer, "//" ) ) == (char*) 0 )
3029 	{
3030 	/* Disallow if we require a referrer and the url matches. */
3031 	if ( no_empty_referrers && match( url_pattern, path ) )
3032 	    return 0;
3033 	/* Otherwise ok. */
3034 	return 1;
3035 	}
3036 
3037     /* Extract referrer host. */
3038     cp1 += 2;
3039     for ( cp2 = cp1; *cp2 != '/' && *cp2 != ':' && *cp2 != '\0'; ++cp2 )
3040 	continue;
3041     refhost = (char*) e_malloc( cp2 - cp1 + 1 );
3042     for ( cp3 = refhost; cp1 < cp2; ++cp1, ++cp3 )
3043 	if ( isupper(*cp1) )
3044 	    *cp3 = tolower(*cp1);
3045 	else
3046 	    *cp3 = *cp1;
3047     *cp3 = '\0';
3048 
3049     /* Local pattern? */
3050     if ( local_pattern != (char*) 0 )
3051 	lp = local_pattern;
3052     else
3053 	{
3054 	/* No local pattern.  What's our hostname? */
3055 	if ( ! vhost )
3056 	    {
3057 	    /* Not vhosting, use the server name. */
3058 	    lp = hostname;
3059 	    if ( lp == (char*) 0 )
3060 		/* Couldn't figure out local hostname - give up. */
3061 		return 1;
3062 	    }
3063 	else
3064 	    {
3065 	    /* We are vhosting, use the hostname on this connection. */
3066 	    lp = req_hostname;
3067 	    if ( lp == (char*) 0 )
3068 		/* Oops, no hostname.  Maybe it's an old browser that
3069 		** doesn't send a Host: header.  We could figure out
3070 		** the default hostname for this IP address, but it's
3071 		** not worth it for the few requests like this.
3072 		*/
3073 		return 1;
3074 	    }
3075 	}
3076 
3077     /* If the referrer host doesn't match the local host pattern, and
3078     ** the URL does match the url pattern, it's an illegal reference.
3079     */
3080     if ( ! match( lp, refhost ) && match( url_pattern, path ) )
3081 	return 0;
3082     /* Otherwise ok. */
3083     return 1;
3084     }
3085 
3086 
3087 static char*
get_method_str(int m)3088 get_method_str( int m )
3089     {
3090     switch ( m )
3091 	{
3092 	case METHOD_GET: return "GET";
3093 	case METHOD_HEAD: return "HEAD";
3094 	case METHOD_POST: return "POST";
3095 	case METHOD_PUT: return "PUT";
3096 	case METHOD_DELETE: return "DELETE";
3097 	case METHOD_TRACE: return "TRACE";
3098 	default: return "UNKNOWN";
3099 	}
3100     }
3101 
3102 
3103 struct mime_entry {
3104     char* ext;
3105     size_t ext_len;
3106     char* val;
3107     size_t val_len;
3108     };
3109 static struct mime_entry enc_tab[] = {
3110 #include "mime_encodings.h"
3111     };
3112 static const int n_enc_tab = sizeof(enc_tab) / sizeof(*enc_tab);
3113 static struct mime_entry typ_tab[] = {
3114 #include "mime_types.h"
3115     };
3116 static const int n_typ_tab = sizeof(typ_tab) / sizeof(*typ_tab);
3117 
3118 
3119 /* qsort comparison routine */
3120 static int
ext_compare(const void * v1,const void * v2)3121 ext_compare( const void* v1, const void* v2 )
3122     {
3123     const struct mime_entry* m1 = (const struct mime_entry*) v1;
3124     const struct mime_entry* m2 = (const struct mime_entry*) v2;
3125     return strcmp( m1->ext, m2->ext );
3126     }
3127 
3128 
3129 static void
init_mime(void)3130 init_mime( void )
3131     {
3132     int i;
3133 
3134     /* Sort the tables so we can do binary search. */
3135     qsort( enc_tab, n_enc_tab, sizeof(*enc_tab), ext_compare );
3136     qsort( typ_tab, n_typ_tab, sizeof(*typ_tab), ext_compare );
3137 
3138     /* Fill in the lengths. */
3139     for ( i = 0; i < n_enc_tab; ++i )
3140 	{
3141 	enc_tab[i].ext_len = strlen( enc_tab[i].ext );
3142 	enc_tab[i].val_len = strlen( enc_tab[i].val );
3143 	}
3144     for ( i = 0; i < n_typ_tab; ++i )
3145 	{
3146 	typ_tab[i].ext_len = strlen( typ_tab[i].ext );
3147 	typ_tab[i].val_len = strlen( typ_tab[i].val );
3148 	}
3149     }
3150 
3151 
3152 /* Figure out MIME encodings and type based on the filename.  Multiple
3153 ** encodings are separated by commas, and are listed in the order in
3154 ** which they were applied to the file.
3155 */
3156 static const char*
figure_mime(char * name,char * me,size_t me_size)3157 figure_mime( char* name, char* me, size_t me_size )
3158     {
3159     char* prev_dot;
3160     char* dot;
3161     char* ext;
3162     int me_indexes[100], n_me_indexes;
3163     size_t ext_len, me_len;
3164     int i, top, bot, mid;
3165     int r;
3166     const char* default_type = "text/plain; charset=%s";
3167     const char* type;
3168 
3169     /* Peel off encoding extensions until there aren't any more. */
3170     n_me_indexes = 0;
3171     for ( prev_dot = &name[strlen(name)]; ; prev_dot = dot )
3172 	{
3173 	for ( dot = prev_dot - 1; dot >= name && *dot != '.'; --dot )
3174 	    ;
3175 	if ( dot < name )
3176 	    {
3177 	    /* No dot found.  No more encoding extensions, and no type
3178 	    ** extension either.
3179 	    */
3180 	    type = default_type;
3181 	    goto done;
3182 	    }
3183 	ext = dot + 1;
3184 	ext_len = prev_dot - ext;
3185 	/* Search the encodings table.  Linear search is fine here, there
3186 	** are only a few entries.
3187 	*/
3188 	for ( i = 0; i < n_enc_tab; ++i )
3189 	    {
3190 	    if ( ext_len == enc_tab[i].ext_len && strncasecmp( ext, enc_tab[i].ext, ext_len ) == 0 )
3191 		{
3192 		if ( n_me_indexes < sizeof(me_indexes)/sizeof(*me_indexes) )
3193 		    {
3194 		    me_indexes[n_me_indexes] = i;
3195 		    ++n_me_indexes;
3196 		    }
3197 		goto next;
3198 		}
3199 	    }
3200 	/* No encoding extension found.  Break and look for a type extension. */
3201 	break;
3202 
3203 	next: ;
3204 	}
3205 
3206     /* Binary search for a matching type extension. */
3207     top = n_typ_tab - 1;
3208     bot = 0;
3209     while ( top >= bot )
3210 	{
3211 	mid = ( top + bot ) / 2;
3212 	r = strncasecmp( ext, typ_tab[mid].ext, ext_len );
3213 	if ( r < 0 )
3214 	    top = mid - 1;
3215 	else if ( r > 0 )
3216 	    bot = mid + 1;
3217 	else
3218 	    if ( ext_len < typ_tab[mid].ext_len )
3219 		top = mid - 1;
3220 	    else if ( ext_len > typ_tab[mid].ext_len )
3221 		bot = mid + 1;
3222 	    else
3223 		{
3224 		type = typ_tab[mid].val;
3225 		goto done;
3226 		}
3227 	}
3228     type = default_type;
3229 
3230     done:
3231 
3232     /* The last thing we do is actually generate the mime-encoding header. */
3233     me[0] = '\0';
3234     me_len = 0;
3235     for ( i = n_me_indexes - 1; i >= 0; --i )
3236 	{
3237 	if ( me_len + enc_tab[me_indexes[i]].val_len + 1 < me_size )
3238 	    {
3239 	    if ( me[0] != '\0' )
3240 		{
3241 		(void) strcpy( &me[me_len], "," );
3242 		++me_len;
3243 		}
3244 	    (void) strcpy( &me[me_len], enc_tab[me_indexes[i]].val );
3245 	    me_len += enc_tab[me_indexes[i]].val_len;
3246 	    }
3247 	}
3248 
3249     return type;
3250     }
3251 
3252 
3253 static void
handle_sigterm(int sig)3254 handle_sigterm( int sig )
3255     {
3256     /* Don't need to set up the handler again, since it's a one-shot. */
3257 
3258     syslog( LOG_NOTICE, "exiting due to signal %d", sig );
3259     (void) fprintf( stderr, "%s: exiting due to signal %d\n", argv0, sig );
3260     closelog();
3261     exit( 1 );
3262     }
3263 
3264 
3265 /* SIGHUP says to re-open the log file. */
3266 static void
handle_sighup(int sig)3267 handle_sighup( int sig )
3268     {
3269     const int oerrno = errno;
3270 
3271 #ifndef HAVE_SIGSET
3272     /* Set up handler again. */
3273     (void) signal( SIGHUP, handle_sighup );
3274 #endif /* ! HAVE_SIGSET */
3275 
3276     /* Just set a flag that we got the signal. */
3277     got_hup = 1;
3278 
3279     /* Restore previous errno. */
3280     errno = oerrno;
3281     }
3282 
3283 
3284 static void
handle_sigchld(int sig)3285 handle_sigchld( int sig )
3286     {
3287     const int oerrno = errno;
3288     pid_t pid;
3289     int s;
3290 
3291 #ifndef HAVE_SIGSET
3292     /* Set up handler again. */
3293     (void) signal( SIGCHLD, handle_sigchld );
3294 #endif /* ! HAVE_SIGSET */
3295 
3296     /* Reap defunct children until there aren't any more. */
3297     for (;;)
3298 	{
3299 #ifdef HAVE_WAITPID
3300 	pid = waitpid( (pid_t) -1, &s, WNOHANG );
3301 #else /* HAVE_WAITPID */
3302 	pid = wait3( &s, WNOHANG, (struct rusage*) 0 );
3303 #endif /* HAVE_WAITPID */
3304 	if ( (int) pid == 0 )		/* none left */
3305 	    break;
3306 	if ( (int) pid < 0 )
3307 	    {
3308 	    if ( errno == EINTR || errno == EAGAIN )
3309 		continue;
3310 	    /* ECHILD shouldn't happen with the WNOHANG option,
3311 	    ** but with some kernels it does anyway.  Ignore it.
3312 	    */
3313 	    if ( errno != ECHILD )
3314 		{
3315 		syslog( LOG_ERR, "child wait - %m" );
3316 		perror( "child wait" );
3317 		}
3318 	    break;
3319 	    }
3320 	}
3321 
3322     /* Restore previous errno. */
3323     errno = oerrno;
3324     }
3325 
3326 
3327 static void
re_open_logfile(void)3328 re_open_logfile( void )
3329     {
3330     if ( logfp != (FILE*) 0 )
3331 	{
3332 	(void) fclose( logfp );
3333 	logfp = (FILE*) 0;
3334 	}
3335     if ( logfile != (char*) 0 )
3336 	{
3337 	syslog( LOG_NOTICE, "re-opening logfile" );
3338 	logfp = fopen( logfile, "a" );
3339 	if ( logfp == (FILE*) 0 )
3340 	    {
3341 	    syslog( LOG_CRIT, "%s - %m", logfile );
3342 	    perror( logfile );
3343 	    exit( 1 );
3344 	    }
3345 	}
3346     }
3347 
3348 
3349 static void
handle_read_timeout(int sig)3350 handle_read_timeout( int sig )
3351     {
3352     syslog( LOG_INFO, "%.80s connection timed out reading", ntoa( &client_addr ) );
3353     send_error(
3354 	408, "Request Timeout", "",
3355 	"No request appeared within a reasonable time period." );
3356     }
3357 
3358 
3359 static void
handle_write_timeout(int sig)3360 handle_write_timeout( int sig )
3361     {
3362     syslog( LOG_INFO, "%.80s connection timed out writing", ntoa( &client_addr ) );
3363     finish_request( 1 );
3364     }
3365 
3366 
3367 
3368 static void
lookup_hostname(usockaddr * usa4P,size_t sa4_len,int * gotv4P,usockaddr * usa6P,size_t sa6_len,int * gotv6P)3369 lookup_hostname( usockaddr* usa4P, size_t sa4_len, int* gotv4P, usockaddr* usa6P, size_t sa6_len, int* gotv6P )
3370     {
3371 #ifdef USE_IPV6
3372 
3373     struct addrinfo hints;
3374     char portstr[10];
3375     int gaierr;
3376     struct addrinfo* ai;
3377     struct addrinfo* ai2;
3378     struct addrinfo* aiv6;
3379     struct addrinfo* aiv4;
3380 
3381     (void) memset( &hints, 0, sizeof(hints) );
3382     hints.ai_family = PF_UNSPEC;
3383     hints.ai_flags = AI_PASSIVE;
3384     hints.ai_socktype = SOCK_STREAM;
3385     (void) snprintf( portstr, sizeof(portstr), "%d", (int) port );
3386     if ( (gaierr = getaddrinfo( hostname, portstr, &hints, &ai )) != 0 )
3387 	{
3388 	syslog(
3389 	    LOG_CRIT, "getaddrinfo %.80s - %s", hostname,
3390 	    gai_strerror( gaierr ) );
3391 	(void) fprintf(
3392 	    stderr, "%s: getaddrinfo %.80s - %s\n", argv0, hostname,
3393 	    gai_strerror( gaierr ) );
3394 	exit( 1 );
3395 	}
3396 
3397     /* Find the first IPv6 and IPv4 entries. */
3398     aiv6 = (struct addrinfo*) 0;
3399     aiv4 = (struct addrinfo*) 0;
3400     for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next )
3401 	{
3402 	switch ( ai2->ai_family )
3403 	    {
3404 	    case AF_INET6:
3405 	    if ( aiv6 == (struct addrinfo*) 0 )
3406 		aiv6 = ai2;
3407 	    break;
3408 	    case AF_INET:
3409 	    if ( aiv4 == (struct addrinfo*) 0 )
3410 		aiv4 = ai2;
3411 	    break;
3412 	    }
3413 	}
3414 
3415     if ( aiv6 == (struct addrinfo*) 0 )
3416 	*gotv6P = 0;
3417     else
3418 	{
3419 	if ( sa6_len < aiv6->ai_addrlen )
3420 	    {
3421 	    syslog(
3422 		LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)",
3423 		hostname, (unsigned long) sa6_len,
3424 		(unsigned long) aiv6->ai_addrlen );
3425 	    (void) fprintf(
3426 		stderr, "%s: %.80s - sockaddr too small (%lu < %lu)\n",
3427 		argv0, hostname, (unsigned long) sa6_len,
3428 		(unsigned long) aiv6->ai_addrlen );
3429 	    exit( 1 );
3430 	    }
3431 	(void) memset( usa6P, 0, sa6_len );
3432 	(void) memmove( usa6P, aiv6->ai_addr, aiv6->ai_addrlen );
3433 	*gotv6P = 1;
3434 	}
3435 
3436     if ( aiv4 == (struct addrinfo*) 0 )
3437 	*gotv4P = 0;
3438     else
3439 	{
3440 	if ( sa4_len < aiv4->ai_addrlen )
3441 	    {
3442 	    syslog(
3443 		LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)",
3444 		hostname, (unsigned long) sa4_len,
3445 		(unsigned long) aiv4->ai_addrlen );
3446 	    (void) fprintf(
3447 		stderr, "%s: %.80s - sockaddr too small (%lu < %lu)\n",
3448 		argv0, hostname, (unsigned long) sa4_len,
3449 		(unsigned long) aiv4->ai_addrlen );
3450 	    exit( 1 );
3451 	    }
3452 	(void) memset( usa4P, 0, sa4_len );
3453 	(void) memmove( usa4P, aiv4->ai_addr, aiv4->ai_addrlen );
3454 	*gotv4P = 1;
3455 	}
3456 
3457     freeaddrinfo( ai );
3458 
3459 #else /* USE_IPV6 */
3460 
3461     struct hostent* he;
3462 
3463     *gotv6P = 0;
3464 
3465     (void) memset( usa4P, 0, sa4_len );
3466     usa4P->sa.sa_family = AF_INET;
3467     if ( hostname == (char*) 0 )
3468 	usa4P->sa_in.sin_addr.s_addr = htonl( INADDR_ANY );
3469     else
3470 	{
3471 	usa4P->sa_in.sin_addr.s_addr = inet_addr( hostname );
3472 	if ( (int) usa4P->sa_in.sin_addr.s_addr == -1 )
3473 	    {
3474 	    he = gethostbyname( hostname );
3475 	    if ( he == (struct hostent*) 0 )
3476 		{
3477 #ifdef HAVE_HSTRERROR
3478 		syslog(
3479 		    LOG_CRIT, "gethostbyname %.80s - %s", hostname,
3480 		    hstrerror( h_errno ) );
3481 		(void) fprintf(
3482 		    stderr, "%s: gethostbyname %.80s - %s\n", argv0, hostname,
3483 		    hstrerror( h_errno ) );
3484 #else /* HAVE_HSTRERROR */
3485 		syslog( LOG_CRIT, "gethostbyname %.80s failed", hostname );
3486 		(void) fprintf(
3487 		    stderr, "%s: gethostbyname %.80s failed\n", argv0,
3488 		    hostname );
3489 #endif /* HAVE_HSTRERROR */
3490 		exit( 1 );
3491 		}
3492 	    if ( he->h_addrtype != AF_INET )
3493 		{
3494 		syslog( LOG_CRIT, "%.80s - non-IP network address", hostname );
3495 		(void) fprintf(
3496 		    stderr, "%s: %.80s - non-IP network address\n", argv0,
3497 		    hostname );
3498 		exit( 1 );
3499 		}
3500 	    (void) memmove(
3501 		&usa4P->sa_in.sin_addr.s_addr, he->h_addr, he->h_length );
3502 	    }
3503 	}
3504     usa4P->sa_in.sin_port = htons( port );
3505     *gotv4P = 1;
3506 
3507 #endif /* USE_IPV6 */
3508     }
3509 
3510 
3511 static char*
ntoa(usockaddr * usaP)3512 ntoa( usockaddr* usaP )
3513     {
3514 #ifdef USE_IPV6
3515     static char str[200];
3516 
3517     if ( getnameinfo( &usaP->sa, sockaddr_len( usaP ), str, sizeof(str), 0, 0, NI_NUMERICHOST ) != 0 )
3518 	{
3519 	str[0] = '?';
3520 	str[1] = '\0';
3521 	}
3522     else if ( IN6_IS_ADDR_V4MAPPED( &usaP->sa_in6.sin6_addr ) && strncmp( str, "::ffff:", 7 ) == 0 )
3523 	/* Elide IPv6ish prefix for IPv4 addresses. */
3524 	(void) ol_strcpy( str, &str[7] );
3525 
3526     return str;
3527 
3528 #else /* USE_IPV6 */
3529 
3530     return inet_ntoa( usaP->sa_in.sin_addr );
3531 
3532 #endif /* USE_IPV6 */
3533     }
3534 
3535 
3536 static int
sockaddr_check(usockaddr * usaP)3537 sockaddr_check( usockaddr* usaP )
3538     {
3539     switch ( usaP->sa.sa_family )
3540 	{
3541 	case AF_INET: return 1;
3542 #ifdef USE_IPV6
3543 	case AF_INET6: return 1;
3544 #endif /* USE_IPV6 */
3545 	default:
3546 	return 0;
3547 	}
3548     }
3549 
3550 
3551 static size_t
sockaddr_len(usockaddr * usaP)3552 sockaddr_len( usockaddr* usaP )
3553     {
3554     switch ( usaP->sa.sa_family )
3555 	{
3556 	case AF_INET: return sizeof(struct sockaddr_in);
3557 #ifdef USE_IPV6
3558 	case AF_INET6: return sizeof(struct sockaddr_in6);
3559 #endif /* USE_IPV6 */
3560 	default:
3561 	return 0;	/* shouldn't happen */
3562 	}
3563     }
3564 
3565 
3566 /* Copies and decodes a string.  It's ok for from and to to be the
3567 ** same string.
3568 */
3569 static void
strdecode(char * to,char * from)3570 strdecode( char* to, char* from )
3571     {
3572     for ( ; *from != '\0'; ++to, ++from )
3573 	{
3574 	if ( from[0] == '%' && isxdigit( from[1] ) && isxdigit( from[2] ) )
3575 	    {
3576 	    *to = hexit( from[1] ) * 16 + hexit( from[2] );
3577 	    from += 2;
3578 	    }
3579 	else
3580 	    *to = *from;
3581 	}
3582     *to = '\0';
3583     }
3584 
3585 
3586 static int
hexit(char c)3587 hexit( char c )
3588     {
3589     if ( c >= '0' && c <= '9' )
3590 	return c - '0';
3591     if ( c >= 'a' && c <= 'f' )
3592 	return c - 'a' + 10;
3593     if ( c >= 'A' && c <= 'F' )
3594 	return c - 'A' + 10;
3595     return 0;           /* shouldn't happen, we're guarded by isxdigit() */
3596     }
3597 
3598 
3599 /* Base-64 decoding.  This represents binary data as printable ASCII
3600 ** characters.  Three 8-bit binary bytes are turned into four 6-bit
3601 ** values, like so:
3602 **
3603 **   [11111111]  [22222222]  [33333333]
3604 **
3605 **   [111111] [112222] [222233] [333333]
3606 **
3607 ** Then the 6-bit values are represented using the characters "A-Za-z0-9+/".
3608 */
3609 
3610 static int b64_decode_table[256] = {
3611     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
3612     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
3613     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
3614     52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
3615     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
3616     15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
3617     -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
3618     41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
3619     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
3620     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
3621     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
3622     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
3623     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
3624     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
3625     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
3626     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
3627     };
3628 
3629 /* Do base-64 decoding on a string.  Ignore any non-base64 bytes.
3630 ** Return the actual number of bytes generated.  The decoded size will
3631 ** be at most 3/4 the size of the encoded, and may be smaller if there
3632 ** are padding characters (blanks, newlines).
3633 */
3634 static int
b64_decode(const char * str,unsigned char * space,int size)3635 b64_decode( const char* str, unsigned char* space, int size )
3636     {
3637     const char* cp;
3638     int space_idx, phase;
3639     int d, prev_d = 0;
3640     unsigned char c;
3641 
3642     space_idx = 0;
3643     phase = 0;
3644     for ( cp = str; *cp != '\0'; ++cp )
3645 	{
3646 	d = b64_decode_table[(int) ((unsigned char) *cp)];
3647 	if ( d != -1 )
3648 	    {
3649 	    switch ( phase )
3650 		{
3651 		case 0:
3652 		++phase;
3653 		break;
3654 		case 1:
3655 		c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) );
3656 		if ( space_idx < size )
3657 		    space[space_idx++] = c;
3658 		++phase;
3659 		break;
3660 		case 2:
3661 		c = ( ( ( prev_d & 0xf ) << 4 ) | ( ( d & 0x3c ) >> 2 ) );
3662 		if ( space_idx < size )
3663 		    space[space_idx++] = c;
3664 		++phase;
3665 		break;
3666 		case 3:
3667 		c = ( ( ( prev_d & 0x03 ) << 6 ) | d );
3668 		if ( space_idx < size )
3669 		    space[space_idx++] = c;
3670 		phase = 0;
3671 		break;
3672 		}
3673 	    prev_d = d;
3674 	    }
3675 	}
3676     return space_idx;
3677     }
3678 
3679 
3680 /* Set NDELAY mode on a socket. */
3681 static void
set_ndelay(int fd)3682 set_ndelay( int fd )
3683     {
3684     int flags, newflags;
3685 
3686     flags = fcntl( fd, F_GETFL, 0 );
3687     if ( flags != -1 )
3688 	{
3689 	newflags = flags | (int) O_NDELAY;
3690 	if ( newflags != flags )
3691 	    (void) fcntl( fd, F_SETFL, newflags );
3692 	}
3693     }
3694 
3695 
3696 /* Clear NDELAY mode on a socket. */
3697 static void
clear_ndelay(int fd)3698 clear_ndelay( int fd )
3699     {
3700     int flags, newflags;
3701 
3702     flags = fcntl( fd, F_GETFL, 0 );
3703     if ( flags != -1 )
3704 	{
3705 	newflags = flags & ~ (int) O_NDELAY;
3706 	if ( newflags != flags )
3707 	    (void) fcntl( fd, F_SETFL, newflags );
3708 	}
3709     }
3710 
3711 
3712 static void*
e_malloc(size_t size)3713 e_malloc( size_t size )
3714     {
3715     void* ptr;
3716 
3717     ptr = malloc( size );
3718     if ( ptr == (void*) 0 )
3719 	{
3720 	syslog( LOG_CRIT, "out of memory" );
3721 	(void) fprintf( stderr, "%s: out of memory\n", argv0 );
3722 	exit( 1 );
3723 	}
3724     return ptr;
3725     }
3726 
3727 
3728 static void*
e_realloc(void * optr,size_t size)3729 e_realloc( void* optr, size_t size )
3730     {
3731     void* ptr;
3732 
3733     ptr = realloc( optr, size );
3734     if ( ptr == (void*) 0 )
3735 	{
3736 	syslog( LOG_CRIT, "out of memory" );
3737 	(void) fprintf( stderr, "%s: out of memory\n", argv0 );
3738 	exit( 1 );
3739 	}
3740     return ptr;
3741     }
3742 
3743 
3744 static char*
e_strdup(char * ostr)3745 e_strdup( char* ostr )
3746     {
3747     char* str;
3748 
3749     str = strdup( ostr );
3750     if ( str == (char*) 0 )
3751 	{
3752 	syslog( LOG_CRIT, "out of memory copying a string" );
3753 	(void) fprintf( stderr, "%s: out of memory copying a string\n", argv0 );
3754 	exit( 1 );
3755 	}
3756     return str;
3757     }
3758 
3759 
3760 #ifdef NO_SNPRINTF
3761 /* Some systems don't have snprintf(), so we make our own that uses
3762 ** vsprintf().  This workaround is probably vulnerable to buffer overruns,
3763 ** so upgrade your OS!
3764 */
3765 static int
snprintf(char * str,size_t size,const char * format,...)3766 snprintf( char* str, size_t size, const char* format, ... )
3767     {
3768     va_list ap;
3769     int r;
3770 
3771     va_start( ap, format );
3772     r = vsprintf( str, format, ap );
3773     va_end( ap );
3774     return r;
3775     }
3776 #endif /* NO_SNPRINTF */
3777