Import NetBSD httpd(8)

Also known as bozohttpd(8).

Change-Id: I40e955b5654674f2c708b10e5e403ca9cbc92534
This commit is contained in:
David van Moolenbroek 2017-03-05 16:03:54 +00:00
parent 8f957290eb
commit 340f5e5660
60 changed files with 8166 additions and 2 deletions

View File

@ -1058,9 +1058,11 @@
./usr/libexec minix-base
./usr/libexec/atf-check minix-base atf
./usr/libexec/blacklistd-helper minix-base
./usr/libexec/bozohttpd minix-base
./usr/libexec/fingerd minix-base
./usr/libexec/ftpd minix-base
./usr/libexec/getty minix-base
./usr/libexec/httpd minix-base
./usr/libexec/kyua-atf-tester minix-base kyua
./usr/libexec/kyua-plain-tester minix-base kyua
./usr/libexec/ld.elf_so minix-base
@ -3965,3 +3967,4 @@
./var/spool/ftp/etc minix-base
./var/spool/ftp/hidden minix-base
./var/tmp minix-base
./var/www minix-base

View File

@ -600,12 +600,14 @@
./usr/libdata/debug/usr/lib/libz.so.1.0.debug minix-debug debug
./usr/libdata/debug/usr/libexec minix-debug
./usr/libdata/debug/usr/libexec/atf-check.debug minix-debug debug
./usr/libdata/debug/usr/libexec/bozohttpd.debug minix-debug debug
./usr/libdata/debug/usr/libexec/cc1.debug minix-debug gcc=5,gcccmds,debug
./usr/libdata/debug/usr/libexec/cc1obj.debug minix-debug gcc=5,gcccmds,debug
./usr/libdata/debug/usr/libexec/cc1plus.debug minix-debug gcc=5,gcccmds,debug
./usr/libdata/debug/usr/libexec/fingerd.debug minix-debug debug
./usr/libdata/debug/usr/libexec/ftpd.debug minix-debug debug
./usr/libdata/debug/usr/libexec/getty.debug minix-debug debug
./usr/libdata/debug/usr/libexec/httpd.debug minix-debug debug
./usr/libdata/debug/usr/libexec/kyua-atf-tester.debug minix-debug debug
./usr/libdata/debug/usr/libexec/kyua-plain-tester.debug minix-debug debug
./usr/libdata/debug/usr/libexec/ld.elf_so.debug minix-debug debug

View File

@ -3462,6 +3462,7 @@
./usr/man/man8/blacklistctl.8 minix-man
./usr/man/man8/blacklistd.8 minix-man
./usr/man/man8/boot.8 minix-man
./usr/man/man8/bozohttpd.8 minix-man
./usr/man/man8/btrace.8 minix-man
./usr/man/man8/cdprobe.8 minix-man
./usr/man/man8/chown.8 minix-man
@ -3501,7 +3502,7 @@
./usr/man/man8/groupinfo.8 minix-man
./usr/man/man8/groupmod.8 minix-man
./usr/man/man8/halt.8 minix-man
./usr/man/man8/httpd.8 minix-man obsolete
./usr/man/man8/httpd.8 minix-man
./usr/man/man8/i2cscan.8 minix-man
./usr/man/man8/ifconfig.8 minix-man
./usr/man/man8/in.httpd.8 minix-man obsolete

View File

@ -735,6 +735,7 @@
./var/spool/ftp/bin
./var/spool/ftp/etc
./var/spool/ftp/hidden #breaks cd image generation with non-root users: mode=0111
./var/www
# Directories with special access rights
/set type=dir uid=0 gid=0 mode=1777

View File

@ -4,7 +4,7 @@
.include <bsd.own.mk>
SUBDIR= \
fingerd ftpd getty \
fingerd ftpd getty httpd \
ld.elf_so \
rshd \
telnetd

275
libexec/httpd/CHANGES Normal file
View File

@ -0,0 +1,275 @@
$eterna: CHANGES,v 1.78 2011/11/18 01:25:11 mrg Exp $
changes in bozohttpd 20150320:
o fix redirection handling
o support transport stream (.ts) and video object (.vob) files
o directory listings show correct file sizes for large files
changes in bozohttpd 20140717:
o properly handle SSL errors
changes in bozohttpd 20140708:
o fixes for virtual host support, from rajeev_v_pillai@yahoo.com
o avoid printing double errors, from shm@netbsd.org
o fix a security issue in basic HTTP authentication which would allow
authentication to be bypassed, from shm@netbsd.org
changes in bozohttpd 20140201:
o support .svg files
o fix a core dump when requests timeout
changes in bozohttpd 20140102:
o update a few content types
o add support for directly calling lua scripts to handle
processes, from mbalmer@netbsd.org
o properly escape generated HTML
o add authentication for redirections, from martin@netbsd.org
o handle chained ssl certifications, from elric@netbsd.org
o add basic support for gzipped files, from elric@netbsd.org
o properly escape generated URIs
changes in bozohttpd 20111118:
o add -P <pidfile> option, from jmmv@netbsd.org
o avoid crashes with http basic auth, from pooka@netbsd.org
o add support for REDIRECT_STATUS variable, from tls@netbsd.org
o support .mp4 files in the default map
o directory indexes with files with : are now displayed properly, from
reed@netbsd.org
o allow -I option to be useful in non-inetd mode as well
changes in bozohttpd 20100920:
o properly fully disable multi-file mode for now
o fix the -t and -U options when used without the -e option, broken since
the library-ifcation
o be explicit that logs go to the FTP facility in syslog
o use scandir() with alphasort() for sorted directory lists, from moof
o fix a serious error in vhost handling; "Host:.." would allow access to
the next level directory from the virtual root directory, from seanb
o fix some various non standard compile time errors, from rudolf
o fix dynamic CGI content maps, from rudolf
changes in bozohttpd 20100617:
o fix some compile issues
o fix SSL mode. from rtr
o fix some cgi-bin issues, as seen with cvsweb
o disable multi-file daemon mode for now, it breaks
o return 404's instead of 403's when chdir of ~user dirs fail
o remove "noreturn" attribute from bozo_http_error() that was
causing incorrect runtime behaviour
changes in bozohttpd 20100509:
o major rework and clean up of internal interfaces. move the main
program into main.c, the remaining parts are useable as library.
add bindings for lua. by Alistair G. Crooks <agc@netbsd.org>
o fix http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=566325
changes in bozohttpd 20090522:
o avoid dying in daemon mode for some uncommon, but recoverable, errors
o close leaking file descriptors for CGI and daemon mode
o handle poll errors properly
o don't try to handle more than one request per process yet
o add subdirs for build "debug" and "small" versions
o clean up a bad merge / duplicate code
o make mmap() usage portable, fixes linux & ranges: support
o document the -f option
o daemon mode now serves 6 files per child
changes in bozohttpd 20090417:
o make bozohttpd internally more modular, preparing the way
to handle more than one request per process
o fix http-auth, set $REMOTE_USER not $REMOTEUSER. also fix
cgi-bin with cvsweb, from Holger Weiss <holger@CIS.FU-Berlin.DE>
o fix an uninitialised variable use in daemon mode
o fix ssl mode with newer OpenSSL
o mmap large files in manageable sizes so we can serve any size file
o refactor url processing to handle query strings correctly for CGI
from Sergey Katsev at Coyote Point
o add If-Modified-Since support, from Joerg Sonnenberger
<joerg@netbsd.org>
o many more manual fixes, from NetBSD
changes in bozohttpd 20080303:
o fix some cgi header processing, from <thelsdj@gmail.com>
o add simple Range: header processing, from <bad@bsd.de>
o man page fixes, from NetBSD
o clean up various parts, from NetBSD
changes in bozohttpd 20060710:
o prefix some function names with "bozo"
o align directory indexing <hr> markers
o clean up some code GCC4 grumbled about
changes in bozohttpd 20060517:
o don't allow "/.." or "../" files
o don't write ":80" into urls for the http port
o fix a fd leak when fork() fails
o make directory indexing mode not look so ugly
o build a text version of the manual page
o make "make clean" work properly
changes in bozohttpd 20050410:
o fix some off-by-one errors from <roland.illig@gmx.de>
o properly support nph- CGI
o make content maps case insensitive
o fix proto header merging to include the missing comma
o major source reorganisation; most features are in separate files now
o new -V flag that makes unknown virtualhosts use slashdir
from <rumble@ephemeral.org>
o HTTP/1.x protocol headers are now properly merged for CGI
changes in bozohttpd 20040808:
o CGI status is now properly handled (-a flag has been removed)
o CGI file upload support works
o %xy translations are no longer ever applied after the first '?',
ala RFC2396. from lukem
o daemon mode (-b) should no longer hang spinning forever if it
sees no children. from lukem
o new .bzabsredirect file support. from <martin@netbsd.org>
o return a 404 error if we see %00 or %2f (/)
o don't print 2 "200" headers for CGI
o support .torrent files
changes in bozohttpd 20040218:
o new .bzredirect file support for sane directory redirection
o new -Z option that enables SSL mode, from <rtr@eterna.com.au>
o the -C option has been changed to take two explicit options, rather
than a single option with a space separating the suffix and the
interpreter. ``-C ".foo /path/to/bar"'' should now be written
as ``-C .foo /path/to/bar''
o the -M option has been changed like -C and no longer requires or
supports a single argument with space-separated options
o with -a, still print the 200 OK. from <rtr@eterna.com.au>
o with -r, if a .bzdirect file appears in a directory, allow direct
access to this directory
changes in bozohttpd 20031005:
o fixes for basic authorisation. from <ecu@ipv42.net>
o always display file size in directory index mode
o add .xbel, .xml & .xsl -> text/xml mappings. from
<wiz@danbala.ifoer.tuwien.ac.at>
changes in bozohttpd 20030626:
o fix a recent core dump when given no input
o add new -r flag that ensures referrer is set to this host
o fix several compile time errors with -DNO_CGIBIN_SUPPORT
o fix some man page details. from lukem@wasabisystems.com
o re-add a missing memset(), fixing a core dump. from lukem
o support HTTP basic authorisation, disabled by default. from lukem
o print the port number in redirects and errors. from lukem
o only syslog the basename of the program. from lukem
o add __attribute__() format checking. from lukem
o fix cgibin SCRIPT_NAME to have a leading /. from zakj@nox.cx
o simplify some code in -C to avoid a core dump. from lukem
o add a .css -> css/text entry to the content_map[]. from zakj@nox.cx
changes in bozohttpd 20030409:
o -d without DEBUG enabled only prints one warning and continues
o one can now define the C macro SERVER_SOFTWARE when building to
change the Server: header and CGI variable of the same name
o add new -s flag the force logging output to stderr. from zakj@nox.cx
o add new -a flag for CGI bin that stops bozohttpd from outputting
any HTTP reply, the CGI program must output these. from zakj@nox.cx
o new REQUEST_URI and DATE_GMT environment variables for CGI. from
zakj@nox.cx
o add a "Makefile.boot" that should work with any make program
o build on linux again
o fix core dumps when using -C
changes in bozohttpd 20030313:
o deprecate -r flag; make this the default and silently ignore -r now
o add support for file extentions to call CGI programs (from lukem)
o add dynamic support to add new content map entries, allowing both
new file types and non /cgi-bin CGI programs to be run with the
new -C "suffix cgihandler" and -M "suffix type encoding encoding11"
options
o in -b mode, set the http date after accept() returns, not before we
call accept()
o in -b mode, bind all addresses found not just the first one
o unsupport old hostname API
o in -b mode, set the SO_REUSEADDR socket option (lukem)
o allow -x (index.html) mode to work with CGI handlers
changes in bozohttpd 20021106:
o add .bz2 support
o properly escape <, > and & in error messages, partly from
Nicolas Jombart <ecu@mariejeanne.net>
o new -H flag to hide .* files in directory index mode
o fix buffer reallocation when parsing a request, to avoid
overflowing the buffer with carriage returns (\r)
o do not decode "%XY"-style cgi-bin data beyond the "?"
changes in bozohttpd 5.15 (20020913):
o add .ogg support -> `application/x-ogg'
o fix CGI requests with "/" in the query part
changes in bozohttpd 5.14 (20020823):
o allow -X mode to work for "/"
o work on systems without MADV_SEQUENTIAL
o make a local cut-down copy of "queue.h" (fixes linux & solaris
support at the very least)
o portability fixes for pre-ipv6 socket api systems (eg, solaris 7)
o portability fixes for missing _PATH_DEFPATH, LOG_FTP and __progname
o better documentation on virtual host support
changes in bozohttpd 5.13 (20020804):
o support .mp3 files (type audio/mpeg)
o use stat() to find out if something is a directory, for -X mode
changes in bozohttpd 5.12 (20020803):
o constification
o fixes & enhancements for directory index mode (-X)
changes in bozohttpd 5.11 (20020730):
o more man page fixes from Thomas Klausner
<wiz@danbala.ifoer.tuwien.ac.at>
o de-K&R C-ification
o fix Date: header for daemon mode
o fix core dump when asking for /cgi-bin/ when CGI isn't configured
o use a valid Server: header
changes in bozohttpd 5.10 (20020710):
- add freebsd support
- fix a couple of header typos
- many cgi-bin fixes from lukem@netbsd.org
- add -T chrootdir and -U user, plus several minor other cleanups
with signals and return values. from xs@kittenz.org
- add -e that does not clear the environment for -T/-U
- fix a formatting error noticed by ISIHARA Takanori <ishit@oak.dti.ne.jp>
changes in bozohttpd 5.09 (20010922):
- add a daemon mode
- document how to use bozohttpd in netbsd inetd with more than 40
connections per minute and also with cgibin
- man page fixes from wiz@netbsd.org
changes in bozohttpd 5.08 (20010812):
- add directory index generation support (-X) from ad@netbsd.org
- add .pa as an alias for .pac
- make server software version configurable (RFC)
changes in bozohttpd 5.07 (20010610):
- add .png support
- new "-x index.html" flag to change default file
- new "-p public_html" flag to change default ~user directory
- fixes cgi-bin support and more from chuck@research.att.com
- add many new content-types, now support most common ones
changes in bozohttpd 5.06 (20000825):
- add IPv6 suppor from itojun@iijlab.net
- man page fixes from jlam@netbsd.org
changes in bozohttpd 5.05 (20000815):
- fix a virtual host bug, from kleink@netbsd.org
changes in bozohttpd 5.04 (20000427):
- fix virtual host support; URI takes precedence over Host:
changes in bozohttpd 5.03 (20000427):
- fix a bug with chdir()
changes in bozohttpd 5.02 (20000426):
- .pac spport from simonb
changes in bozohttpd 5.01 (20000421):
- .swf support
- virtual hosting support

108
libexec/httpd/Makefile Normal file
View File

@ -0,0 +1,108 @@
# $NetBSD: Makefile,v 1.24 2015/08/05 06:50:44 mrg Exp $
#
# $eterna: Makefile,v 1.30 2010/07/11 00:34:27 mrg Exp $
#
# berkeley (netbsd) makefile. see Makefile.boot for other systems.
# compile-time options are:
# NO_DEBUG /* don't include debugging support */
# NO_USER_SUPPORT /* don't support /~user requests */
# NO_CGIBIN_SUPPORT /* don't support cgi-bin requests */
# NO_DIRINDEX_SUPPORT /* don't support directory indexing */
# NO_DAEMON_MODE /* don't support daemon mode */
# NO_DYNAMIC_CONTENT /* don't support dynamic content updates */
# NO_SSL_SUPPORT /* don't support ssl (https) */
# DO_HTPASSWD /* support .htpasswd files */
# NO_LUA_SUPPORT /* don't support Lua for dynamic content */
#
# other system specific defines:
# HAVE_NBUTIL_H /* netbsd compat is in <nbutil.h>
# (don't forget to also enable -lnbutil)
#
# these are usually set via the "COPTS" variable, or some other method
# for setting CFLAGS relevant to your make, eg
# % make COPTS="-DDO_HTPASSWD"
COPTS+= -DDO_HTPASSWD
PROG= bozohttpd
LINKS= ${BINDIR}/bozohttpd ${BINDIR}/httpd
MAN= bozohttpd.8
MLINKS+=bozohttpd.8 httpd.8
SRCS= bozohttpd.c ssl-bozo.c auth-bozo.c cgi-bozo.c daemon-bozo.c \
tilde-luzah-bozo.c dir-index-bozo.c content-bozo.c lua-bozo.c
SRCS+= main.c
LDADD= -lcrypt -llua -lm
DPADD= ${LIBCRYPT} ${LIBLUA} ${LIBM}
WARNS?= 4
.if defined(.OS.MAKE)
OPSYS= ${.OS.MAKE}
.else
OPSYS:= ${:!uname -s!:S/-//g:S/\///g}
.endif
.if ${OPSYS} == "QNX"
CPPFLAGS+= -DHAVE_NBUTIL_H
LDADD+= -lnbutil
.endif
.include <bsd.own.mk>
.if ${MKCRYPTO} != "no"
LDADD+= -lssl -lcrypto
DPADD+= ${LIBSSL} ${LIBCRYPTO}
.else
COPTS+= -DNO_SSL_SUPPORT
.endif
#
# Build release things.
#
NROFF?= nroff
PREHTMLFROB= sed \
-e 's/&/\&amp;/' \
-e 's/</\&lt;/' \
-e 's/>/\&gt;/'
HTMLFROB= sed \
-e 's/\([MC] "[^"]*\)<dd>$$/\1<b>"<\/b><dd>/' \
-e 's/'"''"'/\&rdquo;/' \
-e 's/""/\&ldquo;/' \
-e 's/<a href="\.\.\/html[^>]*>\(.*\)<\/a>/\1/'
TXTFROB= col -b
bozohttpd.8.html: bozohttpd.8
$(PREHTMLFROB) $> | $(NROFF) -mdoc2html | $(HTMLFROB) > $@
bozohttpd.8.txt: bozohttpd.8
$(NROFF) -mdoc -Tascii $> | $(TXTFROB) > $@
CLEANFILES+= bozohttpd.8.html bozohttpd.8.txt
# Create a distfile: uses /tmp
BASE=bozohttpd-${BOZOVER}
TAR=${BASE}.tar
export-distfile:
dir=`mktemp -d /tmp/bozo-export-XXXXXX`; \
cd "$${dir}" || exit; \
mkdir ${BASE}; \
( cd ${BASE} || exit; \
cp -r "${.CURDIR}/." "."; \
find . -name .CVS | xargs rm -r; \
); \
pax -wf ${TAR} ${BASE}; \
gzip -nc9 ${TAR} > ${TAR}.gz; \
bzip2 -9 ${TAR}; \
echo "Exported two files in $${dir}:"; \
echo ${TAR}.gz; \
echo ${TAR}.bz2
.include <bsd.prog.mk>

View File

@ -0,0 +1,26 @@
# $eterna: Makefile.boot,v 1.9 2010/05/10 04:57:50 mrg Exp $
#
# very simple makefile to compile bozohttpd, should work with every make.
# see Makefile for a list of compile options that may be placed in CFLAGS.
CC= cc
OPT= -O
LARGE_CFLAGS= -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS= -DNO_LUA_SUPPORT
CFLAGS= $(OPT) $(LARGE_CFLAGS) $(LOCAL_CFLAGS)
GROFF= groff -Tascii
CRYPTOLIBDIR= # -L/usr/local/lib
CRYPTOLIBS= $(CRYPTOLIBDIR) -lcrypto -lssl
FILES= bozohttpd.c auth-bozo.c cgi-bozo.c content-bozo.c daemon-bozo.c \
dir-index-bozo.c lua-bozo.c ssl-bozo.c tilde-luzah-bozo.c main.c
all:
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o bozohttpd $(FILES) $(CRYPTOLIBS)
man:
$(GROFF) -mandoc bozohttpd.8 > bozohttpd.cat8
clean:
rm -f bozohttpd bozohttpd.cat8 *.o

272
libexec/httpd/auth-bozo.c Normal file
View File

@ -0,0 +1,272 @@
/* $NetBSD: auth-bozo.c,v 1.16 2014/12/26 19:52:00 mrg Exp $ */
/* $eterna: auth-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $ */
/*
* Copyright (c) 1997-2014 Matthew R. Green
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
/* this code implements "http basic authorisation" for bozohttpd */
#ifdef DO_HTPASSWD
#include <sys/param.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "bozohttpd.h"
#ifndef AUTH_FILE
#define AUTH_FILE ".htpasswd"
#endif
static ssize_t base64_decode(const unsigned char *, size_t,
unsigned char *, size_t);
/*
* Check if HTTP authentication is required
*/
int
bozo_auth_check(bozo_httpreq_t *request, const char *file)
{
bozohttpd_t *httpd = request->hr_httpd;
struct stat sb;
char dir[MAXPATHLEN], authfile[MAXPATHLEN], *basename;
char user[BUFSIZ], *pass;
FILE *fp;
int len;
/* get dir=dirname(file) */
snprintf(dir, sizeof(dir), "%s", file);
if ((basename = strrchr(dir, '/')) == NULL)
strcpy(dir, ".");
else {
*basename++ = '\0';
/* ensure basename(file) != AUTH_FILE */
if (bozo_check_special_files(request, basename))
return 1;
}
request->hr_authrealm = bozostrdup(httpd, dir);
if ((size_t)snprintf(authfile, sizeof(authfile), "%s/%s", dir, AUTH_FILE) >=
sizeof(authfile)) {
return bozo_http_error(httpd, 404, request,
"authfile path too long");
}
if (stat(authfile, &sb) < 0) {
debug((httpd, DEBUG_NORMAL,
"bozo_auth_check realm `%s' dir `%s' authfile `%s' missing",
dir, file, authfile));
return 0;
}
if ((fp = fopen(authfile, "r")) == NULL)
return bozo_http_error(httpd, 403, request,
"no permission to open authfile");
debug((httpd, DEBUG_NORMAL,
"bozo_auth_check realm `%s' dir `%s' authfile `%s' open",
dir, file, authfile));
if (request->hr_authuser && request->hr_authpass) {
while (fgets(user, sizeof(user), fp) != NULL) {
len = strlen(user);
if (len > 0 && user[len-1] == '\n')
user[--len] = '\0';
if ((pass = strchr(user, ':')) == NULL)
continue;
*pass++ = '\0';
debug((httpd, DEBUG_NORMAL,
"bozo_auth_check authfile `%s':`%s' "
"client `%s':`%s'",
user, pass, request->hr_authuser,
request->hr_authpass));
if (strcmp(request->hr_authuser, user) != 0)
continue;
if (strcmp(crypt(request->hr_authpass, pass),
pass) != 0)
break;
fclose(fp);
return 0;
}
}
fclose(fp);
return bozo_http_error(httpd, 401, request, "bad auth");
}
void
bozo_auth_init(bozo_httpreq_t *request)
{
request->hr_authuser = NULL;
request->hr_authpass = NULL;
}
void
bozo_auth_cleanup(bozo_httpreq_t *request)
{
if (request == NULL)
return;
free(request->hr_authuser);
free(request->hr_authpass);
free(request->hr_authrealm);
}
int
bozo_auth_check_headers(bozo_httpreq_t *request, char *val, char *str, ssize_t len)
{
bozohttpd_t *httpd = request->hr_httpd;
if (strcasecmp(val, "authorization") == 0 &&
strncasecmp(str, "Basic ", 6) == 0) {
char authbuf[BUFSIZ];
char *pass = NULL;
ssize_t alen;
alen = base64_decode((unsigned char *)str + 6,
(size_t)(len - 6),
(unsigned char *)authbuf,
sizeof(authbuf) - 1);
if (alen != -1)
authbuf[alen] = '\0';
if (alen == -1 ||
(pass = strchr(authbuf, ':')) == NULL)
return bozo_http_error(httpd, 400, request,
"bad authorization field");
*pass++ = '\0';
free(request->hr_authuser);
free(request->hr_authpass);
request->hr_authuser = bozostrdup(httpd, authbuf);
request->hr_authpass = bozostrdup(httpd, pass);
debug((httpd, DEBUG_FAT,
"decoded authorization `%s' as `%s':`%s'",
str, request->hr_authuser, request->hr_authpass));
/* don't store in request->headers */
return 1;
}
return 0;
}
int
bozo_auth_check_special_files(bozo_httpreq_t *request,
const char *name)
{
bozohttpd_t *httpd = request->hr_httpd;
if (strcmp(name, AUTH_FILE) == 0)
return bozo_http_error(httpd, 403, request,
"no permission to open authfile");
return 0;
}
void
bozo_auth_check_401(bozo_httpreq_t *request, int code)
{
bozohttpd_t *httpd = request->hr_httpd;
if (code == 401)
bozo_printf(httpd,
"WWW-Authenticate: Basic realm=\"%s\"\r\n",
(request && request->hr_authrealm) ?
request->hr_authrealm : "default realm");
}
#ifndef NO_CGIBIN_SUPPORT
void
bozo_auth_cgi_setenv(bozo_httpreq_t *request,
char ***curenvpp)
{
bozohttpd_t *httpd = request->hr_httpd;
if (request->hr_authuser && *request->hr_authuser) {
bozo_setenv(httpd, "AUTH_TYPE", "Basic", (*curenvpp)++);
bozo_setenv(httpd, "REMOTE_USER", request->hr_authuser,
(*curenvpp)++);
}
}
int
bozo_auth_cgi_count(bozo_httpreq_t *request)
{
return (request->hr_authuser && *request->hr_authuser) ? 2 : 0;
}
#endif /* NO_CGIBIN_SUPPORT */
/*
* Decode len bytes starting at in using base64 encoding into out.
* Result is *not* NUL terminated.
* Written by Luke Mewburn <lukem@NetBSD.org>
*/
const unsigned char decodetable[] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255,
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255,
};
static ssize_t
base64_decode(const unsigned char *in, size_t ilen, unsigned char *out,
size_t olen)
{
unsigned char *cp;
size_t i;
if (ilen == 0) {
if (olen)
*out = '\0';
return 0;
}
cp = out;
for (i = 0; i < ilen; i += 4) {
if (cp + 3 > out + olen)
return (-1);
#define IN_CHECK(x) \
if ((x) > sizeof(decodetable) || decodetable[(x)] == 255) \
return(-1)
IN_CHECK(in[i + 0]);
/*LINTED*/
*(cp++) = decodetable[in[i + 0]] << 2
| decodetable[in[i + 1]] >> 4;
IN_CHECK(in[i + 1]);
/*LINTED*/
*(cp++) = decodetable[in[i + 1]] << 4
| decodetable[in[i + 2]] >> 2;
IN_CHECK(in[i + 2]);
*(cp++) = decodetable[in[i + 2]] << 6
| decodetable[in[i + 3]];
#undef IN_CHECK
}
while (i > 0 && in[i - 1] == '=')
cp--,i--;
return (cp - out);
}
#endif /* DO_HTPASSWD */

