… | |
… | |
155 | static char** make_envp( httpd_conn* hc ); |
155 | static char** make_envp( httpd_conn* hc ); |
156 | static char** make_argp( httpd_conn* hc ); |
156 | static char** make_argp( httpd_conn* hc ); |
157 | static void cgi_interpose_input( httpd_conn* hc, int wfd ); |
157 | static void cgi_interpose_input( httpd_conn* hc, int wfd ); |
158 | static void post_post_garbage_hack( httpd_conn* hc ); |
158 | static void post_post_garbage_hack( httpd_conn* hc ); |
159 | static void cgi_interpose_output( httpd_conn* hc, int rfd ); |
159 | static void cgi_interpose_output( httpd_conn* hc, int rfd ); |
160 | static void cgi_child( httpd_conn* hc ); |
160 | static void cgi_child( httpd_conn* hc, char* exefilename ); |
161 | static off_t cgi( httpd_conn* hc ); |
161 | static off_t cgi( httpd_conn* hc, char* exefilename ); |
162 | static int really_start_request( httpd_conn* hc, struct timeval* nowP ); |
162 | static int really_start_request( httpd_conn* hc, struct timeval* nowP ); |
163 | static void make_log_entry( httpd_conn* hc, struct timeval* nowP ); |
163 | static void make_log_entry( httpd_conn* hc, struct timeval* nowP ); |
164 | static int check_referer( httpd_conn* hc ); |
164 | static int check_referer( httpd_conn* hc ); |
165 | static int really_check_referer( httpd_conn* hc ); |
165 | static int really_check_referer( httpd_conn* hc ); |
166 | static int sockaddr_check( httpd_sockaddr* saP ); |
166 | static int sockaddr_check( httpd_sockaddr* saP ); |
… | |
… | |
238 | { |
238 | { |
239 | if ( hs->binding_hostname != (char*) 0 ) |
239 | if ( hs->binding_hostname != (char*) 0 ) |
240 | free( (void*) hs->binding_hostname ); |
240 | free( (void*) hs->binding_hostname ); |
241 | if ( hs->cwd != (char*) 0 ) |
241 | if ( hs->cwd != (char*) 0 ) |
242 | free( (void*) hs->cwd ); |
242 | free( (void*) hs->cwd ); |
|
|
243 | if ( hs->autoindex_prog != (char*) 0 ) |
|
|
244 | free( (void*) hs->autoindex_prog ); |
243 | if ( hs->cgi_pattern != (char*) 0 ) |
245 | if ( hs->cgi_pattern != (char*) 0 ) |
244 | free( (void*) hs->cgi_pattern ); |
246 | free( (void*) hs->cgi_pattern ); |
245 | if ( hs->charset != (char*) 0 ) |
247 | if ( hs->charset != (char*) 0 ) |
246 | free( (void*) hs->charset ); |
248 | free( (void*) hs->charset ); |
247 | if ( hs->url_pattern != (char*) 0 ) |
249 | if ( hs->url_pattern != (char*) 0 ) |
… | |
… | |
255 | httpd_server* |
257 | httpd_server* |
256 | httpd_initialize( |
258 | httpd_initialize( |
257 | char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P, int port, |
259 | char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P, int port, |
258 | char* cgi_pattern, char* charset, char* cwd, int no_log, FILE* logfp, |
260 | char* cgi_pattern, char* charset, char* cwd, int no_log, FILE* logfp, |
259 | int no_symlink, int vhost, int global_passwd, char* url_pattern, |
261 | int no_symlink, int vhost, int global_passwd, char* url_pattern, |
260 | char* local_pattern, int no_empty_referers ) |
262 | char* local_pattern, int no_empty_referers, |
|
|
263 | char* autoindex_prog) |
261 | { |
264 | { |
262 | httpd_server* hs; |
265 | httpd_server* hs; |
263 | static char ghnbuf[256]; |
266 | static char ghnbuf[256]; |
264 | char* cp; |
267 | char* cp; |
265 | |
268 | |
… | |
… | |
327 | } |
330 | } |
328 | /* Nuke any leading slashes in the cgi pattern. */ |
331 | /* Nuke any leading slashes in the cgi pattern. */ |
329 | while ( ( cp = strstr( hs->cgi_pattern, "|/" ) ) != (char*) 0 ) |
332 | while ( ( cp = strstr( hs->cgi_pattern, "|/" ) ) != (char*) 0 ) |
330 | (void) strcpy( cp + 1, cp + 2 ); |
333 | (void) strcpy( cp + 1, cp + 2 ); |
331 | } |
334 | } |
|
|
335 | hs->autoindex_prog = autoindex_prog ? strdup( autoindex_prog ) : 0; |
332 | hs->charset = strdup( charset ); |
336 | hs->charset = strdup( charset ); |
333 | hs->cwd = strdup( cwd ); |
337 | hs->cwd = strdup( cwd ); |
334 | if ( hs->cwd == (char*) 0 ) |
338 | if ( hs->cwd == (char*) 0 ) |
335 | { |
339 | { |
336 | syslog( LOG_CRIT, "out of memory copying cwd" ); |
340 | syslog( LOG_CRIT, "out of memory copying cwd" ); |
… | |
… | |
823 | } |
827 | } |
824 | |
828 | |
825 | void |
829 | void |
826 | httpd_send_err_blocked( httpd_conn* hc ) |
830 | httpd_send_err_blocked( httpd_conn* hc ) |
827 | { |
831 | { |
|
|
832 | char *protocol = hc->protocol; |
|
|
833 | |
828 | #ifdef ERR_DIR |
834 | #ifdef ERR_DIR |
829 | |
|
|
830 | char filename[1000]; |
835 | char filename[1000]; |
|
|
836 | #endif |
831 | |
837 | |
|
|
838 | hc->protocol = "HTTP/1.0"; |
|
|
839 | |
|
|
840 | #ifdef ERR_DIR |
832 | /* Try virtual host error page. */ |
841 | /* Try virtual host error page. */ |
833 | if ( hc->hs->vhost && hc->hostdir[0] != '\0' ) |
842 | if ( hc->hs->vhost && hc->hostdir[0] != '\0' ) |
834 | { |
843 | { |
835 | (void) my_snprintf( filename, sizeof(filename), |
844 | (void) my_snprintf( filename, sizeof(filename), |
836 | "%s/%s/err403blocked.html", hc->hostdir, ERR_DIR ); |
845 | "%s/%s/err403blocked.html", hc->hostdir, ERR_DIR ); |
… | |
… | |
850 | #else /* ERR_DIR */ |
859 | #else /* ERR_DIR */ |
851 | |
860 | |
852 | send_response( hc, 403, err403title, "", err403form, "" ); |
861 | send_response( hc, 403, err403title, "", err403form, "" ); |
853 | |
862 | |
854 | #endif /* ERR_DIR */ |
863 | #endif /* ERR_DIR */ |
|
|
864 | hc->protocol = protocol; |
855 | } |
865 | } |
856 | |
866 | |
857 | #ifdef ERR_DIR |
867 | #ifdef ERR_DIR |
858 | static int |
868 | static int |
859 | send_err_file( httpd_conn* hc, int status, char* title, char* extraheads, char* filename ) |
869 | send_err_file( httpd_conn* hc, int status, char* title, char* extraheads, char* filename ) |
… | |
… | |
1465 | checked[0] = '\0'; |
1475 | checked[0] = '\0'; |
1466 | checkedlen = 0; |
1476 | checkedlen = 0; |
1467 | restlen = strlen( path ); |
1477 | restlen = strlen( path ); |
1468 | httpd_realloc_str( &rest, &maxrest, restlen ); |
1478 | httpd_realloc_str( &rest, &maxrest, restlen ); |
1469 | (void) strcpy( rest, path ); |
1479 | (void) strcpy( rest, path ); |
1470 | if ( rest[restlen - 1] == '/' ) |
|
|
1471 | rest[--restlen] = '\0'; /* trim trailing slash */ |
|
|
1472 | if ( ! tildemapped ) |
1480 | if ( ! tildemapped ) |
1473 | /* Remove any leading slashes. */ |
1481 | /* Remove any leading slashes. */ |
1474 | while ( rest[0] == '/' ) |
1482 | while ( rest[0] == '/' ) |
1475 | { |
1483 | { |
1476 | (void) strcpy( rest, &(rest[1]) ); |
1484 | (void) strcpy( rest, &(rest[1]) ); |
… | |
… | |
1732 | hc->init_byte_loc = 0; |
1740 | hc->init_byte_loc = 0; |
1733 | hc->end_byte_loc = -1; |
1741 | hc->end_byte_loc = -1; |
1734 | hc->keep_alive = 0; |
1742 | hc->keep_alive = 0; |
1735 | hc->should_linger = 0; |
1743 | hc->should_linger = 0; |
1736 | hc->file_address = (char*) 0; |
1744 | hc->file_address = (char*) 0; |
|
|
1745 | #ifdef MMAP_MAX |
|
|
1746 | hc->file_fd = -1; |
|
|
1747 | hc->write_buf = (char*) 0; |
|
|
1748 | #endif |
1737 | return GC_OK; |
1749 | return GC_OK; |
1738 | } |
1750 | } |
1739 | |
1751 | |
1740 | |
1752 | |
1741 | /* Checks hc->read_buf to see whether a complete request has been read so far; |
1753 | /* Checks hc->read_buf to see whether a complete request has been read so far; |
… | |
… | |
2382 | void |
2394 | void |
2383 | httpd_close_conn( httpd_conn* hc, struct timeval* nowP ) |
2395 | httpd_close_conn( httpd_conn* hc, struct timeval* nowP ) |
2384 | { |
2396 | { |
2385 | make_log_entry( hc, nowP ); |
2397 | make_log_entry( hc, nowP ); |
2386 | |
2398 | |
|
|
2399 | #ifdef MMAP_MAX |
|
|
2400 | if ( hc->file_fd >= 0) |
|
|
2401 | { |
|
|
2402 | (void) close( hc->file_fd ); |
|
|
2403 | hc->file_fd = -1; |
|
|
2404 | } |
|
|
2405 | if ( hc->write_buf ) |
|
|
2406 | { |
|
|
2407 | (void) free (hc->write_buf); |
|
|
2408 | hc->write_buf = 0; |
|
|
2409 | } |
|
|
2410 | #endif |
2387 | if ( hc->file_address != (char*) 0 ) |
2411 | if ( hc->file_address != (char*) 0 ) |
2388 | { |
2412 | { |
2389 | mmc_unmap( hc->file_address, &(hc->sb), nowP ); |
2413 | mmc_unmap( hc->file_address, &(hc->sb), nowP ); |
2390 | hc->file_address = (char*) 0; |
2414 | hc->file_address = (char*) 0; |
2391 | } |
2415 | } |
… | |
… | |
2790 | exit( 0 ); |
2814 | exit( 0 ); |
2791 | } |
2815 | } |
2792 | |
2816 | |
2793 | /* Parent process. */ |
2817 | /* Parent process. */ |
2794 | closedir( dirp ); |
2818 | closedir( dirp ); |
2795 | syslog( LOG_INFO, "spawned indexing process %d for directory '%.200s'", r, hc->expnfilename ); |
2819 | /*syslog( LOG_INFO, "spawned indexing process %d for directory '%.200s'", r, hc->expnfilename );*/ |
2796 | #ifdef CGI_TIMELIMIT |
2820 | #ifdef CGI_TIMELIMIT |
2797 | /* Schedule a kill for the child process, in case it runs too long */ |
2821 | /* Schedule a kill for the child process, in case it runs too long */ |
2798 | client_data.i = r; |
2822 | client_data.i = r; |
2799 | if ( tmr_create( (struct timeval*) 0, cgi_kill, client_data, CGI_TIMELIMIT * 1000L, 0 ) == (Timer*) 0 ) |
2823 | if ( tmr_create( (struct timeval*) 0, cgi_kill, client_data, CGI_TIMELIMIT * 1000L, 0 ) == (Timer*) 0 ) |
2800 | { |
2824 | { |
… | |
… | |
3156 | } |
3180 | } |
3157 | |
3181 | |
3158 | |
3182 | |
3159 | /* CGI child process. */ |
3183 | /* CGI child process. */ |
3160 | static void |
3184 | static void |
3161 | cgi_child( httpd_conn* hc ) |
3185 | cgi_child( httpd_conn* hc, char* exefilename ) |
3162 | { |
3186 | { |
3163 | int r; |
3187 | int r; |
3164 | char** argp; |
3188 | char** argp; |
3165 | char** envp; |
3189 | char** envp; |
3166 | char* binary; |
3190 | char* binary; |
… | |
… | |
3308 | |
3332 | |
3309 | /* Split the program into directory and binary, so we can chdir() |
3333 | /* Split the program into directory and binary, so we can chdir() |
3310 | ** to the program's own directory. This isn't in the CGI 1.1 |
3334 | ** to the program's own directory. This isn't in the CGI 1.1 |
3311 | ** spec, but it's what other HTTP servers do. |
3335 | ** spec, but it's what other HTTP servers do. |
3312 | */ |
3336 | */ |
3313 | directory = strdup( hc->expnfilename ); |
3337 | if (exefilename) |
3314 | if ( directory == (char*) 0 ) |
3338 | binary = exefilename; |
3315 | binary = hc->expnfilename; /* ignore errors */ |
|
|
3316 | else |
3339 | else |
3317 | { |
3340 | { |
|
|
3341 | directory = strdup( exefilename ? exefilename : hc->expnfilename ); |
|
|
3342 | if ( directory == (char*) 0 ) |
|
|
3343 | binary = exefilename; /* ignore errors */ |
|
|
3344 | else |
|
|
3345 | { |
3318 | binary = strrchr( directory, '/' ); |
3346 | binary = strrchr( directory, '/' ); |
3319 | if ( binary == (char*) 0 ) |
3347 | if ( binary == (char*) 0 ) |
3320 | binary = hc->expnfilename; |
3348 | binary = exefilename; |
3321 | else |
3349 | else |
3322 | { |
3350 | { |
3323 | *binary++ = '\0'; |
3351 | *binary++ = '\0'; |
3324 | (void) chdir( directory ); /* ignore errors */ |
3352 | (void) chdir( directory ); /* ignore errors */ |
|
|
3353 | } |
|
|
3354 | } |
3325 | } |
3355 | } |
3326 | } |
|
|
3327 | |
3356 | |
3328 | /* Default behavior for SIGPIPE. */ |
3357 | /* Default behavior for SIGPIPE. */ |
3329 | (void) signal( SIGPIPE, SIG_DFL ); |
3358 | (void) signal( SIGPIPE, SIG_DFL ); |
3330 | |
3359 | |
3331 | /* Run the program. */ |
3360 | /* Run the program. */ |
… | |
… | |
3337 | exit( 1 ); |
3366 | exit( 1 ); |
3338 | } |
3367 | } |
3339 | |
3368 | |
3340 | |
3369 | |
3341 | static off_t |
3370 | static off_t |
3342 | cgi( httpd_conn* hc ) |
3371 | cgi( httpd_conn* hc, char* exefilename ) |
3343 | { |
3372 | { |
3344 | int r; |
3373 | int r; |
3345 | ClientData client_data; |
3374 | ClientData client_data; |
3346 | |
3375 | |
3347 | if ( hc->method == METHOD_GET || hc->method == METHOD_POST ) |
3376 | if ( hc->method == METHOD_GET || hc->method == METHOD_POST ) |
… | |
… | |
3355 | return -1; |
3384 | return -1; |
3356 | } |
3385 | } |
3357 | if ( r == 0 ) |
3386 | if ( r == 0 ) |
3358 | { |
3387 | { |
3359 | unlisten( hc->hs ); |
3388 | unlisten( hc->hs ); |
3360 | cgi_child( hc ); |
3389 | cgi_child( hc, exefilename ); |
3361 | } |
3390 | } |
3362 | |
3391 | |
3363 | /* Parent process. */ |
3392 | /* Parent process. */ |
3364 | syslog( LOG_INFO, "spawned CGI process %d for file '%.200s'", r, hc->expnfilename ); |
3393 | /*syslog( LOG_INFO, "spawned CGI process %d for file '%.200s'", r, hc->expnfilename );*/ |
3365 | #ifdef CGI_TIMELIMIT |
3394 | #ifdef CGI_TIMELIMIT |
3366 | /* Schedule a kill for the child process, in case it runs too long */ |
3395 | /* Schedule a kill for the child process, in case it runs too long */ |
3367 | client_data.i = r; |
3396 | client_data.i = r; |
3368 | if ( tmr_create( (struct timeval*) 0, cgi_kill, client_data, CGI_TIMELIMIT * 1000L, 0 ) == (Timer*) 0 ) |
3397 | if ( tmr_create( (struct timeval*) 0, cgi_kill, client_data, CGI_TIMELIMIT * 1000L, 0 ) == (Timer*) 0 ) |
3369 | { |
3398 | { |
… | |
… | |
3495 | #endif /* AUTH_FILE */ |
3524 | #endif /* AUTH_FILE */ |
3496 | /* Referer check. */ |
3525 | /* Referer check. */ |
3497 | if ( ! check_referer( hc ) ) |
3526 | if ( ! check_referer( hc ) ) |
3498 | return -1; |
3527 | return -1; |
3499 | /* Ok, generate an index. */ |
3528 | /* Ok, generate an index. */ |
3500 | return ls( hc ); |
3529 | return hc->hs->autoindex_prog ? cgi( hc, hc->hs->autoindex_prog) : ls( hc ); |
3501 | #else /* GENERATE_INDEXES */ |
3530 | #else /* GENERATE_INDEXES */ |
3502 | syslog( |
3531 | syslog( |
3503 | LOG_INFO, "%.80s URL \"%.80s\" tried to index a directory", |
3532 | LOG_INFO, "%.80s URL \"%.80s\" tried to index a directory", |
3504 | httpd_ntoa( &hc->client_addr ), hc->encodedurl ); |
3533 | httpd_ntoa( &hc->client_addr ), hc->encodedurl ); |
3505 | httpd_send_err( |
3534 | httpd_send_err( |
… | |
… | |
3588 | |
3617 | |
3589 | /* Is it world-executable and in the CGI area? */ |
3618 | /* Is it world-executable and in the CGI area? */ |
3590 | if ( hc->hs->cgi_pattern != (char*) 0 && |
3619 | if ( hc->hs->cgi_pattern != (char*) 0 && |
3591 | ( hc->sb.st_mode & S_IXOTH ) && |
3620 | ( hc->sb.st_mode & S_IXOTH ) && |
3592 | match( hc->hs->cgi_pattern, hc->expnfilename ) ) |
3621 | match( hc->hs->cgi_pattern, hc->expnfilename ) ) |
3593 | return cgi( hc ); |
3622 | return cgi( hc, 0 ); |
3594 | |
3623 | |
3595 | /* It's not CGI. If it's executable or there's pathinfo, someone's |
3624 | /* It's not CGI. If it's executable or there's pathinfo, someone's |
3596 | ** trying to either serve or run a non-CGI file as CGI. Either case |
3625 | ** trying to either serve or run a non-CGI file as CGI. Either case |
3597 | ** is prohibited. |
3626 | ** is prohibited. |
3598 | */ |
3627 | */ |
… | |
… | |
3640 | hc, 304, err304title, hc->encodings, "", hc->type, hc->sb.st_size, |
3669 | hc, 304, err304title, hc->encodings, "", hc->type, hc->sb.st_size, |
3641 | hc->sb.st_mtime ); |
3670 | hc->sb.st_mtime ); |
3642 | } |
3671 | } |
3643 | else |
3672 | else |
3644 | { |
3673 | { |
|
|
3674 | #ifdef MMAP_MAX |
|
|
3675 | if ( hc->sb.st_size < MMAP_MAX) |
|
|
3676 | #endif |
3645 | hc->file_address = mmc_map( hc->expnfilename, &(hc->sb), nowP ); |
3677 | hc->file_address = mmc_map( hc->expnfilename, &(hc->sb), nowP ); |
3646 | if ( hc->file_address == (char*) 0 ) |
3678 | if ( hc->file_address == (char*) 0 ) |
3647 | { |
3679 | { |
|
|
3680 | #ifdef MMAP_MAX |
|
|
3681 | hc->file_fd = open ( hc->expnfilename, O_RDONLY); |
|
|
3682 | hc->write_buf = malloc (WRITE_BUFFER); |
|
|
3683 | hc->write_ofs = WRITE_BUFFER; |
|
|
3684 | if ( hc->file_fd < 0 || !hc->write_buf ) |
|
|
3685 | #endif |
|
|
3686 | { |
3648 | httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); |
3687 | httpd_send_err( hc, 500, err500title, "", err500form, hc->encodedurl ); |
3649 | return -1; |
3688 | return -1; |
|
|
3689 | } |
3650 | } |
3690 | } |
3651 | send_mime( |
3691 | send_mime( |
3652 | hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size, |
3692 | hc, 200, ok200title, hc->encodings, "", hc->type, hc->sb.st_size, |
3653 | hc->sb.st_mtime ); |
3693 | hc->sb.st_mtime ); |
3654 | } |
3694 | } |
… | |
… | |
3679 | |
3719 | |
3680 | if ( hc->hs->no_log ) |
3720 | if ( hc->hs->no_log ) |
3681 | return; |
3721 | return; |
3682 | |
3722 | |
3683 | /* don't log UNKNOWN protocol requests (blocks etc..) */ |
3723 | /* don't log UNKNOWN protocol requests (blocks etc..) */ |
3684 | if ( !strcmp (hc->protocol, "UNKNOWN") ) |
3724 | if ( hc->method == METHOD_UNKNOWN ) |
3685 | return; |
3725 | return; |
3686 | |
3726 | |
3687 | /* This is straight CERN Combined Log Format - the only tweak |
3727 | /* This is straight CERN Combined Log Format - the only tweak |
3688 | ** being that if we're using syslog() we leave out the date, because |
3728 | ** being that if we're using syslog() we leave out the date, because |
3689 | ** syslogd puts it in. The included syslogtocern script turns the |
3729 | ** syslogd puts it in. The included syslogtocern script turns the |