diff --git a/CHANGELOG b/CHANGELOG index 974d6357e..bcb7e8433 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,5 +8,7 @@ Changes since 1.0.0 axhttpd Changes * Header file issue fixed (in mime_types.c) * chroot() now used for better security -* Authentication implemented -* +* Basic authentication implemented (with .htpasswd) +* HTTP Port protection implemented (with .htaccess) +* Directory access protection implemented (with .htaccess) + diff --git a/config/linuxconfig b/config/linuxconfig index f73efd664..988e05dd6 100644 --- a/config/linuxconfig +++ b/config/linuxconfig @@ -56,7 +56,7 @@ CONFIG_HTTP_WEBROOT="../www" CONFIG_HTTP_PORT=80 CONFIG_HTTP_TIMEOUT=5 # CONFIG_HTTP_HAS_CGI is not set -CONFIG_HTTP_CGI_EXTENSION="" +CONFIG_HTTP_CGI_EXTENSIONS="" # CONFIG_HTTP_DIRECTORIES is not set # CONFIG_HTTP_PERM_CHECK is not set # CONFIG_HTTP_HAS_IPV6 is not set diff --git a/config/win32config b/config/win32config index fcdcdf129..13bb3c46b 100644 --- a/config/win32config +++ b/config/win32config @@ -59,7 +59,7 @@ CONFIG_HTTP_WEBROOT="www" CONFIG_HTTP_PORT=80 CONFIG_HTTP_TIMEOUT=5 # CONFIG_HTTP_HAS_CGI is not set -CONFIG_HTTP_CGI_EXTENSION="" +CONFIG_HTTP_CGI_EXTENSIONS="" CONFIG_HTTP_DIRECTORIES=y # CONFIG_HTTP_PERM_CHECK is not set # CONFIG_HTTP_HAS_IPV6 is not set diff --git a/httpd/Config.in b/httpd/Config.in index 531f9c882..417106e59 100644 --- a/httpd/Config.in +++ b/httpd/Config.in @@ -10,7 +10,7 @@ config CONFIG_HTTP_STATIC_BUILD bool "Static Build" default n help - Select y if you want axhttp to be a static build (i.e. don't use the + Select y if you want axhttpd to be a static build (i.e. don't use the axtls shared library or dll). config CONFIG_HTTP_PORT @@ -59,12 +59,14 @@ config CONFIG_HTTP_HAS_CGI help Enable the CGI capability. -config CONFIG_HTTP_CGI_EXTENSION - string "CGI File Extension" - default ".php" +config CONFIG_HTTP_CGI_EXTENSIONS + string "CGI File Extension(s)" + default ".php,.sh" depends on CONFIG_HTTP_HAS_CGI help - Tell axhhtp what file extension is used for CGI + Tell axhhtpd what file extension(s) are used for CGI. + + This is a comma separated list. config CONFIG_HTTP_DIRECTORIES bool "Enable Directory Listing" diff --git a/httpd/Makefile b/httpd/Makefile index 71ea462a6..2541c67af 100644 --- a/httpd/Makefile +++ b/httpd/Makefile @@ -25,8 +25,10 @@ ifndef CONFIG_PLATFORM_WIN32 ifdef CONFIG_PLATFORM_CYGWIN TARGET=../$(STAGE)/axhttpd.exe +TARGET2=../$(STAGE)/htpasswd.exe else TARGET=../$(STAGE)/axhttpd +TARGET2=../$(STAGE)/htpasswd endif ifdef CONFIG_HTTP_STATIC_BUILD @@ -39,6 +41,7 @@ CFLAGS += -I../ssl else # win32 build TARGET=../$(STAGE)/axhttpd.exe +TARGET2=../$(STAGE)/htpasswd.exe ifdef CONFIG_HTTP_STATIC_BUILD LIBS=../$(STAGE)/axtls.static.lib ..\\config\\axtls.res @@ -51,7 +54,11 @@ ifndef CONFIG_AXHTTPD web_server: else -web_server : $(TARGET) +web_server :: $(TARGET) + +ifdef CONFIG_HTTP_HAS_AUTHORIZATION +web_server :: $(TARGET2) +endif OBJ= \ axhttpd.o \ @@ -69,14 +76,24 @@ ifndef CONFIG_PLATFORM_SOLARIS strip --remove-section=.comment $(TARGET) endif endif + +$(TARGET2): htpasswd.o ../$(STAGE)/libaxtls.a + $(LD) $(LDFLAGS) -o $@ htpasswd.o $(LIBS) + else # Win32 OBJ:=$(OBJ:.o=.obj) %.obj : %.c $(CC) $(CFLAGS) $< +htpasswd.obj : htpasswd.c + $(CC) $(CFLAGS) $< + $(TARGET): $(OBJ) $(LD) $(LDFLAGS) $(LIBS) /out:$@ $(OBJ) + +$(TARGET2): htpasswd.obj + $(LD) $(LDFLAGS) $(LIBS) /out:$@ $(OBJ) endif endif # CONFIG_AXHTTPD diff --git a/httpd/README b/httpd/README index c8bb279b7..ede9af275 100644 --- a/httpd/README +++ b/httpd/README @@ -4,3 +4,42 @@ axhttpd is a small embedded web server using the axTLS library. It is based originally on the web server written by Doug Currie which is at: http://www.hcsw.org/awhttpd. +Basic Authentication +==================== + +Basic Authentication uses a password file called ".htpasswd", in the +directory to be protected. This file is formatted as the familiar +colon-separated username/encrypted-password pair, records delimited by +newlines. The protection does not carry over to subdirectories. The +utility program htpasswd is included to help manually edit .htpasswd files. + +The encryption of this password uses a proprietary algorithm due to the +dependency of many crypt libraries on DES. + +An example is in /test_dir/prot (username 'abcd', password is '1234'). + +Note: This is an mconf configuration option. + +HTTP Port Protection +==================== + +Directories/files can be accessed using the 'http' or 'https' uri prefix. If +normal http access for a directory needs to be disabled, then put +"SSLRequireSSL" into a '.htaccess' file in the directory to be protected. + +An example is in /test_dir/prot. + +CGI +=== + +chroot() is now used for added security. However this has the impact of +removing the regular filesystem, so any CGI applications no longer have the +usual access. + +So any executables and libraries need to be copied into webroot (under /bin +and /lib). + +Failure to do so will result in mystical blank screens (and probably hundreds +of axhttpd instances being created...). + + diff --git a/httpd/axhttp.h b/httpd/axhttp.h index cce1567b1..229ad8397 100644 --- a/httpd/axhttp.h +++ b/httpd/axhttp.h @@ -25,9 +25,7 @@ #define HAVE_IPV6 #endif -#define MAXFILEPATH 1024 -#define MAXIPLEN 45 -#define MAXREQUESTLENGTH 1024 +#define MAXREQUESTLENGTH 256 #define MAXCGIARGS 100 #define BLOCKSIZE 4096 @@ -40,9 +38,12 @@ #define STATE_WANT_TO_SEND_FILE 4 #define STATE_DOING_DIR 5 -#define TYPE_GET 0 -#define TYPE_HEAD 1 -#define TYPE_POST 2 +enum +{ + TYPE_GET, + TYPE_HEAD, + TYPE_POST +}; struct connstruct { @@ -62,21 +63,21 @@ struct connstruct #endif time_t timeout; - char ip[MAXIPLEN]; char actualfile[MAXREQUESTLENGTH]; char filereq[MAXREQUESTLENGTH]; + char dirname[MAXREQUESTLENGTH]; + char virtualhostreq[MAXREQUESTLENGTH]; + int numbytes; + char databuf[BLOCKSIZE]; + uint8_t is_ssl; + uint8_t close_when_done; + uint8_t modified_since; + #if defined(CONFIG_HTTP_HAS_CGI) char cgiargs[MAXREQUESTLENGTH]; char cgiscriptinfo[MAXREQUESTLENGTH]; char cgipathinfo[MAXREQUESTLENGTH]; #endif - char virtualhostreq[MAXREQUESTLENGTH]; - int numbytes; - char databuf[BLOCKSIZE]; - - uint8_t is_ssl; - uint8_t close_when_done; - uint8_t modified_since; #if defined(CONFIG_HTTP_HAS_AUTHORIZATION) char authorization[MAXREQUESTLENGTH]; #endif diff --git a/httpd/axhttpd.c b/httpd/axhttpd.c index cd899f9cf..e35a77387 100644 --- a/httpd/axhttpd.c +++ b/httpd/axhttpd.c @@ -38,7 +38,7 @@ static void procpermcheck(const char *pathtocheck); #if defined(CONFIG_HTTP_HAS_CGI) struct cgiextstruct *cgiexts; -static void addcgiext(char *tp); +static void addcgiext(const char *tp); #if !defined(WIN32) static void reaper(int sigtype) @@ -55,6 +55,7 @@ static void sigint_cleanup(int sig) struct connstruct *tp; int i; + while (servers != NULL) { if (servers->is_ssl) @@ -75,6 +76,17 @@ static void sigint_cleanup(int sig) freeconns = tp; } +#if defined(CONFIG_HTTP_HAS_CGI) + while (cgiexts) + { + struct cgiextstruct *cp = cgiexts->next; + if (cp == NULL) /* last entry */ + free(cgiexts->ext); + free(cgiexts); + cgiexts = cp; + } +#endif + exit(0); } @@ -159,7 +171,7 @@ int main(int argc, char *argv[]) procpermcheck(webroot); #endif #if defined(CONFIG_HTTP_HAS_CGI) - addcgiext(CONFIG_HTTP_CGI_EXTENSION); + addcgiext(CONFIG_HTTP_CGI_EXTENSIONS); #endif #if defined(CONFIG_HTTP_VERBOSE) printf("axhttpd (%s): listening on ports %d (http) and %d (https)\n", @@ -413,13 +425,21 @@ static void procpermcheck(const char *pathtocheck) #endif /* CONFIG_HTTP_PERM_CHECK */ #if defined(CONFIG_HTTP_HAS_CGI) -static void addcgiext(char *tp) +static void addcgiext(const char *cgi_exts) { - struct cgiextstruct *ex = (struct cgiextstruct *) - malloc(sizeof(struct cgiextstruct)); - ex->ext = strdup(tp); - ex->next = cgiexts; - cgiexts = ex; + char *cp = strdup(cgi_exts); + + /* extenstions are comma separated */ + do + { + struct cgiextstruct *ex = (struct cgiextstruct *) + malloc(sizeof(struct cgiextstruct)); + ex->ext = cp; + ex->next = cgiexts; + cgiexts = ex; + if ((cp = strchr(cp, ',')) != NULL) + *cp++ = 0; + } while (cp != NULL); } #endif @@ -557,10 +577,8 @@ static void addconnection(int sd, char *ip, int is_ssl) #if defined(CONFIG_HTTP_HAS_CGI) *(tp->cgiargs) = '\0'; #endif - *(tp->virtualhostreq) = '\0'; tp->state = STATE_WANT_TO_READ_HEAD; tp->reqtype = TYPE_GET; - my_strncpy(tp->ip, ip, MAXIPLEN); tp->close_when_done = 0; tp->modified_since = 0; tp->timeout = time(NULL) + CONFIG_HTTP_TIMEOUT; diff --git a/httpd/conn.c b/httpd/conn.c deleted file mode 100644 index 2cbffec2d..000000000 --- a/httpd/conn.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright(C) 2006 Cameron Rich - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include "axhttp.h" - -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)); - else - { - tp = freeconns; - freeconns = tp->next; - } - - // Attach it to the used list - tp->next = usedconns; - usedconns = tp; - tp->networkdesc = sd; - - if (is_ssl) - ssl_server_new(servers->ssl_ctx, sd); - tp->is_ssl = is_ssl; - tp->filedesc = -1; -#if defined(CONFIG_HTTP_HAS_DIRECTORIES) - tp->dirp = NULL; -#endif - *(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; - tp->reqtype = TYPE_GET; - my_strncpy(tp->ip, ip, MAXIPLEN); - tp->close_when_done = 0; - tp->modified_since = 0; - tp->timeout = time(NULL) + CONFIG_HTTP_TIMEOUT; -} - -void removeconnection(struct connstruct *cn) -{ - struct connstruct *tp; - int shouldret = 0; - - tp = usedconns; - - if (tp == NULL || cn == NULL) - shouldret = 1; - else if (tp == cn) - usedconns = tp->next; - else - { - while (tp != NULL) - { - if (tp->next == cn) - { - tp->next = (tp->next)->next; - shouldret = 0; - break; - } - - tp = tp->next; - shouldret = 1; - } - } - - if (shouldret) - return; - - // If we did, add it to the free list - cn->next = freeconns; - freeconns = cn; - - // Close it all down - if (cn->networkdesc != -1) - { - if (cn->is_ssl) - ssl_free(ssl_find(servers->ssl_ctx, cn->networkdesc)); - - SOCKET_CLOSE(cn->networkdesc); - } - - if (cn->filedesc != -1) - close(cn->filedesc); - -#if defined(CONFIG_HTTP_HAS_DIRECTORIES) - if (cn->dirp != NULL) -#ifdef WIN32 - FindClose(cn->dirp); -#else - closedir(cn->dirp); -#endif -#endif -} diff --git a/httpd/htpasswd.c b/httpd/htpasswd.c new file mode 100644 index 000000000..e4887f62a --- /dev/null +++ b/httpd/htpasswd.c @@ -0,0 +1,98 @@ +/* + * Copyright(C) 2007 Cameron Rich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "ssl.h" + +int tfd; + +void base64_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen) +{ + static const char b64str[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + while (inlen && outlen) + { + *out++ = b64str[(in[0] >> 2) & 0x3f]; + if (!--outlen) + break; + + *out++ = b64str[((in[0] << 4) + + (--inlen ? in[1] >> 4 : 0)) & 0x3f]; + if (!--outlen) + break; + *out++ = (inlen + ? b64str[((in[1] << 2) + + (--inlen ? in[2] >> 6 : 0)) + & 0x3f] + : '='); + if (!--outlen) + break; + *out++ = inlen ? b64str[in[2] & 0x3f] : '='; + if (!--outlen) + break; + if (inlen) + inlen--; + if (inlen) + in += 3; + } + + if (outlen) + *out = '\0'; +} + +static void usage(void) +{ + fprintf(stderr,"Usage: htpasswd username\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + char* pw; + uint8_t md5_salt[MD5_SIZE], md5_pass[MD5_SIZE]; + char b64_salt[MD5_SIZE+10], b64_pass[MD5_SIZE+10]; + MD5_CTX ctx; + + if (argc != 2) + usage(); + + pw = strdup(getpass("New password:")); + if (strcmp(pw, getpass("Re-type new password:")) != 0) + { + fprintf(stderr, "They don't match, sorry.\n" ); + exit(1); + } + + RNG_initialize(pw, sizeof(pw)); + get_random(MD5_SIZE, md5_salt); + RNG_terminate(); + base64_encode(md5_salt, MD5_SIZE, b64_salt, sizeof(b64_salt)); + + MD5Init(&ctx); + MD5Update(&ctx, md5_salt, MD5_SIZE); + MD5Update(&ctx, pw, strlen(pw)); + MD5Final(&ctx, md5_pass); + base64_encode(md5_pass, MD5_SIZE, b64_pass, sizeof(b64_pass)); + + printf("Add the following to your '.htpasswd' file\n"); + printf("%s:%s$%s\n", argv[1], b64_salt, b64_pass); + return 0; +} diff --git a/httpd/proc.c b/httpd/proc.c index 1c746cf2d..d0a4ebe71 100644 --- a/httpd/proc.c +++ b/httpd/proc.c @@ -35,6 +35,7 @@ static void urldecode(char *buf); static void buildactualfile(struct connstruct *cn); static int sanitizefile(const char *buf); static int sanitizehost(char *buf); +static int htaccess_check(struct connstruct *cn); #if defined(CONFIG_HTTP_DIRECTORIES) static void urlencode(const uint8_t *s, uint8_t *t); @@ -63,11 +64,10 @@ static int procheadelem(struct connstruct *cn, char *buf) *delim = 0; value = delim+1; - printf("BUF %s - value %s\n", buf, value); - if (strcmp(buf, "GET") == 0 || - strcmp(buf, "HEAD") == 0 || - strcmp(buf, "POST") == 0) + /* printf("name: %s, value: %s\n", buf, value); */ + if (strcmp(buf, "GET") == 0 || strcmp(buf, "HEAD") == 0 || + strcmp(buf, "POST") == 0) { if (buf[0] == 'H') cn->reqtype = TYPE_HEAD; @@ -76,13 +76,13 @@ static int procheadelem(struct connstruct *cn, char *buf) if ((delim = strchr(value, ' ')) == NULL) /* expect HTTP type */ return 0; - *delim = 0; + *delim = 0; urldecode(value); if (sanitizefile(value) == 0) { - send_error(cn, 404); + send_error(cn, 403); return 0; } @@ -94,7 +94,6 @@ static int procheadelem(struct connstruct *cn, char *buf) my_strncpy(cn->cgiargs, value+1, MAXREQUESTLENGTH); } #endif - } else if (strcmp(buf, "Host:") == 0) { @@ -117,11 +116,14 @@ static int procheadelem(struct connstruct *cn, char *buf) } #ifdef CONFIG_HTTP_HAS_AUTHORIZATION else if (strcmp(buf, "Authorization:") == 0 && - strncmp(value, "Basic ", 6) == 0) + strncmp(value, "Basic ", 6) == 0) { + int size; if (base64_decode(&value[6], strlen(&value[6]), - cn->authorization, NULL)) + cn->authorization, &size)) cn->authorization[0] = 0; /* error */ + else + cn->authorization[size] = 0; } #endif @@ -319,36 +321,42 @@ void procsendhead(struct connstruct *cn) time_t now = cn->timeout - CONFIG_HTTP_TIMEOUT; char date[32]; -#ifdef CONFIG_HTTP_HAS_AUTHORIZATION - if (auth_check(cn)) + /* are we trying to access a file over the HTTP connection instead of a + * HTTPS connection? Or is this directory disabled? */ + if (htaccess_check(cn)) { + send_error(cn, 403); + return; + } + +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION + if (auth_check(cn)) /* see if there is a '.htpasswd' file */ + { +#ifdef CONFIG_HTTP_VERBOSE + printf("axhttpd: access to %s denied\n", cn->actualfile); TTY_FLUSH(); +#endif removeconnection(cn); return; } #endif - strcpy(date, ctime(&now)); - - if (stat(cn->actualfile, &stbuf) == -1) + if (stat(cn->actualfile, &stbuf) == -1) { #if defined(CONFIG_HTTP_HAS_CGI) - if (trycgi_withpathinfo(cn) == 0) + if (stat(cn->actualfile, &stbuf) == -1 && trycgi_withpathinfo(cn) == 0) { /* We Try To Find A CGI */ proccgi(cn, 1); return; } #endif - - send_error(cn, 404); - return; } #if defined(CONFIG_HTTP_HAS_CGI) if (iscgi(cn->actualfile)) { #ifndef WIN32 - /* Set up CGI script */ + /* An executable file? */ if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { send_error(cn, 404); @@ -396,6 +404,8 @@ void procsendhead(struct connstruct *cn) #endif } + strcpy(date, ctime(&now)); + if (cn->modified_since) { /* file has already been read before */ @@ -407,20 +417,6 @@ void procsendhead(struct connstruct *cn) return; } -#ifdef CONFIG_HTTP_VERBOSE - printf("axhttpd: %s send %s\n", - cn->is_ssl ? "https" : "http", cn->actualfile); - TTY_FLUSH(); -#endif - - snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\n" - "Content-Type: %s\nContent-Length: %ld\n" - "Date: %sLast-Modified: %s\n", VERSION, - getmimetype(cn->actualfile), (long) stbuf.st_size, - date, ctime(&(stbuf.st_mtime))); /* ctime() has a \n on the end */ - - special_write(cn, buf, strlen(buf)); - if (cn->reqtype == TYPE_HEAD) { removeconnection(cn); @@ -437,10 +433,23 @@ void procsendhead(struct connstruct *cn) if (cn->filedesc == -1) { send_error(cn, 404); - removeconnection(cn); return; } + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\n" + "Content-Type: %s\nContent-Length: %ld\n" + "Date: %sLast-Modified: %s\n", VERSION, + getmimetype(cn->actualfile), (long) stbuf.st_size, + date, ctime(&(stbuf.st_mtime))); /* ctime() has a \n on the end */ + + special_write(cn, buf, strlen(buf)); + +#ifdef CONFIG_HTTP_VERBOSE + printf("axhttpd: %s send %s\n", + cn->is_ssl ? "https" : "http", cn->actualfile); + TTY_FLUSH(); +#endif + #ifdef WIN32 for (;;) { @@ -659,10 +668,8 @@ static int trycgi_withpathinfo(struct connstruct *cn) /* We've found our CGI file! */ my_strncpy(cn->actualfile, tpfile, MAXREQUESTLENGTH); my_strncpy(cn->cgiscriptinfo, fr_str, MAXREQUESTLENGTH); - offset = (fr_rs[i] + strlen(fr_rs[i])) - fr_str; my_strncpy(cn->cgipathinfo, cn->filereq+offset, MAXREQUESTLENGTH); - return 0; } @@ -678,11 +685,10 @@ static int trycgi_withpathinfo(struct connstruct *cn) static int iscgi(const char *fn) { - struct cgiextstruct *tp; + struct cgiextstruct *tp = cgiexts; int fnlen, extlen; fnlen = strlen(fn); - tp = cgiexts; while (tp != NULL) { @@ -784,6 +790,7 @@ static int hexit(char c) static void buildactualfile(struct connstruct *cn) { + char *cp; snprintf(cn->actualfile, MAXREQUESTLENGTH, "%s", cn->filereq); /* Add directory slash if not there */ @@ -791,12 +798,23 @@ static void buildactualfile(struct connstruct *cn) cn->actualfile[strlen(cn->actualfile)-1] != '/') strcat(cn->actualfile, "/"); + /* work out the directory name */ + strncpy(cn->dirname, cn->actualfile, MAXREQUESTLENGTH); + if ((cp = strrchr(cn->dirname, '/')) == NULL) + cn->dirname[0] = 0; + else + *cp = 0; + #ifdef WIN32 /* convert all the forward slashes to back slashes */ { char *t = cn->actualfile; while ((t = strchr(t, '/'))) *t++ = '\\'; + + t = cn->dirname; + while ((t = strchr(t, '/'))) + *t++ = '\\'; } #endif } @@ -844,9 +862,14 @@ static int sanitizehost(char *buf) return 1; } -#ifdef CONFIG_HTTP_HAS_AUTHORIZATION -#define AUTH_FILE ".htpasswd" +static FILE * exist_check(struct connstruct *cn, const char *check_file) +{ + char pathname[MAXREQUESTLENGTH]; + snprintf(pathname, MAXREQUESTLENGTH, "%s/%s", cn->dirname, check_file); + return fopen(pathname, "r"); +} +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION static void send_authenticate(struct connstruct *cn, const char *realm) { char buf[1024]; @@ -857,30 +880,29 @@ static void send_authenticate(struct connstruct *cn, const char *realm) special_write(cn, buf, strlen(buf)); } -static int check_digest(char *b64_file_passwd, const char *msg_passwd) +static int check_digest(char *salt, const char *msg_passwd) { - uint8_t real_salt[MAXREQUESTLENGTH]; - uint8_t real_passwd[MAXREQUESTLENGTH]; - int real_passwd_size, real_salt_size; - char *b64_pwd; + uint8_t b256_salt[MAXREQUESTLENGTH]; + uint8_t real_passwd[MD5_SIZE]; + int salt_size; + char *b64_passwd; uint8_t md5_result[MD5_SIZE]; MD5_CTX ctx; /* retrieve the salt */ - if ((b64_pwd = strchr(b64_file_passwd, '$')) == NULL) + if ((b64_passwd = strchr(salt, '$')) == NULL) return -1; - *b64_pwd++ = 0; - if (base64_decode(b64_file_passwd, strlen(b64_file_passwd), - real_salt, &real_salt_size)) + *b64_passwd++ = 0; + if (base64_decode(salt, strlen(salt), b256_salt, &salt_size)) return -1; - if (base64_decode(b64_pwd, strlen(b64_pwd), real_passwd, &real_passwd_size)) + if (base64_decode(b64_passwd, strlen(b64_passwd), real_passwd, NULL)) return -1; /* very simple MD5 crypt algorithm, but then the salt we use is large */ MD5Init(&ctx); - MD5Update(&ctx, real_salt, real_salt_size); /* process the salt */ + MD5Update(&ctx, b256_salt, salt_size); /* process the salt */ MD5Update(&ctx, msg_passwd, strlen(msg_passwd)); /* process the password */ MD5Final(&ctx, md5_result); return memcmp(md5_result, real_passwd, MD5_SIZE);/* 0 = ok */ @@ -888,36 +910,15 @@ static int check_digest(char *b64_file_passwd, const char *msg_passwd) static int auth_check(struct connstruct *cn) { - char dirname[MAXREQUESTLENGTH]; - char authpath[MAXREQUESTLENGTH]; char line[MAXREQUESTLENGTH]; + FILE *fp; char *cp; - FILE *fp = NULL; - struct stat auth_stat; - strncpy(dirname, cn->actualfile, MAXREQUESTLENGTH); - cp = strrchr(dirname, '/'); - if (cp == NULL) - dirname[0] = 0; - else - *cp = 0; - - /* check that the file is not the AUTH_FILE itself */ - if (strcmp(cn->actualfile, AUTH_FILE) == 0) - { - send_error(cn, 403); - goto error; - } - - snprintf(authpath, MAXREQUESTLENGTH, "%s/%s", dirname, AUTH_FILE); - if (stat(authpath, &auth_stat) < 0) /* no auth file, so let though */ - return 0; + if ((fp = exist_check(cn, ".htpasswd")) == NULL) + return 0; /* no .htpasswd file, so let though */ if (cn->authorization[0] == 0) - { - send_authenticate(cn, dirname); - return -1; - } + goto error; /* cn->authorization is in form "username:password" */ if ((cp = strchr(cn->authorization, ':')) == NULL) @@ -925,8 +926,6 @@ static int auth_check(struct connstruct *cn) else *cp++ = 0; /* cp becomes the password */ - fp = fopen(authpath, "r"); - while (fgets(line, sizeof(line), fp) != NULL) { char *b64_file_passwd; @@ -952,14 +951,41 @@ static int auth_check(struct connstruct *cn) } } - fclose(fp); - error: - send_authenticate(cn, dirname); + fclose(fp); + send_authenticate(cn, cn->virtualhostreq); return -1; } #endif +static int htaccess_check(struct connstruct *cn) +{ + char line[MAXREQUESTLENGTH]; + FILE *fp; + int ret = 0; + + if ((fp = exist_check(cn, ".htaccess")) == NULL) + return 0; /* no .htaccess file, so let though */ + + while (fgets(line, sizeof(line), fp) != NULL) + { + if (!cn->is_ssl && strstr(line, "SSLRequireSSL")) + { + ret = -1; /* SSL port access required */ + break; + } + + if (strstr(line, "Deny all")) + { + ret = -1; /* access to this dir denied */ + break; + } + } + + fclose(fp); + return ret; +} + static void send_error(struct connstruct *cn, int err) { char buf[1024]; @@ -971,6 +997,10 @@ static void send_error(struct connstruct *cn, int err) case 403: title = "Forbidden"; text = "File is protected"; +#ifdef CONFIG_HTTP_VERBOSE + printf("axhttpd: access to %s:/%s denied\n", + cn->is_ssl ? "https" : "http", cn->actualfile); TTY_FLUSH(); +#endif break; case 404: @@ -979,9 +1009,12 @@ static void send_error(struct connstruct *cn, int err) break; } - sprintf(buf, "HTTP/1.1 %d %s\nContent-Type: text/html\n" - "\n%d %s" - "