683
libexec/httpd/bozohttpd.8 Normal file
View File

@ -0,0 +1,683 @@
.\" $NetBSD: bozohttpd.8,v 1.53 2015/08/13 12:30:08 wiz Exp $
.\"
.\" $eterna: bozohttpd.8,v 1.101 2011/11/18 01:25:11 mrg Exp $
.\"
.\" Copyright (c) 1997-2015 Matthew R. Green
.\" 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 ``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 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.
.\"
.Dd May 1, 2015
.Dt BOZOHTTPD 8
.Os
.Sh NAME
.Nm bozohttpd
.Nd hyper text transfer protocol version 1.1 daemon
.Sh SYNOPSIS
.Nm
.Op Fl CIMPSZciptvx
.Op Fl C Ar suffix cgihandler
.Op Fl I Ar port
.Op Fl L Ar prefix script
.Op Fl M Ar suffix type encoding encoding11
.Op Fl P Ar pidfile
.Op Fl S Ar server_software
.Op Fl Z Ar cert privkey
.Op Fl c Ar cgibin
.Op Fl i Ar address
.Op Fl p Ar pubdir
.Op Fl t Ar chrootdir
.Op Fl v Ar virtualroot
.Op Fl x Ar index
.Ar slashdir
.Op Ar myname
.Sh DESCRIPTION
The
.Nm
program reads a
.Em HTTP
request from the standard input, and sends a reply to the standard output.
Besides ~user translation and virtual hosting support (see below), all file
requests are from
.Ar slashdir
directory.
The server uses
.Ar myname
as its name, which defaults to the local hostname, obtained from
.Xr gethostname 3
(but see the
.Fl v
option for virtual hosting.)
.Nm
writes logs to
.Xr syslog 3
using the ftp facility (but see the
.Fl s
option for testing.)
.Nm
is designed to be small, simple and relatively featureless,
hopefully increasing its security.
.Ss OPTIONS
The following options are available:
.Bl -tag -width xxxcgibin
.It Fl b
Enables daemon mode, where
.Nm
detaches from the current terminal, running in the background and
servicing HTTP requests.
.It Fl C Ar suffix cgihandler
Adds a new CGI handler program for a particular file type.
The
.Ar suffix
should be any normal file suffix, and the
.Ar cgihandler
should be a full path to an interpreter.
This option is the only way to enable CGI programs that exist
outside of the cgibin directory to be executed.
Multiple
.Fl C
options may be passed.
.It Fl c Ar cgibin
Enables the CGI/1.1 interface.
The
.Ar cgibin
directory is expected to contain the CGI programs to be used.
.Nm
looks for URL's in the form of
.Em /cgi-bin/\*[Lt]scriptname\*[Gt]
where
.Aq scriptname
is a valid CGI program in the
.Ar cgibin
directory.
In other words, all CGI URL's must begin with
.Em \%/cgi-bin/ .
Note that the CGI/1.1 interface is not available with
.Em ~user
translation.
.It Fl e
Causes
.Nm
to not clear the environment when used with either the
.Fl t
or
.Fl U
options.
.It Fl f
Stops the
.Fl b
flag from
.Nm
detaching from the tty and going into the background.
.It Fl H
Causes directory index mode to hide files and directories
that start with a period, except for
.Pa .. .
Also see
.Fl X .
.It Fl I Ar port
Causes
.Nm
to use
.Ar port
instead of the default
.Dq http
port.
When used with the
.Fl b
option, it changes the bound port.
Otherwise it forces redirections to use this port instead of the
value obtained via
.Xr getsockname 2 .
.It Fl i Ar address
Causes
.Ar address
to be used as the address to bind daemon mode.
If otherwise unspecified, the address used to bind is derived from the
.Ar myname ,
which defaults to the name returned by
.Xr gethostname 3 .
Only the last
.Fl i
option is used.
This option is only valid with the
.Fl b
option.
.It Fl L Ar prefix script
Adds a new Lua script for a particular prefix.
The
.Ar prefix
should be an arbitrary text, and the
.Ar script
should be a full path to a Lua script.
Multiple
.Fl L
options may be passed.
A separate Lua state is created for each prefix.
The Lua script can register callbacks using the
httpd.register_handler('<name>', function) Lua function,
which will trigger the execution of the Lua function
.Em function
when a URL in the form
.Em http://<hostname>/<prefix>/<name>
is being accessed.
The function is passed three tables as arguments, the server
environment, the request headers, and the decoded query string
plus any data that was send as application/x-www-form-urlencoded.
.It Fl M Ar suffix type encoding encoding11
Adds a new entry to the table that converts file suffixes to
content type and encoding.
This option takes four additional arguments containing
the file prefix, its
.Dq Content-Type ,
.Dq Content-Encoding ,
and
.Dq Content-Encoding
for HTTP/1.1 connections, respectively.
If any of these are a single dash
.Pq Dq - ,
the empty string is used instead.
Multiple
.Fl M
options may be passed.
.It Fl n
Stops
.Nm
from doing IP address to name resolution of hosts for setting the
.Ev REMOTE_HOST
variable before running a CGI program.
This option has no effect without the
.Fl c
option.
.It Fl P Ar pidfile
Causes
.Nm
to create a pid file in
.Ar pidfile
when run in daemon mode with the
.Fl b
option.
.It Fl p Ar pubdir
Changes the default user directory for
.Em /~user/
translations from
.Dq public_html
to
.Ar pubdir .
.It Fl r
Forces pages besides the
.Dq index.html
(see the
.Fl X
option) page to require that the Referrer: header be present and
refer to this web server, otherwise a redirect to the
.Dq index.html
page will be returned instead.
.It Fl S Ar server_software
Sets the internal server version to
.Ar server_software .
.It Fl s
Forces logging to be set to stderr always.
.It Fl t Ar chrootdir
Makes
.Nm
chroot to the specified directory
before answering requests.
Every other path should be specified relative
to the new root, if this option is used.
Note that the current environment
is normally replaced with an empty environment with this option, unless the
.Fl e
option is also used.
.It Fl U Ar username
Causes
.Nm
to switch to the user and the groups of
.Ar username
after initialization.
This option, like
.Fl t
above, causes
.Nm
to clear the environment unless the
.Fl e
option is given.
.It Fl u
Enables the transformation of Uniform Resource Locators of
the form
.Em /~user/
into the directory
.Pa ~user/public_html
(but see the
.Fl p
option above).
.It Fl V
Sets the default virtual host directory to
.Ar slashdir .
If no directory exists in
.Ar virtualroot
for the request, then
.Ar slashdir
will be used.
The default behaviour is to return 404 (Not Found.)
.It Fl v Ar virtualroot
Enables virtual hosting support.
Directories in
.Ar virtualroot
will be searched for a matching virtual host name, when parsing
the HTML request.
If a matching name is found, it will be used
as both the server's real name,
.Op Ar myname ,
and as the
.Ar slashdir .
See the
.Sx EXAMPLES
section for an example of using this option.
.It Fl X
Enables directory indexing.
A directory index will be generated only when the default file (i.e.
.Pa index.html
normally) is not present.
.It Fl x Ar index
Changes the default file read for directories from
.Dq index.html
to
.Ar index .
.It Fl Z Ar certificate_path privatekey_path
Sets the path to the server certificate file and the private key file
in pem format.
It also causes
.Nm
to start SSL mode.
.El
.Pp
Note that in
.Nm
versions 20031005 and prior that supported the
.Fl C
and
.Fl M
options, they took a single space-separated argument that was parsed.
since version 20040828, they take multiple options (2 in the case of
.Fl C
and 4 in the case of
.Fl M . )
.Ss INETD CONFIGURATION
As
.Nm
uses
.Xr inetd 8
by default to process incoming TCP connections for HTTP requests
(but see the
.Fl b
option),
.Nm
has little internal networking knowledge.
(Indeed, you can run it on the command line with little change of functionality.)
A typical
.Xr inetd.conf 5
entry would be:
.Bd -literal
http stream tcp nowait:600 _httpd /usr/libexec/httpd httpd /var/www
http stream tcp6 nowait:600 _httpd /usr/libexec/httpd httpd /var/www
.Ed
.Pp
This would serve web pages from
.Pa /var/www
on both IPv4 and IPv6 ports.
The
.Em :600
changes the
requests per minute to 600, up from the
.Xr inetd 8
default of 40.
.Pp
Using the
.Nx
.Xr inetd 8 ,
you can provide multiple IP-address based HTTP servers by having multiple
listening ports with different configurations.
.Ss NOTES
This server supports the
.Em HTTP/0.9 ,
.Em HTTP/1.0 ,
and
.Em HTTP/1.1
standards.
Support for these protocols is very minimal and many optional features are
not supported.
.Pp
.Nm
can be compiled without
CGI support (NO_CGIBIN_SUPPORT),
user transformations (NO_USER_SUPPORT),
directory index support (NO_DIRINDEX_SUPPORT),
daemon mode support (NO_DAEMON_MODE),
dynamic MIME content (NO_DYNAMIC_CONTENT),
Lua suport (NO_LUA_SUPPORT),
and SSL support (NO_SSL_SUPPORT)
by defining the listed macros when building
.Nm .
.Ss HTTP BASIC AUTHORISATION
.Nm
has support for HTTP Basic Authorisation.
If a file named
.Pa .htpasswd
exists in the directory of the current request,
.Nm
will restrict access to documents in that directory
using the RFC 2617 HTTP
.Dq Basic
authentication scheme.
.Pp
Note:
This does not recursively protect any sub-directories.
.Pp
The
.Pa .htpasswd
file contains lines delimited with a colon containing
usernames and passwords hashed with
.Xr crypt 3 ,
for example:
.Bd -literal
heather:$1$pZWI4tH/$DzDPl63i6VvVRv2lJNV7k1
jeremy:A.xewbx2DpQ8I
.Ed
.Pp
On
.Nx ,
the
.Xr pwhash 1
utility may be used to generate hashed passwords.
.Pp
While
.Nm
distributed with
.Nx
has support for HTTP Basic Authorisation enabled by default,
in the portable distribution it is excluded.
Compile
.Nm
with
.Dq -DDO_HTPASSWD
on the compiler command line to enable this support.
It may require linking with the crypt library, using
.Dq -lcrypt .
.Ss SSL SUPPORT
.Nm
has support for SSLv2, SSLv3, and TLSv1 protocols that is included by
default.
It requires linking with the crypto and ssl library, using
.Dq -lcrypto -lssl .
To disable SSL SUPPORT compile
.Nm
with
.Dq -DNO_SSL_SUPPORT
on the compiler command line.
.Ss COMPRESSION
.Nm
supports a very basic form compression.
.Nm
will serve the requested file postpended with
.Dq Pa .gz
if it exists, it is readable, the client requested gzip compression, and
the client did not make a ranged request.
.Sh FILES
.Nm
looks for a couple of special files in directories that allow certain features
to be provided on a per-directory basis.
In addition to the
.Pa .htpasswd
used by HTTP basic authorisation,
if a
.Pa .bzdirect
file is found (contents are irrelevant)
.Nm
will allow direct access even with the
.Fl r
option.
If a
.Pa .bzredirect
symbolic link is found,
.Nm
will perform a smart redirect to the target of this symlink.
The target is assumed to live on the same server.
If a
.Pa .bzabsredirect
symbolic link is found,
.Nm
will redirect to the absolute url pointed to by this symlink.
This is useful to redirect to different servers.
.Sh EXAMPLES
To configure set of virtual hosts, one would use an
.Xr inetd.conf 5
entry like:
.Bd -literal
http stream tcp nowait:600 _httpd /usr/libexec/httpd httpd -v /var/vroot /var/www
.Ed
.Pp
and inside
.Pa /var/vroot
create a directory (or a symlink to a directory) with the same name as
the virtual host, for each virtual host.
Lookups for these names are done in a case-insensitive manner, and may
include the port number part of the request, allowing for distinct
virtual hosts on the same name.
.Pp
To use
.Nm
with PHP, one must use the
.Fl C
option to specify a CGI handler for a particular file type.
Typically this will be like:
.Bd -literal
httpd -C .php /usr/pkg/bin/php /var/www
.Ed
.Sh SEE ALSO
.Xr inetd.conf 5 ,
.Xr inetd 8
.Sh HISTORY
.Nm
was first written in perl, based on another perl http server
called
.Dq tinyhttpd .
It was then rewritten from scratch in perl, and then once again in C.
From
.Dq bozohttpd
version 20060517, it has been integrated into
.Nx .
The focus has always been simplicity and security, with minimal features
and regular code audits.
This manual documents
.Nm
version 20150501.
.Sh AUTHORS
.An -nosplit
.Nm
was written by
.An Matthew R. Green
.Aq Mt mrg@eterna.com.au .
.Pp
The large list of contributors includes:
.Bl -dash
.It
.An Marc Balmer
.Aq Mt mbalmer@NetBSD.org
added Lua support for dynamic content creation
.It
.An Christoph Badura
.Aq Mt bad@bsd.de
provided Range: header support
.It
.An Sean Boudreau
.Aq Mt seanb@NetBSD.org
provided a security fix for virtual hosting
.It
.An Julian Coleman
.Aq Mt jdc@coris.org.uk
provided an IPv6 bugfix
.It
.An Chuck Cranor
.Aq Mt chuck@research.att.com
provided cgi-bin support fixes, and more
.It
.An Alistair G. Crooks
.Aq Mt agc@NetBSD.org
cleaned up many internal interfaces, made
.Nm
linkable as a library and provided the Lua binding.
.It
.An DEGROOTE Arnaud
.Aq Mt degroote@NetBSD.org
provided a fix for daemon mode
.It
.An Andrew Doran
.Aq Mt ad@NetBSD.org
provided directory indexing support
.It
.An Per Ekman
.Aq Mt pek@pdc.kth.se
provided a fix for a minor (non-security) buffer overflow condition
.It
.An Roland Dowdeswell
.Aq Mt elric@NetBSD.org
added support for serving gzipped files and better SSL handling
.It
.An Jun-ichiro itojun Hagino, KAME
.Aq Mt itojun@iijlab.net
provided initial IPv6 support
.It
.An Martin Husemann
.Aq Mt martin@NetBSD.org
provided .bzabsredirect support, and fixed various redirection issues
.It
.An Arto Huusko
.Aq Mt arto.huusko@pp2.inet.fi
provided fixes cgi-bin
.It
.An Roland Illig
.Aq Mt roland.illig@gmx.de
provided some off-by-one fixes
.It
.An Zak Johnson
.Aq Mt zakj@nox.cx
provided cgi-bin enhancements
.It
.An Nicolas Jombart
.Aq Mt ecu@ipv42.net
provided fixes for HTTP basic authorisation support
.It
.An Antti Kantee
.Aq Mt pooka@NetBSD.org
provided fixes for HTTP basic authorisation support
.It
.An Thomas Klausner
.Aq Mt wiz@NetBSD.org
provided many fixes and enhancements for the man page
.It
.An Mateusz Kocielski
.Aq Mt shm@NetBSD.org
fixed memory leaks, various issues with userdir support,
information disclosure issues, added support for using CGI handlers
with directory indexing and provided various other fixes.
.It
.An Arnaud Lacombe
.Aq Mt alc@NetBSD.org
provided some clean up for memory leaks
.It
.An Johnny Lam
.Aq Mt jlam@NetBSD.org
provided man page fixes
.It
.An Julio Merino
.Aq Mt jmmv@NetBSD.org
Added the
.Fl P
option.
.It
.An Luke Mewburn
.Aq Mt lukem@NetBSD.org
provided many various fixes, including cgi-bin fixes and enhancements,
HTTP basic authorisation support and much code clean up
.It
.An Rajeev V. Pillai
.Aq Mt rajeev_v_pillai@yahoo.com
provided several fixes for virtual hosting
.It
.An Jeremy C. Reed
.Aq Mt reed@NetBSD.org
provided several clean up fixes, and man page updates
.It
.An Scott Reynolds
.Aq Mt scottr@NetBSD.org
provided various fixes
.It
.An Tyler Retzlaff
.Aq Mt rtr@eterna.com.au
provided SSL support, cgi-bin fixes and much other random other stuff
.It
.An rudolf
.Aq Mt netbsd@eq.cz
provided minor compile fixes and a CGI content map fix
.It
.An Steve Rumble
.Aq Mt rumble@ephemeral.org
provided the
.Fl V
option.
.It
.An Thor Lancelot Simon
.Aq Mt tls@NetBSD.org
enhanced cgi-bin support.
.It
.An Joerg Sonnenberger
.Aq Mt joerg@NetBSD.org
implemented If-Modified-Since support
.It
.An ISIHARA Takanori
.Aq Mt ishit@oak.dti.ne.jp
provided a man page fix
.It
.An Holger Weiss
.Aq Mt holger@CIS.FU-Berlin.DE
provided http authorisation fixes
.It
.Aq Mt xs@kittenz.org
provided chroot and change-to-user support, and other various fixes
.It
Coyote Point provided various CGI fixes.
.It
.An Julio Merino
added pidfile support and provided some man page fixes.
.El
.Pp
There are probably others I have forgotten (let me know if you care)
.Pp
Please send all updates to
.Nm
to
.Aq Mt mrg@eterna.com.au
for inclusion in future releases.
.Sh BUGS
.Nm
does not handle HTTP/1.1 chunked input from the client yet.

