|
|
- /**
- * @PROJECT Kagera uHTTP Daemon
- * @COPYRIGHT See COPYING in the top level directory
- * @FILE kuhttpd.c
- * @PURPOSE HTTP Server
- * @DEVELOPERS Eric Bishop <eric@gargoyle-router.com>
- * Rafal Kupiec <belliash@asiotec.eu.org>
- * Jef Poskanzer <jef@acme.com>
- */
-
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <string.h>
- #include <syslog.h>
- #include <limits.h>
- #include <sys/param.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #include <time.h>
- #include <pwd.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <ctype.h>
- #include <sys/wait.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/tcp.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <dirent.h>
-
- #include <cyassl/openssl/ssl.h>
- #include <cyassl/openssl/err.h>
- #include <cyassl/error.h>
-
- #ifdef CROSS_BUILD
- #include <cyassl/cyassl_error.h>
- #endif
-
- #include "kuhttpd.h"
- #include "dateparse.h"
- #include "match.h"
- #include "mime_enc.h"
- #include "mime_typ.h"
-
- static void add_headers(int s, char* title, char* extra_header, char* me, char* mt, off_t b, time_t mod) {
- time_t now;
- char timebuf[100];
- char buf[10000];
- int buflen;
- const char* rfc1123_fmt = "%a, %d %b %Y %H:%M:%S GMT";
-
- status = s;
- bytes = b;
- make_log_entry();
- start_response();
- buflen = snprintf(buf, sizeof(buf), "%s %d %s\015\012", protocol, status, title);
- add_to_response(buf, buflen);
- buflen = snprintf(buf, sizeof(buf), "Server: %s\015\012", SERVER_SOFTWARE);
- add_to_response(buf, buflen);
- now = time((time_t*) 0);
- (void) strftime(timebuf, sizeof(timebuf), rfc1123_fmt, gmtime(&now));
- buflen = snprintf(buf, sizeof(buf), "Date: %s\015\012", timebuf);
- add_to_response(buf, buflen);
- buflen = snprintf(buf, sizeof(buf), "Expires: %s\015\012", timebuf);
- add_to_response(buf, buflen);
- if(mod != (time_t) -1) {
- (void) strftime(timebuf, sizeof(timebuf), rfc1123_fmt, gmtime(&mod));
- buflen = snprintf(buf, sizeof(buf), "Last-Modified: %s\015\012", timebuf);
- add_to_response(buf, buflen);
- }
- if(extra_header != (char*) 0 && extra_header[0] != '\0') {
- buflen = snprintf(buf, sizeof(buf), "%s\015\012", extra_header);
- add_to_response(buf, buflen);
- }
- if(me != (char*) 0 && me[0] != '\0') {
- buflen = snprintf(buf, sizeof(buf), "Content-Encoding: %s\015\012", me);
- add_to_response(buf, buflen);
- }
- if(mt != (char*) 0 && mt[0] != '\0') {
- buflen = snprintf(buf, sizeof(buf), "Content-Type: %s\015\012", mt);
- add_to_response(buf, buflen);
- }
- if(bytes >= 0) {
- buflen = snprintf(buf, sizeof(buf), "Content-Length: %lld\015\012", (long long int) bytes);
- add_to_response(buf, buflen);
- }
- if(p3p != (char*) 0 && p3p[0] != '\0') {
- buflen = snprintf(buf, sizeof(buf), "P3P: %s\015\012", p3p);
- add_to_response(buf, buflen);
- }
- buflen = snprintf(buf, sizeof(buf), "\015\012");
- add_to_response(buf, buflen);
- }
-
- static void add_to_buf(char** bufP, size_t* bufsizeP, size_t* buflenP, char* str, size_t len) {
- if(*bufsizeP == 0) {
- *bufsizeP = len + 500;
- *buflenP = 0;
- *bufP = (char*) e_malloc(*bufsizeP);
- } else if(*buflenP + len >= *bufsizeP) {
- *bufsizeP = *buflenP + len + 500;
- *bufP = (char*) e_realloc((void*) *bufP, *bufsizeP);
- }
- (void) memmove(&((*bufP)[*buflenP]), str, len);
- *buflenP += len;
- (*bufP)[*buflenP] = '\0';
- }
-
- static void add_to_request(char* str, size_t len) {
- add_to_buf(&request, &request_size, &request_len, str, len);
- }
-
- static void add_to_response(char* str, size_t len) {
- add_to_buf(&response, &response_size, &response_len, str, len);
- }
-
- static void auth_check(char* dirname, int is_ssl) {
- char authpath[10000];
- char realmName[500];
- struct stat sb;
- char authinfo[500];
- char* authpass;
- char* colon;
- static char line[10000];
- int l;
- FILE* fp;
- char* cryp;
-
- if(dirname[strlen(dirname) - 1] == '/') {
- (void) snprintf(authpath, sizeof(authpath), "%s%s", dirname, AUTH_FILE);
- } else {
- (void) snprintf(authpath, sizeof(authpath), "%s/%s", dirname, AUTH_FILE);
- }
- if(stat(authpath, &sb) < 0) {
- if(defaultRealmName == NULL || defaultRealmPasswordFile == NULL) {
- return;
- } else {
- snprintf(authpath, sizeof(authpath), "%s", defaultRealmPasswordFile);
- }
- }
- if(strcmp(authpath, defaultRealmPasswordFile) == 0) {
- snprintf(realmName, sizeof(realmName), "%s", defaultRealmName);
- } else {
- snprintf(realmName, sizeof(realmName), "%s", dirname);
- }
- if(authorization == (char*) 0) {
- send_authenticate(realmName, is_ssl);
- }
- if(strncmp(authorization, "Basic ", 6) != 0) {
- send_authenticate(realmName, is_ssl);
- }
- l = b64_decode(&(authorization[6]), (unsigned char*) authinfo, sizeof(authinfo) - 1);
- authinfo[l] = '\0';
- authpass = strchr(authinfo, ':');
- if(authpass == (char*) 0) {
- send_authenticate(realmName, is_ssl);
- }
- *authpass++ = '\0';
- colon = strchr(authpass, ':');
- if(colon != (char*) 0) {
- *colon = '\0';
- }
- fp = fopen(authpath, "r");
- if(fp == (FILE*) 0) {
- syslog(LOG_ERR, "%.80s auth file %.80s could not be opened - %m", ntoa(&client_addr), authpath);
- send_error(403, "Forbidden", "", "File is protected.", is_ssl);
- }
- while(fgets(line, sizeof(line), fp) != (char*) 0) {
- l = strlen(line);
- if(line[l - 1] == '\n') {
- line[l - 1] = '\0';
- }
- cryp = strchr(line, ':');
- if(cryp == (char*) 0) {
- continue;
- }
- *cryp++ = '\0';
- if(strcmp(line, authinfo) == 0) {
- (void) fclose(fp);
- if(strcmp(crypt(authpass, cryp), cryp) == 0) {
- remoteuser = line;
- return;
- } else {
- send_authenticate(realmName, is_ssl);
- }
- }
- }
- (void) fclose(fp);
- send_authenticate(realmName, is_ssl);
- }
-
- static int b64_decode(const char* str, unsigned char* space, int size) {
- const char* cp;
- int space_idx, phase;
- int d, prev_d = 0;
- unsigned char c;
-
- space_idx = 0;
- phase = 0;
- for(cp = str; *cp != '\0'; ++cp) {
- d = b64_decode_table[(int) *cp];
- if(d != -1) {
- switch(phase) {
- case 0:
- ++phase;
- break;
- case 1:
- c = ((prev_d << 2) | ((d & 0x30) >> 4));
- if(space_idx < size) {
- space[space_idx++] = c;
- }
- ++phase;
- break;
- case 2:
- c = (((prev_d & 0xf) << 4) | ((d & 0x3c) >> 2));
- if(space_idx < size) {
- space[space_idx++] = c;
- }
- ++phase;
- break;
- case 3:
- c = (((prev_d & 0x03) << 6) | d);
- if(space_idx < size) {
- space[space_idx++] = c;
- }
- phase = 0;
- break;
- }
- prev_d = d;
- }
- }
- return space_idx;
- }
-
- static char* build_env(char* fmt, char* arg) {
- char* cp;
- int size;
- static char* buf;
- static int maxbuf = 0;
-
- size = strlen(fmt) + strlen(arg);
- if(size > maxbuf) {
- if(maxbuf == 0) {
- maxbuf = MAX(200, size + 100);
- buf = (char*) e_malloc(maxbuf);
- } else {
- maxbuf = MAX(maxbuf * 2, size * 5 / 4);
- buf = (char*) e_realloc((void*) buf, maxbuf);
- }
- }
- (void) snprintf(buf, maxbuf, fmt, arg);
- cp = e_strdup(buf);
- return cp;
- }
-
- static void cgi_interpose_input(int wfd, int is_ssl) {
- size_t c;
- ssize_t r, r2;
- char buf[1024];
-
- c = request_len - request_idx;
- if(c > 0) {
- if(write(wfd, &(request[request_idx]), c) != c) {
- return;
- }
- }
- while(c < content_length) {
- r = my_read(buf, MIN( sizeof(buf), content_length - c), is_ssl);
- if(r < 0 && (errno == EINTR || errno == EAGAIN)) {
- sleep(1);
- continue;
- }
- if(r <= 0) {
- return;
- }
- for(;;) {
- r2 = write(wfd, buf, r);
- if(r2 < 0 && (errno == EINTR || errno == EAGAIN)) {
- sleep(1);
- continue;
- }
- if(r2 != r) {
- return;
- }
- break;
- }
- c += r;
- }
- post_post_garbage_hack(is_ssl);
- }
-
- static void cgi_interpose_output(int rfd, int parse_headers, int is_ssl) {
- ssize_t r, r2;
- char buf[1024];
-
- if(!parse_headers) {
- char http_head[] = "HTTP/1.0 200 OK\015\012";
- (void) my_write(http_head, sizeof(http_head), is_ssl);
- } else {
- size_t headers_size, headers_len;
- char* headers;
- char* br;
- int status;
- char* title;
- char* cp;
- headers_size = 0;
- add_to_buf(&headers, &headers_size, &headers_len, (char*) 0, 0);
- for(;;) {
- r = read(rfd, buf, sizeof(buf));
- if(r < 0 && (errno == EINTR || errno == EAGAIN)) {
- sleep(1);
- continue;
- }
- if(r <= 0) {
- br = &(headers[headers_len]);
- break;
- }
- add_to_buf(&headers, &headers_size, &headers_len, buf, r);
- if((br = strstr(headers, "\015\012\015\012")) != (char*) 0 || (br = strstr(headers, "\012\012")) != (char*) 0) {
- break;
- }
- }
- if(headers[0] == '\0') {
- return;
- }
- status = 200;
- if((cp = strstr(headers, "Status:")) != (char*) 0 && cp < br && (cp == headers || *(cp-1) == '\012')) {
- cp += 7;
- cp += strspn(cp, " \t");
- status = atoi(cp);
- }
- if((cp = strstr(headers, "Location:")) != (char*) 0 && cp < br && (cp == headers || *(cp-1) == '\012')) {
- status = 302;
- }
- switch(status) {
- case 200:
- title = "OK";
- break;
- case 302:
- title = "Found";
- break;
- case 304:
- title = "Not Modified";
- break;
- case 400:
- title = "Bad Request";
- break;
- case 401:
- title = "Unauthorized";
- break;
- case 403:
- title = "Forbidden";
- break;
- case 404:
- title = "Not Found";
- break;
- case 408:
- title = "Request Timeout";
- break;
- case 500:
- title = "Internal Error";
- break;
- case 501:
- title = "Not Implemented";
- break;
- case 503:
- title = "Service Temporarily Overloaded";
- break;
- default:
- title = "Something";
- break;
- }
- (void) snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\015\012", status, title);
- (void) my_write(buf, strlen(buf), is_ssl);
- if(strstr(headers, "Server:") == NULL) {
- char line[200];
- sprintf(line, "Server: %s\015\012", SERVER_SOFTWARE);
- (void) my_write(line, strlen(line), is_ssl);
- }
- if(strstr(headers, "Date:") == NULL) {
- char line[200];
- char timebuf[100];
- time_t now = time((time_t*) 0);
- const char* rfc1123_fmt = "%a, %d %b %Y %H:%M:%S GMT";
- (void) strftime(timebuf, sizeof(timebuf), rfc1123_fmt, gmtime(&now));
- sprintf(line, "Date: %s\015\012", timebuf);
- (void) my_write(line, strlen(line), is_ssl);
- if(strstr(headers, "Expires:") == NULL) {
- sprintf(line, "Expires: %s\015\012", timebuf);
- (void) my_write(line, strlen(line), is_ssl);
- }
- } else if(strstr(headers, "Expires:") == NULL) {
- char* line = "Expires: Thu, 01 Jan 1970 00:00:00 GMT\015\012";
- (void) my_write(line, strlen(line), is_ssl);
- }
- (void) my_write(headers, headers_len, is_ssl);
- }
- for(;;) {
- r = read(rfd, buf, sizeof(buf));
- if(r < 0 && (errno == EINTR || errno == EAGAIN)) {
- sleep(1);
- continue;
- }
- if(r <= 0) {
- goto done;
- }
- for(;;) {
- r2 = my_write(buf, r, is_ssl);
- if(r2 < 0 && (errno == EINTR || errno == EAGAIN)) {
- sleep(1);
- continue;
- }
- if(r2 != r) {
- goto done;
- }
- break;
- }
- }
- done:
- shutdown(conn_fd, SHUT_WR);
- }
-
- static void check_referer(int is_ssl) {
- char* cp;
-
- if(url_pattern == (char*) 0) {
- return;
- }
- if(really_check_referer()) {
- return;
- }
- cp = hostname;
- if(cp == (char*) 0) {
- cp = "";
- }
- syslog(LOG_INFO, "%.80s non-local referer \"%.80s%.80s\" \"%.80s\"", ntoa(&client_addr), cp, path, referer);
- send_error(403, "Forbidden", "", "You must supply a local referer.", is_ssl);
- }
-
- static void clear_ndelay(int fd) {
- int flags, newflags;
-
- flags = fcntl(fd, F_GETFL, 0);
- if(flags != -1) {
- newflags = flags & ~ (int) O_NDELAY;
- if(newflags != flags) {
- (void) fcntl(fd, F_SETFL, newflags);
- }
- }
- }
-
- static void de_dotdot(char* file) {
- char* cp;
- char* cp2;
- int l;
-
- while((cp = strstr(file, "//")) != (char*) 0) {
- for(cp2 = cp + 2; *cp2 == '/'; ++cp2) {
- continue;
- }
- (void) strcpy(cp + 1, cp2);
- }
- while(strncmp(file, "./", 2) == 0) {
- (void) strcpy(file, file + 2);
- }
- while((cp = strstr( file, "/./")) != (char*) 0) {
- (void) strcpy(cp, cp + 2);
- }
- for(;;) {
- while(strncmp(file, "../", 3) == 0) {
- (void) strcpy( file, file + 3 );
- }
- cp = strstr(file, "/../");
- if(cp == (char*) 0) {
- break;
- }
- for(cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2) {
- continue;
- }
- (void) strcpy(cp2 + 1, cp + 4);
- }
- while((l = strlen(file)) > 3 && strcmp((cp = file + l - 3), "/..") == 0) {
- for(cp2 = cp - 1; cp2 >= file && *cp2 != '/'; --cp2) {
- continue;
- }
- if(cp2 < file) {
- break;
- }
- *cp2 = '\0';
- }
- }
-
- static void do_cgi(int is_ssl, unsigned short conn_port) {
- char** argp;
- char** envp;
- int parse_headers;
- char* binary;
- char* directory;
-
- if(method != METHOD_GET && method != METHOD_POST) {
- send_error(501, "Not Implemented", "", "That method is not implemented for CGI.", is_ssl);
- }
- if(conn_fd == STDIN_FILENO || conn_fd == STDOUT_FILENO || conn_fd == STDERR_FILENO) {
- int newfd = dup2(conn_fd, STDERR_FILENO + 1);
- if(newfd >= 0) {
- conn_fd = newfd;
- }
- }
- envp = make_envp(is_ssl, conn_port);
- argp = make_argp();
- if((method == METHOD_POST && request_len > request_idx) || is_ssl) {
- int p[2];
- int r;
- if(pipe(p) < 0) {
- send_error(500, "Internal Error", "", "Something unexpected went wrong making a pipe.", is_ssl);
- }
- r = fork();
- if(r < 0) {
- send_error(500, "Internal Error", "", "Something unexpected went wrong forking an interposer.", is_ssl);
- }
- if(r == 0) {
- (void) close(p[0]);
- cgi_interpose_input(p[1], is_ssl);
- exit(0);
- }
- (void) close(p[1]);
- if(p[0] != STDIN_FILENO) {
- (void) dup2(p[0], STDIN_FILENO);
- (void) close(p[0]);
- }
- } else {
- if(conn_fd != STDIN_FILENO) {
- (void) dup2(conn_fd, STDIN_FILENO);
- }
- }
- if(strncmp(argp[0], "nph-", 4) == 0) {
- parse_headers = 0;
- } else {
- parse_headers = 1;
- }
- if(parse_headers || is_ssl) {
- int p[2];
- int r;
- if(pipe(p) < 0) {
- send_error(500, "Internal Error", "", "Something unexpected went wrong making a pipe.", is_ssl);
- }
- r = fork();
- if(r < 0) {
- send_error(500, "Internal Error", "", "Something unexpected went wrong forking an interposer.", is_ssl);
- }
- if(r == 0) {
- (void) close(p[1]);
- cgi_interpose_output(p[0], parse_headers, is_ssl);
- exit(0);
- }
- (void) close(p[0]);
- if(p[1] != STDOUT_FILENO) {
- (void) dup2(p[1], STDOUT_FILENO);
- }
- if(p[1] != STDERR_FILENO) {
- (void) dup2(p[1], STDERR_FILENO);
- }
- if(p[1] != STDOUT_FILENO && p[1] != STDERR_FILENO) {
- (void) close(p[1]);
- }
- } else {
- if(conn_fd != STDOUT_FILENO) {
- (void) dup2(conn_fd, STDOUT_FILENO);
- }
- if(conn_fd != STDERR_FILENO) {
- (void) dup2(conn_fd, STDERR_FILENO);
- }
- }
- if(logfp != (FILE*) 0) {
- (void) fclose(logfp);
- }
- closelog();
- if(nice(CGI_NICE) < 0) { ; }
- directory = e_strdup(file);
- binary = strrchr(directory, '/');
- if(binary == (char*) 0) {
- binary = file;
- } else {
- *binary++ = '\0';
- if(chdir(directory) < 0) { ; }
- }
- (void) signal(SIGPIPE, SIG_DFL);
- (void) execve(binary, argp, envp);
- send_error(500, "Internal Error", "", "Something unexpected went wrong running a CGI program.", is_ssl);
- }
-
- static void do_dir(int is_ssl) {
- char buf[10000];
- size_t buflen;
- char* contents;
- size_t contents_size, contents_len;
- int n, i;
- struct dirent **dl;
- char* name_info;
-
- if(pathinfo != (char*) 0) {
- send_error(404, "Not Found", "", "File not found.", is_ssl);
- }
- auth_check(file, is_ssl);
- check_referer(is_ssl);
- n = scandir(file, &dl, NULL, alphasort);
- if(n < 0) {
- syslog(LOG_INFO, "%.80s Directory \"%.80s\" is protected", ntoa(&client_addr), path);
- send_error(403, "Forbidden", "", "Directory is protected.", is_ssl);
- }
- contents_size = 0;
- buflen = snprintf(buf, sizeof(buf), "<html>\n<head><title>Index of %s</title></head>\n<body bgcolor=\"#FFFFFF\">\n<h1>Index of %s</h1><hr><pre>\n", file, file);
- add_to_buf(&contents, &contents_size, &contents_len, buf, buflen);
- for(i = 0; i < n; ++i) {
- if(strcmp(dl[i]->d_name, ".") == 0) {
- continue;
- }
- name_info = file_details(file, dl[i]->d_name);
- add_to_buf(&contents, &contents_size, &contents_len, name_info, strlen(name_info));
- }
- buflen = snprintf(buf, sizeof(buf), "</pre><hr>\n%s\n</body>\n</html>\n", SERVER_SOFTWARE);
- add_to_buf(&contents, &contents_size, &contents_len, buf, buflen);
- add_headers(200, "Ok", "", "", "text/html; charset=%s", contents_len, sb.st_mtime);
- if(method != METHOD_HEAD) {
- add_to_response(contents, contents_len);
- }
- send_response(is_ssl);
- }
-
- static void do_file(int is_ssl, unsigned short conn_port) {
- char buf[10000];
- char mime_encodings[500];
- const char* mime_type;
- char fixed_mime_type[500];
- char* cp;
- int fd;
-
- (void) strncpy(buf, file, sizeof(buf));
- cp = strrchr(buf, '/');
- if(cp == (char*) 0) {
- (void) strcpy(buf, ".");
- } else {
- *cp = '\0';
- }
- auth_check(buf, is_ssl);
- if(strcmp(file, AUTH_FILE) == 0 || (strcmp(&(file[strlen(file) - sizeof(AUTH_FILE) + 1]), AUTH_FILE) == 0 && file[strlen(file) - sizeof(AUTH_FILE)] == '/')) {
- syslog(LOG_NOTICE, "%.80s URL \"%.80s\" tried to retrieve an auth file", ntoa(&client_addr), path);
- send_error(403, "Forbidden", "", "File is protected.", is_ssl);
- }
- if(defaultRealmName != NULL && defaultRealmPasswordFile != NULL) {
- if(strcmp(file, defaultRealmPasswordFile) == 0 || strcmp(&(file[strlen(file) - sizeof(defaultRealmPasswordFile) + 1]), defaultRealmPasswordFile) == 0 && file[strlen(file) - sizeof(defaultRealmPasswordFile)] == '/') {
- syslog(LOG_NOTICE, "%.80s URL \"%.80s\" tried to retrieve an auth file", ntoa(&client_addr), path);
- send_error(403, "Forbidden", "", "File is protected.", is_ssl);
- }
- }
- check_referer(is_ssl);
- if(cgi_pattern != (char*) 0 && match(cgi_pattern, file)) {
- do_cgi(is_ssl, conn_port);
- return;
- } else if(pathinfo != (char*) 0) {
- send_error(404, "Not Found", "", "File not found.", is_ssl);
- }
- fd = open(file, O_RDONLY);
- if(fd < 0) {
- syslog(LOG_INFO, "%.80s File \"%.80s\" is protected", ntoa(&client_addr), path);
- send_error(403, "Forbidden", "", "File is protected.", is_ssl);
- }
- mime_type = figure_mime(file, mime_encodings, sizeof(mime_encodings));
- (void) snprintf(fixed_mime_type, sizeof(fixed_mime_type), mime_type, charset);
- if(if_modified_since != (time_t) -1 && if_modified_since >= sb.st_mtime) {
- add_headers(304, "Not Modified", "", mime_encodings, fixed_mime_type, (off_t) -1, sb.st_mtime);
- send_response(is_ssl);
- return;
- }
- add_headers(200, "Ok", "", mime_encodings, fixed_mime_type, sb.st_size, sb.st_mtime);
- send_response(is_ssl);
- if(method == METHOD_HEAD) {
- return;
- }
- if(sb.st_size > 0) {
- send_via_write(fd, sb.st_size, is_ssl);
- }
- (void) close(fd);
- }
-
- static void* e_malloc(size_t size) {
- void* ptr;
-
- ptr = malloc(size);
- if(ptr == (void*) 0) {
- syslog(LOG_CRIT, "out of memory");
- (void) fprintf(stderr, "%s: out of memory\n", argv0);
- exit(1);
- }
- return ptr;
- }
-
- static void* e_realloc(void* optr, size_t size) {
- void* ptr;
-
- ptr = realloc(optr, size);
- if(ptr == (void*) 0) {
- syslog(LOG_CRIT, "out of memory");
- (void) fprintf(stderr, "%s: out of memory\n", argv0);
- exit(1);
- }
- return ptr;
- }
-
- static char* e_strdup(char* ostr) {
- char* str;
-
- str = strdup(ostr);
- if(str == (char*) 0) {
- syslog(LOG_CRIT, "out of memory copying a string");
- (void) fprintf(stderr, "%s: out of memory copying a string\n", argv0);
- exit(1);
- }
- return str;
- }
-
- static int ext_compare(struct mime_entry* a, struct mime_entry* b) {
- return strcmp(a->ext, b->ext);
- }
-
- static const char* figure_mime(char* name, char* me, size_t me_size) {
- char* prev_dot;
- char* dot;
- char* ext;
- int me_indexes[100], n_me_indexes;
- size_t ext_len, me_len;
- int i, top, bot, mid;
- int r;
- const char* default_type = "application/octet-stream ";
- const char* type;
-
- n_me_indexes = 0;
- for(prev_dot = &name[strlen(name)]; ; prev_dot = dot) {
- for(dot = prev_dot - 1; dot >= name && *dot != '.'; --dot);
- if(dot < name) {
- type = default_type;
- goto done;
- }
- ext = dot + 1;
- ext_len = prev_dot - ext;
- for(i = 0; i < n_enc_tab; ++i) {
- if(ext_len == enc_tab[i].ext_len && strncasecmp(ext, enc_tab[i].ext, ext_len) == 0) {
- if(n_me_indexes < sizeof(me_indexes)/sizeof(*me_indexes)) {
- me_indexes[n_me_indexes] = i;
- ++n_me_indexes;
- }
- goto next;
- }
- }
- break;
- next: ;
- }
- top = n_typ_tab - 1;
- bot = 0;
- while(top >= bot) {
- mid = (top + bot) / 2;
- r = strncasecmp(ext, typ_tab[mid].ext, ext_len);
- if(r < 0) {
- top = mid - 1;
- } else if(r > 0) {
- bot = mid + 1;
- } else if(ext_len < typ_tab[mid].ext_len) {
- top = mid - 1;
- } else if(ext_len > typ_tab[mid].ext_len) {
- bot = mid + 1;
- } else {
- type = typ_tab[mid].val;
- goto done;
- }
- }
- type = default_type;
- done:
- me[0] = '\0';
- me_len = 0;
- for(i = n_me_indexes - 1; i >= 0; --i) {
- if(me_len + enc_tab[me_indexes[i]].val_len + 1 < me_size) {
- if(me[0] != '\0') {
- (void) strcpy(&me[me_len], ",");
- ++me_len;
- }
- (void) strcpy(&me[me_len], enc_tab[me_indexes[i]].val);
- me_len += enc_tab[me_indexes[i]].val_len;
- }
- }
- return type;
- }
-
- static char* file_details(const char* dir, const char* name) {
- struct stat sb;
- char f_time[20];
- static char encname[1000];
- static char buf[2000];
-
- (void) snprintf(buf, sizeof(buf), "%s/%s", dir, name);
- if(lstat(buf, &sb) < 0)
- return "???";
- (void) strftime(f_time, sizeof(f_time), "%d-%b-%Y %H:%M", localtime(&sb.st_mtime));
- strencode(encname, sizeof(encname), name);
- (void) snprintf(buf, sizeof(buf), "<a href=\"%s\">%-50s</a> %15s %14lld\n", encname, name, f_time, (long long int) sb.st_size);
- return buf;
- }
-
- static char* get_method_str(int m) {
- switch(m) {
- case METHOD_GET:
- return "GET";
- case METHOD_HEAD:
- return "HEAD";
- case METHOD_POST:
- return "POST";
- default:
- return "UNKNOWN";
- }
- }
-
- static int get_pathinfo(void) {
- int r;
-
- pathinfo = &file[strlen(file)];
- for(;;) {
- do {
- --pathinfo;
- if(pathinfo <= file) {
- pathinfo = (char*) 0;
- return -1;
- }
- } while(*pathinfo != '/');
- *pathinfo = '\0';
- r = stat(file, &sb);
- if(r >= 0) {
- ++pathinfo;
- return r;
- } else {
- *pathinfo = '/';
- }
- }
- }
-
- static char* get_request_line(void) {
- int i;
- char c;
-
- for(i = request_idx; request_idx < request_len; ++request_idx) {
- c = request[request_idx];
- if(c == '\012' || c == '\015') {
- request[request_idx] = '\0';
- ++request_idx;
- if(c == '\015' && request_idx < request_len && request[request_idx] == '\012') {
- request[request_idx] = '\0';
- ++request_idx;
- }
- return &(request[i]);
- }
- }
- return (char*) 0;
- }
-
- static void handle_read_timeout(int sig, int is_ssl) {
- syslog(LOG_INFO, "%.80s connection timed out reading", ntoa(&client_addr));
- send_error(408, "Request Timeout", "", "No request appeared within a reasonable time period.", is_ssl);
- }
-
- static void handle_read_timeout_sig(int sig) {
- handle_read_timeout(0,0);
- }
-
- static void handle_request(int is_ssl, unsigned short conn_port) {
- char* method_str;
- char* line;
- char* cp;
- int r, file_len, i;
- const char* index_names[] = {"default.html", "default.htm", "index.html", "index.htm", "index.cgi", "index.sh" };
-
- (void) signal(SIGALRM, handle_read_timeout_sig);
- (void) alarm(READ_TIMEOUT);
-
- remoteuser = (char*) 0;
- method = METHOD_UNKNOWN;
- path = (char*) 0;
- file = (char*) 0;
- pathinfo = (char*) 0;
- query = "";
- protocol = (char*) 0;
- status = 0;
- bytes = -1;
- authorization = (char*) 0;
- content_type = (char*) 0;
- content_length = -1;
- cookie = (char*) 0;
- host = (char*) 0;
- if_modified_since = (time_t) -1;
- referer = "";
- useragent = "";
-
- #ifdef TCP_NOPUSH
- r = 1;
- (void) setsockopt(conn_fd, IPPROTO_TCP, TCP_NOPUSH, (void*) &r, sizeof(r));
- #endif
- if(is_ssl) {
- ssl = SSL_new(ssl_ctx);
- SSL_set_fd(ssl, conn_fd);
- int accept_ret = SSL_accept(ssl);
- if(accept_ret <= 0) {
- int e = SSL_get_error(ssl, accept_ret);
- if(e != VERSION_ERROR) {
- syslog(LOG_CRIT, "error: can't initialize ssl connection, error = %d\n", e);
- }
- exit(1);
- }
- }
- start_request();
- for(;;) {
- char buf[10000];
- int r = my_read( buf, sizeof(buf), is_ssl );
- if(r < 0 && (errno == EINTR || errno == EAGAIN)) {
- continue;
- }
- if(r <= 0) {
- break;
- }
- (void) alarm(READ_TIMEOUT);
- add_to_request(buf, r);
- if(strstr(request, "\015\012\015\012") != (char*) 0 || strstr(request, "\012\012") != (char*) 0) {
- break;
- }
- }
- method_str = get_request_line();
- if(method_str == (char*) 0) {
- send_error(400, "Bad Request", "", "Can't parse request.", is_ssl);
- }
- path = strpbrk(method_str, " \t\012\015");
- if(path == (char*) 0) {
- send_error(400, "Bad Request", "", "Can't parse request.", is_ssl);
- }
- *path++ = '\0';
- path += strspn(path, " \t\012\015");
- protocol = strpbrk(path, " \t\012\015");
- if(protocol == (char*) 0) {
- send_error(400, "Bad Request", "", "Can't parse request.", is_ssl);
- }
- *protocol++ = '\0';
- protocol += strspn(protocol, " \t\012\015");
- query = strchr(path, '?');
- if(query == (char*) 0) {
- query = "";
- } else {
- *query++ = '\0';
- }
- while((line = get_request_line()) != (char*) 0) {
- if(line[0] == '\0') {
- break;
- } else if(strncasecmp(line, "Authorization:", 14) == 0) {
- cp = &line[14];
- cp += strspn(cp, " \t");
- authorization = cp;
- } else if(strncasecmp(line, "Content-Length:", 15) == 0) {
- cp = &line[15];
- cp += strspn(cp, " \t");
- content_length = atol(cp);
- } else if(strncasecmp(line, "Content-Type:", 13) == 0) {
- cp = &line[13];
- cp += strspn(cp, " \t");
- content_type = cp;
- } else if(strncasecmp(line, "Cookie:", 7) == 0) {
- cp = &line[7];
- cp += strspn(cp, " \t");
- cookie = cp;
- } else if(strncasecmp(line, "Host:", 5) == 0) {
- cp = &line[5];
- cp += strspn(cp, " \t");
- host = cp;
- if(strchr(host, '/') != (char*) 0 || host[0] == '.') {
- send_error(400, "Bad Request", "", "Can't parse request.", is_ssl);
- }
- } else if(strncasecmp(line, "If-Modified-Since:", 18) == 0) {
- cp = &line[18];
- cp += strspn(cp, " \t");
- if_modified_since = dateparse(cp);
- } else if(strncasecmp(line, "Referer:", 8) == 0) {
- cp = &line[8];
- cp += strspn(cp, " \t");
- referer = cp;
- } else if(strncasecmp(line, "User-Agent:", 11) == 0) {
- cp = &line[11];
- cp += strspn(cp, " \t");
- useragent = cp;
- }
- }
- if(strcasecmp(method_str, get_method_str(METHOD_GET)) == 0) {
- method = METHOD_GET;
- } else if(strcasecmp(method_str, get_method_str(METHOD_HEAD)) == 0) {
- method = METHOD_HEAD;
- } else if(strcasecmp(method_str, get_method_str(METHOD_POST)) == 0) {
- method = METHOD_POST;
- } else {
- send_error(501, "Not Implemented", "", "That method is not implemented.", is_ssl);
- }
- strdecode(path, path);
- if(path[0] != '/') {
- send_error(400, "Bad Request", "", "Bad filename.", is_ssl);
- }
- file = &(path[1]);
- de_dotdot(file);
- if(file[0] == '\0') {
- file = "./";
- }
- if(file[0] == '/' || (file[0] == '.' && file[1] == '.' && (file[2] == '\0' || file[2] == '/'))) {
- send_error(400, "Bad Request", "", "Illegal filename.", is_ssl);
- }
-
- (void) signal(SIGALRM, handle_write_timeout);
- (void) alarm(WRITE_TIMEOUT);
- r = stat(file, &sb);
- if(r < 0) {
- r = get_pathinfo();
- }
- if(r < 0) {
- if(pageNotFoundFile != NULL && host != NULL) {
- send_redirect("", host, pageNotFoundFile, is_ssl);
- } else {
- send_error(404, "Not Found", "", "File not found.", is_ssl);
- }
- }
- file_len = strlen( file );
- if(!S_ISDIR(sb.st_mode)) {
- while(file[file_len - 1] == '/') {
- file[file_len - 1] = '\0';
- --file_len;
- }
- do_file(is_ssl, conn_port);
- } else {
- char idx[10000];
- unsigned char found_index = 0;
- if(file[file_len - 1] != '/' && pathinfo == (char*) 0) {
- char location[10000];
- if(query[0] != '\0') {
- (void) snprintf(location, sizeof(location), "Location: %s/?%s", path, query);
- } else {
- (void) snprintf(location, sizeof(location), "Location: %s/", path);
- send_error(302, "Found", location, "Directories must end with a slash.", is_ssl);
- }
- }
- if(defaultPageFile != NULL) {
- (void) snprintf(idx, sizeof(idx), "%s%s", file, defaultPageFile);
- if(stat( idx, &sb ) >= 0) {
- file = idx;
- do_file(is_ssl, conn_port);
- found_index = 1;
- }
- }
- for(i = 0; i < (sizeof(index_names) / sizeof(char*)) && found_index == 0; ++i) {
- (void) snprintf(idx, sizeof(idx), "%s%s", file, index_names[i]);
- if(stat(idx, &sb) >= 0) {
- file = idx;
- do_file(is_ssl, conn_port);
- found_index = 1;
- }
- }
- if(found_index == 0) {
- if(allowDirectoryListing == 0) {
- if(pageNotFoundFile != NULL && host != NULL) {
- send_redirect("", host, pageNotFoundFile, is_ssl);
- } else {
- send_error(404, "Not Found", "", "File not found.", is_ssl);
- }
- } else {
- do_dir(is_ssl);
- }
- }
- }
- if(is_ssl) {
- SSL_free(ssl);
- }
- }
-
- static void handle_sigchld(int sig) {
- const int oerrno = errno;
- pid_t pid;
- int status;
-
- (void) signal(SIGCHLD, handle_sigchld);
- for(;;) {
- pid = waitpid((pid_t) -1, &status, WNOHANG);
- if((int) pid == 0) {
- break;
- }
- if((int) pid < 0) {
- if(errno == EINTR || errno == EAGAIN) {
- continue;
- }
- if(errno != ECHILD) {
- syslog(LOG_ERR, "child wait - %m");
- perror("child wait");
- }
- break;
- }
- }
- errno = oerrno;
- }
-
- static void handle_sighup(int sig) {
- const int oerrno = errno;
-
- (void) signal(SIGHUP, handle_sighup);
- got_hup = 1;
- errno = oerrno;
- }
-
- static void handle_sigterm(int sig) {
- syslog(LOG_NOTICE, "exiting due to signal %d", sig);
- (void) fprintf(stderr, "%s: exiting due to signal %d\n", argv0, sig);
- closelog();
- exit(1);
- }
-
- static void handle_write_timeout(int sig) {
- syslog(LOG_INFO, "%.80s connection timed out writing", ntoa(&client_addr));
- exit(1);
- }
-
- static int hexit(char c) {
- if(c >= '0' && c <= '9') {
- return c - '0';
- }
- if(c >= 'a' && c <= 'f') {
- return c - 'a' + 10;
- }
- if(c >= 'A' && c <= 'F') {
- return c - 'A' + 10;
- }
- return 0;
- }
-
- static void init_mime(void) {
- int i;
-
- qsort(enc_tab, n_enc_tab, sizeof(*enc_tab), (int(*)(const void*, const void*)) ext_compare);
- qsort(typ_tab, n_typ_tab, sizeof(*typ_tab), (int(*)(const void*, const void*)) ext_compare);
-
- for(i = 0; i < n_enc_tab; ++i) {
- enc_tab[i].ext_len = strlen(enc_tab[i].ext);
- enc_tab[i].val_len = strlen(enc_tab[i].val);
- }
- for(i = 0; i < n_typ_tab; ++i) {
- typ_tab[i].ext_len = strlen(typ_tab[i].ext);
- typ_tab[i].val_len = strlen(typ_tab[i].val);
- }
- }
-
- static int initialize_listen_socket(usockaddr* usaP) {
- int listen_fd;
- int i;
-
- if(!sockaddr_check(usaP)) {
- syslog(LOG_ERR, "unknown sockaddr family on listen socket - %d", usaP->sa.sa_family);
- (void) fprintf(stderr, "%s: unknown sockaddr family on listen socket - %d\n", argv0, usaP->sa.sa_family);
- return -1;
- }
- listen_fd = socket(usaP->sa.sa_family, SOCK_STREAM, 0);
- if(listen_fd < 0) {
- if(usaP->sa.sa_family == AF_INET6 && (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || EPFNOSUPPORT || EAFNOSUPPORT)) {
- /* IPv6 not compiled into kernel, no big deal, don't print errors */
- } else {
- syslog(LOG_CRIT, "socket %.80s - %m", ntoa(usaP));
- perror("socket");
- }
- return -1;
- }
-
- (void) fcntl(listen_fd, F_SETFD, 1);
- i = 1;
- if(setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*) &i, sizeof(i)) < 0) {
- syslog(LOG_CRIT, "setsockopt SO_REUSEADDR - %m");
- perror("setsockopt SO_REUSEADDR");
- return -1;
- }
- if(bind(listen_fd, &usaP->sa, sockaddr_len(usaP)) < 0) {
- syslog(LOG_CRIT, "bind %.80s - %m", ntoa(usaP));
- perror("bind");
- return -1;
- }
- if(listen(listen_fd, 1024) < 0) {
- syslog(LOG_CRIT, "listen - %m");
- perror("listen");
- return -1;
- }
- return listen_fd;
- }
-
- static void lookup_hostname(usockaddr* usa4P, usockaddr* usa4sP, size_t sa4_len, int* gotv4P, int* gotv4sP, usockaddr* usa6P, usockaddr* usa6sP, size_t sa6_len, int* gotv6P, int* gotv6sP) {
- int port_index;
- unsigned short port_list[4];
- port_list[0] = port;
- port_list[1] = sslPort;
- port_list[2] = 0;
-
- *gotv6P = 0;
- *gotv6sP = 0;
- *gotv4P = 0;
- *gotv4sP = 0;
- for(port_index=0; port_list[port_index] != 0; port_index++) {
- struct addrinfo hints;
- char portstr[10];
- int gaierr;
- struct addrinfo* ai;
- struct addrinfo* ai2;
- struct addrinfo* aiv6;
- struct addrinfo* aiv4;
- (void) memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- hints.ai_flags = AI_PASSIVE;
- hints.ai_socktype = SOCK_STREAM;
- (void) snprintf(portstr, sizeof(portstr), "%d", (int) port_list[port_index]);
- if((gaierr = getaddrinfo(hostname, portstr, &hints, &ai)) != 0) {
- syslog(LOG_CRIT, "getaddrinfo %.80s - %s", hostname, gai_strerror(gaierr));
- (void) fprintf(stderr, "%s: getaddrinfo %.80s - %s\n", argv0, hostname, gai_strerror(gaierr));
- exit(1);
- }
- aiv6 = (struct addrinfo*) 0;
- aiv4 = (struct addrinfo*) 0;
- for(ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next) {
- switch(ai2->ai_family) {
- case AF_INET6:
- if(aiv6 == (struct addrinfo*) 0) {
- aiv6 = ai2;
- }
- break;
- case AF_INET:
- if(aiv4 == (struct addrinfo*) 0) {
- aiv4 = ai2;
- }
- break;
- }
- }
- if(aiv6 != (struct addrinfo*) 0) {
- if(sa6_len < aiv6->ai_addrlen) {
- syslog(LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)", hostname, (unsigned long) sa6_len, (unsigned long) aiv6->ai_addrlen);
- (void) fprintf(stderr, "%s: %.80s - sockaddr too small (%lu < %lu)\n", argv0, hostname, (unsigned long) sa6_len, (unsigned long) aiv6->ai_addrlen);
- exit(1);
- }
- if(port_index==0) {
- *gotv6P = 1;
- (void) memset(usa6P, 0, sa6_len);
- (void) memmove(usa6P, aiv6->ai_addr, aiv6->ai_addrlen);
- } else {
- *gotv6sP = 1;
- (void) memset(usa6sP, 0, sa6_len);
- (void) memmove(usa6sP, aiv6->ai_addr, aiv6->ai_addrlen);
- }
- }
- if(aiv4 != (struct addrinfo*) 0) {
- if(sa4_len < aiv4->ai_addrlen) {
- syslog(LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)", hostname, (unsigned long) sa4_len, (unsigned long) aiv4->ai_addrlen);
- (void) fprintf(stderr, "%s: %.80s - sockaddr too small (%lu < %lu)\n", argv0, hostname, (unsigned long) sa4_len, (unsigned long) aiv4->ai_addrlen);
- exit(1);
- }
- if(port_index == 0) {
- *gotv4P = 1;
- (void) memset(usa4P, 0, sa4_len);
- (void) memmove(usa4P, aiv4->ai_addr, aiv4->ai_addrlen);
- } else {
- *gotv4sP = 1;
- (void) memset(usa4sP, 0, sa4_len);
- (void) memmove(usa4sP, aiv4->ai_addr, aiv4->ai_addrlen);
- }
- *gotv4P = 1;
- }
- freeaddrinfo(ai);
- }
- }
-
- int main(int argc, char** argv) {
- int argn;
- struct passwd* pwd;
- uid_t uid = 32767;
- gid_t gid = 32767;
- usockaddr host_addr4;
- usockaddr host_addr6;
- int gotv4, gotv4s, gotv6, gotv6s;
- fd_set lfdset;
- int maxfd;
- usockaddr usa;
- int sz, r;
- char* cp;
- usockaddr host_addr4s;
- usockaddr host_addr6s;
-
- argv0 = argv[0];
- debug = 0;
- port = 0;
- dir = (char*) 0;
- data_dir = (char*) 0;
- cgi_pattern = DEFAULT_CGI_PATTERN;
- url_pattern = (char*) 0;
- no_empty_referers = 0;
- local_pattern = (char*) 0;
- charset = DEFAULT_CHARSET;
- language = DEFAULT_LANGUAGE;
- p3p = (char*) 0;
- max_age = -1;
- user = DEFAULT_USER;
- hostname = (char*) 0;
- logfile = (char*) 0;
- pidfile = (char*) 0;
- logfp = (FILE*) 0;
- do_ssl = 0;
- certfile = DEFAULT_CERTFILE;
- cipher = (char*) 0;
-
- defaultRealmName = NULL;
- defaultRealmPasswordFile = NULL;
- defaultPageFile = NULL;
- pageNotFoundFile = NULL;
- allowDirectoryListing = 1;
- sslPort = 0;
- argn = 1;
-
- while(argn < argc && argv[argn][0] == '-') {
- if(strcmp( argv[argn], "-V" ) == 0) {
- (void) printf("%s\n", SERVER_SOFTWARE);
- exit(0);
- } else if(strcmp(argv[argn], "-C") == 0 && argn + 1 < argc) {
- ++argn;
- read_config(argv[argn]);
- } else if(strcmp(argv[argn], "-D") == 0) {
- debug = 1;
- } else if(strcmp(argv[argn], "-S") == 0) {
- do_ssl = 1;
- } else if(strcmp(argv[argn], "-E") == 0 && argn + 1 < argc) {
- ++argn;
- certfile = argv[argn];
- } else if(strcmp(argv[argn], "-Y") == 0 && argn + 1 < argc) {
- ++argn;
- cipher = argv[argn];
- } else if(strcmp(argv[argn], "-p") == 0 && argn + 1 < argc) {
- ++argn;
- port = (unsigned short) atoi(argv[argn]);
- } else if(strcmp(argv[argn], "-d") == 0 && argn + 1 < argc) {
- ++argn;
- dir = argv[argn];
- } else if(strcmp(argv[argn], "-dd") == 0 && argn + 1 < argc) {
- ++argn;
- data_dir = argv[argn];
- } else if(strcmp(argv[argn], "-c") == 0 && argn + 1 < argc) {
- ++argn;
- cgi_pattern = argv[argn];
- } else if(strcmp(argv[argn], "-u") == 0 && argn + 1 < argc) {
- ++argn;
- user = argv[argn];
- } else if(strcmp(argv[argn], "-h") == 0 && argn + 1 < argc) {
- ++argn;
- hostname = argv[argn];
- } else if(strcmp(argv[argn], "-l") == 0 && argn + 1 < argc) {
- ++argn;
- logfile = argv[argn];
- } else if(strcmp(argv[argn], "-i") == 0 && argn + 1 < argc) {
- ++argn;
- pidfile = argv[argn];
- } else if(strcmp(argv[argn], "-T") == 0 && argn + 1 < argc) {
- ++argn;
- charset = argv[argn];
- } else if(strcmp(argv[argn], "-L") == 0 && argn + 1 < argc) {
- ++argn;
- language = argv[argn];
- } else if(strcmp(argv[argn], "-P") == 0 && argn + 1 < argc) {
- ++argn;
- p3p = argv[argn];
- } else if(strcmp(argv[argn], "-M") == 0 && argn + 1 < argc) {
- ++argn;
- max_age = atoi(argv[argn]);
- } else if(strcmp(argv[argn], "-DRN") == 0 && argn + 1 < argc) {
- ++argn;
- defaultRealmName = argv[argn];
- } else if(strcmp(argv[argn], "-DRP") == 0 && argn + 1 < argc) {
- ++argn;
- defaultRealmPasswordFile = argv[argn];
- } else if(strcmp(argv[argn], "-DPF") == 0 && argn + 1 < argc) {
- ++argn;
- defaultPageFile = argv[argn];
- } else if(strcmp(argv[argn], "-PNF") == 0 && argn + 1 < argc) {
- ++argn;
- pageNotFoundFile = argv[argn];
- } else if(strcmp(argv[argn], "-ADL") == 0 && argn + 1 < argc) {
- ++argn;
- if(strcmp(argv[argn], "1") == 0 || strcmp(argv[argn], "true") == 0 || strcmp(argv[argn], "TRUE") == 0 || strcmp(argv[argn], "yes") == 0 || strcmp(argv[argn], "YES") == 0) {
- allowDirectoryListing = 1;
- } else {
- allowDirectoryListing = 0;
- }
- } else if(strcmp(argv[argn], "-SP") == 0 && argn + 1 < argc) {
- ++argn;
- sslPort = (unsigned short) atoi(argv[argn]);
- } else {
- usage();
- }
- ++argn;
- }
- if(argn != argc) {
- usage();
- }
-
- cp = strrchr(argv0, '/');
- if(cp != (char*) 0) {
- ++cp;
- } else {
- cp = argv0;
- }
- openlog(cp, LOG_NDELAY|LOG_PID, LOG_DAEMON);
-
- if(port == 0) {
- if(sslPort != 0 && do_ssl) {
- port = sslPort;
- sslPort = 0;
- }
- if(do_ssl) {
- port = DEFAULT_HTTPS_PORT;
- } else {
- port = DEFAULT_HTTP_PORT;
- }
- }
-
- if(getuid() == 0) {
- pwd = getpwnam(user);
- if(pwd == (struct passwd*) 0) {
- syslog(LOG_CRIT, "unknown user - '%s'", user);
- (void) fprintf(stderr, "%s: unknown user - '%s'\n", argv0, user);
- exit(1);
- }
- uid = pwd->pw_uid;
- gid = pwd->pw_gid;
- }
-
- if(logfile != (char*) 0) {
- logfp = fopen(logfile, "a");
- if(logfp == (FILE*) 0) {
- syslog(LOG_CRIT, "%s - %m", logfile);
- perror(logfile);
- exit(1);
- }
- if(logfile[0] != '/') {
- syslog(LOG_WARNING, "logfile is not an absolute path, you may not be able to re-open it");
- (void) fprintf(stderr, "%s: logfile is not an absolute path, you may not be able to re-open it\n", argv0);
- }
- if(getuid() == 0) {
- if(fchown(fileno(logfp), uid, gid) < 0) {
- syslog(LOG_WARNING, "fchown logfile - %m");
- perror("fchown logfile");
- }
- }
- }
-
- lookup_hostname(&host_addr4, &host_addr4s, sizeof(struct sockaddr_in), &gotv4, &gotv4s, &host_addr6, &host_addr6s, sizeof(struct sockaddr_in6), &gotv6, &gotv6s);
- if(hostname == (char*) 0) {
- (void) gethostname(hostname_buf, sizeof(hostname_buf));
- hostname = hostname_buf;
- }
- if(!( gotv4 || gotv4s || gotv6 || gotv6s)) {
- syslog(LOG_CRIT, "can't find any valid address");
- (void) fprintf(stderr, "%s: can't find any valid address\n", argv0);
- exit(1);
- }
-
- listen6_fd = -1;
- listen6s_fd = -1;
- listen4_fd = -1;
- listen4s_fd = -1;
- if(gotv6) {
- listen6_fd = initialize_listen_socket(&host_addr6);
- }
- if(gotv6s) {
- listen6s_fd = initialize_listen_socket(&host_addr6s);
- }
- if(gotv4) {
- listen4_fd = initialize_listen_socket(&host_addr4);
- }
- if(gotv4s) {
- listen4s_fd = initialize_listen_socket(&host_addr4s);
- }
-
- if(listen4_fd == -1 && listen6_fd == -1 && listen4s_fd == -1 && listen6s_fd == -1) {
- syslog(LOG_CRIT, "can't bind to any address");
- (void) fprintf(stderr, "%s: can't bind to any address\n", argv0);
- exit(1);
- }
-
- if(do_ssl) {
- ssl_ctx = SSL_CTX_new(TLSv1_server_method());
- SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, 0);
- if(certfile[0] != '\0') {
- if(SSL_CTX_use_certificate_file(ssl_ctx, certfile, SSL_FILETYPE_PEM) != SSL_SUCCESS || SSL_CTX_use_PrivateKey_file(ssl_ctx, certfile, SSL_FILETYPE_PEM) != SSL_SUCCESS) {
- syslog(LOG_CRIT, "can't load certificate and/or private key\n");
- exit(1);
- }
- }
- if(cipher != (char*) 0) {
- if(SSL_CTX_set_cipher_list(ssl_ctx, cipher) <= 0) {
- syslog(LOG_CRIT, "can't load certificate and/or private key\n");
- exit(1);
- }
- }
- }
-
- if(!debug) {
- if(daemon(1, 0) < 0) {
- syslog(LOG_CRIT, "daemon - %m");
- perror("daemon");
- exit(1);
- }
- } else {
- (void) setsid();
- }
-
- if(pidfile != (char*) 0) {
- FILE* pidfp = fopen(pidfile, "w");
- if(pidfp == (FILE*) 0) {
- syslog(LOG_CRIT, "%s - %m", pidfile);
- perror(pidfile);
- exit(1);
- }
- (void) fprintf(pidfp, "%d\n", (int) getpid());
- (void) fclose(pidfp);
- }
-
- tzset();
-
- if(getuid() == 0) {
- if(setgroups(0, (gid_t*) 0) < 0) {
- syslog(LOG_CRIT, "setgroups - %m");
- perror("setgroups");
- exit(1);
- }
- if(setgid(gid) < 0) {
- syslog(LOG_CRIT, "setgid - %m");
- perror("setgid");
- exit(1);
- }
- if(initgroups(user, gid ) < 0) {
- syslog(LOG_ERR, "initgroups - %m");
- perror("initgroups");
- }
- }
-
- if(dir != (char*) 0) {
- if(chdir(dir) < 0) {
- syslog(LOG_CRIT, "chdir - %m");
- perror("chdir");
- exit(1);
- }
- }
- if(getcwd(cwd, sizeof(cwd) - 1) == NULL) { ; }
- if(cwd[strlen(cwd) - 1] != '/') {
- (void) strcat( cwd, "/" );
- }
- if(data_dir != (char*) 0) {
- if(chdir(data_dir) < 0) {
- syslog(LOG_CRIT, "data_dir chdir - %m");
- perror("data_dir chdir");
- exit(1);
- }
- }
- if(getuid() == 0) {
- if(setuid(uid) < 0) {
- syslog(LOG_CRIT, "setuid - %m");
- perror("setuid");
- exit(1);
- }
- }
-
- (void) signal(SIGTERM, handle_sigterm);
- (void) signal(SIGINT, handle_sigterm);
- (void) signal(SIGUSR1, handle_sigterm);
- (void) signal(SIGHUP, handle_sighup);
- (void) signal(SIGCHLD, handle_sigchld);
- (void) signal(SIGPIPE, SIG_IGN);
- got_hup = 0;
- init_mime();
-
- if(hostname == (char*) 0) {
- syslog(LOG_NOTICE, "%.80s starting on port %d", SERVER_SOFTWARE, (int) port);
- } else {
- syslog(LOG_NOTICE, "%.80s starting on %.80s, port %d", SERVER_SOFTWARE, hostname, (int) port);
- }
-
- for(;;) {
- int is_ssl;
- unsigned short conn_port;
- if(got_hup) {
- reopen_logfile();
- got_hup = 0;
- }
- FD_ZERO(&lfdset);
- maxfd = -1;
- if(listen4_fd != -1) {
- FD_SET(listen4_fd, &lfdset);
- if(listen4_fd > maxfd) {
- maxfd = listen4_fd;
- }
- }
- if(listen4s_fd != -1) {
- FD_SET(listen4s_fd, &lfdset);
- if(listen4s_fd > maxfd) {
- maxfd = listen4s_fd;
- }
- }
- if(listen6_fd != -1) {
- FD_SET(listen6_fd, &lfdset);
- if(listen6_fd > maxfd) {
- maxfd = listen6_fd;
- }
- }
- if(listen6s_fd != -1) {
- FD_SET(listen6s_fd, &lfdset);
- if(listen6s_fd > maxfd) {
- maxfd = listen6s_fd;
- }
- }
- if(select(maxfd + 1, &lfdset, (fd_set*) 0, (fd_set*) 0, (struct timeval*) 0) < 0) {
- if(errno == EINTR || errno == EAGAIN) {
- continue;
- }
- syslog(LOG_CRIT, "select - %m");
- perror("select");
- exit(1);
- }
- is_ssl= 0;
- conn_port = port;
- if(do_ssl) {
- if(sslPort == 0) {
- is_ssl= 1;
- } else if(listen4s_fd != -1 && FD_ISSET(listen4s_fd, &lfdset)) {
- is_ssl = 1;
- conn_port = sslPort;
- } else if(listen6s_fd != -1 && FD_ISSET(listen6s_fd, &lfdset)) {
- is_ssl = 1;
- conn_port = sslPort;
- }
- }
- sz = sizeof(usa);
- if(listen4_fd != -1 && FD_ISSET(listen4_fd, &lfdset)) {
- conn_fd = accept(listen4_fd, &usa.sa, &sz);
- } else if(listen4s_fd != -1 && FD_ISSET(listen4s_fd, &lfdset)) {
- conn_fd = accept(listen4s_fd, &usa.sa, &sz);
- } else if(listen6_fd != -1 && FD_ISSET(listen6_fd, &lfdset)) {
- conn_fd = accept(listen6_fd, &usa.sa, &sz);
- } else if(listen6s_fd != -1 && FD_ISSET(listen6s_fd, &lfdset)) {
- conn_fd = accept(listen6s_fd, &usa.sa, &sz);
- } else {
- syslog(LOG_CRIT, "select failure");
- (void) fprintf(stderr, "%s: select failure\n", argv0);
- exit(1);
- }
- if(conn_fd < 0) {
- if(errno == EINTR || errno == EAGAIN) {
- continue;
- }
- #ifdef EPROTO
- if(errno == EPROTO) {
- continue;
- }
- #endif
- syslog(LOG_CRIT, "accept - %m");
- perror("accept");
- exit(1);
- }
- r = fork();
- if(r < 0) {
- syslog(LOG_CRIT, "fork - %m");
- perror("fork");
- exit(1);
- }
- if(r == 0) {
- client_addr = usa;
- if(listen4_fd != -1) {
- (void) close(listen4_fd);
- }
- if(listen4s_fd != -1) {
- (void) close(listen4s_fd);
- }
- if(listen6_fd != -1) {
- (void) close(listen6_fd);
- }
- if(listen6s_fd != -1) {
- (void) close(listen6s_fd);
- }
- handle_request(is_ssl, conn_port);
- exit(0);
- }
- (void) close(conn_fd);
- }
- }
-
- static char** make_argp(void) {
- char** argp;
- int argn;
- char* cp1;
- char* cp2;
-
- argp = (char**) malloc((strlen(query) + 2) * sizeof(char*));
- if(argp == (char**) 0) {
- return (char**) 0;
- }
- argp[0] = strrchr(file, '/');
- if(argp[0] != (char*) 0) {
- ++argp[0];
- } else {
- argp[0] = file;
- }
- argn = 1;
- if(strchr(query, '=') == (char*) 0) {
- for(cp1 = cp2 = query; *cp2 != '\0'; ++cp2) {
- if(*cp2 == '+') {
- *cp2 = '\0';
- strdecode(cp1, cp1);
- argp[argn++] = cp1;
- cp1 = cp2 + 1;
- }
- }
- if(cp2 != cp1) {
- strdecode(cp1, cp1);
- argp[argn++] = cp1;
- }
- }
- argp[argn] = (char*) 0;
- return argp;
- }
-
- static char** make_envp(int is_ssl, unsigned short conn_port) {
- static char* envp[50];
- int envn;
- char* cp;
- char buf[256];
-
- envn = 0;
- envp[envn++] = build_env("PATH=%s", CGI_PATH);
- envp[envn++] = build_env("LD_LIBRARY_PATH=%s", CGI_LD_LIBRARY_PATH);
- envp[envn++] = build_env("SERVER_SOFTWARE=%s", SERVER_SOFTWARE);
- envp[envn++] = build_env("WWW_LANGUAGE=%s", language);
- cp = hostname;
- if(cp != (char*) 0) {
- envp[envn++] = build_env("SERVER_NAME=%s", cp);
- }
- envp[envn++] = "GATEWAY_INTERFACE=CGI/1.1";
- envp[envn++] = "SERVER_PROTOCOL=HTTP/1.0";
- (void) snprintf(buf, sizeof(buf), "%d", (int) conn_port);
- envp[envn++] = build_env("SERVER_PORT=%s", buf);
- envp[envn++] = build_env("REQUEST_METHOD=%s", get_method_str(method));
- envp[envn++] = build_env("SCRIPT_NAME=%s", path);
- if(pathinfo != (char*) 0) {
- envp[envn++] = build_env("PATH_INFO=/%s", pathinfo);
- (void) snprintf(buf, sizeof(buf), "%s%s", cwd, pathinfo);
- envp[envn++] = build_env("PATH_TRANSLATED=%s", buf);
- }
- if(query[0] != '\0') {
- envp[envn++] = build_env("QUERY_STRING=%s", query);
- }
- envp[envn++] = build_env("REMOTE_ADDR=%s", ntoa(&client_addr));
- if(referer[0] != '\0') {
- envp[envn++] = build_env("HTTP_REFERER=%s", referer);
- }
- if(useragent[0] != '\0') {
- envp[envn++] = build_env("HTTP_USER_AGENT=%s", useragent);
- }
- if(cookie != (char*) 0) {
- envp[envn++] = build_env("HTTP_COOKIE=%s", cookie);
- }
- if(host != (char*) 0) {
- envp[envn++] = build_env("HTTP_HOST=%s", host);
- }
- if(content_type != (char*) 0) {
- envp[envn++] = build_env("CONTENT_TYPE=%s", content_type);
- }
- if(content_length != -1) {
- (void) snprintf(buf, sizeof(buf), "%lu", (unsigned long) content_length);
- envp[envn++] = build_env("CONTENT_LENGTH=%s", buf);
- }
- if(remoteuser != (char*) 0) {
- envp[envn++] = build_env("REMOTE_USER=%s", remoteuser);
- }
- if(authorization != (char*) 0) {
- envp[envn++] = build_env("AUTH_TYPE=%s", "Basic");
- }
- if(getenv("TZ") != (char*) 0) {
- envp[envn++] = build_env("TZ=%s", getenv("TZ"));
- }
- envp[envn] = (char*) 0;
- return envp;
- }
-
- static void make_log_entry(void) {
- char* ru;
- char url[500];
- char bytes_str[40];
- time_t now;
- struct tm* t;
- const char* cernfmt_nozone = "%d/%b/%Y:%H:%M:%S";
- char date_nozone[100];
- int zone;
- char sign;
- char date[100];
-
- if(logfp == (FILE*) 0) {
- return;
- }
- if(protocol == (char*) 0) {
- protocol = "UNKNOWN";
- }
- if(path == (char*) 0) {
- path = "";
- }
- if(remoteuser != (char*) 0) {
- ru = remoteuser;
- } else {
- ru = "-";
- }
- now = time((time_t*) 0);
- (void) snprintf(url, sizeof(url), "%s", path);
- if(bytes >= 0) {
- (void) snprintf(bytes_str, sizeof(bytes_str), "%lld", (long long int) bytes );
- } else {
- (void) strcpy(bytes_str, "-");
- }
- t = localtime(&now);
- (void) strftime(date_nozone, sizeof(date_nozone), cernfmt_nozone, t);
- zone = t->tm_gmtoff / 60L;
- if(zone >= 0) {
- sign = '+';
- } else {
- sign = '-';
- zone = -zone;
- }
- zone = (zone / 60) * 100 + zone % 60;
- (void) snprintf(date, sizeof(date), "%s %c%04d", date_nozone, sign, zone);
- (void) fprintf(logfp, "%.80s - %.80s [%s] \"%.80s %.200s %.80s\" %d %s \"%.200s\" \"%.200s\"\n", ntoa(&client_addr), ru, date, get_method_str(method), url, protocol, status, bytes_str, referer, useragent);
- (void) fflush(logfp);
- }
-
- static ssize_t my_read(char* buf, size_t size, int is_ssl) {
- if(is_ssl) {
- return SSL_read(ssl, buf, size);
- } else {
- return read(conn_fd, buf, size);
- }
- }
-
- static ssize_t my_write(char* buf, size_t size, int is_ssl) {
- if(is_ssl) {
- return SSL_write(ssl, buf, size);
- } else {
- return write(conn_fd, buf, size);
- }
- }
-
- static void no_value_required(char* name, char* value) {
- if(value != (char*) 0) {
- (void) fprintf(stderr, "%s: no value required for %s option\n", argv0, name);
- exit(1);
- }
- }
-
- static char* ntoa(usockaddr* usaP) {
- static char str[200];
-
- if(getnameinfo(&usaP->sa, sockaddr_len(usaP), str, sizeof(str), 0, 0, NI_NUMERICHOST) != 0) {
- str[0] = '?';
- str[1] = '\0';
- } else if(IN6_IS_ADDR_V4MAPPED(&usaP->sa_in6.sin6_addr) && strncmp(str, "::ffff:", 7) == 0) {
- (void) strcpy(str, &str[7]);
- }
- return str;
- }
-
- static void post_post_garbage_hack(int is_ssl) {
- char buf[2];
-
- if(is_ssl) {
- return;
- }
- set_ndelay(conn_fd);
- if(read(conn_fd, buf, sizeof(buf)) < 0) { ; };
- clear_ndelay(conn_fd);
- }
-
- static void read_config(char* filename) {
- FILE* fp;
- char line[10000];
- char* cp;
- char* cp2;
- char* name;
- char* value;
-
- fp = fopen(filename, "r");
- if(fp == (FILE*) 0) {
- syslog(LOG_CRIT, "%s - %m", filename);
- perror(filename);
- exit(1);
- }
- while(fgets(line, sizeof(line), fp) != (char*) 0) {
- if((cp = strchr(line, '#')) != (char*) 0) {
- *cp = '\0';
- }
- cp = line;
- cp += strspn(cp, " \t\012\015");
- while(*cp != '\0') {
- cp2 = cp + strcspn(cp, " \t\012\015");
- while(*cp2 == ' ' || *cp2 == '\t' || *cp2 == '\012' || *cp2 == '\015') {
- *cp2++ = '\0';
- }
- name = cp;
- value = strchr(name, '=');
- if(value != (char*) 0) {
- *value++ = '\0';
- }
- if(strcasecmp(name, "debug") == 0) {
- no_value_required(name, value);
- debug = 1;
- } else if(strcasecmp(name, "port") == 0) {
- value_required(name, value);
- port = (unsigned short) atoi(value);
- } else if(strcasecmp(name, "dir") == 0) {
- value_required(name, value);
- dir = e_strdup(value);
- } else if(strcasecmp(name, "data_dir") == 0) {
- value_required(name, value);
- data_dir = e_strdup(value);
- } else if(strcasecmp(name, "user") == 0) {
- value_required(name, value);
- user = e_strdup(value);
- } else if(strcasecmp(name, "cgipat") == 0) {
- value_required(name, value);
- cgi_pattern = e_strdup(value);
- } else if(strcasecmp(name, "urlpat") == 0) {
- value_required(name, value);
- url_pattern = e_strdup(value);
- } else if(strcasecmp(name, "noemptyreferers") == 0) {
- value_required(name, value);
- no_empty_referers = 1;
- } else if(strcasecmp(name, "localpat") == 0) {
- value_required(name, value);
- local_pattern = e_strdup(value);
- } else if(strcasecmp(name, "host") == 0) {
- value_required(name, value);
- hostname = e_strdup(value);
- } else if(strcasecmp(name, "logfile") == 0) {
- value_required(name, value);
- logfile = e_strdup(value);
- } else if(strcasecmp(name, "pidfile") == 0) {
- value_required(name, value);
- pidfile = e_strdup(value);
- } else if(strcasecmp(name, "charset") == 0) {
- value_required(name, value);
- charset = e_strdup(value);
- } else if(strcasecmp(name, "p3p") == 0) {
- value_required(name, value);
- p3p = e_strdup(value);
- } else if(strcasecmp(name, "max_age") == 0) {
- value_required(name, value);
- max_age = atoi(value);
- } else if(strcasecmp(name, "default_realm_name") == 0) {
- value_required(name, value);
- defaultRealmName = e_strdup(value);
- } else if(strcasecmp(name, "default_realm_password_file") == 0) {
- value_required(name, value);
- defaultRealmPasswordFile = e_strdup(value);
- } else if(strcasecmp(name, "default_page_file") == 0) {
- value_required(name, value);
- defaultPageFile = e_strdup(value);
- } else if(strcasecmp(name, "page_not_found_file") == 0) {
- value_required(name, value);
- pageNotFoundFile = e_strdup(value);
- } else if(strcasecmp(name, "allow_directory_listing") == 0) {
- value_required(name, value);
- if(strcmp(value, "1") == 0 || strcmp(value, "true") == 0 || strcmp(value, "TRUE") == 0 || strcmp(value, "yes") == 0 || strcmp(value, "YES") == 0) {
- allowDirectoryListing = 1;
- } else {
- allowDirectoryListing = 0;
- }
- } else if(strcasecmp(name, "ssl") == 0) {
- no_value_required(name, value);
- do_ssl = 1;
- } else if(strcasecmp(name, "certfile") == 0) {
- value_required(name, value);
- certfile = e_strdup(value);
- } else if(strcasecmp(name, "cipher") == 0) {
- value_required(name, value);
- cipher = e_strdup(value);
- } else {
- (void) fprintf(stderr, "%s: unknown config option '%s'\n", argv0, name);
- exit(1);
- }
- cp = cp2;
- cp += strspn(cp, " \t\012\015");
- }
- }
- (void) fclose(fp);
- }
-
- static int really_check_referer(void) {
- char* cp1;
- char* cp2;
- char* cp3;
- char* refhost;
- char *lp;
-
- if(referer == (char*) 0 || referer[0] == '\0' || (cp1 = strstr(referer, "//")) == (char*) 0) {
- if(no_empty_referers && match(url_pattern, path)) {
- return 0;
- } else {
- return 1;
- }
- }
- cp1 += 2;
- for(cp2 = cp1; *cp2 != '/' && *cp2 != ':' && *cp2 != '\0'; ++cp2) {
- continue;
- }
- refhost = (char*) e_malloc(cp2 - cp1 + 1);
- for(cp3 = refhost; cp1 < cp2; ++cp1, ++cp3) {
- if(isupper(*cp1)) {
- *cp3 = tolower(*cp1);
- } else {
- *cp3 = *cp1;
- }
- }
- *cp3 = '\0';
- if(local_pattern != (char*) 0) {
- lp = local_pattern;
- } else {
- lp = hostname;
- if(lp == (char*) 0) {
- return 1;
- }
- }
- if(!match(lp, refhost) && match(url_pattern, path)) {
- return 0;
- } else {
- return 1;
- }
- }
-
- static void reopen_logfile(void) {
- if(logfp != (FILE*) 0) {
- (void) fclose(logfp);
- logfp = (FILE*) 0;
- }
- if(logfile != (char*) 0) {
- syslog(LOG_NOTICE, "re-opening logfile");
- logfp = fopen(logfile, "a");
- if(logfp == (FILE*) 0) {
- syslog(LOG_CRIT, "%s - %m", logfile);
- perror(logfile);
- exit(1);
- }
- }
- }
-
- static void send_authenticate(char* realm, int is_ssl) {
- char header[10000];
-
- (void) snprintf(header, sizeof(header), "WWW-Authenticate: Basic realm=\"%s\"", realm);
- send_error(401, "Unauthorized", header, "Authorization required.", is_ssl);
- }
-
- static void send_error(int s, char* title, char* extra_header, char* text, int is_ssl) {
- add_headers(s, title, extra_header, "", "text/html; charset=%s", (off_t) -1, (time_t) -1);
- send_error_body(s, title, text);
- send_error_tail();
- send_response(is_ssl);
- SSL_free(ssl);
- exit(1);
- }
-
- static void send_error_body(int s, char* title, char* text) {
- char filename[1000];
- char buf[10000];
- int buflen;
-
- (void) snprintf(filename, sizeof(filename), "%s/err%d.html", ERR_DIR, s);
- if(send_error_file(filename)) {
- return;
- }
- buflen = snprintf(buf, sizeof(buf), "<html>\n<head><title>Error %d - %s</title></head>\n<body bgcolor=\"#cc9999\" text=\"#000000\">\n<h2>Error %d</h2>\n", s, title, s);
- add_to_response(buf, buflen);
- buflen = snprintf(buf, sizeof(buf), "%s\n", text);
- add_to_response(buf, buflen);
- }
-
- static int send_error_file(char* filename) {
- FILE* fp;
- char buf[1000];
- size_t r;
-
- fp = fopen(filename, "r");
- if(fp == (FILE*) 0) {
- return 0;
- }
- for(;;) {
- r = fread(buf, 1, sizeof(buf), fp);
- if(r == 0) {
- break;
- }
- add_to_response(buf, r);
- }
- (void) fclose(fp);
- return 1;
- }
-
- static void send_error_tail(void) {
- char buf[500];
- int buflen;
-
- if(match("**MSIE**", useragent)) {
- int n;
- buflen = snprintf(buf, sizeof(buf), "<!--\n");
- add_to_response(buf, buflen);
- for(n = 0; n < 6; ++n) {
- buflen = snprintf(buf, sizeof(buf), "Padding so that MSIE deigns to show this error instead of its own canned one.\n");
- add_to_response(buf, buflen);
- }
- buflen = snprintf(buf, sizeof(buf), "-->\n");
- add_to_response(buf, buflen);
- }
- buflen = snprintf(buf, sizeof(buf), "<hr>\n%s\n</body>\n</html>\n", SERVER_SOFTWARE);
- add_to_response(buf, buflen);
- }
-
- static void send_redirect(char* extra_header, char* hostname, char* new_location, int is_ssl) {
- int extra_length = 0;
- char extra_header_buf[5000];
- const char *sep = new_location[0] == '/' ? "" : "/";
- const char *proto = is_ssl == 1 ? "https://" : "http://";
-
- extra_header = extra_header == NULL ? "" : extra_header;
- if(strcmp(extra_header, "") == 0) {
- sprintf(extra_header_buf, "Location: %s%s%s%s", proto, hostname, sep, new_location);
- } else {
- sprintf(extra_header_buf, "%s\r\nLocation: %s%s%s%s", extra_header, proto, hostname, sep, new_location);
- }
- add_headers(301, "Moved Permanently", extra_header_buf, "", "text/html; charset=%s", (off_t) -1, (time_t) -1);
- send_error_body(301, "Moved Permanently", "Moved Permanently");
- send_error_tail();
- send_response(is_ssl);
- SSL_free(ssl);
- exit(1);
- }
-
- static void send_response(is_ssl) {
- (void) my_write(response, response_len, is_ssl);
- }
-
- static void send_via_write(int fd, off_t size, int is_ssl) {
- if(size <= SIZE_T_MAX) {
- size_t size_size = (size_t) size;
- void* ptr = mmap(0, size_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if(ptr != (void*) -1) {
- (void) my_write(ptr, size_size, is_ssl);
- (void) munmap(ptr, size_size);
- }
- #ifdef MADV_SEQUENTIAL
- (void) madvise(ptr, size_size, MADV_SEQUENTIAL);
- #endif
- } else {
- char buf[30000];
- ssize_t r, r2;
- for(;;) {
- r = read(fd, buf, sizeof(buf));
- if(r < 0 && (errno == EINTR || errno == EAGAIN)) {
- sleep(1);
- continue;
- }
- if(r <= 0) {
- return;
- }
- for(;;) {
- r2 = my_write(buf, r, is_ssl);
- if(r2 < 0 && (errno == EINTR || errno == EAGAIN)) {
- sleep(1);
- continue;
- }
- if(r2 != r) {
- return;
- }
- break;
- }
- }
- }
- }
-
- static void set_ndelay(int fd) {
- int flags, newflags;
-
- flags = fcntl(fd, F_GETFL, 0);
- if(flags != -1) {
- newflags = flags | (int) O_NDELAY;
- if(newflags != flags) {
- (void) fcntl(fd, F_SETFL, newflags);
- }
- }
- }
-
- static int sockaddr_check(usockaddr* usaP) {
- switch (usaP->sa.sa_family) {
- case AF_INET:
- return 1;
- case AF_INET6:
- return 1;
- default:
- return 0;
- }
- }
-
- static size_t sockaddr_len(usockaddr* usaP) {
- switch(usaP->sa.sa_family) {
- case AF_INET:
- return sizeof(struct sockaddr_in);
- case AF_INET6:
- return sizeof(struct sockaddr_in6);
- default:
- return 0;
- }
- }
-
- static void start_request(void) {
- request_size = 0;
- request_idx = 0;
- }
-
- static void start_response(void) {
- response_size = 0;
- }
-
- static void strdecode(char* to, char* from) {
- for(; *from != '\0'; ++to, ++from) {
- if(from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2])) {
- *to = hexit(from[1]) * 16 + hexit(from[2]);
- from += 2;
- } else {
- *to = *from;
- }
- }
- *to = '\0';
- }
-
- static void strencode(char* to, size_t tosize, const char* from) {
- int tolen;
-
- for(tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from) {
- if(isalnum(*from) || strchr("/_.-~", *from) != (char*) 0) {
- *to = *from;
- ++to;
- ++tolen;
- } else {
- (void) sprintf(to, "%%%02x", (int) *from & 0xff);
- to += 3;
- tolen += 3;
- }
- }
- *to = '\0';
- }
-
- static void usage(void) {
- (void) fprintf(stderr, "Usage: %s [-C configfile] [-D] [-S use ssl, if no ssl port is specified all connections will be SSL] [-E certfile] [-SP ssl port] [-Y cipher] [-p port] [-d dir] [-dd data_dir] [-c cgipat] [-u user] [-h hostname] [-l logfile] [-i pidfile] [-T charset] [-L language] [-P P3P] [-M maxage] [-DRN default realm name] [-DRP default realm password file] [-DPF default page file] [-PNF Page to load when 404 Not Found error occurs] \n", argv0);
- exit(1);
- }
-
- static void value_required(char* name, char* value) {
- if(value == (char*) 0) {
- (void) fprintf(stderr, "%s: value required for %s option\n", argv0, name);
- exit(1);
- }
- }
|