%d %s

\n\n", + sprintf(buf, "HTTP/1.1 %d %s\n" + "Content-Type: text/html\n" + "Cache-Control: no-cache,no-store\n" + "Connection: close\n\n" + "\n\n%d %s\n" + "

%d %s

\n\n", err, title, err, title, err, text); special_write(cn, buf, strlen(buf)); removeconnection(cn); diff --git a/ssl/Makefile b/ssl/Makefile index 69392b591..4ef5e347b 100644 --- a/ssl/Makefile +++ b/ssl/Makefile @@ -99,5 +99,5 @@ endif clean:: $(MAKE) -C test clean - -@rm -f ../$(STAGE)/*.pch ../$(STAGE)/*.so* ../$(STAGE)/*.a ../$(STAGE)/*.dll ../$(STAGE)/*.lib ../$(STAGE)/*.exp ../$(STAGE)/*.pdb ../$(STAGE)/*.ilk + -@rm -f ../$(STAGE)/* *.a *.lib diff --git a/ssl/crypto.h b/ssl/crypto.h index 23029f9a6..9bf446f24 100644 --- a/ssl/crypto.h +++ b/ssl/crypto.h @@ -123,9 +123,9 @@ void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, /************************************************************************** * RNG declarations **************************************************************************/ -void RNG_initialize(const uint8_t *seed_buf, int size); -void RNG_terminate(void); -void get_random(int num_rand_bytes, uint8_t *rand_data); +EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size); +EXP_FUNC void STDCALL RNG_terminate(void); +EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data); void get_random_NZ(int num_rand_bytes, uint8_t *rand_data); /************************************************************************** @@ -270,7 +270,7 @@ typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, int get_file(const char *filename, uint8_t **buf); #if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG) -void print_blob(const char *format, const uint8_t *data, int size, ...); +EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...); #else #define print_blob(...) #endif diff --git a/ssl/crypto_misc.c b/ssl/crypto_misc.c index 8eded5af9..6f70665d9 100644 --- a/ssl/crypto_misc.c +++ b/ssl/crypto_misc.c @@ -82,7 +82,7 @@ int get_file(const char *filename, uint8_t **buf) * - On Linux use /dev/urandom * - If none of these work then use a custom RNG. */ -void RNG_initialize(const uint8_t *seed_buf, int size) +EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size) { if (rng_ref_count == 0) { @@ -106,9 +106,7 @@ void RNG_initialize(const uint8_t *seed_buf, int size) int i; for (i = 0; i < size/(int)sizeof(uint64_t); i++) - { rng_num ^= *((uint64_t *)&seed_buf[i*sizeof(uint64_t)]); - } srand((long)seed_buf); /* use the stack ptr as another rnd seed */ #endif @@ -120,7 +118,7 @@ void RNG_initialize(const uint8_t *seed_buf, int size) /** * Terminate the RNG engine. */ -void RNG_terminate(void) +EXP_FUNC void STDCALL RNG_terminate(void) { if (--rng_ref_count == 0) { @@ -135,7 +133,7 @@ void RNG_terminate(void) /** * Set a series of bytes with a random number. Individual bytes can be 0 */ -void get_random(int num_rand_bytes, uint8_t *rand_data) +EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data) { #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM) /* use the Linux default */ @@ -160,9 +158,7 @@ void get_random(int num_rand_bytes, uint8_t *rand_data) memcpy(rand_data, &big_num1, sizeof(uint64_t)); if (num_rand_bytes > sizeof(uint64_t)) - { memcpy(&rand_data[8], &big_num2, sizeof(uint64_t)); - } if (num_rand_bytes > 16) { @@ -189,9 +185,7 @@ void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) for (i = 0; i < num_rand_bytes; i++) { while (rand_data[i] == 0) /* can't be 0 */ - { rand_data[i] = (uint8_t)(rand()); - } } } @@ -243,7 +237,7 @@ static void print_hex(uint8_t hex) * @param data [in] The start of data to use * @param ... [in] Any additional arguments */ -void print_blob(const char *format, +EXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...) { int i; @@ -264,7 +258,7 @@ void print_blob(const char *format, } #elif defined(WIN32) /* VC6.0 doesn't handle variadic macros */ -void print_blob(const char *format, const unsigned char *data, +EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data, int size, ...) {} #endif diff --git a/www/test_dir/health.sh b/www/test_dir/health.sh index 1697e2d09..d5c7d766b 100755 --- a/www/test_dir/health.sh +++ b/www/test_dir/health.sh @@ -3,10 +3,10 @@ echo "Content-Type: text/html" echo echo "System Health" -echo "