2321
libexec/httpd/bozohttpd.c Normal file

File diff suppressed because it is too large Load Diff

350
libexec/httpd/bozohttpd.h Normal file
View File

@ -0,0 +1,350 @@
/* $NetBSD: bozohttpd.h,v 1.36 2015/08/05 06:50:44 mrg Exp $ */
/* $eterna: bozohttpd.h,v 1.39 2011/11/18 09:21:15 mrg Exp $ */
/*
* Copyright (c) 1997-2015 Matthew R. Green
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
#ifndef BOZOHTTOPD_H_
#define BOZOHTTOPD_H_ 1
#include "netbsd_queue.h"
#include <sys/stat.h>
#ifndef NO_LUA_SUPPORT
#include <lua.h>
#endif
#include <stdio.h>
/* QNX provides a lot of NetBSD things in nbutil.h */
#ifdef USE_NBUTIL
#include <nbutil.h>
#endif
/* lots of "const" but gets free()'ed etc at times, sigh */
/* headers */
typedef struct bozoheaders {
/*const*/ char *h_header;
/*const*/ char *h_value; /* this gets free()'ed etc at times */
SIMPLEQ_ENTRY(bozoheaders) h_next;
} bozoheaders_t;
#ifndef NO_LUA_SUPPORT
typedef struct lua_handler {
const char *name;
int ref;
SIMPLEQ_ENTRY(lua_handler) h_next;
} lua_handler_t;
typedef struct lua_state_map {
const char *script;
const char *prefix;
lua_State *L;
SIMPLEQ_HEAD(, lua_handler) handlers;
SIMPLEQ_ENTRY(lua_state_map) s_next;
} lua_state_map_t;
#endif
typedef struct bozo_content_map_t {
const char *name; /* postfix of file */
const char *type; /* matching content-type */
const char *encoding; /* matching content-encoding */
const char *encoding11; /* matching content-encoding (HTTP/1.1) */
const char *cgihandler; /* optional CGI handler */
} bozo_content_map_t;
/* this struct holds the bozo constants */
typedef struct bozo_consts_t {
const char *http_09; /* "HTTP/0.9" */
const char *http_10; /* "HTTP/1.0" */
const char *http_11; /* "HTTP/1.1" */
const char *text_plain; /* "text/plain" */
} bozo_consts_t;
/* this structure encapsulates all the bozo flags and control vars */
typedef struct bozohttpd_t {
char *rootdir; /* root directory */
char *username; /* username to switch to */
int numeric; /* avoid gethostby*() */
char *virtbase; /* virtual directory base */
int unknown_slash; /* unknown vhosts go to normal slashdir */
int untrustedref; /* make sure referrer = me unless url = / */
int logstderr; /* log to stderr (even if not tty) */
int background; /* drop into daemon mode */
int foreground; /* keep daemon mode in foreground */
char *pidfile; /* path to the pid file, if any */
size_t page_size; /* page size */
char *slashdir; /* www slash directory */
char *bindport; /* bind port; default "http" */
char *bindaddress; /* address for binding - INADDR_ANY */
int debug; /* debugging level */
char *virthostname; /* my name */
const char *server_software;/* our brand :-) */
const char *index_html; /* our home page */
const char *public_html; /* ~user/public_html page */
int enable_users; /* enable public_html */
int *sock; /* bound sockets */
int nsock; /* number of above */
struct pollfd *fds; /* current poll fd set */
int request_times; /* # times a request was processed */
int dir_indexing; /* handle directories */
int hide_dots; /* hide .* */
int process_cgi; /* use the cgi handler */
char *cgibin; /* cgi-bin directory */
#ifndef NO_LUA_SUPPORT
int process_lua; /* use the Lua handler */
SIMPLEQ_HEAD(, lua_state_map) lua_states;
#endif
void *sslinfo; /* pointer to ssl struct */
int dynamic_content_map_size;/* size of dyn cont map */
bozo_content_map_t *dynamic_content_map;/* dynamic content map */
size_t mmapsz; /* size of region to mmap */
char *getln_buffer; /* space for getln buffer */
ssize_t getln_buflen; /* length of allocated space */
char *errorbuf; /* no dynamic allocation allowed */
bozo_consts_t consts; /* various constants */
} bozohttpd_t;
/* bozo_httpreq_t */
typedef struct bozo_httpreq_t {
bozohttpd_t *hr_httpd;
int hr_method;
#define HTTP_GET 0x01
#define HTTP_POST 0x02
#define HTTP_HEAD 0x03
#define HTTP_OPTIONS 0x04 /* not supported */
#define HTTP_PUT 0x05 /* not supported */
#define HTTP_DELETE 0x06 /* not supported */
#define HTTP_TRACE 0x07 /* not supported */
#define HTTP_CONNECT 0x08 /* not supported */
const char *hr_methodstr;
char *hr_virthostname; /* server name (if not identical
to hr_httpd->virthostname) */
char *hr_file;
char *hr_oldfile; /* if we added an index_html */
char *hr_query;
char *hr_host; /* HTTP/1.1 Host: or virtual hostname,
possibly including a port number */
const char *hr_proto;
const char *hr_content_type;
const char *hr_content_length;
const char *hr_allow;
const char *hr_referrer;
const char *hr_range;
const char *hr_if_modified_since;
const char *hr_accept_encoding;
int hr_have_range;
off_t hr_first_byte_pos;
off_t hr_last_byte_pos;
/*const*/ char *hr_remotehost;
/*const*/ char *hr_remoteaddr;
/*const*/ char *hr_serverport;
#ifdef DO_HTPASSWD
/*const*/ char *hr_authrealm;
/*const*/ char *hr_authuser;
/*const*/ char *hr_authpass;
#endif
SIMPLEQ_HEAD(, bozoheaders) hr_headers;
int hr_nheaders;
} bozo_httpreq_t;
/* helper to access the "active" host name from a httpd/request pair */
#define BOZOHOST(HTTPD,REQUEST) ((REQUEST)->hr_virthostname ? \
(REQUEST)->hr_virthostname : \
(HTTPD)->virthostname)
/* structure to hold string based (name, value) pairs with preferences */
typedef struct bozoprefs_t {
unsigned size; /* size of the two arrays */
unsigned c; /* # of entries in arrays */
char **name; /* names of each entry */
char **value; /* values for the name entries */
} bozoprefs_t;
/* by default write in upto 64KiB chunks, and mmap in upto 64MiB chunks */
#ifndef BOZO_WRSZ
#define BOZO_WRSZ (64 * 1024)
#endif
#ifndef BOZO_MMAPSZ
#define BOZO_MMAPSZ (BOZO_WRSZ * 1024)
#endif
/* debug flags */
#define DEBUG_NORMAL 1
#define DEBUG_FAT 2
#define DEBUG_OBESE 3
#define DEBUG_EXPLODING 4
#define strornull(x) ((x) ? (x) : "<null>")
#if defined(__GNUC__) && __GNUC__ >= 3
#define BOZO_PRINTFLIKE(x,y) __attribute__((__format__(__printf__, x,y)))
#define BOZO_DEAD __attribute__((__noreturn__))
#endif
#ifndef NO_DEBUG
void debug__(bozohttpd_t *, int, const char *, ...) BOZO_PRINTFLIKE(3, 4);
#define debug(x) debug__ x
#else
#define debug(x)
#endif /* NO_DEBUG */
void bozo_warn(bozohttpd_t *, const char *, ...)
BOZO_PRINTFLIKE(2, 3);
void bozo_err(bozohttpd_t *, int, const char *, ...)
BOZO_PRINTFLIKE(3, 4)
BOZO_DEAD;
int bozo_http_error(bozohttpd_t *, int, bozo_httpreq_t *, const char *);
int bozo_check_special_files(bozo_httpreq_t *, const char *);
char *bozo_http_date(char *, size_t);
void bozo_print_header(bozo_httpreq_t *, struct stat *, const char *, const char *);
char *bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url);
char *bozo_escape_html(bozohttpd_t *httpd, const char *url);
char *bozodgetln(bozohttpd_t *, int, ssize_t *, ssize_t (*)(bozohttpd_t *, int, void *, size_t));
char *bozostrnsep(char **, const char *, ssize_t *);
void *bozomalloc(bozohttpd_t *, size_t);
void *bozorealloc(bozohttpd_t *, void *, size_t);
char *bozostrdup(bozohttpd_t *, const char *);
/* ssl-bozo.c */
#ifdef NO_SSL_SUPPORT
#define bozo_ssl_set_opts(w, x, y) do { /* nothing */ } while (0)
#define bozo_ssl_init(x) do { /* nothing */ } while (0)
#define bozo_ssl_accept(x) (0)
#define bozo_ssl_destroy(x) do { /* nothing */ } while (0)
#else
void bozo_ssl_set_opts(bozohttpd_t *, const char *, const char *);
void bozo_ssl_init(bozohttpd_t *);
int bozo_ssl_accept(bozohttpd_t *);
void bozo_ssl_destroy(bozohttpd_t *);
#endif
/* auth-bozo.c */
#ifdef DO_HTPASSWD
void bozo_auth_init(bozo_httpreq_t *);
int bozo_auth_check(bozo_httpreq_t *, const char *);
void bozo_auth_cleanup(bozo_httpreq_t *);
int bozo_auth_check_headers(bozo_httpreq_t *, char *, char *, ssize_t);
int bozo_auth_check_special_files(bozo_httpreq_t *, const char *);
void bozo_auth_check_401(bozo_httpreq_t *, int);
void bozo_auth_cgi_setenv(bozo_httpreq_t *, char ***);
int bozo_auth_cgi_count(bozo_httpreq_t *);
#else
#define bozo_auth_init(x) do { /* nothing */ } while (0)
#define bozo_auth_check(x, y) 0
#define bozo_auth_cleanup(x) do { /* nothing */ } while (0)
#define bozo_auth_check_headers(y, z, a, b) 0
#define bozo_auth_check_special_files(x, y) 0
#define bozo_auth_check_401(x, y) do { /* nothing */ } while (0)
#define bozo_auth_cgi_setenv(x, y) do { /* nothing */ } while (0)
#define bozo_auth_cgi_count(x) 0
#endif /* DO_HTPASSWD */
/* cgi-bozo.c */
#ifdef NO_CGIBIN_SUPPORT
#define bozo_process_cgi(h) 0
#else
void bozo_cgi_setbin(bozohttpd_t *, const char *);
void bozo_setenv(bozohttpd_t *, const char *, const char *, char **);
int bozo_process_cgi(bozo_httpreq_t *);
void bozo_add_content_map_cgi(bozohttpd_t *, const char *, const char *);
#endif /* NO_CGIBIN_SUPPORT */
/* lua-bozo.c */
#ifdef NO_LUA_SUPPORT
#define bozo_process_lua(h) 0
#else
void bozo_add_lua_map(bozohttpd_t *, const char *, const char *);
int bozo_process_lua(bozo_httpreq_t *);
#endif /* NO_LUA_SUPPORT */
/* daemon-bozo.c */
#ifdef NO_DAEMON_MODE
#define bozo_daemon_init(x) do { /* nothing */ } while (0)
#define bozo_daemon_fork(x) 0
#define bozo_daemon_closefds(x) do { /* nothing */ } while (0)
#else
void bozo_daemon_init(bozohttpd_t *);
int bozo_daemon_fork(bozohttpd_t *);
void bozo_daemon_closefds(bozohttpd_t *);
#endif /* NO_DAEMON_MODE */
/* tilde-luzah-bozo.c */
#ifdef NO_USER_SUPPORT
#define bozo_user_transform(a, c) 0
#else
int bozo_user_transform(bozo_httpreq_t *, int *);
#endif /* NO_USER_SUPPORT */
/* dir-index-bozo.c */
#ifdef NO_DIRINDEX_SUPPORT
#define bozo_dir_index(a, b, c) 0
#else
int bozo_dir_index(bozo_httpreq_t *, const char *, int);
#endif /* NO_DIRINDEX_SUPPORT */
/* content-bozo.c */
const char *bozo_content_type(bozo_httpreq_t *, const char *);
const char *bozo_content_encoding(bozo_httpreq_t *, const char *);
bozo_content_map_t *bozo_match_content_map(bozohttpd_t *, const char *, int);
bozo_content_map_t *bozo_get_content_map(bozohttpd_t *, const char *);
#ifndef NO_DYNAMIC_CONTENT
void bozo_add_content_map_mime(bozohttpd_t *, const char *, const char *, const char *, const char *);
#endif
/* I/O */
int bozo_printf(bozohttpd_t *, const char *, ...) BOZO_PRINTFLIKE(2, 3);;
ssize_t bozo_read(bozohttpd_t *, int, void *, size_t);
ssize_t bozo_write(bozohttpd_t *, int, const void *, size_t);
int bozo_flush(bozohttpd_t *, FILE *);
/* misc */
int bozo_init_httpd(bozohttpd_t *);
int bozo_init_prefs(bozoprefs_t *);
int bozo_set_defaults(bozohttpd_t *, bozoprefs_t *);
int bozo_setup(bozohttpd_t *, bozoprefs_t *, const char *, const char *);
bozo_httpreq_t *bozo_read_request(bozohttpd_t *);
void bozo_process_request(bozo_httpreq_t *);
void bozo_clean_request(bozo_httpreq_t *);
/* variables */
int bozo_set_pref(bozoprefs_t *, const char *, const char *);
char *bozo_get_pref(bozoprefs_t *, const char *);
#endif /* BOZOHTTOPD_H_ */

523
libexec/httpd/cgi-bozo.c Normal file
View File

