diff -Naur awhttpd/aw3.h axTLS/httpd/awhttpd/aw3.h --- awhttpd/aw3.h 2005-01-23 13:17:14.000000000 +1000 +++ axTLS/httpd/awhttpd/aw3.h 2006-11-15 15:09:14.196258200 +1000 @@ -7,17 +7,16 @@ */ -#include -#include -#include -#include -#include +#include "os_port.h" +#include "ssl.h" #define BACKLOG 15 #define VERSION "3.0.7" +#ifdef CONFIG_HTTP_HAS_IPV6 #define HAVE_IPV6 +#endif #define MAXFILEPATH 1024 #define MAXIPLEN 45 @@ -26,6 +25,7 @@ #define BLOCKSIZE 4096 #define INITIAL_CONNECTION_SLOTS 10 +#define CONFIG_HTTP_DEFAULT_SSL_OPTIONS 0 #define STATE_WANT_TO_READ_HEAD 1 #define STATE_WANT_TO_SEND_HEAD 2 @@ -37,7 +37,6 @@ #define TYPE_HEAD 1 #define TYPE_POST 2 - struct connstruct { struct connstruct *next; @@ -46,29 +45,43 @@ int networkdesc; int filedesc; - DIR *dirp; - int timeout; +#if defined(CONFIG_HTTP_DIRECTORIES) +#ifdef WIN32 + HANDLE dirp; + WIN32_FIND_DATA file_data; +#else + DIR *dirp; +#endif +#endif + time_t timeout; char ip[MAXIPLEN]; - char actualfile[MAXREQUESTLENGTH]; char filereq[MAXREQUESTLENGTH]; +#if defined(CONFIG_HTTP_HAS_CGI) char cgiargs[MAXREQUESTLENGTH]; char cgiscriptinfo[MAXREQUESTLENGTH]; char cgipathinfo[MAXREQUESTLENGTH]; +#endif char virtualhostreq[MAXREQUESTLENGTH]; int numbytes; - long offset; char databuf[BLOCKSIZE]; + unsigned char is_ssl; + unsigned char close_when_done; + unsigned char modified_since; }; struct serverstruct { struct serverstruct *next; int sd; + int is_ssl; +#ifdef CONFIG_HTTP_HAS_SSL + SSLCTX *ssl_ctx; +#endif }; @@ -96,28 +109,13 @@ // Conf global prototypes -extern int usevirtualhosts; extern char *webroot; extern int allowdirectorylisting; extern int allowcgi; extern int permcheck; -extern int maxusers; -extern int usertimeout; -extern int initialslots; -extern char *quote; -extern int initialslots; - -extern int numusers; - - -// Useful macros -#define istimedout(tp,ct) ((ct) > (tp)->timeout) -#define updatetimeout(tp,ct) ((tp)->timeout = (ct)+usertimeout) - - // conn.c prototypes -void addconnection(int sd, char *ip); +void addconnection(int sd, char *ip, int is_ssl); void removeconnection(struct connstruct *cn); @@ -129,49 +127,47 @@ void procsendhead(struct connstruct *cn); void procreadfile(struct connstruct *cn); void procsendfile(struct connstruct *cn); +int special_write(struct connstruct *cn, const uint8_t *buf, size_t count); // net.c prototypes void addtoservers(int sd); -void selectloop(); +void selectloop(void); // socket.c prototypes -int pollsocket(int sd, long ustimeout); -void handlenewconnection(int listenfd); +void handlenewconnection(int listenfd, int is_ssl); int openlistener(int port); int openlistener6(int port); // errors.c prototypes -void send505(int sd, char *reason); void send404(struct connstruct *cn); void send301(struct connstruct *cn); // misc.c prototypes -void nada(); -void die(); -void reaper(); +void nada(int sigtype); +void die(int sigtype); +void reaper(int sigtype); void stripcrlf(char *p); char *my_strncpy(char *dest, const char *src, size_t n); #ifndef __HAVE_ARCH_STRNLEN size_t strnlen ( const char * str, size_t maxlen ); #endif int iscgi(char *fn); -int split(char *tp, char *sp[], int maxwords, char sc); -int confsplit(char *tp, char *sp[], int maxwords); +void split(char *tp, char *sp[], int maxwords, char sc); int sanitizefile(char *buf); int sanitizehost(char *buf); void buildactualfile(struct connstruct *cn); int issockwriteable(int sd); int isdir(char *name); -void status(); int trycgi_withpathinfo(struct connstruct *cn); // mime_types.c prototypes -char *getmimetype(char *fn); +void mime_init(void); +const char *getmimetype(const char *fn); // urldecode.c prototypes @@ -188,7 +184,6 @@ // conf.c prototypes -void defaultconfvals(); void procconf(char *filename); @@ -202,4 +197,4 @@ // main.c prototypes -void initlists(); +void initlists(void); diff -Naur awhttpd/cgi.c axTLS/httpd/awhttpd/cgi.c --- awhttpd/cgi.c 2005-06-04 14:09:52.000000000 +1000 +++ axTLS/httpd/awhttpd/cgi.c 2006-11-15 15:09:14.211883700 +1000 @@ -7,93 +7,46 @@ */ -#include #include #include -#include +#include #include "aw3.h" +#if defined(CONFIG_HTTP_HAS_CGI) void addcgiext(char *tp) { struct cgiextstruct *ex; ex = (struct cgiextstruct *) malloc(sizeof(struct cgiextstruct)); - if (ex == NULL) { - fprintf(stderr, "Serious memory error...\n"); - exit(0); - } - ex->ext = strdup(tp); - if (ex->ext == NULL) { - fprintf(stderr, "Serious memory error...\n"); - exit(0); - } - ex->next = cgiexts; cgiexts = ex; - - return; - -} - - - -void gensysenv(struct connstruct *cn) { - - #ifndef LIMITEDCGI - - char buf[1024]; - - setenv("REMOTE_ADDR", cn->ip, 1); - - snprintf(buf, sizeof(buf), "%d", numusers); - setenv("AW_NUMUSERS", buf, 1); - - setenv("AW_VERSION", VERSION, 1); - - setenv("AW_QUOTE", quote, 1); - -/* Commented this out because (and this is ridiculous) PHP - doesn't seem to work with this variable specified - */ -/* - snprintf ( buf, sizeof(buf), "Anti-Web V%s (%s)", VERSION, quote ); - setenv("SERVER_SOFTWARE", buf, 1); -*/ - - setenv("SCRIPT_NAME", cn->cgiscriptinfo, 1); - - setenv("PATH_INFO", cn->cgipathinfo, 1); - - setenv("QUERY_STRING", cn->cgiargs, 1); - - return; - - #endif - } - - void proccgi(struct connstruct *cn, int has_pathinfo) { - int tpipe[2], fv; - char *myargs[3]; + int tpipe[2]; + char *myargs[5]; char buf[MAXREQUESTLENGTH]; - - snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: Anti-Web V%s (%s)\n%s", - VERSION, - quote, (cn->reqtype == TYPE_HEAD) ? "\n" : ""); - write(cn->networkdesc, buf, strlen(buf)); +#ifdef WIN32 + int tmp_stdout; +#else + int fv; +#endif + + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: Anti-Web V%s\n%s", + VERSION, (cn->reqtype == TYPE_HEAD) ? "\n" : ""); + special_write(cn, buf, strlen(buf)); if (cn->reqtype == TYPE_HEAD) { removeconnection(cn); return; } +#ifndef WIN32 if (pipe(tpipe) == -1) { removeconnection(cn); return; @@ -108,7 +61,8 @@ return; } - if (fv != 0) { + if (fv != 0) + { // Close the write descriptor close(tpipe[1]); cn->filedesc = tpipe[0]; @@ -132,19 +86,62 @@ close(tpipe[1]); myargs[0] = cn->actualfile; - myargs[1] = strdup(cn->cgiargs); + myargs[1] = cn->cgiargs; myargs[2] = NULL; - if (!has_pathinfo) - { - my_strncpy(cn->cgipathinfo, "/", MAXREQUESTLENGTH); - my_strncpy(cn->cgiscriptinfo, cn->filereq, MAXREQUESTLENGTH); - } - - gensysenv(cn); + if (!has_pathinfo) { + my_strncpy(cn->cgipathinfo, "/", MAXREQUESTLENGTH); + my_strncpy(cn->cgiscriptinfo, cn->filereq, MAXREQUESTLENGTH); + } execv(cn->actualfile, myargs); +#else /* WIN32 */ + if (_pipe(tpipe, 4096, O_BINARY| O_NOINHERIT) == -1) { + removeconnection(cn); + return; + } - exit(0); + myargs[0] = "sh"; + myargs[1] = "-c"; + myargs[2] = cn->actualfile; + myargs[3] = cn->cgiargs; + myargs[4] = NULL; + + /* convert all the forward slashes to back slashes */ + { + char *t = myargs[2]; + while ((t = strchr(t, '\\'))) + { + *t++ = '/'; + } + } + + tmp_stdout = _dup(_fileno(stdout)); + _dup2(tpipe[1], _fileno(stdout)); + close(tpipe[1]); + + /* change to suit execution method */ + if (spawnl(P_NOWAIT, "c:\\Program Files\\cygwin\\bin\\sh.exe", + myargs[0], myargs[1], myargs[2], myargs[3], myargs[4]) == -1) { + removeconnection(cn); + return; + } + + _dup2(tmp_stdout, _fileno(stdout)); + close(tmp_stdout); + cn->filedesc = tpipe[0]; + cn->state = STATE_WANT_TO_READ_FILE; + + for (;;) + { + procreadfile(cn); + if (cn->filedesc == -1) + break; + + procsendfile(cn); + usleep(200000); /* don't know why this delay makes it work (yet) */ + } +#endif } +#endif /* CONFIG_HTTP_HAS_CGI */ diff -Naur awhttpd/conf.c axTLS/httpd/awhttpd/conf.c --- awhttpd/conf.c 2005-06-04 14:09:52.000000000 +1000 +++ axTLS/httpd/awhttpd/conf.c 1970-01-01 10:00:00.000000000 +1000 @@ -1,265 +0,0 @@ -/* Anti-Web HTTPD */ -/* Hardcore Software */ -/* -This software is Copyright (C) 2001-2004 By Hardcore Software and -others. The software is distributed under the terms of the GNU General -Public License. See the file 'COPYING' for more details. -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include "aw3.h" - - - -// CONF GLOBALS: - -int usevirtualhosts; -char *webroot; -int allowdirectorylisting; -int allowcgi; -int permcheck; -int maxusers; -int usertimeout; -int initialslots; -char *quote; - -int numusers; - - - -void defaultconfvals() { - - usevirtualhosts = 0; - allowdirectorylisting = 0; - allowcgi = 0; - permcheck = 0; - maxusers = 500; - usertimeout = 5; - initialslots = 10; - quote = "Fear and loathing on the WWW"; - - // Not really conf stuff: - numusers = 0; - - return; - -} - - -void procconf(char *filename) { - - FILE *fp; - char buf[MAXREQUESTLENGTH]; - char *segs[10]; - int tp, err=0, warn=0; - - usevirtualhosts = 1; - - fp = fopen(filename, "r"); - - if (fp == NULL) { - fprintf(stderr, "ERROR: Unable to open conf file '%s'\n", filename); - exit(1); - } - - - while (fgets(buf, sizeof(buf), fp) != NULL) { - stripcrlf(buf); - - confsplit(buf, segs, 10); - - if (segs[0] == NULL) continue; - - if (segs[1] == NULL) { - fprintf(stderr, "ERR: Unknown command in '%s': '%s'\n", filename, segs[0]); - err++; - continue; - } - - - if (strcasecmp(segs[0], "listen") == 0) { - if (isdigit(*segs[1])) { - if ((tp=openlistener(atoi(segs[1]))) == -1) { - fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n", atoi(segs[1])); - err++; - continue; - } - - addtoservers(tp); - continue; - } - } - - if (strcasecmp(segs[0], "listen6") == 0) { - #ifdef HAVE_IPV6 - if (isdigit(*segs[1])) { - if ((tp=openlistener6(atoi(segs[1]))) == -1) { - fprintf(stderr, "ERR: Couldn't bind to port %d (IPv6)\n", atoi(segs[1])); - err++; - continue; - } - - addtoservers(tp); - continue; - } - #else - fprintf(stderr, "ERR: AW was compiled without IPv6 support!\n"); - err++; - continue; - #endif - } - - if (strcasecmp(segs[0], "maxusers") == 0) { - maxusers = tp = atoi(segs[1]); - if (tp < 1) { - fprintf(stderr, "ERR: Bad value for maxusers\n"); - err++; - } - if (tp < 10 || tp > 10000) { - fprintf(stderr, "WARN: Value for maxusers (%d) is not withing the recommended range\n", tp); - warn++; - } - continue; - } - - if (strcasecmp(segs[0], "usertimeout") == 0) { - usertimeout = tp = atoi(segs[1]); - if (tp < 1) { - fprintf(stderr, "ERR: Bad value for usertimeout\n"); - err++; - } - if (tp > 100) { - fprintf(stderr, "WARN: Value for usertimeout (%d) is not withing the recommended range\n", tp); - warn++; - } - continue; - } - - if (strcasecmp(segs[0], "initialslots") == 0) { - initialslots = tp = atoi(segs[1]); - if (tp < 1) { - fprintf(stderr, "ERR: Bad value for initialslots\n"); - err++; - } - continue; - } - - if (strcasecmp(segs[0], "directorylisting") == 0) { - if (strcasecmp(segs[1], "on") == 0) allowdirectorylisting = 1; - else if (strcasecmp(segs[1], "off") == 0) allowdirectorylisting = 0; - else { - fprintf(stderr, "ERR: Need on or off for directorylisting\n"); - err++; - } - continue; - } - - if (strcasecmp(segs[0], "cgi") == 0) { - if (strcasecmp(segs[1], "on") == 0) allowcgi = 1; - else if (strcasecmp(segs[1], "off") == 0) allowcgi = 0; - else { - fprintf(stderr, "ERR: Need on or off for cgi\n"); - err++; - } - continue; - } - - if (strcasecmp(segs[0], "cgiext") == 0) { - if (*(segs[1]) != '.' && *(segs[1]+1) != '\0') { - fprintf(stderr, "ERR: CGI extensions must start with a period and be at least 2 chars long\n"); - err++; - continue; - } - addcgiext(segs[1]); - continue; - } - - if (strcasecmp(segs[0], "addindex") == 0) { - if (*(segs[1]) == '.') { - fprintf(stderr, "ERR: Index files can't start with a dot\n"); - err++; - continue; - } - addindex(segs[1]); - continue; - } - - if (strcasecmp(segs[0], "permcheck") == 0) { - if (strcasecmp(segs[1], "on") == 0) permcheck = 1; - else if (strcasecmp(segs[1], "off") == 0) permcheck = 0; - else { - fprintf(stderr, "ERR: Need on or off for permcheck\n"); - err++; - } - continue; - } - - if (strcasecmp(segs[0], "dropto") == 0) { - struct passwd *bl; - - if ((bl = getpwnam(segs[1])) == NULL) { - fprintf(stderr, "ERR: Unable to look up user '%s' to drop privileges\n", segs[1]); - err++; - } else { - if (setgid(bl->pw_gid) != 0) { - fprintf(stderr, "WARN: Unable to drop GID to %d\n", bl->pw_gid); - warn++; - } - if (setuid(bl->pw_uid) != 0) { - fprintf(stderr, "WARN: Unable to drop UID to %d\n", bl->pw_uid); - warn++; - } - } - continue; - } - - if (strcasecmp(segs[0], "quote") == 0) { - quote = strdup(segs[1]); - continue; - } - - - if (segs[2] == NULL) { - fprintf(stderr, "ERR: Unknown command in '%s': '%s'\n", filename, segs[0]); - err++; - continue; - } - - - // Otherwise: - - fprintf(stderr, "ERR: Unknown command in '%s': '%s'\n", filename, segs[0]); - err++; - continue; - - } - - - if (initialslots > maxusers) { - fprintf(stderr, "ERR: initialslots is greater than maxusers!\n"); - err++; - } - - - if (warn) { - fprintf(stderr, "Alert! %d warnings!\n", warn); - } - - if (err) { - fprintf(stderr, "Unable to start: %d errors!\n", err); - exit(1); - } - - fclose(fp); - - return; - -} diff -Naur awhttpd/conn.c axTLS/httpd/awhttpd/conn.c --- awhttpd/conn.c 2004-12-07 16:11:02.000000000 +1000 +++ axTLS/httpd/awhttpd/conn.c 2006-11-15 15:09:14.243134700 +1000 @@ -9,26 +9,16 @@ #include #include -#include -#include #include - #include "aw3.h" - -void addconnection(int sd, char *ip) { +void addconnection(int sd, char *ip, int is_ssl) { struct connstruct *tp; // Get ourselves a connstruct if (freeconns == NULL) { tp = (struct connstruct *) malloc(sizeof(struct connstruct)); - if (tp == NULL) { - send505(sd, "Out of memory"); - // removeconnection() should be used normally - close(sd); - return; - } } else { tp = freeconns; freeconns = tp->next; @@ -39,12 +29,21 @@ usedconns = tp; tp->networkdesc = sd; +#ifdef CONFIG_HTTP_HAS_SSL + if (is_ssl) + ssl_server_new(servers->ssl_ctx, sd); +#endif tp->filedesc = -1; +#if defined(CONFIG_HTTP_HAS_DIRECTORIES) tp->dirp = NULL; +#endif + tp->is_ssl = is_ssl; *(tp->actualfile) = '\0'; *(tp->filereq) = '\0'; +#if defined(CONFIG_HTTP_HAS_CGI) *(tp->cgiargs) = '\0'; +#endif *(tp->virtualhostreq) = '\0'; tp->state = STATE_WANT_TO_READ_HEAD; @@ -52,21 +51,16 @@ my_strncpy(tp->ip, ip, MAXIPLEN); - tp->offset = -1; - - numusers++; - - updatetimeout(tp, time(NULL)); + tp->close_when_done = 0; + tp->modified_since = 0; + tp->timeout = time(NULL) + CONFIG_HTTP_TIMEOUT; return; } -// Remove cn from the used list -// FIXME: This O(N) operation could be avoided if we used -// doubly linked lists... void removeconnection(struct connstruct *cn) { struct connstruct *tp; @@ -95,12 +89,21 @@ freeconns = cn; // Close it all down - if (cn->networkdesc != -1) close(cn->networkdesc); + if (cn->networkdesc != -1) { +#ifdef CONFIG_HTTP_HAS_SSL + if (cn->is_ssl) { + ssl_free(ssl_find(servers->ssl_ctx, cn->networkdesc)); + } +#endif + SOCKET_CLOSE(cn->networkdesc); + } if (cn->filedesc != -1) close(cn->filedesc); - if (cn->dirp != NULL) closedir(cn->dirp); - - numusers--; - - return; - +#if defined(CONFIG_HTTP_HAS_DIRECTORIES) + if (cn->dirp != NULL) +#ifdef WIN32 + FindClose(cn->dirp); +#else + closedir(cn->dirp); +#endif +#endif } diff -Naur awhttpd/errors.c axTLS/httpd/awhttpd/errors.c --- awhttpd/errors.c 2005-01-23 06:49:29.000000000 +1000 +++ axTLS/httpd/awhttpd/errors.c 2006-11-15 15:09:14.258760200 +1000 @@ -8,7 +8,6 @@ #include -#include #include #include "aw3.h" @@ -20,7 +19,7 @@ snprintf(buf, sizeof(buf), "HTTP/1.1 301 Moved Permanently\nLocation: %s/\n\n\n\n301 Moved Permanently\n\n

