From f2065269769a2b4660b21ac873bf805c1836d25a Mon Sep 17 00:00:00 2001 From: patacongo Date: Mon, 13 Jul 2009 01:30:53 +0000 Subject: Add NXFLAT CGI programs git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1983 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/netutils/thttpd/Makefile | 34 +- nuttx/netutils/thttpd/cgi-src/Makefile | 136 +++++ nuttx/netutils/thttpd/cgi-src/phf.c | 86 +++ nuttx/netutils/thttpd/cgi-src/redirect.c | 288 +++++++++ nuttx/netutils/thttpd/cgi-src/ssi.c | 979 +++++++++++++++++++++++++++++++ nuttx/netutils/thttpd/config.h | 18 +- nuttx/netutils/thttpd/libhttpd.c | 68 +-- nuttx/netutils/thttpd/libhttpd.h | 4 +- nuttx/netutils/thttpd/tdate_parse.c | 4 +- 9 files changed, 1574 insertions(+), 43 deletions(-) create mode 100644 nuttx/netutils/thttpd/cgi-src/Makefile create mode 100644 nuttx/netutils/thttpd/cgi-src/phf.c create mode 100644 nuttx/netutils/thttpd/cgi-src/redirect.c create mode 100644 nuttx/netutils/thttpd/cgi-src/ssi.c (limited to 'nuttx') diff --git a/nuttx/netutils/thttpd/Makefile b/nuttx/netutils/thttpd/Makefile index 0840fdd35..6ff882dc4 100644 --- a/nuttx/netutils/thttpd/Makefile +++ b/nuttx/netutils/thttpd/Makefile @@ -37,7 +37,15 @@ -include $(TOPDIR)/Make.defs CGIBINDIR = $(TOPDIR)/netutils/thttpd/cgi-bin + +SUBDIRS = +ifeq ($(CONFIG_NXFLAT),y) SUBDIRS = cgi-src +SUBDIR_BIN1 = phf +SUBDIR_BIN2 = redirect +SUBDIR_BIN3 = ssi +SUBDIR_BIN += cgi-bin/$(SUBDIR_BIN1) cgi-bin/$(SUBDIR_BIN2) cgi-bin/$(SUBDIR_BIN3) +endif ASRCS = AOBJS = $(ASRCS:.S=$(OBJEXT)) @@ -50,7 +58,7 @@ OBJS = $(AOBJS) $(COBJS) BIN = libthttpd$(LIBEXT) -all: $(BIN) +all: $(BIN) $(SUBDIR_BIN) $(AOBJS): %$(OBJEXT): %.S $(call ASSEMBLE, $<, $@) @@ -63,6 +71,29 @@ $(BIN): $(OBJS) $(call ARCHIVE, $@, $${obj}); \ done ; ) +ifeq ($(CONFIG_NXFLAT),y) +cgi-bin: + @mkdir cgi-bin + +cgi-src/$(SUBDIR_BIN1): + @$(MAKE) -C cgi-src $(SUBDIR_BIN1) + +cgi-bin/$(SUBDIR_BIN1): cgi-bin cgi-src/$(SUBDIR_BIN1) + @cp -a cgi-src/$(SUBDIR_BIN1) $@ + +cgi-src/$(SUBDIR_BIN2): + @$(MAKE) -C cgi-src $(SUBDIR_BIN2) + +cgi-bin/$(SUBDIR_BIN2): cgi-bin cgi-src/$(SUBDIR_BIN2) + @cp -a cgi-src/$(SUBDIR_BIN2) $@ + +cgi-src/$(SUBDIR_BIN3): + @$(MAKE) -C cgi-src $(SUBDIR_BIN3) + +cgi-bin/$(SUBDIR_BIN3): cgi-bin cgi-src/$(SUBDIR_BIN3) + @cp -a cgi-src/$(SUBDIR_BIN3) $@ +endif + .depend: Makefile $(SRCS) @$(MKDEP) --dep-path . $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep @touch $@ @@ -71,6 +102,7 @@ depend: .depend clean: @rm -f $(BIN) *~ .*.swp + @rm -rf cgi-bin $(call CLEAN) @( for dir in $(SUBDIRS); do \ rm -f $${dir}/*~ $${dir}/.*.swp; \ diff --git a/nuttx/netutils/thttpd/cgi-src/Makefile b/nuttx/netutils/thttpd/cgi-src/Makefile new file mode 100644 index 000000000..79814fb80 --- /dev/null +++ b/nuttx/netutils/thttpd/cgi-src/Makefile @@ -0,0 +1,136 @@ +############################################################################ +# examples/nxflat/tests/hello/Makefile +# +# Copyright (C) 2009 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. 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. +# 3. Neither the name NuttX 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 $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs # Basic make info + +CFLAGS += -I$(TOPDIR)/netutils/thttpd -I$(TOPDIR)/netutils/thttpd/cgi-src +CGIBINDIR = $(TOPDIR)/netutils/thttpd/cgi-bin +CLEANFILES = *.o redirect ssi phf + +BIN1 = phf +BIN2 = redirect +BIN3 = ssi +BIN = $(BIN1) $(BIN2) $(BIN3) + +R1SRCS1 = $(BIN1).c +R1OBJS1 = $(R1SRCS1:.c=.o) +R2SRC1 = $(BIN1)-thunk.S +R2OBJ1 = $(R2SRC1:.S=.o) + +R1SRCS2 = $(BIN2).c +R1OBJS2 = $(R1SRCS2:.c=.o) +R2SRC2 = $(BIN2)-thunk.S +R2OBJ2 = $(R2SRC2:.S=.o) + +R1SRCS3 = $(BIN3).c +R1OBJS3 = $(R1SRCS3:.c=.o) +R2SRC3 = $(BIN3)-thunk.S +R2OBJ3 = $(R2SRC3:.S=.o) + +DERIVED = $(R2SRC1) $(R2SRC2) $(R2SRC3) + +R1COBJS = $(R1OBJS1) $(R1OBJS2) $(R1OBJS3) +R2AOBJS = $(R2OBJ1) $(R2OBJ2) $(R2OBJ3) + +all: $(BIN1) $(BIN2) $(BIN3) + +$(R1COBJS): %.o: %.c + @echo "CC: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +$(R2AOBJS): %.o: %.S + @echo "AS: $<" + @$(CC) -c $(CPICFLAGS) $< -o $@ + +# BIN1 + +$(BIN1).r1: $(R1OBJS1) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC1): $(BIN1).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN1).r2: $(R2OBJ1) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS1) $(R2OBJ1) + +$(BIN1): $(BIN1).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +#BIN2 + +$(BIN2).r1: $(R1OBJS2) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC2): $(BIN2).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN2).r2: $(R2OBJ2) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS2) $(R2OBJ2) + +$(BIN2): $(BIN2).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ +# BIN3 + +$(BIN3).r1: $(R1OBJS3) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS1) -o $@ $^ + +$(R2SRC3): $(BIN3).r1 + @echo "MK: $<" + @$(MKNXFLAT) -o $@ $^ + +$(BIN3).r2: $(R2OBJ3) + @echo "LD: $<" + @$(LD) $(NXFLATLDFLAGS2) -o $@ $(R1OBJS3) $(R2OBJ3) + +$(BIN3): $(BIN3).r2 + @echo "LD: $<" + @$(LDNXFLAT) $(LDNXFLATFLAGS) -o $@ $^ + +clean: + @rm -f $(BIN1) $(BIN2) $(BIN3) *.r1 *.r2 *-thunk.S *~ .*.swp + $(call CLEAN) + +distclean: clean + diff --git a/nuttx/netutils/thttpd/cgi-src/phf.c b/nuttx/netutils/thttpd/cgi-src/phf.c new file mode 100644 index 000000000..16ea2fefe --- /dev/null +++ b/nuttx/netutils/thttpd/cgi-src/phf.c @@ -0,0 +1,86 @@ +/**************************************************************************** + * netutils/thttpd/cgi-src/phf.c + * Cracker trap + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1996 by Jef Poskanzer . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + ****************************************************************************/ + +/* Old distributions of the NCSA and Apache web servers included a + * version of the phf program that had a bug. The program could + * easily be made to run arbitrary shell commands. There is no real + * legitimate use for phf, so any attempts to run it must be considered + * to be attacks. Accordingly, this version of phf logs the attack + * on stderr and then returns a page on CONFIG_THTTPD_CGI_OUTFD indicating + * that phf doesn't exist. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "config.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char *argv[]) +{ + FILE *outstream; + + fprintf(stderr, "phf CGI probe from %s\n", getenv("REMOTE_ADDR")); + + outstream = fdopen(CONFIG_THTTPD_CGI_OUTFD, "w"); + if (outstream) + { + (void)fprintf(outstream, +"\ +Content-type: text/html\n\ +Status: 404/html\n\ +\n\ +404 Not Found\n\ +

404 Not Found

\n\ +The requested object does not exist on this server.\n\ +The link you followed is either outdated, inaccurate,\n\ +or the server has been instructed not to let you have it.\n\ +\n"); + fclose(outstream); + return 0; + } + return 1; +} diff --git a/nuttx/netutils/thttpd/cgi-src/redirect.c b/nuttx/netutils/thttpd/cgi-src/redirect.c new file mode 100644 index 000000000..5aa099d59 --- /dev/null +++ b/nuttx/netutils/thttpd/cgi-src/redirect.c @@ -0,0 +1,288 @@ +/**************************************************************************** + * netutils/thttpd/cgi-src/redirect.c + * Simple redirection CGI program + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995 by Jef Poskanzer . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + ****************************************************************************/ + +/* Three steps to set up a redirection: + * + * 1. Make sure your web server is set up to allow CGI programs. + * 2. Make a symbolic link from the file you want to redirect, + * pointing at this program in the CGI bin directory. + * 3. Add an entry to the file ".redirects" in the directory where your + * http server runs CGI programs. For most servers, this is the + * directory where the given CGI program lives. The format of the + * file is a bunch of lines with a filename, whitespace, and the new + * URL. For example: + * + * /test/oldfile.html http://www.acme.com/test/newfile.html + * + * The easiest way to figure out precisely what filename to put into + * .redirects is to set up the symlink and then click on it. You'll get + * back a "404 Not Found" page which includes the filename as received by + * the redirect program, and that's what you want to use. + * + * Note: this is designed for thttpd (http://www.acme.com/software/thttpd/) + * and using it with other web servers may require some hacking. A possible + * gotcha is with the symbolic link from the old file pointing at this + * script - servers other than thttpd may not allow that link to be run + * as a CGI program, because they don't check the link to see that it + * points into the allowed CGI directory. + * + * Note two: It would be really cool to have this program look for + * the .redirects file in the same directory as the file being redirected, + * instead of in the binaries directory. Unfortunately, this appears + * to be impossible with the information CGI gives, plus the non-standardized + * but widespread practice of running CGI programs in the directory where + * the binary lives. Perhaps CGI 1.2 will address this. + */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include "config.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +#define LINE_SIZE 80 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static char g_iobuffer[LINE_SIZE]; +static char g_file[LINE_SIZE]; +static char g_url[LINE_SIZE]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void internal_error(FILE *outstream, char *reason) +{ + char *title = "500 Internal Error"; + + (void)fprintf(outstream, +"\ +Status: %s\n\ +Content-type: text/html\n\ +\n\ +%s\n\ +

%s

\n\ +Something unusual went wrong during a redirection request:\n\ +
\n\ +%s\n\ +
\n\ +\n", title, title, title, reason); +} + +static void not_found(FILE *outstream, char *script_name) +{ + char *title = "404 Not Found"; + + (void)fprintf(outstream, +"\ +Status: %s\n\ +Content-type: text/html\n\ +\n\ +%s\n\ +

%s

\n\ +The requested filename, %s, is set up to be redirected to another URL;\n\ +however, the new URL has not yet been specified.\n\ +\n", title, title, title, script_name); +} + +static void moved(FILE *outstream, char *script_name, char *url) +{ + char *title = "Moved"; + + (void)fprintf(outstream, +"\ +Location: %s\n\ +Content-type: text/html\n\ +\n\ +%s\n\ +

%s

\n\ +The requested filename, %s, has moved to a new URL:\n\ +%s.\n\ +\n", url, title, title, script_name, url, url); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, char **argv) +{ + FILE *outstream; + char *script_name; + char *path_info; + char *cp = 0; + FILE *fp; + char *star; + int err = 0; + + outstream = fdopen(CONFIG_THTTPD_CGI_OUTFD, "w"); + if (!outstream) + { + fprintf(stderr, "fdopen failed: %d\n", errno); + err = 1; + goto errout; + } + + /* Get the name that we were run as, which is the filename being ** + * redirected. + */ + + script_name = getenv("SCRIPT_NAME"); + if (!script_name) + { + internal_error(outstream, "Couldn't get SCRIPT_NAME environment variable."); + err = 2; + goto errout_with_outstream; + } + + /* Append the PATH_INFO, if any. This allows redirection of whole ** + * directories. + */ + + path_info = getenv("PATH_INFO"); + if (path_info) + { + cp = (char *)malloc(strlen(script_name) + strlen(path_info) + 1); + if (!cp) + { + internal_error(outstream, "Out of memory."); + err = 3; + goto errout_with_outstream; + } + + (void)sprintf(cp, "%s%s", script_name, path_info); + script_name = cp; + } + + /* Open the redirects file. */ + + fp = fopen(".redirects", "r"); + if (fp == (FILE *) 0) + { + internal_error(outstream, "Couldn't open .redirects file."); + err = 4; + goto errout_with_cp; + } + + /* Search the file for a matching entry. */ + + while (fgets(g_iobuffer, LINE_SIZE, fp) != NULL) + { + /* Remove comments. */ + + cp = strchr(g_iobuffer, '#'); + if (cp) + { + *cp = '\0'; + } + + /* Skip leading whitespace. */ + + cp = g_iobuffer; + cp += strspn(cp, " \t"); + + /* Check for blank line. */ + + if (*cp != '\0') + { + /* Parse line. */ + + if (sscanf(cp, "%[^ \t\n] %[^ \t\n]", g_file, g_url) == 2) + { + /* Check for wildcard match. */ + + star = strchr(g_file, '*'); + if (star != (char *)0) + { + /* Check for leading match. */ + + if (strncmp(g_file, script_name, star - g_file) == 0) + { + /* Got it; put together the full name. */ + + strcat(g_url, script_name + (star - g_file)); + + /* XXX Whack the script_name, too? */ + + moved(outstream, script_name, g_url); + goto success_out; + } + } + + /* Check for exact match. */ + + if (strcmp(g_file, script_name) == 0) + { + /* Got it. */ + + moved(outstream, script_name, g_url); + goto success_out; + } + } + } + } + + /* No match found. */ + + not_found(outstream, script_name); + err = 5; + +success_out: + fclose(fp); +errout_with_cp: + if (cp) + { + free(cp); + } +errout_with_outstream: + fclose(outstream); +errout: + return err; +} diff --git a/nuttx/netutils/thttpd/cgi-src/ssi.c b/nuttx/netutils/thttpd/cgi-src/ssi.c new file mode 100644 index 000000000..042f43b65 --- /dev/null +++ b/nuttx/netutils/thttpd/cgi-src/ssi.c @@ -0,0 +1,979 @@ +/**************************************************************************** + * netutils/thttpd/cgi-src/ssi.c + * Server-side-includes CGI program + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995 by Jef Poskanzer . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "config.h" + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +#define ST_GROUND 0 +#define ST_LESSTHAN 1 +#define ST_BANG 2 +#define ST_MINUS1 3 +#define ST_MINUS2 4 + +#define SF_BYTES 0 +#define SF_ABBREV 1 + +#define DI_CONFIG 0 +#define DI_INCLUDE 1 +#define DI_ECHO 2 +#define DI_FSIZE 3 +#define DI_FLASTMOD 4 + +#define BUFFER_SIZE 512 +#define TIMEFMT_SIZE 80 +#define MAX_TAGS 32 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *filename); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static char *g_url; +static char g_timeformat[TIMEFMT_SIZE]; +static char g_iobuffer1[BUFFER_SIZE]; +static char g_iobuffer2[BUFFER_SIZE]; +static char *g_tags[MAX_TAGS]; +static int g_sizefmt; +static struct stat g_sb; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void internal_error(FILE *outstream, char *reason) +{ + char *title = "500 Internal Error"; + + (void)fprintf(outstream, +"\ +%s\n\ +

%s

\n\ +Something unusual went wrong during a server-side-includes request:\n\ +
\n\ +%s\n\ +
\n\ +\n", title, title, reason); +} + +static void not_found(FILE *outstream, char *filename) +{ + char *title = "404 Not Found"; + + (void)fprintf(outstream, +"\ +%s\n\ +

%s

\n\ +The requested server-side-includes filename, %s,\n\ +does not seem to exist.\n\ +\n", title, title, filename); +} + +static void not_found2(FILE *outstream, char *directive, char *tag, char *filename) +{ + char *title = "Not Found"; + + (void)fprintf(outstream, +"\ +

%s

\n\ +The filename requested in a %s %s directive, %s,\n\ +does not seem to exist.\n\ +
\n", title, directive, tag, filename); +} + +static void not_permitted(FILE *outstream, char *directive, char *tag, char *val) +{ + char *title = "Not Permitted"; + + (void)fprintf(outstream, +"\ +

%s

\n\ +The filename requested in the %s %s=%s directive\n\ +may not be fetched.\n\ +
\n", title, directive, tag, val); +} + +static void unknown_directive(FILE *outstream, char *filename, char *directive) +{ + char *title = "Unknown Directive"; + + (void)fprintf(outstream, +"\ +

%s

\n\ +The requested server-side-includes filename, %s,\n\ +tried to use an unknown directive, %s.\n\ +
\n", title, filename, directive); +} + +static void unknown_tag(FILE *outstream, char *filename, char *directive, char *tag) +{ + char *title = "Unknown Tag"; + + (void)fprintf(outstream, +"\ +

%s

\n\ +The requested server-side-includes filename, %s,\n\ +tried to use the directive %s with an unknown tag, %s.\n\ +
\n", title, filename, directive, tag); +} + +static void unknown_value(FILE *outstream, char *filename, char *directive, char *tag, char *val) +{ + char *title = "Unknown Value"; + + (void)fprintf(outstream, +"\ +

%s

\n\ +The requested server-side-includes filename, %s,\n\ +tried to use the directive %s %s with an unknown value, %s.\n\ +
\n", title, filename, directive, tag, val); +} + +static int get_filename(FILE *outstream, char *vfilename, char *filename, + char *directive, char *tag, char *val, char *fn, + int fnsize) +{ + char *cp; + int vl; + int fl; + + /* Used for the various commands that accept a file name. These commands + * accept two tags: virtual Gives a virtual path to a document on the + * server. file Gives a pathname relative to the current directory. ../ + * cannot be used in this pathname, nor can absolute paths be used. + */ + + vl = strlen(vfilename); + fl = strlen(filename); + + if (strcmp(tag, "virtual") == 0) + { + if (strstr(val, "../") != (char *)0) + { + not_permitted(outstream, directive, tag, val); + return -1; + } + + /* Figure out root using difference between vfilename and filename. */ + + if (vl > fl || strcmp(vfilename, &filename[fl - vl]) != 0) + { + return -1; + } + + if (fl - vl + strlen(val) >= fnsize) + { + return -1; + } + + (void)strncpy(fn, filename, fl - vl); + (void)strcpy(&fn[fl - vl], val); + } + else if (strcmp(tag, "file") == 0) + { + if (val[0] == '/' || strstr(val, "../") != (char *)0) + { + not_permitted(outstream, directive, tag, val); + return -1; + } + if (fl + 1 + strlen(val) >= fnsize) + { + return -1; + } + + (void)strcpy(fn, filename); + cp = strrchr(fn, '/'); + if (cp == (char *)0) + { + cp = &fn[strlen(fn)]; + *cp = '/'; + } + (void)strcpy(++cp, val); + } + else + { + unknown_tag(outstream, filename, directive, tag); + return -1; + } + return 0; +} + +static int check_filename(char *filename) +{ + static int inited = 0; + static char *cgi_pattern; +#ifdef CONFIG_AUTH_FILE + struct stat sb; + char *dirname; + char *authname; + char *cp; + int fnl; + int r; +#endif + + if (!inited) + { + /* Get the cgi pattern. */ + + cgi_pattern = getenv("CGI_PATTERN"); +#ifdef CGI_PATTERN + if (cgi_pattern == (char *)0) + { + cgi_pattern = CGI_PATTERN; + } +#endif /* CGI_PATTERN */ + inited = 1; + } + + /* ../ is not permitted. */ + + if (strstr(filename, "../") !=NULL) + { + return 0; + } + + /* Ensure that we are not reading a basic auth password file. */ + +#ifdef CONFIG_AUTH_FILE + fnl = strlen(filename); + if (strcmp(filename, CONFIG_AUTH_FILE) == 0 || + (fnl >= sizeof(CONFIG_AUTH_FILE) && + strcmp(&filename[fnl - sizeof(CONFIG_AUTH_FILE) + 1], CONFIG_AUTH_FILE) == 0 && + filename[fnl - sizeof(CONFIG_AUTH_FILE)] == '/')) + { + return 0; + } + + /* Check for an auth file in the same directory. We can't do an actual ** + * auth password check here because CGI programs are not given the ** + * authorization header, for security reasons. So instead we just ** + * prohibit access to all auth-protected files. + */ + + dirname = strdup(filename); + if (dirname == (char *)0) + { + /* out of memory */ + + return 0; + } + + cp = strrchr(dirname, '/'); + if (cp == (char *)0) + { + (void)strcpy(dirname, "."); + } + else + { + *cp = '\0'; + } + + authname = malloc(strlen(dirname) + 1 + sizeof(CONFIG_AUTH_FILE)); + if (!authname) + { + /* out of memory */ + + free(dirname); + return 0; + } + + (void)sprintf(authname, "%s/%s", dirname, CONFIG_AUTH_FILE); + r = stat(authname, &sb); + + free(dirname); + free(authname); + + if (r == 0) + { + return 0; + } +#endif /* CONFIG_AUTH_FILE */ + + /* Ensure that we are not reading a CGI file. */ + + if (cgi_pattern != (char *)0 && match(cgi_pattern, filename)) + { + return 0; + } + return 1; +} + +static void show_time(FILE *outstream, time_t t, int gmt) +{ + struct tm *tmP; + + if (gmt) + { + tmP = gmtime(&t); + } + else + { + tmP = localtime(&t); + } + + if (strftime(g_iobuffer2, BUFFER_SIZE, g_timeformat, tmP) > 0) + { + (void)fputs(g_iobuffer2, outstream); + } +} + +static void show_size(FILE *outstream, off_t size) +{ + switch (g_sizefmt) + { + case SF_BYTES: + (void)fprintf(outstream, "%ld", (long)size); /* spec says should have commas */ + break; + + case SF_ABBREV: + if (size < 1024) + { + (void)fprintf(outstream, "%ld", (long)size); + } + else if (size < 1024) + { + (void)fprintf(outstream, "%ldK", (long)size / 1024L); + } + else if (size < 1024 * 1024) + { + (void)fprintf(outstream, "%ldM", (long)size / (1024L * 1024L)); + } + else + { + (void)fprintf(outstream, "%ldG", (long)size / (1024L * 1024L * 1024L)); + } + break; + } +} + +static void do_config(FILE *outstream, FILE *instream, char *vfilename, char *filename, + char *directive, char *tag, char *val) +{ + /* The config directive controls various aspects of the file parsing. ** + * There are two valid tags: g_timeformat Gives the server a new format to + * use when providing dates. This is a string compatible with the + * strftime library call. g_sizefmt Determines the formatting to be used + * when displaying the size of a file. Valid choices are bytes, for a + * formatted byte count (formatted as 1,234,567), or abbrev for an + * abbreviated version displaying the number of kilobytes or megabytes the + * file occupies. + */ + + if (strcmp(tag, "g_timeformat") == 0) + { + (void)strncpy(g_timeformat, val, TIMEFMT_SIZE - 1); + g_timeformat[TIMEFMT_SIZE - 1] = '\0'; + } + else if (strcmp(tag, "g_sizefmt") == 0) + { + if (strcmp(val, "bytes") == 0) + { + g_sizefmt = SF_BYTES; + } + else if (strcmp(val, "abbrev") == 0) + { + g_sizefmt = SF_ABBREV; + } + else + { + unknown_value(outstream, filename, directive, tag, val); + } + } + else + { + unknown_tag(outstream, filename, directive, tag); + } +} + +static void do_include(FILE *outstream, FILE *instream, char *vfilename, char *filename, + char *directive, char *tag, char *val) +{ + FILE *instream2; + int ret; + + /* Inserts the text of another document into the parsed document. */ + + ret = get_filename(outstream, vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE); + if (ret < 0) + { + return; + } + + if (!check_filename(g_iobuffer1)) + { + not_permitted(outstream, directive, tag, g_iobuffer1); + return; + } + + instream2 = fopen(g_iobuffer1, "r"); + if (instream2 == (FILE *) 0) + { + not_found2(outstream, directive, tag, g_iobuffer1); + return; + } + + if (strcmp(tag, "virtual") == 0) + { + if (strlen(val) = 0) + { + show_time(outstream, g_sb.st_mtime, 0); + } + } + else + { + /* Try an environment variable. */ + + cp = getenv(val); + if (cp == (char *)0) + { + unknown_value(outstream, filename, directive, tag, val); + } + else + { + (void)fputs(cp, outstream); + } + } + } +} + +static void do_fsize(FILE *outstream, FILE *instream, char *vfilename, char *filename, + char *directive, char *tag, char *val) +{ + int ret; + + /* Prints the size of the specified file. */ + + ret = get_filename(outstream, vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE); + if (ret < 0) + { + return; + } + + if (stat(g_iobuffer1, &g_sb) < 0) + { + not_found2(outstream, directive, tag, g_iobuffer1); + return; + } + + show_size(outstream, g_sb.st_size); +} + +static void do_flastmod(FILE *outstream, FILE *instream, char *vfilename, char *filename, + char *directive, char *tag, char *val) +{ + int ret; + + /* Prints the last modification date of the specified file. */ + + ret = get_filename(outstream, vfilename, filename, directive, tag, val, g_iobuffer1, BUFFER_SIZE); + if (ret < 0) + { + return; + } + + if (stat(g_iobuffer1, &g_sb) < 0) + { + not_found2(outstream, directive, tag, g_iobuffer1); + return; + } + show_time(outstream, g_sb.st_mtime, 0); +} + +static void parse(FILE *outstream, FILE *instream, char *vfilename, char *filename, char *str) +{ + char *directive; + char *cp; + int ntags; + int dirn; + int i; + char *val; + + directive = str; + directive += strspn(directive, " \t\n\r"); + + ntags = 0; + cp = directive; + for (;;) + { + cp = strpbrk(cp, " \t\n\r\""); + if (cp == (char *)0) + { + break; + } + + if (*cp == '"') + { + cp = strpbrk(cp + 1, "\""); + cp++; + if (*cp == '\0') + { + break; + } + } + + *cp++ = '\0'; + cp += strspn(cp, " \t\n\r"); + if (*cp == '\0') + { + break; + } + + if (ntags < MAX_TAGS) + { + g_tags[ntags++] = cp; + } + } + + if (strcmp(directive, "config") == 0) + { + dirn = DI_CONFIG; + } + else if (strcmp(directive, "include") == 0) + { + dirn = DI_INCLUDE; + } + else if (strcmp(directive, "echo") == 0) + { + dirn = DI_ECHO; + } + else if (strcmp(directive, "fsize") == 0) + { + dirn = DI_FSIZE; + } + else if (strcmp(directive, "flastmod") == 0) + { + dirn = DI_FLASTMOD; + } + else + { + unknown_directive(outstream, filename, directive); + return; + } + + for (i = 0; i < ntags; ++i) + { + if (i > 0) + { + putc(' ', outstream); + } + + val = strchr(g_tags[i], '='); + if (val == (char *)0) + { + val = ""; + } + else + { + *val++ = '\0'; + } + + if (*val == '"' && val[strlen(val) - 1] == '"') + { + val[strlen(val) - 1] = '\0'; + ++val; + } + + switch (dirn) + { + case DI_CONFIG: + do_config(outstream, instream, vfilename, filename, directive, g_tags[i], val); + break; + + case DI_INCLUDE: + do_include(outstream, instream, vfilename, filename, directive, g_tags[i], val); + break; + + case DI_ECHO: + do_echo(outstream, instream, vfilename, filename, directive, g_tags[i], val); + break; + + case DI_FSIZE: + do_fsize(outstream, instream, vfilename, filename, directive, g_tags[i], val); + break; + + case DI_FLASTMOD: + do_flastmod(outstream, instream, vfilename, filename, directive, g_tags[i], val); + break; + } + } +} + +static void slurp(FILE *outstream, FILE *instream, char *vfilename, char *filename) +{ + int state; + int ich; + int i; + + /* Now slurp in the rest of the comment from the input file. */ + + i = 0; + state = ST_GROUND; + while ((ich = getc(instream)) != EOF) + { + switch (state) + { + case ST_GROUND: + if (ich == '-') + { + state = ST_MINUS1; + } + break; + + case ST_MINUS1: + if (ich == '-') + { + state = ST_MINUS2; + } + else + { + state = ST_GROUND; + } + break; + + case ST_MINUS2: + if (ich == '>') + { + g_iobuffer1[i - 2] = '\0'; + parse(outstream, instream, vfilename, filename, g_iobuffer1); + return; + } + else if (ich != '-') + { + state = ST_GROUND; + } + break; + } + + if (i < BUFFER_SIZE - 1) + { + g_iobuffer1[i++] = (char)ich; + } + } +} + +static void read_file(FILE *outstream, FILE *instream, char *vfilename, char *filename) +{ + int ich; + int state; + + /* Copy it to output, while running a state-machine to look for SSI + * directives. + */ + + state = ST_GROUND; + while ((ich = getc(instream)) != EOF) + { + switch (state) + { + case ST_GROUND: + if (ich == '<') + { + state = ST_LESSTHAN; + continue; + } + break; + + case ST_LESSTHAN: + if (ich == '!') + { + state = ST_BANG; + continue; + } + else + { + state = ST_GROUND; + putc('<', outstream); + } + break; + + case ST_BANG: + if (ich == '-') + { + state = ST_MINUS1; + continue; + } + else + { + state = ST_GROUND; + (void)fputs("/username. */ -#ifdef TILDE_MAP_1 -static int tilde_map_1(httpd_conn *hc) +#ifdef CONFIG_THTTPD_TILDE_MAP1 +static intCONFIG_THTTPD_TILDE_MAP1(httpd_conn *hc) { static char *temp; static size_t maxtemp = 0; int len; - static char *prefix = TILDE_MAP_1; + static char *prefix =CONFIG_THTTPD_TILDE_MAP1; len = strlen(hc->expnfilename) - 1; httpd_realloc_str(&temp, &maxtemp, len); @@ -990,16 +990,16 @@ static int tilde_map_1(httpd_conn *hc) (void)strcat(hc->expnfilename, temp); return 1; } -#endif /* TILDE_MAP_1 */ +#endif /*CONFIG_THTTPD_TILDE_MAP1 */ /* Map a ~username/whatever URL into /. */ -#ifdef TILDE_MAP_2 -static int tilde_map_2(httpd_conn *hc) +#ifdef CONFIG_THTTPD_TILDE_MAP2 +static intCONFIG_THTTPD_TILDE_MAP2(httpd_conn *hc) { static char *temp; static size_t maxtemp = 0; - static char *postfix = TILDE_MAP_2; + static char *postfix =CONFIG_THTTPD_TILDE_MAP2; char *cp; struct passwd *pw; char *alt; @@ -1057,7 +1057,7 @@ static int tilde_map_2(httpd_conn *hc) hc->tildemapped = TRUE; return 1; } -#endif /* TILDE_MAP_2 */ +#endif /*CONFIG_THTTPD_TILDE_MAP2 */ /* Virtual host mapping. */ @@ -1622,7 +1622,7 @@ static void cgi_kill(ClientData client_data, struct timeval *nowP) /* qsort comparison routine. */ -#ifdef GENERATE_INDEXES +#ifdef CONFIG_THTTPD_GENERATE_INDICES static int name_compare(char **a, char **b) { return strcmp(*a, *b); @@ -1985,7 +1985,7 @@ static int ls(httpd_conn *hc) return 0; } -#endif /* GENERATE_INDEXES */ +#endif /* CONFIG_THTTPD_GENERATE_INDICES */ /* Set up environment variables. Be real careful here to avoid * letting malicious clients overrun a buffer. We don't have @@ -2843,7 +2843,7 @@ static int really_start_request(httpd_conn *hc, struct timeval *nowP) } /* Nope, no index file, so it's an actual directory request. */ -#ifdef GENERATE_INDEXES +#ifdef CONFIG_THTTPD_GENERATE_INDICES /* Directories must be readable for indexing. */ if (!(hc->sb.st_mode & S_IROTH)) { @@ -2873,7 +2873,7 @@ static int really_start_request(httpd_conn *hc, struct timeval *nowP) /* Ok, generate an index. */ return ls(hc); -#else /* GENERATE_INDEXES */ +#else /* CONFIG_THTTPD_GENERATE_INDICES */ ndbg("%s URL \"%s\" tried to index a directory\n", httpd_ntoa(&hc->client_addr), hc->encodedurl); httpd_send_err(hc, 403, err403title, "", @@ -2881,7 +2881,7 @@ static int really_start_request(httpd_conn *hc, struct timeval *nowP) "The requested URL '%s' is a directory, and directory indexing is disabled on this server.\n"), hc->encodedurl); return -1; -#endif /* GENERATE_INDEXES */ +#endif /* CONFIG_THTTPD_GENERATE_INDICES */ got_one: @@ -3449,9 +3449,9 @@ int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn *hc) hc->maxpathinfo = hc->maxquery = hc->maxaccept = hc->maxaccepte = hc->maxreqhost = hc->maxhostdir = hc->maxremoteuser = 0; -#ifdef TILDE_MAP_2 +#ifdef CONFIG_THTTPD_TILDE_MAP2 hc->maxaltdir = 0; -#endif /* TILDE_MAP_2 */ +#endif /*CONFIG_THTTPD_TILDE_MAP2 */ httpd_realloc_str(&hc->decodedurl, &hc->maxdecodedurl, 1); httpd_realloc_str(&hc->origfilename, &hc->maxorigfilename, 1); httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, 0); @@ -3463,7 +3463,7 @@ int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn *hc) httpd_realloc_str(&hc->reqhost, &hc->maxreqhost, 0); httpd_realloc_str(&hc->hostdir, &hc->maxhostdir, 0); httpd_realloc_str(&hc->remoteuser, &hc->maxremoteuser, 0); -#ifdef TILDE_MAP_2 +#ifdef CONFIG_THTTPD_TILDE_MAP2 httpd_realloc_str(&hc->altdir, &hc->maxaltdir, 0); #endif hc->initialized = 1; @@ -3524,9 +3524,9 @@ int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn *hc) hc->authorization = ""; hc->remoteuser[0] = '\0'; hc->buffer[0] = '\0'; -#ifdef TILDE_MAP_2 +#ifdef CONFIG_THTTPD_TILDE_MAP2 hc->altdir[0] = '\0'; -#endif /* TILDE_MAP_2 */ +#endif /*CONFIG_THTTPD_TILDE_MAP2 */ hc->buflen = 0; hc->if_modified_since = (time_t) - 1; hc->range_if = (time_t) - 1; @@ -4149,20 +4149,20 @@ int httpd_parse_request(httpd_conn *hc) if (hc->expnfilename[0] == '~') { -#ifdef TILDE_MAP_1 +#ifdef CONFIG_THTTPD_TILDE_MAP1 if (!tilde_map_1(hc)) { httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl); return -1; } -#endif /* TILDE_MAP_1 */ -#ifdef TILDE_MAP_2 +#endif /*CONFIG_THTTPD_TILDE_MAP1 */ +#ifdef CONFIG_THTTPD_TILDE_MAP2 if (!tilde_map_2(hc)) { httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl); return -1; } -#endif /* TILDE_MAP_2 */ +#endif /*CONFIG_THTTPD_TILDE_MAP2 */ } /* Virtual host mapping. */ @@ -4215,7 +4215,7 @@ int httpd_parse_request(httpd_conn *hc) (void)strcpy(hc->expnfilename, &hc->expnfilename[strlen(hc->hs->cwd)]); } -#ifdef TILDE_MAP_2 +#ifdef CONFIG_THTTPD_TILDE_MAP2 else if (hc->altdir[0] != '\0' && (strncmp(hc->expnfilename, hc->altdir, strlen(hc->altdir)) == 0 && @@ -4223,7 +4223,7 @@ int httpd_parse_request(httpd_conn *hc) hc->expnfilename[strlen(hc->altdir)] == '/'))) { } -#endif /* TILDE_MAP_2 */ +#endif /*CONFIG_THTTPD_TILDE_MAP2 */ else { ndbg("%s URL \"%s\" goes outside the web tree\n", @@ -4271,9 +4271,9 @@ void httpd_destroy_conn(httpd_conn *hc) free((void *)hc->hostdir); free((void *)hc->remoteuser); free((void *)hc->buffer); -#ifdef TILDE_MAP_2 +#ifdef CONFIG_THTTPD_TILDE_MAP2 free((void *)hc->altdir); -#endif /* TILDE_MAP_2 */ +#endif /*CONFIG_THTTPD_TILDE_MAP2 */ hc->initialized = 0; } } diff --git a/nuttx/netutils/thttpd/libhttpd.h b/nuttx/netutils/thttpd/libhttpd.h index 87804eb2a..c5829614c 100644 --- a/nuttx/netutils/thttpd/libhttpd.h +++ b/nuttx/netutils/thttpd/libhttpd.h @@ -155,10 +155,10 @@ typedef struct size_t maxdecodedurl, maxorigfilename, maxexpnfilename, maxencodings, maxpathinfo, maxquery, maxaccept, maxaccepte, maxreqhost, maxhostdir, maxremoteuser, maxresponse; -#ifdef TILDE_MAP_2 +#ifdef CONFIG_THTTPD_TILDE_MAP2 char *altdir; size_t maxaltdir; -#endif /* TILDE_MAP_2 */ +#endif /*CONFIG_THTTPD_TILDE_MAP2 */ time_t if_modified_since, range_if; size_t contentlength; char *type; /* not malloc()ed */ diff --git a/nuttx/netutils/thttpd/tdate_parse.c b/nuttx/netutils/thttpd/tdate_parse.c index fcd2cfbda..f1e657029 100644 --- a/nuttx/netutils/thttpd/tdate_parse.c +++ b/nuttx/netutils/thttpd/tdate_parse.c @@ -190,7 +190,9 @@ time_t tdate_parse(char *str) /* Skip initial whitespace ourselves - sscanf is clumsy at this. */ for (cp = str; *cp == ' ' || *cp == '\t'; ++cp) - continue; + { + continue; + } /* And do the sscanfs. WARNING: you can add more formats here, but be * careful! You can easily screw up the parsing of existing formats when -- cgit v1.2.3