@ -0,0 +1,523 @@
/* $NetBSD: cgi-bozo.c,v 1.27 2015/05/02 11:35:48 mrg Exp $ */
/* $eterna: cgi-bozo.c,v 1.40 2011/11/18 09:21:15 mrg Exp $ */
/*
* Copyright (c) 1997-2015 Matthew R. Green
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
/* this code implements CGI/1.2 for bozohttpd */
#ifndef NO_CGIBIN_SUPPORT
#include <sys/param.h>
#include <sys/socket.h>
#include <ctype.h>
#include <errno.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <netinet/in.h>
#include "bozohttpd.h"
#define CGIBIN_PREFIX "cgi-bin/"
#define CGIBIN_PREFIX_LEN (sizeof(CGIBIN_PREFIX)-1)
#ifndef USE_ARG
#define USE_ARG(x) /*LINTED*/(void)&(x)
#endif
/*
* given the file name, return a CGI interpreter
*/
static const char *
content_cgihandler(bozohttpd_t *httpd, bozo_httpreq_t *request,
const char *file)
{
bozo_content_map_t *map;
USE_ARG(request);
debug((httpd, DEBUG_FAT, "content_cgihandler: trying file %s", file));
map = bozo_match_content_map(httpd, file, 0);
if (map)
return map->cgihandler;
return NULL;
}
static int
parse_header(bozohttpd_t *httpd, const char *str, ssize_t len, char **hdr_str,
char **hdr_val)
{
char *name, *value;
/* if the string passed is zero-length bail out */
if (*str == '\0')
return -1;
value = bozostrdup(httpd, str);
/* locate the ':' separator in the header/value */
name = bozostrnsep(&value, ":", &len);
if (NULL == name || -1 == len) {
free(name);
return -1;
}
/* skip leading space/tab */
while (*value == ' ' || *value == '\t')
len--, value++;
*hdr_str = name;
*hdr_val = value;
return 0;
}
/*
* handle parsing a CGI header output, transposing a Status: header
* into the HTTP reply (ie, instead of "200 OK").
*/
static void
finish_cgi_output(bozohttpd_t *httpd, bozo_httpreq_t *request, int in, int nph)
{
char buf[BOZO_WRSZ];
char *str;
ssize_t len;
ssize_t rbytes;
SIMPLEQ_HEAD(, bozoheaders) headers;
bozoheaders_t *hdr, *nhdr;
int write_header, nheaders = 0;
/* much of this code is like bozo_read_request()'s header loop. */
SIMPLEQ_INIT(&headers);
write_header = nph == 0;
/* was read(2) here - XXX - agc */
while (nph == 0 &&
(str = bozodgetln(httpd, in, &len, bozo_read)) != NULL) {
char *hdr_name, *hdr_value;
if (parse_header(httpd, str, len, &hdr_name, &hdr_value))
break;
/*
* The CGI 1.{1,2} spec both say that if the cgi program
* returns a `Status:' header field then the server MUST
* return it in the response. If the cgi program does
* not return any `Status:' header then the server should
* respond with 200 OK.
* XXX The CGI 1.1 and 1.2 specification differ slightly on
* this in that v1.2 says that the script MUST NOT return a
* `Status:' header if it is returning a `Location:' header.
* For compatibility we are going with the CGI 1.1 behavior.
*/
if (strcasecmp(hdr_name, "status") == 0) {
debug((httpd, DEBUG_OBESE,
"bozo_process_cgi: writing HTTP header "
"from status %s ..", hdr_value));
bozo_printf(httpd, "%s %s\r\n", request->hr_proto,
hdr_value);
bozo_flush(httpd, stdout);
write_header = 0;
free(hdr_name);
break;
}
hdr = bozomalloc(httpd, sizeof *hdr);
hdr->h_header = hdr_name;
hdr->h_value = hdr_value;
SIMPLEQ_INSERT_TAIL(&headers, hdr, h_next);
nheaders++;
}
if (write_header) {
debug((httpd, DEBUG_OBESE,
"bozo_process_cgi: writing HTTP header .."));
bozo_printf(httpd,
"%s 200 OK\r\n", request->hr_proto);
bozo_flush(httpd, stdout);
}
if (nheaders) {
debug((httpd, DEBUG_OBESE,
"bozo_process_cgi: writing delayed HTTP headers .."));
SIMPLEQ_FOREACH_SAFE(hdr, &headers, h_next, nhdr) {
bozo_printf(httpd, "%s: %s\r\n", hdr->h_header,
hdr->h_value);
free(hdr->h_header);
free(hdr);
}
bozo_printf(httpd, "\r\n");
bozo_flush(httpd, stdout);
}
/* XXX we should have some goo that times us out
*/
while ((rbytes = read(in, buf, sizeof buf)) > 0) {
ssize_t wbytes;
char *bp = buf;
while (rbytes) {
wbytes = bozo_write(httpd, STDOUT_FILENO, buf,
(size_t)rbytes);
if (wbytes > 0) {
rbytes -= wbytes;
bp += wbytes;
} else
bozo_err(httpd, 1,
"cgi output write failed: %s",
strerror(errno));
}
}
}
static void
append_index_html(bozohttpd_t *httpd, char **url)
{
*url = bozorealloc(httpd, *url,
strlen(*url) + strlen(httpd->index_html) + 1);
strcat(*url, httpd->index_html);
debug((httpd, DEBUG_NORMAL,
"append_index_html: url adjusted to `%s'", *url));
}
void
bozo_cgi_setbin(bozohttpd_t *httpd, const char *path)
{
httpd->cgibin = strdup(path);
debug((httpd, DEBUG_OBESE, "cgibin (cgi-bin directory) is %s",
httpd->cgibin));
}
/* help build up the environ pointer */
void
bozo_setenv(bozohttpd_t *httpd, const char *env, const char *val,
char **envp)
{
char *s1 = bozomalloc(httpd, strlen(env) + strlen(val) + 2);
strcpy(s1, env);
strcat(s1, "=");
strcat(s1, val);
debug((httpd, DEBUG_OBESE, "bozo_setenv: %s", s1));
*envp = s1;
}
/*
* Checks if the request has asked for a cgi-bin. Should only be called if
* cgibin is set. If it starts CGIBIN_PREFIX or has a ncontent handler,
* process the cgi, otherwise just return. Returns 0 if it did not handle
* the request.
*/
int
bozo_process_cgi(bozo_httpreq_t *request)
{
bozohttpd_t *httpd = request->hr_httpd;
char buf[BOZO_WRSZ];
char date[40];
bozoheaders_t *headp;
const char *type, *clen, *info, *cgihandler;
char *query, *s, *t, *path, *env, *file, *url;
char command[MAXPATHLEN];
char **envp, **curenvp, *argv[4];
char *uri;
size_t len;
ssize_t rbytes;
pid_t pid;
int envpsize, ix, nph;
int sv[2];
if (!httpd->cgibin && !httpd->process_cgi)
return 0;
if (request->hr_oldfile && strcmp(request->hr_oldfile, "/") != 0)
uri = request->hr_oldfile;
else
uri = request->hr_file;
if (uri[0] == '/')
file = bozostrdup(httpd, uri);
else
asprintf(&file, "/%s", uri);
if (file == NULL)
return 0;
if (request->hr_query && strlen(request->hr_query))
query = bozostrdup(httpd, request->hr_query);
else
query = NULL;
asprintf(&url, "%s%s%s", file, query ? "?" : "", query ? query : "");
if (url == NULL)
goto out;
debug((httpd, DEBUG_NORMAL, "bozo_process_cgi: url `%s'", url));
path = NULL;
envp = NULL;
cgihandler = NULL;
info = NULL;
len = strlen(url);
if (bozo_auth_check(request, url + 1))
goto out;
if (!httpd->cgibin ||
strncmp(url + 1, CGIBIN_PREFIX, CGIBIN_PREFIX_LEN) != 0) {
cgihandler = content_cgihandler(httpd, request, file + 1);
if (cgihandler == NULL) {
debug((httpd, DEBUG_FAT,
"bozo_process_cgi: no handler, returning"));
goto out;
}
if (len == 0 || file[len - 1] == '/')
append_index_html(httpd, &file);
debug((httpd, DEBUG_NORMAL, "bozo_process_cgi: cgihandler `%s'",
cgihandler));
} else if (len - 1 == CGIBIN_PREFIX_LEN) /* url is "/cgi-bin/" */
append_index_html(httpd, &file);
ix = 0;
if (cgihandler) {
snprintf(command, sizeof(command), "%s", file + 1);
path = bozostrdup(httpd, cgihandler);
argv[ix++] = path;
/* argv[] = [ path, command, query, NULL ] */
} else {
snprintf(command, sizeof(command), "%s",
file + CGIBIN_PREFIX_LEN + 1);
if ((s = strchr(command, '/')) != NULL) {
info = bozostrdup(httpd, s);
*s = '\0';
}
path = bozomalloc(httpd,
strlen(httpd->cgibin) + 1 + strlen(command) + 1);
strcpy(path, httpd->cgibin);
strcat(path, "/");
strcat(path, command);
/* argv[] = [ command, query, NULL ] */
}
argv[ix++] = command;
argv[ix++] = query;
argv[ix++] = NULL;
nph = strncmp(command, "nph-", 4) == 0;
type = request->hr_content_type;
clen = request->hr_content_length;
envpsize = 13 + request->hr_nheaders +
(info && *info ? 1 : 0) +
(query && *query ? 1 : 0) +
(type && *type ? 1 : 0) +
(clen && *clen ? 1 : 0) +
(request->hr_remotehost && *request->hr_remotehost ? 1 : 0) +
(request->hr_remoteaddr && *request->hr_remoteaddr ? 1 : 0) +
bozo_auth_cgi_count(request) +
(request->hr_serverport && *request->hr_serverport ? 1 : 0);
debug((httpd, DEBUG_FAT,
"bozo_process_cgi: path `%s', cmd `%s', info `%s', "
"query `%s', nph `%d', envpsize `%d'",
path, command, strornull(info),
strornull(query), nph, envpsize));
envp = bozomalloc(httpd, sizeof(*envp) * envpsize);
for (ix = 0; ix < envpsize; ix++)
envp[ix] = NULL;
curenvp = envp;
SIMPLEQ_FOREACH(headp, &request->hr_headers, h_next) {
const char *s2;
env = bozomalloc(httpd, 6 + strlen(headp->h_header) + 1 +
strlen(headp->h_value));
t = env;
strcpy(t, "HTTP_");
t += strlen(t);
for (s2 = headp->h_header; *s2; t++, s2++)
if (islower((u_int)*s2))
*t = toupper((u_int)*s2);
else if (*s2 == '-')
*t = '_';
else
*t = *s2;
*t = '\0';
debug((httpd, DEBUG_OBESE, "setting header %s as %s = %s",
headp->h_header, env, headp->h_value));
bozo_setenv(httpd, env, headp->h_value, curenvp++);
free(env);
}
#ifndef _PATH_DEFPATH
#define _PATH_DEFPATH "/usr/bin:/bin"
#endif
bozo_setenv(httpd, "PATH", _PATH_DEFPATH, curenvp++);
bozo_setenv(httpd, "IFS", " \t\n", curenvp++);
bozo_setenv(httpd, "SERVER_NAME", BOZOHOST(httpd,request), curenvp++);
bozo_setenv(httpd, "GATEWAY_INTERFACE", "CGI/1.1", curenvp++);
bozo_setenv(httpd, "SERVER_PROTOCOL", request->hr_proto, curenvp++);
bozo_setenv(httpd, "REQUEST_METHOD", request->hr_methodstr, curenvp++);
bozo_setenv(httpd, "SCRIPT_NAME", file, curenvp++);
bozo_setenv(httpd, "SCRIPT_FILENAME", file + 1, curenvp++);
bozo_setenv(httpd, "SERVER_SOFTWARE", httpd->server_software,
curenvp++);
bozo_setenv(httpd, "REQUEST_URI", uri, curenvp++);
bozo_setenv(httpd, "DATE_GMT", bozo_http_date(date, sizeof(date)),
curenvp++);
if (query && *query)
bozo_setenv(httpd, "QUERY_STRING", query, curenvp++);
if (info && *info)
bozo_setenv(httpd, "PATH_INFO", info, curenvp++);
if (type && *type)
bozo_setenv(httpd, "CONTENT_TYPE", type, curenvp++);
if (clen && *clen)
bozo_setenv(httpd, "CONTENT_LENGTH", clen, curenvp++);
if (request->hr_serverport && *request->hr_serverport)
bozo_setenv(httpd, "SERVER_PORT", request->hr_serverport,
curenvp++);
if (request->hr_remotehost && *request->hr_remotehost)
bozo_setenv(httpd, "REMOTE_HOST", request->hr_remotehost,
curenvp++);
if (request->hr_remoteaddr && *request->hr_remoteaddr)
bozo_setenv(httpd, "REMOTE_ADDR", request->hr_remoteaddr,
curenvp++);
/*
* XXX Apache does this when invoking content handlers, and PHP
* XXX 5.3 requires it as a "security" measure.
*/
if (cgihandler)
bozo_setenv(httpd, "REDIRECT_STATUS", "200", curenvp++);
bozo_auth_cgi_setenv(request, &curenvp);
free(file);
free(url);
debug((httpd, DEBUG_FAT, "bozo_process_cgi: going exec %s, %s %s %s",
path, argv[0], strornull(argv[1]), strornull(argv[2])));
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sv) == -1)
bozo_err(httpd, 1, "child socketpair failed: %s",
strerror(errno));
/*
* We create 2 procs: one to become the CGI, one read from
* the CGI and output to the network, and this parent will
* continue reading from the network and writing to the
* CGI procsss.
*/
switch (fork()) {
case -1: /* eep, failure */
bozo_err(httpd, 1, "child fork failed: %s", strerror(errno));
/*NOTREACHED*/
case 0:
close(sv[0]);
dup2(sv[1], STDIN_FILENO);
dup2(sv[1], STDOUT_FILENO);
close(2);
close(sv[1]);
closelog();
bozo_daemon_closefds(httpd);
if (-1 == execve(path, argv, envp))
bozo_err(httpd, 1, "child exec failed: %s: %s",
path, strerror(errno));
/* NOT REACHED */
bozo_err(httpd, 1, "child execve returned?!");
}
close(sv[1]);
/* parent: read from stdin (bozo_read()) write to sv[0] */
/* child: read from sv[0] (bozo_write()) write to stdout */
pid = fork();
if (pid == -1)
bozo_err(httpd, 1, "io child fork failed: %s", strerror(errno));
else if (pid == 0) {
/* child reader/writer */
close(STDIN_FILENO);
finish_cgi_output(httpd, request, sv[0], nph);
/* if we're done output, our parent is useless... */
kill(getppid(), SIGKILL);
debug((httpd, DEBUG_FAT, "done processing cgi output"));
_exit(0);
}
close(STDOUT_FILENO);
/* XXX we should have some goo that times us out
*/
while ((rbytes = bozo_read(httpd, STDIN_FILENO, buf, sizeof buf)) > 0) {
ssize_t wbytes;
char *bp = buf;
while (rbytes) {
wbytes = write(sv[0], buf, (size_t)rbytes);
if (wbytes > 0) {
rbytes -= wbytes;
bp += wbytes;
} else
bozo_err(httpd, 1, "write failed: %s",
strerror(errno));
}
}
debug((httpd, DEBUG_FAT, "done processing cgi input"));
exit(0);
out:
free(query);
free(file);
free(url);
return 0;
}
#ifndef NO_DYNAMIC_CONTENT
/* cgi maps are simple ".postfix /path/to/prog" */
void
bozo_add_content_map_cgi(bozohttpd_t *httpd, const char *arg, const char *cgihandler)
{
bozo_content_map_t *map;
debug((httpd, DEBUG_NORMAL, "bozo_add_content_map_cgi: name %s cgi %s",
arg, cgihandler));
httpd->process_cgi = 1;
map = bozo_get_content_map(httpd, arg);
map->name = arg;
map->type = map->encoding = map->encoding11 = NULL;
map->cgihandler = cgihandler;
}
#endif /* NO_DYNAMIC_CONTENT */
#endif /* NO_CGIBIN_SUPPORT */

View File

@ -0,0 +1,301 @@
/* $NetBSD: content-bozo.c,v 1.12 2015/05/02 11:35:48 mrg Exp $ */
/* $eterna: content-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $ */
/*
* Copyright (c) 1997-2015 Matthew R. Green
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
/* this code implements content-type handling for bozohttpd */
#include <sys/param.h>
#include <errno.h>
#include <string.h>
#include "bozohttpd.h"
/*
* this map and the functions below map between filenames and the
* content type and content encoding definitions. this should become
* a configuration file, perhaps like apache's mime.types (but that
* has less info per-entry).
*/
static bozo_content_map_t static_content_map[] = {
{ ".html", "text/html", "", "", NULL },
{ ".htm", "text/html", "", "", NULL },
{ ".gif", "image/gif", "", "", NULL },
{ ".jpeg", "image/jpeg", "", "", NULL },
{ ".jpg", "image/jpeg", "", "", NULL },
{ ".jpe", "image/jpeg", "", "", NULL },
{ ".png", "image/png", "", "", NULL },
{ ".mp3", "audio/mpeg", "", "", NULL },
{ ".css", "text/css", "", "", NULL },
{ ".txt", "text/plain", "", "", NULL },
{ ".swf", "application/x-shockwave-flash","", "", NULL },
{ ".dcr", "application/x-director", "", "", NULL },
{ ".pac", "application/x-ns-proxy-autoconfig", "", "", NULL },
{ ".pa", "application/x-ns-proxy-autoconfig", "", "", NULL },
{ ".tar", "multipart/x-tar", "", "", NULL },
{ ".gtar", "multipart/x-gtar", "", "", NULL },
{ ".tar.Z", "multipart/x-tar", "x-compress", "compress", NULL },
{ ".tar.gz", "multipart/x-tar", "x-gzip", "gzip", NULL },
{ ".taz", "multipart/x-tar", "x-gzip", "gzip", NULL },
{ ".tgz", "multipart/x-tar", "x-gzip", "gzip", NULL },
{ ".tar.z", "multipart/x-tar", "x-pack", "x-pack", NULL },
{ ".Z", "application/x-compress", "x-compress", "compress", NULL },
{ ".gz", "application/x-gzip", "x-gzip", "gzip", NULL },
{ ".z", "unknown", "x-pack", "x-pack", NULL },
{ ".bz2", "application/x-bzip2", "x-bzip2", "x-bzip2", NULL },
{ ".ogg", "application/x-ogg", "", "", NULL },
{ ".mkv", "video/x-matroska", "", "", NULL },
{ ".xbel", "text/xml", "", "", NULL },
{ ".xml", "text/xml", "", "", NULL },
{ ".xsl", "text/xml", "", "", NULL },
{ ".hqx", "application/mac-binhex40", "", "", NULL },
{ ".cpt", "application/mac-compactpro", "", "", NULL },
{ ".doc", "application/msword", "", "", NULL },
{ ".bin", "application/octet-stream", "", "", NULL },
{ ".dms", "application/octet-stream", "", "", NULL },
{ ".lha", "application/octet-stream", "", "", NULL },
{ ".lzh", "application/octet-stream", "", "", NULL },
{ ".exe", "application/octet-stream", "", "", NULL },
{ ".class", "application/octet-stream", "", "", NULL },
{ ".oda", "application/oda", "", "", NULL },
{ ".pdf", "application/pdf", "", "", NULL },
{ ".ai", "application/postscript", "", "", NULL },
{ ".eps", "application/postscript", "", "", NULL },
{ ".ps", "application/postscript", "", "", NULL },
{ ".ppt", "application/powerpoint", "", "", NULL },
{ ".rtf", "application/rtf", "", "", NULL },
{ ".bcpio", "application/x-bcpio", "", "", NULL },
{ ".torrent", "application/x-bittorrent", "", "", NULL },
{ ".vcd", "application/x-cdlink", "", "", NULL },
{ ".cpio", "application/x-cpio", "", "", NULL },
{ ".csh", "application/x-csh", "", "", NULL },
{ ".dir", "application/x-director", "", "", NULL },
{ ".dxr", "application/x-director", "", "", NULL },
{ ".dvi", "application/x-dvi", "", "", NULL },
{ ".hdf", "application/x-hdf", "", "", NULL },
{ ".cgi", "application/x-httpd-cgi", "", "", NULL },
{ ".skp", "application/x-koan", "", "", NULL },
{ ".skd", "application/x-koan", "", "", NULL },
{ ".skt", "application/x-koan", "", "", NULL },
{ ".skm", "application/x-koan", "", "", NULL },
{ ".latex", "application/x-latex", "", "", NULL },
{ ".mif", "application/x-mif", "", "", NULL },
{ ".nc", "application/x-netcdf", "", "", NULL },
{ ".cdf", "application/x-netcdf", "", "", NULL },
{ ".patch", "application/x-patch", "", "", NULL },
{ ".sh", "application/x-sh", "", "", NULL },
{ ".shar", "application/x-shar", "", "", NULL },
{ ".sit", "application/x-stuffit", "", "", NULL },
{ ".sv4cpio", "application/x-sv4cpio", "", "", NULL },
{ ".sv4crc", "application/x-sv4crc", "", "", NULL },
{ ".tar", "application/x-tar", "", "", NULL },
{ ".tcl", "application/x-tcl", "", "", NULL },
{ ".tex", "application/x-tex", "", "", NULL },
{ ".texinfo", "application/x-texinfo", "", "", NULL },
{ ".texi", "application/x-texinfo", "", "", NULL },
{ ".t", "application/x-troff", "", "", NULL },
{ ".tr", "application/x-troff", "", "", NULL },
{ ".roff", "application/x-troff", "", "", NULL },
{ ".man", "application/x-troff-man", "", "", NULL },
{ ".me", "application/x-troff-me", "", "", NULL },
{ ".ms", "application/x-troff-ms", "", "", NULL },
{ ".ustar", "application/x-ustar", "", "", NULL },
{ ".src", "application/x-wais-source", "", "", NULL },
{ ".zip", "application/zip", "", "", NULL },
{ ".au", "audio/basic", "", "", NULL },
{ ".snd", "audio/basic", "", "", NULL },
{ ".mpga", "audio/mpeg", "", "", NULL },
{ ".mp2", "audio/mpeg", "", "", NULL },
{ ".aif", "audio/x-aiff", "", "", NULL },
{ ".aiff", "audio/x-aiff", "", "", NULL },
{ ".aifc", "audio/x-aiff", "", "", NULL },
{ ".ram", "audio/x-pn-realaudio", "", "", NULL },
{ ".rpm", "audio/x-pn-realaudio-plugin", "", "", NULL },
{ ".ra", "audio/x-realaudio", "", "", NULL },
{ ".wav", "audio/x-wav", "", "", NULL },
{ ".pdb", "chemical/x-pdb", "", "", NULL },
{ ".xyz", "chemical/x-pdb", "", "", NULL },
{ ".ief", "image/ief", "", "", NULL },
{ ".tiff", "image/tiff", "", "", NULL },
{ ".tif", "image/tiff", "", "", NULL },
{ ".ras", "image/x-cmu-raster", "", "", NULL },
{ ".pnm", "image/x-portable-anymap", "", "", NULL },
{ ".pbm", "image/x-portable-bitmap", "", "", NULL },
{ ".pgm", "image/x-portable-graymap", "", "", NULL },
{ ".ppm", "image/x-portable-pixmap", "", "", NULL },
{ ".rgb", "image/x-rgb", "", "", NULL },
{ ".xbm", "image/x-xbitmap", "", "", NULL },
{ ".xpm", "image/x-xpixmap", "", "", NULL },
{ ".xwd", "image/x-xwindowdump", "", "", NULL },
{ ".rtx", "text/richtext", "", "", NULL },
{ ".tsv", "text/tab-separated-values", "", "", NULL },
{ ".etx", "text/x-setext", "", "", NULL },
{ ".sgml", "text/x-sgml", "", "", NULL },
{ ".sgm", "text/x-sgml", "", "", NULL },
{ ".mpeg", "video/mpeg", "", "", NULL },
{ ".mpg", "video/mpeg", "", "", NULL },
{ ".mpe", "video/mpeg", "", "", NULL },
{ ".ts", "video/mpeg", "", "", NULL },
{ ".vob", "video/mpeg", "", "", NULL },
{ ".mp4", "video/mp4", "", "", NULL },
{ ".qt", "video/quicktime", "", "", NULL },
{ ".mov", "video/quicktime", "", "", NULL },
{ ".avi", "video/x-msvideo", "", "", NULL },
{ ".movie", "video/x-sgi-movie", "", "", NULL },
{ ".ice", "x-conference/x-cooltalk", "", "", NULL },
{ ".wrl", "x-world/x-vrml", "", "", NULL },
{ ".vrml", "x-world/x-vrml", "", "", NULL },
{ ".svg", "image/svg+xml", "", "", NULL },
{ NULL, NULL, NULL, NULL, NULL }
};
static bozo_content_map_t *
search_map(bozo_content_map_t *map, const char *name, size_t len)
{
for ( ; map && map->name; map++) {
const size_t namelen = strlen(map->name);
if (namelen < len &&
strcasecmp(map->name, name + (len - namelen)) == 0)
return map;
}
return NULL;
}
/* match a suffix on a file - dynamiconly means no static content search */
bozo_content_map_t *
bozo_match_content_map(bozohttpd_t *httpd, const char *name,
const int dynamiconly)
{
bozo_content_map_t *map;
size_t len;
len = strlen(name);
if ((map = search_map(httpd->dynamic_content_map, name, len)) != NULL) {
return map;
}
if (!dynamiconly) {
if ((map = search_map(static_content_map, name, len)) != NULL) {
return map;
}
}
return NULL;
}
/*
* given the file name, return a valid Content-Type: value.
*/
/* ARGSUSED */
const char *
bozo_content_type(bozo_httpreq_t *request, const char *file)
{
bozohttpd_t *httpd = request->hr_httpd;
bozo_content_map_t *map;
map = bozo_match_content_map(httpd, file, 0);
if (map)
return map->type;
return httpd->consts.text_plain;
}
/*
* given the file name, return a valid Content-Encoding: value.
*/
const char *
bozo_content_encoding(bozo_httpreq_t *request, const char *file)
{
bozohttpd_t *httpd = request->hr_httpd;
bozo_content_map_t *map;
map = bozo_match_content_map(httpd, file, 0);
if (map)
return (request->hr_proto == httpd->consts.http_11) ?
map->encoding11 : map->encoding;
return NULL;
}
#ifndef NO_DYNAMIC_CONTENT
bozo_content_map_t *
bozo_get_content_map(bozohttpd_t *httpd, const char *name)
{
bozo_content_map_t *map;
if ((map = bozo_match_content_map(httpd, name, 1)) != NULL)
return map;
httpd->dynamic_content_map_size++;
httpd->dynamic_content_map = bozorealloc(httpd,
httpd->dynamic_content_map,
(httpd->dynamic_content_map_size + 1) * sizeof *map);
if (httpd->dynamic_content_map == NULL)
bozo_err(httpd, 1, "out of memory allocating content map");
map = &httpd->dynamic_content_map[httpd->dynamic_content_map_size];
map->name = map->type = map->encoding = map->encoding11 =
map->cgihandler = NULL;
map--;
return map;
}
/*
* mime content maps look like:
* ".name type encoding encoding11"
* where any of type, encoding or encoding11 a dash "-" means "".
* eg the .gtar, .tar.Z from above could be written like:
* ".gtar multipart/x-gtar - -"
* ".tar.Z multipart/x-tar x-compress compress"
* or
* ".gtar multipart/x-gtar"
* ".tar.Z multipart/x-tar x-compress compress"
* NOTE: we destroy 'arg'
*/
void
bozo_add_content_map_mime(bozohttpd_t *httpd, const char *cmap0,
const char *cmap1, const char *cmap2, const char *cmap3)
{
bozo_content_map_t *map;
debug((httpd, DEBUG_FAT,
"add_content_map: name %s type %s enc %s enc11 %s ",
cmap0, cmap1, cmap2, cmap3));
map = bozo_get_content_map(httpd, cmap0);
#define CHECKMAP(s) (!s || ((s)[0] == '-' && (s)[1] == '\0') ? "" : (s))
map->name = CHECKMAP(cmap0);
map->type = CHECKMAP(cmap1);
map->encoding = CHECKMAP(cmap2);
map->encoding11 = CHECKMAP(cmap3);
#undef CHECKMAP
map->cgihandler = NULL;
}
#endif /* NO_DYNAMIC_CONTENT */