Moved Permanently

\nThe document has moved here.

\n


\n\n", cn->filereq, cn->filereq); - write(cn->networkdesc, buf, strlen(buf)); + special_write(cn, buf, strlen(buf)); return; @@ -34,21 +33,7 @@ snprintf(buf, sizeof(buf), "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n\n404 Not Found

It ain't there my friend. (404 Not Found)

\n

Anti-Web HTTPD - Take back some simplicity.\n\n"); - write(cn->networkdesc, buf, strlen(buf)); - - return; - -} - - - -void send505(int sd, char *reason) { - - char buf[1024]; - - snprintf(buf, sizeof(buf), "HTTP/1.0 505 Server Error\nContent-Type: text/html\n\n\n505 Internal Server Error

Internal Server Error: %s

\n

Anti-Web HTTPD - Take back some simplicity.\n\n", reason); - - write(sd, buf, strlen(buf)); + special_write(cn, buf, strlen(buf)); return; diff -Naur awhttpd/index.c axTLS/httpd/awhttpd/index.c --- awhttpd/index.c 2005-06-04 14:09:52.000000000 +1000 +++ axTLS/httpd/awhttpd/index.c 2006-11-15 15:09:14.258760200 +1000 @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "aw3.h" @@ -22,20 +21,9 @@ struct indexstruct *ex; ex = (struct indexstruct *) malloc(sizeof(struct indexstruct)); - if (ex == NULL) { - fprintf(stderr, "Serious memory error...\n"); - exit(1); - } - ex->name = strdup(tp); - if (ex->name == NULL) { - fprintf(stderr, "Serious memory error...\n"); - exit(1); - } - ex->next = indexlist; indexlist = ex; - return; } @@ -52,7 +40,13 @@ tp = indexlist; while(tp != NULL) { - snprintf(tbuf, sizeof(tbuf), "%s%s", cn->actualfile, tp->name); + sprintf(tbuf, "%s%s%s", cn->actualfile, +#ifdef WIN32 + "\\", +#else + "/", +#endif + tp->name); if (stat(tbuf, stp) != -1) { my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH); diff -Naur awhttpd/main.c axTLS/httpd/awhttpd/main.c --- awhttpd/main.c 2005-06-04 14:09:52.000000000 +1000 +++ axTLS/httpd/awhttpd/main.c 2006-11-21 16:30:37.093363800 +1000 @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "aw3.h" @@ -21,10 +20,42 @@ struct serverstruct *servers; struct connstruct *usedconns; struct connstruct *freeconns; +#if defined(CONFIG_HTTP_HAS_CGI) struct cgiextstruct *cgiexts; +#endif struct indexstruct *indexlist; +char *webroot = CONFIG_HTTP_WEBROOT; +/* clean up memory for valgrind */ +static void sigint_cleanup(int sig) +{ + struct serverstruct *sp; + struct connstruct *tp; + int i; + + while(servers != NULL) { +#ifdef CONFIG_HTTP_HAS_SSL + if (servers->is_ssl) + ssl_ctx_free(servers->ssl_ctx); +#endif + sp = servers->next; + free(servers); + servers = sp; + } + free(indexlist->name); + free(indexlist); + for(i=0; i< INITIAL_CONNECTION_SLOTS; i++) { + if (freeconns == NULL) + break; + + tp = freeconns->next; + free(freeconns); + freeconns = tp; + } + + exit(0); +} void initlists() { int i; @@ -33,108 +64,118 @@ servers = NULL; usedconns = NULL; freeconns = NULL; +#if defined(CONFIG_HTTP_HAS_CGI) cgiexts = NULL; +#endif indexlist = NULL; for(i=0; inext = tp; } } -void usage(char *cmline) { - fprintf(stderr, "Anti-Web V%s (C) 2001-2004 by Hardcore Software and others\n\n", VERSION); - - fprintf(stderr, " AW has 2 valid command lines (see README for details)\n\n"); - - fprintf(stderr, " %s \n", cmline); - fprintf(stderr, " The root of your HTML tree\n"); - fprintf(stderr, " The port to use\n\n"); - - fprintf(stderr, " %s \n", cmline); - fprintf(stderr, " /awhttpd.conf Conf file\n"); - fprintf(stderr, " /default/ Default HTML root\n"); - fprintf(stderr, " /example.com/ Zero or more virtual host directories\n"); - - exit(1); -} - - int main(int argc, char *argv[]) { - char buf[MAXREQUESTLENGTH]; - int pid, tp; - + int tp; +#if defined(CONFIG_HTTP_IS_DAEMON) + int pid; +#endif + +#ifdef WIN32 + WORD wVersionRequested = MAKEWORD(2,2); + WSADATA wsaData; + WSAStartup(wVersionRequested,&wsaData); +#endif + + mime_init(); initlists(); - - if (argc != 2 && argc != 3) usage(argv[0]); - - webroot = strdup(argv[1]); - tp = strlen(webroot); if (webroot[tp-1] == '/') webroot[tp-1] = '\0'; if (isdir(webroot) == 0) { +#ifdef CONFIG_HTTP_VERBOSE fprintf(stderr, "'%s' is not a directory\n", webroot); +#endif exit(1); } - defaultconfvals(); - - if (argc == 2) { - snprintf(buf, sizeof(buf), "%s/awhttpd.conf", webroot); - procconf(buf); - } else { - if ((tp=openlistener(atoi(argv[2]))) == -1) { - fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n", atoi(argv[2])); + if ((tp=openlistener(CONFIG_HTTP_PORT)) == -1) { +#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n", + CONFIG_HTTP_PORT); +#endif exit(1); - } + } addindex("index.html"); addtoservers(tp); - setgid(32767); - setuid(32767); - } - if (permcheck == 1) procpermcheck(webroot); +#ifndef WIN32 + if (getuid() == 0) + { + setgid(32767); + setuid(32767); + } +#endif + +#ifdef CONFIG_HTTP_HAS_SSL + if ((tp=openlistener(CONFIG_HTTP_HTTPS_PORT)) == -1) { +#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n", + CONFIG_HTTP_HTTPS_PORT); +#endif + exit(1); + } + + addtoservers(tp); + servers->ssl_ctx = ssl_ctx_new(CONFIG_HTTP_DEFAULT_SSL_OPTIONS, + CONFIG_HTTP_SESSION_CACHE_SIZE); + servers->is_ssl = 1; +#endif /* CONFIG_HTTP_HAS_SSL */ + +#if defined(CONFIG_HTTP_PERM_CHECK) + procpermcheck(webroot); +#endif +#if defined(CONFIG_HTTP_HAS_CGI) + addcgiext(CONFIG_HTTP_CGI_EXTENSION); +#endif +#if defined(CONFIG_HTTP_VERBOSE) + printf("awhttpd: listening on ports http:%d and https:%d\n", + CONFIG_HTTP_PORT, CONFIG_HTTP_HTTPS_PORT); + TTY_FLUSH(); +#endif +#if defined(CONFIG_HTTP_IS_DAEMON) pid = fork(); if(pid > 0) { - status(); exit(0); } else if(pid == -1) { +#ifdef CONFIG_HTTP_VERBOSE fprintf(stderr,"Anti-Web: Sorry, fork failed... Tough dice.\n"); +#endif exit(1); } setsid(); +#endif /* SIGNALS */ - signal(SIGINT, die); - signal(SIGQUIT, die); + signal(SIGINT, sigint_cleanup); signal(SIGTERM, die); +#if defined(CONFIG_HTTP_HAS_CGI) +#ifndef WIN32 signal(SIGCHLD, reaper); - - #ifndef SOLARIS - signal(SIGPIPE, nada); - #endif - - #ifdef SOLARIS - act.sa_handler = nada; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - - sigaction(SIGPIPE,&act,NULL); - #endif - +#endif +#endif +#ifndef WIN32 + signal(SIGQUIT, die); + signal(SIGPIPE, SIG_IGN); +#endif + selectloop(); return 0; diff -Naur awhttpd/mime_types.c axTLS/httpd/awhttpd/mime_types.c --- awhttpd/mime_types.c 2004-01-26 01:08:47.000000000 +1000 +++ axTLS/httpd/awhttpd/mime_types.c 2006-11-15 15:09:14.305636700 +1000 @@ -7,28 +7,21 @@ */ -/*Code from mini_httpd - small HTTP server -** -** Copyright C 1999,2000 by Jef Poskanzer . -*/ - -/* mini_httpd code adapted for Anti-Web by zas@norz.org */ -/* A couple TINY changes by Fractal */ - -// Reformatted for aw3 -fractal - -// FIXME: Ideally this code would use a binary search or a hash table... - - #include +#include +#include +#include +#include "os_port.h" -char mime_default[] = "text/plain"; +static const char mime_default[] = "text/plain"; -struct { - char *ext; - char *type; -} mime_table[] = { +typedef struct { + const char * const ext; + const char * const type; +} mime_table_t; + +static mime_table_t mime_table[] = { // Fundamentals { ".html", "text/html" }, @@ -160,21 +153,29 @@ }; +static int mime_cmp(const mime_table_t *t1, const mime_table_t *t2) +{ + return strcasecmp(t1->ext, t2->ext); +} -char *getmimetype(char *name) { - int namelen, extlen, i; - - namelen = strlen(name); - - for (i=0; i= namelen) continue; +const char *getmimetype(const char *name) { + mime_table_t *mime_type; - if (strcasecmp(name+(namelen-extlen), mime_table[i].ext) == 0) - return mime_table[i].type; - } + if ((name = strrchr(name, '.')) == NULL) + return mime_default; - return mime_default; + mime_type = bsearch(&name, mime_table, + sizeof(mime_table)/sizeof(mime_table_t), + sizeof(mime_table_t), + (int (*)(const void *, const void *))mime_cmp); + return mime_type == NULL ? mime_default : mime_type->type; } + diff -Naur awhttpd/misc.c axTLS/httpd/awhttpd/misc.c --- awhttpd/misc.c 2005-01-23 12:59:09.000000000 +1000 +++ axTLS/httpd/awhttpd/misc.c 2006-11-15 15:09:14.321262200 +1000 @@ -7,33 +7,33 @@ */ -#include #include #include #include -#include +#include #include #include -#include -#include -#include #include "aw3.h" -void nada() { } +void nada(int sigtype) { } -void die() { +void die(int sigtype) { exit(0); } -void reaper() { +#if defined(CONFIG_HTTP_HAS_CGI) +#ifndef WIN32 +void reaper(int sigtype) { wait3(NULL,WNOHANG,NULL); } +#endif +#endif void stripcrlf(char *p) { @@ -76,116 +76,6 @@ } #endif - -int iscgi(char *fn) { - - struct cgiextstruct *tp; - int fnlen, extlen; - - fnlen = strlen(fn); - tp = cgiexts; - - while (tp != NULL) { - extlen = strlen(tp->ext); - - if (strcasecmp(fn+(fnlen-extlen), tp->ext) == 0) - return 1; - - tp = tp->next; - } - - return 0; - -} - - - -int split(char *tp, char *sp[], int maxwords, char sc) { - - int i=0; - - while(1) { - /* Skip leading whitespace */ - while(*tp == sc) tp++; - - if (*tp == '\0') { - sp[i] = NULL; - break; - } - if (i==maxwords-2) { - sp[maxwords-2] = NULL; - break; - } - - sp[i] = tp; - - while(*tp != sc && *tp != '\0') tp++; - if (*tp == sc) *tp++ = '\0'; - i++; - - } - - return i; - -} - - - -int confsplit(char *tp, char *sp[], int maxwords) { - - int i; - - // Skip comments - i=0; - while (tp[i] != '\0' && tp[i] != '#') i++; - tp[i] = '\0'; - - i=0; - while(1) { - /* Skip leading whitespace */ - while(*tp == ' ') tp++; - - if (*tp == '\0') { - sp[i] = NULL; - break; - } - if (i==maxwords-2) { - sp[maxwords-2] = NULL; - break; - } - - if (*tp == '"') { - tp++; - - if (*tp == '"') { - tp++; - continue; - } - - sp[i] = tp; - - while(*tp != '"' && *tp != '\0') tp++; - if (*tp == '"') *tp++ = '\0'; - i++; - - } else { - sp[i] = tp; - - while(*tp != ' ' && *tp != '\0') tp++; - if (*tp == ' ') *tp++ = '\0'; - i++; - } - - } - - return i; - -} - - - - - int sanitizefile(char *buf) { int len,i; @@ -198,9 +88,6 @@ // Check for "/." : In other words, don't send files starting with a . // Notice, GOBBLES, that this includes ".." if (buf[i] == '/' && buf[i+1] == '.') return 0; - - // Give people a "hidden prefix" for hiding private files in the HTML tree - if (strncmp(buf+i, "/aw_", 4) == 0) return 0; } return 1; @@ -231,34 +118,33 @@ } - - void buildactualfile(struct connstruct *cn) { - char tpbuf[MAXREQUESTLENGTH]; - - if (usevirtualhosts) { - if (*(cn->virtualhostreq) == '\0') - my_strncpy(cn->virtualhostreq, "default", MAXREQUESTLENGTH); - - snprintf(tpbuf, sizeof(tpbuf), "%s/%s", webroot, cn->virtualhostreq); - if (isdir(tpbuf) == 0) { - my_strncpy(cn->virtualhostreq, "default", MAXREQUESTLENGTH); - } - } else { - *(cn->virtualhostreq) = '\0'; - } - - snprintf(cn->actualfile, MAXREQUESTLENGTH, "%s/%s%s", + snprintf(cn->actualfile, MAXREQUESTLENGTH, "%s%s", webroot, - cn->virtualhostreq, cn->filereq); + /* Add directory slash if not there */ + if (isdir(cn->actualfile) && + cn->actualfile[strlen(cn->actualfile)-1] != '/') + strcat(cn->actualfile, "/"); + +#ifdef WIN32 + /* convert all the forward slashes to back slashes */ + { + char *t = cn->actualfile; + while ((t = strchr(t, '/'))) + { + *t++ = '\\'; + } + } +#endif + return; } - +#if defined(CONFIG_HTTP_DIRECTORIES) int issockwriteable(int sd) { fd_set wfds; @@ -275,11 +161,11 @@ return FD_ISSET(sd, &wfds); } - +#endif int isdir(char *tpbuf) { - static struct stat st; + struct stat st; if (stat(tpbuf, &st) == -1) return 0; @@ -288,25 +174,52 @@ } +#if defined(CONFIG_HTTP_HAS_CGI) +int iscgi(char *fn) { + struct cgiextstruct *tp; + int fnlen, extlen; -// FIXME: Arg! This function is horrible! Rewrite it -void status() { + fnlen = strlen(fn); + tp = cgiexts; - int i; + while (tp != NULL) { + extlen = strlen(tp->ext); - fprintf(stdout," [*************************************************]\n"); - fprintf(stdout," [ Anti-Web V%-6s by Hardcore Software ]\n",VERSION); - fprintf(stdout," [*************************************************]\n"); - fprintf(stdout," [ DIRECTORY {%s}",webroot); - if(strlen(webroot)<35) - for(i=1;i<=35-strlen(webroot);i++) fprintf(stdout," "); - fprintf(stdout,"]\n"); - fprintf(stdout," [*************************************************]\n"); + if (strcasecmp(fn+(fnlen-extlen), tp->ext) == 0) + return 1; + + tp = tp->next; + } + + return 0; } +void split(char *tp, char *sp[], int maxwords, char sc) { + + int i=0; + while(1) { + /* Skip leading whitespace */ + while(*tp == sc) tp++; + + if (*tp == '\0') { + sp[i] = NULL; + break; + } + if (i==maxwords-2) { + sp[maxwords-2] = NULL; + break; + } + + sp[i] = tp; + + while(*tp != sc && *tp != '\0') tp++; + if (*tp == sc) *tp++ = '\0'; + i++; + } +} /* This function was originally written by Nicolas Benoit but I've rewritten some parts of it to work under @@ -329,7 +242,7 @@ while (fr_rs[i] != NULL) { snprintf(tpfile, sizeof(tpfile), "%s/%s%s", webroot, cn->virtualhostreq, fr_str); - if (iscgi(tpfile) && access(tpfile, X_OK) == 0 && isdir(tpfile) == 0) { + if (iscgi(tpfile) && isdir(tpfile) == 0) { /* We've found our CGI file! */ my_strncpy(cn->actualfile, tpfile, MAXREQUESTLENGTH); my_strncpy(cn->cgiscriptinfo, fr_str, MAXREQUESTLENGTH); @@ -349,3 +262,4 @@ *(cn->cgipathinfo) = '\0'; return -1; } +#endif diff -Naur awhttpd/net.c axTLS/httpd/awhttpd/net.c --- awhttpd/net.c 2005-06-04 14:09:52.000000000 +1000 +++ axTLS/httpd/awhttpd/net.c 2006-11-15 15:09:14.352513200 +1000 @@ -8,9 +8,7 @@ #include -#include #include -#include #include #include #include @@ -23,17 +21,10 @@ void addtoservers(int sd) { struct serverstruct *tp; - tp = (struct serverstruct *) malloc(sizeof(struct serverstruct)); - if (tp == NULL) { - fprintf(stderr, "Serious memory error...\n"); - exit(1); - } - + tp = (struct serverstruct *) calloc(1, sizeof(struct serverstruct)); tp->next = servers; tp->sd = sd; - servers = tp; - return; } @@ -64,7 +55,7 @@ currtime = time(NULL); while(tp != NULL) { - if (istimedout(tp, currtime)) { + if (currtime > tp->timeout) { to = tp; tp = tp->next; removeconnection(to); @@ -87,14 +78,15 @@ FD_SET(tp->networkdesc, &wfds); if (tp->networkdesc > wnum) wnum = tp->networkdesc; } +#if defined(CONFIG_HTTP_DIRECTORIES) if (tp->state == STATE_DOING_DIR) { FD_SET(tp->networkdesc, &wfds); if (tp->networkdesc > wnum) wnum = tp->networkdesc; } +#endif tp = tp->next; } - //active = select(4, &rfds, &wfds, NULL, NULL); active = select(wnum > rnum ? wnum+1 : rnum+1, rnum != -1 ? &rfds : NULL, wnum != -1 ? &wfds : NULL, @@ -104,7 +96,7 @@ sp = servers; while(active > 0 && sp != NULL) { if (FD_ISSET(sp->sd, &rfds)) { - handlenewconnection(sp->sd); + handlenewconnection(sp->sd, sp->is_ssl); active--; } sp = sp->next; @@ -112,41 +104,37 @@ // Handle the established sockets tp = usedconns; - currtime = time(NULL); while(active > 0 && tp != NULL) { to = tp; tp = tp->next; if (to->state == STATE_WANT_TO_READ_HEAD) if (FD_ISSET(to->networkdesc, &rfds)) { - updatetimeout(to, currtime); active--; procreadhead(to); } if (to->state == STATE_WANT_TO_SEND_HEAD) if (FD_ISSET(to->networkdesc, &wfds)) { - updatetimeout(to, currtime); active--; procsendhead(to); } if (to->state == STATE_WANT_TO_READ_FILE) if (FD_ISSET(to->filedesc, &rfds)) { - updatetimeout(to, currtime); active--; procreadfile(to); } if (to->state == STATE_WANT_TO_SEND_FILE) if (FD_ISSET(to->networkdesc, &wfds)) { - updatetimeout(to, currtime); active--; procsendfile(to); } +#if defined(CONFIG_HTTP_DIRECTORIES) if (to->state == STATE_DOING_DIR) if (FD_ISSET(to->networkdesc, &wfds)) { - updatetimeout(to, currtime); active--; procdodir(to); } +#endif } diff -Naur awhttpd/permcheck.c axTLS/httpd/awhttpd/permcheck.c --- awhttpd/permcheck.c 2005-01-23 06:49:29.000000000 +1000 +++ axTLS/httpd/awhttpd/permcheck.c 2006-11-15 15:09:14.368138700 +1000 @@ -7,21 +7,23 @@ */ -#include #include +#include +#include #include "aw3.h" +#if defined(CONFIG_HTTP_PERM_CHECK) void procpermcheck(char *pathtocheck) { - + char thepath[MAXREQUESTLENGTH]; +#ifndef WIN32 DIR *tpdir; struct dirent *dp; - char thepath[MAXREQUESTLENGTH]; tpdir=opendir(pathtocheck); if (tpdir==NULL) { - printf("WARNING: UID (%d) is unable to read %s\n", getuid(), pathtocheck); + printf("WARNING: UID (%d) is unable to read %s\n", (int)getuid(), pathtocheck); return; } @@ -38,14 +40,56 @@ } if (access(thepath, R_OK) != 0) - printf("WARNING: UID (%d) is unable to read %s\n", getuid(), thepath); + printf("WARNING: UID (%d) is unable to read %s\n", (int)getuid(), thepath); if (access(thepath, W_OK) == 0) - printf("SECURITY: UID (%d) is ABLE TO WRITE TO %s\n", getuid(), thepath); + printf("SECURITY: UID (%d) is ABLE TO WRITE TO %s\n", (int)getuid(), thepath); } closedir(tpdir); +#else /* Win32 */ + HANDLE tpdir; + WIN32_FIND_DATA file_data; + struct stat st; + char buf2[1024]; + + strcpy(buf2, pathtocheck); + strcat(buf2, "\\*"); + tpdir = FindFirstFile(buf2, &file_data); + + if (tpdir == INVALID_HANDLE_VALUE) { + printf("WARNING: unable to read %s\n", buf2); + TTY_FLUSH(); + return; + } + + while (FindNextFile(tpdir, &file_data)) { + + if (strcmp(file_data.cFileName, "..")==0) continue; + if (strcmp(file_data.cFileName, ".")==0) continue; + + snprintf(thepath, sizeof(thepath), "%s\\%s", + pathtocheck, file_data.cFileName); - return; + if (isdir(thepath)) { + procpermcheck(thepath); + continue; + } + + if (stat(thepath, &st) >= 0) { + if ((st.st_mode & _S_IREAD) == 0) { + printf("WARNING: unable to read %s\n", thepath); + TTY_FLUSH(); + } + + if (st.st_mode & _S_IWRITE) { + printf("SECURITY: ABLE TO WRITE TO %s\n", thepath); + TTY_FLUSH(); + } + } + } + FindClose(tpdir); +#endif } +#endif /* CONFIG_HTTP_PERM_CHECK */ diff -Naur awhttpd/proc.c axTLS/httpd/awhttpd/proc.c --- awhttpd/proc.c 2005-01-23 10:59:41.000000000 +1000 +++ axTLS/httpd/awhttpd/proc.c 2006-11-15 15:09:14.399389700 +1000 @@ -13,91 +13,92 @@ #include #include #include -#include #include #include #include "aw3.h" - - +static int special_read(struct connstruct *cn, void *buf, size_t count); // Returns 1 if elems should continue being read, 0 otherwise int procheadelem(struct connstruct *cn, char *buf) { - char *words[10]; - - split(buf, words, 10, ' '); + char *delim, *value; +#if defined(CONFIG_HTTP_HAS_CGI) + char *cgi_delim; +#endif - if (words[0] == NULL) return 0; - - if (strcmp(words[0], "GET")==0 || - strcmp(words[0], "HEAD")==0 || - strcmp(words[0], "POST")==0) { - char *segs[4]; - - if (*words[0] == 'H') cn->reqtype = TYPE_HEAD; - else if (*words[0] == 'P') cn->reqtype = TYPE_POST; + if ((delim = strchr(buf, ' ')) == NULL) + return 0; - split(words[1], segs, 4, '?'); + *delim = 0; + value = delim+1; - if (segs[0] == NULL) return 0; + if (strcmp(buf, "GET")==0 || + strcmp(buf, "HEAD")==0 || + strcmp(buf, "POST")==0) + { + if (buf[0] == 'H') + cn->reqtype = TYPE_HEAD; + else if (buf[0] == 'P') + cn->reqtype = TYPE_POST; + + if ((delim = strchr(value, ' ')) == NULL) /* expect HTTP type */ + return 0; + *delim = 0; - urldecode(segs[0]); + urldecode(value); - if (sanitizefile(segs[0]) == 0) { + if (sanitizefile(value) == 0) { send404(cn); removeconnection(cn); return 0; } - my_strncpy(cn->filereq, segs[0], MAXREQUESTLENGTH); - - if (segs[1] != NULL) my_strncpy(cn->cgiargs, segs[1], MAXREQUESTLENGTH); - - } else if (strcmp(words[0], "Host:")==0) { + my_strncpy(cn->filereq, value, MAXREQUESTLENGTH); +#if defined(CONFIG_HTTP_HAS_CGI) + if ((cgi_delim = strchr(value, '?'))) + { + *cgi_delim = 0; + my_strncpy(cn->cgiargs, value+1, MAXREQUESTLENGTH); + } +#endif - if (words[1] == NULL) return 0; + } else if (strcmp(buf, "Host:")==0) { - if (sanitizehost(words[1]) == 0) { + if (sanitizehost(value) == 0) { send404(cn); removeconnection(cn); return 0; } - my_strncpy(cn->virtualhostreq, words[1], MAXREQUESTLENGTH); - } else if (strcmp(words[0], "Range:")==0) { - - cn->offset = -1; - - if (strchr(words[1], '-') == NULL) return 1; - - if (strchr(words[1], '=') != NULL) { - while(*words[1] != '=') words[1]++; - words[1]++; - } - - if (isdigit(*words[1]) == 0) return 1; - - cn->offset = atoi(words[1]); - + my_strncpy(cn->virtualhostreq, value, MAXREQUESTLENGTH); + } else if (strcmp(buf, "Connection:")==0 && + strcmp(value, "close")==0) { + cn->close_when_done = 1; + } else if (strcmp(buf, "If-Modified-Since:") ==0 ) { + /* TODO: parse this date properly with getdate() or similar */ + cn->modified_since = 1; } return 1; -} - +} +#if defined(CONFIG_HTTP_DIRECTORIES) void procdirlisting(struct connstruct *cn) { char buf[MAXREQUESTLENGTH]; + char actualfile[1024]; +#ifndef CONFIG_HTTP_DIRECTORIES if (allowdirectorylisting == 0) { send404(cn); removeconnection(cn); return; } +#endif if (cn->reqtype == TYPE_HEAD) { snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nContent-Type: text/html\n\n"); @@ -107,7 +108,17 @@ return; } - cn->dirp = opendir(cn->actualfile); + strcpy(actualfile, cn->actualfile); +#ifdef WIN32 + strcat(actualfile, "*"); + cn->dirp = FindFirstFile(actualfile, &cn->file_data); + if (cn->dirp == INVALID_HANDLE_VALUE) { + send404(cn); + removeconnection(cn); + return; + } +#else + cn->dirp = opendir(actualfile); if (cn->dirp == NULL) { send404(cn); removeconnection(cn); @@ -116,12 +127,10 @@ // Get rid of the "." readdir(cn->dirp); +#endif - // If the browser doesn't specify a virtual host, the client will - // see "http://default/thedir/" instead of "http://thehost.com/thedir/" - // Consider this punishment for using such an old browser. - snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nContent-Type: text/html\n\n\nDirectory Listing\n

Directory listing of http://%s%s


\n", cn->virtualhostreq, cn->filereq); - write(cn->networkdesc, buf, strlen(buf)); + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nContent-Type: text/html\n\n\nDirectory Listing\n

Directory listing of %s://%s%s


\n", cn->is_ssl ? "https" : "http", cn->virtualhostreq, cn->filereq); + special_write(cn, buf, strlen(buf)); cn->state = STATE_DOING_DIR; @@ -134,36 +143,48 @@ void procdodir(struct connstruct *cn) { +#ifndef WIN32 struct dirent *dp; +#endif char buf[MAXREQUESTLENGTH]; - char encbuf[sizeof(dp->d_name)*3+1]; + char encbuf[1024]; int putslash; + char *file; do { - if ((dp = readdir(cn->dirp)) == NULL) { - snprintf(buf, sizeof(buf), "

End of Anti-Web directory listing.\n"); - write(cn->networkdesc, buf, strlen(buf)); +#ifdef WIN32 + if (!FindNextFile(cn->dirp, &cn->file_data)) { +#else + if ((dp = readdir(cn->dirp)) == NULL) { +#endif + snprintf(buf, sizeof(buf), "\n"); + special_write(cn, buf, strlen(buf)); removeconnection(cn); return; } +#ifdef WIN32 + file = cn->file_data.cFileName; +#else + file = dp->d_name; +#endif if (cn->filereq[0] == '/' && cn->filereq[1] == '\0' && - strcmp(dp->d_name, "..") == 0) continue; + strcmp(file, "..") == 0) continue; - snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, dp->d_name); + snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file); putslash = isdir(buf); - urlencode(dp->d_name, encbuf); + urlencode(file, encbuf); snprintf(buf, sizeof(buf), "%s%s
\n", - encbuf, putslash ? "/" : "", dp->d_name, putslash ? "/" : ""); - write(cn->networkdesc, buf, strlen(buf)); + encbuf, putslash ? "/" : "", file, putslash ? "/" : ""); + special_write(cn, buf, strlen(buf)); } while (issockwriteable(cn->networkdesc)); return; } - +#endif @@ -172,9 +193,10 @@ char buf[MAXREQUESTLENGTH*4], *tp, *next; int rv; - rv = read(cn->networkdesc, buf, sizeof(buf)-1); - if (rv == 0 || rv == -1) { - removeconnection(cn); + rv = special_read(cn, buf, sizeof(buf)-1); + if (rv <= 0) { + if (rv < 0) + removeconnection(cn); return; } @@ -217,36 +239,85 @@ void procsendhead(struct connstruct *cn) { char buf[1024]; + char actualfile[1024]; struct stat stbuf; + time_t now = cn->timeout - CONFIG_HTTP_TIMEOUT; + char date[32]; + strcpy(date, ctime(&now)); + + strcpy(actualfile, cn->actualfile); + +#ifdef WIN32 + /* stat() under win32 can't deal with trail slash */ + if (actualfile[strlen(actualfile)-1] == '\\') + actualfile[strlen(actualfile)-1] = 0; +#endif - if (stat(cn->actualfile, &stbuf) == -1) { - if (allowcgi != 0) { + if (stat(actualfile, &stbuf) == -1) { +#if defined(CONFIG_HTTP_HAS_CGI) if (trycgi_withpathinfo(cn) == 0) { // We Try To Find A CGI proccgi(cn,1); return; } - } +#endif send404(cn); removeconnection(cn); return; } +#if defined(CONFIG_HTTP_HAS_CGI) if (iscgi(cn->actualfile)) { +#ifndef WIN32 // Set up CGI script - if (allowcgi == 0 || - access(cn->actualfile, X_OK) != 0 || - isdir(cn->actualfile)) { + if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { + send404(cn); + removeconnection(cn); + return; + } +#endif + + proccgi(cn,0); + return; + } +#endif + + if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { + if (cn->filereq[strlen(cn->filereq)-1] != '/') { + send301(cn); + removeconnection(cn); + return; + } + + // Check to see if this dir has an index file + if (procindex(cn, &stbuf) == 0) { +#if defined(CONFIG_HTTP_DIRECTORIES) + // If not, we do a directory listing of it + procdirlisting(cn); +#else send404(cn); removeconnection(cn); +#endif return; } - proccgi(cn,0); - return; - } +#if defined(CONFIG_HTTP_HAS_CGI) + // If the index is a CGI file, handle it like any other CGI + if (iscgi(cn->actualfile)) { + // Set up CGI script + if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { + send404(cn); + removeconnection(cn); + return; + } + proccgi(cn,0); + return; + } +#endif + // If the index isn't a CGI, we continue on with the index file + } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { if (cn->filereq[strlen(cn->filereq)-1] != '/') { send301(cn); @@ -256,17 +327,18 @@ // Check to see if this dir has an index file if (procindex(cn, &stbuf) == 0) { +#if defined(CONFIG_HTTP_DIRECTORIES) // If not, we do a directory listing of it procdirlisting(cn); +#endif return; } +#if defined(CONFIG_HTTP_HAS_CGI) // If the index is a CGI file, handle it like any other CGI if (iscgi(cn->actualfile)) { // Set up CGI script - if (allowcgi == 0 || - access(cn->actualfile, X_OK) != 0 || - isdir(cn->actualfile)) { + if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { send404(cn); removeconnection(cn); return; @@ -275,50 +347,68 @@ proccgi(cn,0); return; } +#endif // If the index isn't a CGI, we continue on with the index file } - if (cn->offset == -1 || cn->offset >= stbuf.st_size) { - cn->offset = -1; + if (cn->modified_since) { + snprintf(buf, sizeof(buf), "HTTP/1.1 304 Not Modified\nServer: Anti-Web V%s\nDate: %s\n", VERSION, date); + special_write(cn, buf, strlen(buf)); + cn->modified_since = 0; + cn->state = STATE_WANT_TO_READ_HEAD; + return; + } + else { +#ifdef CONFIG_HTTP_VERBOSE + printf("awhttpd: %s send %s\n", + cn->is_ssl ? "https" : "http", cn->actualfile); + TTY_FLUSH(); +#endif - snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: Anti-Web V%s (%s)\nContent-Type: %s\nContent-Length: %ld\nLast-Modified: %s\n", - VERSION, - quote, - getmimetype(cn->actualfile), - (long) stbuf.st_size, - ctime(&(stbuf.st_mtime))); // ctime() has a \n on the end - } else { - snprintf(buf, sizeof(buf), "HTTP/1.1 206 OK\nServer: Anti-Web V%s (%s)\nContent-Type: %s\nContent-Range: %ld-%ld/%ld\nContent-Length: %ld\nLast-Modified: %s\n", + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: Anti-Web V%s\nContent-Type: %s\nContent-Length: %ld\nDate: %sLast-Modified: %s\n", VERSION, - quote, getmimetype(cn->actualfile), - cn->offset, - (long) stbuf.st_size-1, (long) stbuf.st_size, - (long) stbuf.st_size - cn->offset, + date, ctime(&(stbuf.st_mtime))); // ctime() has a \n on the end } - write(cn->networkdesc, buf, strlen(buf)); + special_write(cn, buf, strlen(buf)); if (cn->reqtype == TYPE_HEAD) { removeconnection(cn); return; } else { + int flags = O_RDONLY; +#if defined(WIN32) || defined(CYGWIN) + flags |= O_BINARY; +#endif - cn->filedesc = open(cn->actualfile, O_RDONLY); + cn->filedesc = open(cn->actualfile, flags); if (cn->filedesc == -1) { send404(cn); removeconnection(cn); return; } - if (cn->offset != -1) { - lseek(cn->filedesc, cn->offset, SEEK_SET); +#ifdef WIN32 + for (;;) + { + procreadfile(cn); + if (cn->filedesc == -1) + { + break; + } + + do + { + procsendfile(cn); + } while (cn->state != STATE_WANT_TO_READ_FILE); } - +#else cn->state = STATE_WANT_TO_READ_FILE; +#endif return; } @@ -328,13 +418,18 @@ void procreadfile(struct connstruct *cn) { - int rv; - - rv = read(cn->filedesc, cn->databuf, BLOCKSIZE); + int rv = read(cn->filedesc, cn->databuf, BLOCKSIZE); if (rv == 0 || rv == -1) { - removeconnection(cn); - return; + close(cn->filedesc); + cn->filedesc = -1; + if (cn->close_when_done) /* close immediately */ + removeconnection(cn); + else { /* keep socket open - HTTP 1.1 */ + cn->state = STATE_WANT_TO_READ_HEAD; + cn->numbytes = 0; + } + return; } cn->numbytes = rv; @@ -347,11 +442,9 @@ void procsendfile(struct connstruct *cn) { - int rv; - - rv = write(cn->networkdesc, cn->databuf, cn->numbytes); + int rv = special_write(cn, cn->databuf, cn->numbytes); - if (rv == -1) + if (rv < 0) removeconnection(cn); else if (rv == cn->numbytes) cn->state = STATE_WANT_TO_READ_FILE; @@ -361,7 +454,47 @@ memmove(cn->databuf, cn->databuf + rv, cn->numbytes - rv); cn->numbytes -= rv; } +} - return; +int special_write(struct connstruct *cn, + const uint8_t *buf, size_t count) +{ + int res; + +#ifdef CONFIG_HTTP_HAS_SSL + if (cn->is_ssl) + { + SSL *ssl = ssl_find(servers->ssl_ctx, cn->networkdesc); + if (ssl) + { + res = ssl_write(ssl, (unsigned char *)buf, count); + } + else + return -1; + } + else +#endif + res = SOCKET_WRITE(cn->networkdesc, buf, count); + + return res; +} + +static int special_read(struct connstruct *cn, void *buf, size_t count) +{ + int res; + +#ifdef CONFIG_HTTP_HAS_SSL + if (cn->is_ssl) + { + SSL *ssl = ssl_find(servers->ssl_ctx, cn->networkdesc); + unsigned char *read_buf; + + if ((res = ssl_read(ssl, &read_buf)) > SSL_OK) + memcpy(buf, read_buf, res > (int)count ? count : res); + } + else +#endif + res = SOCKET_READ(cn->networkdesc, buf, count); + return res; } diff -Naur awhttpd/socket.c axTLS/httpd/awhttpd/socket.c --- awhttpd/socket.c 2004-04-25 13:03:05.000000000 +1000 +++ axTLS/httpd/awhttpd/socket.c 2006-11-15 15:09:14.415015200 +1000 @@ -8,61 +8,17 @@ #include -#include -#include #include -#include -#include -#include -#include -#include -#include #include - #include "aw3.h" -int checkmaxusers(int sd) { - - if (maxusers <= 0) return 1; - - if (numusers >= maxusers) { - send505(sd, "Maximum user limit reached"); - // removeconnection() should be used normally - close(sd); - - return 0; - } - - return 1; -} - - -int pollsocket(int sd, long ustimeout) { - - fd_set rfds; - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = ustimeout; - - FD_ZERO(&rfds); - FD_SET(sd, &rfds); - - select(FD_SETSIZE, &rfds, NULL, NULL, (ustimeout >= 0) ? &tv : NULL); - - return FD_ISSET(sd, &rfds); - -} - - - #ifdef HAVE_IPV6 -void handlenewconnection(int listenfd) { +void handlenewconnection(int listenfd, int is_ssl) { struct sockaddr_in6 their_addr; int tp = sizeof(their_addr); @@ -82,7 +38,7 @@ *ipbuf = '\0'; } - if (checkmaxusers(connfd)) addconnection(connfd, ipbuf); + addconnection(connfd, ipbuf, is_ssl); return; @@ -90,19 +46,17 @@ #else -void handlenewconnection(int listenfd) { +void handlenewconnection(int listenfd, int is_ssl) { struct sockaddr_in their_addr; int tp = sizeof(struct sockaddr_in); int connfd; - char ipbuf[100]; connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp); if (connfd == -1) return; - if (checkmaxusers(connfd)) - addconnection(connfd, inet_ntoa(their_addr.sin_addr)); + addconnection(connfd, inet_ntoa(their_addr.sin_addr), is_ssl); return; } @@ -113,8 +67,12 @@ int openlistener(int port) { - - int tp=0,sd; + int sd; +#ifdef WIN32 + char tp=1; +#else + int tp=1; +#endif struct sockaddr_in my_addr; if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) return -1; @@ -125,7 +83,7 @@ setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp)); my_addr.sin_family = AF_INET; // host byte order - my_addr.sin_port = htons(port); // short, network byte order + my_addr.sin_port = htons((short)port); // short, network byte order my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset(&(my_addr.sin_zero), 0, 8); // zero the rest of the struct diff -Naur awhttpd/urlencode.c axTLS/httpd/awhttpd/urlencode.c --- awhttpd/urlencode.c 2004-05-14 10:53:47.000000000 +1000 +++ axTLS/httpd/awhttpd/urlencode.c 2006-11-15 15:09:14.430640700 +1000 @@ -13,7 +13,7 @@ #include #include - +#include #include "aw3.h" @@ -37,7 +37,7 @@ (*p > 'Z' && *p < '_') || (*p > '_' && *p < 'a') || (*p > 'z' && *p < 0xA1)) { - sprintf(tp, "%%%02X", *p); + sprintf((char *)tp, "%%%02X", *p); tp += 3; } else { *tp = *p;