System Health for '`hostname`'

" +echo "

System Health for '`/bin/hostname`'

" echo "

Processes

" -ps -ef | sed -e "s/\(.*\)/
\1<\/td><\/tr>/" +/bin/ps -ef | /bin/sed -e "s/\(.*\)/
\1<\/td><\/tr>/" echo "

Free FileSystem Space

" echo "" -df -h . | sed -e "s/\(.*\)/
\1<\/td><\/tr>/" +/bin/df -h / | /bin/sed -e "s/\(.*\)/
\1<\/td><\/tr>/" echo "
" diff --git a/www/test_dir/prot/.htaccess b/www/test_dir/prot/.htaccess new file mode 100644 index 000000000..a8cf5665e --- /dev/null +++ b/www/test_dir/prot/.htaccess @@ -0,0 +1,2 @@ +SSLRequireSSL + diff --git a/www/test_dir/prot/.htpasswd b/www/test_dir/prot/.htpasswd new file mode 100644 index 000000000..16d3fe1a3 --- /dev/null +++ b/www/test_dir/prot/.htpasswd @@ -0,0 +1 @@ +abcd:CQhgDPyy0rvEU8OMxnQIvg==$YdJfIKZimFLYxPf/rbnhtQ== diff --git a/www/test_dir/prot/index.html b/www/test_dir/prot/index.html new file mode 100644 index 000000000..65f23bce6 --- /dev/null +++ b/www/test_dir/prot/index.html @@ -0,0 +1,6 @@ + +axhttpd is running + +Looks like you got to this directory. + + diff --git a/www/test_dir/test_cgi.php b/www/test_dir/test_cgi.php index 5171ff3e7..feecbb1ec 100755 --- a/www/test_dir/test_cgi.php +++ b/www/test_dir/test_cgi.php @@ -1,4 +1,4 @@ -#!/usr/bin/php +#!/bin/php