339
libexec/httpd/daemon-bozo.c Normal file
View File

@ -0,0 +1,339 @@
/* $NetBSD: daemon-bozo.c,v 1.16 2014/01/02 08:21:38 mrg Exp $ */
/* $eterna: daemon-bozo.c,v 1.24 2011/11/18 09:21:15 mrg Exp $ */
/*
* Copyright (c) 1997-2014 Matthew R. Green
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
/* this code implements daemon mode for bozohttpd */
#ifndef NO_DAEMON_MODE
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bozohttpd.h"
static void sigchild(int); /* SIGCHLD handler */
#ifndef POLLRDNORM
#define POLLRDNORM 0
#endif
#ifndef POLLRDBAND
#define POLLRDBAND 0
#endif
#ifndef INFTIM
#define INFTIM -1
#endif
static const char* pidfile_path = NULL;
static pid_t pidfile_pid = 0;
/* ARGSUSED */
static void
sigchild(int signo)
{
while (waitpid(-1, NULL, WNOHANG) > 0) {
}
}
/* Signal handler to exit in a controlled manner. This ensures that
* any atexit(3) handlers are properly executed. */
/* ARGSUSED */
BOZO_DEAD static void
controlled_exit(int signo)
{
exit(EXIT_SUCCESS);
}
static void
remove_pidfile(void)
{
if (pidfile_path != NULL && pidfile_pid == getpid()) {
(void)unlink(pidfile_path);
pidfile_path = NULL;
}
}
static void
create_pidfile(bozohttpd_t *httpd)
{
FILE *file;
assert(pidfile_path == NULL);
if (httpd->pidfile == NULL)
return;
if (atexit(remove_pidfile) == -1)
bozo_err(httpd, 1, "Failed to install pidfile handler");
if ((file = fopen(httpd->pidfile, "w")) == NULL)
bozo_err(httpd, 1, "Failed to create pidfile '%s'",
httpd->pidfile);
(void)fprintf(file, "%d\n", getpid());
(void)fclose(file);
pidfile_path = httpd->pidfile;
pidfile_pid = getpid();
debug((httpd, DEBUG_FAT, "Created pid file '%s' for pid %d",
pidfile_path, pidfile_pid));
}
void
bozo_daemon_init(bozohttpd_t *httpd)
{
struct addrinfo h, *r, *r0;
const char *portnum;
int e, i, on = 1;
if (!httpd->background)
return;
portnum = (httpd->bindport) ? httpd->bindport : "http";
memset(&h, 0, sizeof(h));
h.ai_family = PF_UNSPEC;
h.ai_socktype = SOCK_STREAM;
h.ai_flags = AI_PASSIVE;
e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0);
if (e)
bozo_err(httpd, 1, "getaddrinfo([%s]:%s): %s",
httpd->bindaddress ? httpd->bindaddress : "*",
portnum, gai_strerror(e));
for (r = r0; r != NULL; r = r->ai_next)
httpd->nsock++;
httpd->sock = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->sock));
httpd->fds = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->fds));
for (i = 0, r = r0; r != NULL; r = r->ai_next) {
httpd->sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
if (httpd->sock[i] == -1)
continue;
if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)) == -1)
bozo_warn(httpd, "setsockopt SO_REUSEADDR: %s",
strerror(errno));
if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1)
continue;
if (listen(httpd->sock[i], SOMAXCONN) == -1)
continue;
httpd->fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
POLLRDBAND | POLLERR;
httpd->fds[i].fd = httpd->sock[i];
i++;
}
if (i == 0)
bozo_err(httpd, 1, "could not find any addresses to bind");
httpd->nsock = i;
freeaddrinfo(r0);
if (httpd->foreground == 0)
daemon(1, 0);
create_pidfile(httpd);
bozo_warn(httpd, "started in daemon mode as `%s' port `%s' root `%s'",
httpd->virthostname, portnum, httpd->slashdir);
signal(SIGHUP, controlled_exit);
signal(SIGINT, controlled_exit);
signal(SIGTERM, controlled_exit);
signal(SIGCHLD, sigchild);
}
void
bozo_daemon_closefds(bozohttpd_t *httpd)
{
int i;
for (i = 0; i < httpd->nsock; i++)
close(httpd->sock[i]);
}
static void
daemon_runchild(bozohttpd_t *httpd, int fd)
{
httpd->request_times++;
/* setup stdin/stdout/stderr */
dup2(fd, 0);
dup2(fd, 1);
/*dup2(fd, 2);*/
close(fd);
}
static int
daemon_poll_err(bozohttpd_t *httpd, int fd, int idx)
{
if ((httpd->fds[idx].revents & (POLLNVAL|POLLERR|POLLHUP)) == 0)
return 0;
bozo_warn(httpd, "poll on fd %d pid %d revents %d: %s",
httpd->fds[idx].fd, getpid(), httpd->fds[idx].revents,
strerror(errno));
bozo_warn(httpd, "nsock = %d", httpd->nsock);
close(httpd->sock[idx]);
httpd->nsock--;
bozo_warn(httpd, "nsock now = %d", httpd->nsock);
/* no sockets left */
if (httpd->nsock == 0)
exit(0);
/* last socket closed is the easy case */
if (httpd->nsock != idx) {
memmove(&httpd->fds[idx], &httpd->fds[idx+1],
(httpd->nsock - idx) * sizeof(*httpd->fds));
memmove(&httpd->sock[idx], &httpd->sock[idx+1],
(httpd->nsock - idx) * sizeof(*httpd->sock));
}
return 1;
}
/*
* the parent never returns from this function, only children that
* are ready to run... XXXMRG - still true in fork-lesser bozo?
*/
int
bozo_daemon_fork(bozohttpd_t *httpd)
{
int i;
debug((httpd, DEBUG_FAT, "%s: pid %u request_times %d",
__func__, getpid(),
httpd->request_times));
/* if we've handled 5 files, exit and let someone else work */
if (httpd->request_times > 5 ||
(httpd->background == 2 && httpd->request_times > 0))
_exit(0);
#if 1
if (httpd->request_times > 0)
_exit(0);
#endif
while (httpd->background) {
struct sockaddr_storage ss;
socklen_t slen;
int fd;
if (httpd->nsock == 0)
exit(0);
/*
* wait for a connection, then fork() and return NULL in
* the parent, who will come back here waiting for another
* connection. read the request in in the child, and return
* it, for processing.
*/
again:
if (poll(httpd->fds, (unsigned)httpd->nsock, INFTIM) == -1) {
/* fail on programmer errors */
if (errno == EFAULT ||
errno == EINVAL)
bozo_err(httpd, 1, "poll: %s",
strerror(errno));
/* sleep on some temporary kernel failures */
if (errno == ENOMEM ||
errno == EAGAIN)
sleep(1);
goto again;
}
for (i = 0; i < httpd->nsock; i++) {
if (daemon_poll_err(httpd, fd, i))
break;
if (httpd->fds[i].revents == 0)
continue;
slen = sizeof(ss);
fd = accept(httpd->fds[i].fd,
(struct sockaddr *)(void *)&ss, &slen);
if (fd == -1) {
if (errno == EFAULT ||
errno == EINVAL)
bozo_err(httpd, 1, "accept: %s",
strerror(errno));
if (errno == ENOMEM ||
errno == EAGAIN)
sleep(1);
continue;
}
#if 0
/*
* This code doesn't work. It interacts very poorly
* with ~user translation and needs to be fixed.
*/
if (httpd->request_times > 0) {
daemon_runchild(httpd, fd);
return 0;
}
#endif
switch (fork()) {
case -1: /* eep, failure */
bozo_warn(httpd, "fork() failed, sleeping for "
"10 seconds: %s", strerror(errno));
close(fd);
sleep(10);
break;
case 0: /* child */
daemon_runchild(httpd, fd);
return 0;
default: /* parent */
close(fd);
break;
}
}
}
return 0;
}
#endif /* NO_DAEMON_MODE */

View File

@ -0,0 +1,9 @@
# $eterna: Makefile,v 1.1 2009/05/22 21:51:39 mrg Exp $
# build a debug bozohttpd
PROG= bozohttpd-debug
COPTS+= -DDEBUG -I$(.CURDIR)/..
.include "../Makefile"
.PATH: $(.CURDIR)/..

View File

@ -0,0 +1,212 @@
/* $NetBSD: dir-index-bozo.c,v 1.21 2015/08/27 17:12:18 mrg Exp $ */
/* $eterna: dir-index-bozo.c,v 1.20 2011/11/18 09:21:15 mrg Exp $ */
/*
* Copyright (c) 1997-2014 Matthew R. Green
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
/* this code implements directory index generation for bozohttpd */
#ifndef NO_DIRINDEX_SUPPORT
#include <sys/param.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include "bozohttpd.h"
static void
directory_hr(bozohttpd_t *httpd)
{
bozo_printf(httpd,
"<hr noshade align=\"left\" width=\"80%%\">\r\n\r\n");
}
/*
* output a directory index. return 1 if it actually did something..
*/
int
bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex)
{
bozohttpd_t *httpd = request->hr_httpd;
struct stat sb;
struct dirent **de, **deo;
struct tm *tm;
DIR *dp;
char buf[MAXPATHLEN];
char spacebuf[48];
char *file = NULL;
int l, k, j, i;
if (!isindex || !httpd->dir_indexing)
return 0;
if (strlen(dirpath) <= strlen(httpd->index_html))
dirpath = ".";
else {
file = bozostrdup(httpd, dirpath);
file[strlen(file) - strlen(httpd->index_html)] = '\0';
dirpath = file;
}
debug((httpd, DEBUG_FAT, "bozo_dir_index: dirpath ``%s''", dirpath));
if (stat(dirpath, &sb) < 0 ||
(dp = opendir(dirpath)) == NULL) {
if (errno == EPERM)
(void)bozo_http_error(httpd, 403, request,
"no permission to open directory");
else if (errno == ENOENT)
(void)bozo_http_error(httpd, 404, request, "no file");
else
(void)bozo_http_error(httpd, 500, request,
"open directory");
goto done;
/* NOTREACHED */
}
bozo_printf(httpd, "%s 200 OK\r\n", request->hr_proto);
if (request->hr_proto != httpd->consts.http_09) {
bozo_print_header(request, NULL, "text/html", "");
bozo_printf(httpd, "\r\n");
}
bozo_flush(httpd, stdout);
if (request->hr_method == HTTP_HEAD) {
closedir(dp);
goto done;
}
bozo_printf(httpd,
"<html><head><title>Index of %s</title></head>\r\n",
request->hr_file);
bozo_printf(httpd, "<body><h1>Index of %s</h1>\r\n",
request->hr_file);
bozo_printf(httpd, "<pre>\r\n");
#define NAMELEN 40
#define LMODLEN 19
bozo_printf(httpd, "Name "
"Last modified "
"Size\n");
bozo_printf(httpd, "</pre>");
directory_hr(httpd);
bozo_printf(httpd, "<pre>");
for (j = k = scandir(dirpath, &de, NULL, alphasort), deo = de;
j--; de++) {
int nostat = 0;
char *name = (*de)->d_name;
char *urlname, *htmlname;
if (strcmp(name, ".") == 0 ||
(strcmp(name, "..") != 0 &&
httpd->hide_dots && name[0] == '.'))
continue;
snprintf(buf, sizeof buf, "%s/%s", dirpath, name);
if (stat(buf, &sb))
nostat = 1;
l = 0;
urlname = bozo_escape_rfc3986(httpd, name);
htmlname = bozo_escape_html(httpd, name);
if (htmlname == NULL)
htmlname = name;
if (strcmp(name, "..") == 0) {
bozo_printf(httpd, "<a href=\"../\">");
l += bozo_printf(httpd, "Parent Directory");
} else if (S_ISDIR(sb.st_mode)) {
bozo_printf(httpd, "<a href=\"%s/\">", urlname);
l += bozo_printf(httpd, "%s/", htmlname);
} else if (strchr(name, ':') != NULL) {
/* RFC 3986 4.2 */
bozo_printf(httpd, "<a href=\"./%s\">", urlname);
l += bozo_printf(httpd, "%s", htmlname);
} else {
bozo_printf(httpd, "<a href=\"%s\">", urlname);
l += bozo_printf(httpd, "%s", htmlname);
}
if (htmlname != name)
free(htmlname);
bozo_printf(httpd, "</a>");
/* NAMELEN spaces */
/*LINTED*/
assert(/*CONSTCOND*/sizeof(spacebuf) > NAMELEN);
i = (l < NAMELEN) ? (NAMELEN - l) : 0;
i++;
memset(spacebuf, ' ', (size_t)i);
spacebuf[i] = '\0';
bozo_printf(httpd, "%s", spacebuf);
l += i;
if (nostat)
bozo_printf(httpd, "? ?");
else {
tm = gmtime(&sb.st_mtime);
strftime(buf, sizeof buf, "%d-%b-%Y %R", tm);
l += bozo_printf(httpd, "%s", buf);
/* LMODLEN spaces */
/*LINTED*/
assert(/*CONSTCOND*/sizeof(spacebuf) > LMODLEN);
i = (l < (LMODLEN+NAMELEN+1)) ?
((LMODLEN+NAMELEN+1) - l) : 0;
i++;
memset(spacebuf, ' ', (size_t)i);
spacebuf[i] = '\0';
bozo_printf(httpd, "%s", spacebuf);
bozo_printf(httpd, "%12llukB",
(unsigned long long)sb.st_size >> 10);
}
bozo_printf(httpd, "\r\n");
}
closedir(dp);
while (k--)
free(deo[k]);
free(deo);
bozo_printf(httpd, "</pre>");
directory_hr(httpd);
bozo_printf(httpd, "</body></html>\r\n\r\n");
bozo_flush(httpd, stdout);
done:
free(file);
return 1;
}
#endif /* NO_DIRINDEX_SUPPORT */

View File

@ -0,0 +1,37 @@
# $eterna: Makefile,v 1.1 2010/05/10 02:24:31 mrg Exp $
.PATH: $(.CURDIR)/..
# build bozohttpd library
LIB= bozohttpd
COPTS+= -I$(.CURDIR)/..
COPTS+= -DDO_HTPASSWD
CPPFLAGS+= -DDO_HTPASSWD
SRCS= bozohttpd.c ssl-bozo.c auth-bozo.c cgi-bozo.c daemon-bozo.c
SRCS+= tilde-luzah-bozo.c dir-index-bozo.c content-bozo.c
SRCS+= lua-bozo.c
LDADD= -lcrypt
DPADD= ${LIBCRYPT}
MAN= libbozohttpd.3
WARNS= 4
INCS= bozohttpd.h
INCSDIR= /usr/include
.include <bsd.own.mk>
.if ${MKCRYPTO} != "no"
LDADD+= -lssl -lcrypto
DPADD+= ${LIBSSL} ${LIBCRYPTO}
.else
COPTS+= -DNO_SSL_SUPPORT
.endif
.include <bsd.lib.mk>

View File

@ -0,0 +1,143 @@
.\" $NetBSD: libbozohttpd.3,v 1.3 2014/03/18 18:20:38 riastradh Exp $
.\"
.\" $eterna: libbozohttpd.3,v 1.2 2010/05/10 02:48:23 mrg Exp $
.\"
.\" Copyright (c) 2009 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This manual page is derived from software contributed to The
.\" NetBSD Foundation by Alistair Crooks (agc@NetBSD.org)
.\"
.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
.\"
.Dd November 5, 2009
.Dt LIBBOZOHTTPD 3
.Os
.Sh NAME
.Nm libbozohttpd
.Nd embedded web server library
.Sh LIBRARY
.Lb libbozohttpd
.Sh SYNOPSIS
.In bozohttpd.h
.Ft int
.Fo bozo_set_pref
.Fa "bozoprefs_t *prefs" "char *name" "char *value"
.Fc
.Ft char *
.Fo bozo_get_pref
.Fa "bozoprefs_t *prefs" "char *name"
.Fc
.Ft int
.Fo bozo_set_defaults
.Fa "bozohttpd_t *httpd" "bozoprefs_t *prefs"
.Fc
.Ft void
.Fo bozo_setup
.Fa "bozohttpd_t *httpd" "bozoprefs_t *prefs" "const char *vhost" "char *slash"
.Fc
.Ft bozo_httpreq_t *
.Fo bozo_read_request
.Fa "bozohttpd_t *httpd"
.Fc
.Ft void
.Fo bozo_process_request
.Fa "bozo_httpreq_t *"
.Fc
.Ft void
.Fo bozo_clean_request
.Fa "bozo_httpreq_t *"
.Fc
.Sh DESCRIPTION
.Nm
is a library interface to the
.Xr bozohttpd 8
web server.
The
.Nm
library can be used to embed a webserver
in your applications.
.Pp
Normal operation sees the
.Nm
process be initialised using the
.Fn bozo_set_defaults
function, which will set up the default port
and other internal settings, allocating
any necessary space as needed.
The
.Fn bozo_set_defaults
function returns 1 on sucess, 0 on failure.
.Pp
The
.Fn bozo_setup
function is used to specify the virtual host name
for the web server.
A NULL host name will mean that
.Nm
will use the local value for the host name,
as returned by
.Xr gethostname 3 .
This virtual hostname should be a fully qualified domain name.
The final argument to
.Fn bozo_setup
is the name of the directory to serve as the root
directory of the web server tree.
.Pp
Once the server has been set up, it serves
requests by using the
.Fn bozo_read_request
function, which returns a pointer to a request structure,
and
.Fn bozo_process_request ,
which deals with the request, and answers the client.
The request space is de-allocated
using the
.Fn bozo_clean_request
function.
.Pp
Preferences are set
using the function
.Fn bozo_set_pref
function
and queried using the two
.Fn bozo_get_pref
function.
This is the main interface for selecting options, and for
setting preferences.
.Sh SEE ALSO
.Xr gethostname 3 ,
.Xr ssl 3 ,
.Xr services 5 ,
.Xr httpd 8
.Sh HISTORY
The
.Nm
library first appeared in
.Nx 6.0 .
.Sh AUTHORS
.An Matthew R. Green Aq Mt mrg@eterna.com.au
.An Alistair Crooks Aq Mt agc@NetBSD.org
wrote this high-level interface.
.Pp
This manual page was written by
.An Alistair Crooks .

View File

@ -0,0 +1,2 @@
major=0
minor=0

452
libexec/httpd/lua-bozo.c Normal file
View File

