diff options
Diffstat (limited to 'libs/luci-lib-nixio/axTLS/httpd')
-rw-r--r-- | libs/luci-lib-nixio/axTLS/httpd/Config.in | 163 | ||||
-rw-r--r-- | libs/luci-lib-nixio/axTLS/httpd/Makefile | 127 | ||||
-rw-r--r-- | libs/luci-lib-nixio/axTLS/httpd/axhttp.h | 154 | ||||
-rw-r--r-- | libs/luci-lib-nixio/axTLS/httpd/axhttpd.c | 604 | ||||
-rw-r--r-- | libs/luci-lib-nixio/axTLS/httpd/htpasswd.c | 136 | ||||
-rwxr-xr-x | libs/luci-lib-nixio/axTLS/httpd/kepler-1.1-snapshot-20070521-1825.tar.gz | bin | 0 -> 768249 bytes | |||
-rw-r--r-- | libs/luci-lib-nixio/axTLS/httpd/kepler.patch | 64 | ||||
-rw-r--r-- | libs/luci-lib-nixio/axTLS/httpd/proc.c | 1238 | ||||
-rw-r--r-- | libs/luci-lib-nixio/axTLS/httpd/tdate_parse.c | 119 |
9 files changed, 2605 insertions, 0 deletions
diff --git a/libs/luci-lib-nixio/axTLS/httpd/Config.in b/libs/luci-lib-nixio/axTLS/httpd/Config.in new file mode 100644 index 000000000..513d57ae3 --- /dev/null +++ b/libs/luci-lib-nixio/axTLS/httpd/Config.in @@ -0,0 +1,163 @@ +# +# For a description of the syntax of this configuration file, +# see scripts/config/Kconfig-language.txt +# + +menu "Axhttpd Configuration" +depends on CONFIG_AXHTTPD + +config CONFIG_HTTP_STATIC_BUILD + bool "Static Build" + default n + help + 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 + int "HTTP port" + default 80 + help + The port number of the normal HTTP server. + + You must be a root user in order to use the default port. + +config CONFIG_HTTP_HTTPS_PORT + int "HTTPS port" + default 443 + help + The port number of the HTTPS server. + + You must be a root user in order to use the default port. + +config CONFIG_HTTP_SESSION_CACHE_SIZE + int "SSL session cache size" + default 5 + help + The size of the SSL session cache. + + This is not actually related to the number of concurrent users, but + for optimum performance they should be the same (with a penalty + in memory usage). + +config CONFIG_HTTP_WEBROOT + string "Web root location" + default "../www" if !CONFIG_PLATFORM_WIN32 + default "..\\www" if CONFIG_PLATFORM_WIN32 + help + The location of the web root in relation to axhttpd. This is + the directory where index.html lives. + +config CONFIG_HTTP_TIMEOUT + int "Timeout" + default 300 + help + Set the timeout of a connection in seconds. + +menu "CGI" +depends on !CONFIG_PLATFORM_WIN32 + +config CONFIG_HTTP_HAS_CGI + bool "Enable CGI" + default y + depends on !CONFIG_PLATFORM_WIN32 + help + Enable the CGI capability. Not available on Win32 platforms. + +config CONFIG_HTTP_CGI_EXTENSIONS + string "CGI File Extension(s)" + default ".lua,.lp" + depends on CONFIG_HTTP_HAS_CGI + help + Tell axhhtpd what file extension(s) are used for CGI. + + This is a comma separated list - e.g. ".php,.pl" etc + +config CONFIG_HTTP_ENABLE_LUA + bool "Enable Lua" + default y + depends on CONFIG_HTTP_HAS_CGI + help + Lua is a powerful, fast, light-weight, embeddable scripting language. + + See http://www.lua.org for details. + +config CONFIG_HTTP_LUA_PREFIX + string "Lua's Installation Prefix" + default "/usr/local" + depends on CONFIG_HTTP_ENABLE_LUA + + help + The location of Lua's installation prefix. This is also necessary for + Lua's cgi launcher application. + +config CONFIG_HTTP_LUA_CGI_LAUNCHER + string "CGI launcher location" + default "/bin/cgi.exe" if CONFIG_PLATFORM_CYGWIN + default "/bin/cgi" if !CONFIG_PLATFORM_CYGWIN + depends on CONFIG_HTTP_ENABLE_LUA + help + The location of LUA's CGI launcher application (after + the CONFIG_HTTP_LUA_PREFIX) + +config CONFIG_HTTP_BUILD_LUA + bool "Build Lua" + default n + depends on CONFIG_HTTP_ENABLE_LUA + help + Build Lua and install in /usr/local/bin + +endmenu + +config CONFIG_HTTP_DIRECTORIES + bool "Enable Directory Listing" + default y + help + Enable directory listing. + +config CONFIG_HTTP_HAS_AUTHORIZATION + bool "Enable authorization" + default y + help + Pages/directories can have passwords associated with them. + +config CONFIG_HTTP_HAS_IPV6 + bool "Enable IPv6" + default n + depends on !CONFIG_PLATFORM_WIN32 + help + Use IPv6 instead of IPv4. + + Does not work under Win32 + +config CONFIG_HTTP_ENABLE_DIFFERENT_USER + bool "Enable different user" + default n + depends on !CONFIG_PLATFORM_WIN32 + help + Allow the web server to be run as a different user + +config CONFIG_HTTP_USER + string "As User" + default "nobody" + depends on CONFIG_HTTP_ENABLE_DIFFERENT_USER + help + The user name that will be used to run axhttpd. + +config CONFIG_HTTP_VERBOSE + bool "Verbose Mode" + default y if CONFIG_SSL_FULL_MODE + default n if !CONFIG_SSL_FULL_MODE + help + Enable extra statements used when using axhttpd. + +config CONFIG_HTTP_IS_DAEMON + bool "Run as a daemon" + default n + depends on !CONFIG_PLATFORM_WIN32 + help + Run axhttpd as a background process. + + Does not work under Win32 + +endmenu + diff --git a/libs/luci-lib-nixio/axTLS/httpd/Makefile b/libs/luci-lib-nixio/axTLS/httpd/Makefile new file mode 100644 index 000000000..b8c18d244 --- /dev/null +++ b/libs/luci-lib-nixio/axTLS/httpd/Makefile @@ -0,0 +1,127 @@ +# +# Copyright (c) 2007, Cameron Rich +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the axTLS project nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +all : web_server lua + +AXTLS_HOME=.. + +include $(AXTLS_HOME)/config/.config +include $(AXTLS_HOME)/config/makefile.conf + +ifndef CONFIG_PLATFORM_WIN32 + +ifdef CONFIG_PLATFORM_CYGWIN +TARGET=$(AXTLS_HOME)/$(STAGE)/axhttpd.exe +TARGET2=$(AXTLS_HOME)/$(STAGE)/htpasswd.exe +else +TARGET=$(AXTLS_HOME)/$(STAGE)/axhttpd +TARGET2=$(AXTLS_HOME)/$(STAGE)/htpasswd +endif + +ifdef CONFIG_HTTP_STATIC_BUILD +LIBS=$(AXTLS_HOME)/$(STAGE)/libaxtls.a +else +LIBS=-L$(AXTLS_HOME)/$(STAGE) -laxtls +endif + +ifdef CONFIG_HTTP_BUILD_LUA +lua: kepler-1.1 + +kepler-1.1: + @tar xvfz kepler-1.1-snapshot-20070521-1825.tar.gz + @cat kepler.patch | patch -p0 + cd kepler-1.1; ./configure --prefix=$(CONFIG_HTTP_LUA_PREFIX) --launcher=cgi --lua-suffix= ; make install +else +lua: +endif + +else # win32 build +lua: + +TARGET=$(AXTLS_HOME)/$(STAGE)/axhttpd.exe +TARGET2=$(AXTLS_HOME)/$(STAGE)/htpasswd.exe + +ifdef CONFIG_HTTP_STATIC_BUILD +LIBS=$(AXTLS_HOME)/$(STAGE)/axtls.static.lib $(AXTLS_HOME)\\config\\axtls.res +else +LIBS=$(AXTLS_HOME)/$(STAGE)/axtls.lib $(AXTLS_HOME)\\config\\axtls.res +endif +endif + +ifndef CONFIG_AXHTTPD +web_server: +else + +web_server :: $(TARGET) + +ifdef CONFIG_HTTP_HAS_AUTHORIZATION +web_server :: $(TARGET2) +endif + +OBJ= \ + axhttpd.o \ + proc.o \ + tdate_parse.o + +include $(AXTLS_HOME)/config/makefile.post + +ifndef CONFIG_PLATFORM_WIN32 + +$(TARGET): $(OBJ) $(AXTLS_HOME)/$(STAGE)/libaxtls.a + $(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) +ifdef CONFIG_STRIP_UNWANTED_SECTIONS + $(STRIP) --remove-section=.comment $(TARGET) +endif + +$(TARGET2): htpasswd.o $(AXTLS_HOME)/$(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) /out:$@ $(LIBS) $? + +$(TARGET2): htpasswd.obj + $(LD) $(LDFLAGS) /out:$@ $(LIBS) $? +endif + +endif # CONFIG_AXHTTPD + +clean:: + -@rm -f $(TARGET)* + -@rm -fr kepler-1.1 + diff --git a/libs/luci-lib-nixio/axTLS/httpd/axhttp.h b/libs/luci-lib-nixio/axTLS/httpd/axhttp.h new file mode 100644 index 000000000..73c299fb1 --- /dev/null +++ b/libs/luci-lib-nixio/axTLS/httpd/axhttp.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ssl.h" + +#define BACKLOG 15 +#define VERSION "1.0.0" +#ifdef CONFIG_HTTP_HAS_IPV6 +#define HAVE_IPV6 +#endif + +#define MAXPOSTDATASIZE 30000 +#define MAXREQUESTLENGTH 256 +#define BLOCKSIZE 4096 + +#define INITIAL_CONNECTION_SLOTS 10 +#define CONFIG_HTTP_DEFAULT_SSL_OPTIONS SSL_DISPLAY_CERTS + +#define STATE_WANT_TO_READ_HEAD 1 +#define STATE_WANT_TO_SEND_HEAD 2 +#define STATE_WANT_TO_READ_FILE 3 +#define STATE_WANT_TO_SEND_FILE 4 +#define STATE_DOING_DIR 5 + +enum +{ + TYPE_GET, + TYPE_HEAD, + TYPE_POST +}; + +struct connstruct +{ + struct connstruct *next; + int state; + int reqtype; + int networkdesc; + int filedesc; + SSL *ssl; + +#if defined(CONFIG_HTTP_DIRECTORIES) +#ifdef WIN32 + HANDLE dirp; + WIN32_FIND_DATA file_data; +#else + DIR *dirp; +#endif +#endif + + time_t timeout; + char actualfile[MAXREQUESTLENGTH]; + char filereq[MAXREQUESTLENGTH]; + char dirname[MAXREQUESTLENGTH]; + char server_name[MAXREQUESTLENGTH]; + int numbytes; + char databuf[BLOCKSIZE]; + uint8_t is_ssl; + uint8_t close_when_done; + time_t if_modified_since; + +#if defined(CONFIG_HTTP_HAS_CGI) + uint8_t is_cgi; +#ifdef CONFIG_HTTP_ENABLE_LUA + uint8_t is_lua; +#endif + int content_length; + char remote_addr[MAXREQUESTLENGTH]; + char uri_request[MAXREQUESTLENGTH]; + char uri_path_info[MAXREQUESTLENGTH]; + char uri_query[MAXREQUESTLENGTH]; + char cookie[MAXREQUESTLENGTH]; +#endif +#if defined(CONFIG_HTTP_HAS_AUTHORIZATION) + char authorization[MAXREQUESTLENGTH]; +#endif + int post_read; + int post_state; + char *post_data; +}; + +struct serverstruct +{ + struct serverstruct *next; + int sd; + int is_ssl; + SSL_CTX *ssl_ctx; +}; + +#if defined(CONFIG_HTTP_HAS_CGI) +struct cgiextstruct +{ + struct cgiextstruct *next; + char *ext; +}; +#endif + +/* global prototypes */ +extern struct serverstruct *servers; +extern struct connstruct *usedconns; +extern struct connstruct *freeconns; +extern const char * const server_version; + +#if defined(CONFIG_HTTP_HAS_CGI) +extern struct cgiextstruct *cgiexts; +#endif + +/* conn.c prototypes */ +void removeconnection(struct connstruct *cn); + +/* proc.c prototypes */ +void procdodir(struct connstruct *cn); +void procreadhead(struct connstruct *cn); +void procsendhead(struct connstruct *cn); +void procreadfile(struct connstruct *cn); +void procsendfile(struct connstruct *cn); +#if defined(CONFIG_HTTP_HAS_CGI) +void read_post_data(struct connstruct *cn); +#endif + +/* misc.c prototypes */ +char *my_strncpy(char *dest, const char *src, size_t n); +int isdir(const char *name); + +/* tdate prototypes */ +void tdate_init(void); +time_t tdate_parse(const char* str); + diff --git a/libs/luci-lib-nixio/axTLS/httpd/axhttpd.c b/libs/luci-lib-nixio/axTLS/httpd/axhttpd.c new file mode 100644 index 000000000..35d36f64c --- /dev/null +++ b/libs/luci-lib-nixio/axTLS/httpd/axhttpd.c @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <pwd.h> +#include "axhttp.h" + +struct serverstruct *servers; +struct connstruct *usedconns; +struct connstruct *freeconns; +const char * const server_version = "axhttpd/"AXTLS_VERSION; + +static void addtoservers(int sd); +static int openlistener(int port); +static void handlenewconnection(int listenfd, int is_ssl); +static void addconnection(int sd, char *ip, int is_ssl); +static void ax_chdir(void); + +#if defined(CONFIG_HTTP_HAS_CGI) +struct cgiextstruct *cgiexts; +static void addcgiext(const char *tp); + +#if !defined(WIN32) +static void reaper(int sigtype) +{ + wait3(NULL, WNOHANG, NULL); +} +#endif +#endif + +#ifdef CONFIG_HTTP_VERBOSE /* should really be in debug mode or something */ +/* clean up memory for valgrind */ +static void sigint_cleanup(int sig) +{ + struct serverstruct *sp; + struct connstruct *tp; + + while (servers != NULL) + { + if (servers->is_ssl) + ssl_ctx_free(servers->ssl_ctx); + + sp = servers->next; + free(servers); + servers = sp; + } + + while (freeconns != NULL) + { + tp = freeconns->next; + free(freeconns); + freeconns = tp; + } + + while (usedconns != NULL) + { + tp = usedconns->next; + free(usedconns); + usedconns = 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); +} + +static void die(int sigtype) +{ + exit(0); +} +#endif + +int main(int argc, char *argv[]) +{ + fd_set rfds, wfds; + struct connstruct *tp, *to; + struct serverstruct *sp; + int rnum, wnum, active; + int i; + time_t currtime; + +#ifdef WIN32 + WORD wVersionRequested = MAKEWORD(2, 2); + WSADATA wsaData; + WSAStartup(wVersionRequested,&wsaData); +#else + signal(SIGPIPE, SIG_IGN); +#if defined(CONFIG_HTTP_HAS_CGI) + signal(SIGCHLD, reaper); +#endif +#ifdef CONFIG_HTTP_VERBOSE + signal(SIGQUIT, die); +#endif +#endif + +#ifdef CONFIG_HTTP_VERBOSE + signal(SIGTERM, die); + signal(SIGINT, sigint_cleanup); +#endif + tdate_init(); + + for (i = 0; i < INITIAL_CONNECTION_SLOTS; i++) + { + tp = freeconns; + freeconns = (struct connstruct *)calloc(1, sizeof(struct connstruct)); + freeconns->next = tp; + } + + if ((active = openlistener(CONFIG_HTTP_PORT)) == -1) + { +#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "ERR: Couldn't bind to port %d\n", + CONFIG_HTTP_PORT); +#endif + exit(1); + } + + addtoservers(active); + + if ((active = openlistener(CONFIG_HTTP_HTTPS_PORT)) == -1) + { +#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "ERR: Couldn't bind to port %d\n", + CONFIG_HTTP_HTTPS_PORT); +#endif + exit(1); + } + + addtoservers(active); + servers->ssl_ctx = ssl_ctx_new(CONFIG_HTTP_DEFAULT_SSL_OPTIONS, + CONFIG_HTTP_SESSION_CACHE_SIZE); + servers->is_ssl = 1; + +#if defined(CONFIG_HTTP_HAS_CGI) + addcgiext(CONFIG_HTTP_CGI_EXTENSIONS); +#endif + +#if defined(CONFIG_HTTP_VERBOSE) +#if defined(CONFIG_HTTP_HAS_CGI) + printf("addcgiext %s\n", CONFIG_HTTP_CGI_EXTENSIONS); +#endif + printf("%s: listening on ports %d (http) and %d (https)\n", + server_version, CONFIG_HTTP_PORT, CONFIG_HTTP_HTTPS_PORT); + TTY_FLUSH(); +#endif + + ax_chdir(); + +#ifdef CONFIG_HTTP_ENABLE_DIFFERENT_USER + { + struct passwd *pd = getpwnam(CONFIG_HTTP_USER); + + if (pd != NULL) + { + int res = setuid(pd->pw_uid); + res |= setgid(pd->pw_gid); + +#if defined(CONFIG_HTTP_VERBOSE) + if (res == 0) + { + printf("change to '%s' successful\n", CONFIG_HTTP_USER); + TTY_FLUSH(); + } +#endif + } + + } +#endif + + +#ifndef WIN32 +#ifdef CONFIG_HTTP_IS_DAEMON + if (fork() > 0) /* parent will die */ + exit(0); + + setsid(); +#endif +#endif + + /* main loop */ + while (1) + { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + rnum = wnum = -1; + sp = servers; + + while (sp != NULL) /* read each server port */ + { + FD_SET(sp->sd, &rfds); + + if (sp->sd > rnum) + rnum = sp->sd; + sp = sp->next; + } + + /* Add the established sockets */ + tp = usedconns; + currtime = time(NULL); + + while (tp != NULL) + { + if (currtime > tp->timeout) /* timed out? Kill it. */ + { + to = tp; + tp = tp->next; + removeconnection(to); + continue; + } + + if (tp->state == STATE_WANT_TO_READ_HEAD) + { + FD_SET(tp->networkdesc, &rfds); + if (tp->networkdesc > rnum) + rnum = tp->networkdesc; + } + + if (tp->state == STATE_WANT_TO_SEND_HEAD) + { + FD_SET(tp->networkdesc, &wfds); + if (tp->networkdesc > wnum) + wnum = tp->networkdesc; + } + + if (tp->state == STATE_WANT_TO_READ_FILE) + { + FD_SET(tp->filedesc, &rfds); + if (tp->filedesc > rnum) + rnum = tp->filedesc; + } + + if (tp->state == STATE_WANT_TO_SEND_FILE) + { + 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(wnum > rnum ? wnum+1 : rnum+1, + rnum != -1 ? &rfds : NULL, + wnum != -1 ? &wfds : NULL, + NULL, NULL); + + /* New connection? */ + sp = servers; + while (active > 0 && sp != NULL) + { + if (FD_ISSET(sp->sd, &rfds)) + { + handlenewconnection(sp->sd, sp->is_ssl); + active--; + } + + sp = sp->next; + } + + /* Handle the established sockets */ + tp = usedconns; + + while (active > 0 && tp != NULL) + { + to = tp; + tp = tp->next; + + if (to->state == STATE_WANT_TO_READ_HEAD && + FD_ISSET(to->networkdesc, &rfds)) + { + active--; +#if defined(CONFIG_HTTP_HAS_CGI) + if (to->post_state) + read_post_data(to); + else +#endif + procreadhead(to); + } + + if (to->state == STATE_WANT_TO_SEND_HEAD && + FD_ISSET(to->networkdesc, &wfds)) + { + active--; + procsendhead(to); + } + + if (to->state == STATE_WANT_TO_READ_FILE && + FD_ISSET(to->filedesc, &rfds)) + { + active--; + procreadfile(to); + } + + if (to->state == STATE_WANT_TO_SEND_FILE && + FD_ISSET(to->networkdesc, &wfds)) + { + active--; + procsendfile(to); + } + +#if defined(CONFIG_HTTP_DIRECTORIES) + if (to->state == STATE_DOING_DIR && + FD_ISSET(to->networkdesc, &wfds)) + { + active--; + procdodir(to); + } +#endif + } + } + + return 0; +} + +#if defined(CONFIG_HTTP_HAS_CGI) +static void addcgiext(const char *cgi_exts) +{ + 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 + +static void addtoservers(int sd) +{ + struct serverstruct *tp = (struct serverstruct *) + calloc(1, sizeof(struct serverstruct)); + tp->next = servers; + tp->sd = sd; + servers = tp; +} + +#ifdef HAVE_IPV6 +static void handlenewconnection(int listenfd, int is_ssl) +{ + struct sockaddr_in6 their_addr; + int tp = sizeof(their_addr); + char ipbuf[100]; + int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp); + + if (tp == sizeof(struct sockaddr_in6)) + inet_ntop(AF_INET6, &their_addr.sin6_addr, ipbuf, sizeof(ipbuf)); + else if (tp == sizeof(struct sockaddr_in)) + inet_ntop(AF_INET, &(((struct sockaddr_in *)&their_addr)->sin_addr), + ipbuf, sizeof(ipbuf)); + else + *ipbuf = '\0'; + + addconnection(connfd, ipbuf, is_ssl); +} + +#else +static void handlenewconnection(int listenfd, int is_ssl) +{ + struct sockaddr_in their_addr; + socklen_t tp = sizeof(struct sockaddr_in); + int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp); + addconnection(connfd, inet_ntoa(their_addr.sin_addr), is_ssl); +} +#endif + +static int openlistener(int port) +{ + int sd; +#ifdef WIN32 + char tp = 1; +#else + int tp = 1; +#endif +#ifndef HAVE_IPV6 + struct sockaddr_in my_addr; + + if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + return -1; + + memset(&my_addr, 0, sizeof(my_addr)); + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons((short)port); + my_addr.sin_addr.s_addr = INADDR_ANY; +#else + struct sockaddr_in6 my_addr; + + if ((sd = socket(AF_INET6, SOCK_STREAM, 0)) == -1) + return -1; + + memset(&my_addr, 0, sizeof(my_addr)); + my_addr.sin6_family = AF_INET6; + my_addr.sin6_port = htons(port); + my_addr.sin6_addr.s_addr = INADDR_ANY; +#endif + + setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp)); + if (bind(sd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) + { + close(sd); + return -1; + } + + listen(sd, BACKLOG); + return sd; +} + +/* Wrapper function for strncpy() that guarantees + a null-terminated string. This is to avoid any possible + issues due to strncpy()'s behaviour. + */ +char *my_strncpy(char *dest, const char *src, size_t n) +{ + strncpy(dest, src, n); + dest[n-1] = '\0'; + return dest; +} + +int isdir(const char *tpbuf) +{ + struct stat st; + char path[MAXREQUESTLENGTH]; + strcpy(path, tpbuf); + +#ifdef WIN32 /* win32 stat() can't handle trailing '\' */ + if (path[strlen(path)-1] == '\\') + path[strlen(path)-1] = 0; +#endif + + if (stat(path, &st) == -1) + return 0; + + if ((st.st_mode & S_IFMT) == S_IFDIR) + return 1; + + return 0; +} + +static void addconnection(int sd, char *ip, int is_ssl) +{ + struct connstruct *tp; + + /* Get ourselves a connstruct */ + if (freeconns == NULL) + tp = (struct connstruct *)calloc(1, 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) + tp->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'; + tp->state = STATE_WANT_TO_READ_HEAD; + tp->reqtype = TYPE_GET; + tp->close_when_done = 0; + tp->timeout = time(NULL) + CONFIG_HTTP_TIMEOUT; +#if defined(CONFIG_HTTP_HAS_CGI) + strcpy(tp->remote_addr, ip); +#endif +} + +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(cn->ssl); + cn->ssl = NULL; + } + + 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 +} + +/* + * Change directories one way or the other. + */ +static void ax_chdir(void) +{ + static char *webroot = CONFIG_HTTP_WEBROOT; + + if (chdir(webroot)) + { +#ifdef CONFIG_HTTP_VERBOSE + fprintf(stderr, "'%s' is not a directory\n", webroot); +#endif + exit(1); + } +} + diff --git a/libs/luci-lib-nixio/axTLS/httpd/htpasswd.c b/libs/luci-lib-nixio/axTLS/httpd/htpasswd.c new file mode 100644 index 000000000..1a7a2311f --- /dev/null +++ b/libs/luci-lib-nixio/axTLS/httpd/htpasswd.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#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); +} + +#ifdef WIN32 +static char * getpass(const char *prompt) +{ + static char buf[127]; + FILE *fp = stdin; + + printf(prompt); TTY_FLUSH(); +#if 0 + fp = fopen("/dev/tty", "w"); + if (fp == NULL) + { + printf("null\n"); TTY_FLUSH(); + fp = stdin; + } +#endif + + fgets(buf, sizeof(buf), fp); + while (buf[strlen(buf)-1] < ' ') + buf[strlen(buf)-1] = '\0'; + + //if (fp != stdin) + // fclose(fp); + return buf; +} +#endif + +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((uint8_t *)pw, sizeof(pw)); + get_random(MD5_SIZE, md5_salt); + RNG_terminate(); + base64_encode(md5_salt, MD5_SIZE, b64_salt, sizeof(b64_salt)); + + MD5_Init(&ctx); + MD5_Update(&ctx, md5_salt, MD5_SIZE); + MD5_Update(&ctx, (uint8_t *)pw, strlen(pw)); + MD5_Final(md5_pass, &ctx); + 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/libs/luci-lib-nixio/axTLS/httpd/kepler-1.1-snapshot-20070521-1825.tar.gz b/libs/luci-lib-nixio/axTLS/httpd/kepler-1.1-snapshot-20070521-1825.tar.gz Binary files differnew file mode 100755 index 000000000..d1caec5a5 --- /dev/null +++ b/libs/luci-lib-nixio/axTLS/httpd/kepler-1.1-snapshot-20070521-1825.tar.gz diff --git a/libs/luci-lib-nixio/axTLS/httpd/kepler.patch b/libs/luci-lib-nixio/axTLS/httpd/kepler.patch new file mode 100644 index 000000000..dbab7e501 --- /dev/null +++ b/libs/luci-lib-nixio/axTLS/httpd/kepler.patch @@ -0,0 +1,64 @@ +diff -Naur kepler-1.1/launcher/cgi/Makefile kepler-1.1.new/launcher/cgi/Makefile +--- kepler-1.1/launcher/cgi/Makefile 2007-04-21 06:41:49.000000000 +1000 ++++ kepler-1.1.new/launcher/cgi/Makefile 2007-05-16 22:13:38.750000000 +1000 +@@ -16,7 +16,7 @@ + + + $T: $(CH) $(OBJS) +- $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) ++ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) -L../../lua-5.1.2/src -llua + + build: $T + +diff -Naur kepler-1.1/luafilesystem/Makefile kepler-1.1.new/luafilesystem/Makefile +--- kepler-1.1/luafilesystem/Makefile 2007-04-21 06:41:49.000000000 +1000 ++++ kepler-1.1.new/luafilesystem/Makefile 2007-05-16 22:06:25.546875000 +1000 +@@ -12,7 +12,7 @@ + lib: src/$(LIBNAME) + + src/$(LIBNAME): $(OBJS) +- export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS) ++ export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS) -L../lua-5.1.2/src -llua + + install: src/$(LIBNAME) + mkdir -p $(LUA_LIBDIR) +diff -Naur kepler-1.1/luasocket-2.0.1/src/makefile kepler-1.1.new/luasocket-2.0.1/src/makefile +--- kepler-1.1/luasocket-2.0.1/src/makefile 2007-04-21 06:41:49.000000000 +1000 ++++ kepler-1.1.new/luasocket-2.0.1/src/makefile 2007-05-16 22:36:37.125000000 +1000 +@@ -47,10 +47,10 @@ + all: $(SOCKET_SO) $(MIME_SO) + + $(SOCKET_SO): $(SOCKET_OBJS) +- $(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS) ++ $(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS) -L../../lua-5.1.2/src -llua + + $(MIME_SO): $(MIME_OBJS) +- $(LD) $(LDFLAGS) -o $@ $(MIME_OBJS) ++ $(LD) $(LDFLAGS) -o $@ $(MIME_OBJS) -L../../lua-5.1.2/src -llua + + $(UNIX_SO): $(UNIX_OBJS) + $(LD) $(LDFLAGS) -o $@ $(UNIX_OBJS) +diff -Naur kepler-1.1/md5/Makefile kepler-1.1.new/md5/Makefile +--- kepler-1.1/md5/Makefile 2007-04-21 06:41:49.000000000 +1000 ++++ kepler-1.1.new/md5/Makefile 2007-05-16 22:06:44.593750000 +1000 +@@ -15,7 +15,7 @@ + + + src/$(LIBNAME) : $(OBJS) +- export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS) ++ export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS) -L../lua-5.1.2/src -llua + + $(COMPAT_DIR)/compat-5.1.o: $(COMPAT_DIR)/compat-5.1.c + $(CC) -c $(CFLAGS) -o $@ $(COMPAT_DIR)/compat-5.1.c +diff -Naur kepler-1.1/rings/Makefile kepler-1.1.new/rings/Makefile +--- kepler-1.1/rings/Makefile 2007-04-21 06:41:49.000000000 +1000 ++++ kepler-1.1.new/rings/Makefile 2007-05-16 22:05:28.765625000 +1000 +@@ -10,7 +10,7 @@ + OBJS= src/rings.o + + src/$(LIBNAME) : $(OBJS) +- export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS) ++ export MACOSX_DEPLOYMENT_TARGET="10.3"; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/$(LIBNAME) $(OBJS) -L../lua-5.1.2/src -llua + + install: + mkdir -p $(LUA_LIBDIR) diff --git a/libs/luci-lib-nixio/axTLS/httpd/proc.c b/libs/luci-lib-nixio/axTLS/httpd/proc.c new file mode 100644 index 000000000..3c897c98b --- /dev/null +++ b/libs/luci-lib-nixio/axTLS/httpd/proc.c @@ -0,0 +1,1238 @@ +/* + * Copyright (c) 2007-2008, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <string.h> +#include "axhttp.h" + +#define HTTP_VERSION "HTTP/1.1" + +static const char * index_file = "index.html"; + +static int special_read(struct connstruct *cn, void *buf, size_t count); +static int special_write(struct connstruct *cn, + const char *buf, size_t count); +static void send_error(struct connstruct *cn, int err); +static int hexit(char c); +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); +static const char *getmimetype(const char *name); + +#if defined(CONFIG_HTTP_DIRECTORIES) +static void urlencode(const uint8_t *s, char *t); +static void procdirlisting(struct connstruct *cn); +#endif +#if defined(CONFIG_HTTP_HAS_CGI) +static void proccgi(struct connstruct *cn); +static void decode_path_info(struct connstruct *cn, char *path_info); +static int init_read_post_data(char *buf, char *data, struct connstruct *cn, int old_rv); +#endif +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION +static int auth_check(struct connstruct *cn); +#endif + +#if AXDEBUG +#define AXDEBUGSTART \ + { \ + FILE *axdout; \ + axdout = fopen("/var/log/axdebug", "a"); \ + +#define AXDEBUGEND \ + fclose(axdout); \ + } +#else /* AXDEBUG */ +#define AXDEBUGSTART +#define AXDEBUGEND +#endif /* AXDEBUG */ + +/* Returns 1 if elems should continue being read, 0 otherwise */ +static int procheadelem(struct connstruct *cn, char *buf) +{ + char *delim, *value; + + if ((delim = strchr(buf, ' ')) == NULL) + return 0; + + *delim = 0; + value = delim+1; + + 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(value); + + if (sanitizefile(value) == 0) + { + send_error(cn, 403); + return 0; + } + +#if defined(CONFIG_HTTP_HAS_CGI) + decode_path_info(cn, value); +#else + my_strncpy(cn->filereq, value, MAXREQUESTLENGTH); +#endif + cn->if_modified_since = -1; + } + else if (strcmp(buf, "Host:") == 0) + { + if (sanitizehost(value) == 0) + { + removeconnection(cn); + return 0; + } + + my_strncpy(cn->server_name, 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) + { + cn->if_modified_since = tdate_parse(value); + } + else if (strcmp(buf, "Expect:") == 0) + { + send_error(cn, 417); /* expectation failed */ + return 0; + } +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION + else if (strcmp(buf, "Authorization:") == 0 && + strncmp(value, "Basic ", 6) == 0) + { + int size; + if (base64_decode(&value[6], strlen(&value[6]), + (uint8_t *)cn->authorization, &size)) + cn->authorization[0] = 0; /* error */ + else + cn->authorization[size] = 0; + } +#endif +#if defined(CONFIG_HTTP_HAS_CGI) + else if (strcmp(buf, "Content-Length:") == 0) + { + sscanf(value, "%d", &cn->content_length); + } + else if (strcmp(buf, "Cookie:") == 0) + { + my_strncpy(cn->cookie, value, MAXREQUESTLENGTH); + } +#endif + + return 1; +} + +#if defined(CONFIG_HTTP_DIRECTORIES) +static void procdirlisting(struct connstruct *cn) +{ + char buf[MAXREQUESTLENGTH]; + char actualfile[1024]; + + if (cn->reqtype == TYPE_HEAD) + { + snprintf(buf, sizeof(buf), HTTP_VERSION + " 200 OK\nContent-Type: text/html\n\n"); + write(cn->networkdesc, buf, strlen(buf)); + removeconnection(cn); + return; + } + + strcpy(actualfile, cn->actualfile); + +#ifdef WIN32 + strcat(actualfile, "*"); + cn->dirp = FindFirstFile(actualfile, &cn->file_data); + + if (cn->dirp == INVALID_HANDLE_VALUE) + { + send_error(cn, 404); + return; + } +#else + if ((cn->dirp = opendir(actualfile)) == NULL) + { + send_error(cn, 404); + return; + } +#endif + + snprintf(buf, sizeof(buf), HTTP_VERSION + " 200 OK\nContent-Type: text/html\n\n" + "<html><body>\n<title>Directory Listing</title>\n" + "<h3>Directory listing of %s://%s%s</h3><br />\n", + cn->is_ssl ? "https" : "http", cn->server_name, cn->filereq); + special_write(cn, buf, strlen(buf)); + cn->state = STATE_DOING_DIR; +} + +void procdodir(struct connstruct *cn) +{ +#ifndef WIN32 + struct dirent *dp; +#endif + char buf[MAXREQUESTLENGTH]; + char encbuf[1024]; + char *file; + + do + { + buf[0] = 0; + +#ifdef WIN32 + if (!FindNextFile(cn->dirp, &cn->file_data)) +#else + if ((dp = readdir(cn->dirp)) == NULL) +#endif + { + snprintf(buf, sizeof(buf), "</body></html>\n"); + special_write(cn, buf, strlen(buf)); + removeconnection(cn); +#ifndef WIN32 + closedir(cn->dirp); +#endif + return; + } + +#ifdef WIN32 + file = cn->file_data.cFileName; +#else + file = dp->d_name; +#endif + + /* if no index file, don't display the ".." directory */ + if (cn->filereq[0] == '/' && cn->filereq[1] == '\0' && + strcmp(file, "..") == 0) + continue; + + /* don't display files beginning with "." */ + if (file[0] == '.' && file[1] != '.') + continue; + + /* make sure a '/' is at the end of a directory */ + if (cn->filereq[strlen(cn->filereq)-1] != '/') + strcat(cn->filereq, "/"); + + /* see if the dir + file is another directory */ + snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file); + if (isdir(buf)) + strcat(file, "/"); + + urlencode((uint8_t *)file, encbuf); + snprintf(buf, sizeof(buf), "<a href=\"%s%s\">%s</a><br />\n", + cn->filereq, encbuf, file); + } while (special_write(cn, buf, strlen(buf))); +} + +/* Encode funny chars -> %xx in newly allocated storage */ +/* (preserves '/' !) */ +static void urlencode(const uint8_t *s, char *t) +{ + const uint8_t *p = s; + char *tp = t; + + for (; *p; p++) + { + if ((*p > 0x00 && *p < ',') || + (*p > '9' && *p < 'A') || + (*p > 'Z' && *p < '_') || + (*p > '_' && *p < 'a') || + (*p > 'z' && *p < 0xA1)) + { + sprintf((char *)tp, "%%%02X", *p); + tp += 3; + } + else + { + *tp = *p; + tp++; + } + } + + *tp='\0'; +} + +#endif + +void procreadhead(struct connstruct *cn) +{ + char buf[MAXREQUESTLENGTH*4], *tp, *next; + int rv; + + memset(buf, 0, MAXREQUESTLENGTH*4); + rv = special_read(cn, buf, sizeof(buf)-1); + if (rv <= 0) + { + if (rv < 0) /* really dead? */ + removeconnection(cn); + return; + } + + buf[rv] = '\0'; + next = tp = buf; + +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION + cn->authorization[0] = 0; +#endif + + /* Split up lines and send to procheadelem() */ + while (*next != '\0') + { + /* If we have a blank line, advance to next stage */ + if (*next == '\r' || *next == '\n') + { +#if defined(CONFIG_HTTP_HAS_CGI) + if (cn->reqtype == TYPE_POST && cn->content_length > 0) + { + if (init_read_post_data(buf,next,cn,rv) == 0) + return; + } +#endif + + buildactualfile(cn); + cn->state = STATE_WANT_TO_SEND_HEAD; + return; + } + + while (*next != '\r' && *next != '\n' && *next != '\0') + next++; + + if (*next == '\r') + { + *next = '\0'; + next += 2; + } + else if (*next == '\n') + *next++ = '\0'; + + if (procheadelem(cn, tp) == 0) + return; + + tp = next; + } +} + +/* In this function we assume that the file has been checked for + * maliciousness (".."s, etc) and has been decoded + */ +void procsendhead(struct connstruct *cn) +{ + char buf[MAXREQUESTLENGTH]; + struct stat stbuf; + time_t now = cn->timeout - CONFIG_HTTP_TIMEOUT; + char date[32]; + int file_exists; + + /* 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->filereq); TTY_FLUSH(); +#endif + removeconnection(cn); + return; + } +#endif + + file_exists = stat(cn->actualfile, &stbuf); + +#if defined(CONFIG_HTTP_HAS_CGI) + + if (file_exists != -1 && cn->is_cgi) + { + if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) + { + /* A non-executable file, or directory? */ + send_error(cn, 403); + } + else + proccgi(cn); + + return; + } +#endif + + /* look for "index.html"? */ + if (isdir(cn->actualfile)) + { + char tbuf[MAXREQUESTLENGTH]; + snprintf(tbuf, MAXREQUESTLENGTH, "%s%s", cn->actualfile, index_file); + + if ((file_exists = stat(tbuf, &stbuf)) != -1) + my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH); + else + { +#if defined(CONFIG_HTTP_DIRECTORIES) + /* If not, we do a directory listing of it */ + procdirlisting(cn); +#else + send_error(cn, 404); +#endif + return; + } + } + + if (file_exists == -1) + { + send_error(cn, 404); + return; + } + + strcpy(date, ctime(&now)); + + /* has the file been read before? */ + if (cn->if_modified_since != -1 && (cn->if_modified_since == 0 || + cn->if_modified_since >= stbuf.st_mtime)) + { + snprintf(buf, sizeof(buf), HTTP_VERSION" 304 Not Modified\nServer: " + "%s\nDate: %s\n", server_version, date); + special_write(cn, buf, strlen(buf)); + cn->state = STATE_WANT_TO_READ_HEAD; + return; + } + + if (cn->reqtype == TYPE_HEAD) + { + removeconnection(cn); + return; + } + else + { + int flags = O_RDONLY; +#if defined(WIN32) || defined(CONFIG_PLATFORM_CYGWIN) + flags |= O_BINARY; +#endif + cn->filedesc = open(cn->actualfile, flags); + + if (cn->filedesc < 0) + { + send_error(cn, 404); + return; + } + + snprintf(buf, sizeof(buf), HTTP_VERSION" 200 OK\nServer: %s\n" + "Content-Type: %s\nContent-Length: %ld\n" + "Date: %sLast-Modified: %s\n", server_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:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq); + TTY_FLUSH(); +#endif + +#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 + } +} + +void procreadfile(struct connstruct *cn) +{ + int rv = read(cn->filedesc, cn->databuf, BLOCKSIZE); + + if (rv <= 0) + { + 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; + cn->state = STATE_WANT_TO_SEND_FILE; +} + +void procsendfile(struct connstruct *cn) +{ + int rv = special_write(cn, cn->databuf, cn->numbytes); + + if (rv < 0) + removeconnection(cn); + else if (rv == cn->numbytes) + { + cn->state = STATE_WANT_TO_READ_FILE; + } + else if (rv == 0) + { + /* Do nothing */ + } + else + { + memmove(cn->databuf, cn->databuf + rv, cn->numbytes - rv); + cn->numbytes -= rv; + } +} + +#if defined(CONFIG_HTTP_HAS_CGI) +/* Should this be a bit more dynamic? It would mean more calls to malloc etc */ +#define CGI_ARG_SIZE 17 + +static void proccgi(struct connstruct *cn) +{ + int tpipe[2], spipe[2]; + char *myargs[2]; + char cgienv[CGI_ARG_SIZE][MAXREQUESTLENGTH]; + char * cgiptr[CGI_ARG_SIZE+4]; + const char *type = "HEAD"; + int cgi_index = 0, i; + pid_t pid; +#ifdef WIN32 + int tmp_stdout; +#endif + + snprintf(cgienv[0], MAXREQUESTLENGTH, + HTTP_VERSION" 200 OK\nServer: %s\n%s", + server_version, (cn->reqtype == TYPE_HEAD) ? "\n" : ""); + special_write(cn, cgienv[0], strlen(cgienv[0])); + + if (cn->reqtype == TYPE_HEAD) + { + removeconnection(cn); + return; + } + +#ifdef CONFIG_HTTP_VERBOSE + printf("[CGI]: %s:/%s\n", cn->is_ssl ? "https" : "http", cn->filereq); + TTY_FLUSH(); +#endif + + /* win32 cgi is a bit too painful */ +#ifndef WIN32 + /* set up pipe that is used for sending POST query data to CGI script*/ + if (cn->reqtype == TYPE_POST) + { + if (pipe(spipe) == -1) + { + printf("[CGI]: could not create pipe"); + TTY_FLUSH(); + return; + } + } + + if (pipe(tpipe) == -1) + { + printf("[CGI]: could not create pipe"); + TTY_FLUSH(); + return; + } + + /* + * use vfork() instead of fork() for performance + */ + if ((pid = vfork()) > 0) /* parent */ + { + /* Send POST query data to CGI script */ + if ((cn->reqtype == TYPE_POST) && (cn->content_length > 0)) + { + write(spipe[1], cn->post_data, cn->content_length); + close(spipe[0]); + close(spipe[1]); + + /* free the memory that is allocated in read_post_data() */ + free(cn->post_data); + cn->post_data = NULL; + } + + /* Close the write descriptor */ + close(tpipe[1]); + cn->filedesc = tpipe[0]; + cn->state = STATE_WANT_TO_READ_FILE; + cn->close_when_done = 1; + return; + } + + if (pid < 0) /* vfork failed */ + exit(1); + + /* The problem child... */ + + /* Our stdout/stderr goes to the socket */ + dup2(tpipe[1], 1); + dup2(tpipe[1], 2); + + /* If it was a POST request, send the socket data to our stdin */ + if (cn->reqtype == TYPE_POST) + dup2(spipe[0], 0); + else /* Otherwise we can shutdown the read side of the sock */ + shutdown(cn->networkdesc, 0); + + myargs[0] = cn->actualfile; + myargs[1] = NULL; + + /* + * set the cgi args. A url is defined by: + * http://$SERVER_NAME:$SERVER_PORT$SCRIPT_NAME$PATH_INFO?$QUERY_STRING + * TODO: other CGI parameters? + */ + sprintf(cgienv[cgi_index++], "SERVER_SOFTWARE=%s", server_version); + strcpy(cgienv[cgi_index++], "DOCUMENT_ROOT=" CONFIG_HTTP_WEBROOT); + snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH, + "SERVER_NAME=%s", cn->server_name); + sprintf(cgienv[cgi_index++], "SERVER_PORT=%d", + cn->is_ssl ? CONFIG_HTTP_HTTPS_PORT : CONFIG_HTTP_PORT); + snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH, + "REQUEST_URI=%s", cn->uri_request); + snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH, + "SCRIPT_NAME=%s", cn->filereq); + snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH, + "PATH_INFO=%s", cn->uri_path_info); + snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH, + "QUERY_STRING=%s", cn->uri_query); + snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH, + "REMOTE_ADDR=%s", cn->remote_addr); + snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH, + "HTTP_COOKIE=%s", cn->cookie); /* note: small size */ +#if defined(CONFIG_HTTP_HAS_AUTHORIZATION) + snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH, + "REMOTE_USER=%s", cn->authorization); +#endif + + switch (cn->reqtype) + { + case TYPE_GET: + type = "GET"; + break; + + case TYPE_POST: + type = "POST"; + sprintf(cgienv[cgi_index++], + "CONTENT_LENGTH=%d", cn->content_length); + strcpy(cgienv[cgi_index++], /* hard-code? */ + "CONTENT_TYPE=application/x-www-form-urlencoded"); + break; + } + + sprintf(cgienv[cgi_index++], "REQUEST_METHOD=%s", type); + + if (cn->is_ssl) + strcpy(cgienv[cgi_index++], "HTTPS=on"); + +#ifdef CONFIG_PLATFORM_CYGWIN + /* TODO: find out why Lua needs this */ + strcpy(cgienv[cgi_index++], "PATH=/usr/bin"); +#endif + + if (cgi_index >= CGI_ARG_SIZE) + { + printf("Content-type: text/plain\n\nToo many CGI args (%d, %d)\n", + cgi_index, CGI_ARG_SIZE); + _exit(1); + } + + /* copy across the pointer indexes */ + for (i = 0; i < cgi_index; i++) + cgiptr[i] = cgienv[i]; + + cgiptr[i++] = "AUTH_TYPE=Basic"; + cgiptr[i++] = "GATEWAY_INTERFACE=CGI/1.1"; + cgiptr[i++] = "SERVER_PROTOCOL="HTTP_VERSION; + cgiptr[i] = NULL; + + execve(myargs[0], myargs, cgiptr); + printf("Content-type: text/plain\n\nshouldn't get here\n"); + _exit(1); +#endif +} + +static char * cgi_filetype_match(struct connstruct *cn, const char *fn) +{ + struct cgiextstruct *tp = cgiexts; + + while (tp != NULL) + { + char *t; + + if ((t = strstr(fn, tp->ext)) != NULL) + { + t += strlen(tp->ext); + + if (*t == '/' || *t == '\0') + { +#ifdef CONFIG_HTTP_ENABLE_LUA + if (strcmp(tp->ext, ".lua") == 0 || strcmp(tp->ext, ".lp") == 0) + cn->is_lua = 1; +#endif + + return t; + } + else + return NULL; + + } + + tp = tp->next; + } + + return NULL; +} + +static void decode_path_info(struct connstruct *cn, char *path_info) +{ + char *cgi_delim; + + cn->is_cgi = 0; +#ifdef CONFIG_HTTP_ENABLE_LUA + cn->is_lua = 0; +#endif + *cn->uri_request = '\0'; + *cn->uri_path_info = '\0'; + *cn->uri_query = '\0'; + + my_strncpy(cn->uri_request, path_info, MAXREQUESTLENGTH); + + /* query info? */ + if ((cgi_delim = strchr(path_info, '?'))) + { + *cgi_delim = '\0'; + my_strncpy(cn->uri_query, cgi_delim+1, MAXREQUESTLENGTH); + } + + if ((cgi_delim = cgi_filetype_match(cn, path_info)) != NULL) + { + cn->is_cgi = 1; /* definitely a CGI script */ + + /* path info? */ + if (*cgi_delim != '\0') + { + my_strncpy(cn->uri_path_info, cgi_delim, MAXREQUESTLENGTH); + *cgi_delim = '\0'; + } + } + + /* the bit at the start must be the script name */ + my_strncpy(cn->filereq, path_info, MAXREQUESTLENGTH); +} + +static int init_read_post_data(char *buf, char *data, + struct connstruct *cn, int old_rv) +{ + char *next = data; + int rv = old_rv; + char *post_data; + + /* Too much Post data to send. MAXPOSTDATASIZE should be + configured (now it can be chaged in the header file) */ + if (cn->content_length > MAXPOSTDATASIZE) + { + send_error(cn, 418); + return 0; + } + + /* remove CRLF */ + while ((*next == '\r' || *next == '\n') && (next < &buf[rv])) + next++; + + if (cn->post_data == NULL) + { + cn->post_data = (char *) calloc(1, (cn->content_length + 1)); + /* Allocate buffer for the POST data that will be used by proccgi + to send POST data to the CGI script */ + + if (cn->post_data == NULL) + { + printf("axhttpd: could not allocate memory for POST data\n"); + TTY_FLUSH(); + send_error(cn, 599); + return 0; + } + } + + cn->post_state = 0; + cn->post_read = 0; + post_data = cn->post_data; + + while (next < &buf[rv]) + { + /*copy POST data to buffer*/ + *post_data = *next; + post_data++; + next++; + cn->post_read++; + if (cn->post_read == cn->content_length) + { + /* No more POST data to be copied */ + *post_data = '\0'; + return 1; + } + } + + /* More POST data has to be read. read_post_data will continue with that */ + cn->post_state = 1; + return 0; +} + +void read_post_data(struct connstruct *cn) +{ + char buf[MAXREQUESTLENGTH*4], *next; + char *post_data; + int rv; + + bzero(buf,MAXREQUESTLENGTH*4); + rv = special_read(cn, buf, sizeof(buf)-1); + if (rv <= 0) + { + if (rv < 0) /* really dead? */ + removeconnection(cn); + return; + } + + buf[rv] = '\0'; + next = buf; + + post_data = &cn->post_data[cn->post_read]; + + while (next < &buf[rv]) + { + *post_data = *next; + post_data++; + next++; + cn->post_read++; + if (cn->post_read == cn->content_length) + { + /* No more POST data to be copied */ + *post_data='\0'; + cn->post_state = 0; + buildactualfile(cn); + cn->state = STATE_WANT_TO_SEND_HEAD; + return; + } + } + + /* More POST data to read */ +} + +#endif /* CONFIG_HTTP_HAS_CGI */ + +/* Decode string %xx -> char (in place) */ +static void urldecode(char *buf) +{ + int v; + char *p, *s, *w; + + w = p = buf; + + while (*p) + { + v = 0; + + if (*p == '%') + { + s = p; + s++; + + if (isxdigit((int) s[0]) && isxdigit((int) s[1])) + { + v = hexit(s[0])*16 + hexit(s[1]); + + if (v) + { + /* do not decode %00 to null char */ + *w = (char)v; + p = &s[1]; + } + } + + } + + if (!v) *w=*p; + p++; + w++; + } + + *w='\0'; +} + +static int hexit(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else + return 0; +} + +static void buildactualfile(struct connstruct *cn) +{ + char *cp; + snprintf(cn->actualfile, MAXREQUESTLENGTH, ".%s", cn->filereq); + +#ifndef WIN32 + /* Add directory slash if not there */ + if (isdir(cn->actualfile) && + 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; +#else + { + char curr_dir[MAXREQUESTLENGTH]; + char path[MAXREQUESTLENGTH]; + char *t = cn->actualfile; + + GetCurrentDirectory(MAXREQUESTLENGTH, curr_dir); + + /* convert all the forward slashes to back slashes */ + while ((t = strchr(t, '/'))) + *t++ = '\\'; + + snprintf(path, MAXREQUESTLENGTH, "%s%s", curr_dir, cn->actualfile); + memcpy(cn->actualfile, path, MAXREQUESTLENGTH); + + /* Add directory slash if not there */ + if (isdir(cn->actualfile) && + 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; + } +#endif + +#if defined(CONFIG_HTTP_ENABLE_LUA) + /* + * Use the lua launcher if this file has a lua extension. Put this at the + * end as we need the directory name. + */ + if (cn->is_lua) + sprintf(cn->actualfile, "%s%s", CONFIG_HTTP_LUA_PREFIX, + CONFIG_HTTP_LUA_CGI_LAUNCHER); +#endif +} + +static int sanitizefile(const char *buf) +{ + int len, i; + + /* Don't accept anything not starting with a / */ + if (*buf != '/') + return 0; + + len = strlen(buf); + for (i = 0; i < len; i++) + { + /* Check for "/." i.e. don't send files starting with a . */ + if (buf[i] == '/' && buf[i+1] == '.') + return 0; + } + + return 1; +} + +static int sanitizehost(char *buf) +{ + while (*buf != '\0') + { + /* Handle the port */ + if (*buf == ':') + { + *buf = '\0'; + return 1; + } + + /* Enforce some basic URL rules... */ + if ((isalnum(*buf) == 0 && *buf != '-' && *buf != '.') || + (*buf == '.' && *(buf+1) == '.') || + (*buf == '.' && *(buf+1) == '-') || + (*buf == '-' && *(buf+1) == '.')) + return 0; + + buf++; + } + + return 1; +} + +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]; + + snprintf(buf, sizeof(buf), HTTP_VERSION" 401 Unauthorized\n" + "WWW-Authenticate: Basic\n" + "realm=\"%s\"\n", realm); + special_write(cn, buf, strlen(buf)); +} + +static int check_digest(char *salt, const char *msg_passwd) +{ + 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_passwd = strchr(salt, '$')) == NULL) + return -1; + + *b64_passwd++ = 0; + if (base64_decode(salt, strlen(salt), b256_salt, &salt_size)) + return -1; + + 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 */ + MD5_Init(&ctx); + MD5_Update(&ctx, b256_salt, salt_size); /* process the salt */ + MD5_Update(&ctx, (uint8_t *)msg_passwd, strlen(msg_passwd)); + MD5_Final(md5_result, &ctx); + return memcmp(md5_result, real_passwd, MD5_SIZE);/* 0 = ok */ +} + +static int auth_check(struct connstruct *cn) +{ + char line[MAXREQUESTLENGTH]; + FILE *fp; + char *cp; + + if ((fp = exist_check(cn, ".htpasswd")) == NULL) + return 0; /* no .htpasswd file, so let though */ + + if (cn->authorization[0] == 0) + goto error; + + /* cn->authorization is in form "username:password" */ + if ((cp = strchr(cn->authorization, ':')) == NULL) + goto error; + else + *cp++ = 0; /* cp becomes the password */ + + while (fgets(line, sizeof(line), fp) != NULL) + { + char *b64_file_passwd; + int l = strlen(line); + + /* nuke newline */ + if (line[l-1] == '\n') + line[l-1] = 0; + + /* line is form "username:salt(b64)$password(b64)" */ + if ((b64_file_passwd = strchr(line, ':')) == NULL) + continue; + + *b64_file_passwd++ = 0; + + if (strcmp(line, cn->authorization)) /* our user? */ + continue; + + if (check_digest(b64_file_passwd, cp) == 0) + { + fclose(fp); + return 0; + } + } + +error: + fclose(fp); + send_authenticate(cn, cn->server_name); + 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 (strstr(line, "Deny all") || /* access to this dir denied */ + /* Access will be denied unless SSL is active */ + (!cn->is_ssl && strstr(line, "SSLRequireSSL")) || + /* Access will be denied if SSL is active */ + (cn->is_ssl && strstr(line, "SSLDenySSL"))) + { + ret = -1; + break; + } + } + + fclose(fp); + return ret; +} + +static void send_error(struct connstruct *cn, int err) +{ + char buf[MAXREQUESTLENGTH]; + char *title; + char *text; + + switch (err) + { + case 403: + title = "Forbidden"; + text = "File is protected"; +#ifdef CONFIG_HTTP_VERBOSE + printf("axhttpd: access to %s denied\n", cn->filereq); TTY_FLUSH(); +#endif + break; + + case 404: + title = "Not Found"; + text = title; + break; + + case 418: + title = "POST data size is to large"; + text = title; + break; + + default: + title = "Unknown"; + text = "Unknown"; + break; + } + + snprintf(buf, MAXREQUESTLENGTH, "HTTP/1.1 %d %s\n" + "Content-Type: text/html\n" + "Cache-Control: no-cache,no-store\n" + "Connection: close\n\n" + "<html>\n<head>\n<title>%d %s</title></head>\n" + "<body><h1>%d %s</h1>\n</body></html>\n", + err, title, err, title, err, text); + special_write(cn, buf, strlen(buf)); + removeconnection(cn); +} + +static const char *getmimetype(const char *name) +{ + /* only bother with a few mime types - let the browser figure the rest out */ + if (strstr(name, ".htm")) + return "text/html"; + else if (strstr(name, ".css")) + return "text/css"; + else + return "application/octet-stream"; +} + +static int special_write(struct connstruct *cn, + const char *buf, size_t count) +{ + if (cn->is_ssl) + { + SSL *ssl = cn->ssl; + return ssl ? ssl_write(ssl, (uint8_t *)buf, count) : -1; + } + else + return SOCKET_WRITE(cn->networkdesc, buf, count); +} + +static int special_read(struct connstruct *cn, void *buf, size_t count) +{ + int res; + + if (cn->is_ssl) + { + uint8_t *read_buf; + if ((res = ssl_read(cn->ssl, &read_buf)) > SSL_OK) + { + memcpy(buf, read_buf, res > (int)count ? count : res); + } + } + else + res = SOCKET_READ(cn->networkdesc, buf, count); + + return res; +} + diff --git a/libs/luci-lib-nixio/axTLS/httpd/tdate_parse.c b/libs/luci-lib-nixio/axTLS/httpd/tdate_parse.c new file mode 100644 index 000000000..813bdc578 --- /dev/null +++ b/libs/luci-lib-nixio/axTLS/httpd/tdate_parse.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "axhttp.h" + +struct day_mon_map +{ + const char* s; + uint8_t l; +}; + +static struct day_mon_map wday_tab[] = +{ + { "Sun", 0 }, { "Mon", 1 }, { "Tue", 2 }, { "Wed", 3 }, + { "Thu", 4 }, { "Fri", 5 }, { "Sat", 6 }, +}; + +static struct day_mon_map mon_tab[] = +{ + { "Jan", 0 }, { "Feb", 1 }, { "Mar", 2 }, { "Apr", 3 }, + { "May", 4 }, { "Jun", 5 }, { "Jul", 6 }, { "Aug", 7 }, + { "Sep", 8 }, { "Oct", 9 }, { "Nov", 10 }, { "Dec", 11 }, +}; + +static int day_mon_map_compare(const char *v1, const char *v2) +{ + return strcmp(((struct day_mon_map*)v1)->s, ((struct day_mon_map*)v2)->s); +} + +void tdate_init(void) +{ + qsort(wday_tab, sizeof(wday_tab)/sizeof(struct day_mon_map), + sizeof(struct day_mon_map), + (int (*)(const void *, const void *))day_mon_map_compare); + qsort(mon_tab, sizeof(mon_tab)/sizeof(struct day_mon_map), + sizeof(struct day_mon_map), + (int (*)(const void *, const void *))day_mon_map_compare); +} + +static int8_t day_mon_map_search(const char* str, + const struct day_mon_map* tab, int n) +{ + struct day_mon_map *search = bsearch(&str, tab, n, + sizeof(struct day_mon_map), + (int (*)(const void *, const void *))day_mon_map_compare); + return search ? search->l : -1; +} + +time_t tdate_parse(const char* str) +{ + struct tm tm; + char str_mon[4], str_wday[4]; + int tm_sec, tm_min, tm_hour, tm_mday, tm_year; + + /* Initialize. */ + memset(&tm, 0, sizeof(struct tm)); + + /* wdy, DD mth YY HH:MM:SS GMT */ + if ((sscanf(str, "%3[a-zA-Z], %d %3[a-zA-Z] %d %d:%d:%d GMT", + str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, + &tm_sec) == 7) || + /* wdy mth DD HH:MM:SS YY */ + (sscanf(str, "%3[a-zA-Z] %3[a-zA-Z] %d %d:%d:%d %d", + str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec, + &tm_year) == 7)) + { + int8_t tm_wday = day_mon_map_search(str_wday, wday_tab, + sizeof(wday_tab)/sizeof(struct day_mon_map)); + int8_t tm_mon = day_mon_map_search(str_mon, mon_tab, + sizeof(mon_tab)/sizeof(struct day_mon_map)); + + if (tm_wday < 0 || tm_mon < 0) + return -1; + + tm.tm_wday = tm_wday; + tm.tm_mon = tm_mon; + tm.tm_mday = tm_mday; + tm.tm_hour = tm_hour; + tm.tm_min = tm_min; + tm.tm_sec = tm_sec; + tm.tm_year = tm_year - 1900; + return mktime(&tm); + } + + return -1; /* error */ +} |