@ -0,0 +1,452 @@
/* $NetBSD: lua-bozo.c,v 1.12 2015/07/04 22:39:23 christos Exp $ */
/*
* Copyright (c) 2013 Marc Balmer <marc@msys.ch>
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
/* this code implements dynamic content generation using Lua for bozohttpd */
#ifndef NO_LUA_SUPPORT
#include <sys/param.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bozohttpd.h"
/* Lua binding for bozohttp */
#if LUA_VERSION_NUM < 502
#define LUA_HTTPDLIBNAME "httpd"
#endif
#define FORM "application/x-www-form-urlencoded"
static int
lua_flush(lua_State *L)
{
bozohttpd_t *httpd;
lua_pushstring(L, "bozohttpd");
lua_gettable(L, LUA_REGISTRYINDEX);
httpd = lua_touserdata(L, -1);
lua_pop(L, 1);
bozo_flush(httpd, stdout);
return 0;
}
static int
lua_print(lua_State *L)
{
bozohttpd_t *httpd;
lua_pushstring(L, "bozohttpd");
lua_gettable(L, LUA_REGISTRYINDEX);
httpd = lua_touserdata(L, -1);
lua_pop(L, 1);
bozo_printf(httpd, "%s\r\n", lua_tostring(L, -1));
return 0;
}
static int
lua_read(lua_State *L)
{
bozohttpd_t *httpd;
int n, len;
char *data;
lua_pushstring(L, "bozohttpd");
lua_gettable(L, LUA_REGISTRYINDEX);
httpd = lua_touserdata(L, -1);
lua_pop(L, 1);
len = luaL_checkinteger(L, -1);
data = bozomalloc(httpd, len + 1);
n = bozo_read(httpd, STDIN_FILENO, data, len);
if (n >= 0) {
data[n] = '\0';
lua_pushstring(L, data);
} else
lua_pushnil(L);
free(data);
return 1;
}
static int
lua_register_handler(lua_State *L)
{
lua_state_map_t *map;
lua_handler_t *handler;
bozohttpd_t *httpd;
lua_pushstring(L, "lua_state_map");
lua_gettable(L, LUA_REGISTRYINDEX);
map = lua_touserdata(L, -1);
lua_pushstring(L, "bozohttpd");
lua_gettable(L, LUA_REGISTRYINDEX);
httpd = lua_touserdata(L, -1);
lua_pop(L, 2);
luaL_checkstring(L, 1);
luaL_checktype(L, 2, LUA_TFUNCTION);
handler = bozomalloc(httpd, sizeof(lua_handler_t));
handler->name = bozostrdup(httpd, lua_tostring(L, 1));
handler->ref = luaL_ref(L, LUA_REGISTRYINDEX);
SIMPLEQ_INSERT_TAIL(&map->handlers, handler, h_next);
httpd->process_lua = 1;
return 0;
}
static int
lua_write(lua_State *L)
{
bozohttpd_t *httpd;
const char *data;
lua_pushstring(L, "bozohttpd");
lua_gettable(L, LUA_REGISTRYINDEX);
httpd = lua_touserdata(L, -1);
lua_pop(L, 1);
data = luaL_checkstring(L, -1);
lua_pushinteger(L, bozo_write(httpd, STDIN_FILENO, data, strlen(data)));
return 1;
}
static int
luaopen_httpd(lua_State *L)
{
struct luaL_Reg functions[] = {
{ "flush", lua_flush },
{ "print", lua_print },
{ "read", lua_read },
{ "register_handler", lua_register_handler },
{ "write", lua_write },
{ NULL, NULL }
};
#if LUA_VERSION_NUM >= 502
luaL_newlib(L, functions);
#else
luaL_register(L, LUA_HTTPDLIBNAME, functions);
#endif
lua_pushstring(L, "httpd 1.0.0");
lua_setfield(L, -2, "_VERSION");
return 1;
}
#if LUA_VERSION_NUM < 502
static void
lua_openlib(lua_State *L, const char *name, lua_CFunction fn)
{
lua_pushcfunction(L, fn);
lua_pushstring(L, name);
lua_call(L, 1, 0);
}
#endif
/* bozohttpd integration */
void
bozo_add_lua_map(bozohttpd_t *httpd, const char *prefix, const char *script)
{
lua_state_map_t *map;
map = bozomalloc(httpd, sizeof(lua_state_map_t));
map->prefix = bozostrdup(httpd, prefix);
if (*script == '/')
map->script = bozostrdup(httpd, script);
else {
char cwd[MAXPATHLEN], *path;
getcwd(cwd, sizeof(cwd) - 1);
asprintf(&path, "%s/%s", cwd, script);
map->script = path;
}
map->L = luaL_newstate();
if (map->L == NULL)
bozo_err(httpd, 1, "can't create Lua state");
SIMPLEQ_INIT(&map->handlers);
#if LUA_VERSION_NUM >= 502
luaL_openlibs(map->L);
lua_getglobal(map->L, "package");
lua_getfield(map->L, -1, "preload");
lua_pushcfunction(map->L, luaopen_httpd);
lua_setfield(map->L, -2, "httpd");
lua_pop(map->L, 2);
#else
lua_openlib(map->L, "", luaopen_base);
lua_openlib(map->L, LUA_LOADLIBNAME, luaopen_package);
lua_openlib(map->L, LUA_TABLIBNAME, luaopen_table);
lua_openlib(map->L, LUA_STRLIBNAME, luaopen_string);
lua_openlib(map->L, LUA_MATHLIBNAME, luaopen_math);
lua_openlib(map->L, LUA_OSLIBNAME, luaopen_os);
lua_openlib(map->L, LUA_IOLIBNAME, luaopen_io);
lua_openlib(map->L, LUA_HTTPDLIBNAME, luaopen_httpd);
#endif
lua_pushstring(map->L, "lua_state_map");
lua_pushlightuserdata(map->L, map);
lua_settable(map->L, LUA_REGISTRYINDEX);
lua_pushstring(map->L, "bozohttpd");
lua_pushlightuserdata(map->L, httpd);
lua_settable(map->L, LUA_REGISTRYINDEX);
if (luaL_loadfile(map->L, script))
bozo_err(httpd, 1, "failed to load script %s: %s", script,
lua_tostring(map->L, -1));
if (lua_pcall(map->L, 0, 0, 0))
bozo_err(httpd, 1, "failed to execute script %s: %s", script,
lua_tostring(map->L, -1));
SIMPLEQ_INSERT_TAIL(&httpd->lua_states, map, s_next);
}
static void
lua_env(lua_State *L, const char *name, const char *value)
{
lua_pushstring(L, value);
lua_setfield(L, -2, name);
}
/* decode query string */
static void
lua_url_decode(lua_State *L, char *s)
{
char *v, *p, *val, *q;
char buf[3];
int c;
v = strchr(s, '=');
if (v == NULL)
return;
*v++ = '\0';
val = malloc(strlen(v) + 1);
if (val == NULL)
return;
for (p = v, q = val; *p; p++) {
switch (*p) {
case '%':
if (*(p + 1) == '\0' || *(p + 2) == '\0') {
free(val);
return;
}
buf[0] = *++p;
buf[1] = *++p;
buf[2] = '\0';
sscanf(buf, "%2x", &c);
*q++ = (char)c;
break;
case '+':
*q++ = ' ';
break;
default:
*q++ = *p;
}
}
*q = '\0';
lua_pushstring(L, val);
lua_setfield(L, -2, s);
free(val);
}
static void
lua_decode_query(lua_State *L, char *query)
{
char *s;
s = strtok(query, "&");
while (s) {
lua_url_decode(L, s);
s = strtok(NULL, "&");
}
}
int
bozo_process_lua(bozo_httpreq_t *request)
{
bozohttpd_t *httpd = request->hr_httpd;
lua_state_map_t *map;
lua_handler_t *hndlr;
int n, ret, length;
char date[40];
bozoheaders_t *headp;
char *s, *query, *uri, *file, *command, *info, *content;
const char *type, *clen;
char *prefix, *handler, *p;
int rv = 0;
if (!httpd->process_lua)
return 0;
info = NULL;
query = NULL;
prefix = NULL;
uri = request->hr_oldfile ? request->hr_oldfile : request->hr_file;
if (*uri == '/') {
file = bozostrdup(httpd, uri);
if (file == NULL)
goto out;
prefix = bozostrdup(httpd, &uri[1]);
} else {
if (asprintf(&file, "/%s", uri) < 0)
goto out;
prefix = bozostrdup(httpd, uri);
}
if (prefix == NULL)
goto out;
if (request->hr_query && request->hr_query[0])
query = bozostrdup(httpd, request->hr_query);
p = strchr(prefix, '/');
if (p == NULL)
goto out;
*p++ = '\0';
handler = p;
if (!*handler)
goto out;
p = strchr(handler, '/');
if (p != NULL)
*p++ = '\0';
command = file + 1;
if ((s = strchr(command, '/')) != NULL) {
info = bozostrdup(httpd, s);
*s = '\0';
}
type = request->hr_content_type;
clen = request->hr_content_length;
SIMPLEQ_FOREACH(map, &httpd->lua_states, s_next) {
if (strcmp(map->prefix, prefix))
continue;
SIMPLEQ_FOREACH(hndlr, &map->handlers, h_next) {
if (strcmp(hndlr->name, handler))
continue;
lua_rawgeti(map->L, LUA_REGISTRYINDEX, hndlr->ref);
/* Create the "environment" */
lua_newtable(map->L);
lua_env(map->L, "SERVER_NAME",
BOZOHOST(httpd, request));
lua_env(map->L, "GATEWAY_INTERFACE", "Luigi/1.0");
lua_env(map->L, "SERVER_PROTOCOL", request->hr_proto);
lua_env(map->L, "REQUEST_METHOD",
request->hr_methodstr);
lua_env(map->L, "SCRIPT_PREFIX", map->prefix);
lua_env(map->L, "SCRIPT_NAME", file);
lua_env(map->L, "HANDLER_NAME", hndlr->name);
lua_env(map->L, "SCRIPT_FILENAME", map->script);
lua_env(map->L, "SERVER_SOFTWARE",
httpd->server_software);
lua_env(map->L, "REQUEST_URI", uri);
lua_env(map->L, "DATE_GMT",
bozo_http_date(date, sizeof(date)));
if (query && *query)
lua_env(map->L, "QUERY_STRING", query);
if (info && *info)
lua_env(map->L, "PATH_INFO", info);
if (type && *type)
lua_env(map->L, "CONTENT_TYPE", type);
if (clen && *clen)
lua_env(map->L, "CONTENT_LENGTH", clen);
if (request->hr_serverport && *request->hr_serverport)
lua_env(map->L, "SERVER_PORT",
request->hr_serverport);
if (request->hr_remotehost && *request->hr_remotehost)
lua_env(map->L, "REMOTE_HOST",
request->hr_remotehost);
if (request->hr_remoteaddr && *request->hr_remoteaddr)
lua_env(map->L, "REMOTE_ADDR",
request->hr_remoteaddr);
/* Pass the headers in a separate table */
lua_newtable(map->L);
SIMPLEQ_FOREACH(headp, &request->hr_headers, h_next)
lua_env(map->L, headp->h_header,
headp->h_value);
/* Pass the query variables */
if ((query && *query) ||
(type && *type && !strcmp(type, FORM))) {
lua_newtable(map->L);
if (query && *query)
lua_decode_query(map->L, query);
if (type && *type && !strcmp(type, FORM)) {
if (clen && *clen && atol(clen) > 0) {
length = atol(clen);
content = bozomalloc(httpd,
length + 1);
n = bozo_read(httpd,
STDIN_FILENO, content,
length);
if (n >= 0) {
content[n] = '\0';
lua_decode_query(map->L,
content);
} else {
lua_pop(map->L, 1);
lua_pushnil(map->L);
}
free(content);
}
}
} else
lua_pushnil(map->L);
ret = lua_pcall(map->L, 3, 0, 0);
if (ret)
printf("<br>Lua error: %s\n",
lua_tostring(map->L, -1));
bozo_flush(httpd, stdout);
rv = 1;
goto out;
}
}
out:
free(prefix);
free(uri);
free(info);
free(query);
free(file);
return rv;
}
#endif /* NO_LUA_SUPPORT */

View File

@ -0,0 +1,39 @@
#PREFIX=/Users/agcrooks
PREFIX=/usr
#LIBDIR=/usr/lib
LIB=luabozohttpd
SRCS=glue.c
MKMAN=no
CPPFLAGS+=-g -I${PREFIX}/pkg/include
LDADD+= -lbozohttpd
WARNS=4
CLEANFILES+= a a.sig
.include <bsd.lib.mk>
.include <bsd.own.mk>
LUABOZOOBJDIR != cd ${.CURDIR} && ${PRINTOBJDIR}
OPSYS!= uname -s
.if ${OPSYS} == "Darwin"
.sinclude <bsd.warns.mk>
lib${LIB}.dylib:
libtool -dynamic -o ${.TARGET} ${OBJS} ${PREFIX}/pkg/lib/liblua.dylib /usr/lib/libc.dylib ${PREFIX}/pkg/lib/libbozohttpd.dylib
t: lib${LIB}.dylib
cp Makefile a
./bozo.lua --sign --detached a
./bozo.lua --verify a.sig
.else
t:
cp Makefile a
env LD_LIBRARY_PATH=${LUABOZOOBJDIR}:/lib:/usr/lib:${PREFIX}/lib \
./bozo.lua --sign --detached a
env LD_LIBRARY_PATH=${LUABOZOOBJDIR}:/lib:/usr/lib:${PREFIX}/lib \
./bozo.lua --verify a.sig
.endif

162
libexec/httpd/lua/bozo.lua Executable file
View File

@ -0,0 +1,162 @@
#! /usr/bin/env lua
--
-- Copyright (c) 2009 The NetBSD Foundation, Inc.
-- All rights reserved.
--
-- This code is derived from software contributed to The NetBSD Foundation
-- by Alistair Crooks (agc@netbsd.org)
--
-- 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
--
-- command line args
dofile "optparse.lua"
opt = OptionParser{usage="%prog [options] root [vhost]", version="20091105"}
opt.add_option{"-C", "--cgimap", action="store", dest="cgimap", help="--cgimap 's t'"}
opt.add_option{"-H", "--hide-dots", action="store_true", dest="hidedots", help="--hide-dots"}
opt.add_option{"-I", "--portnum", action="store", dest="portnum", help="--portnum number"}
opt.add_option{"-M", "--dynamicmime", action="store", dest="dynmime", help="--dynamicmime 'suffix type a b'"}
opt.add_option{"-S", "--server-software", action="store", dest="serversw", help="--server-software name"}
opt.add_option{"-U", "--username", action="store", dest="username", help="--username name"}
opt.add_option{"-V", "--unknown-slash", action="store_true", dest="unknown", help="--unknown-slash"}
opt.add_option{"-X", "--dir-index", action="store_true", dest="dirindex", help="--dir-index"}
opt.add_option{"-Z", "--ssl", action="store", dest="ssl", help="--ssl 'cert priv'"}
opt.add_option{"-b", "--background", action="store", dest="background", help="--background count"}
opt.add_option{"-c", "--cgibin", action="store", dest="cgibin", help="--cgibin bin"}
opt.add_option{"-e", "--dirtyenv", action="store_true", dest="dirtyenv", help="--dirtyenv"}
opt.add_option{"-f", "--foreground", action="store_true", dest="foreground", help="--foreground"}
opt.add_option{"-i", "--bindaddr", action="store", dest="bindaddress", help="--bindaddr address"}
opt.add_option{"-n", "--numeric", action="store_true", dest="numeric", help="--numeric"}
opt.add_option{"-p", "--public-html", action="store", dest="public_html", help="--public-html dir"}
opt.add_option{"-r", "--trusted-referal", action="store_true", dest="trustedref", help="trusted referal"}
opt.add_option{"-s", "--logtostderr", action="store_true", dest="logstderr", help="log to stderr"}
opt.add_option{"-t", "--chroot", action="store", dest="chroot", help="--chroot dir"}
opt.add_option{"-u", "--enable-users", action="store_true", dest="enableusers", help="--enable-users"}
opt.add_option{"-v", "--virtbase", action="store", dest="virtbase", help="virtual base location"}
opt.add_option{"-x", "--index-html", action="store", dest="indexhtml", help="index.html name"}
-- caller lua script
local extension = ".so"
f = io.open("libluabozohttpd.dylib", "r")
if f then
extension = ".dylib"
io.close(f)
end
glupkg = package.loadlib("./" .. "libluabozohttpd" .. extension, "luaopen_bozohttpd")
bozohttpd = glupkg()
-- initialise
httpd = bozohttpd.new()
bozohttpd.init_httpd(httpd)
prefs = bozohttpd.init_prefs()
-- parse command line args
options,args = opt.parse_args()
if options.portnum then
bozohttpd.set_pref(prefs, "port number", options.portnum)
end
if options.background then
bozohttpd.set_pref(prefs, "background", options.background)
end
if options.numeric then
bozohttpd.set_pref(prefs, "numeric", "true")
end
if options.logstderr then
bozohttpd.set_pref(prefs, "log to stderr", "true")
end
if options.foreground then
bozohttpd.set_pref(prefs, "foreground", "true")
end
if options.trustedref then
bozohttpd.set_pref(prefs, "trusted referal", "true")
end
if options.dynmime then
suffix, type, s1, s2 = string.find(options.dynmime,
"(%S+)%s+(%S+)%s+(%S+)%s+(%S+)")
bozohttpd.dynamic_mime(httpd, suffix, type, s1, s2)
end
if options.serversw then
bozohttpd.set_pref(prefs, "server software", options.serversw)
end
if options.ssl then
cert, priv = string.find(options.ssl, "(%S+)%s+(%S+)")
bozohttpd.dynamic_mime(httpd, cert, priv)
end
if options.username then
bozohttpd.set_pref(prefs, "username", options.username)
end
if options.unknownslash then
bozohttpd.set_pref(prefs, "unknown slash", "true")
end
if options.virtbase then
bozohttpd.set_pref(prefs, "virtual base", options.virtbase)
end
if options.indexhtml then
bozohttpd.set_pref(prefs, "index.html", options.indexhtml)
end
if options.dirtyenv then
bozohttpd.set_pref(prefs, "dirty environment", "true")
end
if options.bindaddr then
bozohttpd.set_pref(prefs, "bind address", options.bindaddr)
end
if options.cgibin then
bozohttpd.cgi_setbin(httpd, options.cgibin)
end
if options.cgimap then
name, handler = string.find(options.cgimap, "(%S+)%s+(%S+)")
bozohttpd.cgi_map(httpd, name, handler)
end
if options.public_html then
bozohttpd.set_pref(prefs, "public_html", options.public_html)
end
if options.chroot then
bozohttpd.set_pref(prefs, "chroot dir", options.chroot)
end
if options.enableusers then
bozohttpd.set_pref(prefs, "enable users", "true")
end
if options.hidedots then
bozohttpd.set_pref(prefs, "hide dots", "true")
end
if options.dirindex then
bozohttpd.set_pref(prefs, "directory indexing", "true")
end
if #args < 1 then
print("At least one arg needed for root directory")
else
-- set up connections
local vhost = args[2] or ""
bozohttpd.setup(httpd, prefs, vhost, args[1])
-- loop, serving requests
local numreps = options.background or 0
repeat
req = bozohttpd.read_request(httpd)
bozohttpd.process_request(httpd, req)
bozohttpd.clean_request(req)
until numreps == 0
end

276
libexec/httpd/lua/glue.c Normal file
View File

@ -0,0 +1,276 @@
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Alistair Crooks (agc@netbsd.org)
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <sys/param.h>
#include <sys/stat.h>
#include <bozohttpd.h>
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define LUA_LIB
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#ifndef __UNCONST
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif /* !__UNCONST */
int luaopen_bozohttpd(lua_State *);
#if 0
typedef struct strarg_t {
const char *s; /* string */
const int n; /* corresponding int value */
} strarg_t;
/* map a string onto an int */
static int
findtype(strarg_t *strs, const char *s)
{
strarg_t *sp;
for (sp = strs ; sp->s && strcasecmp(sp->s, s) != 0 ; sp++) {
}
return sp->n;
}
#endif
/* init() */
static int
l_new(lua_State *L)
{
bozohttpd_t *httpd;
httpd = lua_newuserdata(L, sizeof(*httpd));
(void) memset(httpd, 0x0, sizeof(*httpd));
return 1;
}
/* initialise(httpd) */
static int
l_init_httpd(lua_State *L)
{
bozohttpd_t *httpd;
httpd = lua_touserdata(L, 1);
lua_pushnumber(L, bozo_init_httpd(httpd));
return 1;
}
/* initialise(prefs) */
static int
l_init_prefs(lua_State *L)
{
bozoprefs_t *prefs;
prefs = lua_newuserdata(L, sizeof(*prefs));
(void) memset(prefs, 0x0, sizeof(*prefs));
(void) bozo_init_prefs(prefs);
return 1;
}
/* bozo_set_pref(prefs, name, value) */
static int
l_bozo_set_pref(lua_State *L)
{
bozoprefs_t *prefs;
const char *name;
const char *value;
prefs = lua_touserdata(L, 1);
name = luaL_checkstring(L, 2);
value = luaL_checkstring(L, 3);
lua_pushnumber(L, bozo_set_pref(prefs, name, value));
return 1;
}
/* bozo_get_pref(prefs, name) */
static int
l_bozo_get_pref(lua_State *L)
{
bozoprefs_t *prefs;
const char *name;
prefs = lua_touserdata(L, 1);
name = luaL_checkstring(L, 2);
lua_pushstring(L, bozo_get_pref(prefs, name));
return 1;
}
/* bozo_setup(httpd, prefs, host, root) */
static int
l_bozo_setup(lua_State *L)
{
bozohttpd_t *httpd;
bozoprefs_t *prefs;
const char *vhost;
const char *root;
httpd = lua_touserdata(L, 1);
prefs = lua_touserdata(L, 2);
vhost = luaL_checkstring(L, 3);
if (vhost && *vhost == 0x0) {
vhost = NULL;
}
root = luaL_checkstring(L, 4);
lua_pushnumber(L, bozo_setup(httpd, prefs, vhost, root));
return 1;
}
/* bozo_read_request(httpd) */
static int
l_bozo_read_request(lua_State *L)
{
bozo_httpreq_t *req;
bozohttpd_t *httpd;
httpd = lua_touserdata(L, 1);
req = bozo_read_request(httpd);
lua_pushlightuserdata(L, req);
return 1;
}
/* bozo_process_request(httpd, req) */
static int
l_bozo_process_request(lua_State *L)
{
bozo_httpreq_t *req;
bozohttpd_t *httpd;
httpd = lua_touserdata(L, 1);
req = lua_touserdata(L, 2);
bozo_process_request(httpd, req);
lua_pushnumber(L, 1);
return 1;
}
/* bozo_clean_request(req) */
static int
l_bozo_clean_request(lua_State *L)
{
bozo_httpreq_t *req;
req = lua_touserdata(L, 1);
bozo_clean_request(req);
lua_pushnumber(L, 1);
return 1;
}
/* dynamic_mime(httpd, one, two, three, four) */
static int
l_bozo_dynamic_mime(lua_State *L)
{
bozohttpd_t *httpd;
const char *s[4];
httpd = lua_touserdata(L, 1);
s[0] = luaL_checkstring(L, 2);
s[1] = luaL_checkstring(L, 3);
s[2] = luaL_checkstring(L, 4);
s[3] = luaL_checkstring(L, 5);
bozo_add_content_map_mime(httpd, s[0], s[1], s[2], s[3]);
lua_pushnumber(L, 1);
return 1;
}
/* ssl_set_opts(httpd, one, two) */
static int
l_bozo_ssl_set_opts(lua_State *L)
{
bozohttpd_t *httpd;
const char *s[2];
httpd = lua_touserdata(L, 1);
s[0] = luaL_checkstring(L, 2);
s[1] = luaL_checkstring(L, 3);
bozo_ssl_set_opts(httpd, s[0], s[1]);
lua_pushnumber(L, 1);
return 1;
}
/* cgi_setbin(httpd, bin) */
static int
l_bozo_cgi_setbin(lua_State *L)
{
bozohttpd_t *httpd;
const char *bin;
httpd = lua_touserdata(L, 1);
bin = luaL_checkstring(L, 2);
bozo_cgi_setbin(httpd, bin);
lua_pushnumber(L, 1);
return 1;
}
/* cgi_map(httpd, 1, 2) */
static int
l_bozo_cgi_map(lua_State *L)
{
bozohttpd_t *httpd;
const char *s[2];
httpd = lua_touserdata(L, 1);
s[0] = luaL_checkstring(L, 2);
s[1] = luaL_checkstring(L, 3);
bozo_add_content_map_cgi(httpd, s[0], s[1]);
lua_pushnumber(L, 1);
return 1;
}
const struct luaL_reg libluabozohttpd[] = {
{ "new", l_new },
{ "init_httpd", l_init_httpd },
{ "init_prefs", l_init_prefs },
{ "set_pref", l_bozo_set_pref },
{ "get_pref", l_bozo_get_pref },
{ "setup", l_bozo_setup },
{ "dynamic_mime", l_bozo_dynamic_mime },
{ "ssl_set_opts", l_bozo_ssl_set_opts },
{ "cgi_setbin", l_bozo_cgi_setbin },
{ "cgi_map", l_bozo_cgi_map },
{ "read_request", l_bozo_read_request },
{ "process_request", l_bozo_process_request },
{ "clean_request", l_bozo_clean_request },
{ NULL, NULL }
};
int
luaopen_bozohttpd(lua_State *L)
{
luaL_openlib(L, "bozohttpd", libluabozohttpd, 0);
return 1;
}

View File

@ -0,0 +1,123 @@
-- Lua command line option parser.
-- Interface based on Pythons optparse.
-- http://docs.python.org/lib/module-optparse.html
-- (c) 2008 David Manura, Licensed under the same terms as Lua (MIT license)
--
-- To be used like this:
-- t={usage="<some usage message>", version="<version string>"}
-- op=OptionParser(t)
-- op=add_option{"<opt>", action=<action>, dest=<dest>, help="<help message for this option>"}
--
-- with :
-- <opt> the option string to be used (can be anything, if one letter opt, then should be -x val, more letters: -xy=val )
-- <action> one of
-- - store: store in options as key, val
-- - store_true: stores key, true
-- - store_false: stores key, false
-- <dest> is the key under which the option is saved
--
-- options,args = op.parse_args()
--
-- now options is the table of options (key, val) and args is the table with non-option arguments.
-- You can use op.fail(message) for failing and op.print_help() for printing the usage as you like.
function OptionParser(t)
local usage = t.usage
local version = t.version
local o = {}
local option_descriptions = {}
local option_of = {}
function o.fail(s) -- extension
io.stderr:write(s .. '\n')
os.exit(1)
end
function o.add_option(optdesc)
option_descriptions[#option_descriptions+1] = optdesc
for _,v in ipairs(optdesc) do
option_of[v] = optdesc
end
end
function o.parse_args()
-- expand options (e.g. "--input=file" -> "--input", "file")
local arg = {unpack(arg)}
for i=#arg,1,-1 do local v = arg[i]
local flag, val = v:match('^(%-%-%w+)=(.*)')
if flag then
arg[i] = flag
table.insert(arg, i+1, val)
end
end
local options = {}
local args = {}
local i = 1
while i <= #arg do local v = arg[i]
local optdesc = option_of[v]
if optdesc then
local action = optdesc.action
local val
if action == 'store' or action == nil then
i = i + 1
val = arg[i]
if not val then o.fail('option requires an argument ' .. v) end
elseif action == 'store_true' then
val = true
elseif action == 'store_false' then
val = false
end
options[optdesc.dest] = val
else
if v:match('^%-') then o.fail('invalid option ' .. v) end
args[#args+1] = v
end
i = i + 1
end
if options.help then
o.print_help()
os.exit()
end
if options.version then
io.stdout:write(t.version .. "\n")
os.exit()
end
return options, args
end
local function flags_str(optdesc)
local sflags = {}
local action = optdesc.action
for _,flag in ipairs(optdesc) do
local sflagend
if action == nil or action == 'store' then
local metavar = optdesc.metavar or optdesc.dest:upper()
sflagend = #flag == 2 and ' ' .. metavar
or '=' .. metavar
else
sflagend = ''
end
sflags[#sflags+1] = flag .. sflagend
end
return table.concat(sflags, ', ')
end
function o.print_help()
io.stdout:write("Usage: " .. usage:gsub('%%prog', arg[0]) .. "\n")
io.stdout:write("\n")
io.stdout:write("Options:\n")
for _,optdesc in ipairs(option_descriptions) do
io.stdout:write(" " .. flags_str(optdesc) ..
" " .. optdesc.help .. "\n")
end
end
o.add_option{"--help", action="store_true", dest="help",
help="show this help message and exit"}
if t.version then
o.add_option{"--version", action="store_true", dest="version",
help="output version info."}
end
return o
end

View File

@ -0,0 +1,2 @@
major=0
minor=0

356
libexec/httpd/main.c Normal file
View File

@ -0,0 +1,356 @@
/* $NetBSD: main.c,v 1.8 2014/07/16 07:41:43 mrg Exp $ */
/* $eterna: main.c,v 1.6 2011/11/18 09:21:15 mrg Exp $ */
/* from: eterna: bozohttpd.c,v 1.159 2009/05/23 02:14:30 mrg Exp */
/*
* Copyright (c) 1997-2014 Matthew R. Green
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
/* this program is dedicated to the Great God of Processed Cheese */
/*
* main.c: C front end to bozohttpd
*/
#include <sys/types.h>
#include <sys/param.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include "bozohttpd.h"
/* variables and functions */
#ifndef LOG_FTP
#define LOG_FTP LOG_DAEMON
#endif
/* print a usage message, and then exit */
BOZO_DEAD static void
usage(bozohttpd_t *httpd, char *progname)
{
bozo_warn(httpd, "usage: %s [options] slashdir [virtualhostname]",
progname);
bozo_warn(httpd, "options:");
#ifndef NO_DEBUG
bozo_warn(httpd, " -d\t\t\tenable debug support");
#endif
bozo_warn(httpd, " -s\t\t\talways log to stderr");
#ifndef NO_USER_SUPPORT
bozo_warn(httpd, " -u\t\t\tenable ~user/public_html support");
bozo_warn(httpd, " -p dir\t\tchange `public_html' directory name]");
#endif
#ifndef NO_DYNAMIC_CONTENT
bozo_warn(httpd, " -M arg t c c11\tadd this mime extenstion");
#endif
#ifndef NO_CGIBIN_SUPPORT
#ifndef NO_DYNAMIC_CONTENT
bozo_warn(httpd, " -C arg prog\t\tadd this CGI handler");
#endif
bozo_warn(httpd,
" -c cgibin\t\tenable cgi-bin support in this directory");
#endif
#ifndef NO_LUA_SUPPORT
bozo_warn(httpd, " -L arg script\tadd this Lua script");
#endif
bozo_warn(httpd, " -I port\t\tbind or use on this port");
#ifndef NO_DAEMON_MODE
bozo_warn(httpd, " -b\t\t\tbackground and go into daemon mode");
bozo_warn(httpd, " -f\t\t\tkeep daemon mode in the foreground");
bozo_warn(httpd,
" -i address\t\tbind on this address (daemon mode only)");
bozo_warn(httpd, " -P pidfile\t\tpath to the pid file to create");
#endif
bozo_warn(httpd, " -S version\t\tset server version string");
bozo_warn(httpd, " -t dir\t\tchroot to `dir'");
bozo_warn(httpd, " -U username\t\tchange user to `user'");
bozo_warn(httpd,
" -e\t\t\tdon't clean the environment (-t and -U only)");
bozo_warn(httpd,
" -v virtualroot\tenable virtual host support "
"in this directory");
bozo_warn(httpd,
" -r\t\t\tmake sure sub-pages come from "
"this host via referrer");
#ifndef NO_DIRINDEX_SUPPORT
bozo_warn(httpd,
" -X\t\t\tenable automatic directory index support");
bozo_warn(httpd,
" -H\t\t\thide files starting with a period (.)"
" in index mode");
#endif
bozo_warn(httpd,
" -x index\t\tchange default `index.html' file name");
#ifndef NO_SSL_SUPPORT
bozo_warn(httpd,
" -Z cert privkey\tspecify path to server certificate"
" and private key file\n"
"\t\t\tin pem format and enable bozohttpd in SSL mode");
#endif /* NO_SSL_SUPPORT */
bozo_err(httpd, 1, "%s failed to start", progname);
}
int
main(int argc, char **argv)
{
bozo_httpreq_t *request;
bozohttpd_t httpd;
bozoprefs_t prefs;
char *progname;
int c;
(void) memset(&httpd, 0x0, sizeof(httpd));
(void) memset(&prefs, 0x0, sizeof(prefs));
if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
progname++;
openlog(progname, LOG_PID|LOG_NDELAY, LOG_FTP);
bozo_set_defaults(&httpd, &prefs);
while ((c = getopt(argc, argv,
"C:HI:L:M:P:S:U:VXZ:bc:defhi:np:rst:uv:x:z:")) != -1) {
switch(c) {
case 'L':
#ifdef NO_LUA_SUPPORT
bozo_err(&httpd, 1,
"Lua support is not enabled");
/* NOTREACHED */
#else
/* make sure there's two argument */
if (argc - optind < 1)
usage(&httpd, progname);
bozo_add_lua_map(&httpd, optarg, argv[optind]);
optind++;
break;
#endif /* NO_LUA_SUPPORT */
case 'M':
#ifdef NO_DYNAMIC_CONTENT
bozo_err(&httpd, 1,
"dynamic mime content support is not enabled");
/* NOTREACHED */
#else
/* make sure there's four arguments */
if (argc - optind < 3)
usage(&httpd, progname);
bozo_add_content_map_mime(&httpd, optarg, argv[optind],
argv[optind+1], argv[optind+2]);
optind += 3;
break;
#endif /* NO_DYNAMIC_CONTENT */
case 'n':
bozo_set_pref(&prefs, "numeric", "true");
break;
case 'r':
bozo_set_pref(&prefs, "trusted referal", "true");
break;
case 's':
bozo_set_pref(&prefs, "log to stderr", "true");
break;
case 'S':
bozo_set_pref(&prefs, "server software", optarg);
break;
case 'Z':
#ifdef NO_SSL_SUPPORT
bozo_err(&httpd, 1, "ssl support is not enabled");
/* NOT REACHED */
#else
/* make sure there's two arguments */
if (argc - optind < 1)
usage(&httpd, progname);
bozo_ssl_set_opts(&httpd, optarg, argv[optind++]);
break;
#endif /* NO_SSL_SUPPORT */
case 'U':
bozo_set_pref(&prefs, "username", optarg);
break;
case 'V':
bozo_set_pref(&prefs, "unknown slash", "true");
break;
case 'v':
bozo_set_pref(&prefs, "virtual base", optarg);
break;
case 'x':
bozo_set_pref(&prefs, "index.html", optarg);
break;
case 'I':
bozo_set_pref(&prefs, "port number", optarg);
break;
#ifdef NO_DAEMON_MODE
case 'b':
case 'e':
case 'f':
case 'i':
case 'P':
bozo_err(&httpd, 1, "Daemon mode is not enabled");
/* NOTREACHED */
#else
case 'b':
/*
* test suite support - undocumented
* background == 2 (aka, -b -b) means to
* only process 1 per kid
*/
if (bozo_get_pref(&prefs, "background") == NULL) {
bozo_set_pref(&prefs, "background", "1");
} else {
bozo_set_pref(&prefs, "background", "2");
}
break;
case 'e':
bozo_set_pref(&prefs, "dirty environment", "true");
break;
case 'f':
bozo_set_pref(&prefs, "foreground", "true");
break;
case 'i':
bozo_set_pref(&prefs, "bind address", optarg);
break;
case 'P':
bozo_set_pref(&prefs, "pid file", optarg);
break;
#endif /* NO_DAEMON_MODE */
#ifdef NO_CGIBIN_SUPPORT
case 'c':
case 'C':
bozo_err(&httpd, 1, "CGI is not enabled");
/* NOTREACHED */
#else
case 'c':
bozo_cgi_setbin(&httpd, optarg);
break;
case 'C':
# ifdef NO_DYNAMIC_CONTENT
bozo_err(&httpd, 1,
"dynamic CGI handler support is not enabled");
/* NOTREACHED */
# else
/* make sure there's two arguments */
if (argc - optind < 1)
usage(&httpd, progname);
bozo_add_content_map_cgi(&httpd, optarg,
argv[optind++]);
break;
# endif /* NO_DYNAMIC_CONTENT */
#endif /* NO_CGIBIN_SUPPORT */
case 'd':
httpd.debug++;
#ifdef NO_DEBUG
if (httpd.debug == 1)
bozo_warn(&httpd, "Debugging is not enabled");
#endif /* NO_DEBUG */
break;
case 't':
bozo_set_pref(&prefs, "chroot dir", optarg);
break;
#ifdef NO_USER_SUPPORT
case 'p':
case 'u':
bozo_err(&httpd, 1, "User support is not enabled");
/* NOTREACHED */
#else
case 'p':
bozo_set_pref(&prefs, "public_html", optarg);
break;
case 'u':
bozo_set_pref(&prefs, "enable users", "true");
break;
#endif /* NO_USER_SUPPORT */
#ifdef NO_DIRINDEX_SUPPORT
case 'H':
case 'X':
bozo_err(&httpd, 1,
"directory indexing is not enabled");
/* NOTREACHED */
#else
case 'H':
bozo_set_pref(&prefs, "hide dots", "true");
break;
case 'X':
bozo_set_pref(&prefs, "directory indexing", "true");
break;
#endif /* NO_DIRINDEX_SUPPORT */
default:
usage(&httpd, progname);
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if (argc == 0 || argc > 2) {
usage(&httpd, progname);
}
/* virtual host, and root of tree to serve */
bozo_setup(&httpd, &prefs, argv[1], argv[0]);
/*
* read and process the HTTP request.
*/
do {
if ((request = bozo_read_request(&httpd)) != NULL) {
bozo_process_request(request);
bozo_clean_request(request);
}
} while (httpd.background);
return (0);
}

View File

@ -0,0 +1,82 @@
/* $eterna: queue.h,v 1.6 2009/04/18 08:36:03 mrg Exp $ */
/* from: NetBSD: queue.h,v 1.51 2009/03/11 06:51:53 mrg Exp */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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.
* 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_FOREACH(var, head, field) \
for ((var) = ((head)->sqh_first); \
(var); \
(var) = ((var)->field.sqe_next))
#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \
for ((var) = ((head)->sqh_first); \
(var) && ((next = ((var)->field.sqe_next)), 1); \
(var) = (next))
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#endif /* !_SYS_QUEUE_H_ */

View File

@ -0,0 +1,85 @@
-- $NetBSD: printenv.lua,v 1.2 2014/01/02 08:21:38 mrg Exp $
-- this small Lua script demonstrates the use of Lua in (bozo)httpd
-- it will simply output the "environment"
-- Keep in mind that bozohttpd forks for each request when started in
-- daemon mode, you can set global veriables here, but they will have
-- the same value on each invocation. You can not keep state between
-- two calls.
local httpd = require 'httpd'
function printenv(env, headers, query)
-- we get the "environment" in the env table, the values are more
-- or less the same as the variable for a CGI program
if count == nil then
count = 1
end
-- output a header
print([[
<html>
<head>
<title>Bozotic Lua Environment</title>
</head>
<body>
<h1>Bozotic Lua Environment</h1>
]])
print('module version: ' .. httpd._VERSION .. '<br>')
print('<h2>Server Environment</h2>')
-- print the list of "environment" variables
for k, v in pairs(env) do
print(k .. '=' .. v .. '<br/>')
end
print('<h2>Request Headers</h2>')
for k, v in pairs(headers) do
print(k .. '=' .. v .. '<br/>')
end
if query ~= nil then
print('<h2>Query Variables</h2>')
for k, v in pairs(query) do
print(k .. '=' .. v .. '<br/>')
end
end
print('<h2>Form Test</h2>')
print([[
<form method="POST" action="/rest/form?sender=me">
<input type="text" name="a_value">
<input type="submit">
</form>
]])
-- output a footer
print([[
</body>
</html>
]])
end
function form(env, header, query)
if query ~= nil then
print('<h2>Form Variables</h2>')
if env.CONTENT_TYPE ~= nil then
print('Content-type: ' .. env.CONTENT_TYPE .. '<br>')
end
for k, v in pairs(query) do
print(k .. '=' .. v .. '<br/>')
end
else
print('No values')
end
end
-- register this handler for http://<hostname>/<prefix>/printenv
httpd.register_handler('printenv', printenv)
httpd.register_handler('form', form)

View File

@ -0,0 +1,30 @@
# $eterna: Makefile,v 1.1 2009/05/22 21:51:39 mrg Exp $
# build a 100% lean bozohttpd-small.c
PROG= bozohttpd-small
NOMAN= # defined
SRCS= bozohttpd-small.c content-bozo-small.c ssl-bozo.c main.c:
LEAN_IFDEF_FLAGS= -UDEBUG -DNO_USER_SUPPORT \
-DNO_CGIBIN_SUPPORT -DNO_DIRINDEX_SUPPORT \
-DNO_DAEMON_MODE -DNO_DYNAMIC_CONTENT \
-DNO_SSL_SUPPORT -UDO_HTPASSWD \
-DNO_LUA_SUPPORT
CFLAGS= -I$(.CURDIR)/.. ${LEAN_IFDEF_FLAGS}
bozohttpd-small.c: bozohttpd.c
unifdef $(LEAN_IFDEF_FLAGS) < $> > $@.tmp ;\
if [ $$? -ne 1 ]; then echo "unifdef returned $?, expecting 1" 2>&1; false; fi
mv -f $@.tmp $@
content-bozo-small.c: content-bozo.c
unifdef $(LEAN_IFDEF_FLAGS) < $> > $@.tmp ;\
if [ $$? -ne 1 ]; then echo "unifdef returned $?, expecting 1" 2>&1; false; fi
mv -f $@.tmp $@
CLEANFILES+= content-bozo-small.c bozohttpd-small.c
.PATH: $(.CURDIR)/..
.include <bsd.prog.mk>

321
libexec/httpd/ssl-bozo.c Normal file
View File

@ -0,0 +1,321 @@
/* $NetBSD: ssl-bozo.c,v 1.18 2014/07/17 06:27:52 mrg Exp $ */
/* $eterna: ssl-bozo.c,v 1.15 2011/11/18 09:21:15 mrg Exp $ */
/*
* Copyright (c) 1997-2014 Matthew R. Green
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
/* this code implements SSL and backend IO for bozohttpd */
#include <stdarg.h>
#include <stdio.h>
#include <syslog.h>
#include <unistd.h>
#include "bozohttpd.h"
#ifndef NO_SSL_SUPPORT
#include <openssl/ssl.h>
#include <openssl/err.h>
#ifndef USE_ARG
#define USE_ARG(x) /*LINTED*/(void)&(x)
#endif
/* this structure encapsulates the ssl info */
typedef struct sslinfo_t {
SSL_CTX *ssl_context;
const SSL_METHOD *ssl_method;
SSL *bozossl;
char *certificate_file;
char *privatekey_file;
} sslinfo_t;
/*
* bozo_clear_ssl_queue: print the contents of the SSL error queue
*/
static void
bozo_clear_ssl_queue(bozohttpd_t *httpd)
{
unsigned long sslcode = ERR_get_error();
do {
static const char sslfmt[] = "SSL Error: %s:%s:%s";
if (httpd->logstderr || isatty(STDERR_FILENO)) {
fprintf(stderr, sslfmt,
ERR_lib_error_string(sslcode),
ERR_func_error_string(sslcode),
ERR_reason_error_string(sslcode));
} else {
syslog(LOG_ERR, sslfmt,
ERR_lib_error_string(sslcode),
ERR_func_error_string(sslcode),
ERR_reason_error_string(sslcode));
}
} while (0 != (sslcode = ERR_get_error()));
}
/*
* bozo_ssl_warn works just like bozo_warn, plus the SSL error queue
*/
BOZO_PRINTFLIKE(2, 3) static void
bozo_ssl_warn(bozohttpd_t *httpd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (httpd->logstderr || isatty(STDERR_FILENO)) {
vfprintf(stderr, fmt, ap);
fputs("\n", stderr);
} else
vsyslog(LOG_ERR, fmt, ap);
va_end(ap);
bozo_clear_ssl_queue(httpd);
}
/*
* bozo_ssl_err works just like bozo_err, plus the SSL error queue
*/
BOZO_PRINTFLIKE(3, 4) BOZO_DEAD static void
bozo_ssl_err(bozohttpd_t *httpd, int code, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (httpd->logstderr || isatty(STDERR_FILENO)) {
vfprintf(stderr, fmt, ap);
fputs("\n", stderr);
} else
vsyslog(LOG_ERR, fmt, ap);
va_end(ap);
bozo_clear_ssl_queue(httpd);
exit(code);
}
/*
* bozo_check_error_queue: print warnings if the error isn't expected
*/
static void
bozo_check_error_queue(bozohttpd_t *httpd, const char *tag, int ret)
{
if (ret > 0)
return;
const sslinfo_t *sslinfo = httpd->sslinfo;
const int sslerr = SSL_get_error(sslinfo->bozossl, ret);
if (sslerr != SSL_ERROR_ZERO_RETURN &&
sslerr != SSL_ERROR_SYSCALL &&
sslerr != SSL_ERROR_NONE)
bozo_ssl_warn(httpd, "%s: SSL_ERROR %d", tag, sslerr);
}
static BOZO_PRINTFLIKE(2, 0) int
bozo_ssl_printf(bozohttpd_t *httpd, const char * fmt, va_list ap)
{
char *buf;
int nbytes;
if ((nbytes = vasprintf(&buf, fmt, ap)) != -1) {
const sslinfo_t *sslinfo = httpd->sslinfo;
int ret = SSL_write(sslinfo->bozossl, buf, nbytes);
bozo_check_error_queue(httpd, "write", ret);
}
free(buf);
return nbytes;
}
static ssize_t
bozo_ssl_read(bozohttpd_t *httpd, int fd, void *buf, size_t nbytes)
{
const sslinfo_t *sslinfo = httpd->sslinfo;
int ret;
USE_ARG(fd);
ret = SSL_read(sslinfo->bozossl, buf, (int)nbytes);
bozo_check_error_queue(httpd, "read", ret);
return (ssize_t)ret;
}
static ssize_t
bozo_ssl_write(bozohttpd_t *httpd, int fd, const void *buf, size_t nbytes)
{
const sslinfo_t *sslinfo = httpd->sslinfo;
int ret;
USE_ARG(fd);
ret = SSL_write(sslinfo->bozossl, buf, (int)nbytes);
bozo_check_error_queue(httpd, "write", ret);
return (ssize_t)ret;
}
void
bozo_ssl_init(bozohttpd_t *httpd)
{
sslinfo_t *sslinfo = httpd->sslinfo;
if (sslinfo == NULL || !sslinfo->certificate_file)
return;
SSL_library_init();
SSL_load_error_strings();
sslinfo->ssl_method = SSLv23_server_method();
sslinfo->ssl_context = SSL_CTX_new(sslinfo->ssl_method);
if (NULL == sslinfo->ssl_context)
bozo_ssl_err(httpd, EXIT_FAILURE,
"SSL context creation failed");
if (1 != SSL_CTX_use_certificate_chain_file(sslinfo->ssl_context,
sslinfo->certificate_file))
bozo_ssl_err(httpd, EXIT_FAILURE,
"Unable to use certificate file '%s'",
sslinfo->certificate_file);
if (1 != SSL_CTX_use_PrivateKey_file(sslinfo->ssl_context,
sslinfo->privatekey_file, SSL_FILETYPE_PEM))
bozo_ssl_err(httpd, EXIT_FAILURE,
"Unable to use private key file '%s'",
sslinfo->privatekey_file);
/* check consistency of key vs certificate */
if (!SSL_CTX_check_private_key(sslinfo->ssl_context))
bozo_ssl_err(httpd, EXIT_FAILURE,
"Check private key failed");
}
/*
* returns non-zero for failure
*/
int
bozo_ssl_accept(bozohttpd_t *httpd)
{
sslinfo_t *sslinfo = httpd->sslinfo;
if (sslinfo == NULL || !sslinfo->ssl_context)
return 0;
sslinfo->bozossl = SSL_new(sslinfo->ssl_context);
if (sslinfo->bozossl == NULL)
bozo_err(httpd, 1, "SSL_new failed");
SSL_set_rfd(sslinfo->bozossl, 0);
SSL_set_wfd(sslinfo->bozossl, 1);
const int ret = SSL_accept(sslinfo->bozossl);
bozo_check_error_queue(httpd, "accept", ret);
return ret != 1;
}
void
bozo_ssl_destroy(bozohttpd_t *httpd)
{
const sslinfo_t *sslinfo = httpd->sslinfo;
if (sslinfo && sslinfo->bozossl)
SSL_free(sslinfo->bozossl);
}
void
bozo_ssl_set_opts(bozohttpd_t *httpd, const char *cert, const char *priv)
{
sslinfo_t *sslinfo = httpd->sslinfo;
if (sslinfo == NULL) {
sslinfo = bozomalloc(httpd, sizeof(*sslinfo));
if (sslinfo == NULL)
bozo_err(httpd, 1, "sslinfo allocation failed");
httpd->sslinfo = sslinfo;
}
sslinfo->certificate_file = strdup(cert);
sslinfo->privatekey_file = strdup(priv);
debug((httpd, DEBUG_NORMAL, "using cert/priv files: %s & %s",
sslinfo->certificate_file,
sslinfo->privatekey_file));
if (!httpd->bindport)
httpd->bindport = strdup("https");
}
#endif /* NO_SSL_SUPPORT */
int
bozo_printf(bozohttpd_t *httpd, const char *fmt, ...)
{
va_list args;
int cc;
va_start(args, fmt);
#ifndef NO_SSL_SUPPORT
if (httpd->sslinfo)
cc = bozo_ssl_printf(httpd, fmt, args);
else
#endif
cc = vprintf(fmt, args);
va_end(args);
return cc;
}
ssize_t
bozo_read(bozohttpd_t *httpd, int fd, void *buf, size_t len)
{
#ifndef NO_SSL_SUPPORT
if (httpd->sslinfo)
return bozo_ssl_read(httpd, fd, buf, len);
#endif
return read(fd, buf, len);
}
ssize_t
bozo_write(bozohttpd_t *httpd, int fd, const void *buf, size_t len)
{
#ifndef NO_SSL_SUPPORT
if (httpd->sslinfo)
return bozo_ssl_write(httpd, fd, buf, len);
#endif
return write(fd, buf, len);
}
int
bozo_flush(bozohttpd_t *httpd, FILE *fp)
{
#ifndef NO_SSL_SUPPORT
if (httpd->sslinfo)
return 0;
#endif
return fflush(fp);
}

View File

@ -0,0 +1,32 @@
# $eterna: Makefile,v 1.14 2009/05/22 21:51:39 mrg Exp $
SIMPLETESTS= t1 t2 t3 t4 t5 t6 t7 t8 t9 t10
BIGFILETESTS= partial4000 partial8000
BOZOHTTPD?= ../bozohttpd
BOZOHTTPD?= ../debug/bozohttpd-debug
WGET?= wget
all:
clean:
for a in $(SIMPLETESTS); do \
rm -f tmp.$$a.out; \
done
check: check-simple check-bigfile
check-simple:
.for a in $(SIMPLETESTS)
echo "Running test $a"
$(BOZOHTTPD) ./data < $(.CURDIR)/$a.in > tmp.$a.out || true
$(.CURDIR)/html_cmp $(.CURDIR)/$a.out tmp.$a.out
.endfor
check-bigfile:
.for a in $(BIGFILETESTS)
echo "Running test $a"
$(.CURDIR)/test-bigfile "$a" "${BOZOHTTPD}" "${WGET}" "./data"
.endfor
.include <bsd.obj.mk>

View File

@ -0,0 +1,127 @@
this is the big data file. it has to be over 1 page size in length. 0123456789
these lines are all 80 long. this is the second line. 012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
012345678901 this is the seventh line. 12345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
456789 this is the 13th line, and there 127 lines in total. 67890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
901234567890123456789012345 this is the 18th line. 456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
78901234567890123456 this is the 31st line. 345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
90123456789012345678901234567890123456789 this is the 38th line. 78901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456 this is the 47th line. 4567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
789012345678901234567890123456789012345678901234567 50th 7890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012 this is the 52nd line. 1234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012 54th 1234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345 this is the 60th line. 2345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
678901234 this is the 71st line. 12345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567 this is the 80th line. 567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456 this is the 93th line. 3456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456 this is the 101st line. 456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
123456789012345678901234567890123456789012345 this is the 106th line. 3456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
789012345678901234 110th 4567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
34567890123456789012345678 114th 9012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
67890123 this is the 121st line. 12345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
this is the last line. this is the end of the file. there is no more. good bye.

View File

@ -0,0 +1,50 @@
this is the big data file. it has to be over 1 page size in length. 0123456789
these lines are all 80 long. this is the second line. 012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
012345678901 this is the seventh line. 12345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
456789 this is the 13th line, and there 127 lines in total. 67890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
901234567890123456789012345 this is the 18th line. 456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
78901234567890123456 this is the 31st line. 345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
90123456789012345678901234567890123456789 this is the 38th line. 78901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456 this is the 47th line. 4567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
789012345678901234567890123456789012345678901234567 50th 7890123456789012345

View File

@ -0,0 +1,100 @@
this is the big data file. it has to be over 1 page size in length. 0123456789
these lines are all 80 long. this is the second line. 012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
012345678901 this is the seventh line. 12345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
456789 this is the 13th line, and there 127 lines in total. 67890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
901234567890123456789012345 this is the 18th line. 456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
78901234567890123456 this is the 31st line. 345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
90123456789012345678901234567890123456789 this is the 38th line. 78901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456 this is the 47th line. 4567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
789012345678901234567890123456789012345678901234567 50th 7890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
56789012 this is the 52nd line. 1234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012 54th 1234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345 this is the 60th line. 2345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
678901234 this is the 71st line. 12345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567 this is the 80th line. 567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456789012345678901234567890123456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345
6789012345678901234567890123456789012345678901234567890123456789012345678901234
5678901234567890123456789012345678901234567890123456789012345678901234567890123
4567890123456 this is the 93th line. 3456789012345678901234567890123456789012
3456789012345678901234567890123456789012345678901234567890123456789012345678901
2345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789012345678
9012345678901234567890123456789012345678901234567890123456789012345678901234567
8901234567890123456789012345678901234567890123456789012345678901234567890123456
7890123456789012345678901234567890123456789012345678901234567890123456789012345

View File

@ -0,0 +1,4 @@
123456781234567
345678903456789
234567892345678
012345670123456

View File

@ -0,0 +1 @@
this is the bozohttpd testsuite ./data/index.html file

View File

@ -0,0 +1,27 @@
#! /bin/sh
#
# $eterna: html_cmp,v 1.9 2011/11/17 22:18:02 mrg Exp $
#
# like cmp(1) but compares to files after making their `Date: ' headers
# the same, to allow `now' and `then' to work properly. it also tries
# to find servername's that might be the local host and converts those
# as well..
#
# it must be called like `cmp file1 file1' *only*.
h=`hostname || uname -n`
sedcmd="s/^Date: .*/Date: nowish/;
s/^Last-Modified: .*/Last-Modified: nowish/;
s/[a-zA-Z0-9-]*\.eterna\.com\.au/$h/g;
s/^Server: .*/^Server: bozotic HTTP server version 5.08/;
s/^Content-Length: .*/Content-Length: 223/;"
sed -e "$sedcmd" < "$1" > "f1.tmp.$$"
sed -e "$sedcmd" < "$2" > "f2.tmp.$$"
cmp -s "f1.tmp.$$" "f2.tmp.$$"
rv=$?
rm -f "f1.tmp.$$" "f2.tmp.$$"
exit $rv

View File

@ -0,0 +1 @@
get /

View File

@ -0,0 +1,2 @@
HTTP/0.9 200 OK
this is the bozohttpd testsuite ./data/index.html file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
HTTP/1.0 404 Not Found
Content-Type: text/html
Content-Length: 1024
Server: bozohttpd/20140708
<html><head><title>404 Not Found</title></head>
<body><h1>404 Not Found</h1>
/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

View File

@ -0,0 +1 @@
GET / HTTP/1.0

View File

@ -0,0 +1,9 @@
HTTP/1.0 200 OK
Date: Tue, 10 Jul 2001 15:45:36 GMT
Server: bozotic HTTP server version 5.08
Accept-Ranges: bytes
Last-Modified: Tue, 10 Jul 2001 15:50:43 GMT
Content-Type: text/html
Content-Length: 55
this is the bozohttpd testsuite ./data/index.html file

View File

@ -0,0 +1 @@
GET / HTTP/1.1

View File

@ -0,0 +1,11 @@
HTTP/1.1 400 Bad Request
Content-Type: text/html
Content-Length: 229
Server: bozotic HTTP server version 5.08
Allow: GET, HEAD, POST
<html><head><title>400 Bad Request</title></head>
<body><h1>400 Bad Request</h1>
/: <pre>The request was not valid</pre>
<hr><address><a href="http://madrugada.eterna.com.au/">madrugada.eterna.com.au</a></address>
</body></html>

View File

@ -0,0 +1,2 @@
GET / HTTP/1.1
Host:

View File

@ -0,0 +1,10 @@
HTTP/1.1 200 OK
Date: Tue, 10 Jul 2001 15:49:21 GMT
Server: bozotic HTTP server version 5.08
Accept-Ranges: bytes
Last-Modified: Tue, 10 Jul 2001 15:34:33 GMT
Content-Type: text/html
Content-Length: 55
Connection: close
this is the bozohttpd testsuite ./data/index.html file

View File

@ -0,0 +1,2 @@
GET /cgi-bin/..M-@M-/..M-@M-/..M-@M-/..M-@M-/..M-@M-/../winnt/system32/cmd.exe?/c+dir+c:\\ HTTP/1.0

View File

@ -0,0 +1,10 @@
HTTP/1.0 403 Forbidden
Content-Type: text/html
Content-Length: 336
Server: bozohttpd/20030206
<html><head><title>403 Forbidden</title></head>
<body><h1>403 Forbidden</h1>
/cgi-bin/..M-@M-/..M-@M-/..M-@M-/..M-@M-/..M-@M-/../winnt/system32/cmd.exe: <pre>Access to this item has been denied</pre>
<hr><address><a href="http://what-time-is-love.eterna.com.au/">what-time-is-love.eterna.com.au</a></address>
</body></html>

View File

@ -0,0 +1,2 @@
GET /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx HTTP/1.0

View File

@ -0,0 +1,10 @@
HTTP/1.0 404 Not Found
Content-Type: text/html
Content-Length: 335
Server: bozohttpd/5.15
<html><head><title>404 Not Found</title></head>
<body><h1>404 Not Found</h1>
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: <pre>This item has not been found</pre>
<hr><address><a href="http://splode.eterna.com.au/">splode.eterna.com.au</a></address>
</body></html>

View File

@ -0,0 +1,4 @@
GET /file HTTP/1.1
Host:
Range: bytes=0-63

View File

@ -0,0 +1,14 @@
HTTP/1.1 206 Partial Content
Date: Sun, 02 Mar 2008 08:52:03 GMT
Server: bozohttpd/20060710
Accept-Ranges: bytes
Last-Modified: Sun, 02 Mar 2008 08:44:38 GMT
Content-Type: text/plain
Content-Range: bytes 0-63/64
Content-Length: 64
Connection: close
123456781234567
345678903456789
234567892345678
012345670123456

View File

@ -0,0 +1,4 @@
GET /file HTTP/1.1
Host:
Range: bytes=0-31

View File

@ -0,0 +1,12 @@
HTTP/1.1 206 Partial Content
Date: Sun, 02 Mar 2008 08:52:03 GMT
Server: bozohttpd/20060710
Accept-Ranges: bytes
Last-Modified: Sun, 02 Mar 2008 08:44:38 GMT
Content-Type: text/plain
Content-Range: bytes 0-31/64
Content-Length: 32
Connection: close
123456781234567
345678903456789

View File

@ -0,0 +1,4 @@
GET /file HTTP/1.1
Host:
Range: bytes=32-63

View File

@ -0,0 +1,12 @@
HTTP/1.1 206 Partial Content
Date: Sun, 02 Mar 2008 08:52:03 GMT
Server: bozohttpd/20060710
Accept-Ranges: bytes
Last-Modified: Sun, 02 Mar 2008 08:44:38 GMT
Content-Type: text/plain
Content-Range: bytes 32-63/64
Content-Length: 32
Connection: close
234567892345678
012345670123456

View File

@ -0,0 +1,27 @@
#! /bin/sh
test="$1" # partial4000 or partial8000
bozohttpd="$2"
wget="$3"
datadir="$4"
bozotestport=11111
# copy beginning file
cp ./data/bigfile.${test} ./bigfile
# fire up bozohttpd
${bozohttpd} -b -b -I ${bozotestport} -n -s -f ${datadir} &
bozopid=$!
${wget} -c http://localhost:${bozotestport}/bigfile
kill -9 $bozopid
if cmp ./bigfile ./data/bigfile; then
rm -f ./bigfile
exit 0
else
rm -f ./bigfile
exit 1
fi

View File

@ -0,0 +1,140 @@
/* $NetBSD: tilde-luzah-bozo.c,v 1.11 2015/07/16 12:19:23 shm Exp $ */
/* $eterna: tilde-luzah-bozo.c,v 1.16 2011/11/18 09:21:15 mrg Exp $ */
/*
* Copyright (c) 1997-2014 Matthew R. Green
* 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 and
* dedication in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
*/
/* this code implements ~user support for bozohttpd */
#ifndef NO_USER_SUPPORT
#include <sys/param.h>
#include <assert.h>
#include <errno.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bozohttpd.h"
/*
* bozo_user_transform does this:
* - chdir's /~user/public_html
* - returns the rest of the file, index.html appended if required
* - returned malloced file to serve in request->hr_file,
* ala transform_request().
*
* transform_request() is supposed to check that we have user support
* enabled.
*/
int
bozo_user_transform(bozo_httpreq_t *request, int *isindex)
{
bozohttpd_t *httpd = request->hr_httpd;
char c, *s, *file = NULL, *user;
struct passwd *pw;
*isindex = 0;
/* find username */
user = strchr(request->hr_file + 2, '~');
/* this shouldn't happen, but "better paranoid than sorry" */
assert(user != NULL);
user++;
if ((s = strchr(user, '/')) != NULL) {
*s++ = '\0';
c = s[strlen(s)-1];
*isindex = (c == '/' || c == '\0');
}
debug((httpd, DEBUG_OBESE, "looking for user %s",
user));
pw = getpwnam(user);
/* fix this up immediately */
if (s)
s[-1] = '/';
if (pw == NULL) {
(void)bozo_http_error(httpd, 404, request, "no such user");
return 0;
}
debug((httpd, DEBUG_OBESE, "user %s dir %s/%s uid %d gid %d",
pw->pw_name, pw->pw_dir, httpd->public_html,
pw->pw_uid, pw->pw_gid));
if (chdir(pw->pw_dir) < 0) {
bozo_warn(httpd, "chdir1 error: %s: %s", pw->pw_dir,
strerror(errno));
(void)bozo_http_error(httpd, 404, request,
"can't chdir to homedir");
return 0;
}
if (chdir(httpd->public_html) < 0) {
bozo_warn(httpd, "chdir2 error: %s: %s", httpd->public_html,
strerror(errno));
(void)bozo_http_error(httpd, 404, request,
"can't chdir to public_html");
return 0;
}
if (s == NULL || *s == '\0') {
file = bozostrdup(httpd, httpd->index_html);
} else {
file = bozomalloc(httpd, strlen(s) +
(*isindex ? strlen(httpd->index_html) + 1 : 1));
strcpy(file, s);
if (*isindex)
strcat(file, httpd->index_html);
}
/* see transform_request() */
if (*file == '/' || strcmp(file, "..") == 0 ||
strstr(file, "/..") || strstr(file, "../")) {
(void)bozo_http_error(httpd, 403, request, "illegal request");
free(file);
return 0;
}
if (bozo_auth_check(request, file)) {
free(file);
return 0;
}
free(request->hr_file);
request->hr_file = file;
debug((httpd, DEBUG_FAT, "transform_user returning %s under %s", file,
pw->pw_dir));
return 1;
}
#endif /* NO_USER_SUPPORT */