--- /dev/null
+New features with this release, as extensions of the Apache functionality
+(see also more detailed CHANGES file) in the source directory.
+
+*) API for server extensions --- see src/API.html for an overview. Most
+ server functionality (including includes, CGI, and most forms of access
+ control) are actually implemented as API-conformant modules.
+
+ The API is not yet quite stable (see src/TODO for some possible
+ changes), but anything done now will be easily adapted for future
+ versions --- after all, we have more modules to adapt than you do.
+
+*) <VirtualHost> is more general --- just about any srm.conf or
+ httpd.conf command can go in a <Virtualhost> section, with the
+ following specific exceptions: ServerType, UserId, GroupId,
+ StartServers, MaxRequestsPerChild, BindAddress, PidFile,
+ TypesConfig, ServerRoot.
+
+*) Support for content negotiation of languages through MultiViews
+ (*.fr, *.de, *.en suffixes), via the new AddLanguage and LanguagePriority
+ commands (code written by Francois Guillaume).
+
+*) Significant internal cleanups and rearrangements. The two externally
+ visible consequences of this are that just about all of the unchecked
+ fixed limits are gone, and that the server is somewhat pickier about
+ config file syntax (noting and complaining about extraneous command
+ arguments or other stuff at the end of command lines).
+
+*) XBITHACK is a run-time option, and can be selectively enabled per
+ directory --- the -DXBITHACK compile-time option just changes the
+ default. The command which configures it is "XBitHack", which is
+ allowed everywhere "Options" is; this takes an argument ---
+ "XBitHack Off" turns it off; "XBitHack On" gets you the NCSA
+ -DXBITHACK behavior; and "XBitHack Full" gets you the Apache GXBIT
+ stuff on top of that. (-DXBITHACK makes "Full" the default;
+ otherwise, it defaults "Off").
+
+*) TransferLog can specify a program which gets the log entries piped to it,
+ a la 'TransferLog "| /var/www/my-perl-script -arg valu"' --- this should
+ give the same SIGTERM/pause/SIGKILL treatment to the logging process on
+ server restarts that a CGI script gets on an aborted request. NB the
+ server is counting on the logging process to work, and will probably hang
+ or worse if it dies.
+
+We also have a few experimental modules which indicate directions for
+a future release (NB these experimental, meaning they haven't been
+tested as much as the rest of the code here; also, they are not in
+final form yet, and what appears as supported may not be quite what
+you see now, though it will support at least the same functionality):
+
+*) Configurable logging module --- this is a replacement for the
+ standard plane-jane Common Log Format code, which supports a
+ LogFormat directive which allows you to control the formatting of
+ entries in the TransferLog, and add some new items if you like (in
+ particular, Referer and User-Agent).
+
+*) The optional dld module is a proof-of-concept piece of code which
+ loads other modules into the server as it is configuring itself (the
+ first time only --- for now, rereading the config files cannot
+ affect the state of loaded modules), using the GNU dynamic linking
+ library, DLD. It isn't compiled into the server by default, since
+ not everyone has DLD, but it works when I try it. (Famous last
+ words).
+
+ This module defines two commands:
+
+ LoadModule module_sym filename
+ LoadFile filename filename filename...
+
+ LoadModule tells the server to link in the file "filename", and add
+ the module structure named "module_sym" to the list of active
+ modules (this is the "foo_module" in "module foo_module = {..." at
+ the bottom of all the mod_*.c files).
+
+ LoadFile links with additional object files or libraries which may
+ be required for some module to work. Filenames are taken relative
+ to ServerRoot unless they begin with '/'. Note that for some
+ reason, "LoadFile /lib/libc.a" seems to be required for just about
+ everything.
+
+ NB that DLD needs to read the symbol table out of the server binary
+ when starting up; these commands will fail if the server can't find
+ its own binary when it starts up, or if that binary is stripped.
+
+ Sample usage:
+
+ LoadModule ai_backcompat_module modules/mod_ai_backcompat.o
+ LoadFile /lib/libc.a
+
+ (assuming mod_ai_backcompat.o is in fact in the 'modules'
+ subdirectory of ServerRoot).
+
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+
--- /dev/null
+ Apache
+ Version 1.0 (and up)
+
+What is it?
+-----------
+
+Apache is an HTTP server designed as a plug-in replacement for the NCSA
+server version 1.3 (or 1.4). It fixes numerous bugs in the NCSA server and
+includes many frequently requested new features, and has an API which
+allows it to be extended to meet users' needs more easily.
+
+Documentation
+-------------
+
+All the documentation is on-line on the WWW, via <URL:http://www.apache.org/>.
+
+Installation
+------------
+
+This program is distributed in source form only. In order to compile
+it, you must set compile-time options (in particular, system type) for
+your system by editing a Configuration file, run a script which generates
+a Makefile and a small piece of C code, and then compile it.
+
+For instructions on compilation, see the file 'INSTALL' in the src/ directory.
+
+After compilation, you will have a binary called "httpd" in the src/
+directory. If you received a binary distribution of apache, you
+should have this file already.
+
+The next step is to edit the configuration files for the server. In
+the subdirectory called "conf" you should find distribution versions
+of the three configuration files: srm.conf-dist, access.conf-dist, and
+httpd.conf-dist. Copy them to srm.conf, access.conf, httpd.conf
+respectively.
+
+First edit httpd.conf. This sets up general attributes about the
+server - the port number, the user it runs as, etc. Next edit the
+srm.conf file - this sets up the root of the document tree, special
+functions like server-parsed HTML or internal imagemap parsing, etc.
+Finally, edit the access.conf file to at least set the base cases of
+access. Documentation for all of these is located at
+<URL:http://www.apache.org/docs/>.
+
+Finally, make a call to httpd, with a -f to the full path to the
+httpd.conf file. I.e., the common case:
+
+ /usr/local/etc/apache/src/httpd -f /usr/local/etc/apache/conf/httpd.conf
+
+And voila! The server should be running.
+
+By default the srm.conf and access.conf files are located by name - to
+specifically call them by other names, use the AccessConfig and
+ResourceConfig directives in httpd.conf.
+
+The Latest Version
+------------------
+
+Details of the latest version are in the apache project page (above).
+The most recent distribution is also available by anonymous ftp
+from ftp.ast.cam.ac.uk in the directory /pub/WWW/apache.
+
+Licencing
+---------
+
+Please see the file called LICENSE.
+
--- /dev/null
+#!/bin/sh
+
+ARCHIE=/usr/local/bin/archie
+
+
+echo Content-type: text/html
+echo
+
+if [ -x $ARCHIE ]; then
+ if [ $# = 0 ]; then
+ cat << EOM
+<TITLE>Archie Gateway</TITLE>
+<H1>Archie Gateway</H1>
+
+<ISINDEX>
+
+This is a gateway to archie. Type search query in your browser's search
+dialog.<P>
+EOM
+ else
+ echo \<PRE\>
+ $ARCHIE "$*"
+ fi
+else
+ echo Cannot find archie on this system.
+fi
+
--- /dev/null
+#!/bin/sh
+
+CAL=/bin/cal
+
+echo Content-type: text/html
+echo
+
+if [ -x $CAL ]; then
+ if [ $# = 0 ]; then
+ cat << EOM
+<TITLE>Calendar</TITLE>
+<H1>Calendar</H1>
+
+<ISINDEX>
+
+To look up a calendar month, type the month followed by a space then the year.<P>
+Example: <code>3 1993</code> would give the calendar for March 1993.
+
+EOM
+ else
+ echo \<PRE\>
+ $CAL $*
+ fi
+else
+ echo Cannot find cal on this system.
+fi
+
+
--- /dev/null
+#!/bin/sh
+
+DATE=/bin/date
+
+echo Content-type: text/plain
+echo
+
+if [ -x $DATE ]; then
+ $DATE
+else
+ echo Cannot find date command on this system.
+fi
+
+
--- /dev/null
+#!/bin/sh
+
+FINGER=/usr/ucb/finger
+
+echo Content-type: text/html
+echo
+
+if [ -x $FINGER ]; then
+ if [ $# = 0 ]; then
+ cat << EOM
+<TITLE>Finger Gateway</TITLE>
+<H1>Finger Gateway</H1>
+
+<ISINDEX>
+
+This is a gateway to "finger". Type a user@host combination in your browser's
+search dialog.<P>
+EOM
+ else
+ echo \<PRE\>
+ $FINGER "$*"
+ fi
+else
+ echo Cannot find finger on this system.
+fi
+
--- /dev/null
+#!/bin/sh
+
+FORTUNE=/usr/games/fortune
+
+echo Content-type: text/plain
+echo
+
+if [ -x $FORTUNE ]; then
+ $FORTUNE
+else
+ echo Cannot find fortune command on this system.
+fi
+
+
--- /dev/null
+#!/bin/sh
+
+echo HTTP/1.0 200 OK
+echo Content-type: text/plain
+echo Server: $SERVER_SOFTWARE
+echo
+
+echo CGI/1.0 test script report:
+echo
+
+echo argc is $#. argv is "$*".
+echo
+
+echo SERVER_SOFTWARE = $SERVER_SOFTWARE
+echo SERVER_NAME = $SERVER_NAME
+echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE
+echo SERVER_PROTOCOL = $SERVER_PROTOCOL
+echo SERVER_PORT = $SERVER_PORT
+echo REQUEST_METHOD = $REQUEST_METHOD
+echo HTTP_ACCEPT = "$HTTP_ACCEPT"
+echo PATH_INFO = $PATH_INFO
+echo PATH_TRANSLATED = $PATH_TRANSLATED
+echo SCRIPT_NAME = $SCRIPT_NAME
+echo QUERY_STRING = $QUERY_STRING
+echo REMOTE_HOST = $REMOTE_HOST
+echo REMOTE_ADDR = $REMOTE_ADDR
+echo REMOTE_USER = $REMOTE_USER
+echo CONTENT_TYPE = $CONTENT_TYPE
+echo CONTENT_LENGTH = $CONTENT_LENGTH
--- /dev/null
+#!/bin/sh
+
+echo Content-type: text/plain
+echo
+
+echo CGI/1.0 test script report:
+echo
+
+echo argc is $#. argv is "$*".
+echo
+
+echo SERVER_SOFTWARE = $SERVER_SOFTWARE
+echo SERVER_NAME = $SERVER_NAME
+echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE
+echo SERVER_PROTOCOL = $SERVER_PROTOCOL
+echo SERVER_PORT = $SERVER_PORT
+echo REQUEST_METHOD = $REQUEST_METHOD
+echo HTTP_ACCEPT = "$HTTP_ACCEPT"
+echo PATH_INFO = "$PATH_INFO"
+echo PATH_TRANSLATED = "$PATH_TRANSLATED"
+echo SCRIPT_NAME = "$SCRIPT_NAME"
+echo QUERY_STRING = "$QUERY_STRING"
+echo REMOTE_HOST = $REMOTE_HOST
+echo REMOTE_ADDR = $REMOTE_ADDR
+echo REMOTE_USER = $REMOTE_USER
+echo AUTH_TYPE = $AUTH_TYPE
+echo CONTENT_TYPE = $CONTENT_TYPE
+echo CONTENT_LENGTH = $CONTENT_LENGTH
--- /dev/null
+#!/usr/local/bin/tclsh
+# tcl-cgi.tcl
+# robert.bagwill@nist.gov, no warranty, no rights reserved
+# print out command line args, stdin, and environment variables
+#
+set envvars {SERVER_SOFTWARE SERVER_NAME GATEWAY_INTERFACE SERVER_PROTOCOL SERVER_PORT REQUEST_METHOD PATH_INFO PATH_TRANSLATED SCRIPT_NAME QUERY_STRING REMOTE_HOST REMOTE_ADDR REMOTE_USER AUTH_TYPE CONTENT_TYPE CONTENT_LENGTH HTTP_ACCEPT}
+
+puts "Content-type: text/HTML\n"
+puts "<HTML>"
+puts "<HEAD>"
+puts "<TITLE>CGI/1.0 TCL script report:</TITLE>"
+puts "</HEAD>"
+
+puts "<BODY>"
+puts "<H1>Command Line Arguments</H1>"
+puts "argc is $argc. argv is $argv."
+puts ""
+
+puts "<H1>Message</H1>"
+puts "<PRE>"
+set message [split [read stdin $env(CONTENT_LENGTH)] &]
+foreach pair $message {
+ set name [lindex [split $pair =] 0]
+ set val [lindex [split $pair =] 1]
+ regsub -all {\+} $val { } val
+ # kludge to unescape chars
+ regsub -all {\%0A} $val \n\t val
+ regsub -all {\%2C} $val {,} val
+ regsub -all {\%27} $val {'} val
+ puts "$name\t= $val"
+}
+puts "</PRE>"
+
+puts "<H1>Environment Variables</H1>"
+puts "<DL>"
+foreach var $envvars {
+ if {[info exists env($var)]} {
+ puts -nonewline "<DT>$var"
+ eval {set val $env($var)}
+ if {[llength $val] > 1} {
+ puts "<DD>"
+ foreach subval [lsort $val] {
+ puts "$subval"
+ }
+ } else {
+ puts "<DD>$val"
+ }
+ }
+}
+puts "</DL>"
+puts "</BODY>"
+puts "</HTML>"
+######################
+# end of tcl-cgi.tcl
+######################
+
--- /dev/null
+#!/bin/sh
+
+UPTIME=/usr/ucb/uptime
+
+echo Content-type: text/plain
+echo
+
+if [ -x $UPTIME ]; then
+ $UPTIME
+else
+ echo Cannot find uptime command on this system.
+fi
+
+
--- /dev/null
+#!/usr/local/bin/perl
+#
+# wais.pl -- WAIS search interface
+#
+# wais.pl,v 1.2 1994/04/10 05:33:29 robm Exp
+#
+# Tony Sanders <sanders@bsdi.com>, Nov 1993
+#
+# Example configuration (in local.conf):
+# map topdir wais.pl &do_wais($top, $path, $query, "database", "title")
+#
+
+$waisq = "/usr/local/bin/waisq";
+$waisd = "/u/Web/wais-sources";
+$src = "www";
+$title = "NCSA httpd documentation";
+
+sub send_index {
+ print "Content-type: text/html\n\n";
+
+ print "<HEAD>\n<TITLE>Index of ", $title, "</TITLE>\n</HEAD>\n";
+ print "<BODY>\n<H1>", $title, "</H1>\n";
+
+ print "This is an index of the information on this server. Please\n";
+ print "type a query in the search dialog.\n<P>";
+ print "You may use compound searches, such as: <CODE>environment AND cgi</CODE>\n";
+ print "<ISINDEX>";
+}
+
+sub do_wais {
+# local($top, $path, $query, $src, $title) = @_;
+
+ do { &'send_index; return; } unless defined @ARGV;
+ local(@query) = @ARGV;
+ local($pquery) = join(" ", @query);
+
+ print "Content-type: text/html\n\n";
+
+ open(WAISQ, "-|") || exec ($waisq, "-c", $waisd,
+ "-f", "-", "-S", "$src.src", "-g", @query);
+
+ print "<HEAD>\n<TITLE>Search of ", $title, "</TITLE>\n</HEAD>\n";
+ print "<BODY>\n<H1>", $title, "</H1>\n";
+
+ print "Index \`$src\' contains the following\n";
+ print "items relevant to \`$pquery\':<P>\n";
+ print "<DL>\n";
+
+ local($hits, $score, $headline, $lines, $bytes, $type, $date);
+ while (<WAISQ>) {
+ /:score\s+(\d+)/ && ($score = $1);
+ /:number-of-lines\s+(\d+)/ && ($lines = $1);
+ /:number-of-bytes\s+(\d+)/ && ($bytes = $1);
+ /:type "(.*)"/ && ($type = $1);
+ /:headline "(.*)"/ && ($headline = $1); # XXX
+ /:date "(\d+)"/ && ($date = $1, $hits++, &docdone);
+ }
+ close(WAISQ);
+ print "</DL>\n";
+
+ if ($hits == 0) {
+ print "Nothing found.\n";
+ }
+ print "</BODY>\n";
+}
+
+sub docdone {
+ if ($headline =~ /Search produced no result/) {
+ print "<HR>";
+ print $headline, "<P>\n<PRE>";
+# the following was &'safeopen
+ open(WAISCAT, "$waisd/$src.cat") || die "$src.cat: $!";
+ while (<WAISCAT>) {
+ s#(Catalog for database:)\s+.*#$1 <A HREF="/$top/$src.src">$src.src</A>#;
+ s#Headline:\s+(.*)#Headline: <A HREF="$1">$1</A>#;
+ print;
+ }
+ close(WAISCAT);
+ print "\n</PRE>\n";
+ } else {
+ print "<DT><A HREF=\"$headline\">$headline</A>\n";
+ print "<DD>Score: $score, Lines: $lines, Bytes: $bytes\n";
+ }
+ $score = $headline = $lines = $bytes = $type = $date = '';
+}
+
+open (STDERR,"> /dev/null");
+eval '&do_wais';
--- /dev/null
+# For gcc
+CC= gcc
+# For ANSI compilers
+#CC= cc
+
+#For Optimization
+#CFLAGS= -O2
+#For debugging
+CFLAGS= -g
+
+RM= /bin/rm -f
+#--- You shouldn't have to edit anything else. ---
+
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
+all: query post-query imagemap jj phf
+
+ibm:
+ make all CC=gcc
+
+sun:
+ make all CC=gcc
+
+hp:
+ make all CC=gcc
+
+sgi:
+ make all CC=cc
+
+decmips:
+ make all CC=cc
+
+decaxp:
+ make all CC=cc
+
+tar: query post-query imagemap jj phf
+ $(RM) post-query.o util.o imagerect.o jj.o phf.o
+
+post-query: post-query.o util.o
+ $(CC) post-query.o util.o -o ../cgi-bin/post-query
+
+query: query.o util.o
+ $(CC) query.o util.o -o ../cgi-bin/query
+
+imagemap: imagemap.o
+ $(CC) imagemap.o -o ../cgi-bin/imagemap
+
+jj: jj.o util.o
+ $(CC) jj.o util.o -o ../cgi-bin/jj
+
+phf: phf.o util.o
+ $(CC) phf.o util.o -o ../cgi-bin/phf
+
+change-passwd: change-passwd.o util.o
+ $(CC) change-passwd.o util.o -o ../cgi-bin/change-passwd
+
+
+clean:
+ rm -f *.o ../cgi-bin/post-query ../cgi-bin/query ../cgi-bin/change-passwd ../cgi-bin/phf ../cgi-bin/jj ../cgi-bin/imagemap
+
--- /dev/null
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/signal.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define USER_FILE "/usr/local/etc/httpd/conf/.htpasswd"
+#define WIZARD "surobm"
+
+char *makeword(char *line, char stop);
+char *fmakeword(FILE *f, char stop, int *len);
+char x2c(char *what);
+void unescape_url(char *url);
+void plustospace(char *str);
+
+char *crypt(char *pw, char *salt); /* why aren't these prototyped in include */
+
+
+char *tn;
+
+/* From local_passwd.c (C) Regents of Univ. of California blah blah */
+static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+to64(s, v, n)
+ register char *s;
+ register long v;
+ register int n;
+{
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+void change_password(char *user, char *pw, FILE *f) {
+ char *cpw, salt[3];
+
+ (void)srand((int)time((time_t *)NULL));
+ to64(&salt[0],rand(),2);
+ cpw = crypt(pw,salt);
+ free(pw);
+ fprintf(f,"%s:%s\n",user,cpw);
+}
+
+void putline(FILE *f,char *l) {
+ int x;
+
+ for(x=0;l[x];x++) fputc(l[x],f);
+ fputc('\n',f);
+}
+
+main(int argc, char *argv[]) {
+ register int x;
+ int cl,found,create;
+ char *u,*t1,*t2,*p1,*p2,*user, command[256], line[256], l[256], w[256];
+ FILE *tfp,*f;
+
+ tn = NULL;
+
+ printf("Content-type: text/html%c%c",10,10);
+
+ if(strcmp(getenv("REQUEST_METHOD"),"POST")) {
+ printf("This script should be referenced with a METHOD of POST.\n");
+ printf("If you don't understand this, see this ");
+ printf("<A HREF=\"http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html\">forms overview</A>.%c",10);
+ exit(1);
+ }
+ if(strcmp(getenv("CONTENT_TYPE"),"application/x-www-form-urlencoded")) {
+ printf("This script can only be used to decode form results. \n");
+ exit(1);
+ }
+ cl = atoi(getenv("CONTENT_LENGTH"));
+
+ user=NULL;
+ p1=NULL;
+ p2=NULL;
+ create=0;
+ for(x=0;cl && (!feof(stdin));x++) {
+ t1 = fmakeword(stdin,'&',&cl);
+ t2 = makeword(t1,'=');
+ unescape_url(t1);
+ unescape_url(t2);
+ if(!strcmp(t2,"user")) {
+ if(!user)
+ user = t1;
+ else {
+ printf("This script was accessed from the wrong form.\n");
+ exit(1);
+ }
+ }
+ else if(!strcmp(t2,"newpasswd1")) {
+ if(!p1)
+ p1 = t1;
+ else {
+ printf("This script was accessed from the wrong form.\n");
+ exit(1);
+ }
+ }
+ else if(!strcmp(t2,"newpasswd2")) {
+ if(!p2)
+ p2 = t1;
+ else {
+ printf("This script was accessed from the wrong form.\n");
+ exit(1);
+ }
+ }
+ else {
+ printf("This script was accessed from the wrong form.\n");
+ printf("Unrecognized directive %s.\n",t2);
+ exit(1);
+ }
+ free(t2);
+ }
+ u=getenv("REMOTE_USER");
+ if((strcmp(u,WIZARD)) && (strcmp(user,u))) {
+ printf("<TITLE>User Mismatch</TITLE>");
+ printf("<H1>User Mismatch</H1>");
+ printf("The username you gave does not correspond with the ");
+ printf("user you authenticated as.\n");
+ exit(1);
+ }
+ if(strcmp(p1,p2)) {
+ printf("<TITLE>Password Mismatch</TITLE>");
+ printf("<H1>Password Mismatch</H1>");
+ printf("The two copies of your the password do not match. Please");
+ printf(" try again.");
+ exit(1);
+ }
+
+ tn = tmpnam(NULL);
+ if(!(tfp = fopen(tn,"w"))) {
+ fprintf(stderr,"Could not open temp file.\n");
+ exit(1);
+ }
+
+ if(!(f = fopen(USER_FILE,"r"))) {
+ fprintf(stderr,
+ "Could not open passwd file for reading.\n",USER_FILE);
+ exit(1);
+ }
+
+ found = 0;
+ while(!(getline(line,256,f))) {
+ if(found || (line[0] == '#') || (!line[0])) {
+ putline(tfp,line);
+ continue;
+ }
+ strcpy(l,line);
+ getword(w,l,':');
+ if(strcmp(user,w)) {
+ putline(tfp,line);
+ continue;
+ }
+ else {
+ change_password(user,p1,tfp);
+ found=1;
+ }
+ }
+ if((!found) && (create))
+ change_password(user,p1,tfp);
+ fclose(f);
+ fclose(tfp);
+ sprintf(command,"cp %s %s",tn,USER_FILE);
+ system(command);
+ unlink(tn);
+ printf("<TITLE>Successful Change</TITLE>");
+ printf("<H1>Successful Change</H1>");
+ printf("Your password has been successfully changed.<P>");
+ exit(0);
+}
--- /dev/null
+/*
+** mapper 1.2
+** 7/26/93 Kevin Hughes, kevinh@pulua.hcc.hawaii.edu
+** "macmartinized" polygon code copyright 1992 by Eric Haines, erich@eye.com
+** All suggestions, help, etc. gratefully accepted!
+**
+** 1.1 : Better formatting, added better polygon code.
+** 1.2 : Changed isname(), added config file specification.
+**
+** 11/13/93: Rob McCool, robm@ncsa.uiuc.edu
+**
+** 1.3 : Rewrote configuration stuff for NCSA /htbin script
+**
+** 12/05/93: Rob McCool, robm@ncsa.uiuc.edu
+**
+** 1.4 : Made CGI/1.0 compliant.
+**
+** 06/27/94: Chris Hyams, cgh@rice.edu
+** Based on an idea by Rick Troth (troth@rice.edu)
+**
+** 1.5 : Imagemap configuration file in PATH_INFO. Backwards compatible.
+**
+** Old-style lookup in imagemap table:
+** <a href="http://foo.edu/cgi-bin/imagemap/oldmap">
+**
+** New-style specification of mapfile relative to DocumentRoot:
+** <a href="http://foo.edu/cgi-bin/imagemap/path/for/new.map">
+**
+** New-style specification of mapfile in user's public HTML directory:
+** <a href="http://foo.edu/cgi-bin/imagemap/~username/path/for/new.map">
+**
+** 07/11/94: Craig Milo Rogers, Rogers@ISI.Edu
+**
+** 1.6 : Added "point" datatype: the nearest point wins. Overrides "default".
+**
+** 08/28/94: Carlos Varela, cvarela@ncsa.uiuc.edu
+**
+** 1.7 : Fixed bug: virtual URLs are now understood.
+** Better error reporting when not able to open configuration file.
+**
+** 03/07/95: Carlos Varela, cvarela@ncsa.uiuc.edu
+**
+** 1.8 : Fixed bug (strcat->sprintf) when reporting error.
+** Included getline() function from util.c in NCSA httpd distribution.
+**
+*/
+
+#include <stdio.h>
+#include <string.h>
+#ifndef pyr
+#include <stdlib.h>
+#else
+#include <ctype.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define CONF_FILE "/usr/local/etc/httpd/conf/imagemap.conf"
+
+#define MAXLINE 500
+#define MAXVERTS 100
+#define X 0
+#define Y 1
+#define LF 10
+#define CR 13
+
+int isname(char);
+
+int main(int argc, char **argv)
+{
+ char input[MAXLINE], *mapname, def[MAXLINE], conf[MAXLINE], errstr[MAXLINE];
+ double testpoint[2], pointarray[MAXVERTS][2];
+ int i, j, k;
+ FILE *fp;
+ char *t;
+ double dist, mindist;
+ int sawpoint = 0;
+
+ if (argc != 2)
+ servererr("Wrong number of arguments, client may not support ISMAP.");
+ mapname=getenv("PATH_INFO");
+
+ if((!mapname) || (!mapname[0]))
+ servererr("No map name given. Please read the <A HREF=\"http://hoohoo.ncsa.uiuc.edu/docs/setup/admin/Imagemap.html\">instructions</A>.<P>");
+
+
+ mapname++;
+ if(!(t = strchr(argv[1],',')))
+ servererr("Your client doesn't support image mapping properly.");
+ *t++ = '\0';
+ testpoint[X] = (double) atoi(argv[1]);
+ testpoint[Y] = (double) atoi(t);
+
+ /*
+ * if the mapname contains a '/', it represents a unix path -
+ * we get the translated path, and skip reading the configuration file.
+ */
+ if (strchr(mapname,'/')) {
+ strcpy(conf,getenv("PATH_TRANSLATED"));
+ goto openconf;
+ }
+
+ if ((fp = fopen(CONF_FILE, "r")) == NULL){
+ sprintf(errstr, "Couldn't open configuration file: %s", CONF_FILE);
+ servererr(errstr);
+ }
+
+ while(!(getline(input,MAXLINE,fp))) {
+ char confname[MAXLINE];
+ if((input[0] == '#') || (!input[0]))
+ continue;
+ for(i=0;isname(input[i]) && (input[i] != ':');i++)
+ confname[i] = input[i];
+ confname[i] = '\0';
+ if(!strcmp(confname,mapname))
+ goto found;
+ }
+ /*
+ * if mapname was not found in the configuration file, it still
+ * might represent a file in the server root directory -
+ * we get the translated path, and check to see if a file of that
+ * name exists, jumping to the opening of the map file if it does.
+ */
+ if(feof(fp)) {
+ struct stat sbuf;
+ strcpy(conf,getenv("PATH_TRANSLATED"));
+ if (!stat(conf,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
+ goto openconf;
+ else
+ servererr("Map not found in configuration file.");
+ }
+
+ found:
+ fclose(fp);
+ while(isspace(input[i]) || input[i] == ':') ++i;
+
+ for(j=0;input[i] && isname(input[i]);++i,++j)
+ conf[j] = input[i];
+ conf[j] = '\0';
+
+ openconf:
+ if(!(fp=fopen(conf,"r"))){
+ sprintf(errstr, "Couldn't open configuration file: %s", conf);
+ servererr(errstr);
+ }
+
+ while(!(getline(input,MAXLINE,fp))) {
+ char type[MAXLINE];
+ char url[MAXLINE];
+ char num[10];
+
+ if((input[0] == '#') || (!input[0]))
+ continue;
+
+ type[0] = '\0';url[0] = '\0';
+
+ for(i=0;isname(input[i]) && (input[i]);i++)
+ type[i] = input[i];
+ type[i] = '\0';
+
+ while(isspace(input[i])) ++i;
+ for(j=0;input[i] && isname(input[i]);++i,++j)
+ url[j] = input[i];
+ url[j] = '\0';
+
+ if(!strcmp(type,"default") && !sawpoint) {
+ strcpy(def,url);
+ continue;
+ }
+
+ k=0;
+ while (input[i]) {
+ while (isspace(input[i]) || input[i] == ',')
+ i++;
+ j = 0;
+ while (isdigit(input[i]))
+ num[j++] = input[i++];
+ num[j] = '\0';
+ if (num[0] != '\0')
+ pointarray[k][X] = (double) atoi(num);
+ else
+ break;
+ while (isspace(input[i]) || input[i] == ',')
+ i++;
+ j = 0;
+ while (isdigit(input[i]))
+ num[j++] = input[i++];
+ num[j] = '\0';
+ if (num[0] != '\0')
+ pointarray[k++][Y] = (double) atoi(num);
+ else {
+ fclose(fp);
+ servererr("Missing y value.");
+ }
+ }
+ pointarray[k][X] = -1;
+ if(!strcmp(type,"poly"))
+ if(pointinpoly(testpoint,pointarray))
+ sendmesg(url);
+ if(!strcmp(type,"circle"))
+ if(pointincircle(testpoint,pointarray))
+ sendmesg(url);
+ if(!strcmp(type,"rect"))
+ if(pointinrect(testpoint,pointarray))
+ sendmesg(url);
+ if(!strcmp(type,"point")) {
+ /* Don't need to take square root. */
+ dist = ((testpoint[X] - pointarray[0][X])
+ * (testpoint[X] - pointarray[0][X]))
+ + ((testpoint[Y] - pointarray[0][Y])
+ * (testpoint[Y] - pointarray[0][Y]));
+ /* If this is the first point, or the nearest, set the default. */
+ if ((! sawpoint) || (dist < mindist)) {
+ mindist = dist;
+ strcpy(def,url);
+ }
+ sawpoint++;
+ }
+ }
+ if(def[0])
+ sendmesg(def);
+ servererr("No default specified.");
+}
+
+sendmesg(char *url)
+{
+ if (strchr(url, ':')) /*** It is a full URL ***/
+ printf("Location: ");
+ else /*** It is a virtual URL ***/
+ printf("Location: http://%s:%s", getenv("SERVER_NAME"),
+ getenv("SERVER_PORT"));
+
+ printf("%s%c%c",url,10,10);
+ printf("This document has moved <A HREF=\"%s\">here</A>%c",url,10);
+ exit(1);
+}
+
+int pointinrect(double point[2], double coords[MAXVERTS][2])
+{
+ return ((point[X] >= coords[0][X] && point[X] <= coords[1][X]) &&
+ (point[Y] >= coords[0][Y] && point[Y] <= coords[1][Y]));
+}
+
+int pointincircle(double point[2], double coords[MAXVERTS][2])
+{
+ int radius1, radius2;
+
+ radius1 = ((coords[0][Y] - coords[1][Y]) * (coords[0][Y] -
+ coords[1][Y])) + ((coords[0][X] - coords[1][X]) * (coords[0][X] -
+ coords[1][X]));
+ radius2 = ((coords[0][Y] - point[Y]) * (coords[0][Y] - point[Y])) +
+ ((coords[0][X] - point[X]) * (coords[0][X] - point[X]));
+ return (radius2 <= radius1);
+}
+
+int pointinpoly(double point[2], double pgon[MAXVERTS][2])
+{
+ int i, numverts, inside_flag, xflag0;
+ int crossings;
+ double *p, *stop;
+ double tx, ty, y;
+
+ for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++)
+ ;
+ numverts = i;
+ crossings = 0;
+
+ tx = point[X];
+ ty = point[Y];
+ y = pgon[numverts - 1][Y];
+
+ p = (double *) pgon + 1;
+ if ((y >= ty) != (*p >= ty)) {
+ if ((xflag0 = (pgon[numverts - 1][X] >= tx)) ==
+ (*(double *) pgon >= tx)) {
+ if (xflag0)
+ crossings++;
+ }
+ else {
+ crossings += (pgon[numverts - 1][X] - (y - ty) *
+ (*(double *) pgon - pgon[numverts - 1][X]) /
+ (*p - y)) >= tx;
+ }
+ }
+
+ stop = pgon[numverts];
+
+ for (y = *p, p += 2; p < stop; y = *p, p += 2) {
+ if (y >= ty) {
+ while ((p < stop) && (*p >= ty))
+ p += 2;
+ if (p >= stop)
+ break;
+ if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
+ if (xflag0)
+ crossings++;
+ }
+ else {
+ crossings += (*(p - 3) - (*(p - 2) - ty) *
+ (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
+ }
+ }
+ else {
+ while ((p < stop) && (*p < ty))
+ p += 2;
+ if (p >= stop)
+ break;
+ if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
+ if (xflag0)
+ crossings++;
+ }
+ else {
+ crossings += (*(p - 3) - (*(p - 2) - ty) *
+ (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
+ }
+ }
+ }
+ inside_flag = crossings & 0x01;
+ return (inside_flag);
+}
+
+servererr(char *msg)
+{
+ printf("Content-type: text/html%c%c",10,10);
+ printf("<title>Mapping Server Error</title>");
+ printf("<h1>Mapping Server Error</h1>");
+ printf("This server encountered an error:<p>");
+ printf("%s", msg);
+ exit(-1);
+}
+
+int isname(char c)
+{
+ return (!isspace(c));
+}
+
+int getline(char *s, int n, FILE *f) {
+ register int i=0;
+
+ while(1) {
+ s[i] = (char)fgetc(f);
+
+ if(s[i] == CR)
+ s[i] = fgetc(f);
+
+ if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) {
+ s[i] = '\0';
+ return (feof(f) ? 1 : 0);
+ }
+ ++i;
+ }
+}
+
--- /dev/null
+/*
+ * Submarine ordering form through FAX gateway
+ *
+ * Rob McCool
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 1
+#define JJ_FAX "JIMMY_JOHNS_3440603@fax.uiuc.edu"
+#else
+#define JJ_FAX "robm@imsa.edu"
+#endif
+
+#define PASSWORD "SDGROCKS"
+#define LF 10
+
+void getword(char *word, char *line, char stop);
+char x2c(char *what);
+void unescape_url(char *url);
+void plustospace(char *str);
+
+
+char *sublist[] = {
+ "The Pepe Gourmet Sub",
+ "Big John Gourmet Sub",
+ "Sorry Charlie Gourmet Sub",
+ "Turkey Tom Gourmet Sub",
+ "Vito Gourmet Sub",
+ "Vegetarian Gourmet Sub",
+ "Gourmet Smoked Ham Club",
+ "Billy Club",
+ "Italian Night Club",
+ "Hunter's Club",
+ "Country Club",
+ "The Beach Club"
+ };
+
+char *slimlist[] = {
+ "Ham and Cheese",
+ "Rare Roast Beef",
+ "California Tuna",
+ "Sliced Turkey",
+ "Salami and Capacola",
+ "Double Provolone"
+ };
+
+char *sidelist[] = {
+ "Lay's Potato Chips",
+ "Jumbo Kosher Dill"
+ };
+
+char *poplist[] = {
+ "Pepsi",
+ "Mountain Dew",
+ "Diet Pepsi",
+ "Iced Tea"
+ };
+
+void dump_form() {
+ printf("<TITLE>Form for Submarine Order</TITLE>%c",LF);
+ printf("<H1>Jimmy John's Submarine Order Form</H1>%c",LF);
+ printf("This form will send a faxed order to Jimmy John's in Champaign. Proper password is requred%c",LF);
+ printf("for order to be submitted, otherwise a copy of the order that would have been submitted will%c",LF);
+ printf("will be displayed.<P>%c",LF);
+ printf("<HR>%c",LF);
+ printf("<FORM ACTION=\"http://hoohoo.ncsa.uiuc.edu:80/htbin/jj\">%c",LF);
+ printf("Password: <INPUT TYPE=\"text\" NAME=\"pwd\" MAXLENGTH=\"20\"><P>%c",LF);
+ printf("<H3>Sub Type</H3>%c",LF);
+ printf("Select which you would like of the following:<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"0\">%s:%c",sublist[0],LF);
+ printf("Smoked virginia ham and provolone cheese topped with lettuce, tomato, and mayo.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"1\">%s:%c",sublist[1],LF);
+ printf("Medium rare shaved roast beef topped with mayo, lettuce, and tomato.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"2\">%s:%c",sublist[2],LF);
+ printf("Tuna, mixed with celery, onions, and sauce, topped with lettuce,%c",LF);
+ printf("tomato, and alfalfa sprouts.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"3\">%s:%c",sublist[3],LF);
+ printf("Turkey breast topped with lettuce, mayo, alfalfa sprouts, and mayo.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"4\">%s:%c",sublist[4],LF);
+ printf("Genoa salami and provolone cheese topped with capacola, onion, lettuce, tomato, and Italian sauce.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"5\">%s:%c",sublist[5],LF);
+ printf("Layers of provolone cheese, separated by avocado, sprouts, lettuce, tomato, and mayo.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"6\">%s:%c",sublist[6],LF);
+ printf("1/4 pound of smoked ham, provolone cheese, topped with lettuce,%c",LF);
+ printf("tomato, and mayo.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"7\">%s:%c",sublist[7],LF);
+ printf("Shaved roast beef, provolone cheese, french dijon mustard, topped with shaved ham, lettuce,%c",LF);
+ printf("tomato, and mayo.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"8\">%s:%c",sublist[8],LF);
+ printf("Genoa salami, Italian capacola, smoked ham, and provolone cheese topped with lettuce,%c",LF);
+ printf("tomato, onions, mayo, and Italian sauce.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"9\">%s:%c",sublist[9],LF);
+ printf("1/4 pound of sliced roast beef, provolone cheese, topped with lettuce, tomato, and mayo.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"10\">%s:%c",sublist[10],LF);
+ printf("Turkey breast, smoked ham, and provolonecheese topped with lettuce, tomato, and mayo.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sub\" VALUE=\"11\">%s:%c",sublist[11],LF);
+ printf("Turkey breast, avocado, and cheese topped with lettuce, mayo, alfalfa, and tomato.<P>%c",LF);
+ printf("<H3>Slim Jim Subs</H3>%c",LF);
+ printf("Subs without veggies or sauce.<P>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"slj\" VALUE=\"0\">%s<P>%c",slimlist[0],LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"slj\" VALUE=\"1\">%s<P>%c",slimlist[1],LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"slj\" VALUE=\"2\">%s<P>%c",slimlist[2],LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"slj\" VALUE=\"3\">%s<P>%c",slimlist[3],LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"slj\" VALUE=\"4\">%s<P>%c",slimlist[4],LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"slj\" VALUE=\"5\">%s<P>%c",slimlist[5],LF);
+ printf("<H3>Side orders</H3>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sde\" VALUE=\"0\">%s<P>%c",sidelist[0],LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"sde\" VALUE=\"1\">%s<P>%c",sidelist[1],LF);
+ printf("<H3>Drinks</H3>%c",LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"pop\" VALUE=\"0\">%s<P>%c",poplist[0],LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"pop\" VALUE=\"1\">%s<P>%c",poplist[1],LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"pop\" VALUE=\"2\">%s<P>%c",poplist[2],LF);
+ printf("<INPUT TYPE=\"checkbox\" NAME=\"pop\" VALUE=\"3\">%s<P>%c",poplist[3],LF);
+ printf("<H3>Your Address, Phone Number, and Name</H3>%c",LF);
+ printf("<INPUT TYPE=\"text\" NAME=\"name\" MAXLENGTH=\"32\">Name<P>%c",LF);
+ printf("<INPUT TYPE=\"text\" NAME=\"adr\" MAXLENGTH=\"64\">Address<P>%c",LF);
+ printf("<INPUT TYPE=\"text\" NAME=\"phone\" MAXLENGTH=\"10\">Phone Number<P>%c",LF);
+ printf("<INPUT type=\"submit\">%c",LF);
+ printf("</FORM>%c",LF);
+ exit(0);
+}
+
+void print_error(char *reason) {
+ printf("<TITLE>Order Not Submitted</TITLE>%c",LF);
+ printf("<H1>Order Not Submitted</H1>%c",LF);
+ printf("Your order has not been submitted, because %s.<P>%c",reason,LF);
+ exit(1);
+}
+
+main(int argc, char *argv[]) {
+ register int x,m=0;
+ char *cl;
+ char w[256];
+ char tfile[L_tmpnam];
+ int subs,slims,sides,drinks,allow;
+ char name[32];
+ char phone[10];
+ char address[64];
+ FILE *tfp,*order;
+
+ printf("Content-type: text/html%c%c",LF,LF);
+
+ cl=getenv("QUERY_STRING");
+ if((!cl) || (!cl[0]))
+ dump_form();
+
+ tmpnam(tfile);
+ if(!(tfp=fopen(tfile,"w"))) {
+ printf("<TITLE>Server Error</TITLE>%c",LF);
+ printf("<H1>Server Error</H1>%c",LF);
+ printf("Server unable to get a temporary file. Please try again later.<P>%c",LF);
+ exit(1);
+ }
+
+ subs=0;slims=0;sides=0;drinks=0;allow=0;
+ name[0]='\0';
+ phone[0]='\0';
+ address[0]='\0';
+
+ for(x=0;cl[0] != '\0'; x++) {
+ m=x;
+ getword(w,cl,'=');
+ plustospace(w);
+ unescape_url(w);
+ if(!strcmp(w,"pwd")) {
+ getword(w,cl,'&');
+ plustospace(w);
+ unescape_url(w);
+ allow=(strcmp(w,PASSWORD) ? 0 : 1);
+ }
+ if(!strcmp(w,"sub")) {
+ getword(w,cl,'&');
+ plustospace(w);
+ unescape_url(w);
+ subs |= (1 << atoi(w));
+ }
+ else if(!strcmp(w,"slj")) {
+ getword(w,cl,'&');
+ plustospace(w);
+ unescape_url(w);
+ slims |= (1 << atoi(w));
+ }
+ else if(!strcmp(w,"sde")) {
+ getword(w,cl,'&');
+ plustospace(w);
+ unescape_url(w);
+ sides |= (1 << atoi(w));
+ }
+ else if(!strcmp(w,"pop")) {
+ getword(w,cl,'&');
+ plustospace(w);
+ unescape_url(w);
+ drinks |= (1 << atoi(w));
+ }
+ else if(!strcmp(w,"name")) {
+ getword(w,cl,'&');
+ plustospace(w);
+ unescape_url(w);
+ strcpy(name,w);
+ }
+ else if(!strcmp(w,"phone")) {
+ getword(w,cl,'&');
+ plustospace(w);
+ unescape_url(w);
+ strcpy(phone,w);
+ }
+ else if(!strcmp(w,"adr")) {
+ getword(w,cl,'&');
+ plustospace(w);
+ unescape_url(w);
+ strcpy(address,w);
+ }
+ }
+
+ if(!name[0]) print_error("you didn't give your name");
+ if(!address[0]) print_error("you didn't give your address");
+ if(!phone[0]) print_error("you didn't give your phone number");
+ if((!subs) && (!slims) && (!sides) && (!drinks)) print_error("you didn't order anything");
+
+ if(allow) {
+ char t[256];
+ sprintf(t,"/bin/mail %s",JJ_FAX);
+ if(!(order=popen(t,"w")))
+ print_error("the server was unable to open a pipe to mail");
+ printf("<TITLE>Order Sent</TITLE>%c",LF);
+ printf("<H1>Order Sent</H1>%c",LF);
+ printf("Your order has been sent to the UIUC e-mail to FAX gateway.<P>%c",LF);
+ } else {
+ printf("<TITLE>Your Order</TITLE>%c",LF);
+ printf("<H1>Your Order</H1>%c",LF);
+ printf("This is how your order would have looked if it had been sent.<P><PLAINTEXT>%c",LF);
+ order=stdout;
+ }
+
+ fprintf(order,"My name is %s, and I would like to have the following%c",
+ name,LF);
+ fprintf(order,"order delivered to %s:%c%c",address,LF,LF);
+ for(x=0;x<12;x++)
+ if(subs & (1 << x))
+ fprintf(order,"\t(1) %s%c",sublist[x],LF);
+ for(x=0;x<6;x++)
+ if(slims & (1 << x))
+ fprintf(order,"\t(1) %s Slim Jim%c",slimlist[x],LF);
+ for(x=0;x<2;x++)
+ if(sides & (1 << x))
+ fprintf(order,"\t(1) %s%c",sidelist[x],LF);
+ for(x=0;x<4;x++)
+ if(drinks & (1 << x))
+ fprintf(order,"\t(1) %s%c",poplist[x],LF);
+ fprintf(order,"%cPlease feel free to call me at %s if there is any%c",LF,
+ phone,LF);
+ fprintf(order,"problem. Thank you.%c%c.%c",LF,LF,LF);
+ fclose(order);
+ exit(0);
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+#define LF 10
+#define HTML_BREAK printf("<P>%c", LF);
+typedef struct {
+ char name[128];
+ char val[128];
+} entry;
+
+typedef struct {
+ char qfield[256];
+ int qlen;
+ char qname[256];
+} fields;
+
+void getword(char *word, char *line, char stop);
+char x2c(char *what);
+void unescape_url(char *url);
+void plustospace(char *str);
+void send_fd(FILE *f, FILE *fd);
+void send_doc(int which);
+
+static fields idxfields[] = { {"Qalias", 32, "Alias"},
+ {"Qname", 256, "Name" },
+ {"Qemail", 128, "E-mail Address"},
+ {"Qnickname", 120, "Nickname"},
+ {"Qoffice_phone", 60, "Office Phone Number"},
+ {"Qcallsign", 16, "HAM Callsign"},
+ {"Qproxy", 64, "Proxy"},
+ {"Qhigh_school", 30, "High School"},
+ {"Qslip", 256, "SLIP Address"},
+ {NULL, 0, NULL}
+ };
+
+static fields othersearchfields[] = { {"Qcurriculum", 64, "Curriculum"},
+ {"Qphone", 64, "Phone Number" },
+ {"Qaddress", 128, "Address"},
+ {"Qoffice_address", 128, "Office Address"},
+ {"Qhome_address", 128, "Home Address"},
+ {"Qpermanent_address", 128, "Permanent Address"},
+ {"Qpermanent_phone", 60, "Permanent Phone"},
+ {"Qdepartment", 64, "Department"},
+ {"Qtitle", 64, "Title"},
+ {"Qproject", 256, "Project"},
+ {"Qother", 256, "Other"},
+ {"Qbirthday", 24, "Birthday"},
+ {"Qcolleges", 120, "Colleges Attended"},
+ {"Qleft_uiuc", 24, "Date/Month Person left UIUC"},
+ {NULL, 0, NULL},
+ };
+
+void send_doc(int which) {
+ int x;
+
+ printf("<TITLE>Form for CSO PH query</TITLE>%c", LF);
+ printf("<H1>Form for CSO PH query</H1>%c", LF);
+ printf("This form will send a PH query to the specified ph server.%c", LF);
+ HTML_BREAK
+ printf("<HR>%c", LF);
+
+ printf("<FORM ACTION=\"http://%s:%s%s\">%c", getenv("SERVER_NAME"),
+ getenv("SERVER_PORT"), getenv("SCRIPT_NAME"), LF);
+
+ printf("PH Server:<INPUT TYPE=\"text\" NAME=\"Jserver\" VALUE=\"ns.uiuc.edu\" MAXLENGTH=\"256\">%c", LF);
+ HTML_BREAK
+
+ printf("<H3>At least one of these fields must be specified:</H3><UL>%c",LF);
+ for(x=0; idxfields[x].qlen != 0; x++)
+ printf("<LI><INPUT TYPE=\"text\" NAME=\"%s\" MAXLENGTH=\"%d\">%s%c"
+ ,idxfields[x].qfield, idxfields[x].qlen, idxfields[x].qname,LF);
+
+ printf("</UL>%c", LF);
+
+ if (!(which&0x10)) {
+ printf("<A HREF=\"%s?Jform=%d\"><H3>Show additional fields to narrow query</H3></A>%c", getenv("SCRIPT_NAME"), (which | 0x10), LF);
+ }
+ else {
+ printf("<H3>Additional fields to narrow query:</H3><UL>%c",LF);
+
+ for(x=0; othersearchfields[x].qlen != 0; x++)
+ printf("<LI><INPUT TYPE=\"text\" NAME=\"%s\" MAXLENGTH=\"%d\">%s%c"
+ ,othersearchfields[x].qfield, othersearchfields[x].qlen,
+ othersearchfields[x].qname,LF);
+
+ printf("</UL>%c", LF);
+
+ printf("<A HREF=\"%s?Jform=%d\">Show fewer query fields</A>%c", getenv("SCRIPT_NAME"), (which & 0x01), LF);
+ }
+
+ HTML_BREAK
+
+ if (!(which & 0x01)) {
+ printf("<A HREF=\"%s?Jform=%d\"><H3>Return more than default fields</H3></A>%c", getenv("SCRIPT_NAME"), (which | 0x01), LF);
+ }
+ else {
+ printf("<H3>Fields to return:</H3><UL>%c", LF);
+
+ for(x=0; idxfields[x].qlen != 0; x++)
+ printf("<LI><INPUT TYPE=\"checkbox\" NAME=\"return\" VALUE=\"%s\">%s%c", &(idxfields[x].qfield[1]), idxfields[x].qname, LF);
+
+ for(x=0; othersearchfields[x].qlen != 0; x++)
+ printf("<LI><INPUT TYPE=\"checkbox\" NAME=\"return\" VALUE=\"%s\">%s%c", &(othersearchfields[x].qfield[1]), othersearchfields[x].qname, LF);
+
+ printf("</UL>%c", LF);
+
+ printf("<A HREF=\"%s?Jform=%d\">Return default fields</A>%c", getenv("SCRIPT_NAME"), (which & 0x10), LF);
+ }
+
+ HTML_BREAK
+ printf("<INPUT TYPE=\"submit\">%c", LF);
+ printf("</FORM>%c", LF);
+
+ printf("<HR>%c<ADDRESS>", LF);
+ printf("Questions, comments to: <a href=\"http://www.ncsa.uiuc.edu/SDG/People/jbrowne/jbrowne.html\">Jim Browne</a>%c", LF);
+ printf("</ADDRESS>%c", LF);
+
+}
+
+main(int argc, char *argv[]) {
+ entry entries[64];
+ register int x,m=0;
+ char *cl;
+ char returnstr[1024], typestr[4098], commandstr[8192], serverstr[256];
+ int atleastonereturn = 0, atleastonequery = 0, which = 0;
+ FILE *phfp;
+
+ printf("Content-type: text/html%c%c",LF,LF);
+
+ strcpy(returnstr, "return ");
+ strcpy(typestr, " ");
+
+ cl = getenv("QUERY_STRING");
+
+ if((!cl) || (!cl[0])) {
+ send_doc(0);
+ exit(1);
+ }
+
+ for(x=0;cl[0] != '\0';x++) {
+ m=x;
+ getword(entries[x].val,cl,'&');
+ plustospace(entries[x].val);
+ unescape_url(entries[x].val);
+ getword(entries[x].name,entries[x].val,'=');
+ }
+
+ for(x=0; x <= m; x++) {
+/* printf("%s = %s %c", entries[x].name, entries[x].val, LF); */
+
+ if (!strcmp(entries[x].name, "return")) {
+ strcat(returnstr, entries[x].val);
+ strcat(returnstr, " ");
+ atleastonereturn = 1;
+ }
+ else if ((entries[x].name[0] == 'Q') && strlen(entries[x].val)) {
+ strcat(typestr, &(entries[x].name[1]));
+ strcat(typestr, "=");
+ strcat(typestr, entries[x].val);
+ strcat(typestr, " ");
+ atleastonequery = 1;
+ }
+ else if (!strcmp(entries[x].name, "Jserver"))
+ strcpy(serverstr, entries[x].val);
+ else if (!strcmp(entries[x].name, "Jform"))
+ if (sscanf(entries[x].val, "%d", &which)) {
+ send_doc(which);
+ exit(1);
+ }
+ else exit(1);
+ }
+
+ printf("<H1>Query Results</H1>%c", LF);
+ HTML_BREAK
+
+ if (!atleastonequery) printf("<B>You did not enter a query!</B>%c",LF);
+ else {
+ strcpy(commandstr, "/usr/local/bin/ph -m ");
+ if (strlen(serverstr)) {
+ strcat(commandstr, " -s ");
+ /* RM 2/22/94 oops */
+ escape_shell_cmd(serverstr);
+ strcat(commandstr, serverstr);
+ strcat(commandstr, " ");
+ }
+ escape_shell_cmd(typestr);
+ strcat(commandstr, typestr);
+ if (atleastonereturn) {
+ escape_shell_cmd(returnstr);
+ strcat(commandstr, returnstr);
+ }
+
+ printf("%s%c", commandstr, LF);
+ printf("<PRE>%c", LF);
+
+ phfp = popen(commandstr,"r");
+ send_fd(phfp, stdout);
+
+ printf("</PRE>%c", LF);
+ }
+}
--- /dev/null
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MAX_ENTRIES 10000
+
+typedef struct {
+ char *name;
+ char *val;
+} entry;
+
+char *makeword(char *line, char stop);
+char *fmakeword(FILE *f, char stop, int *len);
+char x2c(char *what);
+void unescape_url(char *url);
+void plustospace(char *str);
+
+
+main(int argc, char *argv[]) {
+ entry entries[MAX_ENTRIES];
+ register int x,m=0;
+ int cl;
+
+ printf("Content-type: text/html%c%c",10,10);
+
+ if(strcmp(getenv("REQUEST_METHOD"),"POST")) {
+ printf("This script should be referenced with a METHOD of POST.\n");
+ printf("If you don't understand this, see this ");
+ printf("<A HREF=\"http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html\">forms overview</A>.%c",10);
+ exit(1);
+ }
+ if(strcmp(getenv("CONTENT_TYPE"),"application/x-www-form-urlencoded")) {
+ printf("This script can only be used to decode form results. \n");
+ exit(1);
+ }
+ cl = atoi(getenv("CONTENT_LENGTH"));
+
+ for(x=0;cl && (!feof(stdin));x++) {
+ m=x;
+ entries[x].val = fmakeword(stdin,'&',&cl);
+ plustospace(entries[x].val);
+ unescape_url(entries[x].val);
+ entries[x].name = makeword(entries[x].val,'=');
+ }
+
+ printf("<H1>Query Results</H1>");
+ printf("You submitted the following name/value pairs:<p>%c",10);
+ printf("<ul>%c",10);
+
+ for(x=0; x <= m; x++)
+ printf("<li> <code>%s = %s</code>%c",entries[x].name,
+ entries[x].val,10);
+ printf("</ul>%c",10);
+}
--- /dev/null
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct {
+ char name[128];
+ char val[128];
+} entry;
+
+void getword(char *word, char *line, char stop);
+char x2c(char *what);
+void unescape_url(char *url);
+void plustospace(char *str);
+
+
+
+main(int argc, char *argv[]) {
+ entry entries[10000];
+ register int x,m=0;
+ char *cl;
+
+ printf("Content-type: text/html%c%c",10,10);
+
+ if(strcmp(getenv("REQUEST_METHOD"),"GET")) {
+ printf("This script should be referenced with a METHOD of GET.\n");
+ printf("If you don't understand this, see this ");
+ printf("<A HREF=\"http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html\">forms overview</A>.%c",10);
+ exit(1);
+ }
+
+ cl = getenv("QUERY_STRING");
+ if(cl == NULL) {
+ printf("No query information to decode.\n");
+ exit(1);
+ }
+ for(x=0;cl[0] != '\0';x++) {
+ m=x;
+ getword(entries[x].val,cl,'&');
+ plustospace(entries[x].val);
+ unescape_url(entries[x].val);
+ getword(entries[x].name,entries[x].val,'=');
+ }
+
+ printf("<H1>Query Results</H1>");
+ printf("You submitted the following name/value pairs:<p>%c",10);
+ printf("<ul>%c",10);
+
+ for(x=0; x <= m; x++)
+ printf("<li> <code>%s = %s</code>%c",entries[x].name,
+ entries[x].val,10);
+ printf("</ul>%c",10);
+}
--- /dev/null
+#include <stdio.h>
+
+#define LF 10
+#define CR 13
+
+void getword(char *word, char *line, char stop) {
+ int x = 0,y;
+
+ for(x=0;((line[x]) && (line[x] != stop));x++)
+ word[x] = line[x];
+
+ word[x] = '\0';
+ if(line[x]) ++x;
+ y=0;
+
+ while(line[y++] = line[x++]);
+}
+
+char *makeword(char *line, char stop) {
+ int x = 0,y;
+ char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));
+
+ for(x=0;((line[x]) && (line[x] != stop));x++)
+ word[x] = line[x];
+
+ word[x] = '\0';
+ if(line[x]) ++x;
+ y=0;
+
+ while(line[y++] = line[x++]);
+ return word;
+}
+
+char *fmakeword(FILE *f, char stop, int *cl) {
+ int wsize;
+ char *word;
+ int ll;
+
+ wsize = 102400;
+ ll=0;
+ word = (char *) malloc(sizeof(char) * (wsize + 1));
+
+ while(1) {
+ word[ll] = (char)fgetc(f);
+ if(ll==wsize) {
+ word[ll+1] = '\0';
+ wsize+=102400;
+ word = (char *)realloc(word,sizeof(char)*(wsize+1));
+ }
+ --(*cl);
+ if((word[ll] == stop) || (feof(f)) || (!(*cl))) {
+ if(word[ll] != stop) ll++;
+ word[ll] = '\0';
+ return word;
+ }
+ ++ll;
+ }
+}
+
+char x2c(char *what) {
+ register char digit;
+
+ digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
+ digit *= 16;
+ digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
+ return(digit);
+}
+
+void unescape_url(char *url) {
+ register int x,y;
+
+ for(x=0,y=0;url[y];++x,++y) {
+ if((url[x] = url[y]) == '%') {
+ url[x] = x2c(&url[y+1]);
+ y+=2;
+ }
+ }
+ url[x] = '\0';
+}
+
+void plustospace(char *str) {
+ register int x;
+
+ for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
+}
+
+int rind(char *s, char c) {
+ register int x;
+ for(x=strlen(s) - 1;x != -1; x--)
+ if(s[x] == c) return x;
+ return -1;
+}
+
+int getline(char *s, int n, FILE *f) {
+ register int i=0;
+
+ while(1) {
+ s[i] = (char)fgetc(f);
+
+ if(s[i] == CR)
+ s[i] = fgetc(f);
+
+ if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) {
+ s[i] = '\0';
+ return (feof(f) ? 1 : 0);
+ }
+ ++i;
+ }
+}
+
+void send_fd(FILE *f, FILE *fd)
+{
+ int num_chars=0;
+ char c;
+
+ while (1) {
+ c = fgetc(f);
+ if(feof(f))
+ return;
+ fputc(c,fd);
+ }
+}
+
+int ind(char *s, char c) {
+ register int x;
+
+ for(x=0;s[x];x++)
+ if(s[x] == c) return x;
+
+ return -1;
+}
+
+void escape_shell_cmd(char *cmd) {
+ register int x,y,l;
+
+ l=strlen(cmd);
+ for(x=0;cmd[x];x++) {
+ if(ind("&;`'\"|*?~<>^()[]{}$\\",cmd[x]) != -1){
+ for(y=l+1;y>x;y--)
+ cmd[y] = cmd[y-1];
+ l++; /* length has been increased */
+ cmd[x] = '\\';
+ x++; /* skip the character */
+ }
+ }
+}
+
--- /dev/null
+# access.conf: Global access configuration
+# Online docs at http://www.apache.org/
+
+# This file defines server settings which affect which types of services
+# are allowed, and in what circumstances.
+
+# Each directory to which Apache has access, can be configured with respect
+# to which services and features are allowed and/or disabled in that
+# directory (and its subdirectories).
+
+# Originally by Rob McCool
+
+# /usr/local/etc/httpd/ should be changed to whatever you set ServerRoot to.
+<Directory /usr/local/etc/httpd/cgi-bin>
+Options Indexes FollowSymLinks
+</Directory>
+
+# This should be changed to whatever you set DocumentRoot to.
+
+<Directory /usr/local/etc/httpd/htdocs>
+
+# This may also be "None", "All", or any combination of "Indexes",
+# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews".
+
+# Note that "MultiViews" must be named *explicitly* --- "Options All"
+# doesn't give it to you (or at least, not yet).
+
+Options Indexes FollowSymLinks
+
+# This option allows you to turn on the XBitHack behavior, which allows you
+# to make text/html server-parsed by activating the owner x bit with chmod.
+# This directive may be used wherever Options may, and has three
+# possible arguments: Off, On or Full. If set to full, Apache will also
+# add a Last-Modified header to the document if the group x bit is set.
+
+# Unless the server has been compiled with -DXBITHACK, this function is
+# off by default. To use, uncomment the following line:
+
+#XBitHack Full
+
+# This controls which options the .htaccess files in directories can
+# override. Can also be "None", or any combination of "Options", "FileInfo",
+# "AuthConfig", and "Limit"
+
+AllowOverride All
+
+# Controls who can get stuff from this server.
+
+<Limit GET>
+order allow,deny
+allow from all
+</Limit>
+
+</Directory>
+
+# You may place any other directories you wish to have access
+# information for after this one.
+
--- /dev/null
+# This is the main server configuration file. See URL http://www.apache.org/
+# for instructions.
+
+# Do NOT simply read the instructions in here without understanding
+# what they do, if you are unsure consult the online docs. You have been
+# warned.
+
+# Originally by Rob McCool
+
+# ServerType is either inetd, or standalone.
+
+ServerType standalone
+
+# If you are running from inetd, go to "ServerAdmin".
+
+# Port: The port the standalone listens to. For ports < 1023, you will
+# need httpd to be run as root initially.
+
+Port 80
+
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.
+
+# User/Group: The name (or #number) of the user/group to run httpd as.
+# On SCO (ODT 3) use User nouser and Group nogroup
+User nobody
+Group #-1
+
+# ServerAdmin: Your address, where problems with the server should be
+# e-mailed.
+
+ServerAdmin you@your.address
+
+# ServerRoot: The directory the server's config, error, and log files
+# are kept in
+
+ServerRoot /usr/local/etc/httpd
+
+# BindAddress: You can support virtual hosts with this option. This option
+# is used to tell the server which IP address to listen to. It can either
+# contain "*", an IP address, or a fully qualified Internet domain name.
+# See also the VirtualHost directive.
+
+#BindAddress *
+
+# ErrorLog: The location of the error log file. If this does not start
+# with /, ServerRoot is prepended to it.
+
+ErrorLog logs/error_log
+
+# TransferLog: The location of the transfer log file. If this does not
+# start with /, ServerRoot is prepended to it.
+
+TransferLog logs/access_log
+
+# PidFile: The file the server should log its pid to
+PidFile logs/httpd.pid
+
+# ServerName allows you to set a host name which is sent back to clients for
+# your server if it's different than the one the program would get (i.e. use
+# "www" instead of the host's real name).
+#
+# Note: You cannot just invent host names and hope they work. The name you
+# define here must be a valid DNS name for your host. If you don't understand
+# this, ask your network administrator.
+
+#ServerName new.host.name
+
+# CacheNegotiatedDocs: By default, Apache sends Pragma: no-cache with each
+# document that was negotiated on the basis of content. This asks proxy
+# servers not to cache the document. Uncommenting the following line disables
+# this behavior, and proxies will be allowed to cache the documents.
+
+#CacheNegotiatedDocs
+
+# Timeout: The number of seconds before receives and sends time out
+# n.b. the compiled default is 1200 (20 minutes !)
+
+Timeout 400
+
+# Server-pool size regulation. Rather than making you guess how many
+# server processes you need, Apache dynamically adapts to the load it
+# sees --- that is, it tries to maintain enough server processes to
+# handle the current load, plus a few spare servers to handle transient
+# load spikes (e.g., multiple simultaneous requests from a single
+# Netscape browser).
+
+# It does this by periodically checking how many servers are waiting
+# for a request. If there are fewer than MinSpareServers, it creates
+# a new spare. If there are more than MaxSpareServers, some of the
+# spares die off. These values are probably OK for most sites ---
+
+MinSpareServers 5
+MaxSpareServers 10
+
+# Number of servers to start --- should be a reasonable ballpark figure.
+
+StartServers 5
+
+# Limit on total number of servers running, i.e., limit on the number
+# of clients who can simultaneously connect --- if this limit is ever
+# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW.
+# It is intended mainly as a brake to keep a runaway server from taking
+# Unix with it as it spirals down...
+
+MaxClients 150
+
+# MaxRequestsPerChild: the number of requests each child process is
+# allowed to process before the child dies.
+# The child will exit so as to avoid problems after prolonged use when
+# Apache (and maybe the libraries it uses) leak. On most systems, this
+# isn't really needed, but a few (such as Solaris) do have notable leaks
+# in the libraries.
+
+MaxRequestsPerChild 30
+
+# VirtualHost: Allows the daemon to respond to requests for more than one
+# server address, if your server machine is configured to accept IP packets
+# for multiple addresses. This can be accomplished with the ifconfig
+# alias flag, or through kernel patches like VIF.
+
+# Any httpd.conf or srm.conf directive may go into a VirtualHost command.
+# See alto the BindAddress entry.
+
+#<VirtualHost host.foo.com>
+#ServerAdmin webmaster@host.foo.com
+#DocumentRoot /www/docs/host.foo.com
+#ServerName host.foo.com
+#ErrorLog logs/host.foo.com-error_log
+#TransferLog logs/host.foo.com-access_log
+#</VirtualHost>
--- /dev/null
+# This is a comment. I love comments.
+
+
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/macwriteii
+application/msword
+application/news-message-id
+application/news-transmission
+application/octet-stream bin
+application/oda oda
+application/pdf pdf
+application/postscript ai eps ps
+application/remote-printing
+application/rtf rtf
+application/slate
+application/x-mif mif
+application/wita
+application/wordperfect5.1
+application/x-csh csh
+application/x-dvi dvi
+application/x-hdf hdf
+application/x-latex latex
+application/x-netcdf nc cdf
+application/x-sh sh
+application/x-tcl tcl
+application/x-tex tex
+application/x-texinfo texinfo texi
+application/x-troff t tr roff
+application/x-troff-man man
+application/x-troff-me me
+application/x-troff-ms ms
+application/x-wais-source src
+application/zip zip
+application/x-bcpio bcpio
+application/x-cpio cpio
+application/x-gtar gtar
+application/x-shar shar
+application/x-sv4cpio sv4cpio
+application/x-sv4crc sv4crc
+application/x-tar tar
+application/x-ustar ustar
+audio/basic au snd
+audio/x-aiff aif aiff aifc
+audio/x-wav wav
+image/gif gif
+image/ief ief
+image/jpeg jpeg jpg jpe
+image/tiff tiff tif
+image/x-cmu-raster ras
+image/x-portable-anymap pnm
+image/x-portable-bitmap pbm
+image/x-portable-graymap pgm
+image/x-portable-pixmap ppm
+image/x-rgb rgb
+image/x-xbitmap xbm
+image/x-xpixmap xpm
+image/x-xwindowdump xwd
+message/external-body
+message/news
+message/partial
+message/rfc822
+multipart/alternative
+multipart/appledouble
+multipart/digest
+multipart/mixed
+multipart/parallel
+text/html html
+text/plain txt
+text/richtext rtx
+text/tab-separated-values tsv
+text/x-setext etx
+video/mpeg mpeg mpg mpe
+video/quicktime qt mov
+video/x-msvideo avi
+video/x-sgi-movie movie
+
--- /dev/null
+# With this document, you define the name space that users see of your http
+# server. This file also defines server settings which affect how requests are
+# serviced, and how results should be formatted.
+
+# See the tutorials at http://www.apache.org/ for
+# more information.
+
+# Originally by Rob McCool; Adapted for Apache
+
+
+# DocumentRoot: The directory out of which you will serve your
+# documents. By default, all requests are taken from this directory, but
+# symbolic links and aliases may be used to point to other locations.
+
+DocumentRoot /usr/local/etc/httpd/htdocs
+
+# UserDir: The name of the directory which is appended onto a user's home
+# directory if a ~user request is recieved.
+
+UserDir public_html
+
+# DirectoryIndex: Name of the file or files to use as a pre-written HTML
+# directory index. Separate multiple entries with spaces.
+
+DirectoryIndex index.html
+
+# FancyIndexing is whether you want fancy directory indexing or standard
+
+FancyIndexing on
+
+# AddIcon tells the server which icon to show for different files or filename
+# extensions
+
+AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
+AddIconByType (TXT,/icons/text.gif) text/*
+AddIconByType (IMG,/icons/image2.gif) image/*
+AddIconByType (SND,/icons/sound2.gif) audio/*
+AddIconByType (VID,/icons/movie.gif) video/*
+AddIcon /icons/text.gif .ps .shtml
+AddIcon /icons/movie.gif .mpg .qt
+AddIcon /icons/binary.gif .bin
+AddIcon /icons/burst.gif .wrl
+AddIcon /icons/binhex.gif .hqx .sit
+AddIcon /icons/uu.gif .uu
+AddIcon /icons/tar.gif .tar .tar
+AddIcon /icons/back.gif ..
+AddIcon /icons/dir.gif ^^DIRECTORY^^
+AddIcon /icons/blank.gif ^^BLANKICON^^
+
+# DefaultIcon is which icon to show for files which do not have an icon
+# explicitly set.
+
+DefaultIcon /icons/unknown.gif
+
+# AddDescription allows you to place a short description after a file in
+# server-generated indexes.
+# Format: AddDescription "description" filename
+
+# ReadmeName is the name of the README file the server will look for by
+# default. Format: ReadmeName name
+#
+# The server will first look for name.html, include it if found, and it will
+# then look for name and include it as plaintext if found.
+#
+# HeaderName is the name of a file which should be prepended to
+# directory indexes.
+
+ReadmeName README
+HeaderName HEADER
+
+# IndexIgnore is a set of filenames which directory indexing should ignore
+# Format: IndexIgnore name1 name2...
+
+IndexIgnore */.??* *~ *# */HEADER* */README* */RCS
+
+# AccessFileName: The name of the file to look for in each directory
+# for access control information.
+
+AccessFileName .htaccess
+
+# DefaultType is the default MIME type for documents which the server
+# cannot find the type of from filename extensions.
+
+DefaultType text/plain
+
+# AddEncoding allows you to have certain browsers (Mosaic/X 2.1+) uncompress
+# information on the fly. Note: Not all browsers support this.
+
+AddEncoding x-compress Z
+AddEncoding x-gzip gz
+
+# AddLanguage allows you to specify the language of a document. You can
+# then use content negotiation to give a browser a file in a language
+# it can understand. Note that the suffix does not have to be the same
+# as the language keyword --- those with documents in Polish (whose
+# net-standard language code is pl) may wish to use "AddLanguage pl .po"
+# to avoid the ambiguity with the common suffix for perl scripts.
+
+AddLanguage en .en
+AddLanguage fr .fr
+AddLanguage de .de
+AddLanguage da .da
+AddLanguage el .el
+AddLanguage it .it
+
+# LanguagePriority allows you to give precedence to some languages
+# in case of a tie during content negotiation.
+# Just list the languages in decreasing order of preference.
+
+LanguagePriority en fr de
+
+# Redirect allows you to tell clients about documents which used to exist in
+# your server's namespace, but do not anymore. This allows you to tell the
+# clients where to look for the relocated document.
+# Format: Redirect fakename url
+
+
+# Aliases: Add here as many aliases as you need (with no limit). The format is
+# Alias fakename realname
+
+Alias /icons/ /usr/local/etc/httpd/icons/
+
+# ScriptAlias: This controls which directories contain server scripts.
+# Format: ScriptAlias fakename realname
+
+ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin/
+
+# If you want to use server side includes, or CGI outside
+# ScriptAliased directories, uncomment the following lines.
+
+# AddType allows you to tweak mime.types without actually editing it, or to
+# make certain files to be certain types.
+# Format: AddType type/subtype ext1
+
+#AddType text/x-server-parsed-html .shtml
+#AddType application/x-httpd-cgi .cgi
+
+# For server-side includes which will be treated as HTML3
+# for purposes of content negotiation, use
+
+#AddType text/x-server-parsed-html3 .shtml3
+
+# Uncomment the following line to enable Apache's send-asis HTTP file
+# feature
+
+#AddType httpd/send-as-is asis
+
+# To enable type maps, you might want to use
+
+#AddType application/x-type-map var
+
+# If you wish to use server-parsed imagemap files, use
+
+#AddType application/x-httpd-imap map
+
+# Customizable error response (Apache style)
+# these come in three flavors
+#
+# 1) plain text
+#ErrorDocument 500 "The server made a boo boo.
+# n.b. the (") marks it as text, it does not get output
+#
+# 2) local redirects
+#ErrorDocument 404 /missing.html
+# to redirect to local url /missing.html
+#ErrorDocument 404 /cgi-bin/missing_handler.pl
+# n.b. can redirect to a script or a document using server-side-includes.
+#
+# 3) external redirects
+#ErrorDocument 402 http://other.server.com/subscription_info.html
+#
--- /dev/null
+<title>Apache API notes</title>
+<h1>Apache API notes</h1>
+
+<h3>Robert S. Thau</h3>
+
+These are some notes on the Apache API and the data structures you
+have to deal with, etc. They are not yet nearly complete, but
+hopefully, they will help you get your bearings. Keep in mind that
+the API is still subject to change as we gain experience with it.
+(See the TODO file for what <em>might</em> be coming). However,
+it will be easy to adapt modules to any changes that are made.
+(We have more modules to adapt than you do).
+<p>
+
+A few notes on general pedagogical style here. In the interest of
+conciseness, all structure declarations here are incomplete --- the
+real ones have more slots, that I'm not telling you about. For the
+most part, these are reserved to one component of the server core or
+another, and should be altered by modules with caution. However, in
+some cases, they really are things I just haven't gotten around to
+yet. Welcome to the bleeding edge.<p>
+
+Finally, here's an outline, to give you some bare idea of what's
+coming up, and in what order:
+
+<ul>
+ <li> <a href="#basics">Basic concepts.</a>
+ <ul>
+ <li> <a href="#HMR">Handlers, Modules, and Requests</a>
+ <li> <a href="#moduletour">A brief tour of a module</a>
+ </ul>
+ <li> <a href="#handlers">How handlers work</a>
+ <ul>
+ <li> <a href="#req_tour">A brief tour of the <code>request_rec</code></a>
+ <li> <a href="#req_orig">Where request_rec structures come from</a>
+ <li> <a href="#req_return">Handling requests, declining, and returning error codes</a>
+ <li> <a href="#resp_handlers">Special considerations for response handlers</a>
+ <li> <a href="#auth_handlers">Special considerations for authentication handlers</a>
+ <li> <a href="#log_handlers">Special considerations for logging handlers</a>
+ </ul>
+ <li> <a href="#pools">Resource allocation and resource pools</a>
+ <li> <a href="#config">Configuration, commands and the like</a>
+ <ul>
+ <li> <a href="#per-dir">Per-directory configuration structures</a>
+ <li> <a href="#commands">Command handling</a>
+ <li> <a href="#servconf">Side notes --- per-server configuration, virtual servers, etc.</a>
+ </ul>
+</ul>
+
+<h2><a name="basics">Basic concepts.</a></h2>
+
+We begin with an overview of the basic concepts behind the
+API, and how they are manifested in the code.
+
+<h3><a name="HMR">Handlers, Modules, and Requests</a></h3>
+
+Apache breaks down request handling into a series of steps, more or
+less the same way the Netscape Server API does (although this API has
+a few more stages than NetSite does, as hooks for stuff I thought
+might be useful in the future). These are:
+
+<ul>
+ <li> URI -> Filename translation
+ <li> Auth ID checking [is the user who they say they are?]
+ <li> Auth access checking [is the user authorized <em>here</em>?]
+ <li> Access checking other than auth
+ <li> Determining MIME type of the object requested
+ <li> "Fixups" --- there aren't any of these yet, but the phase is
+ intended as a hook for possible extensions like
+ <code>SetEnv</code>, which don't really fit well elsewhere.
+ <li> Actually sending a response back to the client.
+ <li> Logging the request
+</ul>
+
+These phases are handled by looking at each of a succession of
+<em>modules</em>, looking to see if each of them has a handler for the
+phase, and attempting invoking it if so. The handler can typically do
+one of three things:
+
+<ul>
+ <li> <em>Handle</em> the request, and indicate that it has done so
+ by returning the magic constant <code>OK</code>.
+ <li> <em>Decline</em> to handle the request, by returning the magic
+ integer constant <code>DECLINED</code>. In this case, the
+ server behaves in all respects as if the handler simply hadn't
+ been there.
+ <li> Signal an error, by returning one of the HTTP error codes.
+ This terminates normal handling of the request, although an
+ ErrorDocument may be invoked to try to mop up, and it will be
+ logged in any case.
+</ul>
+
+Most phases are terminated by the first module that handles them;
+however, for logging, "fixups", and non-access authentication
+checking, all handlers always run (barring an error). Also, the
+response phase is unique in that modules may declare multiple handlers
+for it, via a dispatch table keyed on the MIME type of the requested
+object. Modules may declare a response-phase handler which can handle
+<em>any</em> request, by giving it the key <code>*/*</code> (i.e., a
+wildcard MIME type specification). However, wildcard handlers are
+only invoked if the server has already tried and failed to find a more
+specific response handler for the MIME type of the requested object
+(either none existed, or they all declined).<p>
+
+The handlers themselves are functions of one argument (a
+<code>request_rec</code> structure. vide infra), which returns an
+integer, as above.<p>
+
+<h3><a name="moduletour">A brief tour of a module</a></h3>
+
+At this point, we need to explain the structure of a module. Our
+candidate will be one of the messier ones, the CGI module --- this
+handles both CGI scripts and the <code>ScriptAlias</code> config file
+command. It's actually a great deal more complicated than most
+modules, but if we're going to have only one example, it might as well
+be the one with its fingers in everyplace.<p>
+
+Let's begin with handlers. In order to handle the CGI scripts, the
+module declares a response handler for them. Because of
+<code>ScriptAlias</code>, it also has handlers for the name
+translation phase (to recognise <code>ScriptAlias</code>ed URI's), the
+type-checking phase (any <code>ScriptAlias</code>ed request is typed
+as a CGI script).<p>
+
+The module needs to maintain some per (virtual)
+server information, namely, the <code>ScriptAlias</code>es in effect;
+the module structure therefore contains pointers to a functions which
+builds these structures, and to another which combines two of them (in
+case the main server and a virtual server both have
+<code>ScriptAlias</code>es declared).<p>
+
+Finally, this module contains code to handle the
+<code>ScriptAlias</code> command itself. This particular module only
+declares one command, but there could be more, so modules have
+<em>command tables</em> which declare their commands, and describe
+where they are permitted, and how they are to be invoked. <p>
+
+A final note on the declared types of the arguments of some of these
+commands: a <code>pool</code> is a pointer to a <em>resource pool</em>
+structure; these are used by the server to keep track of the memory
+which has been allocated, files opened, etc., either to service a
+particular request, or to handle the process of configuring itself.
+That way, when the request is over (or, for the configuration pool,
+when the server is restarting), the memory can be freed, and the files
+closed, en masse, without anyone having to write explicit code to
+track them all down and dispose of them. Also, a
+<code>cmd_parms</code> structure contains various information about
+the config file being read, and other status information, which is
+sometimes of use to the function which processes a config-file command
+(such as <code>ScriptAlias</code>).
+
+With no further ado, the module itself:
+
+<pre>
+/* Declarations of handlers. */
+
+int translate_scriptalias (request_rec *);
+int type_scriptalias (request_rec *);
+int cgi_handler (request_rec *);
+
+/* Subsdiary dispatch table for response-phase handlers, by MIME type */
+
+handler_rec cgi_handlers[] = {
+{ "application/x-httpd-cgi", cgi_handler },
+{ NULL }
+};
+
+/* Declarations of routines to manipulate the module's configuration
+ * info. Note that these are returned, and passed in, as void *'s;
+ * the server core keeps track of them, but it doesn't, and can't,
+ * know their internal structure.
+ */
+
+void *make_cgi_server_config (pool *);
+void *merge_cgi_server_config (pool *, void *, void *);
+
+/* Declarations of routines to handle config-file commands */
+
+char *script_alias (cmd_parms *, void *per_dir_config, char *fake, char *real);
+
+command_rec cgi_cmds[] = {
+{ "ScriptAlias", script_alias, NULL, RSRC_CONF, TAKE2,
+ "a fakename and a realname"},
+{ NULL }
+};
+
+module cgi_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ make_cgi_server_config, /* server config */
+ merge_cgi_server_config, /* merge server config */
+ cgi_cmds, /* command table */
+ cgi_handlers, /* handlers */
+ translate_scriptalias, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ type_scriptalias, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
+</pre>
+
+<h2><a name="handlers">How handlers work</a></h2>
+
+The sole argument to handlers is a <code>request_rec</code> structure.
+This structure describes a particular request which has been made to
+the server, on behalf of a client. In most cases, each connection to
+the client generates only one <code>request_rec</code> structure.<p>
+
+<h3><a name="req_tour">A brief tour of the <code>request_rec</code></a></h3>
+
+The <code>request_rec</code> contains pointers to a resource pool
+which will be cleared when the server is finished handling the
+request; to structures containing per-server and per-connection
+information, and most importantly, information on the request itself.<p>
+
+The most important such information is a small set of character
+strings describing attributes of the object being requested, including
+its URI, filename, content-type and content-encoding (these being filled
+in by the translation and type-check handlers which handle the
+request, respectively). <p>
+
+Other commonly used data items are tables giving the MIME headers on
+the client's original request, MIME headers to be sent back with the
+ppppresponse (which modules can add to at will), and environment variables
+for any subprocesses which are spawned off in the course of servicing
+the request. These tables are manipulated using the
+<code>table_get</code> and <code>table_set</code> routines. <p>
+
+Finally, there are pointers to two data structures which, in turn,
+point to per-module configuration structures. Specifically, these
+hold pointers to the data structures which the module has built to
+describe the way it has been configured to operate in a given
+directory (via <code>.htaccess</code> files or
+<code><Directory></code> sections), for private data it has
+built in the course of servicing the request (so modules' handlers for
+one phase can pass "notes" to their handlers for other phases). There
+is another such configuration vector in the <code>server_rec</code>
+data structure pointed to by the <code>request_rec</code>, which
+contains per (virtual) server configuration data.<p>
+
+Here is an abridged declaration, giving the fields most commonly used:<p>
+
+<pre>
+struct request_rec {
+
+ pool *pool;
+ conn_rec *connection;
+ server_rec *server;
+
+ /* What object is being requested */
+
+ char *uri;
+ char *filename;
+ char *path_info;
+ char *args; /* QUERY_ARGS, if any */
+ struct stat finfo; /* Set by server core;
+ * st_mode set to zero if no such file */
+
+ char *content_type;
+ char *content_encoding;
+
+ /* MIME header environments, in and out. Also, an array containing
+ * environment variables to be passed to subprocesses, so people can
+ * write modules to add to that environment.
+ *
+ * The difference between headers_out and err_headers_out is that the
+ * latter are printed even on error, and persist across internal redirects
+ * (so the headers printed for ErrorDocument handlers will have them).
+ */
+
+ table *headers_in;
+ table *headers_out;
+ table *err_headers_out;
+ table *subprocess_env;
+
+ /* Info about the request itself... */
+
+ int header_only; /* HEAD request, as opposed to GET */
+ char *protocol; /* Protocol, as given to us, or HTTP/0.9 */
+ char *method; /* GET, HEAD, POST, etc. */
+ int method_number; /* M_GET, M_POST, etc. */
+
+ /* Info for logging */
+
+ char *the_request;
+ int bytes_sent;
+
+ /* A flag which modules can set, to indicate that the data being
+ * returned is volatile, and clients should be told not to cache it.
+ */
+
+ int no_cache;
+
+ /* Various other config info which may change with .htaccess files
+ * These are config vectors, with one void* pointer for each module
+ * (the thing pointed to being the module's business).
+ */
+
+ void *per_dir_config; /* Options set in config files, etc. */
+ void *request_config; /* Notes on *this* request */
+
+};
+
+</pre>
+
+<h3><a name="req_orig">Where request_rec structures come from</a></h3>
+
+Most <code>request_rec</code> structures are built by reading an HTTP
+request from a client, and filling in the fields. However, there are
+a few exceptions:
+
+<ul>
+ <li> If the request is to an imagemap, a type map (i.e., a
+ <code>*.var</code> file), or a CGI script which returned a
+ local "Location:", then the resource which the user requested
+ is going to be ultimately located by some URI other than what
+ the client originally supplied. In this case, the server does
+ an <em>internal redirect</em>, constructing a new
+ <code>request_rec</code> for the new URI, and processing it
+ almost exactly as if the client had requested the new URI
+ directly. <p>
+
+ <li> If some handler signaled an error, and an
+ <code>ErrorDocument</code> is in scope, the same internal
+ redirect machinery comes into play.<p>
+
+ <li> Finally, a handler occasionally needs to investigate "what
+ would happen if" some other request were run. For instance,
+ the directory indexing module needs to know what MIME type
+ would be assigned to a request for each directory entry, in
+ order to figure out what icon to use.<p>
+
+ Such handlers can construct a <em>sub-request</em>, using the
+ functions <code>sub_req_lookup_file</code> and
+ <code>sub_req_lookup_uri</code>; this constructs a new
+ <code>request_rec</code> structure and processes it as you
+ would expect, up to but not including the point of actually
+ sending a response. (These functions skip over the access
+ checks if the sub-request is for a file in the same directory
+ as the original request).<p>
+
+ (Server-side includes work by building sub-requests and then
+ actually invoking the response handler for them, via the
+ function <code>run_sub_request</code>).
+</ul>
+
+<h3><a name="req_return">Handling requests, declining, and returning error codes</a></h3>
+
+As discussed above, each handler, when invoked to handle a particular
+<code>request_rec</code>, has to return an <code>int</code> to
+indicate what happened. That can either be
+
+<ul>
+ <li> OK --- the request was handled successfully. This may or may
+ not terminate the phase.
+ <li> DECLINED --- no erroneous condition exists, but the module
+ declines to handle the phase; the server tries to find another.
+ <li> an HTTP error code, which aborts handling of the request.
+</ul>
+
+Note that if the error code returned is <code>REDIRECT</code>, then
+the module should put a <code>Location</code> in the request's
+<code>headers_out</code>, to indicate where the client should be
+redirected <em>to</em>. <p>
+
+<h3><a name="resp_handlers">Special considerations for response handlers</a></h3>
+
+Handlers for most phases do their work by simply setting a few fields
+in the <code>request_rec</code> structure (or, in the case of access
+checkers, simply by returning the correct error code). However,
+response handlers have to actually send a request back to the client. <p>
+
+They should begin by sending an HTTP response header, using the
+function <code>send_http_header</code>. (You don't have to do
+anything special to skip sending the header for HTTP/0.9 requests; the
+function figures out on its own that it shouldn't do anything). If
+the request is marked <code>header_only</code>, that's all they should
+do; they should return after that, without attempting any further
+output. <p>
+
+Otherwise, they should produce a request body which responds to the
+client as appropriate. The primitives for this are <code>rputc</code>
+and <code>rprintf</code>, for internally generated output, and
+<code>send_fd</code>, to copy the contents of some <code>FILE *</code>
+straight to the client. <p>
+
+At this point, you should more or less understand the following piece
+of code, which is the handler which handles <code>GET</code> requests
+which have no more specific handler; it also shows how conditional
+<code>GET</code>s can be handled, if it's desirable to do so in a
+particular response handler --- <code>set_last_modified</code> checks
+agaisnt the <code>If-modified-since</code> value supplied by the
+client, if annny, and returns an appropriate code (which will, if
+nonzero, be USE_LOCAL_COPY). No similar considerations apply for
+<code>set_content_length</code>, but it returns an error code for
+symmetry.<p>
+
+<pre>
+int default_handler (request_rec *r)
+{
+ int errstatus;
+ FILE *f;
+
+ if (r->method_number != M_GET) return DECLINED;
+ if (r->finfo.st_mode == 0) return NOT_FOUND;
+
+ if ((errstatus = set_content_length (r, r->finfo.st_size))
+ || (errstatus = set_last_modified (r, r->finfo.st_mtime)))
+ return errstatus;
+
+ f = fopen (r->filename, "r");
+
+ if (f == NULL) {
+ log_reason("file permissions deny server access", r->filename, r);
+ return FORBIDDEN;
+ }
+
+ register_timeout ("send", r);
+ send_http_header (r);
+
+ if (!r->header_only) send_fd (f, r);
+ pfclose (r->pool, f);
+ return OK;
+}
+</pre>
+
+Finally, if all of this is too much of a challenge, there are a few
+ways out of it. First off, as shown above, a response handler which
+has not yet produced any output can simply return an error code, in
+which case the server will automatically produce an error response.
+Secondly, it can punt to some other handler by invoking
+<code>internal_redirect</code>, which is how the internal redirection
+machinery discussed above is invoked. A response handler which has
+internally redirected should always return <code>OK</code>. <p>
+
+(Invoking <code>internal_redirect</code> from handlers which are
+<em>not</em> response handlers will lead to serious confusion).
+
+<h3><a name="auth_handlers">Special considerations for authentication handlers</a></h3>
+
+Stuff that should be discussed here in detail:
+
+<ul>
+ <li> Authentication-phase handlers not invoked unless auth is
+ configured for the directory.
+ <li> Common auth configuration stored in the core per-dir
+ configuration; it has accessors <code>auth_type</code>,
+ <code>auth_name</code>, and <code>requires</code>.
+ <li> Common routines, to handle the protocol end of things, at least
+ for HTTP basic authentication (<code>get_basic_auth_pw</code>,
+ which sets the <code>connection->user</code> structure field
+ automatically, and <code>note_basic_auth_failure</code>, which
+ arranges for the proper <code>WWW-Authenticate:</code> header
+ to be sent back).
+</ul>
+
+<h3><a name="log_handlers">Special considerations for logging handlers</a></h3>
+
+When a request has internally redirected, there is the question of
+what to log. Apache handles this by bundling the entire chain of
+redirects into a list of <code>request_rec</code> structures which are
+threaded through the <code>r->prev</code> and <code>r->next</code>
+pointers. The <code>request_rec</code> which is passed to the logging
+handlers in such cases is the one which was originally built for the
+intial request from the client; note that the bytes_sent field will
+only be correct in the last request in the chain (the one for which a
+response was actually sent).
+
+<h2><a name="pools">Resource allocation and resource pools</a></h2>
+
+One of the problems of writing and designing a server-pool server is
+that of preventing leakage, that is, allocating resources (memory,
+open files, etc.), without subsequently releasing them. The resource
+pool machinery is designed to make it easy to prevent this from
+happening, by allowing resource to be allocated in such a way that
+they are <em>automatically</em> released when the server is done with
+them. <p>
+
+The way this works is as follows: the memory which is allocated, file
+opened, etc., to deal with a particular request are tied to a
+<em>resource pool</em> which is allocated for the request. The pool
+is a data structure which itself tracks the resources in question. <p>
+
+When the request has been processed, the pool is <em>cleared</em>. At
+that point, all the memory associated with it is released for reuse,
+all files associated with it are closed, and any other clean-up
+functions which are associated with the pool are run. When this is
+over, we can be confident that all the resource tied to the pool have
+been released, and that none of them have leaked. <p>
+
+Server restarts, and allocation of memory and resources for per-server
+configuration, are handled in a similar way. There is a
+<em>configuration pool</em>, which keeps track of resources which were
+allocated while reading the server configuration files, and handling
+the commands therein (for instance, the memory that was allocated for
+per-server module configuration, log files and other files that were
+opened, and so forth). When the server restarts, and has to reread
+the configuration files, the configuration pool is cleared, and so the
+memory and file descriptors which were taken up by reading them the
+last time are made available for reuse. <p>
+
+It should be noted that use of the pool machinery isn't generally
+obligatory, except for situations like logging handlers, where you
+really need to register cleanups to make sure that the log file gets
+closed when the server restarts (this is most easily done by using the
+function <code><a href="#pool-files">pfopen</a></code>, which also
+arranges for the underlying file descriptor to be closed before any
+child processes, such as for CGI scripts, are <code>exec</code>ed), or
+in case you are using the timeout machinery (which isn't yet even
+documented here). However, there are two benefits to using it:
+resources allocated to a pool never leak (even if you allocate a
+scratch string, and just forget about it); also, for memory
+allocation, <code>palloc</code> is generally faster than
+<code>malloc</code>.<p>
+
+We begin here by describing how memory is allocated to pools, and then
+discuss how other resources are tracked by the resource pool
+machinery.
+
+<h3>Allocation of memory in pools</h3>
+
+Memory is allocated to pools by calling the function
+<code>palloc</code>, which takes two arguments, one being a pointer to
+a resource pool structure, and the other being the amount of memory to
+allocate (in <code>char</code>s). Within handlers for handling
+requests, the most common way of getting a resource pool structure is
+by looking at the <code>pool</code> slot of the relevant
+<code>request_rec</code>; hence the repeated appearance of the
+following idiom in module code:
+
+<pre>
+int my_handler(request_rec *r)
+{
+ struct my_structure *foo;
+ ...
+
+ foo = (foo *)palloc (r->pool, sizeof(my_structure));
+}
+</pre>
+
+Note that <em>there is no <code>pfree</code></em> ---
+<code>palloc</code>ed memory is freed only when the associated
+resource pool is cleared. This means that <code>palloc</code> doesn't
+have to do as much accounting as <code>malloc()</code>; all it does in
+the typical case is to round up the size, bump a pointer, and do a
+range check.<p>
+
+(It also raises the possibility that heavy use of <code>palloc</code>
+could cause a server process to grow excessively large. There are
+two ways to deal with this, which are dealt with below; briefly, you
+can use <code>malloc</code>, and try to be sure that all of the memory
+gets explicitly <code>free</code>d, or you can allocate a sub-pool of
+the main pool, allocate your memory in the sub-pool, and clear it out
+periodically. The latter technique is discussed in the section on
+sub-pools below, and is used in the directory-indexing code, in order
+to avoid excessive storage allocation when listing directories with
+thousands of files).
+
+<h3>Allocating initialized memory</h3>
+
+There are functions which allocate initialized memory, and are
+frequently useful. The function <code>pcalloc</code> has the same
+interface as <code>palloc</code>, but clears out the memory it
+allocates before it returns it. The function <code>pstrdup</code>
+takes a resource pool and a <code>char *</code> as arguments, and
+allocates memory for a copy of the string the pointer points to,
+returning a pointer to the copy. Finally <code>pstrcat</code> is a
+varargs-style function, which takes a pointer to a resource pool, and
+at least two <code>char *</code> arguments, the last of which must be
+<code>NULL</code>. It allocates enough memory to fit copies of each
+of the strings, as a unit; for instance:
+
+<pre>
+ pstrcat (r->pool, "foo", "/", "bar", NULL);
+</pre>
+
+returns a pointer to 8 bytes worth of memory, initialized to
+<code>"foo/bar"</code>.
+
+<h3>Tracking open files, etc.</h3>
+
+As indicated above, resource pools are also used to track other sorts
+of resources besides memory. The most common are open files. The
+routine which is typically used for this is <code>pfopen</code>, which
+takes a resource pool and two strings as arguments; the strings are
+the same as the typical arguments to <code>fopen</code>, e.g.,
+
+<pre>
+ ...
+ FILE *f = pfopen (r->pool, r->filename, "r");
+
+ if (f == NULL) { ... } else { ... }
+</pre>
+
+There is also a <code>popenf</code> routine, which parallels the
+lower-level <code>open</code> system call. Both of these routines
+arrange for the file to be closed when the resource pool in question
+is cleared. <p>
+
+Unlike the case for memory, there <em>are</em> functions to close
+files allocated with <code>pfopen</code>, and <code>popenf</code>,
+namely <code>pfclose</code> and <code>pclosef</code>. (This is
+because, on many systems, the number of files which a single process
+can have open is quite limited). It is important to use these
+functions to close files allocated with <code>pfopen</code> and
+<code>popenf</code>, since to do otherwise could cause fatal errors on
+systems such as Linux, which react badly if the same
+<code>FILE*</code> is closed more than once. <p>
+
+(Using the <code>close</code> functions is not mandatory, since the
+file will eventually be closed regardless, but you should consider it
+in cases where your module is opening, or could open, a lot of files).
+
+<h3>Other sorts of resources --- cleanup functions</h3>
+
+More text goes here. Describe the the cleanup primitives in terms of
+which the file stuff is implemented; also, <code>spawn_process</code>.
+
+<h3>Fine control --- creating and dealing with sub-pools, with a note
+on sub-requests</h3>
+
+On rare occasions, too-free use of <code>palloc()</code> and the
+associated primitives may result in undesirably profligate resource
+allocation. You can deal with such a case by creating a
+<em>sub-pool</em>, allocating within the sub-pool rather than the main
+pool, and clearing or destroying the sub-pool, which releases the
+resources which were associated with it. (This really <em>is</em> a
+rare situation; the only case in which it comes up in the standard
+module set is in case of listing directories, and then only with
+<em>very</em> large directories. Unnecessary use of the primitives
+dicussed here can hair up your code quite a bit, with very little
+gain). <p>
+
+The primitive for creating a sub-pool is <code>make_sub_pool</code>,
+which takes another pool (the parent pool) as an argument. When the
+main pool is cleared, the sub-pool will be destroyed. The sub-pool
+may also be cleared or destroyed at any time, by calling the functions
+<code>clear_pool</code> and <code>destroy_pool</code>, respectively.
+(The difference is that <code>clear_pool</code> frees resources
+associated with the pool, while <code>destroy_pool</code> also
+deallocates the pool itself. In the former case, you can allocate new
+resources within the pool, and clear it again, and so forth; in the
+latter case, it is simply gone). <p>
+
+One final note --- sub-requests have their own resource pools, which
+are sub-pools of the resource pool for the main request. The polite
+way to reclaim the resources associated with a sub request which you
+have allocated (using the <code>sub_req_lookup_...</code> functions)
+is <code>destroy_sub_request</code>, which frees the resource pool.
+Before calling this function, be sure to copy anything that you care
+about which might be allocated in the sub-request's resource pool into
+someplace a little less volatile (for instance, the filename in its
+<code>request_rec</code> structure). <p>
+
+(Again, under most circumstances, you shouldn't feel obliged to call
+this function; only 2K of memory or so are allocated for a typical sub
+request, and it will be freed anyway when the main request pool is
+cleared. It is only when you are allocating many, many sub-requests
+for a single main request that you should seriously consider the
+<code>destroy...</code> functions).
+
+<h2><a name="config">Configuration, commands and the like</a></h2>
+
+One of the design goals for this server was to maintain external
+compatibility with the NCSA 1.3 server --- that is, to read the same
+configuration files, to process all the directives therein correctly,
+and in general to be a drop-in replacement for NCSA. On the other
+hand, another design goal was to move as much of the server's
+functionality into modules which have as little as possible to do with
+the monolithic server core. The only way to reconcile these goals is
+to move the handling of most commands from the central server into the
+modules. <p>
+
+However, just giving the modules command tables is not enough to
+divorce them completely from the server core. The server has to
+remember the commands in order to act on them later. That involves
+maintaining data which is private to the modules, and which can be
+either per-server, or per-directory. Most things are per-directory,
+including in particular access control and authorization information,
+but also information on how to determine file types from suffixes,
+which can be modified by <code>AddType</code> and
+<code>DefaultType</code> directives, and so forth. In general, the
+governing philosophy is that anything which <em>can</em> be made
+configurable by directory should be; per-server information is
+generally used in the standard set of modules for information like
+<code>Alias</code>es and <code>Redirect</code>s which come into play
+before the request is tied to a particular place in the underlying
+file system. <p>
+
+Another requirement for emulating the NCSA server is being able to
+handle the per-directory configuration files, generally called
+<code>.htaccess</code> files, though even in the NCSA server they can
+contain directives which have nothing at all to do with access
+control. Accordingly, after URI -> filename translation, but before
+performing any other phase, the server walks down the directory
+hierarchy of the underlying filesystem, following the translated
+pathname, to read any <code>.htaccess</code> files which might be
+present. The information which is read in then has to be
+<em>merged</em> with the applicable information from the server's own
+config files (either from the <code><Directory></code> sections
+in <code>access.conf</code>, or from defaults in
+<code>srm.conf</code>, which actually behaves for most purposes almost
+exactly like <code><Directory /></code>).<p>
+
+Finally, after having served a request which involved reading
+<code>.htaccess</code> files, we need to discard the storage allocated
+for handling them. That is solved the same way it is solved wherever
+else similar problems come up, by tying those structures to the
+per-transaction resource pool. <p>
+
+<h3><a name="per-dir">Per-directory configuration structures</a></h3>
+
+Let's look out how all of this plays out in <code>mod_mime.c</code>,
+which defines the file typing handler which emulates the NCSA server's
+behavior of determining file types from suffixes. What we'll be
+looking at, here, is the code which implements the
+<code>AddType</code> and <code>AddEncoding</code> commands. These
+commands can appear in <code>.htaccess</code> files, so they must be
+handled in the module's private per-directory data, which in fact,
+consists of two separate <code>table</code>s for MIME types and
+encoding information, and is declared as follows:
+
+<pre>
+typedef struct {
+ table *forced_types; /* Additional AddTyped stuff */
+ table *encoding_types; /* Added with AddEncoding... */
+} mime_dir_config;
+</pre>
+
+When the server is reading a configuration file, or
+<code><Directory></code> section, which includes one of the MIME
+module's commands, it needs to create a <code>mime_dir_config</code>
+structure, so those commands have something to act on. It does this
+by invoking the function it finds in the module's "create per-dir
+config slot", with two arguments: the name of the directory to which
+this configuration information applies (or <code>NULL</code> for
+<code>srm.conf</code>), and a pointer to a resource pool in which the
+allocation should happen. <p>
+
+(If we are reading a <code>.htaccess</code> file, that resource pool
+is the per-request resource pool for the request; otherwise it is a
+resource pool which is used for configuration data, and cleared on
+restarts. Either way, it is important for the structure being created
+to vanish when the pool is cleared, by registering a cleanup on the
+pool if necessary). <p>
+
+For the MIME module, the per-dir config creation function just
+<code>palloc</code>s the structure above, and a creates a couple of
+<code>table</code>s to fill it. That looks like this:
+
+<pre>
+void *create_mime_dir_config (pool *p, char *dummy)
+{
+ mime_dir_config *new =
+ (mime_dir_config *) palloc (p, sizeof(mime_dir_config));
+
+ new->forced_types = make_table (p, 4);
+ new->encoding_types = make_table (p, 4);
+
+ return new;
+}
+</pre>
+
+Now, suppose we've just read in a <code>.htaccess</code> file. We
+already have the per-directory configuration structure for the next
+directory up in the hierarchy. If the <code>.htaccess</code> file we
+just read in didn't have any <code>AddType</code> or
+<code>AddEncoding</code> commands, its per-directory config structure
+for the MIME module is still valid, and we can just use it.
+Otherwise, we need to merge the two structures somehow. <p>
+
+To do that, the server invokes the module's per-directory config merge
+function, if one is present. That function takes three arguments:
+the two structures being merged, and a resource pool in which to
+allocate the result. For the MIME module, all that needs to be done
+is overlay the tables from the new per-directory config structure with
+those from the parent:
+
+<pre>
+void *merge_mime_dir_configs (pool *p, void *parent_dirv, void *subdirv)
+{
+ mime_dir_config *parent_dir = (mime_dir_config *)parent_dirv;
+ mime_dir_config *subdir = (mime_dir_config *)subdirv;
+ mime_dir_config *new =
+ (mime_dir_config *)palloc (p, sizeof(mime_dir_config));
+
+ new->forced_types = overlay_tables (p, subdir->forced_types,
+ parent_dir->forced_types);
+ new->encoding_types = overlay_tables (p, subdir->encoding_types,
+ parent_dir->encoding_types);
+
+ return new;
+}
+</pre>
+
+As a note --- if there is no per-directory merge function present, the
+server will just use the subdirectory's configuration info, and ignore
+the parent's. For some modules, that works just fine (e.g., for the
+includes module, whose per-directory configuration information
+consists solely of the state of the <code>XBITHACK</code>), and for
+those modules, you can just not declare one, and leave the
+corresponding structure slot in the module itself <code>NULL</code>.<p>
+
+<h3><a name="commands">Command handling</a></h3>
+
+Now that we have these structures, we need to be able to figure out
+how to fill them. That involves processing the actual
+<code>AddType</code> and <code>AddEncoding</code> commands. To find
+commands, the server looks in the module's <code>command table</code>.
+That table contains information on how many arguments the commands
+take, and in what formats, where it is permitted, and so forth. That
+information is sufficient to allow the server to invoke most
+command-handling functions with preparsed arguments. Without further
+ado, let's look at the <code>AddType</code> command handler, which
+looks like this (the <code>AddEncoding</code> command looks basically
+the same, and won't be shown here):
+
+<pre>
+char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext)
+{
+ if (*ext == '.') ++ext;
+ table_set (m->forced_types, ext, ct);
+ return NULL;
+}
+</pre>
+
+This command handler is unusually simple. As you can see, it takes
+four arguments, two of which are preparsed arguments, the third being
+the per-directory configuration structure for the module in question,
+and the fourth being a pointer to a <code>cmd_parms</code> structure.
+That structure contains a bunch of arguments which are frequently of
+use to some, but not all, commands, including a resource pool (from
+which memory can be allocated, and to which cleanups should be tied),
+and the (virtual) server being configured, from which the module's
+per-server configuration data can be obtained if required.<p>
+
+Another way in which this particular command handler is unusually
+simple is that there are no error conditions which it can encounter.
+If there were, it could return an error message instead of
+<code>NULL</code>; this causes an error to be printed out on the
+server's <code>stderr</code>, followed by a quick exit, if it is in
+the main config files; for a <code>.htaccess</code> file, the syntax
+error is logged in the server error log (along with an indication of
+where it came from), and the request is bounced with a server error
+response (HTTP error status, code 500). <p>
+
+The MIME module's command table has entries for these commands, which
+look like this:
+
+<pre>
+command_rec mime_cmds[] = {
+{ "AddType", add_type, NULL, OR_FILEINFO, TAKE2,
+ "a mime type followed by a file extension" },
+{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, TAKE2,
+ "an encoding (e.g., gzip), followed by a file extension" },
+{ NULL }
+};
+</pre>
+
+The entries in these tables are:
+
+<ul>
+ <li> The name of the command
+ <li> The function which handles it
+ <li> a <code>(void *)</code> pointer, which is passed in the
+ <code>cmd_parms</code> structure to the command handler ---
+ this is useful in case many similar commands are handled by the
+ same function.
+ <li> A bit mask indicating where the command may appear. There are
+ mask bits corresponding to each <code>AllowOverride</code>
+ option, and an additional mask bit, <code>RSRC_CONF</code>,
+ indicating that the command may appear in the server's own
+ config files, but <em>not</em> in any <code>.htaccess</code>
+ file.
+ <li> A flag indicating how many arguments the command handler wants
+ preparsed, and how they should be passed in.
+ <code>TAKE2</code> indicates two preparsed arguments. Other
+ options are <code>TAKE1</code>, which indicates one preparsed
+ argument, <code>FLAG</code>, which indicates that the argument
+ should be <code>On</code> or <code>Off</code>, and is passed in
+ as a boolean flag, <code>RAW_ARGS</code>, which causes the
+ server to give the command the raw, unparsed arguments
+ (everything but the command name itself). There is also
+ <code>ITERATE</code>, which means that the handler looks the
+ same as <code>TAKE1</code>, but that if multiple arguments are
+ present, it should be called multiple times, and finally
+ <code>ITERATE2</code>, which indicates that the command handler
+ looks like a <code>TAKE2</code>, but if more arguments are
+ present, then it should be called multiple times, holding the
+ first argument constant.
+ <li> Finally, we have a string which describes the arguments that
+ should be present. If the arguments in the actual config file
+ are not as required, this string will be used to help give a
+ more specific error message. (You can safely leave this
+ <code>NULL</code>).
+</ul>
+
+Finally, having set this all up, we have to use it. This is
+ultimately done in the module's handlers, specifically for its
+file-typing handler, which looks more or less like this; note that the
+per-directory configuration structure is extracted from the
+<code>request_rec</code>'s per-directory configuration vector by using
+the <code>get_module_config</code> function.
+
+<pre>
+int find_ct(request_rec *r)
+{
+ int i;
+ char *fn = pstrdup (r->pool, r->filename);
+ mime_dir_config *conf =
+ (mime_dir_config *)get_module_config(r->per_dir_config, &mime_module);
+ char *type;
+
+ if (S_ISDIR(r->finfo.st_mode)) {
+ r->content_type = DIR_MAGIC_TYPE;
+ return OK;
+ }
+
+ if((i=rind(fn,'.')) < 0) return DECLINED;
+ ++i;
+
+ if ((type = table_get (conf->encoding_types, &fn[i])))
+ {
+ r->content_encoding = type;
+
+ /* go back to previous extension to try to use it as a type */
+
+ fn[i-1] = '\0';
+ if((i=rind(fn,'.')) < 0) return OK;
+ ++i;
+ }
+
+ if ((type = table_get (conf->forced_types, &fn[i])))
+ {
+ r->content_type = type;
+ }
+
+ return OK;
+}
+
+</pre>
+
+<h3><a name="servconf">Side notes --- per-server configuration, virtual servers, etc.</a></h3>
+
+The basic ideas behind per-server module configuration are basically
+the same as those for per-directory configuration; there is a creation
+function and a merge function, the latter being invoked where a
+virtual server has partially overriden the base server configuration,
+and a combined structure must be computed. (As with per-directory
+configuration, the default if no merge function is specified, and a
+module is configured in some virtual server, is that the base
+configuration is simply ignored). <p>
+
+The only substantial difference is that when a command needs to
+configure the per-server private module data, it needs to go to the
+<code>cmd_parms</code> data to get at it. Here's an example, from the
+alias module, which also indicates how a syntax error can be returned
+(note that the per-directory configuration argument to the command
+handler is declared as a dummy, since the module doesn't actually have
+per-directory config data):
+
+<pre>
+char *add_redirect(cmd_parms *cmd, void *dummy, char *f, char *url)
+{
+ server_rec *s = cmd->server;
+ alias_server_conf *conf =
+ (alias_server_conf *)get_module_config(s->module_config,&alias_module);
+ alias_entry *new = push_array (conf->redirects);
+
+ if (!is_url (url)) return "Redirect to non-URL";
+
+ new->fake = f; new->real = url;
+ return NULL;
+}
+</pre>
+
--- /dev/null
+Changes with Apache 1.0.0
+
+ *) 'dbmmanage' script now takes fourth command-line argument, which is
+ group(s) of the user, if given. [Rob Hartill]
+
+ *) httpd_monitor Perl utility script added to "support" directory;
+ lets you know what your active server processes are up to. [Known
+ to work on SunOS and HP-UX at least]. [Rob Hartill]
+
+ *) Passes TZ environment variable to child processes if set on startup
+ [ David Robinson ]
+
+ *) Attempting to retrieve the URI /foo/bar/zot.map (an imagemap request
+ with *no* QUERY_STRING) returns the default URL, rather than a core
+ dump. [Mark Cox]
+
+ *) Attempting to configure auth without any "requires" lines should now
+ be equivalent to "require valid-user", rather than a core dump.
+ [Patch supplied by J. Katzman]
+
+ *) Getparents() routine fixed to handle some awkward corner cases better;
+ in particular, '/./' is eliminated from incoming URIs. Also fixed the
+ no2slash() utility routine to reduce any number of consecutive slashes
+ to one. These changes keep "trick" URIs from avoiding <Directory>
+ checks. [David Robinson]
+
+ *) Allowed any number of '/' characters to match a single '/' when
+ checking for Aliases; this keeps certain ScriptAlias directives
+ from getting bypassed. [Robert Thau]
+
+ *) DBM group code now checks all groups, not just the first [Rob Hartill]
+
+ *) "allow from good.com" no longer allows clients from nogood.com to
+ connect; formerly this was allowed because the terminal substrings
+ do match. [Robert Thau]
+
+ *) Transactions interrupted in the middle of processing some include
+ directive are now logged correctly [Robert Thau]
+
+ *) Cleaned up Configure script so it doesn't abuse EXTRA_LIBS to specify
+ host-specific default libraries. [Ben Laurie]
+
+ *) Cleaned up http_main code a bit; IdentityCheck may now work better on
+ systems with virtual hosts. [David Robinson]
+
+ *) Improved installation instructions in top-level README [Brian Behlendorf]
+
+Changes with Apache 0.8.16
+
+ *) New man page for 'httpd' added to support directory [David Robinson]
+
+ *) .htgroup files can have more than one line giving members for a
+ given group (each must have the group name in front), for NCSA
+ back-compatibility [Robert Thau]
+
+ *) Mutual exclusion around accept() is on by default for SVR4 systems
+ generally, since they generally can't handle multiple processes in
+ accept() on the same socket. This should cure flaky behavior on
+ a lot of those systems. [David Robinson]
+
+ *) AddType, AddEncoding, and AddLanguage directives take multiple
+ extensions on a single command line [David Robinson]
+
+ *) UserDir can be disabled for a given virtual host by saying
+ "UserDir disabled" in the <VirtualHost> section --- it was a bug
+ that this didn't work. [David Robinson]
+
+ *) Compiles on QNX [Ben Laurie]
+
+ *) Corrected parsing of ctime time format [David Robinson]
+
+ *) httpd does a perror() before exiting if it can't log its pid
+ to the PidFile, to make diagnosing the error a bit easier.
+ [David Robinson]
+
+ *) <!--#include file="..."--> can no longer include files in the
+ parent directory, for NCSA back-compatibility. [David Robinson]
+
+ *) '~' is *not* escaped in URIs generated for directory listings
+ [Roy Fielding]
+
+ *) Eliminated compiler warning in the imagemap module [Randy Terbush]
+
+ *) Fixed bug involving handling URIs with escaped %-characters
+ in redirects [David Robinson]
+
+Changes with Apache 0.8.15
+
+ *) Switched to new, simpler license
+
+ *) Eliminated core dumps with improperly formatted DBM group files [Mark Cox]
+
+ *) Don't allow requests for ordinary files to have PATH_INFO [Ben Laurie]
+
+ *) Reject paths containing %-escaped '%' or null characters [David Robinson]
+
+ *) Correctly handles internal redirects to files with names containing '%'
+ [David Robinson]
+
+ *) Repunctuated some error messages [Aram Mirzadeh, Andrew Wilson]
+
+ *) Use geteuid() rather than getuid() to see if we have root privilege,
+ so that server correctly resets privilege if run setuid root. [Andrew
+ Wilson]
+
+ *) Handle ftp: and telnet: URLs correctly in imagemaps (built-in module)
+ [Randy Terbush]
+
+ *) Fix relative URLs in imagemap files [Randy Terbush]
+
+ *) Somewhat better fix for the old "Alias /foo/ /bar/" business
+ [David Robinson]
+
+ *) Don't repeatedly open the ErrorLog if a bunch of <VirtualHost>
+ entries all name the same one. [David Robinson]
+
+ *) Fix directory listings with filenames containing unusual characters
+ [David Robinson]
+
+ *) Better URI-escaping for generated URIs in directories with filenames
+ containing unusual characters [Ben Laurie]
+
+ *) Fixed potential FILE* leak in http_main.c [Ben Laurie]
+
+ *) Unblock alarms on error return from spawn_child() [David Robinson]
+
+ *) Sample Config files have extra note for SCO users [Ben Laurie]
+
+ *) Configuration has note for HP-UX users [Rob Hartill]
+
+ *) Eliminated some bogus Linux-only #defines in conf.h [Aram Mirzadeh]
+
+ *) Nuked bogus #define in httpd.h [David Robinson]
+
+ *) Better test for whether a system has setrlimit() [David Robinson]
+
+ *) Calls update_child_status() after reopen_scoreboard() [David Robinson]
+
+ *) Doesn't send itself SIGHUP on startup when run in the -X debug-only mode
+ [Ben Laurie]
+
+Changes with Apache 0.8.14
+
+ *) Compiles on SCO ODT 3.0 [Ben Laurie]
+
+ *) AddDescription works (better) [Ben Laurie]
+
+ *) Leaves an intelligible error diagnostic when it can't set group
+ privileges on standalone startup [Andrew Wilson]
+
+ *) Compiles on NeXT again --- the 0.8.13 RLIMIT patch was failing on
+ that machine, which claims to be BSD but does not support RLIMIT.
+ [Randy Terbush]
+
+ *) gcc -Wall no longer complains about an unused variable when util.c
+ is compiled with -DMINIMAL_DNS [Andrew Wilson]
+
+ *) Nuked another compiler warning for -Wall on Linux [Aram Mirzadeh]
+
+Changes with Apache 0.8.13
+
+ *) Make IndexIgnore *work* (ooops) [Jarkko Torppa]
+
+ *) Have built-in imagemap code recognize & honor Point directive [James
+ Cloos]
+
+ *) Generate cleaner directory listings in directories with a mix of
+ long and short filenames [Rob Hartill]
+
+ *) Properly initialize dynamically loaded modules [Royston Shufflebotham]
+
+ *) Properly default ServerName for virtual servers [Robert Thau]
+
+ *) Rationalize handling of BSD in conf.h and elsewhere [Randy Terbush,
+ Paul Richards and a cast of thousands...]
+
+ *) On self-identified BSD systems (we don't try to guess any more),
+ allocate a few extra file descriptors per virtual host with setrlimit,
+ if we can, to avoid running out. [Randy Terbush]
+
+ *) Write 22-character lock file name into buffer with enough space
+ on startup [Konstantin Olchanski]
+
+ *) Use archaic setpgrp() interface on NeXT, which requires it [Brian
+ Pinkerton]
+
+ *) Suppress -Wall warning by casting const away in util.c [Aram Mirzadeh]
+
+ *) Suppress -Wall warning by initializing variable in negotation code
+ [Tobias Weingartner]
+
+Changes with Apache 0.8.12
+
+ *) Doesn't pause three seconds after including a CGI script which is
+ too slow to die off (this is done by not even trying to kill off
+ subprocesses, including the SIGTERM/pause/SIGKILL routine, until
+ after the entire document has been processed). [Robert Thau]
+
+ *) Doesn't do SSI if Options Includes is off. (Ooops). [David Robinson]
+
+ *) Options IncludesNoExec allows inclusion of at least text/* [Roy Fielding]
+
+ *) Allows .htaccess files to override <Directory> sections naming the
+ same directory [David Robinson]
+
+ *) Removed an efficiency hack in sub_req_lookup_uri which was
+ causing certain extremely marginal cases (e.g., ScriptAlias of a
+ *particular* index.html file) to fail. [David Robinson]
+
+ *) Doesn't log an error when the requested URI requires
+ authentication, but no auth header line was supplied by the
+ client; this is a normal condition (the client doesn't no auth is
+ needed here yet). [Robert Thau]
+
+ *) Behaves more sanely when the name server loses its mind [Sean Welch]
+
+ *) RFC931 code compiles cleanly on old BSDI releases [Randy Terbush]
+
+ *) RFC931 code no longer passes out name of prior clients on current
+ requests if the current request came from a server that doesn't
+ do RFC931. [David Robinson]
+
+ *) Configuration script accepts "Module" lines with trailing whitespace.
+ [Robert Thau]
+
+ *) Cleaned up compiler warning from mod_access.c [Robert Thau]
+
+ *) Cleaned up comments in mod_cgi.c [Robert Thau]
+
+Changes with Apache 0.8.11
+
+ *) Wildcard <Directory> specifications work. [Robert Thau]
+
+ *) Doesn't loop for buggy CGI on Solaris [Cliff Skolnick]
+
+ *) Symlink checks (FollowSymLinks off, or SymLinkIfOwnerMatch) always check
+ the file being requested itself, in addition to the directories leading
+ up to it. [Robert Thau]
+
+ *) Logs access failures due to symlink checks or invalid client address
+ in the error log [Roy Fielding, Robert Thau]
+
+ *) Symlink checks deal correctly with systems where lstat of
+ "/path/to/some/link/" follows the link. [Thau, Fielding]
+
+ *) Doesn't reset DirectoryIndex to 'index.html' when
+ other directory options are set in a .htaccess file. [Robert Thau]
+
+ *) Clarifed init code and nuked bogus warning in mod_access.c
+ [Florent Guillaume]
+
+ *) Corrected several directives in sample srm.conf
+ --- includes corrections to directory indexing icon-related directives
+ (using unknown.gif rather than unknown.xbm as the DefaultIcon, doing
+ icons for encodings right, and turning on AddEncoding by default).
+ [Roy Fielding]
+
+ *) Corrected descriptions of args to AddIcon and AddAlt in command table
+ [James Cloos]
+
+ *) INSTALL & README mention "contributed modules" directory [Brian
+ Behlendorf]
+
+ *) Fixed English in the license language... "for for" --> "for".
+ [Roy Fielding]
+
+ *) Fixed ScriptAlias/Alias interaction by moving ScriptAlias handling to
+ mod_alias.c, merging it almost completely with handling of Alias, and
+ adding a 'notes' field to the request_rec which allows the CGI module
+ to discover whether the Alias module has put this request through
+ ScriptAlias (which it needs to know for back-combatibility, as the old
+ NCSA code did not check Options ExecCGI in ScriptAliased directories).
+ [Robert Thau]
+
+
+Changes with Apache 0.8.10
+
+ *) AllowOverride applies to the named directory, and not just
+ subdirectories. [David Robinson]
+
+ *) Do locking for accept() exclusion (on systems that need it)
+ using a special file created for the purpose in /usr/tmp, and
+ not the error log; using the error log causes real problems
+ if it's NFS-mounted; this is known to be the cause of a whole
+ lot of "server hang" problems with Solaris. [David Robinson;
+ thanks to Merten Schumann for help diagnosing the problem].
+
+Changes with Apache 0.8.9
+
+ *) Compiles with -DMAXIMUM_DNS ---- ooops! [Henrik Mortensen]
+
+ *) Nested includes see environment variables of the including document,
+ for NCSA bug-compatibility (some sites have standard footer includes
+ which try to print out the last-modified date). [Eric Hagberg/Robert
+ Thau]
+
+ *) <!--exec cgi="/some/uri/here"--> always treats the item named by the
+ URI as a CGI script, even if it would have been treated as something
+ else if requested directly, for NCSA back-combatibility. (Note that
+ this means that people who know the name of the script can see the
+ code just by asking for it). [Robert Thau]
+
+ *) New version of dbmmanage script included in support directory as
+ dbmmanage.new.
+
+ *) Check if scoreboard file couldn't be opened, and say so, rather
+ then going insane [David Robinson]
+
+ *) POST to CGI works on A/UX [Jim Jaglieski]
+
+ *) AddIcon and AddAlt commands work properly [Rob Hartill]
+
+ *) NCSA server push works properly --- the Arena bug compatibility
+ workaround, which broke it, is gone (use -DARENA_BUG_WORKAROUND
+ if you still want the workaround). [Rob Hartill]
+
+ *) If client didn't submit any Accept-encodings, ignore encodings in
+ content negotiation. (NB this will all have to be reworked anyway
+ for the new HTTP draft). [Florent Guillaume]
+
+ *) Don't dump core when trying to log timed-out requests [Jim Jaglieski]
+
+ *) Really honor CacheNegotiatedDocs [Florent Guillaume]
+
+ *) Give Redirect priority over Alias, for NCSA bug compatibility
+ [David Robinson]
+
+ *) Correctly set PATH_TRANSLATED in all cases from <!--#exec cmd=""-->,
+ paralleling earlier bug fix for CGI [David Robinson]
+
+ *) If DBM auth is improperly configured, report a server error and don't
+ dump core.
+
+ *) Deleted FCNTL_SERIALIZED_ACCEPTS from conf.h entry for A/UX;
+ it seems to work well enough without it (even in a 10 hits/sec
+ workout), and the overhead for the locking under A/UX is
+ alarmingly high (though it is very low on other systems).
+ [Eric Hagberg]
+
+ *) Fixed portability problems with mod_cookies.c [Cliff Skolnick]
+
+ *) Further de-Berklize mod_cookies.c; change the bogus #include. [Brian
+ Behlendorf/Eric Hagberg]
+
+ *) More improvements to default Configuration for A/UX [Jim Jaglieski]
+
+ *) Compiles clean on NEXT [Rob Hartill]
+
+ *) Compiles clean on SGI [Robert Thau]
+
+Changes with Apache 0.8.8
+
+ *) SunOS library prototypes now never included unless explicitly
+ requested in the configuration (via -DSUNOS_LIB_PROTOTYPES);
+ people using GNU libc on SunOS are screwed by prototypes for the
+ standard library.
+
+ (Those who wish to compile clean with gcc -Wall on a standard
+ SunOS setup need the prototypes, and may obtain them using
+ -DSUNOS_LIB_PROTOTYPES. Those wishing to use -Wall on a system
+ with nonstandard libraries are presumably competent to make their
+ own arrangements).
+
+ *) Strips trailing '/' characters off both args to the Alias command,
+ to make 'Alias /foo/ /bar/' work.
+
+Changes with Apache 0.8.7
+
+ *) Don't hang when restarting with a child from 'TransferLog "|..."' running
+ [reported by David Robinson]
+
+ *) Compiles clean on OSF/1 [David Robinson]
+
+ *) Added some of the more recent significant changes (AddLanguage stuff,
+ experimental LogFormat support) to CHANGES file in distribution root
+ directory
+
+Changes with Apache 0.8.6
+
+ *) Deleted Netscape reload workaround --- it's in violation of HTTP specs.
+ (If you actually wanted a conditional GET which bypassed the cache, you
+ couldn't get it). [Reported by Roy Fielding]
+
+ *) Properly terminate headers on '304 Not Modified' replies to conditional
+ GETs --- no browser we can find cares much, but the CERN proxy chokes.
+ [Reported by Cliff Skolnick; fix discovered independently by Rob Hartill]
+
+ *) httpd -v doesn't call itself "Shambhala". [Reported by Chuck Murcko]
+
+ *) SunOS lib-function prototypes in conf.h conditionalized on __GNUC__,
+ not __SUNPRO_C (they're needed to quiet gcc -Wall, but acc chokes on 'em,
+ and older versions don't set the __SUNPRO_C preprocessor variable). On
+ all other systems, these are never used anyway. [Reported by Mark Cox].
+
+ *) Scoreboard file (/tmp/htstatus.*) no longer publically writable.
+
+Changes with Apache 0.8.5
+
+ *) Added last-minute configurable log experiment, as optional module
+
+ *) Correctly set r->bytes_sent for HTTP/0.9 requests, so they get logged
+ properly. (One-line fix to http_protocol.c).
+
+ *) Work around bogus behavior when reloading from Netscape.
+ It's Netscape's bug --- for some reason they expect a request with
+ If-modified-since: to not function as a conditional GET if it also
+ comes with Pragma: no-cache, which is way out of line with the HTTP
+ spec (according to Roy Fielding, the redactor).
+
+ *) Added parameter to set maximum number of server processes.
+
+ *) Added patches to make it work on A/UX. A/UX is *weird*. [Eric Hagberg]
+
+ *) IdentityCheck bugfix [Chuck Murcko].
+
+ *) Corrected cgi-src/Makefile entry for new imagemap script. [Alexei Kosut]
+
+ *) More sample config file corrections; add extension to AddType for
+ *.asis, move AddType generic description to its proper place, and
+ fix miscellaneous typos. [ Alexei Kosut ]
+
+ *) Deleted the *other* reference to the regents from the Berkeley
+ legal disclaimer (everyplace).
+
+ *) Nuked Shambhala name from src/README; had already cleaned it out
+ of everywhere else.
+
+Changes with Apache 0.8.4
+
+ *) Changes to server-pool management parms --- renamed current
+ StartServers to MinSpareServers, created separate StartServers
+ parameter which means what it says, and renamed MaxServers to
+ MaxSpareServers (though the old name still works, for NCSA 1.4
+ back-combatibility). The old names were generally regarded as
+ too confusing. Also altered "docs" in sample config files.
+
+ *) More improvements to default config files ---
+ sample directives (commented out) for XBitHack, BindAddress,
+ CacheNegotiatedDocs, VirtualHost; decent set of AddLanguage
+ defaults, AddTypes for send-as-is and imagemap magic types, and
+ improvements to samples for DirectoryIndex [Alexei Kosut]
+
+ *) Yet more improvements to default config files --- changes to
+ Alexei's sample AddLanguage directives, and sample LanguagePriority
+ [ Florent Guillaume ]
+
+ *) Set config file locations properly if not set in httpd.conf
+ [ David Robinson ]
+
+ *) Don't escape URIs in internal redirects multiple times; don't
+ do that when translating PATH_INFO to PATH_TRANSLATED either.
+ [ David Robinson ]
+
+ *) Corrected spelling of "Required" in 401 error reports [Andrew Wilson]
+
+Changes with Apache 0.8.3
+
+ *) Edited distribution README to *briefly* summarize installation
+ procedures, and give a pointer to the INSTALL file in the src/
+ directory.
+
+ *) Upgraded imagemap script in cgi-bin to 1.8 version from more
+ recent NCSA distributions.
+
+ *) Bug fix to previous bug fix --- if .htaccess file and <Directory>
+ exist for the same directory, use both and don't segfault. [Reported
+ by David Robinson]
+
+ *) Proper makefile dependencies [David Robinson]
+
+ *) Note (re)starts in error log --- reported by Rob Hartill.
+
+ *) Only call no2slash() after get_path_info() has been done, to
+ preserve multiple slashes in the PATH_INFO [NCSA compatibility,
+ reported by Andrew Wilson, though this one is probably a real bug]
+
+ *) Fixed mod_imap.c --- relative paths with base_uri referer don't
+ dump core when Referer is not supplied. [Randy Terbush]
+
+ *) Lightly edited sample config files to refer people to our documentation
+ instead of NCSA's, and to list Rob McCool as *original* author (also
+ deleted his old, and no doubt non-functional email address). Would be
+ nice to have examples of new features...
+
+Changes with Apache 0.8.2
+
+ *) Added AddLanuage code [Florent Guillaume]
+
+ *) Don't say "access forbidden" when a CGI script is not found. [Mark Cox]
+
+ *) All sorts of problems when MultiViews finds a directory. It would
+ be nice if mod_dir.c was robust enough to handle that, but for now,
+ just punt. [reported by Brian Behlendorf]
+
+ *) Wait for all children on restart, to make sure that the old socket
+ is gone and we can reopen it. [reported by Randy Terbush]
+
+ *) Imagemap module is enabled in default Configuration
+
+ *) RefererLog and UserAgentLog modules properly default the logfile
+ [Randy Terbush]
+
+ *) Mark Cox's mod_cookies added to the distribution as an optional
+ module (commented out in the default Configuration, and noted as
+ an experiment, along with mod_dld). [Mark Cox]
+
+ *) Compiles on Ultrix (a continuing battle...). [Robert Thau]
+
+ *) Fixed nasty bug in SIGTERM handling [reported by Randy Terbush]
+
+ *) Changed "Shambhala" to "Apache" in API docs. [Robert Thau]
+
+ *) Added new, toothier legal disclaimer. [Robert Thau; copied from BSD
+ license]
+
+Changes with Apache 0.8.1
+
+ *) New imagemap module [Randy Terbush]
+
+ *) Replacement referer log module with NCSA-compatible RefererIgnore
+ [Matthew Gray again]
+
+ *) Don't mung directory listings with very long filenames.
+ [Florent Guillaume]
+
+Changes with Apache 0.8.0 (nee Shambhala 0.6.2):
+
+ *) New config script. See INSTALL for info. [Robert Thau]
+
+ *) Scoreboard mechanism for regulating the number of extant server
+ processes. MaxServers and StartServers defaults are the same as
+ for NCSA, but the meanings are slightly different. (Actually,
+ I should probably lower the MaxServers default to 10).
+
+ Before asking for a new connection, each server process checks
+ the number of other servers which are also waiting for a
+ connection. If there are more than MaxServers, it quietly dies
+ off. Conversely, every second, the root, or caretaker, process
+ looks to see how many servers are waiting for a new connection;
+ if there are fewer than StartServers, it starts a new one. This
+ does not depend on the number of server processes already extant.
+ The accounting is arranged through a "scoreboard" file, named
+ /tmp/htstatus.*, on which each process has an independant file
+ descriptor (they need to seek without interference).
+
+ The end effect is that MaxServers is the maximum number of
+ servers on an *inactive* server machine, but more will be forked
+ off to handle unusually heavy loads (or unusually slow clients);
+ these will die off when they are no longer needed --- without
+ reverting to the overhead of full forking operation. There is a
+ hard maximum of 150 server processes compiled in, largely to
+ avoid forking out of control and dragging the machine down.
+ (This is arguably too high).
+
+ In my server endurance tests, this mechanism did not appear to
+ impose any significant overhead, even after I forced it to put the
+ scoreboard file on a normal filesystem (which might have more
+ overhead than tmpfs). [Robert Thau]
+
+ *) Set HTTP_FOO variables for SSI <!--#exec cmd-->s, not just CGI scripts.
+ [Cliff Skolnick]
+
+ *) Read .htaccess files even in directory with <Directory> section.
+ (Former incompatibility noted on mailing list, now fixed). [Robert
+ Thau]
+
+ *) "HEAD /" gives the client a "Bad Request" error message, rather
+ than trying to send no body *and* no headers. [Cliff Skolnick].
+
+ *) Don't produce double error reports for some very obscure cases
+ mainly involving auth configuration (the "all modules decline to
+ handle" case which is a sure sign of a server bug in most cases,
+ but also happens when authentication is badly misconfigured).
+ [Robert Thau]
+
+ *) Moved FCNTL_SERIALIZED_ACCEPT defines into conf.h (that's what
+ it's *for*, and this sort of thing really shouldn't be cluttering
+ up the Makefile). [Robert Thau]
+
+ *) Incidental code cleanups in http_main.c --- stop dragging
+ sa_client around; just declare it where used. [Robert Thau]
+
+ *) Another acc-related fix. (It doesn't like const char
+ in some places...). [Mark Cox]
+
+Changes with 0.6.1
+
+ *) Fixed auth_name-related typos in http_core.c [Brian Behlendorf]
+ Also, fixed auth typo in http_protocol.c unmasked by this fix.
+
+ *) Compiles clean with acc on SunOS [Paul Sutton]
+
+ *) Reordered modules in modules.c so that Redirect takes priority
+ over ScriptAlias, for NCSA bug-compatibility [Rob Hartill] ---
+ believe it or not, he has an actual site with a ScriptAlias and
+ a Redirect declared for the *exact same directory*. Even *my*
+ compatibility fetish wouldn't motivate me to fix this if the fix
+ required any effort, but it doesn't, so what the hey.
+
+ *) Fixed to properly default several server_rec fields for virtual
+ servers from the corresponding fields in the main server_rec.
+ [Cliff Skolnick --- 'port' was a particular irritant].
+
+ *) No longer kills off nph- child processes before they are
+ finished sending output. [Matthew Gray]
+
+Changes with 0.6.0
+
+ *) Two styles of timeout --- hard and soft. soft_timeout()s just put
+ the connection to the client in an "aborted" state, but otherwise
+ allow whatever handlers are running to clean up. hard_timeout()s
+ abort the request in progress completely; anything not tied to some
+ resource pool cleanup will leak. They're still around because I
+ haven't yet come up with a more elegant way of handling
+ timeouts when talking to something that isn't the client. The
+ default_handler and the dir_handler now use soft timeouts, largely
+ so I can test the feature. [Robert Thau]
+
+ *) TransferLog "| my_postprocessor ..." seems to be there. Note that
+ the case of log handlers dying prematurely is probably handled VERY
+ gracelessly at this point, and if the logger stops reading input,
+ the server will hang. (It is known to correctly restart the
+ logging process on server restart; this is (should be!) going through
+ the same SIGTERM/pause/SIGKILL routine used to ding an errant CGI
+ script). [Robert Thau]
+
+ *) asis files supported (new module). [Robert Thau]
+
+ *) IdentityCheck code is compiled in, but has not been tested. (I
+ don't know anyone who runs identd). [Robert Thau]
+
+ *) PATH_INFO and PATH_TRANSLATED are not set unless some real PATH_INFO
+ came in with the request, for NCSA bug-compatibility. [Robert Thau]
+
+ *) Don't leak the DIR * on HEAD request for a directory. [Robert Thau]
+
+ *) Deleted the block_alarms() stuff from dbm_auth; no longer necessary,
+ as timeouts are not in scope. [Robert Thau]
+
+ *) quoted-string args in config files now handled correctly (doesn't drop
+ the last character). [Robert Thau; reported by Randy Terbush]
+
+ *) Fixed silly typo in http_main.c which was suddenly fatal in HP-UX.
+ How the hell did it ever work? [Robert Thau; reported by Rob Hartill]
+
+ *) mod_core.c --- default_type returns DEFAULT_TYPE (the compile-time
+ default default type); the former default default behavior when all
+ type-checkers defaulted had been a core dump. [Paul Sutton]
+
+ *) Copy filenames out of the struct dirent when indexing
+ directories. (On Linux, readdir() returns a pointer to the same
+ memory area every time). Fix is in mod_dir.c. [Paul Sutton]
+
+Changes with 0.5.3 [not released]
+
+ *) Default response handler notes "file not found" in the error log,
+ if the file was not found. [Cliff Skolnick].
+
+ *) Another Cliff bug --- "GET /~user" now properly redirects (the userdir
+ code no longer sets up bogus PATH_INFO which fakes out the directory
+ handler). [Cliff Skolnick]
+
+Changes with 0.5.2
+
+ *) Changes to http_main.c --- root server no longer plays silly
+ games with SIGCHLD, and so now detects and replaces dying
+ children. Child processes just die on SIGTERM, without taking
+ the whole process group with them. Potential problem --- if any
+ child process refuses to die, we hang in restart.
+ MaxRequestsPerChild may still not work, but it certainly works
+ better than it did before this! [Robert Thau]
+
+ *) mod_dir.c bug fixes: ReadmeName and HeaderName
+ work (or work better, at least); over-long description lines
+ properly terminated. [Mark Cox]
+
+ *) http_request.c now calls unescape_url() more places where it
+ should [Paul Sutton].
+
+ *) More directory handling bugs (reported by Cox)
+ Parent Directory link is now set correctly. [Robert Thau]
+
+Changes with 0.5.1: [Hopefully complete]
+
+ *) Generalized cleanup interface in alloc.c --- any function can be
+ registered with alloc.c as a cleanup for a resource pool;
+ tracking of files and file descriptors has been reimplemented in
+ terms of this interface, so I can give it some sort of a test.
+ [Robert Thau]
+
+ *) More changes in alloc.c --- new cleanup_for_exec() function,
+ which tracks down and closes all file descriptors which have been
+ registered with the alloc.c machinery before the server exec()s a
+ child process for CGI or <!--#exec-->. CGI children now get
+ started with exactly three file descriptors open. Hopefully,
+ this cures the problem Rob H. was having with overly persistent
+ CGI connections. [Robert Thau]
+
+ *) Mutual exclusion around the accept() in child_main() --- this is
+ required on at least SGI, Solaris and Linux, and is #ifdef'ed in
+ by default on those systems only (-DFCNTL_SERIALIZED_ACCEPT).
+ This uses fcntl(F_SETLK,...) on the error log descriptor because
+ flock() on that descriptor won't work on systems which have BSD
+ flock() semantics, including (I think) Linux 1.3 and Solaris.
+
+ This does work on SunOS (when the server is idle, only one
+ process in the pool is waiting on accept()); it *ought* to work
+ on the other systems. [Robert Thau]
+
+ *) FreeBSD and BSDI portability tweaks [Chuck Murcko]
+
+ *) sizeof(*sa_client) bugfix from [Rob Hartill]
+
+ *) pstrdup(..., NULL) returns NULL, [Randy Terbush]
+
+ *) block_alarms() to avoid leaking the DBM* in dbm auth (this should
+ be unnecessary if I go to the revised timeout-handling scheme).
+ [Robert Thau]
+
+ *) For NCSA bug-compatibility, set QUERY_STRING env var (to a null
+ string) even if none came in with the request. [Robert Thau]
+
+ *) CHANGES file added to distribution ;-).
--- /dev/null
+# Config file for the Apache httpd.
+
+# There are three types of lines here:
+
+# '#' comments, distinguished by having a '#' as the first non-blank character
+#
+# Lines which set a Make option --- these are simply copied into the Makefile
+#
+# Module selection lines, distinguished by having 'Module' at the front.
+# These list the configured modules, in priority order (highest priority
+# first). They're down at the bottom.
+
+# First, ordinary compile-time configuration.
+
+# What to call the compiler: For normal machines with ANSI compilers
+# CC= cc
+# For Suns or other non-ANSI platforms. Please make sure your gcc is
+# 2.0 or later, as 1.40 seems to create bad code for the Sun 4.
+CC= gcc
+
+# CFLAGS, compile flags.
+
+# If you want no reverse hostname resolution, use -DMINIMAL_DNS
+# If you want to have more secure hostname resolution at the cost of some
+# performance, use -DMAXIMUM_DNS.
+# If you want setting the xbit of a file to cause it to be treated as
+# server-included HTML (unless it is a CGI script), say -DXBITHACK. Note
+# that this is a run-time option, per-directory, either way (via the XBITHACK
+# command); this option only sets the default.
+
+# [Some other former Apache compile-time options are now treated differently;
+# the virtual host code is always present; DBM auth is an optional module, and
+# may be configured out by changing the module config below, though it still
+# defaults in. Note that this config file does not include DBM auth by
+# default --- configure it in below if you need it].
+
+CFLAGS= -O2
+
+# Place here any flags you may need upon linking, such as a flag to
+# prevent dynamic linking (if desired)
+LFLAGS=
+
+# Place here any extra libraries you may need to link to.
+# -lndbm is commonly required for DBM auth, if that is configured in.
+EXTRA_LIBS=
+
+# AUX_CFLAGS are system-specific control flags.
+# NOTE: IF YOU DO NOT CHOOSE ONE OF THESE, EDIT httpd.h AND CHOOSE
+# SETTINGS FOR THE SYSTEM FLAGS. IF YOU DON'T, BAD THINGS WILL HAPPEN.
+
+# For SunOS 4
+AUX_CFLAGS= -DSUNOS4
+# For Solaris 2.
+#AUX_CFLAGS= -DSOLARIS2
+#AUX_LIBS= -lsocket -lnsl
+# For SGI IRIX. Use the AUX_LIBS line if you're using NIS and want
+# user-supported directories
+#AUX_CFLAGS= -DIRIX
+#AUX_LIBS= -lsun
+# For HP-UX n.b. if you use the paid-for HP CC compiler, use flag -Ae
+#AUX_CFLAGS= -DHPUX
+# For AIX
+#AUX_CFLAGS= -DAIX -U__STR__
+# For Ultrix
+#AUX_CFLAGS= -DULTRIX
+# For DEC OSF/1
+#AUX_CFLAGS= -DOSF1
+# For NeXT
+#AUX_CFLAGS= -DNEXT
+# For Sequent
+#AUX_CFLAGS= -DSEQUENT
+# For Linux -m486 ONLY IF YOU HAVE 486 BINARY SUPPORT IN KERNEL
+#AUX_CFLAGS= -DLINUX
+# For A/UX
+#AUX_CFLAGS= -DAUX -D_POSIX_SOURCE
+#AUX_LIBS= -lposix -lbsd -s
+# For SCO ODT
+# libcrypt_i available from sosco.sco.com, files /SLS/lng225b.Z and
+# /SLS/lng225b.ltr.Z
+# the -Oe option causes cc to die compiling mod_imap (using 3.0.0a of the dev sys)
+#CFLAGS= -Oacgiltz
+#AUX_CFLAGS= -DSCO
+#AUX_LIBS= -lPW -lsocket -lmalloc -lcrypt_i
+# For SVR4
+#AUX_CFLAGS= -DSVR4
+#AUX_LIBS= -lsocket -lnsl -lc
+# For Amdahl UTS 2.1
+# -Xa enables ANSI mode, -eft is expanded types
+#AUX_CFLAGS= -Xa -eft -DUTS21
+#AUX_LIBS= -lsocket -lbsd -la
+# For HP/Apollo Domain/OS
+#AUX_CFLAGS= -DAPOLLO
+# For NetBSD/FreeBSD/BSDI 2.x
+# -m486 only if you are running on Intel 486/586
+#AUX_CFLAGS= -m486
+# BSDI doesn't need -lcrypt
+#AUX_LIBS= -lcrypt
+# For QNX
+#AUX_CFLAGS= -DQNX
+#AUX_LFLAGS= -N 0x20000
+
+################################################################
+# Module configuration
+#
+# Modules are listed in reverse priority order --- the ones that come
+# later can override the behavior of those that come earlier. This
+# can have visible effects; for instance, if UserDir followed Alias,
+# you couldn't alias out a particular user's home directory.
+
+# Basic modules (i.e., generally useful stuff that works everyplace):
+
+Module mime_module mod_mime.o
+Module access_module mod_access.o
+Module auth_module mod_auth.o
+Module negotiation_module mod_negotiation.o
+Module includes_module mod_include.o
+Module dir_module mod_dir.o
+Module cgi_module mod_cgi.o
+Module userdir_module mod_userdir.o
+Module alias_module mod_alias.o
+Module common_log_module mod_log_common.o
+
+# Modules which implement Apache extensions:
+# These can be commented out if you don't want them
+# (or don't have the decade-old "new" DBM libs).
+
+Module asis_module mod_asis.o
+Module imap_module mod_imap.o
+# Module dbm_auth_module mod_auth_dbm.o
+
+# Optional modules for *full* NCSA compatibility --- we think these log
+# files are a bad idea, but reasonable people seem to disagree:
+
+# Module agent_log_module mod_log_agent.o
+# Module referer_log_module mod_log_referer.o
+
+# Finally, outright experiments --- mod_dld defines commands which
+# allows other modules to be loaded in at runtime, and mod_cookies
+# uses Netscape cookies to automatically construct and log accurate
+# click-trails from Netscape cookies, for Netscape-using clients who
+# aren't coming in via proxy.
+
+# Module dld_module mod_dld.o
+# Module cookies_module mod_cookies.o
+
+# Finally, this is a *replacement* for mod_log_common which
+# supports a LogFormat directive which allows you to specify what
+# goes into the TransferLog (if you want Referer, etc.) --- see the
+# source code for docs. It is likely that something like this will
+# be the default logger in a future release, but this is very much
+# an experimental piece of code, and the syntax, etc., are still
+# up for grabs.
+#
+# If you play with this, remember to drop the standard
+# mod_log_common --- a server with both will work, but you'll get
+# very confused trying to figure out what's going on...
+
+# Module config_log_module mod_log_config.o
+
+
--- /dev/null
+#! /bin/sh
+
+# Apache configuration script, first cut --- rst.
+# Dont like it? Inspired to do something better? Go for it.
+
+file=Configuration
+tmpfile=/tmp/htconf.$$
+
+if [ "x$1" = "x-file" ] ; then
+ echo "Using alternate config file $2"
+ file=$2
+else
+ echo "Using 'Configuration' as config file"
+fi
+
+# First, strip comments and blank lines...
+
+sed 's/#.*//' $file | sed '/^[ ]*$/d' | sed 's/[ ]*$//' > $tmpfile
+
+# Check for syntax errors...
+
+if grep -v = $tmpfile | \
+ egrep -v '^Module[ ]+[A-Za-z0-9_]+[ ]+[^ ]+$' > /dev/null
+then
+ echo "Syntax error --- each config file command must either"
+ echo "set a Makefile option, or configure a module (giving a"
+ echo "module name and a filename). This doesn't appear to be"
+ echo "doing either:"
+ grep -v = $tmpfile | \
+ egrep -v '^Module[ ]+[A-Za-z0-9_]+[ ]+[^ ]+$'
+ rm $tmpfile
+ exit 1
+fi
+
+# File is OK --- make backup copies of things and then get the new ones:
+
+if [ -f Makefile ] ; then mv Makefile Makefile.bak; fi
+if [ -f modules.c ] ; then mv modules.c modules.c.bak; fi
+
+awk >modules.c <$tmpfile '\
+ BEGIN { modules[n++] = "core_module" } \
+ /^Module/ { modules[n++] = $2 } \
+ END { print "/* modules.c --- automatically generated by Apache"; \
+ print " * configuration script. DO NOT HAND EDIT!!!!!"; \
+ print " */"; \
+ print ""; \
+ print "#include \"httpd.h\""; \
+ print "#include \"http_config.h\""; \
+ print ""; \
+ for (i = 0; i < n; ++i) { \
+ printf ("extern module %s;\n", modules[i]); \
+ } \
+ print ""; \
+ print "module *prelinked_modules[] = {"; \
+ for (i = 0; i < n; ++i) { \
+ printf " &%s,\n", modules[i]; \
+ } \
+ print " NULL"; \
+ print "};"; \
+ }'
+
+awk >Makefile <$tmpfile '\
+ BEGIN { print "# Makefile automatically generated from Makefile.tmpl"; \
+ print "# and configuration file by Apache config script. "; \
+ print "# Hand-edited changes will be lost if the config script"; \
+ print "# is re-run."; \
+ } \
+ /^Module/ { modules[n++] = $3 } \
+ /\=/ { print } \
+ END { print "MODULES=\\"; \
+ for (i = 0; i < n; ++i) { \
+ if (i < n-1) printf (" %s \\\n", modules[i]); \
+ else printf (" %s\n", modules[i]); \
+ } \
+ print "" \
+ }'
+
+cat Makefile.tmpl >> Makefile
+rm $tmpfile
--- /dev/null
+This release of Apache supports the notion of "optional modules".
+However, the server has to know which modules are compiled into it, in
+order for those modules to be effective; this requires generation of a
+short bit of code ("modules.c") which simply has a list of them.
+
+If you are satisfied with our standard module set, and expect to
+continue to be satisfied with it, then you can just edit the stock
+Makefile and compile as you have been doing previously. If you would
+like to select optional modules, however, you need to run the
+configuration script.
+
+To do this:
+
+1) Edit the file "Configuration". This contains the per-machine
+ config settings of the Makefile, and also an additional section at
+ the bottom which lists the modules which have been compiled in, and
+ also names the files containing them. You will need to:
+
+ a) Select a compiler, and compilation options as appropriate to
+ your machine.
+
+ b) Uncomment lines corresponding to those optional modules you wish
+ to include (among the Module lines at the bottom of the file),
+ or add new lines corresponding to custom modules you have written.
+ (See API.html for preliminary docs on how to do that).
+
+ Note that DBM auth has to be explicitly configured in, if you want
+ it --- just uncomment the corresponding line.
+
+2) Run the "Configure" script:
+
+ % Configure
+ Using 'Configuration' as config file
+ %
+
+ This generates new versions of the Makefile and of modules.c. (If
+ you want to maintain multiple configurations, you can say, e.g.,
+
+ % Configure -file Configuration.ai
+ Using alternate config file Configuration.ai
+ %
+
+3) Type "make".
+
+The modules we place in the Apache distribution are the ones we have
+tested and are used regularly by various members of the Apache
+development group. Additional modules contributed by members or third
+parties with specific needs or functions are available at
+<URL:http://www.apache.org/dist/contrib/modules/>. There are
+instructions on that page for linking these modules into the
+core Apache code.
+
+
+
--- /dev/null
+# Makefile for the Apache httpd.
+
+# For normal machines with ANSI compilers
+# CC= cc
+# For Suns or other non-ANSI platforms. Please make sure your gcc is
+# 2.0 or later, as 1.40 seems to create bad code for the Sun 4.
+CC= gcc -Wall
+
+# CFLAGS, compile flags.
+
+# If you want no reverse hostname resolution, use -DMINIMAL_DNS
+# If you want to have more secure hostname resolution at the cost of some
+# performance, use -DMAXIMUM_DNS
+
+#CFLAGS= -O2
+CFLAGS= -g
+
+# Modules precompiled with the server. Note that these must also be
+# in the list in modules.c in order to be active.
+
+MODULES = mod_mime.o mod_access.o mod_alias.o mod_cgi.o mod_include.o \
+ mod_dir.o mod_auth.o mod_auth_dbm.o mod_negotiation.o mod_userdir.o \
+ mod_log_common.o mod_asis.o
+
+# Place here any extra libraries you may need to link to.
+# If you want DBM auth, -lndbm is commonly required.
+EXTRA_LIBS=
+
+# AUX_CFLAGS are system-specific control flags.
+# NOTE: IF YOU DO NOT CHOOSE ONE OF THESE, EDIT httpd.h AND CHOOSE
+# SETTINGS FOR THE SYSTEM FLAGS. IF YOU DON'T, BAD THINGS WILL HAPPEN.
+
+# For SunOS 4
+AUX_CFLAGS= -DSUNOS4
+# For Solaris 2.
+# AUX_CFLAGS= -DSOLARIS2 -DFCNTL_SERIALIZED_ACCEPT
+# EXTRA_LIBS= -lsocket -lnsl
+# For SGI IRIX. Use the EXTRA_LIBS line if you're using NIS and want
+# user-supported directories
+#AUX_CFLAGS= -DIRIX -DFCNTL_SERIALIZED_ACCEPT
+#EXTRA_LIBS= -lsun
+# For HP-UX
+#AUX_CFLAGS= -DHPUX
+# For AIX
+#AUX_CFLAGS= -DAIX -U__STR__
+# For Ultrix
+#AUX_CFLAGS= -DULTRIX
+# For DEC OSF/1
+#AUX_CFLAGS= -DOSF1
+# For NeXT
+#AUX_CFLAGS= -DNEXT
+# For Sequent
+#AUX_CFLAGS= -DSEQUENT
+# For Linux -m486 ONLY IF YOU HAVE 486 BINARY SUPPORT IN KERNEL
+#AUX_CFLAGS= -DLINUX -DFCNTL_SERIALIZED_ACCEPT
+# For A/UX
+#AUX_CFLAGS= -DAUX
+#EXTRA_LIBS= -lbsd -lposix -s
+# For SCO ODT
+# libcrypt_i available from sosco.sco.com, files /SLS/lng225b.Z and
+# /SLS/lng225b.ltr.Z
+#AUX_CFLAGS= -DSCO
+#EXTRA_LIBS= -lPW -lsocket -lmalloc -lcrypt_i
+# For SVR4
+#AUX_CFLAGS= -DSVR4
+#EXTRA_LIBS= -lsocket -lnsl -lc
+# For Amdahl UTS 2.1
+# -Xa enables ANSI mode, -eft is expanded types
+#AUX_CFLAGS= -Xa -eft -DUTS21
+#EXTRA_LIBS= -lsocket -lbsd -la
+# For HP/Apollo Domain/OS
+#AUX_CFLAGS= -DAPOLLO
+# For NetBSD/FreeBSD/BSDI 2.x
+# -m486 only if you are running on Intel 486/586
+#AUX_CFLAGS= -m486
+# BSDI doesn't need -lcrypt
+#EXTRA_LIBS= -lcrypt
+
+# Place here any flags you may need upon linking, such as a flag to
+# prevent dynamic linking (if desired)
+LFLAGS=
+
+# You shouldn't have to edit anything else.
+
+OBJS= alloc.o http_main.o http_core.o http_config.o http_request.o \
+ http_log.o http_protocol.o rfc931.o util.o util_script.o modules.o $(MODULES)
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(AUX_CFLAGS) $<
+
+all: httpd
+
+httpd: $(OBJS)
+ $(CC) $(LFLAGS) -o httpd $(OBJS) $(EXTRA_LIBS)
+
+clean:
+ rm -f httpd $(OBJS) *pure*
+
+#Dependencies
+#Core code
+$(OBJS): Makefile httpd.h alloc.h conf.h
+
+http_config.o http_core.o http_main.o util.o: http_conf_globals.h
+http_config.o http_core.o http_main.o: http_config.h http_log.h
+http_log.o http_protocol.o http_request.o modules.o: http_config.h
+http_config.o http_core.o http_protocol.o http_request.o: http_core.h
+http_protocol.o http_request.o util_script.o: http_log.h
+http_core.o http_main.o http_protocol.o http_request.o: http_main.h
+http_core.o http_main.o http_protocol.o http_request.o: http_protocol.h
+http_config.o http_main.o http_request.o: http_request.h
+http_main.o: scoreboard.h
+
+#Modules
+$(MODULES): http_config.h
+mod_dld.o: http_conf_globals.h
+mod_ai_backcompat.o mod_auth.o mod_auth_dbm.o mod_cgi.o mod_dir.o: http_core.h
+mod_imap.o mod_include.o mod_negotiation.o: http_core.h
+mod_asis.o mod_auth.o mod_auth_dbm.o mod_cgi.o mod_dir.o: http_core.h
+mod_imap.o mod_include.o mod_negotiation.o: http_log.h
+mod_asis.o mod_cgi.o mod_dir.o mod_imap.o mod_include.o: http_main.h
+mod_asis.o mod_auth.o mod_auth_dbm.o mod_cgi.o mod_dir.o: http_protocol.h
+mod_imap.o mod_include.o: http_protocol.h
+mod_cgi.o mod_dir.o mod_imap.o mod_include.o mod_negotiation.o: http_request.h
+mod_asis.o mod_cgi.o mod_dir.o mod_imap.o mod_include.o: util_script.h
+
+#Utils
+util.o: http_conf_globals.h
+util_script.o: http_core.h http_main.h http_protocol.h util_script.h
--- /dev/null
+# Apache makefile template (well, suffix).
+
+# This is combined with the information in the "Configuration" file
+# by the configure script to make the actual Makefile.
+
+OBJS= alloc.o http_main.o http_core.o http_config.o http_request.o \
+ http_log.o http_protocol.o rfc931.o util.o util_script.o modules.o $(MODULES)
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(AUX_CFLAGS) $<
+
+all: httpd
+
+httpd: $(OBJS)
+ $(CC) $(LFLAGS) $(AUX_LFLAGS) -o httpd $(OBJS) $(EXTRA_LIBS) $(AUX_LIBS)
+
+clean:
+ rm -f httpd $(OBJS) *pure*
+
+dist.tar:
+ # Assure a semi-sensible configuration going out...
+ cp Makefile.orig Makefile
+ cp modules.c.orig modules.c
+ tar cvf dist.tar README INSTALL CHANGES TODO API.html \
+ Configuration Configure Makefile.tmpl Makefile *.h *.c
+
+#Dependencies
+#Core code
+$(OBJS): Makefile httpd.h alloc.h conf.h
+
+http_config.o http_core.o http_main.o util.o: http_conf_globals.h
+http_config.o http_core.o http_main.o: http_config.h http_log.h
+http_log.o http_protocol.o http_request.o modules.o: http_config.h
+http_config.o http_core.o http_protocol.o http_request.o: http_core.h
+http_protocol.o http_request.o util_script.o: http_log.h
+http_core.o http_main.o http_protocol.o http_request.o: http_main.h
+http_core.o http_main.o http_protocol.o http_request.o: http_protocol.h
+http_config.o http_main.o http_request.o: http_request.h
+http_main.o: scoreboard.h
+
+#Modules
+$(MODULES): http_config.h
+mod_dld.o: http_conf_globals.h
+mod_ai_backcompat.o mod_auth.o mod_auth_dbm.o mod_cgi.o mod_dir.o: http_core.h
+mod_imap.o mod_include.o mod_negotiation.o: http_core.h
+mod_asis.o mod_auth.o mod_auth_dbm.o mod_cgi.o mod_dir.o: http_core.h
+mod_imap.o mod_include.o mod_negotiation.o: http_log.h
+mod_asis.o mod_cgi.o mod_dir.o mod_imap.o mod_include.o: http_main.h
+mod_asis.o mod_auth.o mod_auth_dbm.o mod_cgi.o mod_dir.o: http_protocol.h
+mod_imap.o mod_include.o: http_protocol.h
+mod_cgi.o mod_dir.o mod_imap.o mod_include.o mod_negotiation.o: http_request.h
+mod_asis.o mod_cgi.o mod_dir.o mod_imap.o mod_include.o: util_script.h
+
+#Utils
+util.o: http_conf_globals.h
+util_script.o: http_core.h http_main.h http_protocol.h util_script.h
--- /dev/null
+The basic idea of the new Apache release is to make a modular
+"tinkertoy" server, to which people can easily add code which is
+valuable to them (even if it isn't universally useful) without hairing
+up a monolithic server. Applications for this idea include database
+integration, support for experimental search and scripting extensions,
+new authentication modes (digest authentication, for instance, could
+be done entirely as a module), and so forth. All modules have the
+same interface to the server core, and through it, to each other.
+
+In particular, the following are modules in the current code base:
+common log format (other loggers can easily coexist with it), auth and
+dbm auth (although both use common code in http_protocol.c to parse
+the Authorization: line), directory handling (which can be added or
+replaced), handling of aliases and access control, content
+negotiation, CGI, includes, aliases, and so forth. (What's left in
+the basic server? Not a whole lot). The configuration file commands
+which configure these things are defined, for the most part, by the
+modules themselves, and not by the server core (each module has, or
+can have, a command dispatch table).
+
+Besides carving up the base code into modules, this release makes a
+few other fairly pervasive changes. Most of the global variables are
+gone; most of the MAX_STRING_LENGTH char arrays are gone (the few that
+are left being sprintf() targets, or I/O buffers of various sorts),
+and unmunge_name has vanished. The most drastic change is the use of
+a "compool" strategy to manage resources allocated for a request ---
+the code in alloc.c keeps track of it all and allows it to be freed en
+bloc at the end of the request. This strategy seems to be effective
+in stanching memory and descriptor leaks.
+
+Additional third-party modules can be found at
+<URL:http://www.apache.org/dist/contrib/modules/>.
+
+
+A brief code review:
+
+The code here can be divided into the server core (the http_* files,
+along with alloc.c and the various utility files), and several modules
+(the mod_* files).
+
+The core interfaces to modules through the "module" structure which
+describes each one. There's a linked list of these things rooted at
+top_module, through which http_config.c dispatches when necessary. The
+module structures themselves are defined at the bottom of the mod_foo
+files. (Loading new modules dynamically at runtime should be simple;
+just push them onto the linked list. The only complication is what to
+do with AddModule commands when the config files are reread,
+particularly if you find a module has been taken out).
+
+In addition to the core itself (which does have a module structure to
+hold its command tables, and the handlers for various phases of
+request handling which make it *barely* a web server on its own),
+the modules included here are the following:
+
+mod_mime.c --- deduction of MIME types and content-encodings from
+ filename extensions. This module defines the AddType, AddEncoding,
+ and TypesConfig config-file directives. This code is off in a
+ module by itself so that people who want to experiment with other
+ meta-information schemes can replace it, and still have content
+ negotiation work.
+
+mod_common_log.c --- logging in common log format.
+
+mod_auth.c --- HTTP authentication. Defines the AuthUserFile and
+ AuthGroupFile directives (other auth-related commands are handled by
+ the core itself, so it knows which requests require it to poll the
+ modules for authentication handlers).
+
+mod_auth_dbm.c --- DBM auth. Untested, and left out of the modules
+ list in modules.c because of that, but it does at least compile.
+ Grump.
+
+mod_access.c --- access checking by DNS name or IP address; defines
+ the "order", "allow" and "deny" config-file commands. (If this
+ module is compiled out, the server fails safe --- any attempt to
+ configure access control will die on a config file syntax error when
+ the relevant commands go unrecognized).
+
+mod_negotiation.c --- Content negotiation. Defines the
+ CacheNegotiatedDocs config-file command. Making this a module is
+ perhaps going overboard, but I wanted to see how far I could push
+ it.
+
+mod_alias.c --- Alias command and file translation.
+
+mod_userdir.c --- ditto for Userdir.
+
+mod_cgi.c --- Common Gateway Interface. Also defines ScriptAlias,
+ because scripts are treated slightly differently depending on
+ whether they are ScriptAliased or not (in particular, ExecCGI is not
+ required in the former case).
+
+mod_includes.c --- server-side includes.
+
+mod_dir.c --- defines a whole *raft* of commands; handles directories.
+
+mod_asis.c --- ASIS file handling.
+
+mod_dld.c --- the experimental runtime-code-loader described above.
+ You'll have to alter the makefile and modules.c to make this active
+ if you want it.
+
+
+
+As to the core, here's a brief review of what's where:
+
+http_protocol.c --- functions for dealing directly with the client.
+ Reading requests, writing replies of various sorts. I've tried to
+ route all data transfer between server and client through here, so
+ there's a single piece of code to change if we want to add, say,
+ HTTP-NG packetization. The major glaring exception is NPH- CGI
+ scripts; what *will* we do with those for HTTP-NG?
+
+http_request.c --- functions which direct the processing of requests,
+ including error handling. Generally responsible for making sure
+ that the right module handlers get invoked, in the right order.
+ (This includes the "sub-request" mechanism, which is used by
+ includes and other stuff to ask about the status of particular
+ subfiles).
+
+http_core.c ---
+ Contains the core module structure, its command table, and the
+ command handlers, also the filename translation routine, and the
+ like for the core. (Basically, this is all of the core module stuff
+ which looks more or less like the boilerplate from the other modules).
+
+http_config.c --- Functions to read config files and dispatch to the
+ command handlers; also, routines to manage configuration vectors,
+ and to dispatch to modules' handlers for the various phases of
+ handling a request.
+
+http_log.c --- just the error log. Error handling is split between
+ http_protocol.c (for generating the default error responses) and
+ http_request.c (for executive handling, including ErrorDocument
+ invocation); transaction logging is in the modules.
+
+http_main.c --- System startup, restart, and accepting connections;
+ also timeout handling (which is pretty grotesque right now; ideas?)
+
+alloc.c --- allocation of all resources which might have to be reclaimed
+ eventually, including memory, files, and child processes.
+
--- /dev/null
+*) Random stray failures to get_local_addr --- it's returning EINVAL, of all
+ things. Are these clients aborting really, really early or what?
+
+*) Clean up inclusion stuff --- PATH_INFO in <!--#exec cgi-->, also
+ make sure that if the response handler sets an error code, then an
+ error report winds up on the output...
+
+*) More complete scoreboard for child processes. For each process, at least:
+ number of requests handled, start time, current request (first line and
+ client and server addresses). Also an httpstat program to print this all
+ out readably (thereby giving you your first real shot at figuring out what
+ that CGI script which has been chewing up all your CPU for the past few
+ minutes thinks it's actually doing...).
+
+*) Assess efficiency cost of rputc() in includes.
+
+*) Varargs printf-like log_reason (would allow me to ditch most of the
+ remaining instances of MAX_STRING_LENGTH).
+
+*) Byte ranges, as per recent Netscape/Franks I-D.
+
+*) Allow modules to request their own AllowOverrides and Options bits.
+ (If nothing else, will get rid of the last bit of directory-handling
+ lint in the core --- likewise for CGI and includes lint).
+
+*) -c command line option; processed as commands, *after* config files
+ (so -c "Port ..." can override).
+
+*) multiple util_files: util_time, util_string, util_sys, util_misc (?).
+
+*) Look at multithreading... known problem areas:
+ need to throw a mutex around free-block management in alloc.c; need to
+ adjust timeout and SIGPIPE handling (who got the SIGPIPE?); need to
+ create new per-connection pools in main.c (as subpools of pconf,
+ presumably), rather than just using one global ptrans pool, and need
+ to triple-check that no thread will want to allocate in the same pool
+ as another that is simultaneously running. Then we get to worry about
+ all the obscure C library functions that return pointers to static
+ data (the time stuff is particularly bad about this).
+
+ Oh yeah, the rfc931 code is nowhere near thread-safe (is it leak-safe?);
+ it has a single static jmp_buf, and returns a pointer to static data.
+
+*) Possible cleanup --- feed module functions their per-directory configuration
+ as a second argument, rather than making them fish it out of r->per_dir_....
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Resource allocation routines...
+ *
+ * designed so that we don't have to keep track of EVERYTHING so that
+ * it can be explicitly freed later (a fundamentally unsound strategy ---
+ * particularly in the presence of die()).
+ *
+ * Instead, we maintain pools, and allocate items (both memory and I/O
+ * handlers) from the pools --- currently there are two, one for per
+ * transaction info, and one for config info. When a transaction is over,
+ * we can delete everything in the per-transaction pool without fear, and
+ * without thinking too hard about it either.
+ *
+ * rst
+ */
+
+/* Arenas for configuration info and transaction info
+ * --- actual layout of the pool structure is private to
+ * alloc.c.
+ */
+
+typedef struct pool pool;
+
+extern pool *permanent_pool;
+void init_alloc(); /* Set up everything */
+pool *make_sub_pool (pool *); /* All pools are subpools of permanent_pool */
+void destroy_pool (pool *);
+
+/* Clearing out EVERYTHING in an pool... destroys any sub-pools */
+
+void clear_pool (struct pool *);
+
+/* Preparing for exec() --- close files, etc., but *don't* flush I/O
+ * buffers, *don't* wait for subprocesses, and *don't* free any memory.
+ */
+
+void cleanup_for_exec ();
+
+/* routines to allocate memory from an pool... */
+
+void *palloc(struct pool *, int nbytes);
+void *pcalloc(struct pool *, int nbytes);
+char *pstrdup(struct pool *, char *s);
+char *pstrcat(struct pool *, ...); /* all '...' must be char* */
+
+/* array and alist management... keeping lists of things.
+ * Common enough to want common support code ...
+ */
+
+typedef struct {
+ pool *pool;
+ int elt_size;
+ int nelts;
+ int nalloc;
+ char *elts;
+} array_header;
+
+array_header *make_array (pool *p, int nelts, int elt_size);
+void *push_array (array_header *);
+void array_cat (array_header *dst, array_header *src);
+array_header *append_arrays (pool *, array_header *, array_header *);
+
+/* copy_array copies the *entire* array. copy_array_hdr just copies
+ * the header, and arranges for the elements to be copied if (and only
+ * if) the code subsequently does a push or arraycat.
+ */
+
+array_header *copy_array (pool *p, array_header *src);
+array_header *copy_array_hdr (pool *p, array_header *src);
+
+
+/* Tables. Implemented alist style, for now, though we try to keep
+ * it so that imposing a hash table structure on top in the future
+ * wouldn't be *too* hard...
+ *
+ * Note that key comparisons for these are case-insensitive, largely
+ * because that's what's appropriate and convenient everywhere they're
+ * currently being used...
+ */
+
+typedef array_header table;
+
+typedef struct {
+ char *key; /* maybe NULL in future;
+ * check when iterating thru table_elts
+ */
+ char *val;
+} table_entry;
+
+table *make_table (pool *p, int nelts);
+table *copy_table (pool *p, table *);
+char *table_get (table *, char *);
+void table_set (table *, char *name, char *val);
+void table_merge (table *, char *name, char *more_val);
+
+table *overlay_tables (pool *p, table *overlay, table *base);
+
+array_header *table_elts (table *);
+
+/* routines to remember allocation of other sorts of things...
+ * generic interface first. Note that we want to have two separate
+ * cleanup functions in the general case, one for exec() preparation,
+ * to keep CGI scripts and the like from inheriting access to things
+ * they shouldn't be able to touch, and one for actually cleaning up,
+ * when the actual server process wants to get rid of the thing,
+ * whatever it is.
+ *
+ * kill_cleanup disarms a cleanup, presumably because the resource in
+ * question has been closed, freed, or whatever, and it's scarce
+ * enough to want to reclaim (e.g., descriptors). It arranges for the
+ * resource not to be cleaned up a second time (it might have been
+ * reallocated). run_cleanup does the same, but runs it first.
+ *
+ * Cleanups are identified for purposes of finding & running them off by the
+ * plain_cleanup and data, which should presumably be unique.
+ *
+ * NB any code which invokes register_cleanup or kill_cleanup directly
+ * is a critical section which should be guarded by block_alarms() and
+ * unblock_alarms() below...
+ */
+
+void register_cleanup (pool *p, void *data,
+ void (*plain_cleanup)(void *),
+ void (*child_cleanup)(void *));
+
+void kill_cleanup (pool *p, void *data, void (*plain_cleanup)(void *));
+
+/* The time between when a resource is actually allocated, and when it
+ * its cleanup is registered is a critical section, during which the
+ * resource could leak if we got interrupted or timed out. So, anything
+ * which registers cleanups should bracket resource allocation and the
+ * cleanup registry with these. (This is done internally by run_cleanup).
+ *
+ * NB they are actually implemented in http_main.c, since they are bound
+ * up with timeout handling in general...
+ */
+
+extern void block_alarms();
+extern void unblock_alarms();
+
+/* Common cases which want utility support..
+ * the note_cleanups_for_foo routines are for
+ */
+
+FILE *pfopen(struct pool *, char *name, char *fmode);
+FILE *pfdopen(struct pool *, int fd, char *fmode);
+int popenf(struct pool *, char *name, int flg, int mode);
+
+void note_cleanups_for_file (pool *, FILE *);
+void note_cleanups_for_fd (pool *, int);
+
+/* routines to note closes... file descriptors are constrained enough
+ * on some systems that we want to support this.
+ */
+
+int pfclose(struct pool *, FILE *);
+int pclosef(struct pool *, int fd);
+
+/* ... even child processes (which we may want to wait for,
+ * or to kill outright, on unexpected termination).
+ *
+ * spawn_child is a utility routine which handles an awful lot of
+ * the rigamarole associated with spawning a child --- it arranges
+ * for pipes to the child's stdin and stdout, if desired (if not,
+ * set the associated args to NULL). It takes as args a function
+ * to call in the child, and an argument to be passed to the function.
+ */
+
+enum kill_conditions { kill_never, kill_always, kill_after_timeout, just_wait};
+
+int spawn_child (pool *, void (*)(void *), void *,
+ enum kill_conditions, FILE **pipe_in, FILE **pipe_out);
+
+/* magic numbers --- only one so far, min free bytes in a new pool block */
+
+#define BLOCK_MINFREE 8192
+
+/* Finally, some accounting */
+
+long bytes_in_pool(pool *p);
+long bytes_in_free_blocks();
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * conf.h: system-dependant #defines and includes...
+ */
+
+#ifndef QNX
+#include <sys/param.h>
+#endif
+
+/* Define one of these according to your system. */
+#if defined(SUNOS4)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+char *crypt(char *pw, char *salt);
+#define JMP_BUF sigjmp_buf
+
+#elif defined(SOLARIS2)
+#undef HAS_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_RESOURCE 1
+#define bzero(a,b) memset(a,0,b)
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(IRIX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(HPUX)
+#undef HAS_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#ifndef _HPUX_SOURCE
+#define _HPUX_SOURCE
+#endif
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+#define JMP_BUF sigjmp_buf
+
+#elif defined(AIX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_SELECT_H
+#define JMP_BUF sigjmp_buf
+
+#elif defined(ULTRIX)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define ULTRIX_BRAIN_DEATH
+#define NEED_STRDUP
+/* If you have Ultrix 4.3, and are using cc, const is broken */
+#ifndef __ultrix__ /* Hack to check for pre-Ultrix 4.4 cc */
+#define const /* Not implemented */
+#endif
+#define JMP_BUF sigjmp_buf
+
+#elif defined(OSF1)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+
+#elif defined(SEQUENT)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#define tolower(c) (isupper(c) ? tolower(c) : c)
+
+#elif defined(NEXT)
+#include <libc.h>
+typedef unsigned short mode_t;
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#undef _POSIX_SOURCE
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m)&(S_IFMT)) == (S_IFDIR))
+#endif
+#ifndef S_ISREG
+#define S_ISREG(m) (((m)&(S_IFMT)) == (S_IFREG))
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 00100
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 00010
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 00001
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR S_IWRITE
+#endif
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define waitpid(a,b,c) wait4(a,(union wait *)b,c,NULL)
+typedef int pid_t;
+#define JMP_BUF jmp_buf
+
+#elif defined(LINUX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#undef NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(SCO)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define JMP_BUF sigjmp_buf
+#define SIGURG SIGUSR1 /* but note, this signal will be sent to a process group if enabled (for OOB data). It is not currently enabled. */
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+
+#elif defined(CONVEXOS)
+#define HAS_GMTOFF
+#define NEED_STRDUP
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+
+#elif defined(AUX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+
+#elif defined(SVR4)
+#define NO_KILLPG
+#undef NO_SETSID
+#undef NEED_STRDUP
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+/* A lot of SVR4 systems need this */
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(__NetBSD__)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+
+#elif defined(UTS21)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_WAITPID
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define strftime(buf,bufsize,fmt,tm) ascftime(buf,fmt,tm)
+#include <sys/types.h>
+
+#elif defined(APOLLO)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define timezone _bky_timezone
+
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+
+#elif defined(QNX)
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define JMP_BUF sigjmp_buf
+
+/* Unknown system - Edit these to match */
+#else
+#ifdef BSD
+#define HAS_GMTOFF
+#else
+#undef HAS_GMTOFF
+#endif
+/* NO_KILLPG is set on systems that don't have killpg */
+#undef NO_KILLPG
+/* NO_SETSID is set on systems that don't have setsid */
+#undef NO_SETSID
+/* NEED_STRDUP is set on stupid systems that don't have strdup. */
+#undef NEED_STRDUP
+#endif
+
+/* Do we have sys/resource.h; assume that BSD does. */
+#ifndef HAVE_RESOURCE
+#ifdef BSD
+#define HAVE_RESOURCE 1
+#else
+#define HAVE_RESOURCE 0
+#endif
+#endif /* HAVE_RESOURCE */
+
+/*
+ * The particular directory style your system supports. If you have dirent.h
+ * in /usr/include (POSIX) or /usr/include/sys (SYSV), #include
+ * that file and define DIR_TYPE to be dirent. Otherwise, if you have
+ * /usr/include/sys/dir.h, define DIR_TYPE to be direct and include that
+ * file. If you have neither, I'm confused.
+ */
+
+#include <sys/types.h>
+
+#if !defined(NEXT) && !defined(CONVEXOS)
+#include <dirent.h>
+#define DIR_TYPE dirent
+#else
+#include <sys/dir.h>
+#define DIR_TYPE direct
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#ifdef NEED_SELECT_H
+#include <sys/select.h>
+#endif
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h> /* for inet_ntoa */
+#include <time.h> /* for ctime */
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifndef QNX
+#include <memory.h>
+#endif
+
+#if HAVE_RESOURCE
+#include <sys/resource.h>
+#endif
+
+#ifndef LOGNAME_MAX
+#define LOGNAME_MAX 25
+#endif
+
+#ifndef NEXT
+#include <unistd.h>
+#endif
+
+#ifdef ultrix
+#define ULTRIX_BRAIN_DEATH
+#endif
+
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+/* Finding offsets of elements within structures.
+ * Taken from the X code... they've sweated portability of this stuff
+ * so we don't have to. Sigh...
+ */
+
+#if defined(CRAY) || defined(__arm)
+#if __STDC__
+#define XtOffset(p_type,field) _Offsetof(p_type,field)
+#else
+#ifdef CRAY2
+#define XtOffset(p_type,field) \
+ (sizeof(int)*((unsigned int)&(((p_type)NULL)->field)))
+
+#else /* !CRAY2 */
+
+#define XtOffset(p_type,field) ((unsigned int)&(((p_type)NULL)->field))
+
+#endif /* !CRAY2 */
+#endif /* __STDC__ */
+#else /* ! (CRAY || __arm) */
+
+#define XtOffset(p_type,field) \
+ ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL)))
+
+#endif /* !CRAY */
+
+#ifdef offsetof
+#define XtOffsetOf(s_type,field) offsetof(s_type,field)
+#else
+#define XtOffsetOf(s_type,field) XtOffset(s_type*,field)
+#endif
+
+#ifdef SUNOS_LIB_PROTOTYPES
+/* Prototypes needed to get a clean compile with gcc -Wall.
+ * Believe it or not, these do have to be declared, at least on SunOS,
+ * because they aren't mentioned in the relevant system headers.
+ * Sun Quality Software. Gotta love it.
+ */
+
+int getopt (int, char **, char *);
+
+int strcasecmp (char *, char *);
+int strncasecmp (char *, char *, int);
+int toupper(int);
+int tolower(int);
+
+int printf (char *, ...);
+int fprintf (FILE *, char *, ...);
+int fputs (char *, FILE *);
+int fread (char *, int, int, FILE *);
+int fwrite (char *, int, int, FILE *);
+int fflush (FILE *);
+int fclose (FILE *);
+int ungetc (int, FILE *);
+int _filbuf (FILE *); /* !!! */
+int _flsbuf (unsigned char, FILE *); /* !!! */
+int sscanf (char *, char *, ...);
+void setbuf (FILE *, char *);
+void perror (char *);
+
+time_t time (time_t *);
+int strftime (char *, int, char *, struct tm *);
+
+int initgroups (char *, int);
+int wait3 (int *, int, void*); /* Close enough for us... */
+int lstat (const char *, struct stat *);
+int stat (const char *, struct stat *);
+int flock (int, int);
+int getwd (char *);
+#ifndef NO_KILLPG
+int killpg(int, int);
+#endif
+int socket (int, int, int);
+int setsockopt (int, int, int, const char*, int);
+int listen (int, int);
+int bind (int, struct sockaddr *, int);
+int connect (int, struct sockaddr *, int);
+int accept (int, struct sockaddr *, int *);
+int shutdown (int, int);
+
+int getsockname (int s, struct sockaddr *name, int *namelen);
+int getpeername (int s, struct sockaddr *name, int *namelen);
+int gethostname (char *name, int namelen);
+void syslog (int, char *, ...);
+char *mktemp (char *);
+
+#include <stdarg.h>
+long vfprintf (FILE *, char *, va_list);
+
+#endif
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * conf.h: system-dependant #defines and includes...
+ */
+
+#ifndef QNX
+#include <sys/param.h>
+#endif
+
+/* Define one of these according to your system. */
+#if defined(SUNOS4)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+char *crypt(char *pw, char *salt);
+#define JMP_BUF sigjmp_buf
+
+#elif defined(SOLARIS2)
+#undef HAS_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#define HAVE_RESOURCE 1
+#define bzero(a,b) memset(a,0,b)
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(IRIX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(HPUX)
+#undef HAS_GMTOFF
+#define NO_KILLPG
+#undef NO_SETSID
+#ifndef _HPUX_SOURCE
+#define _HPUX_SOURCE
+#endif
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+#define JMP_BUF sigjmp_buf
+
+#elif defined(AIX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_SELECT_H
+#define JMP_BUF sigjmp_buf
+
+#elif defined(ULTRIX)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define ULTRIX_BRAIN_DEATH
+#define NEED_STRDUP
+/* If you have Ultrix 4.3, and are using cc, const is broken */
+#ifndef __ultrix__ /* Hack to check for pre-Ultrix 4.4 cc */
+#define const /* Not implemented */
+#endif
+#define JMP_BUF sigjmp_buf
+
+#elif defined(OSF1)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+
+#elif defined(SEQUENT)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#define tolower(c) (isupper(c) ? tolower(c) : c)
+
+#elif defined(NEXT)
+#include <libc.h>
+typedef unsigned short mode_t;
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_STRDUP
+#undef _POSIX_SOURCE
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m)&(S_IFMT)) == (S_IFDIR))
+#endif
+#ifndef S_ISREG
+#define S_ISREG(m) (((m)&(S_IFMT)) == (S_IFREG))
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 00100
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 00040
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 00010
+#endif
+#ifndef S_IROTH
+#define S_IROTH 00004
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 00001
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR S_IWRITE
+#endif
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define waitpid(a,b,c) wait4(a,(union wait *)b,c,NULL)
+typedef int pid_t;
+#define JMP_BUF jmp_buf
+
+#elif defined(LINUX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#undef NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(SCO)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define JMP_BUF sigjmp_buf
+#define SIGURG SIGUSR1 /* but note, this signal will be sent to a process group if enabled (for OOB data). It is not currently enabled. */
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+
+#elif defined(CONVEXOS)
+#define HAS_GMTOFF
+#define NEED_STRDUP
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+
+#elif defined(AUX)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_STRDUP
+#define JMP_BUF sigjmp_buf
+
+#elif defined(SVR4)
+#define NO_KILLPG
+#undef NO_SETSID
+#undef NEED_STRDUP
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define bzero(a,b) memset(a,0,b)
+#define JMP_BUF sigjmp_buf
+#define getwd(d) getcwd(d,MAX_STRING_LEN)
+/* A lot of SVR4 systems need this */
+#define FCNTL_SERIALIZED_ACCEPT
+
+#elif defined(__NetBSD__)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+
+#elif defined(UTS21)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#define NO_SETSID
+#define NEED_WAITPID
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define strftime(buf,bufsize,fmt,tm) ascftime(buf,fmt,tm)
+#include <sys/types.h>
+
+#elif defined(APOLLO)
+#undef HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define timezone _bky_timezone
+
+#elif defined(__FreeBSD__) || defined(__bsdi__)
+#define HAS_GMTOFF
+#undef NO_KILLPG
+#undef NO_SETSID
+#define JMP_BUF sigjmp_buf
+
+#elif defined(QNX)
+#undef NO_KILLPG
+#undef NO_SETSID
+#define NEED_INITGROUPS
+#define JMP_BUF sigjmp_buf
+
+/* Unknown system - Edit these to match */
+#else
+#ifdef BSD
+#define HAS_GMTOFF
+#else
+#undef HAS_GMTOFF
+#endif
+/* NO_KILLPG is set on systems that don't have killpg */
+#undef NO_KILLPG
+/* NO_SETSID is set on systems that don't have setsid */
+#undef NO_SETSID
+/* NEED_STRDUP is set on stupid systems that don't have strdup. */
+#undef NEED_STRDUP
+#endif
+
+/* Do we have sys/resource.h; assume that BSD does. */
+#ifndef HAVE_RESOURCE
+#ifdef BSD
+#define HAVE_RESOURCE 1
+#else
+#define HAVE_RESOURCE 0
+#endif
+#endif /* HAVE_RESOURCE */
+
+/*
+ * The particular directory style your system supports. If you have dirent.h
+ * in /usr/include (POSIX) or /usr/include/sys (SYSV), #include
+ * that file and define DIR_TYPE to be dirent. Otherwise, if you have
+ * /usr/include/sys/dir.h, define DIR_TYPE to be direct and include that
+ * file. If you have neither, I'm confused.
+ */
+
+#include <sys/types.h>
+
+#if !defined(NEXT) && !defined(CONVEXOS)
+#include <dirent.h>
+#define DIR_TYPE dirent
+#else
+#include <sys/dir.h>
+#define DIR_TYPE direct
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#ifdef NEED_SELECT_H
+#include <sys/select.h>
+#endif
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h> /* for inet_ntoa */
+#include <time.h> /* for ctime */
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifndef QNX
+#include <memory.h>
+#endif
+
+#if HAVE_RESOURCE
+#include <sys/resource.h>
+#endif
+
+#ifndef LOGNAME_MAX
+#define LOGNAME_MAX 25
+#endif
+
+#ifndef NEXT
+#include <unistd.h>
+#endif
+
+#ifdef ultrix
+#define ULTRIX_BRAIN_DEATH
+#endif
+
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+/* Finding offsets of elements within structures.
+ * Taken from the X code... they've sweated portability of this stuff
+ * so we don't have to. Sigh...
+ */
+
+#if defined(CRAY) || defined(__arm)
+#if __STDC__
+#define XtOffset(p_type,field) _Offsetof(p_type,field)
+#else
+#ifdef CRAY2
+#define XtOffset(p_type,field) \
+ (sizeof(int)*((unsigned int)&(((p_type)NULL)->field)))
+
+#else /* !CRAY2 */
+
+#define XtOffset(p_type,field) ((unsigned int)&(((p_type)NULL)->field))
+
+#endif /* !CRAY2 */
+#endif /* __STDC__ */
+#else /* ! (CRAY || __arm) */
+
+#define XtOffset(p_type,field) \
+ ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL)))
+
+#endif /* !CRAY */
+
+#ifdef offsetof
+#define XtOffsetOf(s_type,field) offsetof(s_type,field)
+#else
+#define XtOffsetOf(s_type,field) XtOffset(s_type*,field)
+#endif
+
+#ifdef SUNOS_LIB_PROTOTYPES
+/* Prototypes needed to get a clean compile with gcc -Wall.
+ * Believe it or not, these do have to be declared, at least on SunOS,
+ * because they aren't mentioned in the relevant system headers.
+ * Sun Quality Software. Gotta love it.
+ */
+
+int getopt (int, char **, char *);
+
+int strcasecmp (char *, char *);
+int strncasecmp (char *, char *, int);
+int toupper(int);
+int tolower(int);
+
+int printf (char *, ...);
+int fprintf (FILE *, char *, ...);
+int fputs (char *, FILE *);
+int fread (char *, int, int, FILE *);
+int fwrite (char *, int, int, FILE *);
+int fflush (FILE *);
+int fclose (FILE *);
+int ungetc (int, FILE *);
+int _filbuf (FILE *); /* !!! */
+int _flsbuf (unsigned char, FILE *); /* !!! */
+int sscanf (char *, char *, ...);
+void setbuf (FILE *, char *);
+void perror (char *);
+
+time_t time (time_t *);
+int strftime (char *, int, char *, struct tm *);
+
+int initgroups (char *, int);
+int wait3 (int *, int, void*); /* Close enough for us... */
+int lstat (const char *, struct stat *);
+int stat (const char *, struct stat *);
+int flock (int, int);
+int getwd (char *);
+#ifndef NO_KILLPG
+int killpg(int, int);
+#endif
+int socket (int, int, int);
+int setsockopt (int, int, int, const char*, int);
+int listen (int, int);
+int bind (int, struct sockaddr *, int);
+int connect (int, struct sockaddr *, int);
+int accept (int, struct sockaddr *, int *);
+int shutdown (int, int);
+
+int getsockname (int s, struct sockaddr *name, int *namelen);
+int getpeername (int s, struct sockaddr *name, int *namelen);
+int gethostname (char *name, int namelen);
+void syslog (int, char *, ...);
+char *mktemp (char *);
+
+#include <stdarg.h>
+long vfprintf (FILE *, char *, va_list);
+
+#endif
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Process config --- what the process ITSELF is doing
+ */
+
+extern int standalone;
+extern uid_t user_id;
+extern char *user_name;
+extern gid_t group_id;
+extern int max_requests_per_child;
+extern struct in_addr bind_address;
+extern int daemons_to_start;
+extern int daemons_min_free;
+extern int daemons_max_free;
+extern int daemons_limit;
+
+extern char *pid_fname;
+extern char *server_argv0;
+
+/* Trying to allocate these in the config pool gets us into some *nasty*
+ * chicken-and-egg problems in http_main.c --- where do you stick them
+ * when pconf gets cleared? Better to just allocate a little space
+ * statically...
+ */
+
+extern char server_root[MAX_STRING_LEN];
+extern char server_confname[MAX_STRING_LEN];
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * The central data structures around here...
+ */
+
+/* Command dispatch structures... */
+
+enum cmd_how {
+ RAW_ARGS, /* cmd_func parses command line itself */
+ TAKE1, /* one argument only */
+ TAKE2, /* two arguments only */
+ ITERATE, /* one argument, occuring multiple times
+ * (e.g., IndexIgnore)
+ */
+ ITERATE2, /* two arguments, 2nd occurs multiple times
+ * (e.g., AddIcon)
+ */
+ FLAG, /* One of 'On' or 'Off' */
+ NO_ARGS /* No args at all, e.g. </Directory> */
+};
+
+typedef struct command_struct {
+ char *name; /* Name of this command */
+ char *(*func)(); /* Function invoked */
+ void *cmd_data; /* Extra data, for functions which
+ * implement multiple commands...
+ */
+ int req_override; /* What overrides need to be allowed to
+ * enable this command.
+ */
+ enum cmd_how args_how; /* What the command expects as arguments */
+
+ char *errmsg; /* 'usage' message, in case of syntax errors */
+} command_rec;
+
+/* Values for the req_override slot */
+
+#define OR_NONE 0
+#define OR_LIMIT 1
+#define OR_OPTIONS 2
+#define OR_FILEINFO 4
+#define OR_AUTHCFG 8
+#define OR_INDEXES 16
+#define OR_UNSET 32
+#define ACCESS_CONF 64 /* command valid in access.conf */
+#define RSRC_CONF 128 /* command valid in srm.conf */
+#define OR_ALL (OR_LIMIT|OR_OPTIONS|OR_FILEINFO|OR_AUTHCFG|OR_INDEXES)
+
+/*
+ * This structure is passed to a command which is being invoked,
+ * to carry a large variety of miscellaneous data which is all of
+ * use to *somebody*...
+ */
+
+typedef struct {
+ void *info; /* Argument to command from cmd_table */
+ int override; /* Which allow-override bits are set */
+ int limited; /* Which methods are <Limit>ed */
+
+ char *config_file; /* Filename cmd read from */
+ int config_line; /* Line cmd read from */
+ FILE *infile; /* fd for more lines (not currently used) */
+
+ pool *pool; /* Pool to allocate new storage in */
+ pool *temp_pool; /* Pool for scratch memory; persists during
+ * configuration, but wiped before the first
+ * request is served...
+ */
+ server_rec *server; /* Server_rec being configured for */
+ char *path; /* If configuring for a directory,
+ * pathname of that directory.
+ */
+} cmd_parms;
+
+/* This structure records the existence of handlers in a module... */
+
+typedef struct {
+ char *content_type;
+ int (*handler) ();
+} handler_rec;
+
+/*
+ * Module structures. Just about everything is dispatched through
+ * these, directly or indirectly (through the command and handler
+ * tables).
+ */
+
+typedef struct module_struct {
+ int version; /* API version, *not* module version;
+ * check that module is compatible with this
+ * version of the server.
+ */
+ int module_index; /* Index to this modules structures in
+ * config vectors.
+ */
+ struct module_struct *next;
+
+#ifdef ULTRIX_BRAIN_DEATH
+ void (*init)();
+ void *(*create_dir_config)();
+ void *(*merge_dir_config)();
+ void *(*create_server_config)();
+ void *(*merge_server_config)();
+#else
+ void (*init)(server_rec *, pool *);
+ void *(*create_dir_config)(pool *p, char *dir);
+ void *(*merge_dir_config)(pool *p, void *base_conf, void *new_conf);
+ void *(*create_server_config)(pool *p, server_rec *s);
+ void *(*merge_server_config)(pool *p, void *base_conf, void *new_conf);
+#endif
+
+ command_rec *cmds;
+ handler_rec *handlers;
+
+ /* Hooks for getting into the middle of server ops...
+ *
+ * translate_handler --- translate URI to filename
+ * access_checker --- check access by host address, etc. All of these
+ * run; if all decline, that's still OK.
+ * check_user_id --- get and validate user id from the HTTP request
+ * auth_checker --- see if the user (from check_user_id) is OK *here*.
+ * If all of *these* decline, the request is rejected
+ * (as a SERVER_ERROR, since the module which was
+ * supposed to handle this was configured wrong).
+ * type_checker --- Determine MIME type of the requested entity;
+ * sets content_type, _encoding and _language fields.
+ * logger --- log a transaction. Not supported yet out of sheer
+ * laziness on my part.
+ */
+
+ int (*translate_handler)(request_rec *);
+ int (*check_user_id)(request_rec *);
+ int (*auth_checker)(request_rec *);
+ int (*access_checker)(request_rec *);
+ int (*type_checker)(request_rec *);
+ int (*fixer_upper)(request_rec *);
+ int (*logger)(request_rec *);
+} module;
+
+/* Initializer for the first few module slots, which are only
+ * really set up once we start running. Note that the first word
+ * is a version check; this should allow us to deal with changes to
+ * the API (the server can detect an old-format module, and either
+ * handle it back-compatibly, or at least signal an error).
+ */
+
+#define MODULE_MAGIC_NUMBER 19950525
+#define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, 0, NULL
+
+/* Generic accessors for other modules to get at their own module-specific
+ * data
+ */
+
+void *get_module_config (void *conf_vector, module *m);
+void set_module_config (void *conf_vector, module *m, void *val);
+
+/* Generic command handling function... */
+
+char *set_string_slot (cmd_parms *, char *, char *);
+
+/* For modules which need to read config files, open logs, etc. ...
+ * this returns the fname argument if it begins with '/'; otherwise
+ * it relativizes it wrt server_root.
+ */
+
+char *server_root_relative (pool *p, char *fname);
+
+/* Finally, the hook for dynamically loading modules in... */
+
+void add_module (module *m);
+
+#ifdef CORE_PRIVATE
+
+/* For http_main.c... */
+
+server_rec *read_config (pool *conf_pool, pool *temp_pool, char *config_name);
+void setup_prelinked_modules();
+
+/* For http_request.c... */
+
+void *create_request_config (pool *p);
+void *create_per_dir_config (pool *p);
+void *merge_per_dir_configs (pool *p, void *base, void *new);
+
+/* For http_core.c... (<Directory> command and virtual hosts) */
+
+int parse_htaccess(void **result, request_rec *r, int override,
+ char *path, char *file);
+char *srm_command_loop (cmd_parms *parms, void *config);
+
+server_rec *init_virtual_host (pool *p, char *hostname);
+int is_virtual_server (server_rec *);
+void process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp);
+
+/* Module-method dispatchers, also for http_request.c */
+
+int translate_name (request_rec *);
+int directory_walk (request_rec *); /* check symlinks, get per-dir config */
+int check_access (request_rec *); /* check access on non-auth basis */
+int check_user_id (request_rec *); /* obtain valid username from client auth */
+int check_auth (request_rec *); /* check (validated) user is authorized here */
+int find_types (request_rec *); /* identify MIME type */
+int run_fixups (request_rec *); /* poke around for other metainfo, etc.... */
+int invoke_handler (request_rec *);
+int log_transaction (request_rec *r);
+
+#endif
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*****************************************************************
+ *
+ * The most basic server code is encapsulated in a single module
+ * known as the core, which is just *barely* functional enough to
+ * serve documents, though not terribly well.
+ *
+ * Largely for NCSA back-compatibility reasons, the core needs to
+ * make pieces of its config structures available to other modules.
+ * The accessors are declared here, along with the interpretation
+ * of one of them (allow_options).
+ */
+
+#define OPT_NONE 0
+#define OPT_INDEXES 1
+#define OPT_INCLUDES 2
+#define OPT_SYM_LINKS 4
+#define OPT_EXECCGI 8
+#define OPT_UNSET 16
+#define OPT_INCNOEXEC 32
+#define OPT_SYM_OWNER 64
+#define OPT_MULTI 128
+#define OPT_ALL (OPT_INDEXES|OPT_INCLUDES|OPT_SYM_LINKS|OPT_EXECCGI)
+
+int allow_options (request_rec *);
+int allow_overrides (request_rec *);
+char *default_type (request_rec *);
+char *document_root (request_rec *); /* Don't use this! If your request went
+ * through a Userdir, or something like
+ * that, it'll screw you. But it's
+ * back-compatible...
+ */
+
+/* Authentication stuff. This is one of the places where compatibility
+ * with the old config files *really* hurts; they don't discriminate at
+ * all between different authentication schemes, meaning that we need
+ * to maintain common state for all of them in the core, and make it
+ * available to the other modules through interfaces.
+ */
+
+typedef struct {
+ int method_mask;
+ char *requirement;
+} require_line;
+
+char *auth_type (request_rec *);
+char *auth_name (request_rec *);
+array_header *requires (request_rec *);
+
+#ifdef CORE_PRIVATE
+
+/*
+ * Core is also unlike other modules in being implemented in more than
+ * one file... so, data structures are declared here, even though most of
+ * the code that cares really is in http_core.c. Also, anothre accessor.
+ */
+
+char *response_code_string (request_rec *r, int error_index);
+
+extern module core_module;
+
+/* Per-directory configuration */
+
+typedef char allow_options_t;
+typedef char overrides_t;
+
+typedef struct {
+ char *d;
+ allow_options_t opts;
+ overrides_t override;
+
+ /* MIME typing --- the core doesn't do anything at all with this,
+ * but it does know what to slap on a request for a document which
+ * goes untyped by other mechanisms before it slips out the door...
+ */
+
+ char *default_type;
+
+ /* Authentication stuff. Groan... */
+
+ char *auth_type;
+ char *auth_name;
+ array_header *requires;
+
+ /* Custom response config. These can contain text or a URL to redirect to.
+ */
+
+ char *response_code_strings[RESPONSE_CODES+1];
+} core_dir_config;
+
+/* Per-server core configuration */
+
+typedef struct {
+
+ /* Name translations --- we want the core to be able to do *something*
+ * so it's at least a minimally functional web server on its own (and
+ * can be tested that way). But let's keep it to the bare minimum:
+ */
+ char *document_root;
+
+ /* Access control */
+
+ char *access_name;
+ array_header *sec;
+} core_server_config;
+
+#endif
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+void open_logs (server_rec *, pool *p);
+void error_log2stderr (server_rec *);
+
+void log_pid (pool *p, char *pid_fname);
+void log_error(char *err, server_rec *s);
+void log_reason(char *reason, char *fname, request_rec *r);
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Routines in http_main.c which other code --- in particular modules ---
+ * may want to call. Right now, that's limited to timeout handling.
+ * There are two functions which modules can call to trigger a timeout
+ * (with the per-virtual-server timeout duration); these are hard_timeout
+ * and soft_timeout.
+ *
+ * The difference between the two is what happens when the timeout
+ * expires (or earlier than that, if the client connection aborts) ---
+ * a soft_timeout just puts the connection to the client in an
+ * "aborted" state, which will cause http_protocol.c to stop trying to
+ * talk to the client, but otherwise allows the code to continue normally.
+ * hard_timeout(), by contrast, logs the request, and then aborts it
+ * completely --- longjmp()ing out to the accept() loop in http_main.
+ * Any resources tied into the request's resource pool will be cleaned up;
+ * everything that isn't will leak.
+ *
+ * soft_timeout() is recommended as a general rule, because it gives your
+ * code a chance to clean up. However, hard_timeout() may be the most
+ * convenient way of dealing with timeouts waiting for some external
+ * resource other than the client, if you can live with the restrictions.
+ *
+ * (When a hard timeout is in scope, critical sections can be guarded
+ * with block_alarms() and unblock_alarms() --- these are declared in
+ * alloc.c because they are most often used in conjunction with
+ * routines to allocate something or other, to make sure that the
+ * cleanup does get registered before any alarm is allowed to happen
+ * which might require it to be cleaned up; they * are, however,
+ * implemented in http_main.c).
+ *
+ * kill_timeout() will disarm either variety of timeout.
+ */
+
+void hard_timeout (char *, request_rec *);
+void soft_timeout (char *, request_rec *);
+void kill_timeout (request_rec *);
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Prototypes for routines which either talk directly back to the user,
+ * or control the ones that eventually do.
+ */
+
+/* Read a request and fill in the fields. */
+
+request_rec *read_request (conn_rec *c);
+
+/* Send header for http response */
+
+void send_http_header (request_rec *l);
+
+/* Send error back to client... last arg indicates error status in case
+ * we get an error in the process of trying to deal with an ErrorDocument
+ * to handle some other error. In that case, we print the default report
+ * for the first thing that went wrong, and more briefly report on the
+ * problem with the ErrorDocument.
+ */
+
+void send_error_response (request_rec *r, int recursive_error);
+
+/* Set last modified header line from the lastmod date of the associated file.
+ * Also, set content length.
+ *
+ * May return an error status, typically USE_LOCAL_COPY (that when the
+ * permit_cache argument is set to one).
+ */
+
+int set_content_length (request_rec *r, long length);
+int set_last_modified (request_rec *r, time_t mtime);
+
+void add_env_var (array_header *env, char *header_name, char *val);
+
+/* Other ways to send stuff at the client. All of these keep track
+ * of bytes_sent automatically. This indirection is intended to make
+ * it a little more painless to slide things like HTTP-NG packetization
+ * underneath the main body of the code later. In the meantime, it lets
+ * us centralize a bit of accounting (bytes_sent).
+ *
+ * These also return the number of bytes written by the call.
+ * They should only be called with a timeout registered, for obvious reaasons.
+ * (Ditto the send_header stuff).
+ */
+
+long send_fd(FILE *f, request_rec *r);
+
+/* Hmmm... could macrofy these for now, and maybe forever, though the
+ * definitions of the macros would get a whole lot hairier.
+ */
+
+long rprintf (request_rec *r, char *s, ...);
+int rputc (int c, request_rec *r);
+
+/*
+ * Index used in custom_responses array for a specific error code
+ * (only use outside protocol.c is in getting them configured).
+ */
+
+int index_of_response (int status);
+
+/* Reading a block of data from the client connection (e.g., POST arg) */
+
+long read_client_block (request_rec *r, char *buffer, int bufsiz);
+
+/* Finally, this charming little number is here to encapsulate the
+ * degree to which nph- scripts completely escape from any discipline
+ * the protocol code might care to impose (this as opposed to other
+ * scripts, which *partially* escape to the extent that they may try
+ * to explicitly set the status line).
+ */
+
+void client_to_stdout (conn_rec *c);
+
+
+/* Support for the Basic authentication protocol. Note that there's
+ * nothing that prevents these from being in mod_auth.c, except that other
+ * modules which wanted to provide their own variants on finding users and
+ * passwords for Basic auth (a fairly common request) would then require
+ * mod_auth to be loaded or they wouldn't work.
+ *
+ * get_basic_auth_pw returns 0 (OK) if it set the 'pw' argument (and assured
+ * a correct value in r->connection->user); otherwise it returns an error
+ * code, either SERVER_ERROR if things are really confused, AUTH_REQUIRED
+ * if no authentication at all seemed to be in use, or DECLINED if there
+ * was authentication but it wasn't Basic (in which case, the caller should
+ * presumably decline as well).
+ *
+ * note_basic_auth_failure arranges for the right stuff to be scribbled on
+ * the HTTP return so that the client knows how to authenticate itself the
+ * next time.
+ */
+
+void note_basic_auth_failure(request_rec *r);
+int get_basic_auth_pw (request_rec *r, char **pw);
+
+/*
+ * Setting up the protocol fields for subsidiary requests...
+ * Also, a wrapup function to keep the internal accounting straight.
+ */
+
+void set_sub_req_protocol (request_rec *rnew, request_rec *r);
+void finalize_sub_req_protocol (request_rec *sub_r);
+
+/* This is also useful for putting sub_reqs and internal_redirects together */
+
+void parse_uri (request_rec *r, char *uri);
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/* http_request.c is the code which handles the main line of request
+ * processing, once a request has been read in (finding the right per-
+ * directory configuration, building it if necessary, and calling all
+ * the module dispatch functions in the right order).
+ *
+ * The pieces here which are public to the modules, allow them to learn
+ * how the server would handle some other file or URI, or perhaps even
+ * direct the server to serve that other file instead of the one the
+ * client requested directly.
+ *
+ * There are two ways to do that. The first is the sub_request mechanism,
+ * which handles looking up files and URIs as adjuncts to some other
+ * request (e.g., directory entries for multiviews and directory listings);
+ * the lookup functions stop short of actually running the request, but
+ * (e.g., for includes), a module may call for the request to be run
+ * by calling run_sub_req. The space allocated to create sub_reqs can be
+ * reclaimed by calling destroy_sub_req --- be sure to copy anything you care
+ * about which was allocated in its pool elsewhere before doing this.
+ */
+
+request_rec *sub_req_lookup_uri (char *new_file, request_rec *r);
+request_rec *sub_req_lookup_file (char *new_file, request_rec *r);
+int run_sub_req (request_rec *r);
+void destroy_sub_req (request_rec *r);
+
+/*
+ * Then there's the case that you want some other request to be served
+ * as the top-level request INSTEAD of what the client requested directly.
+ * If so, call this from a handler, and then immediately return OK.
+ */
+
+void internal_redirect (char *new_uri, request_rec *);
+
+#ifdef CORE_PRIVATE
+/* Function called by main.c to handle first-level request */
+void process_request (request_rec *);
+int default_handler (request_rec *);
+#endif
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * httpd.h: header for simple (ha! not anymore) http daemon
+ */
+
+/* Headers in which EVERYONE has an interest... */
+
+#include "conf.h"
+#include "alloc.h"
+
+/* ----------------------------- config dir ------------------------------ */
+
+/* Define this to be the default server home dir. Anything later in this
+ * file with a relative pathname will have this added.
+ */
+#define HTTPD_ROOT "/usr/local/etc/httpd"
+
+/* Root of server */
+#define DOCUMENT_LOCATION "/usr/local/etc/httpd/htdocs"
+
+/* Max. number of dynamically loaded modules */
+#define DYNAMIC_MODULE_LIMIT 64
+
+/* Default administrator's address */
+#define DEFAULT_ADMIN "[no address given]"
+
+/*
+ * --------- You shouldn't have to edit anything below this line ----------
+ *
+ * Any modifications to any defaults not defined above should be done in the
+ * respective config. file.
+ *
+ */
+
+
+/* -------------- Port number for server running standalone --------------- */
+
+#define DEFAULT_PORT 80
+
+/* --------- Default user name and group name running standalone ---------- */
+/* --- These may be specified as numbers by placing a # before a number --- */
+
+#define DEFAULT_USER "#-1"
+#define DEFAULT_GROUP "#-1"
+
+/* The name of the log files */
+#define DEFAULT_XFERLOG "logs/access_log"
+#define DEFAULT_ERRORLOG "logs/error_log"
+#define DEFAULT_PIDLOG "logs/httpd.pid"
+
+/* Define this to be what your HTML directory content files are called */
+#define DEFAULT_INDEX "index.html"
+
+/* Define this to 1 if you want fancy indexing, 0 otherwise */
+#define DEFAULT_INDEXING 0
+
+/* Define this to be what type you'd like returned for files with unknown */
+/* suffixes */
+#define DEFAULT_TYPE "text/html"
+
+/* Define this to be what your per-directory security files are called */
+#define DEFAULT_ACCESS_FNAME ".htaccess"
+
+/* The name of the server config file */
+#define SERVER_CONFIG_FILE "conf/httpd.conf"
+
+/* The name of the document config file */
+#define RESOURCE_CONFIG_FILE "conf/srm.conf"
+
+/* The name of the MIME types file */
+#define TYPES_CONFIG_FILE "conf/mime.types"
+
+/* The name of the access file */
+#define ACCESS_CONFIG_FILE "conf/access.conf"
+
+/* Whether we should enable rfc931 identity checking */
+#define DEFAULT_RFC931 0
+/* The default directory in user's home dir */
+#define DEFAULT_USER_DIR "public_html"
+
+/* The default path for CGI scripts if none is currently set */
+#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
+
+/* The path to the Bourne shell, for parsed docs */
+#define SHELL_PATH "/bin/sh"
+
+/* The default string lengths */
+#define MAX_STRING_LEN HUGE_STRING_LEN
+#define HUGE_STRING_LEN 8192
+
+/* The timeout for waiting for messages */
+#define DEFAULT_TIMEOUT 1200
+
+/* The size of the server's internal read-write buffers */
+#define IOBUFSIZE 8192
+
+/* The number of header lines we will accept from a client */
+#define MAX_HEADERS 200
+
+/* RFC 1123 format for date - this is what HTTP/1.0 wants */
+#define HTTP_TIME_FORMAT "%a, %d %b %Y %T GMT"
+
+/* Number of servers to spawn off by default --- also, if fewer than
+ * this free when the caretaker checks, it will spawn more.
+ */
+#define DEFAULT_START_DAEMON 5
+
+/* Maximum number of *free* server processes --- more than this, and
+ * they will die off.
+ */
+
+#define DEFAULT_MAX_FREE_DAEMON 10
+
+/* Minimum --- fewer than this, and more will be created */
+
+#define DEFAULT_MIN_FREE_DAEMON 5
+
+/* Limit on the total --- clients will be locked out if more servers than
+ * this are needed. It is intended solely to keep the server from crashing
+ * when things get out of hand.
+ */
+
+#define DEFAULT_SERVER_LIMIT 150
+
+/* Number of requests to try to handle in a single process. If <= 0,
+ * the children don't die off. That's the default here, since I'm still
+ * interested in finding and stanching leaks.
+ */
+
+#define DEFAULT_MAX_REQUESTS_PER_CHILD 0
+
+/* ------------------------------ error types ------------------------------ */
+
+#define SERVER_VERSION "Apache/1.0.0"
+#define SERVER_PROTOCOL "HTTP/1.0"
+#define SERVER_SUPPORT "http://www.apache.org/"
+
+#define DECLINED -1 /* Module declines to handle */
+#define OK 0 /* Module has handled this stage. */
+
+#define DOCUMENT_FOLLOWS 200
+#define REDIRECT 302
+#define USE_LOCAL_COPY 304
+#define BAD_REQUEST 400
+#define AUTH_REQUIRED 401
+#define FORBIDDEN 403
+#define NOT_FOUND 404
+#define SERVER_ERROR 500
+#define NOT_IMPLEMENTED 501
+#define SERVICE_UNAVAILABLE 503
+#define RESPONSE_CODES 10
+
+#define METHODS 5
+#define M_GET 0
+#define M_PUT 1
+#define M_POST 2
+#define M_DELETE 3
+#define M_INVALID 4
+
+#define CGI_MAGIC_TYPE "application/x-httpd-cgi"
+#define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html"
+#define INCLUDES_MAGIC_TYPE3 "text/x-server-parsed-html3"
+#define MAP_FILE_MAGIC_TYPE "application/x-type-map"
+#define ASIS_MAGIC_TYPE "httpd/send-as-is"
+#define DIR_MAGIC_TYPE "httpd/unix-directory"
+
+/* Just in case your linefeed isn't the one the other end is expecting. */
+#define LF 10
+#define CR 13
+
+/* Things which may vary per file-lookup WITHIN a request ---
+ * e.g., state of MIME config. Basically, the name of an object, info
+ * about the object, and any other info we may ahve which may need to
+ * change as we go poking around looking for it (e.g., overridden by
+ * .htaccess files).
+ *
+ * Note how the default state of almost all these things is properly
+ * zero, so that allocating it with pcalloc does the right thing without
+ * a whole lot of hairy initialization... so long as we are willing to
+ * make the (fairly) portable assumption that the bit pattern of a NULL
+ * pointer is, in fact, zero.
+ */
+
+typedef struct conn_rec conn_rec;
+typedef struct server_rec server_rec;
+typedef struct request_rec request_rec;
+
+struct request_rec {
+
+ pool *pool;
+ conn_rec *connection;
+ server_rec *server;
+
+ request_rec *next; /* If we wind up getting redirected,
+ * pointer to the request we redirected to.
+ */
+ request_rec *prev; /* If this is an internal redirect,
+ * pointer to where we redirected *from*.
+ */
+
+ request_rec *main; /* If this is a sub_request (see request.h)
+ * pointer back to the main request.
+ */
+
+ /* Info about the request itself... we begin with stuff that only
+ * protocol.c should ever touch...
+ */
+
+ char *the_request; /* First line of request, so we can log it */
+ int assbackwards; /* HTTP/0.9, "simple" request */
+ int header_only; /* HEAD request, as opposed to GET */
+ char *protocol; /* Protocol, as given to us, or HTTP/0.9 */
+
+ char *status_line; /* Status line, if set by script */
+ int status; /* In any case */
+
+ /* Request method, two ways; also, protocol, etc.. Outside of protocol.c,
+ * look, but don't touch.
+ */
+
+ char *method; /* GET, HEAD, POST, etc. */
+ int method_number; /* M_GET, M_POST, etc. */
+
+ /* int header_bytes_sent; */
+ int bytes_sent; /* body --- not headers */
+
+ /* MIME header environments, in and out. Also, an array containing
+ * environment variables to be passed to subprocesses, so people can
+ * write modules to add to that environment.
+ *
+ * The difference between headers_out and err_headers_out is that the
+ * latter are printed even on error, and persist across internal redirects
+ * (so the headers printed for ErrorDocument handlers will have them).
+ *
+ * The 'notes' table is for notes from one module to another, with no
+ * other set purpose in mind...
+ */
+
+ table *headers_in;
+ table *headers_out;
+ table *err_headers_out;
+ table *subprocess_env;
+ table *notes;
+
+ char *content_type; /* Break these out --- we dispatch on 'em */
+ char *content_encoding;
+ char *content_language;
+
+ int no_cache;
+
+ /* What object is being requested (either directly, or via include
+ * or content-negotiation mapping).
+ */
+
+ char *uri;
+ char *filename;
+ char *path_info;
+ char *args; /* QUERY_ARGS, if any */
+ struct stat finfo; /* ST_MODE set to zero if no such file */
+
+ /* Various other config info which may change with .htaccess files
+ * These are config vectors, with one void* pointer for each module
+ * (the thing pointed to being the module's business).
+ */
+
+ void *per_dir_config; /* Options set in config files, etc. */
+ void *request_config; /* Notes on *this* request */
+
+};
+
+
+/* Things which are per connection
+ */
+
+struct conn_rec {
+
+ pool *pool;
+ server_rec *server;
+
+ /* Information about the connection itself */
+
+ FILE *client; /* Connetion to the guy */
+ FILE *request_in; /* Connection from the guy */
+ int aborted; /* Are we still talking? */
+
+ /* Who is the client? */
+
+ char *remote_ip; /* Client's IP address */
+ char *remote_host; /* Client's DNS name, if known */
+ char *remote_name; /* Host ID --- same as remote_host, if known;
+ * otherwise same as remote_ip.
+ */
+ char *remote_logname; /* Only ever set if doing_rfc931 */
+
+ char *user; /* If an authentication check was made,
+ * this gets set to the user name. We assume
+ * that there's only one user per connection(!)
+ */
+ char *auth_type; /* Ditto. */
+};
+
+/* Per-vhost config... */
+
+struct server_rec {
+
+ server_rec *next;
+
+ /* Full locations of server config info */
+
+ char *srm_confname;
+ char *access_confname;
+
+ /* Contact information */
+
+ char *server_admin;
+ char *server_hostname;
+
+ /* Log files --- note that transfer log is now in the modules... */
+
+ char *error_fname;
+ FILE *error_log;
+
+ /* Module-specific configuration for server, and defaults... */
+
+ void *module_config; /* Config vector containing pointers to
+ * modules' per-server config structures.
+ */
+ void *lookup_defaults; /* MIME type info, etc., before we start
+ * checking per-directory info.
+ */
+ /* Transaction handling */
+
+ short port;
+ struct in_addr host_addr; /* Specific address, if "virtual" server */
+ int timeout; /* Timeout, in seconds, before we give up */
+ int do_rfc931; /* See if client is advertising a username? */
+
+};
+
+/* Prototypes for utilities... util.c.
+ */
+
+/* Time */
+
+struct tm *get_gmtoff(long *tz);
+char *get_time();
+char *ht_time (pool *p, time_t t, char *fmt, int gmt);
+char *gm_timestr_822(pool *p, time_t t);
+
+/* String handling */
+
+char *getword(pool *p, char **line, char stop);
+char *getword_conf (pool *p, char **line);
+
+int is_url(char *u);
+extern int unescape_url(char *url);
+void no2slash(char *name);
+void getparents(char *name);
+char *escape_path_segment(pool *p, const char *s);
+char *os_escape_path(pool *p,const char *path);
+char *escape_uri (pool *p, char *s);
+char *construct_url (pool *p, char *path, server_rec *s);
+char *escape_shell_cmd (pool *p, char *s);
+
+int count_dirs(char *path);
+char *make_dirstr(pool *a, char *s, int n);
+char *make_full_path(pool *a, char *dir, char *f);
+
+int is_matchexp(char *str);
+int strcmp_match(char *str, char *exp);
+char *uudecode (pool *, char *);
+
+void str_tolower (char *);
+int ind (const char *, char); /* Sigh... */
+int rind (const char *, char);
+
+int cfg_getline(char *s, int n, FILE *f);
+
+/* Misc system hackery */
+
+uid_t uname2id(char *name);
+gid_t gname2id(char *name);
+int is_directory(char *name);
+int can_exec(struct stat *);
+void chdir_file(char *file);
+
+char *get_local_host(pool *);
+struct in_addr get_local_addr (int sd);
+unsigned long get_virthost_addr (char *hostname, int wild_allowed);
+void get_remote_host(conn_rec *conn);
+int get_portnum(int sd);
+
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/* Scoreboard info on a process is, for now, kept very brief ---
+ * just status value and pid (the latter so that the caretaker process
+ * can properly update the scoreboard when a process dies). We may want
+ * to eventually add a separate set of long_score structures which would
+ * give, for each process, the number of requests serviced, and info on
+ * the current, or most recent, request.
+ *
+ * Status values:
+ */
+
+#define SERVER_DEAD 0 /* Unused scoreboard entry */
+#define SERVER_READY 1 /* Waiting for connection (or accept() lock) */
+#define SERVER_BUSY 2 /* Processing a client request */
+
+typedef struct {
+ pid_t pid;
+ char status;
+} short_score;
+
+/*
+ * We keep a hard maximum number of servers, for two reasons --- first off,
+ * in case something goes seriously wrong, we want to stop the fork bomb
+ * short of actually crashing the machine we're running on by filling some
+ * kernel table (I was originally going to make this 256, but it turns out
+ * that that would actually fill the process table on reasonably configured
+ * machines). Secondly, it keeps the size of the scoreboard file small
+ * enough that we can read the whole thing without worrying too much about
+ * the overhead.
+ */
+
+#define HARD_SERVER_MAX 150
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+char **create_argv(pool *p, char *av0, char *args);
+char **create_environment(pool *p, table *t);
+void add_common_vars(request_rec *r);
+int scan_script_header(request_rec *r, FILE *f);
+void send_size(size_t size, request_rec *r);
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Resource allocation code... the code here is responsible for making
+ * sure that nothing leaks.
+ *
+ * rst --- 4/95 --- 6/95
+ */
+
+#include "conf.h"
+#include "alloc.h"
+
+#include <stdarg.h>
+
+/*****************************************************************
+ *
+ * Managing free storage blocks...
+ */
+
+union align
+{
+ /* Types which are likely to have the longest RELEVANT alignment
+ * restrictions... we don't do much with doubles.
+ */
+
+ char *cp;
+ void (*f)();
+ long l;
+ FILE *fp;
+};
+
+#define CLICK_SZ (sizeof(union align))
+
+union block_hdr
+{
+ union align a;
+
+ /* Actual header... */
+
+ struct {
+ char *endp;
+ union block_hdr *next;
+ char *first_avail;
+ } h;
+};
+
+union block_hdr *block_freelist = NULL;
+
+
+
+/* Get a completely new block from the system pool */
+
+union block_hdr *malloc_block (int size)
+{
+ union block_hdr *blok =
+ (union block_hdr *)malloc(size + sizeof(union block_hdr));
+
+ if (blok == NULL) return NULL;
+
+ blok->h.next = NULL;
+ blok->h.first_avail = (char *)(blok + 1);
+ blok->h.endp = size + blok->h.first_avail;
+
+ return blok;
+}
+
+
+
+void chk_on_blk_list (union block_hdr *blok, union block_hdr *free_blk)
+{
+ /* Debugging code. Left in for the moment. */
+
+ while (free_blk) {
+ if (free_blk == blok) {
+ fprintf (stderr, "Ouch! Freeing free block\n");
+ exit (1);
+ }
+ free_blk = free_blk->h.next;
+ }
+}
+
+/* Free a chain of blocks --- must be called with alarms blocked. */
+
+void free_blocks (union block_hdr *blok)
+{
+ /* First, put new blocks at the head of the free list ---
+ * we'll eventually bash the 'next' pointer of the last block
+ * in the chain to point to the free blocks we already had.
+ */
+
+ union block_hdr *old_free_list = block_freelist;
+
+ if (blok == NULL) return; /* Sanity check --- freeing empty pool? */
+
+ block_freelist = blok;
+
+ /*
+ * Next, adjust first_avail pointers of each block --- have to do it
+ * sooner or later, and it simplifies the search in new_block to do it
+ * now.
+ */
+
+ while (blok->h.next != NULL) {
+ chk_on_blk_list (blok, old_free_list);
+ blok->h.first_avail = (char *)(blok + 1);
+ blok = blok->h.next;
+ }
+
+ chk_on_blk_list (blok, old_free_list);
+ blok->h.first_avail = (char *)(blok + 1);
+
+ /* Finally, reset next pointer to get the old free blocks back */
+
+ blok->h.next = old_free_list;
+}
+
+
+
+
+/* Get a new block, from our own free list if possible, from the system
+ * if necessary. Must be called with alarms blocked.
+ */
+
+union block_hdr *new_block (int min_size)
+{
+ union block_hdr **lastptr = &block_freelist;
+ union block_hdr *blok = block_freelist;
+
+ /* First, see if we have anything of the required size
+ * on the free list...
+ */
+
+ min_size += BLOCK_MINFREE;
+
+ while (blok != NULL) {
+ if (min_size <= blok->h.endp - blok->h.first_avail) {
+
+ *lastptr = blok->h.next;
+ blok->h.next = NULL;
+ return blok;
+ }
+ else {
+ lastptr = &blok->h.next;
+ blok = blok->h.next;
+ }
+ }
+
+ /* Nope. */
+
+ return malloc_block (min_size);
+}
+
+
+
+/* Accounting */
+
+long bytes_in_block_list (union block_hdr *blok)
+{
+ long size = 0;
+
+ while (blok) {
+ size += blok->h.endp - (char *)(blok + 1);
+ blok = blok->h.next;
+ }
+
+ return size;
+}
+
+
+/*****************************************************************
+ *
+ * Pool internals and management...
+ * NB that subprocesses are not handled by the generic cleanup code,
+ * basically because we don't want cleanups for multiple subprocesses
+ * to result in multiple three-second pauses.
+ */
+
+struct process_chain;
+struct cleanup;
+
+static void run_cleanups (struct cleanup *);
+static void free_proc_chain (struct process_chain *);
+
+struct pool {
+ union block_hdr *first;
+ union block_hdr *last;
+ struct cleanup *cleanups;
+ struct process_chain *subprocesses;
+ struct pool *sub_pools;
+ struct pool *sub_next;
+ struct pool *sub_prev;
+ struct pool *parent;
+ char *free_first_avail;
+};
+
+pool *permanent_pool;
+
+/* Each pool structure is allocated in the start of its own first block,
+ * so we need to know how many bytes that is (once properly aligned...).
+ * This also means that when a pool's sub-pool is destroyed, the storage
+ * associated with it is *completely* gone, so we have to make sure it
+ * gets taken off the parent's sub-pool list...
+ */
+
+#define POOL_HDR_CLICKS (1 + ((sizeof(struct pool) - 1) / CLICK_SZ))
+#define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ)
+
+struct pool *make_sub_pool (struct pool *p)
+{
+ union block_hdr *blok;
+ pool *new_pool;
+
+ block_alarms();
+
+ blok = new_block (0);
+ new_pool = (pool *)blok->h.first_avail;
+ blok->h.first_avail += POOL_HDR_BYTES;
+
+ memset ((char *)new_pool, '\0', sizeof (struct pool));
+ new_pool->free_first_avail = blok->h.first_avail;
+ new_pool->first = new_pool->last = blok;
+
+ if (p) {
+ new_pool->parent = p;
+ new_pool->sub_next = p->sub_pools;
+ if (new_pool->sub_next) new_pool->sub_next->sub_prev = new_pool;
+ p->sub_pools = new_pool;
+ }
+
+ unblock_alarms();
+
+ return new_pool;
+}
+
+void init_alloc() { permanent_pool = make_sub_pool (NULL); }
+
+void clear_pool (struct pool *a)
+{
+ block_alarms();
+
+ while (a->sub_pools)
+ destroy_pool (a->sub_pools);
+
+ a->sub_pools = NULL;
+
+ run_cleanups (a->cleanups); a->cleanups = NULL;
+ free_proc_chain (a->subprocesses); a->subprocesses = NULL;
+ free_blocks (a->first->h.next); a->first->h.next = NULL;
+
+ a->last = a->first;
+ a->first->h.first_avail = a->free_first_avail;
+
+ unblock_alarms();
+}
+
+void destroy_pool (pool *a)
+{
+ block_alarms();
+ clear_pool (a);
+
+ if (a->parent) {
+ if (a->parent->sub_pools == a) a->parent->sub_pools = a->sub_next;
+ if (a->sub_prev) a->sub_prev->sub_next = a->sub_next;
+ if (a->sub_next) a->sub_next->sub_prev = a->sub_prev;
+ }
+
+ free_blocks (a->first);
+ unblock_alarms();
+}
+
+long bytes_in_pool (pool *p) { return bytes_in_block_list (p->first); }
+long bytes_in_free_blocks () { return bytes_in_block_list (block_freelist); }
+
+/*****************************************************************
+ *
+ * Allocating stuff...
+ */
+
+
+void *palloc (struct pool *a, int reqsize)
+{
+ /* Round up requested size to an even number of alignment units (core clicks)
+ */
+
+ int nclicks = 1 + ((reqsize - 1) / CLICK_SZ);
+ int size = nclicks * CLICK_SZ;
+
+ /* First, see if we have space in the block most recently
+ * allocated to this pool
+ */
+
+ union block_hdr *blok = a->last;
+ char *first_avail = blok->h.first_avail;
+ char *new_first_avail;
+
+ if (size <= 0) size = 1;
+ new_first_avail = first_avail + size;
+
+ if (new_first_avail <= blok->h.endp) {
+ blok->h.first_avail = new_first_avail;
+ return (void *)first_avail;
+ }
+
+ /* Nope --- get a new one that's guaranteed to be big enough */
+
+ block_alarms();
+ blok = new_block (size);
+ a->last->h.next = blok;
+ a->last = blok;
+ unblock_alarms();
+
+ first_avail = blok->h.first_avail;
+ blok->h.first_avail += size;
+
+ return (void *)first_avail;
+}
+
+void *pcalloc(struct pool *a, int size)
+{
+ void *res = palloc (a, size);
+ memset (res, '\0', size);
+ return res;
+}
+
+char *pstrdup(struct pool *a, char *s)
+{
+ char *res;
+ if (s == NULL) return NULL;
+ res = palloc (a, strlen(s) + 1);
+ strcpy (res, s);
+ return res;
+}
+
+char *pstrcat(pool *a, ...)
+{
+ char *cp, *argp, *res;
+
+ /* Pass one --- find length of required string */
+
+ int len = 0;
+ va_list adummy;
+
+ va_start (adummy, a);
+
+ while ((cp = va_arg (adummy, char *)) != NULL)
+ len += strlen(cp);
+
+ va_end (adummy);
+
+ /* Allocate the required string */
+
+ res = (char *)palloc(a, len + 1);
+ cp = res;
+
+ /* Pass two --- copy the argument strings into the result space */
+
+ va_start (adummy, a);
+
+ while ((argp = va_arg (adummy, char *)) != NULL) {
+ strcpy (cp, argp);
+ cp += strlen(argp);
+ }
+
+ va_end (adummy);
+
+ /* Return the result string */
+
+ return res;
+}
+
+
+/*****************************************************************
+ *
+ * The 'array' functions...
+ */
+
+array_header *make_array (pool *p, int nelts, int elt_size)
+{
+ array_header *res = (array_header *)palloc(p, sizeof(array_header));
+
+ if (nelts < 1) nelts = 1; /* Assure sanity if someone asks for
+ * array of zero elts.
+ */
+
+ res->elts = pcalloc (p, nelts * elt_size);
+
+ res->pool = p;
+ res->elt_size = elt_size;
+ res->nelts = 0; /* No active elements yet... */
+ res->nalloc = nelts; /* ...but this many allocated */
+
+ return res;
+}
+
+void *push_array (array_header *arr)
+{
+ if (arr->nelts == arr->nalloc) {
+ char *new_data = pcalloc (arr->pool, arr->nalloc * arr->elt_size * 2);
+
+ memcpy (new_data, arr->elts, arr->nalloc * arr->elt_size);
+ arr->elts = new_data;
+ arr->nalloc *= 2;
+ }
+
+ ++arr->nelts;
+ return arr->elts + (arr->elt_size * (arr->nelts - 1));
+}
+
+void array_cat (array_header *dst, array_header *src)
+{
+ int elt_size = dst->elt_size;
+
+ if (dst->nelts + src->nelts > dst->nalloc) {
+ int new_size = dst->nalloc * 2;
+ char *new_data;
+
+ if (new_size == 0) ++new_size;
+
+ while (dst->nelts + src->nelts > new_size)
+ new_size *= 2;
+
+ new_data = pcalloc (dst->pool, elt_size * new_size);
+ memcpy (new_data, dst->elts, dst->nalloc * elt_size);
+
+ dst->elts = new_data;
+ dst->nalloc = new_size;
+ }
+
+ memcpy (dst->elts + dst->nelts * elt_size, src->elts, elt_size * src->nelts);
+ dst->nelts += src->nelts;
+}
+
+array_header *copy_array (pool *p, array_header *arr)
+{
+ array_header *res = make_array (p, arr->nalloc, arr->elt_size);
+
+ memcpy (res->elts, arr->elts, arr->elt_size * arr->nelts);
+ res->nelts = arr->nelts;
+ return res;
+}
+
+/* This cute function copies the array header *only*, but arranges
+ * for the data section to be copied on the first push or arraycat.
+ * It's useful when the elements of the array being copied are
+ * read only, but new stuff *might* get added on the end; we have the
+ * overhead of the full copy only where it is really needed.
+ */
+
+array_header *copy_array_hdr (pool *p, array_header *arr)
+{
+ array_header *res = (array_header *)palloc(p, sizeof(array_header));
+
+ res->elts = arr->elts;
+
+ res->pool = p;
+ res->elt_size = arr->elt_size;
+ res->nelts = arr->nelts;
+ res->nalloc = arr->nelts; /* Force overflow on push */
+
+ return res;
+}
+
+/* The above is used here to avoid consing multiple new array bodies... */
+
+array_header *append_arrays (pool *p,
+ array_header *first, array_header *second)
+{
+ array_header *res = copy_array_hdr (p, first);
+
+ array_cat (res, second);
+ return res;
+}
+
+
+/*****************************************************************
+ *
+ * The "table" functions.
+ */
+
+table *make_table (pool *p, int nelts) {
+ return make_array (p, nelts, sizeof (table_entry));
+}
+
+table *copy_table (pool *p, table *t) {
+ return copy_array (p, t);
+}
+
+array_header *table_elts (table *t) { return t; }
+
+char *table_get (table *t, char *key)
+{
+ table_entry *elts = (table_entry *)t->elts;
+ int i;
+
+ for (i = 0; i < t->nelts; ++i)
+ if (!strcasecmp (elts[i].key, key))
+ return elts[i].val;
+
+ return NULL;
+}
+
+void table_set (table *t, char *key, char *val)
+{
+ table_entry *elts = (table_entry *)t->elts;
+ int i;
+
+ for (i = 0; i < t->nelts; ++i)
+ if (!strcasecmp (elts[i].key, key)) {
+ elts[i].val = pstrdup (t->pool, val);
+ return;
+ }
+
+ elts = (table_entry *)push_array(t);
+ elts->key = pstrdup (t->pool, key);
+ elts->val = pstrdup (t->pool, val);
+}
+
+void table_merge (table *t, char *key, char *val)
+{
+ table_entry *elts = (table_entry *)t->elts;
+ int i;
+
+ for (i = 0; i < t->nelts; ++i)
+ if (!strcasecmp (elts[i].key, key)) {
+ elts[i].val = pstrcat (t->pool, elts[i].val, ", ", val, NULL);
+ return;
+ }
+
+ elts = (table_entry *)push_array(t);
+ elts->key = pstrdup (t->pool, key);
+ elts->val = pstrdup (t->pool, val);
+}
+
+table* overlay_tables (pool *p, table *overlay, table *base)
+{
+ return append_arrays (p, overlay, base);
+}
+
+/*****************************************************************
+ *
+ * Managing generic cleanups.
+ */
+
+struct cleanup {
+ void *data;
+ void (*plain_cleanup)(void *);
+ void (*child_cleanup)(void *);
+ struct cleanup *next;
+};
+
+void register_cleanup (pool *p, void *data, void (*plain_cleanup)(void *),
+ void (*child_cleanup)(void *))
+{
+ struct cleanup *c = (struct cleanup *)palloc(p, sizeof (struct cleanup));
+ c->data = data;
+ c->plain_cleanup = plain_cleanup;
+ c->child_cleanup = child_cleanup;
+ c->next = p->cleanups;
+ p->cleanups = c;
+}
+
+void kill_cleanup (pool *p, void *data, void (*cleanup)(void *))
+{
+ struct cleanup *c = p->cleanups;
+ struct cleanup **lastp = &p->cleanups;
+
+ while (c) {
+ if (c->data == data && c->plain_cleanup == cleanup) {
+ *lastp = c->next;
+ break;
+ }
+
+ lastp = &c->next;
+ c = c->next;
+ }
+}
+
+void run_cleanup (pool *p, void *data, void (*cleanup)(void *))
+{
+ block_alarms(); /* Run cleanup only once! */
+ (*cleanup)(data);
+ kill_cleanup (p, data, cleanup);
+ unblock_alarms();
+}
+
+static void run_cleanups (struct cleanup *c)
+{
+ while (c) {
+ (*c->plain_cleanup)(c->data);
+ c = c->next;
+ }
+}
+
+static void run_child_cleanups (struct cleanup *c)
+{
+ while (c) {
+ (*c->child_cleanup)(c->data);
+ c = c->next;
+ }
+}
+
+static void cleanup_pool_for_exec (pool *p)
+{
+ run_child_cleanups (p->cleanups);
+ p->cleanups = NULL;
+
+ for (p = p->sub_pools; p; p = p->sub_next)
+ cleanup_pool_for_exec (p);
+}
+
+void cleanup_for_exec()
+{
+ block_alarms();
+ cleanup_pool_for_exec (permanent_pool);
+ unblock_alarms();
+}
+
+/*****************************************************************
+ *
+ * Files and file descriptors; these are just an application of the
+ * generic cleanup interface.
+ */
+
+static void fd_cleanup (void *fdv) { close ((int)fdv); }
+
+void note_cleanups_for_fd (pool *p, int fd) {
+ register_cleanup (p, (void *)fd, fd_cleanup, fd_cleanup);
+}
+
+int popenf(struct pool *a, char *name, int flg, int mode)
+{
+ int fd;
+
+ block_alarms();
+ fd = open(name, flg, mode);
+ if (fd >= 0) note_cleanups_for_fd (a, fd);
+ unblock_alarms();
+ return fd;
+}
+
+int pclosef(struct pool *a, int fd)
+{
+ int res;
+
+ block_alarms();
+ res = close(fd);
+ kill_cleanup(a, (void *)fd, fd_cleanup);
+ unblock_alarms();
+ return res;
+}
+
+/* Note that we have separate plain_ and child_ cleanups for FILE *s,
+ * since fclose() would flush I/O buffers, which is extremely undesirable;
+ * we just close the descriptor.
+ */
+
+static void file_cleanup (void *fpv) { fclose ((FILE *)fpv); }
+static void file_child_cleanup (void *fpv) { close (fileno ((FILE *)fpv)); }
+
+void note_cleanups_for_file (struct pool *p, FILE *fp) {
+ register_cleanup (p, (void *)fp, file_cleanup, file_child_cleanup);
+}
+
+FILE *pfopen(struct pool *a, char *name, char *mode)
+{
+ FILE *fd;
+
+ block_alarms();
+ fd = fopen(name, mode);
+ if (fd != NULL) note_cleanups_for_file (a, fd);
+ unblock_alarms();
+ return fd;
+}
+
+FILE *pfdopen(struct pool *a,int fd,char *mode)
+{
+ FILE *f;
+
+ block_alarms();
+ f=fdopen(fd,mode);
+ if(f != NULL)
+ note_cleanups_for_file(a,f);
+ unblock_alarms();
+ return f;
+}
+
+
+int pfclose(struct pool *a, FILE *fd)
+{
+ int res;
+
+ block_alarms();
+ res = fclose(fd);
+ kill_cleanup(a, (void *)fd, file_cleanup);
+ unblock_alarms();
+ return res;
+}
+
+/*****************************************************************
+ *
+ * More grotty system stuff... subprocesses. Frump. These don't use
+ * the generic cleanup interface because I don't want multiple
+ * subprocesses to result in multiple three-second pauses; the
+ * subprocesses have to be "freed" all at once. If someone comes
+ * along with another resource they want to allocate which has the
+ * same property, we might want to fold support for that into the
+ * generic interface, but for now, it's a special case
+ */
+
+struct process_chain {
+ pid_t pid;
+ enum kill_conditions kill_how;
+ struct process_chain *next;
+};
+
+void note_subprocess (pool *a, int pid, enum kill_conditions how)
+{
+ struct process_chain *new =
+ (struct process_chain *)palloc(a, sizeof(struct process_chain));
+
+ new->pid = pid;
+ new->kill_how = how;
+ new->next = a->subprocesses;
+ a->subprocesses = new;
+}
+
+int spawn_child (pool *p, void (*func)(void *), void *data,
+ enum kill_conditions kill_how,
+ FILE **pipe_in, FILE **pipe_out)
+{
+ int pid;
+ int in_fds[2];
+ int out_fds[2];
+
+ block_alarms();
+
+ if (pipe_in && pipe (in_fds) < 0)
+ {
+ unblock_alarms();
+ return 0;
+ }
+
+ if (pipe_out && pipe (out_fds) < 0) {
+ if (pipe_in) {
+ close (in_fds[0]); close (in_fds[1]);
+ }
+ unblock_alarms();
+ return 0;
+ }
+
+ if ((pid = fork()) < 0) {
+ if (pipe_in) {
+ close (in_fds[0]); close (in_fds[1]);
+ }
+ if (pipe_out) {
+ close (out_fds[0]); close (out_fds[1]);
+ }
+ unblock_alarms();
+ return 0;
+ }
+
+ if (!pid) {
+ /* Child process */
+
+ if (pipe_out) {
+ close (out_fds[0]);
+ dup2 (out_fds[1], STDOUT_FILENO);
+ close (out_fds[1]);
+ }
+
+ if (pipe_in) {
+ close (in_fds[1]);
+ dup2 (in_fds[0], STDIN_FILENO);
+ close (in_fds[0]);
+ }
+
+ /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */
+ signal (SIGCHLD, SIG_DFL); /* Was that it? */
+
+ func (data);
+ exit (0); /* Should never get here... */
+ }
+
+ /* Parent process */
+
+ note_subprocess (p, pid, kill_how);
+
+ if (pipe_out) {
+ close (out_fds[1]);
+ *pipe_out = fdopen (out_fds[0], "r");
+
+ if (*pipe_out) note_cleanups_for_file (p, *pipe_out);
+ }
+
+ if (pipe_in) {
+ close (in_fds[0]);
+ *pipe_in = fdopen (in_fds[1], "w");
+
+ if (*pipe_in) note_cleanups_for_file (p, *pipe_in);
+ }
+
+ unblock_alarms();
+ return pid;
+}
+
+static void free_proc_chain (struct process_chain *procs)
+{
+ /* Dispose of the subprocesses we've spawned off in the course of
+ * whatever it was we're cleaning up now. This may involve killing
+ * some of them off...
+ */
+
+ struct process_chain *p;
+ int need_timeout = 0;
+ int status;
+
+ if (procs == NULL) return; /* No work. Whew! */
+
+ /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL
+ * dance with any of the processes we're cleaning up. If we've got
+ * any kill-on-sight subprocesses, ditch them now as well, so they
+ * don't waste any more cycles doing whatever it is that they shouldn't
+ * be doing anymore.
+ */
+
+ for (p = procs; p; p = p->next) {
+ if (p->kill_how == kill_after_timeout) {
+ /* Subprocess may be dead already. Only need the timeout if not. */
+ if (kill (p->pid, SIGTERM) != -1)
+ need_timeout = 1;
+ } else if (p->kill_how == kill_always) {
+ kill (p->pid, SIGKILL);
+ }
+ }
+
+ /* Sleep only if we have to... */
+
+ if (need_timeout) sleep (3);
+
+ /* OK, the scripts we just timed out for have had a chance to clean up
+ * --- now, just get rid of them, and also clean up the system accounting
+ * goop...
+ */
+
+ for (p = procs; p; p = p->next){
+
+ if (p->kill_how == kill_after_timeout)
+ kill (p->pid, SIGKILL);
+
+ if (p->kill_how != kill_never)
+ waitpid (p->pid, &status, 0);
+ }
+}
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_config.c: once was auxillary functions for reading httpd's config
+ * file and converting filenames into a namespace
+ *
+ * Rob McCool
+ *
+ * Wall-to-wall rewrite for Shambhala... commands which are part of the
+ * server core can now be found next door in "http_core.c". Now contains
+ * general command loop, and functions which do bookkeeping for the new
+ * Shambhala config stuff (modules and configuration vectors).
+ *
+ * rst
+ *
+ */
+
+#define CORE_PRIVATE
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h" /* for errors in parse_htaccess */
+#include "http_request.h" /* for default_handler (see invoke_handler) */
+#include "http_conf_globals.h" /* Sigh... */
+
+/****************************************************************
+ *
+ * We begin with the functions which deal with the linked list
+ * of modules which control just about all of server operation in
+ * Shambhala.
+ */
+
+static int num_modules = 0;
+module *top_module = NULL;
+
+typedef int (*handler)(request_rec *);
+typedef void *(*maker)(pool *);
+typedef void *(*dir_maker)(pool *, char *);
+typedef void *(*merger)(pool *, void *, void *);
+
+/* Dealing with config vectors. These are associated with per-directory,
+ * per-server, and per-request configuration, and have a void* pointer for
+ * each modules. The nature of the structure pointed to is private to the
+ * module in question... the core doesn't (and can't) know. However, there
+ * are defined interfaces which allow it to create instances of its private
+ * per-directory and per-server structures, and to merge the per-directory
+ * structures of a directory and its subdirectory (producing a new one in
+ * which the defaults applying to the base directory have been properly
+ * overridden).
+ */
+
+void *
+get_module_config (void *conf_vector, module *m)
+{
+ void **confv = (void**)conf_vector;
+ return confv[m->module_index];
+}
+
+void
+set_module_config (void *conf_vector, module *m, void *val)
+{
+ void **confv = (void**)conf_vector;
+ confv[m->module_index] = val;
+}
+
+void *
+create_empty_config (pool *p)
+{
+ void **conf_vector = (void **)pcalloc(p, sizeof(void*) * num_modules);
+ return (void *)conf_vector;
+}
+
+void *
+create_default_per_dir_config (pool *p)
+{
+ void **conf_vector = (void **)pcalloc(p, sizeof(void*) * (num_modules+DYNAMIC_MODULE_LIMIT));
+ module *modp;
+
+ for (modp = top_module; modp; modp = modp->next) {
+ dir_maker df = modp->create_dir_config;
+
+ if (df) conf_vector[modp->module_index] = (*df)(p, NULL);
+ }
+
+ return (void*)conf_vector;
+}
+
+void *
+merge_per_dir_configs (pool *p, void *base, void *new)
+{
+ void **conf_vector = (void **)pcalloc(p, sizeof(void*) * num_modules);
+ void **base_vector = (void **) base;
+ void **new_vector = (void **) new;
+ module *modp;
+
+ for (modp = top_module; modp; modp = modp->next) {
+ merger df = modp->merge_dir_config;
+ int i = modp->module_index;
+
+ if (df && new_vector[i])
+ conf_vector[i] = (*df)(p, base_vector[i], new_vector[i]);
+ else
+ conf_vector[i] = new_vector[i]? new_vector[i] : base_vector[i];
+ }
+
+ return (void*)conf_vector;
+}
+
+void *
+create_server_config (pool *p, server_rec *s)
+{
+ void **conf_vector = (void **)pcalloc(p, sizeof(void*) * (num_modules+DYNAMIC_MODULE_LIMIT));
+ module *modp;
+
+ for (modp = top_module; modp; modp = modp->next) {
+ if (modp->create_server_config)
+ conf_vector[modp->module_index]=(*modp->create_server_config)(p,s);
+ }
+
+ return (void*)conf_vector;
+}
+
+void merge_server_configs (pool *p, void *base, void *virt)
+{
+ /* Can reuse the 'virt' vector for the spine of it, since we don't
+ * have to deal with the moral equivalent of .htaccess files here...
+ */
+
+ void **base_vector = (void **)base;
+ void **virt_vector = (void **)virt;
+ module *modp;
+
+ for (modp = top_module; modp; modp = modp->next) {
+ merger df = modp->merge_server_config;
+ int i = modp->module_index;
+
+ if (!virt_vector[i])
+ virt_vector[i] = base_vector[i];
+ else if (df)
+ virt_vector[i] = (*df)(p, base_vector[i], virt_vector[i]);
+ }
+}
+
+void *create_connection_config (pool *p) {
+ return create_empty_config (p);
+}
+
+void *create_request_config (pool *p) {
+ return create_empty_config (p);
+}
+
+void *create_per_dir_config (pool *p) {
+ return create_empty_config (p);
+}
+
+/****************************************************************
+ *
+ * Dispatch through the modules to find handlers for various phases
+ * of request handling. These are invoked by http_request.c to actually
+ * do the dirty work of slogging through the module structures.
+ */
+
+int
+run_method (request_rec *r, int offset, int run_all)
+{
+ module *modp;
+ for (modp = top_module; modp; modp = modp->next) {
+ handler mod_handler = *(handler *)(offset + (char *)(modp));
+
+ if (mod_handler) {
+ int result = (*mod_handler)(r);
+
+ if (result != DECLINED && (!run_all || result != OK))
+ return result;
+ }
+ }
+
+ return run_all ? OK : DECLINED;
+}
+
+int translate_name(request_rec *r) {
+ return run_method (r, XtOffsetOf (module, translate_handler), 0);
+}
+
+int check_access(request_rec *r) {
+ return run_method (r, XtOffsetOf (module, access_checker), 1);
+}
+
+int find_types (request_rec *r) {
+ return run_method (r, XtOffsetOf (module, type_checker), 0);
+}
+
+int run_fixups (request_rec *r) {
+ return run_method (r, XtOffsetOf (module, fixer_upper), 1);
+}
+
+int log_transaction (request_rec *r) {
+ return run_method (r, XtOffsetOf (module, logger), 1);
+}
+
+/* Auth stuff --- anything that defines one of these will presumably
+ * want to define something for the other. Note that check_auth is
+ * separate from check_access to make catching some config errors easier.
+ */
+
+int check_user_id (request_rec *r) {
+ return run_method (r, XtOffsetOf (module, check_user_id), 0);
+}
+
+int check_auth (request_rec *r) {
+ return run_method (r, XtOffsetOf (module, auth_checker), 0);
+}
+
+/*
+ * This should really do multiple passes, choosing wildcards last,
+ * which would allow us to declare default_handler as a wildcard on
+ * core_module. Close enough for now...
+ */
+
+int invoke_handler (request_rec *r)
+{
+ module *modp;
+ handler_rec *handp;
+ char *content_type = r->content_type ? r->content_type : default_type (r);
+
+ /* Pass one --- direct matches */
+
+ for (modp = top_module; modp; modp = modp->next)
+ {
+ if (!modp->handlers) continue;
+
+ for (handp = modp->handlers; handp->content_type; ++handp) {
+ if (!strcasecmp (content_type, handp->content_type)) {
+ int result = (*handp->handler)(r);
+
+ if (result != DECLINED) return result;
+ }
+ }
+ }
+
+ /* Pass two --- wildcard matches */
+
+ for (modp = top_module; modp; modp = modp->next)
+ {
+ if (!modp->handlers) continue;
+
+ for (handp = modp->handlers; handp->content_type; ++handp) {
+ char *starp = strchr (handp->content_type, '*');
+ int len;
+
+ if (!starp) continue;
+
+ len = starp - handp->content_type;
+
+ if (!len || !strncasecmp (content_type, handp->content_type, len))
+ {
+ int result = (*handp->handler)(r);
+
+ if (result != DECLINED) return result;
+ }
+ }
+ }
+
+ return NOT_IMPLEMENTED;
+}
+
+/* One-time setup for precompiled modules --- NOT to be done on restart */
+
+void add_module (module *m)
+{
+ /* This could be called from an AddModule httpd.conf command,
+ * after the file has been linked and the module structure within it
+ * teased out...
+ */
+
+ m->next = top_module;
+ top_module = m;
+ m->module_index = num_modules++;
+}
+
+void setup_prelinked_modules ()
+{
+ extern module *prelinked_modules[];
+ module **m = prelinked_modules;
+
+ while (*m) {
+ add_module (*m);
+ ++m;
+ }
+}
+
+/*****************************************************************
+ *
+ * Resource, access, and .htaccess config files now parsed by a common
+ * command loop.
+ *
+ * Let's begin with the basics; parsing the line and
+ * invoking the function...
+ */
+
+char *invoke_cmd(command_rec *cmd, cmd_parms *parms, void *mconfig, char *args)
+{
+ char *w, *w2, *errmsg;
+
+ if ((parms->override & cmd->req_override) == 0)
+ return pstrcat (parms->pool, cmd->name, " not allowed here", NULL);
+
+ parms->info = cmd->cmd_data;
+
+ switch (cmd->args_how) {
+ case RAW_ARGS:
+ return (*cmd->func) (parms, mconfig, args);
+
+ case NO_ARGS:
+ if (*args != 0)
+ return pstrcat (parms->pool, cmd->name, " takes no arguments",
+ NULL);
+
+ return (*cmd->func) (parms, mconfig);
+
+ case TAKE1:
+ w = getword_conf (parms->pool, &args);
+
+ if (*w == '\0' || *args != 0)
+ return pstrcat (parms->pool, cmd->name, " takes one argument",
+ cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+ return (*cmd->func) (parms, mconfig, w);
+
+ case TAKE2:
+
+ w = getword_conf (parms->pool, &args);
+ w2 = getword_conf (parms->pool, &args);
+
+ if (*w == '\0' || *w2 == '\0' || *args != 0)
+ return pstrcat (parms->pool, cmd->name, " takes two arguments",
+ cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+ return (*cmd->func) (parms, mconfig, w, w2);
+
+ case ITERATE:
+
+ while (*(w = getword_conf (parms->pool, &args)) != '\0')
+ if ((errmsg = (*cmd->func) (parms, mconfig, w)))
+ return errmsg;
+
+ return NULL;
+
+ case ITERATE2:
+
+ w = getword_conf (parms->pool, &args);
+
+ if (*w == '\0' || *args == 0)
+ return pstrcat(parms->pool, cmd->name,
+ " requires at least two arguments",
+ cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
+
+
+ while (*(w2 = getword_conf (parms->pool, &args)) != '\0')
+ if ((errmsg = (*cmd->func) (parms, mconfig, w, w2)))
+ return errmsg;
+
+ return NULL;
+
+ case FLAG:
+
+ w = getword_conf (parms->pool, &args);
+
+ if (*w == '\0' || ((!strcasecmp(w, "on")) && (!strcasecmp (w, "off"))))
+ return pstrcat (parms->pool, cmd->name, " must be On or Off",
+ NULL);
+
+ return (*cmd->func) (parms, mconfig, strcasecmp (w, "off"));
+
+ default:
+
+ return pstrcat (parms->pool, cmd->name,
+ " is improperly configured internally (server bug)",
+ NULL);
+ }
+}
+
+command_rec *find_command (char *name, command_rec *cmds)
+{
+ while (cmds->name)
+ if (!strcasecmp (name, cmds->name))
+ return cmds;
+ else
+ ++cmds;
+
+ return NULL;
+}
+
+command_rec *find_command_in_modules (char *cmd_name, module **mod)
+{
+ command_rec *cmdp;
+ module *modp;
+
+ for (modp = top_module; modp; modp = modp->next)
+ if (modp->cmds && (cmdp = find_command (cmd_name, modp->cmds))) {
+ *mod = modp;
+ return cmdp;
+ }
+
+ return NULL;
+}
+
+char *handle_command (cmd_parms *parms, void *config, char *l)
+{
+ char *args, *cmd_name;
+ command_rec *cmd;
+ module *mod;
+
+ ++parms->config_line;
+ if((l[0] == '#') || (!l[0])) return NULL;
+
+ args = l;
+ cmd_name = getword_conf (parms->temp_pool, &args);
+ if (*cmd_name == '\0') return NULL;
+
+ if (!(cmd = find_command_in_modules (cmd_name, &mod))) {
+ return pstrcat (parms->pool, "Invalid command ", cmd_name, NULL);
+ }
+ else {
+ void *mconfig = get_module_config (config, mod);
+ void *sconfig = get_module_config (parms->server->module_config, mod);
+
+ if (!mconfig && mod->create_dir_config) {
+ mconfig = (*mod->create_dir_config) (parms->pool, parms->path);
+ set_module_config (config, mod, mconfig);
+ }
+
+ if (!sconfig && mod->create_server_config) {
+ sconfig = (*mod->create_server_config)(parms->pool, parms->server);
+ set_module_config (parms->server->module_config, mod, sconfig);
+ }
+
+ return invoke_cmd (cmd, parms, mconfig, args);
+ }
+}
+
+char *srm_command_loop (cmd_parms *parms, void *config)
+{
+ char l[MAX_STRING_LEN];
+
+ while (!(cfg_getline (l, MAX_STRING_LEN, parms->infile))) {
+ char *errmsg = handle_command (parms, config, l);
+ if (errmsg) return errmsg;
+ }
+
+ return NULL;
+}
+
+/*
+ * Generic command functions...
+ */
+
+char *set_string_slot (cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ /* This one's pretty generic... */
+
+ int offset = (int)cmd->info;
+ *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg);
+ return NULL;
+}
+
+/*****************************************************************
+ *
+ * Reading whole config files...
+ */
+
+cmd_parms default_parms = { NULL, 0, -1, NULL, 0, NULL, NULL, NULL, NULL };
+
+char *server_root_relative (pool *p, char *file)
+{
+ if (file[0] == '/') return file;
+ return make_full_path (p, server_root, file);
+}
+
+void process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp)
+{
+ FILE *cfg;
+ char *errmsg;
+ cmd_parms parms;
+
+ fname = server_root_relative (p, fname);
+
+ /* GCC's initialization extensions are soooo nice here... */
+
+ parms = default_parms;
+ parms.config_file = fname;
+ parms.pool = p;
+ parms.temp_pool = ptemp;
+ parms.server = s;
+ parms.override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT);
+
+ if(!(cfg = fopen(fname, "r"))) {
+ fprintf(stderr,"httpd: could not open document config file %s\n",
+ fname);
+ perror("fopen");
+ exit(1);
+ }
+
+ parms.infile = cfg;
+
+ errmsg = srm_command_loop (&parms, s->lookup_defaults);
+
+ if (errmsg) {
+ fprintf (stderr, "Syntax error on line %d of %s:\n",
+ parms.config_line, fname);
+ fprintf (stderr, "%s\n", errmsg);
+ exit(1);
+ }
+
+ fclose(cfg);
+}
+
+
+int parse_htaccess(void **result, request_rec *r, int override,
+ char *d, char *filename)
+{
+ FILE *f;
+ cmd_parms parms;
+ char *errmsg;
+
+ parms = default_parms;
+ parms.override = override;
+ parms.pool = r->pool;
+ parms.temp_pool = r->pool;
+ parms.server = r->server;
+ parms.path = d;
+
+ if((f=pfopen(r->pool, filename, "r"))) {
+ void *dc = create_per_dir_config (r->pool);
+
+ parms.infile = f;
+ parms.config_file = filename;
+
+ errmsg = srm_command_loop (&parms, dc);
+
+ pfclose(r->pool, f);
+
+ if (errmsg) {
+ log_reason (errmsg, filename, r);
+ return SERVER_ERROR;
+ }
+
+ *result = dc;
+ return OK;
+ }
+ else
+ return OK;
+}
+
+/*****************************************************************
+ *
+ * Virtual host stuff; note that the commands that invoke this stuff
+ * are with the command table in http_core.c.
+ */
+
+server_rec *init_virtual_host (pool *p, char *hostname)
+{
+ server_rec *s = (server_rec *)pcalloc (p, sizeof (server_rec));
+
+#ifdef RLIMIT_NOFILE
+ struct rlimit limits;
+
+ getrlimit ( RLIMIT_NOFILE, &limits );
+ if ( limits.rlim_cur < limits.rlim_max ) {
+ limits.rlim_cur += 2;
+ if ( setrlimit ( RLIMIT_NOFILE, &limits ) < 0 )
+ fprintf (stderr, "Cannot exceed hard limit for open files");
+ }
+#endif
+
+ s->port = 0;
+ s->server_admin = NULL;
+ s->server_hostname = NULL;
+ s->error_fname = NULL;
+ s->srm_confname = NULL;
+ s->access_confname = NULL;
+ s->timeout = 0;
+ s->do_rfc931 = 0;
+ s->host_addr.s_addr = get_virthost_addr (hostname, 0);
+ s->next = NULL;
+
+ s->module_config = create_empty_config (p);
+ s->lookup_defaults = create_per_dir_config (p);
+
+ return s;
+}
+
+int is_virtual_server (server_rec *s)
+{
+ return s->host_addr.s_addr != htonl (INADDR_ANY);
+}
+
+void fixup_virtual_hosts (pool *p, server_rec *main_server)
+{
+ server_rec *virt;
+
+ for (virt = main_server->next; virt; virt = virt->next) {
+ merge_server_configs (p, main_server->module_config,
+ virt->module_config);
+
+ virt->lookup_defaults =
+ merge_per_dir_configs (p, main_server->lookup_defaults,
+ virt->lookup_defaults);
+
+ if (virt->port == 0)
+ virt->port = main_server->port;
+
+ if (virt->server_admin == NULL)
+ virt->server_admin = main_server->server_admin;
+
+ if (virt->srm_confname == NULL)
+ virt->srm_confname = main_server->srm_confname;
+
+ if (virt->access_confname == NULL)
+ virt->access_confname = main_server->access_confname;
+
+ if (virt->timeout == 0)
+ virt->timeout = main_server->timeout;
+
+ if (virt->do_rfc931 == 0)
+ virt->do_rfc931 = main_server->do_rfc931;
+ }
+}
+
+/*****************************************************************
+ *
+ * Getting *everything* configured...
+ */
+
+void init_config_globals (pool *p)
+{
+ /* ServerRoot, server_confname set in httpd.c */
+
+ standalone = 1;
+ user_name = DEFAULT_USER;
+ user_id = uname2id(DEFAULT_USER);
+ group_id = gname2id(DEFAULT_GROUP);
+ daemons_to_start = DEFAULT_START_DAEMON;
+ daemons_min_free = DEFAULT_MIN_FREE_DAEMON;
+ daemons_max_free = DEFAULT_MAX_FREE_DAEMON;
+ daemons_limit = DEFAULT_SERVER_LIMIT;
+ pid_fname = DEFAULT_PIDLOG;
+ max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
+ bind_address.s_addr = htonl(INADDR_ANY);
+}
+
+server_rec *init_server_config(pool *p)
+{
+ server_rec *s = (server_rec *)pcalloc (p, sizeof (server_rec));
+
+ s->port = DEFAULT_PORT;
+ s->server_admin = DEFAULT_ADMIN;
+ s->server_hostname = NULL;
+ s->error_fname = DEFAULT_ERRORLOG;
+ s->srm_confname = RESOURCE_CONFIG_FILE;
+ s->access_confname = ACCESS_CONFIG_FILE;
+ s->timeout = DEFAULT_TIMEOUT;
+ s->do_rfc931 = DEFAULT_RFC931;
+ s->next = NULL;
+ s->host_addr.s_addr = htonl (INADDR_ANY); /* NOT virtual host;
+ * don't match any real network
+ * interface.
+ */
+
+ s->module_config = create_server_config (p, s);
+ s->lookup_defaults = create_default_per_dir_config (p);
+
+ return s;
+}
+
+server_rec *read_config(pool *p, pool *ptemp, char *confname)
+{
+ server_rec *s = init_server_config(p);
+ module *m;
+
+ init_config_globals(p);
+
+ /* All server-wide config files now have the SAME syntax... */
+
+ process_resource_config (s, confname, p, ptemp);
+ process_resource_config (s, s->srm_confname, p, ptemp);
+ process_resource_config (s, s->access_confname, p, ptemp);
+
+ fixup_virtual_hosts (p, s);
+
+ for (m = top_module; m; m = m->next)
+ if (m->init)
+ (*m->init) (s, p);
+
+ return s;
+}
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+#define CORE_PRIVATE
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h" /* For index_of_response(). Grump. */
+#include "http_conf_globals.h"
+
+#include "http_main.h" /* For the default_handler below... */
+#include "http_log.h"
+
+/* Server core module... This module provides support for really basic
+ * server operations, including options and commands which control the
+ * operation of other modules. Consider this the bureaucracy module.
+ *
+ * The core module also defines handlers, etc., do handle just enough
+ * to allow a server with the core module ONLY to actually serve documents
+ * (though it slaps DefaultType on all of 'em); this was useful in testing,
+ * but may not be worth preserving.
+ *
+ * This file could almost be mod_core.c, except for the stuff which affects
+ * the http_conf_globals.
+ */
+
+void *create_core_dir_config (pool *a, char *dir)
+{
+ core_dir_config *conf =
+ (core_dir_config *)pcalloc(a, sizeof(core_dir_config));
+
+ if (!dir || dir[strlen(dir) - 1] == '/') conf->d = dir;
+ else conf->d = pstrcat (a, dir, "/", NULL);
+
+ conf->opts = dir ? OPT_UNSET : OPT_ALL;
+ conf->override = dir ? OR_UNSET : OR_ALL;
+
+ return (void *)conf;
+}
+
+void *merge_core_dir_configs (pool *a, void *basev, void *newv)
+{
+ core_dir_config *base = (core_dir_config *)basev;
+ core_dir_config *new = (core_dir_config *)newv;
+ core_dir_config *conf =
+ (core_dir_config *)pcalloc (a, sizeof(core_dir_config));
+ int i;
+
+ memcpy ((char *)conf, (const char *)base, sizeof(core_dir_config));
+
+ conf->d = new->d;
+
+ if (new->opts != OPT_UNSET) conf->opts = new->opts;
+ if (new->override != OR_UNSET) conf->override = new->override;
+ if (new->default_type) conf->default_type = new->default_type;
+
+ if (new->auth_type) conf->auth_type = new->auth_type;
+ if (new->auth_name) conf->auth_name = new->auth_name;
+ if (new->requires) conf->requires = new->requires;
+
+ for (i = 0; i <= RESPONSE_CODES; ++i)
+ if (new->response_code_strings[i] != NULL)
+ conf->response_code_strings[i] = new->response_code_strings[i];
+
+ return (void*)conf;
+}
+
+void *create_core_server_config (pool *a, server_rec *s)
+{
+ core_server_config *conf =
+ (core_server_config *)pcalloc(a, sizeof(core_server_config));
+ int is_virtual = is_virtual_server (s);
+
+ conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME;
+ conf->document_root = is_virtual ? NULL : DOCUMENT_LOCATION;
+ conf->sec = make_array (a, 40, sizeof(void *));
+
+ return (void *)conf;
+}
+
+void *merge_core_server_configs (pool *p, void *basev, void *virtv)
+{
+ core_server_config *base = (core_server_config *)basev;
+ core_server_config *virt = (core_server_config *)virtv;
+ core_server_config *conf =
+ (core_server_config *)pcalloc(p, sizeof(core_server_config));
+
+ *conf = *virt;
+ if (!conf->access_name) conf->access_name = base->access_name;
+ if (!conf->document_root) conf->document_root = base->document_root;
+ conf->sec = append_arrays (p, virt->sec, base->sec);
+
+ return conf;
+}
+
+/* Add per-directory configuration entry (for <directory> section);
+ * these are part of the core server config.
+ */
+
+void add_per_dir_conf (server_rec *s, void *dir_config)
+{
+ core_server_config *sconf = get_module_config (s->module_config,
+ &core_module);
+ void **new_space = (void **) push_array (sconf->sec);
+
+ *new_space = dir_config;
+}
+
+/*****************************************************************
+ *
+ * There are some elements of the core config structures in which
+ * other modules have a legitimate interest (this is ugly, but necessary
+ * to preserve NCSA back-compatibility). So, we have a bunch of accessors
+ * here...
+ */
+
+int allow_options (request_rec *r)
+{
+ core_dir_config *conf =
+ (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+
+ return conf->opts;
+}
+
+int allow_overrides (request_rec *r)
+{
+ core_dir_config *conf =
+ (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+
+ return conf->override;
+}
+
+char *auth_type (request_rec *r)
+{
+ core_dir_config *conf =
+ (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+
+ return conf->auth_type;
+}
+
+char *auth_name (request_rec *r)
+{
+ core_dir_config *conf =
+ (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+
+ return conf->auth_name;
+}
+
+char *default_type (request_rec *r)
+{
+ core_dir_config *conf =
+ (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+
+ return conf->default_type ? conf->default_type : DEFAULT_TYPE;
+}
+
+char *document_root (request_rec *r) /* Don't use this!!! */
+{
+ core_server_config *conf =
+ (core_server_config *)get_module_config(r->server->module_config,
+ &core_module);
+
+ return conf->document_root;
+}
+
+array_header *requires (request_rec *r)
+{
+ core_dir_config *conf =
+ (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+
+ return conf->requires;
+}
+
+
+/* Should probably just get rid of this... the only code that cares is
+ * part of the core anyway (and in fact, it isn't publicised to other
+ * modules).
+ */
+
+char *response_code_string (request_rec *r, int error_index)
+{
+ core_dir_config *conf =
+ (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+
+ return conf->response_code_strings[error_index];
+}
+
+/*****************************************************************
+ *
+ * Commands... this module handles almost all of the NCSA httpd.conf
+ * commands, but most of the old srm.conf is in the the modules.
+ */
+
+char *set_access_name (cmd_parms *cmd, void *dummy, char *arg)
+{
+ void *sconf = cmd->server->module_config;
+ core_server_config *conf = get_module_config (sconf, &core_module);
+
+ conf->access_name = arg;
+ return NULL;
+}
+
+char *set_document_root (cmd_parms *cmd, void *dummy, char *arg)
+{
+ void *sconf = cmd->server->module_config;
+ core_server_config *conf = get_module_config (sconf, &core_module);
+
+ if (!is_directory (arg)) return "DocumentRoot must be a directory";
+
+ conf->document_root = arg;
+ return NULL;
+}
+
+char *set_error_document (cmd_parms *cmd, core_dir_config *conf, char *line)
+{
+ int error_number, index_number;
+ char *w;
+
+ /* 1st parameter should be a 3 digit number, which we recognize;
+ * convert it into an array index
+ */
+
+ w = getword_conf (cmd->pool, &line);
+ error_number = atoi(w);
+ index_number = index_of_response(error_number);
+
+ if (index_number < 0)
+ return pstrcat (cmd->pool, "Illegal HTTP response code ", w, NULL);
+
+ /* Nuke trailing '"', if present */
+
+ if (line[strlen(line) - 1] == '"') line[strlen(line) - 1] = '\0';
+
+ /* Store it... */
+
+ conf->response_code_strings[index_number] = pstrdup (cmd->pool, line);
+
+ return NULL;
+}
+
+/* access.conf commands...
+ *
+ * The *only* thing that can appear in access.conf at top level is a
+ * <Directory> section. NB we need to have a way to cut the srm_command_loop
+ * invoked by dirsection (i.e., <Directory>) short when </Directory> is seen.
+ * We do that by returning an error, which dirsection itself recognizes and
+ * discards as harmless. Cheesy, but it works.
+ */
+
+char *set_override (cmd_parms *cmd, core_dir_config *d, char *l)
+{
+ char *w;
+
+ d->override = OR_NONE;
+ while(l[0]) {
+ w = getword_conf (cmd->pool, &l);
+ if(!strcasecmp(w,"Limit"))
+ d->override |= OR_LIMIT;
+ else if(!strcasecmp(w,"Options"))
+ d->override |= OR_OPTIONS;
+ else if(!strcasecmp(w,"FileInfo"))
+ d->override |= OR_FILEINFO;
+ else if(!strcasecmp(w,"AuthConfig"))
+ d->override |= OR_AUTHCFG;
+ else if(!strcasecmp(w,"Indexes"))
+ d->override |= OR_INDEXES;
+ else if(!strcasecmp(w,"None"))
+ d->override = OR_NONE;
+ else if(!strcasecmp(w,"All"))
+ d->override = OR_ALL;
+ else
+ return pstrcat (cmd->pool, "Illegal override option ", w, NULL);
+ }
+
+ return NULL;
+}
+
+char *set_options (cmd_parms *cmd, core_dir_config *d, char *l)
+{
+ d->opts = OPT_NONE;
+ while(l[0]) {
+ char *w = getword_conf(cmd->pool, &l);
+ if(!strcasecmp(w,"Indexes"))
+ d->opts |= OPT_INDEXES;
+ else if(!strcasecmp(w,"Includes"))
+ d->opts |= OPT_INCLUDES;
+ else if(!strcasecmp(w,"IncludesNOEXEC"))
+ d->opts |= (OPT_INCLUDES | OPT_INCNOEXEC);
+ else if(!strcasecmp(w,"FollowSymLinks"))
+ d->opts |= OPT_SYM_LINKS;
+ else if(!strcasecmp(w,"SymLinksIfOwnerMatch"))
+ d->opts |= OPT_SYM_OWNER;
+ else if(!strcasecmp(w,"execCGI"))
+ d->opts |= OPT_EXECCGI;
+ else if (!strcasecmp(w,"MultiViews"))
+ d->opts |= OPT_MULTI;
+ else if (!strcasecmp(w,"RunScripts")) /* AI backcompat. Yuck */
+ d->opts |= OPT_MULTI|OPT_EXECCGI;
+ else if(!strcasecmp(w,"None"))
+ d->opts = OPT_NONE;
+ else if(!strcasecmp(w,"All"))
+ d->opts = OPT_ALL;
+ else
+ return pstrcat (cmd->pool, "Illegal option ", w, NULL);
+ }
+
+ return NULL;
+}
+
+char *require (cmd_parms *cmd, core_dir_config *c, char *arg)
+{
+ require_line *r;
+
+ if (!c->requires)
+ c->requires = make_array (cmd->pool, 2, sizeof(require_line));
+
+ r = (require_line *)push_array (c->requires);
+ r->requirement = pstrdup (cmd->pool, arg);
+ r->method_mask = cmd->limited;
+ return NULL;
+}
+
+char *limit (cmd_parms *cmd, void *dummy, char *arg)
+{
+ char *limited_methods = getword(cmd->pool,&arg,'>');
+ int limited = 0;
+
+ if (cmd->limited > 0) return "Can't nest <Limit> sections";
+
+ while(limited_methods[0]) {
+ char *method = getword_conf (cmd->pool, &limited_methods);
+ if(!strcasecmp(method,"GET")) limited |= (1 << M_GET);
+ else if(!strcasecmp(method,"PUT")) limited |= (1 << M_PUT);
+ else if(!strcasecmp(method,"POST")) limited |= (1 << M_POST);
+ else if(!strcasecmp(method,"DELETE")) limited |= (1 << M_DELETE);
+ else return "unknown method in <Limit>";
+ }
+
+ cmd->limited = limited;
+ return NULL;
+}
+
+char *endlimit (cmd_parms *cmd, void *dummy, void *dummy2)
+{
+ if (cmd->limited == -1) return "</Limit> unexpected";
+
+ cmd->limited = -1;
+ return NULL;
+}
+
+static char *end_dir_magic = "</Directory> outside of any <Directory> section";
+
+char *end_dirsection (cmd_parms *cmd, void *dummy) {
+ return end_dir_magic;
+}
+
+char *dirsection (cmd_parms *cmd, void *dummy, char *arg)
+{
+ char *errmsg, *endp = strrchr (arg, '>');
+ int old_overrides = cmd->override;
+ char *old_path = cmd->path;
+ void *new_dir_conf = create_per_dir_config (cmd->pool);
+
+ if (endp) *endp = '\0';
+
+ if (cmd->path) return "<Directory> sections don't nest";
+ if (cmd->limited != -1) return "Can't have <Directory> within <Limit>";
+
+ cmd->path = getword_conf (cmd->pool, &arg);
+ cmd->override = OR_ALL|ACCESS_CONF;
+
+ errmsg = srm_command_loop (cmd, new_dir_conf);
+ add_per_dir_conf (cmd->server, new_dir_conf);
+
+ cmd->path = old_path;
+ cmd->override = old_overrides;
+
+ if (errmsg == end_dir_magic) return NULL;
+ return errmsg;
+}
+
+/* httpd.conf commands... beginning with the <VirtualHost> business */
+
+char *end_virthost_magic = "</Virtualhost> out of place";
+
+char *end_virtualhost_section (cmd_parms *cmd, void *dummy) {
+ return end_virthost_magic;
+}
+
+char *virtualhost_section (cmd_parms *cmd, void *dummy, char *arg)
+{
+ server_rec *main_server = cmd->server, *s;
+ char *errmsg, *endp = strrchr (arg, '>');
+ pool *p = cmd->pool, *ptemp = cmd->temp_pool;
+
+ if (endp) *endp = '\0';
+
+ if (is_virtual_server (main_server))
+ return "<VirtualHost> doesn't nest!";
+
+ s = init_virtual_host (p, arg);
+ s->next = main_server->next;
+ main_server->next = s;
+
+ cmd->server = s;
+ errmsg = srm_command_loop (cmd, s->lookup_defaults);
+ cmd->server = main_server;
+
+ if (s->srm_confname)
+ process_resource_config (s, s->srm_confname, p, ptemp);
+
+ if (s->access_confname)
+ process_resource_config (s, s->access_confname, p, ptemp);
+
+ if (errmsg == end_virthost_magic) return NULL;
+ return errmsg;
+}
+
+char *set_server_string_slot (cmd_parms *cmd, void *dummy, char *arg)
+{
+ /* This one's pretty generic... */
+
+ int offset = (int)cmd->info;
+ char *struct_ptr = (char *)cmd->server;
+
+ *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg);
+ return NULL;
+}
+
+char *server_type (cmd_parms *cmd, void *dummy, char *arg)
+{
+ if (!strcasecmp (arg, "inetd")) standalone = 0;
+ else if (!strcasecmp (arg, "standalone")) standalone = 1;
+ else return "ServerType must be either 'inetd' or 'standalone'";
+
+ return NULL;
+}
+
+char *server_port (cmd_parms *cmd, void *dummy, char *arg) {
+ cmd->server->port = atoi (arg);
+ return NULL;
+}
+
+char *set_user (cmd_parms *cmd, void *dummy, char *arg) {
+ user_name = pstrdup (cmd->pool, arg);
+ user_id = uname2id (user_name);
+ return NULL;
+}
+
+char *set_group (cmd_parms *cmd, void *dummy, char *arg) {
+ group_id = gname2id(arg);
+ return NULL;
+}
+
+char *set_server_root (cmd_parms *cmd, void *dummy, char *arg) {
+ if (!is_directory (arg)) return "ServerRoot must be a valid directory";
+ strcpy (server_root, arg);
+ return NULL;
+}
+
+char *set_timeout (cmd_parms *cmd, void *dummy, char *arg) {
+ cmd->server->timeout = atoi (arg);
+ return NULL;
+}
+
+char *set_pidfile (cmd_parms *cmd, void *dummy, char *arg) {
+ pid_fname = pstrdup (cmd->pool, arg);
+ return NULL;
+}
+
+char *set_idcheck (cmd_parms *cmd, void *dummy, int arg) {
+ cmd->server->do_rfc931 = arg;
+ return NULL;
+}
+
+char *set_daemons_to_start (cmd_parms *cmd, void *dummy, char *arg) {
+ daemons_to_start = atoi (arg);
+ return NULL;
+}
+
+char *set_min_free_servers (cmd_parms *cmd, void *dummy, char *arg) {
+ daemons_min_free = atoi (arg);
+ return NULL;
+}
+
+char *set_max_free_servers (cmd_parms *cmd, void *dummy, char *arg) {
+ daemons_max_free = atoi (arg);
+ return NULL;
+}
+
+char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) {
+ daemons_limit = atoi (arg);
+ return NULL;
+}
+
+char *set_max_requests (cmd_parms *cmd, void *dummy, char *arg) {
+ max_requests_per_child = atoi (arg);
+ return NULL;
+}
+
+char *set_bind_address (cmd_parms *cmd, void *dummy, char *arg) {
+ bind_address.s_addr = get_virthost_addr (arg, 1);
+ return NULL;
+}
+
+/* Note --- change the mask below, and ErrorDocument will work from
+ * .htaccess files. The question is, what AllowOverride should webmasters
+ * have to turn it off?
+ */
+
+command_rec core_cmds[] = {
+
+/* Old access config file commands */
+
+{ "<Directory", dirsection, NULL, RSRC_CONF, RAW_ARGS, NULL },
+{ "</Directory>", end_dirsection, NULL, ACCESS_CONF, NO_ARGS, NULL },
+{ "<Limit", limit, NULL, OR_ALL, RAW_ARGS, NULL },
+{ "</Limit>", endlimit, NULL, OR_ALL, RAW_ARGS, NULL },
+{ "AuthType", set_string_slot, (void*)XtOffsetOf(core_dir_config, auth_type),
+ OR_AUTHCFG, TAKE1, "an HTTP authorization type (e.g., \"Basic\")" },
+{ "AuthName", set_string_slot, (void*)XtOffsetOf(core_dir_config, auth_name),
+ OR_AUTHCFG, RAW_ARGS, NULL },
+{ "Require", require, NULL, OR_AUTHCFG, RAW_ARGS, NULL },
+
+/* Old resource config file commands */
+
+{ "AccessFileName", set_access_name, NULL, RSRC_CONF, TAKE1, NULL },
+{ "DocumentRoot", set_document_root, NULL, RSRC_CONF, TAKE1, NULL },
+{ "ErrorDocument", set_error_document, NULL, RSRC_CONF, RAW_ARGS, NULL },
+{ "AllowOverride", set_override, NULL, ACCESS_CONF, RAW_ARGS, NULL },
+{ "Options", set_options, NULL, OR_OPTIONS, RAW_ARGS, NULL },
+{ "DefaultType", set_string_slot,
+ (void*)XtOffsetOf (core_dir_config, default_type),
+ OR_FILEINFO, TAKE1, "the default MIME type for untypable files" },
+
+/* Old server config file commands */
+
+{ "ServerType", server_type, NULL, RSRC_CONF, TAKE1,"'inetd' or 'standalone'"},
+{ "Port", server_port, NULL, RSRC_CONF, TAKE1, "a TCP port number"},
+{ "User", set_user, NULL, RSRC_CONF, TAKE1, "a username"},
+{ "Group", set_group, NULL, RSRC_CONF, TAKE1, "a group name"},
+{ "ServerAdmin", set_server_string_slot,
+ (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1,
+ "The email address of the server administrator" },
+{ "ServerName", set_server_string_slot,
+ (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF, TAKE1,
+ "The hostname of the server" },
+{ "ServerRoot", set_server_root, NULL, RSRC_CONF, TAKE1, "a directory"},
+{ "ErrorLog", set_server_string_slot,
+ (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1,
+ "the filename of the error log" },
+{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
+ "a file for logging the server process ID"},
+{ "AccessConfig", set_server_string_slot,
+ (void *)XtOffsetOf (server_rec, access_confname), RSRC_CONF, TAKE1,
+ "the filename of the access config file" },
+{ "ResourceConfig", set_server_string_slot,
+ (void *)XtOffsetOf (server_rec, srm_confname), RSRC_CONF, TAKE1,
+ "the filename of the resource config file" },
+{ "Timeout", set_timeout, NULL, RSRC_CONF, TAKE1, "timeout duration (sec)"},
+{ "IdentityCheck", set_idcheck, NULL, RSRC_CONF, FLAG, NULL },
+{ "CacheNegotiatedDocs", },
+{ "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MaxServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, NULL },
+{ "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1, NULL },
+{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1, NULL },
+{ "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1,
+ "'*', a numeric IP address, or the name of a host with a unique IP address"},
+{ "<VirtualHost", virtualhost_section, NULL, RSRC_CONF, RAW_ARGS, NULL },
+{ "</VirtualHost>", end_virtualhost_section, NULL, RSRC_CONF, NO_ARGS, NULL },
+{ NULL },
+};
+
+/*****************************************************************
+ *
+ * Core handlers for various phases of server operation...
+ */
+
+int core_translate (request_rec *r)
+{
+ void *sconf = r->server->module_config;
+ core_server_config *conf = get_module_config (sconf, &core_module);
+
+ if (r->uri[0] != '/') return BAD_REQUEST;
+
+ r->filename = pstrcat (r->pool, conf->document_root, r->uri, NULL);
+ return OK;
+}
+
+int do_nothing (request_rec *r) { return OK; }
+
+/*
+ * Default handler for MIME types without other handlers. Only GET
+ * at this point... anyone who wants to write a generic handler for
+ * PUT or POST is free to do so, but it seems unwise to provide any
+ * defaults yet...
+ */
+
+int default_handler (request_rec *r)
+{
+ int errstatus;
+ FILE *f;
+
+ if (r->method_number != M_GET) return DECLINED;
+ if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) {
+ log_reason("File does not exist", r->filename, r);
+ return NOT_FOUND;
+ }
+
+ if ((errstatus = set_content_length (r, r->finfo.st_size))
+ || (errstatus = set_last_modified (r, r->finfo.st_mtime)))
+ return errstatus;
+
+ f = fopen (r->filename, "r");
+
+ if (f == NULL) {
+ log_reason("file permissions deny server access", r->filename, r);
+ return FORBIDDEN;
+ }
+
+ soft_timeout ("send", r);
+
+ send_http_header (r);
+ if (!r->header_only) send_fd (f, r);
+ fclose (f);
+ return OK;
+}
+
+handler_rec core_handlers[] = {
+{ "*/*", default_handler },
+{ NULL }
+};
+
+module core_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ create_core_dir_config, /* create per-directory config structure */
+ merge_core_dir_configs, /* merge per-directory config structures */
+ create_core_server_config, /* create per-server config structure */
+ merge_core_server_configs, /* merge per-server config structures */
+ core_cmds, /* command table */
+ core_handlers, /* handlers */
+ core_translate, /* translate_handler */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ do_nothing, /* check access */
+ do_nothing, /* type_checker */
+ NULL, /* pre-run fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_log.c: Dealing with the logs and errors
+ *
+ * Rob McCool
+ *
+ */
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+
+void open_error_log(server_rec *s, pool *p)
+{
+ char *fname;
+
+ fname = server_root_relative (p, s->error_fname);
+ if(!(s->error_log = pfopen(p, fname, "a"))) {
+ fprintf(stderr,"httpd: could not open error log file %s.\n", fname);
+ perror("fopen");
+ exit(1);
+ }
+}
+
+void open_logs (server_rec *s_main, pool *p)
+{
+ server_rec *virt, *q;
+
+ open_error_log (s_main, p);
+
+ for (virt = s_main->next; virt; virt = virt->next) {
+ if (virt->error_fname)
+ {
+ for (q=s_main; q != virt; q = q->next)
+ if (q->error_fname != NULL &&
+ strcmp(q->error_fname, virt->error_fname) == 0)
+ break;
+ if (q == virt) open_error_log (virt, p);
+ else virt->error_log = q->error_log;
+ }
+ else
+ virt->error_log = s_main->error_log;
+ }
+}
+
+void error_log2stderr(server_rec *s) {
+ if(fileno(s->error_log) != STDERR_FILENO)
+ dup2(fileno(s->error_log),STDERR_FILENO);
+}
+
+void log_pid(pool *p, char *pid_fname) {
+ FILE *pid_file;
+
+ if (!pid_fname) return;
+ pid_fname = server_root_relative (p, pid_fname);
+ if(!(pid_file = fopen(pid_fname,"w"))) {
+ perror("fopen");
+ fprintf(stderr,"httpd: could not log pid to file %s\n", pid_fname);
+ exit(1);
+ }
+ fprintf(pid_file,"%ld\n",(long)getpid());
+ fclose(pid_file);
+}
+
+void log_error(char *err, server_rec *s) {
+ fprintf(s->error_log, "[%s] %s\n",get_time(),err);
+ fflush(s->error_log);
+}
+
+void log_reason(char *reason, char *file, request_rec *r) {
+ fprintf (r->server->error_log,
+ "[%s] access to %s failed for %s, reason: %s\n",
+ get_time(), file, r->connection->remote_name, reason);
+ fflush (r->server->error_log);
+}
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * httpd.c: simple http daemon for answering WWW file requests
+ *
+ *
+ * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3)
+ *
+ * 03-06-95 blong
+ * changed server number for child-alone processes to 0 and changed name
+ * of processes
+ *
+ * 03-10-95 blong
+ * Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu)
+ * including set group before fork, and call gettime before to fork
+ * to set up libraries.
+ *
+ * 04-14-95 rst / rh
+ * Brandon's code snarfed from NCSA 1.4, but tinkered to work with the
+ * Apache server, and also to have child processes do accept() directly.
+ *
+ * April-July '95 rst
+ * Extensive rework for Shambhala.
+ */
+
+
+#define CORE_PRIVATE
+
+#include "httpd.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_config.h" /* for read_config */
+#include "http_protocol.h" /* for read_request */
+#include "http_request.h" /* for process_request */
+#include "http_conf_globals.h"
+#include "scoreboard.h"
+#include <setjmp.h>
+
+/*
+ * Actual definitions of config globals... here because this is
+ * for the most part the only code that acts on 'em. (Hmmm... mod_main.c?)
+ */
+
+int standalone;
+uid_t user_id;
+char *user_name;
+gid_t group_id;
+int max_requests_per_child;
+char *pid_fname;
+char *server_argv0;
+struct in_addr bind_address;
+int daemons_to_start;
+int daemons_min_free;
+int daemons_max_free;
+int daemons_limit;
+
+char server_root[MAX_STRING_LEN];
+char server_confname[MAX_STRING_LEN];
+
+/* *Non*-shared http_main globals... */
+
+server_rec *server_conf;
+JMP_BUF jmpbuffer;
+JMP_BUF restart_buffer;
+int sd;
+pid_t pgrp;
+
+/* one_process --- debugging mode variable; can be set from the command line
+ * with the -X flag. If set, this gets you the child_main loop running
+ * in the process which originally started up (no detach, no make_child),
+ * which is a pretty nice debugging environment. (You'll get a SIGHUP
+ * early in standalone_main; just continue through. This is the server
+ * trying to kill off any child processes which it might have lying
+ * around --- Shambhala doesn't keep track of their pids, it just sends
+ * SIGHUP to the process group, ignoring it in the root process.
+ * Continue through and you'll be fine.).
+ */
+
+int one_process = 0;
+
+#ifdef FCNTL_SERIALIZED_ACCEPT
+static struct flock lock_it = { F_WRLCK, 0, 0, 0 };
+static struct flock unlock_it = { F_UNLCK, 0, 0, 0 };
+
+static int lock_fd=-1;
+
+/*
+ * Initialise mutex lock.
+ * Must be safe to call this on a restart.
+ */
+void
+accept_mutex_init(pool *p)
+{
+ char lock_fname[30];
+
+ strcpy(lock_fname, "/usr/tmp/htlock.XXXXXX");
+
+ if (mktemp(lock_fname) == NULL || lock_fname[0] == '\0')
+ {
+ fprintf (stderr, "Cannot assign name to lock file!\n");
+ exit (1);
+ }
+
+ lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY, 0644);
+ if (lock_fd == -1)
+ {
+ perror ("open");
+ fprintf (stderr, "Cannot open lcok file\n");
+ exit (1);
+ }
+ unlink(lock_fname);
+}
+
+void accept_mutex_on()
+{
+ int ret;
+
+ while ((ret = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR)
+ continue;
+
+ if (ret < 0) {
+ log_error ("Unknown failure grabbing accept lock. Exiting!",
+ server_conf);
+ exit(1);
+ }
+}
+
+void accept_mutex_off()
+{
+ if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0)
+ {
+ log_error("Error freeing accept lock. Exiting!", server_conf);
+ exit(1);
+ }
+}
+#else
+/* Default --- no serialization. Other methods *could* go here,
+ * as #elifs...
+ */
+#define accept_mutex_init(x)
+#define accept_mutex_on()
+#define accept_mutex_off()
+#endif
+
+void usage(char *bin)
+{
+ fprintf(stderr,"Usage: %s [-d directory] [-f file] [-v]\n",bin);
+ fprintf(stderr,"-d directory : specify an alternate initial ServerRoot\n");
+ fprintf(stderr,"-f file : specify an alternate ServerConfigFile\n");
+ exit(1);
+}
+
+/*****************************************************************
+ *
+ * Timeout handling. DISTINCTLY not thread-safe, but all this stuff
+ * has to change for threads anyway. Note that this code allows only
+ * one timeout in progress at a time...
+ */
+
+static conn_rec *current_conn;
+static request_rec *timeout_req;
+static char *timeout_name;
+static int alarms_blocked = 0;
+static int alarm_pending = 0;
+
+void abort_connection (conn_rec *);
+
+void timeout(sig) /* Also called on SIGPIPE */
+int sig;
+{
+ char errstr[MAX_STRING_LEN];
+
+ if (alarms_blocked) {
+ alarm_pending = 1;
+ return;
+ }
+
+ if (!current_conn) {
+#ifdef NEXT
+ longjmp(jmpbuffer,1);
+#else
+ siglongjmp(jmpbuffer,1);
+#endif
+ }
+
+ sprintf(errstr,"%s timed out for %s",
+ timeout_name ? timeout_name : "request",
+ current_conn->remote_name);
+
+ log_error(errstr, current_conn->server);
+
+ if (timeout_req) {
+ /* Someone has asked for this transaction to just be aborted
+ * if it times out...
+ */
+
+ request_rec *log_req = timeout_req;
+
+ while (log_req->main || log_req->prev) {
+ /* Get back to original request... */
+ if (log_req->main) log_req = log_req->main;
+ else log_req = log_req->prev;
+ }
+
+ log_transaction(log_req);
+
+ pfclose (timeout_req->connection->pool,
+ timeout_req->connection->client);
+ pfclose (timeout_req->connection->pool,
+ timeout_req->connection->request_in);
+
+ if (!standalone) exit(0);
+#ifdef NEXT
+ longjmp(jmpbuffer,1);
+#else
+ siglongjmp(jmpbuffer,1);
+#endif
+ }
+ else {
+ abort_connection (current_conn);
+ }
+}
+
+/*
+ * These two called from alloc.c to protect its critical sections...
+ * Note that they can nest (as when destroying the sub_pools of a pool
+ * which is itself being cleared); we have to support that here.
+ */
+
+void block_alarms() {
+ ++alarms_blocked;
+}
+
+void unblock_alarms() {
+ --alarms_blocked;
+ if (alarms_blocked == 0 && alarm_pending) {
+ alarm_pending = 0;
+ timeout(0);
+ }
+}
+
+void hard_timeout (char *name, request_rec *r)
+{
+ timeout_req = r;
+ timeout_name = name;
+
+ signal(SIGALRM,(void (*)())timeout);
+ alarm (r->server->timeout);
+}
+
+void soft_timeout (char *name, request_rec *r)
+{
+ timeout_name = name;
+
+ signal(SIGALRM,(void (*)())timeout);
+ alarm (r->server->timeout);
+}
+
+void kill_timeout (request_rec *dummy) {
+ alarm (0);
+ timeout_req = NULL;
+ timeout_name = NULL;
+}
+
+/*****************************************************************
+ *
+ * Dealing with the scoreboard... a lot of these variables are global
+ * only to avoid getting clobbered by the longjmp() that happens when
+ * a hard timeout expires...
+ *
+ * We begin with routines which deal with the file itself...
+ */
+
+static short_score scoreboard_image[HARD_SERVER_MAX];
+static char scoreboard_fname[] = "/tmp/htstatus.XXXXXX";
+static int have_scoreboard_fname = 0;
+static int scoreboard_fd;
+
+static int force_write (int fd, char *buffer, int bufsz)
+{
+ int rv, orig_sz = bufsz;
+
+ do {
+ rv = write (fd, buffer, bufsz);
+ if (rv > 0) {
+ buffer += rv;
+ bufsz -= rv;
+ }
+ } while (rv > 0 && bufsz > 0);
+
+ return rv < 0? rv : orig_sz - bufsz;
+}
+
+static int force_read (int fd, char *buffer, int bufsz)
+{
+ int rv, orig_sz = bufsz;
+
+ do {
+ rv = read (fd, buffer, bufsz);
+ if (rv > 0) {
+ buffer += rv;
+ bufsz -= rv;
+ }
+ } while (rv > 0 && bufsz > 0);
+
+ return rv < 0? rv : orig_sz - bufsz;
+}
+
+void reinit_scoreboard (pool *p)
+{
+ if (!have_scoreboard_fname && (mktemp(scoreboard_fname) == NULL ||
+ scoreboard_fname[0] == '\0')) {
+ fprintf (stderr, "Cannot assign name to scoreboard file!\n");
+ exit (1);
+ }
+
+ have_scoreboard_fname = 1;
+
+ scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0644);
+ if (scoreboard_fd == -1)
+ {
+ fprintf (stderr, "Cannot open scoreboard file:\n");
+ perror (scoreboard_fname);
+ exit (1);
+ }
+
+ memset ((char*)scoreboard_image, 0, sizeof(scoreboard_image));
+ force_write (scoreboard_fd, (char*)scoreboard_image,
+ sizeof(scoreboard_image));
+}
+
+void reopen_scoreboard (pool *p)
+{
+ if (scoreboard_fd != -1) pclosef (p, scoreboard_fd);
+
+ scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0666);
+ if (scoreboard_fd == -1)
+ {
+ fprintf (stderr, "Cannot open scoreboard file:\n");
+ perror (scoreboard_fname);
+ exit (1);
+ }
+}
+
+void cleanup_scoreboard ()
+{
+ unlink (scoreboard_fname);
+}
+
+/* Routines called to deal with the scoreboard image
+ * --- note that we do *not* need write locks, since update_child_status
+ * only updates a *single* record in place, and only one process writes to
+ * a given scoreboard slot at a time (either the child process owning that
+ * slot, or the parent, noting that the child has died).
+ *
+ * As a final note --- setting the score entry to getpid() is always safe,
+ * since when the parent is writing an entry, it's only noting SERVER_DEAD
+ * anyway.
+ */
+
+void sync_scoreboard_image ()
+{
+ lseek (scoreboard_fd, 0L, 0);
+ force_read (scoreboard_fd, (char*)scoreboard_image,
+ sizeof(scoreboard_image));
+}
+
+void update_child_status (int child_num, int status)
+{
+ short_score new_score_rec;
+ new_score_rec.pid = getpid();
+ new_score_rec.status = status;
+
+ lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
+ force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
+}
+
+int count_idle_servers ()
+{
+ int i;
+ int res = 0;
+
+ for (i = 0; i < HARD_SERVER_MAX; ++i)
+ if (scoreboard_image[i].status == SERVER_READY)
+ ++res;
+
+ return res;
+}
+
+int find_free_child_num ()
+{
+ int i;
+
+ for (i = 0; i < HARD_SERVER_MAX; ++i)
+ if (scoreboard_image[i].status == SERVER_DEAD)
+ return i;
+
+ return -1;
+}
+
+int find_child_by_pid (int pid)
+{
+ int i;
+
+ for (i = 0; i < HARD_SERVER_MAX; ++i)
+ if (scoreboard_image[i].pid == pid)
+ return i;
+
+ return -1;
+}
+
+void reclaim_child_processes ()
+{
+ int i, status;
+ int my_pid = getpid();
+
+ sync_scoreboard_image();
+ for (i = 0; i < HARD_SERVER_MAX; ++i) {
+ int pid = scoreboard_image[i].pid;
+
+ if (pid != my_pid && pid != 0)
+ waitpid (scoreboard_image[i].pid, &status, 0);
+ }
+}
+
+/* Finally, this routine is used by the caretaker process to wait for
+ * a while...
+ */
+
+static jmp_buf wait_timeout_buf;
+static int wait_or_timeout_retval = -1;
+
+static void longjmp_out_of_alarm (int sig) {
+ longjmp (wait_timeout_buf, 1);
+}
+
+int wait_or_timeout (int *status)
+{
+ wait_or_timeout_retval = -1;
+
+ if (setjmp(wait_timeout_buf) != 0) {
+ errno = ETIMEDOUT;
+ alarm(0);
+ return wait_or_timeout_retval;
+ }
+
+ signal (SIGALRM, longjmp_out_of_alarm);
+ alarm(1);
+#if defined(NEXT)
+ wait_or_timeout_retval = wait((union wait *)status);
+#else
+ wait_or_timeout_retval = wait(status);
+#endif
+ alarm(0);
+ return wait_or_timeout_retval;
+}
+
+
+/*****************************************************************
+ * Here follows a long bunch of generic server bookkeeping stuff...
+ */
+
+void detach()
+{
+ int x;
+
+ chdir("/");
+ if((x = fork()) > 0)
+ exit(0);
+ else if(x == -1) {
+ fprintf(stderr,"httpd: unable to fork new process\n");
+ perror("fork");
+ exit(1);
+ }
+#ifndef NO_SETSID
+ if((pgrp=setsid()) == -1) {
+ fprintf(stderr,"httpd: setsid failed\n");
+ perror("setsid");
+ exit(1);
+ }
+#else
+#if defined(NEXT)
+ if(setpgrp(0,getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
+ fprintf(stderr,"httpd: setpgrp or getpgrp failed\n");
+ perror("setpgrp");
+ exit(1);
+ }
+#else
+ if((pgrp=setpgrp(getpid(),0)) == -1) {
+ fprintf(stderr,"httpd: setpgrp failed\n");
+ perror("setpgrp");
+ exit(1);
+ }
+#endif
+#endif
+}
+
+void sig_term() {
+ log_error("httpd: caught SIGTERM, shutting down", server_conf);
+ cleanup_scoreboard();
+#ifndef NO_KILLPG
+ killpg(pgrp,SIGKILL);
+#else
+ kill(-pgrp,SIGKILL);
+#endif
+ shutdown(sd,2);
+ close(sd);
+ exit(1);
+}
+
+void bus_error() {
+ log_error("httpd: caught SIGBUS, dumping core", server_conf);
+ chdir(server_root);
+ abort();
+ exit(1);
+}
+
+void seg_fault() {
+ log_error("httpd: caught SIGSEGV, dumping core", server_conf);
+ chdir(server_root);
+ abort();
+ exit(1);
+}
+
+void just_die() /* SIGHUP to child process??? */
+{
+ exit (0);
+}
+
+/* Reset group privileges, after rereading the config files
+ * (our uid may have changed, and if so, we want the new perms).
+ *
+ * Don't reset the uid yet --- we do that only in the child process,
+ * so as not to lose any root privs. But we can set the group stuff
+ * now, once, as opposed to once per each new child.
+ *
+ * Note that we use the username as set in the config files, rather than
+ * the lookup of to uid --- the same uid may have multiple passwd entries,
+ * with different sets of groups for each.
+ */
+
+static void set_group_privs()
+{
+ if(!geteuid()) {
+ char *name;
+
+ /* Get username if passed as a uid */
+
+ if (user_name[0] == '#') {
+ struct passwd* ent;
+ uid_t uid=atoi(&user_name[1]);
+
+ if ((ent = getpwuid(uid)) == NULL) {
+ log_error("couldn't determine user name from uid", server_conf);
+ exit(1);
+ }
+
+ name = ent->pw_name;
+ } else name = user_name;
+
+ /* Reset `groups' attributes. */
+
+ if (initgroups(name, group_id) == -1) {
+ log_error ("unable to set groups", server_conf);
+ exit (1);
+ }
+
+ if (setgid(group_id) == -1) {
+ log_error ("unable to set group id", server_conf);
+ exit (1);
+ }
+ }
+}
+
+void restart() {
+ signal (SIGALRM, SIG_IGN);
+ alarm (0);
+#ifdef NEXT
+ longjmp(restart_buffer,1);
+#else
+ siglongjmp(restart_buffer,1);
+#endif
+}
+
+void set_signals() {
+ if(!one_process)
+ {
+ signal(SIGSEGV,(void (*)())seg_fault);
+ signal(SIGBUS,(void (*)())bus_error);
+ }
+ signal(SIGTERM,(void (*)())sig_term);
+ signal(SIGHUP,(void (*)())restart);
+}
+
+/*****************************************************************
+ * Connection structures and accounting...
+ * Should these be global? Only to this file, at least...
+ */
+
+pool *pconf; /* Pool for config stuff */
+pool *ptrans; /* Pool for per-transaction stuff */
+
+server_rec *find_virtual_server (struct in_addr server_ip, server_rec *server)
+{
+ server_rec *virt;
+
+ for (virt = server->next; virt; virt = virt->next)
+ if (virt->host_addr.s_addr == server_ip.s_addr)
+ return virt;
+
+ return server;
+}
+
+void default_server_hostnames(server_rec *s)
+{
+ /* Main host first */
+
+ if (!s->server_hostname)
+ s->server_hostname = get_local_host(pconf);
+
+ /* Then virtual hosts */
+
+ for (s = s->next; s; s = s->next)
+ if (!s->server_hostname) {
+ struct hostent *h = gethostbyaddr ((char *)&(s->host_addr),
+ sizeof (struct in_addr),
+ AF_INET);
+ if (h != NULL) {
+ s->server_hostname = pstrdup (pconf, (char *)h->h_name);
+ }
+ }
+}
+
+void abort_connection (conn_rec *c)
+{
+ /* Make sure further I/O DOES NOT HAPPEN */
+ shutdown (fileno (c->client), 2);
+ signal (SIGPIPE, SIG_IGN); /* Ignore further complaints */
+ c->aborted = 1;
+}
+
+conn_rec *new_connection (pool *p, server_rec *server, FILE *in, FILE *out,
+ const struct sockaddr_in *saddr)
+{
+ conn_rec *conn = (conn_rec *)pcalloc (p, sizeof(conn_rec));
+
+ /* Get a connection structure, and initialize what fields we can
+ * (the rest are zeroed out by pcalloc).
+ */
+
+ conn = (conn_rec *)pcalloc(p, sizeof(conn_rec));
+
+ conn->pool = p;
+ conn->server = find_virtual_server (saddr->sin_addr, server);
+ conn->client = out;
+ conn->request_in = in;
+
+ get_remote_host(conn);
+
+ return conn;
+}
+
+/*****************************************************************
+ * Child process main loop.
+ * The following vars are static to avoid getting clobbered by longjmp();
+ * they are really private to child_main.
+ */
+
+static int csd;
+static int dupped_csd;
+static int requests_this_child;
+static int child_num;
+
+void child_main(int child_num_arg)
+{
+ int clen;
+ struct sockaddr sa_server;
+ struct sockaddr sa_client;
+
+#ifdef ULTRIX_BRAIN_DEATH
+ extern char *rfc931();
+#else
+ extern char *rfc931 (struct sockaddr_in *, struct sockaddr_in *);
+#endif
+
+ csd = -1;
+ dupped_csd = -1;
+ child_num = child_num_arg;
+ requests_this_child = 0;
+ reopen_scoreboard (pconf);
+ update_child_status (child_num, SERVER_READY);
+
+ /* Only try to switch if we're running as root */
+ if(!geteuid() && setuid(user_id) == -1) {
+ log_error ("unable to change uid", server_conf);
+ exit (1);
+ }
+
+#ifdef NEXT
+ setjmp(jmpbuffer);
+#else
+ sigsetjmp(jmpbuffer,1);
+#endif
+ signal(SIGURG, timeout);
+
+ while (1) {
+ FILE *conn_in, *conn_out;
+ request_rec *r;
+
+ alarm(0); /* Cancel any outstanding alarms. */
+ timeout_req = NULL; /* No request in progress */
+ current_conn = NULL;
+ signal(SIGPIPE, timeout);
+
+ clear_pool (ptrans);
+
+ sync_scoreboard_image();
+
+ if ((count_idle_servers() >= daemons_max_free)
+ || (max_requests_per_child > 0
+ && ++requests_this_child >= max_requests_per_child))
+ {
+ exit(0);
+ }
+
+ clen=sizeof(sa_client);
+ update_child_status (child_num, SERVER_READY);
+
+ accept_mutex_on(); /* Lock around "accept", if necessary */
+
+ while ((csd=accept(sd, &sa_client, &clen)) == -1)
+ if (errno != EINTR)
+ log_error("socket error: accept failed", server_conf);
+
+ accept_mutex_off(); /* unlock after "accept" */
+
+ clen = sizeof(sa_server);
+ if(getsockname(csd, &sa_server, &clen) < 0) {
+ log_error("getsockname: failed", server_conf);
+ continue;
+ }
+
+ dupped_csd = csd;
+#if defined(AUX) || defined(SCO)
+ if ((dupped_csd = dup(csd)) < 0) {
+ log_error("couldn't duplicate csd", server_conf);
+ dupped_csd = csd; /* Oh well... */
+ }
+#endif
+ update_child_status (child_num, SERVER_BUSY);
+ conn_in = pfdopen (ptrans, csd, "r");
+ conn_out = pfdopen (ptrans, dupped_csd, "w");
+
+ current_conn = new_connection (ptrans, server_conf, conn_in, conn_out,
+ (struct sockaddr_in *)&sa_server);
+
+ if (current_conn->server->do_rfc931)
+ current_conn->remote_logname =
+ rfc931((struct sockaddr_in *)&sa_client,
+ (struct sockaddr_in *)&sa_server);
+
+ r = read_request (current_conn);
+ if (r) process_request (r); /* else premature EOF --- ignore */
+
+ if (bytes_in_pool (ptrans) > 80000) {
+ char errstr[MAX_STRING_LEN];
+ sprintf (errstr, "Memory hog alert: allocated %ld bytes for %s",
+ bytes_in_pool (ptrans), r->the_request);
+ log_error (errstr, r->server);
+ }
+
+ fflush (conn_out);
+ pfclose (ptrans,conn_in);
+ pfclose (ptrans,conn_out);
+ }
+}
+
+void make_child(server_rec *server_conf, int child_num)
+{
+ int pid;
+
+ if (one_process) {
+ signal (SIGHUP, (void (*)())just_die);
+ signal (SIGTERM, (void (*)())just_die);
+ child_main (child_num);
+ }
+
+ if ((pid = fork()) == -1) {
+ log_error("Unable to fork new process", server_conf);
+ return;
+ }
+
+ if (!pid) {
+ signal (SIGHUP, (void (*)())just_die);
+ signal (SIGTERM, (void (*)())just_die);
+ child_main (child_num);
+ }
+}
+
+/*****************************************************************
+ * Executive routines.
+ */
+
+static int keepalive_value = 1;
+static int one = 1;
+static int num_children = 0;
+
+void standalone_main(int argc, char **argv)
+{
+ struct sockaddr_in sa_server;
+
+ standalone = 1;
+ sd = -1;
+
+ if (!one_process) detach();
+
+#ifdef NEXT
+ setjmp(restart_buffer);
+#else
+ sigsetjmp(restart_buffer,1);
+#endif
+
+ signal (SIGHUP, SIG_IGN); /* Until we're done (re)reading config */
+
+ if(!one_process)
+#ifndef NO_KILLPG
+ killpg(pgrp,SIGHUP); /* Kill 'em off */
+#else
+ kill(-pgrp,SIGHUP);
+#endif
+
+ if (sd != -1) {
+ reclaim_child_processes(); /* Not when just starting up */
+ log_error ("SIGHUP received. Attempting to restart", server_conf);
+ }
+
+ clear_pool (pconf);
+ ptrans = make_sub_pool (pconf);
+
+ server_conf = read_config(pconf, ptrans, server_confname);
+ open_logs(server_conf, pconf);
+ set_group_privs();
+ accept_mutex_init(pconf);
+ reinit_scoreboard(pconf);
+
+ default_server_hostnames (server_conf);
+
+ if ((sd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
+ fprintf(stderr,"httpd: could not get socket\n");
+ perror("socket");
+ exit(1);
+ }
+
+ note_cleanups_for_fd (pconf, sd); /* arrange to close on exec or restart */
+
+ if((setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,(const char *)&one,sizeof(one)))
+ == -1) {
+ fprintf(stderr,"httpd: could not set socket option\n");
+ perror("setsockopt");
+ exit(1);
+ }
+ if((setsockopt(sd,SOL_SOCKET,SO_KEEPALIVE,(const void *)&keepalive_value,
+ sizeof(keepalive_value))) == -1) {
+ fprintf(stderr,"httpd: could not set socket option SO_KEEPALIVE\n");
+ perror("setsockopt");
+ exit(1);
+ }
+
+ memset((char *) &sa_server, 0, sizeof(sa_server));
+ sa_server.sin_family=AF_INET;
+ sa_server.sin_addr=bind_address;
+ sa_server.sin_port=htons(server_conf->port);
+ if(bind(sd,(struct sockaddr *) &sa_server,sizeof(sa_server)) == -1) {
+ if (bind_address.s_addr != htonl(INADDR_ANY))
+ fprintf(stderr,"httpd: could not bind to address %s port %d\n",
+ inet_ntoa(bind_address), server_conf->port);
+ else
+ fprintf(stderr,"httpd: could not bind to port %d\n",
+ server_conf->port);
+ perror("bind");
+ exit(1);
+ }
+ listen(sd, 512);
+
+ set_signals();
+ log_pid(pconf, pid_fname);
+
+ num_children = 0;
+
+ if (daemons_max_free < daemons_min_free + 1) /* Don't thrash... */
+ daemons_max_free = daemons_min_free + 1;
+
+ while (num_children < daemons_to_start) {
+ make_child(server_conf, num_children++);
+ }
+
+ log_error ("Server configured -- resuming normal operations", server_conf);
+
+ while (1) {
+ int status, child_slot;
+ int pid = wait_or_timeout(&status);
+
+ if (pid >= 0) {
+ /* Child died... note that it's gone in the scoreboard. */
+ sync_scoreboard_image();
+ child_slot = find_child_by_pid (pid);
+ if (child_slot >= 0) update_child_status (child_slot, SERVER_DEAD);
+ }
+
+ sync_scoreboard_image();
+ if ((count_idle_servers() < daemons_min_free)
+ && (child_slot = find_free_child_num()) >= 0
+ && child_slot <= daemons_limit)
+ make_child(server_conf, child_slot);
+ }
+
+} /* standalone_main */
+
+extern char *optarg;
+extern int optind;
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+
+ init_alloc();
+ pconf = permanent_pool;
+ ptrans = make_sub_pool(pconf);
+
+ server_argv0 = argv[0];
+ strcpy (server_root, HTTPD_ROOT);
+ strcpy (server_confname, SERVER_CONFIG_FILE);
+
+ while((c = getopt(argc,argv,"Xd:f:v")) != -1) {
+ switch(c) {
+ case 'd':
+ strcpy (server_root, optarg);
+ break;
+ case 'f':
+ strcpy (server_confname, optarg);
+ break;
+ case 'v':
+ printf("Server version %s.\n",SERVER_VERSION);
+ exit(1);
+ case 'X':
+ ++one_process; /* Weird debugging mode. */
+ break;
+ case '?':
+ usage(argv[0]);
+ }
+ }
+
+ setup_prelinked_modules();
+
+ server_conf = read_config (pconf, ptrans, server_confname);
+
+ if(standalone) {
+ clear_pool (pconf); /* standalone_main rereads... */
+ standalone_main(argc, argv);
+ }
+ else {
+ conn_rec *conn;
+ request_rec *r;
+ struct sockaddr sa_server;
+
+ open_logs(server_conf, pconf);
+ set_group_privs();
+ default_server_hostnames (server_conf);
+
+ user_id = getuid();
+ group_id = getgid();
+
+ c = sizeof(sa_server);
+ if(getsockname(csd, &sa_server, &c) < 0) {
+ perror("getsockname");
+ fprintf(stderr, "Error getting local address\n");
+ exit(1);
+ }
+ server_conf->port =ntohs(((struct sockaddr_in *)&sa_server)->sin_port);
+ conn = new_connection (ptrans, server_conf, stdin, stdout,
+ (struct sockaddr_in *)&sa_server);
+ r = read_request (conn);
+ if (r) process_request (r); /* else premature EOF (ignore) */
+ }
+ exit (0);
+}
+
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_protocol.c --- routines which directly communicate with the
+ * client.
+ *
+ * Code originally by Rob McCool; much redone by rst.
+ */
+
+#define CORE_PRIVATE
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h" /* For errors detected in basic auth
+ * common support code...
+ */
+
+#include <stdarg.h>
+
+/* Handling of conditional gets (if-modified-since); Roy owes Rob beer.
+ * This would be considerably easier if strptime or timegm were portable...
+ */
+
+static char *months[] = {
+ "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
+};
+
+int find_month(char *mon) {
+ register int x;
+
+ for(x=0;x<12;x++)
+ if(!strcmp(months[x],mon))
+ return x;
+ return -1;
+}
+
+int later_than(struct tm *lms, char *ims) {
+ char *ip;
+ char mname[MAX_STRING_LEN];
+ int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, x;
+
+ /* Whatever format we're looking at, it will start with weekday. */
+ /* Skip to first space. */
+ if(!(ip = strchr(ims,' ')))
+ return 0;
+ else
+ while(isspace(*ip))
+ ++ip;
+
+ if(isalpha(*ip)) {
+ /* ctime */
+ sscanf(ip,"%s %d %d:%d:%d %d",mname,&day,&hour,&min,&sec,&year);
+ }
+ else if(ip[2] == '-') {
+ /* RFC 850 (normal HTTP) */
+ char t[MAX_STRING_LEN];
+ sscanf(ip,"%s %d:%d:%d",t,&hour,&min,&sec);
+ t[2] = '\0';
+ day = atoi(t);
+ t[6] = '\0';
+ strcpy(mname,&t[3]);
+ x = atoi(&t[7]);
+ /* Prevent wraparound from ambiguity */
+ if(x < 70)
+ x += 100;
+ year = 1900 + x;
+ }
+ else {
+ /* RFC 822 */
+ sscanf(ip,"%d %s %d %d:%d:%d",&day,mname,&year,&hour,&min,&sec);
+ }
+ month = find_month(mname);
+
+ if((x = (1900+lms->tm_year) - year))
+ return x < 0;
+ if((x = lms->tm_mon - month))
+ return x < 0;
+ if((x = lms->tm_mday - day))
+ return x < 0;
+ if((x = lms->tm_hour - hour))
+ return x < 0;
+ if((x = lms->tm_min - min))
+ return x < 0;
+ if((x = lms->tm_sec - sec))
+ return x < 0;
+
+ return 1;
+}
+
+
+int set_content_length (request_rec *r, long clength)
+{
+ char ts[MAX_STRING_LEN];
+
+ sprintf (ts, "%ld", (long)r->finfo.st_size);
+ table_set (r->headers_out, "Content-length", pstrdup (r->pool, ts));
+ return 0;
+}
+
+int set_last_modified(request_rec *r, time_t mtime)
+{
+ struct tm *tms;
+ char ts[MAX_STRING_LEN];
+ char *if_modified_since = table_get (r->headers_in, "If-modified-since");
+
+ /* Cacheing proxies use the absence of a Last-modified header
+ * to indicate that a document is dynamic and shouldn't be cached.
+ * For the moment, we enforce that here, though it would probably
+ * work just as well to generate an Expires: header in send_http_header.
+ *
+ * However, even in that case, if no_cache is set, we would *not*
+ * want to send USE_LOCAL_COPY, since the client isn't *supposed*
+ * to have it cached.
+ */
+
+ if (r->no_cache) return OK;
+
+ tms = gmtime(&mtime);
+ strftime(ts,MAX_STRING_LEN,HTTP_TIME_FORMAT,tms);
+ table_set (r->headers_out, "Last-modified", pstrdup (r->pool, ts));
+
+ /* Check for conditional GETs --- note that we only want this check
+ * to succeed if the GET was successful; ErrorDocuments *always* get sent.
+ */
+
+ if (r->status == 200 &&
+ if_modified_since && later_than(tms, if_modified_since))
+
+ return USE_LOCAL_COPY;
+ else
+ return OK;
+}
+
+/*
+ * Finally, real protocol stuff.
+ */
+
+char *getline (char *s, int n, FILE *in)
+{
+ char *retval = fgets (s, n, in);
+ char *cp;
+
+ if (retval == NULL) return NULL;
+
+ cp = s + strlen(s) - 1;
+
+ while (cp >= s && (*cp == '\015' || *cp == '\012'))
+ *cp-- = '\0';
+
+ return s;
+}
+
+void parse_uri (request_rec *r, char *uri)
+{
+ /* If we ever want to do byte-ranges a la Netscape & Franks,
+ * this is the place to parse them; with proper support in
+ * rprintf and rputc, and the sub-request setup and finalizers
+ * here, it'll all just work, even for vile cases like
+ * inclusion of byte-ranges of the output of CGI scripts, with
+ * the client requesting only a byte-range of *that*!
+ *
+ * But for now...
+ */
+
+ r->uri = getword (r->pool, &uri, '?');
+ if (*uri) r->args= uri;
+ else r->args = NULL;
+}
+
+int read_request_line (request_rec *r)
+{
+ char l[HUGE_STRING_LEN];
+ char *ll = l, *uri;
+ conn_rec *conn = r->connection;
+
+ l[0] = '\0';
+ if(!getline(l, HUGE_STRING_LEN, conn->request_in))
+ return 0;
+ if(!l[0])
+ return 0;
+
+ r->the_request = pstrdup (r->pool, l);
+ r->method = getword(r->pool, &ll,' ');
+ uri = getword(r->pool, &ll,' ');
+ parse_uri (r, uri);
+
+ r->assbackwards = (ll[0] == '\0');
+ r->protocol = ll[0] ? pstrdup (r->pool, ll) : "HTTP/0.9";
+ return 1;
+}
+
+void get_mime_headers(request_rec *r)
+{
+ char w[MAX_STRING_LEN];
+ char *t;
+ conn_rec *c = r->connection;
+
+ while(getline(w, MAX_STRING_LEN-1, c->request_in)) {
+ if(!w[0])
+ return;
+ if(!(t = strchr(w,':')))
+ continue;
+ *t++ = '\0';
+ while(isspace(*t)) ++t;
+
+ table_merge (r->headers_in, w, t);
+ }
+}
+
+request_rec *read_request (conn_rec *conn)
+{
+ request_rec *r = (request_rec *)pcalloc (conn->pool, sizeof(request_rec));
+
+ r->connection = conn;
+ r->server = conn->server;
+ r->pool = conn->pool;
+
+ r->headers_in = make_table (r->pool, 50);
+ r->subprocess_env = make_table (r->pool, 50);
+ r->headers_out = make_table (r->pool, 5);
+ r->err_headers_out = make_table (r->pool, 5);
+ r->notes = make_table (r->pool, 5);
+
+ r->request_config = create_request_config (r->pool);
+ r->per_dir_config = r->server->lookup_defaults; /* For now. */
+
+ r->bytes_sent = -1;
+
+ r->status = 200; /* Until further notice.
+ * Only changed by die(), or (bletch!)
+ * scan_script_header...
+ */
+
+ /* Get the request... */
+
+ hard_timeout ("read", r);
+ if (!read_request_line (r)) return NULL;
+ if (!r->assbackwards) get_mime_headers(r);
+ kill_timeout (r);
+
+ if(!strcmp(r->method, "HEAD")) {
+ r->header_only=1;
+ r->method_number = M_GET;
+ }
+ else if(!strcmp(r->method, "GET"))
+ r->method_number = M_GET;
+ else if(!strcmp(r->method,"POST"))
+ r->method_number = M_POST;
+ else if(!strcmp(r->method,"PUT"))
+ r->method_number = M_PUT;
+ else if(!strcmp(r->method,"DELETE"))
+ r->method_number = M_DELETE;
+ else
+ r->method_number = M_INVALID; /* Will eventually croak. */
+
+ return r;
+}
+
+/*
+ * A couple of other functions which initialize some of the fields of
+ * a request structure, as appropriate for adjuncts of one kind or another
+ * to a request in progress. Best here, rather than elsewhere, since
+ * *someone* has to set the protocol-specific fields...
+ */
+
+void set_sub_req_protocol (request_rec *rnew, request_rec *r)
+{
+ rnew->assbackwards = 1; /* Don't send headers from this. */
+ rnew->no_cache = 1; /* Don't try to send USE_LOCAL_COPY for a
+ * fragment.
+ */
+ rnew->method = "GET"; rnew->method_number = M_GET;
+ rnew->protocol = "INCLUDED";
+
+ rnew->status = 200;
+
+ rnew->headers_in = r->headers_in;
+ rnew->subprocess_env = copy_table (rnew->pool, r->subprocess_env);
+ rnew->headers_out = make_table (rnew->pool, 5);
+ rnew->err_headers_out = make_table (rnew->pool, 5);
+ rnew->notes = make_table (rnew->pool, 5);
+
+ rnew->main = r;
+}
+
+void finalize_sub_req_protocol (request_rec *sub)
+{
+ sub->main->bytes_sent += sub->bytes_sent;
+}
+
+/* Support for the Basic authentication protocol.
+ */
+
+void note_basic_auth_failure(request_rec *r)
+{
+ table_set (r->err_headers_out, "WWW-Authenticate",
+ pstrcat(r->pool, "Basic realm=\"", auth_name(r), "\"", NULL));
+}
+
+
+int get_basic_auth_pw (request_rec *r, char **pw)
+{
+ char *auth_line = table_get (r->headers_in, "Authorization");
+ char *t;
+
+ if(!(t = auth_type(r)) || strcasecmp(t, "Basic"))
+ return DECLINED;
+
+ if (!auth_name (r)) {
+ log_reason ("need AuthName", r->uri, r);
+ return SERVER_ERROR;
+ }
+
+ if(!auth_line) {
+ note_basic_auth_failure (r);
+ return AUTH_REQUIRED;
+ }
+
+ if (strcmp(getword (r->pool, &auth_line, ' '), "Basic")) {
+ /* Client tried to authenticate using wrong auth scheme */
+ log_reason ("client used wrong authentication scheme", r->uri, r);
+ note_basic_auth_failure (r);
+ return AUTH_REQUIRED;
+ }
+
+ t = uudecode (r->pool, auth_line);
+ r->connection->user = getword (r->pool, &t, ':');
+
+ *pw = t;
+
+ return OK;
+}
+
+#define RESPONSE_CODE_LIST " 200 302 304 400 401 403 404 500 503 501 "
+
+/* New Apache routine to map error responses into array indicies
+ * e.g. 400 -> 0, 500 -> 1, 502 -> 2 ...
+ * the indicies have no significance
+ */
+
+char *status_lines[] = {
+ "200 OK",
+ "302 Found",
+ "304 Not Modified",
+ "400 Bad Request",
+ "401 Unauthorized",
+ "403 Forbidden",
+ "404 Not found",
+ "500 Server error",
+ "503 Out of resources",
+ "501 Not Implemented",
+};
+
+char *response_titles[] = {
+ "200 OK", /* Never actually sent, barring die(200,...) */
+ "Document moved", /* 302 Redirect */
+ "304 Not Modified", /* Never sent... 304 MUST be header only */
+ "Bad Request",
+ "Authorization Required",
+ "Forbidden",
+ "File Not found",
+ "Server Error",
+ "Out of resources",
+ "Method not implemented"
+};
+
+int index_of_response(int err_no) {
+ char *cptr, err_string[10];
+ static char *response_codes = RESPONSE_CODE_LIST;
+ int index_number;
+
+ sprintf(err_string,"%3d",err_no);
+
+ cptr = response_codes;
+ cptr++;
+ index_number = 0;
+ while (*cptr && strncmp(cptr, err_string, 3)) {
+ cptr += 4;
+ index_number++;
+ }
+ if (!*cptr) return -1;
+ return index_number;
+}
+
+
+void basic_http_header (request_rec *r)
+{
+ FILE *fd = r->connection->client;
+
+ if (r->assbackwards) return;
+
+ if (!r->status_line)
+ r->status_line = status_lines[index_of_response(r->status)];
+
+ fprintf(fd,"%s %s\015\012", SERVER_PROTOCOL, r->status_line);
+ fprintf(fd,"Date: %s\015\012", gm_timestr_822 (r->pool, time(NULL)));
+ fprintf(fd,"Server: %s\015\012",SERVER_VERSION);
+}
+
+char *nuke_mime_parms (pool *p, char *content_type)
+{
+ /* How marvelous. Arena doesn't *accept* "text/html; level=3"
+ * as a MIME type, so we have to strip off the parms.
+ */
+
+#ifndef ARENA_BUG_WORKAROUND
+ return content_type;
+#else
+
+ char *cp = strchr(content_type, ';');
+
+ if (cp) {
+ content_type = pstrdup (p, content_type);
+ cp = strchr (content_type, ';');
+
+ while (cp > content_type && isspace (cp[-1]))
+ --cp;
+ *cp = '\0';
+ }
+
+ return content_type;
+#endif
+}
+
+void send_http_header(request_rec *r)
+{
+ conn_rec *c = r->connection;
+ FILE *fd = c->client;
+
+ array_header *hdrs_arr = table_elts (r->headers_out);
+ table_entry *hdrs = (table_entry *)hdrs_arr->elts;
+
+ array_header *err_hdrs_arr = table_elts (r->err_headers_out);
+ table_entry *err_hdrs = (table_entry *)err_hdrs_arr->elts;
+ int i;
+
+ core_dir_config *dir_conf =
+ (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
+ char *default_type = dir_conf->default_type;
+
+ if (r->assbackwards) {
+ r->bytes_sent = 0;
+ return;
+ }
+
+ basic_http_header (r);
+
+ if (r->content_type)
+ fprintf (fd, "Content-type: %s\015\012",
+ nuke_mime_parms (r->pool, r->content_type));
+ else
+ fprintf (fd, "Content-type: %s\015\012", default_type);
+
+ if (r->content_encoding)
+ fprintf (fd, "Content-encoding: %s\015\012", r->content_encoding);
+
+ if (r->content_language)
+ fprintf (fd, "Content-language: %s\015\012", r->content_language);
+
+ for (i = 0; i < hdrs_arr->nelts; ++i) {
+ if (!hdrs[i].key) continue;
+ fprintf (fd, "%s: %s\015\012", hdrs[i].key, hdrs[i].val);
+ }
+
+ for (i = 0; i < err_hdrs_arr->nelts; ++i) {
+ if (!err_hdrs[i].key) continue;
+ fprintf (fd, "%s: %s\015\012", err_hdrs[i].key, err_hdrs[i].val);
+ }
+
+ fputs("\015\012",fd);
+
+ r->bytes_sent = 0; /* Whatever follows is real body stuff... */
+}
+
+long read_client_block (request_rec *r, char *buffer, int bufsiz)
+{
+ return fread (buffer, sizeof(char), bufsiz, r->connection->request_in);
+}
+
+long send_fd(FILE *f, request_rec *r)
+{
+ char buf[IOBUFSIZE];
+ long total_bytes_sent;
+ register int n,o,w;
+ conn_rec *c = r->connection;
+
+ total_bytes_sent = 0;
+ while (!r->connection->aborted) {
+ while ((n= fread(buf, sizeof(char), IOBUFSIZE, f)) < 1
+ && ferror(f) && errno == EINTR)
+ continue;
+
+ if (n < 1) {
+ break;
+ }
+ o=0;
+ if (r->bytes_sent != -1) r->bytes_sent += n;
+ total_bytes_sent += n;
+
+ while(n && !r->connection->aborted) {
+ w=fwrite(&buf[o],sizeof(char),n,c->client);
+ n-=w;
+ o+=w;
+ }
+ }
+ fflush(c->client);
+
+ return total_bytes_sent;
+}
+
+int rputc (int c, request_rec *r)
+{
+ if (r->connection->aborted) return EOF;
+ putc (c, r->connection->client);
+ ++r->bytes_sent;
+ return c;
+}
+
+long rprintf (request_rec *r, char *fmt, ...)
+{
+ va_list args;
+ int retval;
+
+ if (r->connection->aborted) return EOF;
+
+ va_start (args, fmt);
+ retval = vfprintf (r->connection->client, fmt, args);
+ va_end (args);
+
+ r->bytes_sent += retval;
+ return retval;
+}
+
+void send_error_response (request_rec *r, int recursive_error)
+{
+ conn_rec *c = r->connection;
+ char *custom_response;
+ int status = r->status;
+ int idx = index_of_response (status);
+ char *location = table_get (r->headers_out, "Location");
+
+ if (!r->assbackwards) {
+ int i;
+ table *err_hdrs_arr = r->err_headers_out;
+ table_entry *err_hdrs = (table_entry *)err_hdrs_arr->elts;
+
+ basic_http_header (r);
+
+ /* For conditional get's which didn't send anything, *don't*
+ * send a bogus content-type, or any body --- but must still
+ * terminate header.
+ */
+
+ if (status == USE_LOCAL_COPY) {
+ fprintf (c->client, "\015\012");
+ return;
+ }
+
+ if (status == REDIRECT)
+ fprintf (c->client, "Location: %s\015\012", location);
+
+ for (i = 0; i < err_hdrs_arr->nelts; ++i) {
+ if (!err_hdrs[i].key) continue;
+ fprintf (c->client, "%s: %s\015\012",
+ err_hdrs[i].key, err_hdrs[i].val);
+ }
+
+ fprintf(c->client, "Content-type: text/html\015\012\015\012");
+ }
+
+ if (r->header_only) return;
+
+ if ((custom_response = response_code_string (r, idx)))
+ fputs (custom_response, c->client);
+ else {
+ char *title = response_titles[idx];
+ FILE *fd = c->client;
+
+ fprintf(fd,"<HEAD><TITLE>%s</TITLE></HEAD>%c",title,LF);
+ fprintf(fd,"<BODY><H1>%s</H1>%c",title,LF);
+
+ switch (r->status) {
+ case REDIRECT:
+ fprintf (fd,"The document has moved <A HREF=\"%s\">here</A>.<P>%c",
+ location, LF);
+ break;
+ case AUTH_REQUIRED:
+ fprintf (fd, "This server could not verify that you%c", LF);
+ fprintf (fd, "are authorized to access the document you%c", LF);
+ fprintf (fd, "requested. Either you supplied the wrong%c", LF);
+ fprintf (fd, "credentials (e.g., bad password), or your%c", LF);
+ fprintf (fd, "browser doesn't understand how to supply%c", LF);
+ fprintf (fd, "the credentials required.<P>%c", LF);
+ break;
+ case BAD_REQUEST:
+ fprintf (fd, "Your browser sent a query that%c", LF);
+ fprintf (fd, "this server could not understand.<P>%c", LF);
+ break;
+ case FORBIDDEN:
+ fprintf (fd, "You don't have permission to access %s%c",
+ r->uri, LF);
+ fprintf (fd, "on this server.<P>%c", LF);
+ break;
+ case NOT_FOUND:
+ fprintf (fd,
+ "The requested URL %s was not found on this server.<P>%c",
+ r->uri, LF);
+ break;
+ case SERVER_ERROR:
+ fprintf(fd,"The server encountered an internal error or%c",LF);
+ fprintf(fd,"misconfiguration and was unable to complete%c",LF);
+ fprintf(fd,"your request.<P>%c",LF);
+ fprintf(fd,"Please contact the server administrator,%c",LF);
+ fprintf(fd," %s ", r->server->server_admin);
+ fprintf(fd,"and inform them of the time the error occurred,%c",LF);
+ fprintf(fd,"and anything you might have done that may have%c",LF);
+ fprintf(fd,"caused the error.<P>%c",LF);
+ break;
+ case NOT_IMPLEMENTED:
+ fprintf(fd,"%s to %s not supported.<P>%c", r->method,
+ r->uri, LF);
+ break;
+ }
+
+ if (recursive_error) {
+ fprintf (fd, "Additionally, an error of type %d was encountered%c",
+ recursive_error, LF);
+ fprintf (fd, "while trying to use an ErrorDocument to%c", LF);
+ fprintf (fd, "handle the request.%c", LF);
+ }
+ fprintf (fd, "</BODY>%c", LF);
+ }
+
+}
+
+/* Finally, this... it's here to support nph- scripts
+ * Now what ever are we going to do about them when HTTP-NG packetization
+ * comes along?
+ */
+
+void client_to_stdout (conn_rec *c)
+{
+ fflush (c->client);
+ dup2 (fileno (c->client), STDOUT_FILENO);
+}
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_request.c: functions to get and process requests
+ *
+ * Rob McCool 3/21/93
+ *
+ * Thoroughly revamped by rst for Shambhala. NB this file reads
+ * best from the bottom up.
+ *
+ */
+
+#define CORE_PRIVATE
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+
+/*****************************************************************
+ *
+ * Getting and checking directory configuration. Also checks the
+ * FollowSymlinks and FollowSymOwner stuff, since this is really the
+ * only place that can happen (barring a new mid_dir_walk callout).
+ *
+ * We can't do it as an access_checker module function which gets
+ * called with the final per_dir_config, since we could have a directory
+ * with FollowSymLinks disabled, which contains a symlink to another
+ * with a .htaccess file which turns FollowSymLinks back on --- and
+ * access in such a case must be denied. So, whatever it is that
+ * checks FollowSymLinks needs to know the state of the options as
+ * they change, all the way down.
+ */
+
+int check_symlinks (char *d, int opts)
+{
+ struct stat lfi, fi;
+ char *lastp;
+ int res;
+
+ if (opts & OPT_SYM_LINKS) return OK;
+
+ /* Strip trailing '/', if any, off what we're checking; trailing
+ * slashes make some systems follow symlinks to directories even in
+ * lstat(). After we've done the lstat, put it back. Also, don't
+ * bother checking '/' at all...
+ *
+ * Note that we don't have to worry about multiple slashes here
+ * because of no2slash() below...
+ */
+
+ lastp = d + strlen(d) - 1;
+ if (lastp == d) return OK; /* Root directory, '/' */
+
+ if (*lastp == '/') *lastp = '\0';
+ else lastp = NULL;
+
+ res = lstat (d, &lfi);
+
+ if (lastp) *lastp = '/';
+
+ /* Note that we don't reject accesses to nonexistent files (multiviews
+ * or the like may cons up a way to run the transaction anyway)...
+ */
+
+ if (!(res >= 0) || !S_ISLNK(lfi.st_mode)) return OK;
+
+ /* OK, it's a symlink. May still be OK with OPT_SYM_OWNER */
+
+ if (!(opts & OPT_SYM_OWNER)) return FORBIDDEN;
+
+ if (stat (d, &fi) < 0) return FORBIDDEN;
+
+ return (fi.st_uid == lfi.st_uid) ? OK : FORBIDDEN;
+}
+
+/* Dealing with the file system to get PATH_INFO
+ */
+
+void get_path_info(request_rec *r)
+{
+ char *cp;
+ char *path = r->filename;
+ char *end = &path[strlen(path)];
+ char *last_cp = NULL;
+ int rv;
+
+ /* Advance over trailing slashes ... NOT part of filename */
+
+ for (cp = end; cp > path && cp[-1] == '/'; --cp)
+ continue;
+
+ while (cp > path) {
+
+ /* See if the pathname ending here exists... */
+
+ *cp = '\0';
+ rv = stat(path, &r->finfo);
+ if (cp != end) *cp = '/';
+
+ if (!rv) {
+
+ /* Aha! Found something. If it was a directory, we will
+ * search contents of that directory for a multi_match, so
+ * the PATH_INFO argument starts with the component after that.
+ */
+
+ if (S_ISDIR(r->finfo.st_mode) && last_cp) {
+ r->finfo.st_mode = 0; /* No such file... */
+ cp = last_cp;
+ }
+
+ r->path_info = pstrdup (r->pool, cp);
+ *cp = '\0';
+ return;
+ }
+ else {
+ last_cp = cp;
+
+ while (--cp > path && *cp != '/')
+ continue;
+
+ while (cp > path && cp[-1] == '/')
+ --cp;
+ }
+ }
+}
+
+int directory_walk (request_rec *r)
+{
+ core_server_config *sconf = get_module_config (r->server->module_config,
+ &core_module);
+ array_header *sec_array = copy_array (r->pool, sconf->sec);
+
+ core_dir_config **sec = (core_dir_config **)sec_array->elts;
+ int num_sec = sec_array->nelts;
+ void *per_dir_defaults = r->server->lookup_defaults;
+ char *test_filename = pstrdup (r->pool, r->filename);
+
+ int num_dirs, res;
+ int i;
+
+ /* Go down the directory hierarchy. Where we have to check for symlinks,
+ * do so. Where a .htaccess file has permission to override anything,
+ * try to find one. If either of these things fails, we could poke
+ * around, see why, and adjust the lookup_rec accordingly --- this might
+ * save us a call to get_path_info (with the attendant stat()s); however,
+ * for the moment, that's not worth the trouble.
+ */
+
+ no2slash (test_filename);
+ num_dirs = count_dirs(test_filename);
+ get_path_info (r);
+
+ if (S_ISDIR (r->finfo.st_mode)) ++num_dirs;
+
+ for (i = 1; i <= num_dirs; ++i) {
+ core_dir_config *core_dir =
+ (core_dir_config *)get_module_config(per_dir_defaults, &core_module);
+ int allowed_here = core_dir->opts;
+ int overrides_here = core_dir->override;
+ void *this_conf = NULL, *htaccess_conf = NULL;
+ char *this_dir = make_dirstr (r->pool, test_filename, i);
+ char *config_name = make_full_path(r->pool, this_dir,
+ sconf->access_name);
+ int j;
+
+ /* Do symlink checks first, because they are done with the
+ * permissions appropriate to the *parent* directory...
+ */
+
+ if ((res = check_symlinks (this_dir, allowed_here)))
+ {
+ log_reason("Symbolic link not allowed", this_dir, r);
+ return res;
+ }
+
+ /* Begin *this* level by looking for matching <Directory> sections from
+ * access.conf.
+ */
+
+ for (j = 0; j < num_sec; ++j) {
+ void *entry_config = sec[j];
+ core_dir_config *entry_core;
+ char *entry_dir;
+
+ if (!entry_config) continue;
+
+ entry_core =
+ (core_dir_config *)get_module_config(entry_config, &core_module);
+ entry_dir = entry_core->d;
+
+ if (is_matchexp(entry_dir) && !strcmp_match(this_dir, entry_dir)) {
+ /* Don't try this wildcard again --- if it ends in '*'
+ * it'll match again, and subdirectories won't be able to
+ * override it...
+ */
+ sec[j] = NULL;
+ this_conf = entry_config;
+ }
+ else if (!strcmp (this_dir, entry_dir))
+ this_conf = entry_config;
+ }
+
+ if (this_conf)
+ {
+ per_dir_defaults =
+ merge_per_dir_configs (r->pool, per_dir_defaults, this_conf);
+ core_dir =(core_dir_config *)get_module_config(per_dir_defaults,
+ &core_module);
+ }
+ overrides_here = core_dir->override;
+
+ /* If .htaccess files are enabled, check for one.
+ */
+
+ if (overrides_here) {
+ res = parse_htaccess (&htaccess_conf, r, overrides_here,
+ this_dir, config_name);
+ if (res) return res;
+ }
+
+ if (htaccess_conf)
+ per_dir_defaults =
+ merge_per_dir_configs (r->pool, per_dir_defaults,
+ htaccess_conf);
+
+ }
+
+ r->per_dir_config = per_dir_defaults;
+
+ if ((res = check_symlinks (r->filename, allow_options(r))))
+ {
+ log_reason("Symbolic link not allowed", r->filename, r);
+ return res;
+ }
+
+ return OK; /* Can only "fail" if access denied
+ * by the symlink goop.
+ */
+}
+
+/*****************************************************************
+ *
+ * The sub_request mechanism.
+ *
+ * Fns to look up a relative URI from, e.g., a map file or SSI document.
+ * These do all access checks, etc., but don't actually run the transaction
+ * ... use run_sub_req below for that. Also, be sure to use destroy_sub_req
+ * as appropriate if you're likely to be creating more than a few of these.
+ * (An early Shambhala version didn't destroy the sub_reqs used in directory
+ * indexing. The result, when indexing a directory with 800-odd files in
+ * it, was massively excessive storage allocation).
+ *
+ * Note more manipulation of protocol-specific vars in the request
+ * structure...
+ */
+
+request_rec *make_sub_request (request_rec *r)
+{
+ pool *rrp = make_sub_pool (r->pool);
+ request_rec *rr = pcalloc (rrp, sizeof (request_rec));
+
+ rr->pool = rrp;
+ return rr;
+}
+
+request_rec *sub_req_lookup_simple (char *new_file, request_rec *r)
+{
+ /* This handles the simple case, common to ..._lookup_uri and _file,
+ * of looking up another file in the same directory.
+ */
+ request_rec *rnew = make_sub_request (r);
+ pool *rnewp = rnew->pool;
+ int res;
+
+ char *udir = make_dirstr(rnewp, r->uri, count_dirs(r->uri));
+ char *fdir = make_dirstr(rnewp, r->filename, count_dirs(r->filename));
+
+ *rnew = *r; /* Copy per_dir config, etc. */
+ rnew->pool = rnewp;
+ rnew->uri = make_full_path (rnewp, udir, new_file);
+ rnew->filename = make_full_path (rnewp, fdir, new_file);
+ set_sub_req_protocol (rnew, r);
+
+ rnew->finfo.st_mode = 0;
+
+ if ((res = check_symlinks (rnew->filename, allow_options (rnew))))
+ {
+ rnew->status = res;
+ }
+
+ if (rnew->finfo.st_mode == 0 && stat (rnew->filename, &rnew->finfo) < 0)
+ rnew->finfo.st_mode = 0;
+
+ if ((rnew->status == 200) && (res = find_types (rnew)))
+ rnew->status = res;
+
+ if ((rnew->status == 200) && (res = run_fixups (rnew)))
+ rnew->status = res;
+
+ return rnew;
+}
+
+request_rec *sub_req_lookup_uri (char *new_file, request_rec *r)
+{
+ request_rec *rnew;
+ int res;
+ char *udir;
+
+ rnew = make_sub_request (r);
+ rnew->connection = r->connection;
+ rnew->server = r->server;
+ rnew->request_config = create_request_config (rnew->pool);
+ set_sub_req_protocol (rnew, r);
+
+ if (new_file[0] == '/')
+ parse_uri(rnew, new_file);
+ else
+ {
+ udir = make_dirstr (rnew->pool, r->uri, count_dirs (r->uri));
+ udir = escape_uri(rnew->pool, udir); /* re-escape it */
+ parse_uri (rnew, make_full_path (rnew->pool, udir, new_file));
+ }
+
+ res = unescape_url (rnew->uri);
+ if (res)
+ {
+ rnew->status = res;
+ return rnew;
+ }
+
+ getparents (rnew->uri);
+
+ res = translate_name(rnew);
+ if (res)
+ {
+ rnew->status = res;
+ return rnew;
+ }
+
+ /* We could be clever at this point, and avoid calling directory_walk, etc.
+ * However, we'd need to test that the old and new filenames contain the
+ * same directory components, so it would require duplicating the start
+ * of translate_name.
+ * Maybe it would be easier to implement a cache for directory and
+ * .htaccess stats, or perhaps pass the old request to translate_name()
+ * for it to do the optimisation.
+ */
+
+ if ((res = directory_walk (rnew))
+ || (!auth_type (rnew) ? 0 :
+ ((res = check_user_id (rnew)) || (res = check_auth (rnew))))
+ || (res = check_access (rnew))
+ || (res = find_types (rnew))
+ || (res = run_fixups (rnew))
+ )
+ {
+ rnew->status = res;
+ }
+
+ return rnew;
+}
+
+request_rec *sub_req_lookup_file (char *new_file, request_rec *r)
+{
+ request_rec *rnew;
+ int res;
+ char *fdir;
+
+ /* Check for a special case... if there are no '/' characters in new_file
+ * at all, then we are looking at a relative lookup in the same directory.
+ * That means we don't have to redo any access checks.
+ */
+
+ if (strchr (new_file, '/') == NULL)
+ return sub_req_lookup_simple (new_file, r);
+
+ rnew = make_sub_request (r);
+ fdir = make_dirstr (rnew->pool, r->filename, count_dirs (r->filename));
+
+ rnew->connection = r->connection; /* For now... */
+ rnew->server = r->server;
+ rnew->request_config = create_request_config (rnew->pool);
+ set_sub_req_protocol (rnew, r);
+
+ rnew->uri = "INTERNALLY GENERATED file-relative req";
+ rnew->filename = ((new_file[0] == '/') ?
+ new_file :
+ make_full_path (rnew->pool, fdir, new_file));
+
+ if ((res = directory_walk (rnew))
+ || (res = check_access (rnew))
+ || (!auth_type (rnew) ? 0 :
+ ((res = check_user_id (rnew)) && (res = check_auth (rnew))))
+ || (res = find_types (rnew))
+ || (res = run_fixups (rnew))
+ )
+ {
+ rnew->status = res;
+ }
+
+ return rnew;
+}
+
+int run_sub_req (request_rec *r)
+{
+ int retval = invoke_handler (r);
+ finalize_sub_req_protocol (r);
+ return retval;
+}
+
+void destroy_sub_req (request_rec *r)
+{
+ /* Reclaim the space */
+ destroy_pool (r->pool);
+}
+
+/*****************************************************************
+ *
+ * Mainline request processing...
+ */
+
+void die(int type, request_rec *r)
+{
+ int error_index = index_of_response (type);
+ char *custom_response = response_code_string(r, error_index);
+ int recursive_error = 0;
+
+ /* The following takes care of Apache redirects to custom response URLs
+ * Note that if we are already dealing with the response to some other
+ * error condition, we just report on the original error, and give up on
+ * any attempt to handle the other thing "intelligently"...
+ */
+
+ if (r->status != 200) {
+ recursive_error = type;
+
+ while (r->prev && r->prev->status != 200)
+ r = r->prev; /* Get back to original error */
+
+ type = r->status;
+ custom_response = NULL; /* Do NOT retry the custom thing! */
+ }
+
+ r->status = type;
+
+ /* Two types of custom redirects --- plain text, and URLs.
+ * Plain text has a leading '"', so the URL code, here, is triggered
+ * on its absence
+ */
+
+ if (custom_response && custom_response[0] != '"') {
+
+ if (is_url(custom_response)) {
+ /* The URL isn't local, so lets drop through the rest of
+ * this apache code, and continue with the usual REDIRECT
+ * handler. But note that the client will ultimately see
+ * the wrong status...
+ */
+ r->status = REDIRECT;
+ table_set (r->headers_out, "Location", custom_response);
+ } else if ( custom_response[0] == '/') {
+ r->no_cache = 1; /* Do NOT send USE_LOCAL_COPY for
+ * error documents!
+ */
+ internal_redirect (custom_response, r);
+ return;
+ } else {
+ /* Dumb user has given us a bad url to redirect to
+ * --- fake up dying with a recursive server error...
+ */
+ recursive_error = SERVER_ERROR;
+ log_reason("Invalid error redirection directive", custom_response,
+ r);
+ }
+ }
+
+ send_error_response (r, recursive_error);
+}
+
+static void decl_die (int status, char *phase, request_rec *r)
+{
+ if (status == DECLINED) {
+ log_reason (pstrcat (r->pool,
+ "configuration error: couldn't ",
+ phase, NULL),
+ r->uri,
+ r);
+ die (SERVER_ERROR, r);
+ }
+ else die (status, r);
+}
+
+void process_request_internal (request_rec *r)
+{
+ int access_status;
+
+ /* Kludge to be reading the assbackwards field outside of protocol.c,
+ * but we've got to check for this sort of nonsense somewhere...
+ */
+
+ if (r->assbackwards && r->header_only) {
+ /* Client asked for headers only with HTTP/0.9, which doesn't
+ * send headers! Have to dink things even to make sure the
+ * error message comes through...
+ */
+ log_reason ("client sent illegal HTTP/0.9 request", r->uri, r);
+ r->header_only = 0;
+ die (BAD_REQUEST, r);
+ return;
+ }
+
+ access_status = unescape_url(r->uri);
+ if (access_status)
+ {
+ die(access_status, r);
+ return;
+ }
+
+ getparents(r->uri); /* OK --- shrinking transformations... */
+
+ if ((access_status = translate_name (r))) {
+ decl_die (access_status, "translate", r);
+ return;
+ }
+
+ if ((access_status = directory_walk (r))) {
+ die (access_status, r);
+ return;
+ }
+
+ if ((access_status = check_access (r)) != 0) {
+ decl_die (access_status, "check access", r);
+ return;
+ }
+
+ if (auth_type (r)) {
+ if ((access_status = check_user_id (r)) != 0) {
+ decl_die (access_status, "check user. No user file?", r);
+ return;
+ }
+
+ if ((access_status = check_auth (r)) != 0) {
+ decl_die (access_status, "check access. No groups file?", r);
+ return;
+ }
+ }
+
+ if ((access_status = find_types (r)) != 0) {
+ decl_die (access_status, "find types", r);
+ return;
+ }
+
+ if ((access_status = run_fixups (r)) != 0) {
+ die (access_status, r);
+ return;
+ }
+
+ if ((access_status = invoke_handler (r)) != 0)
+ die (access_status, r);
+}
+
+void process_request (request_rec *r)
+{
+ process_request_internal (r);
+ log_transaction (r);
+}
+
+table *rename_original_env (pool *p, table *t)
+{
+ array_header *env_arr = table_elts (t);
+ table_entry *elts = (table_entry *)env_arr->elts;
+ table *new = make_table (p, env_arr->nelts);
+ int i;
+
+ for (i = 0; i < env_arr->nelts; ++i) {
+ if (!elts[i].key) continue;
+ table_set (new, pstrcat (p, "REDIRECT_", elts[i].key, NULL),
+ elts[i].val);
+ }
+
+ return new;
+}
+
+void internal_redirect (char *new_uri, request_rec *r)
+{
+ request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec));
+ char t[10]; /* Long enough... */
+
+ new->connection = r->connection;
+ new->server = r->server;
+ new->pool = r->pool;
+
+ /* A whole lot of this really ought to be shared with protocol.c...
+ * another missing cleanup. It's particularly inappropriate to be
+ * setting header_only, etc., here.
+ */
+
+ parse_uri (new, new_uri);
+ new->request_config = create_request_config (r->pool);
+ new->per_dir_config = r->server->lookup_defaults;
+
+ new->prev = r;
+ r->next = new;
+
+ /* We are redirecting. Treat the internally generated transaction
+ * as a GET, since there is not a chance of its getting POST-style
+ * arguments.
+ */
+ new->method = "GET";
+ new->method_number = M_GET;
+
+ /* Inherit the rest of the protocol info... */
+
+ new->status = r->status;
+ new->assbackwards = r->assbackwards;
+ new->header_only = r->header_only;
+ new->protocol = r->protocol;
+ new->main = r->main;
+
+ new->headers_in = r->headers_in;
+ new->headers_out = make_table (r->pool, 5);
+ new->err_headers_out = r->err_headers_out;
+ new->subprocess_env = rename_original_env (r->pool, r->subprocess_env);
+ new->notes = make_table (r->pool, 5);
+
+ new->no_cache = r->no_cache; /* If we've already made up our minds
+ * about this, don't change 'em back!
+ */
+
+ sprintf (t, "%d", r->status);
+ table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t));
+
+ process_request_internal (new);
+}
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * str.c: string utility things
+ *
+ * 3/21/93 Rob McCool
+ *
+ */
+
+
+#include "httpd.h"
+#include "http_conf_globals.h" /* for user_id & group_id */
+#ifdef QNX
+#include <time.h>
+#endif
+
+#ifdef NOTDEF
+extern char** environ;
+
+/* taken from bdflush-1.5 for Linux source code */
+void inststr(char *dst[], int argc, char *src)
+{
+ if (strlen(src) <= strlen(dst[0]))
+ {
+ char *ptr;
+
+ for (ptr = dst[0]; *ptr; *(ptr++) = '\0');
+
+ strcpy(dst[0], src);
+ } else
+ {
+ /* stolen from the source to perl 4.036 (assigning to $0) */
+ char *ptr, *ptr2;
+ int count;
+ ptr = dst[0] + strlen(dst[0]);
+ for (count = 1; count < argc; count++) {
+ if (dst[count] == ptr + 1)
+ ptr += strlen(++ptr);
+ }
+ if (environ[0] == ptr + 1) {
+ for (count = 0; environ[count]; count++)
+ if (environ[count] == ptr + 1)
+ ptr += strlen(++ptr);
+ }
+ count = 0;
+ for (ptr2 = dst[0]; ptr2 <= ptr; ptr2++) {
+ *ptr2 = '\0';
+ count++;
+ }
+ strncpy(dst[0], src, count);
+ }
+}
+#endif
+
+char *get_time() {
+ time_t t;
+ char *time_string;
+
+ t=time(NULL);
+ time_string = ctime(&t);
+ time_string[strlen(time_string) - 1] = '\0';
+ return (time_string);
+}
+
+char *ht_time(pool *p, time_t t, char *fmt, int gmt) {
+ char ts[MAX_STRING_LEN];
+ struct tm *tms;
+
+ tms = (gmt ? gmtime(&t) : localtime(&t));
+
+ /* check return code? */
+ strftime(ts,MAX_STRING_LEN,fmt,tms);
+ return pstrdup (p, ts);
+}
+
+char *gm_timestr_822(pool *p, time_t sec) {
+ return ht_time(p, sec, HTTP_TIME_FORMAT, 1);
+}
+
+/* What a pain in the ass. */
+struct tm *get_gmtoff(long *tz) {
+ time_t tt;
+ struct tm *t;
+
+ tt = time(NULL);
+ t = localtime(&tt);
+#if defined(HAS_GMTOFF)
+ *tz = t->tm_gmtoff;
+#else
+ *tz = - timezone;
+ if(t->tm_isdst)
+ *tz += 3600;
+#endif
+ return t;
+}
+
+
+/* Match = 0, NoMatch = 1, Abort = -1 */
+/* Based loosely on sections of wildmat.c by Rich Salz
+ * Hmmm... shouldn't this really go component by component?
+ */
+int strcmp_match(char *str, char *exp) {
+ int x,y;
+
+ for(x=0,y=0;exp[y];++y,++x) {
+ if((!str[x]) && (exp[y] != '*'))
+ return -1;
+ if(exp[y] == '*') {
+ while(exp[++y] == '*');
+ if(!exp[y])
+ return 0;
+ while(str[x]) {
+ int ret;
+ if((ret = strcmp_match(&str[x++],&exp[y])) != 1)
+ return ret;
+ }
+ return -1;
+ } else
+ if((exp[y] != '?') && (str[x] != exp[y]))
+ return 1;
+ }
+ return (str[x] != '\0');
+}
+
+int is_matchexp(char *str) {
+ register int x;
+
+ for(x=0;str[x];x++)
+ if((str[x] == '*') || (str[x] == '?'))
+ return 1;
+ return 0;
+}
+
+/*
+ * Parse .. so we don't compromise security
+ */
+void getparents(char *name)
+{
+ int l, w;
+
+ /* Four paseses, as per RFC 1808 */
+ /* a) remove ./ path segments */
+
+ for (l=0, w=0; name[l] != '\0';)
+ {
+ if (name[l] == '.' && name[l+1] == '/' && (l == 0 || name[l-1] == '/'))
+ l += 2;
+ else
+ name[w++] = name[l++];
+ }
+
+ /* b) remove trailing . path, segment */
+ if (w == 1 && name[0] == '.') w--;
+ else if (w > 1 && name[w-1] == '.' && name[w-2] == '/') w--;
+ name[w] = '\0';
+
+ /* c) remove all xx/../ segments. (including leading ../ and /../) */
+ l = 0;
+
+ while(name[l]!='\0') {
+ if(name[l] == '.' && name[l+1] == '.' && name[l+2] == '/' &&
+ (l == 0 || name[l-1] == '/')) {
+ register int m=l+3,n;
+
+ l=l-2;
+ if(l>=0) {
+ while(l >= 0 && name[l] != '/') l--;
+ l++;
+ }
+ else l=0;
+ n=l;
+ while((name[n]=name[m])) (++n,++m);
+ }
+ else ++l;
+ }
+
+ /* d) remove trailing xx/.. segment. */
+ if (l == 2 && name[0] == '.' && name[1] == '.') name[0] = '\0';
+ else if (l > 2 && name[l-1] == '.' && name[l-2] == '.' && name[l-3] == '/')
+ {
+ l = l - 4;
+ if (l >= 0)
+ {
+ while (l >= 0 && name[l] != '/') l--;
+ l++;
+ }
+ else l = 0;
+ name[l] = '\0';
+ }
+}
+
+void no2slash(char *name) {
+ register int x,y;
+
+ for(x=0; name[x];)
+ if(x && (name[x-1] == '/') && (name[x] == '/'))
+ for(y=x+1;name[y-1];y++)
+ name[y-1] = name[y];
+ else x++;
+}
+
+char *make_dirstr(pool *p, char *s, int n) {
+ register int x,f;
+ char *res;
+
+ for(x=0,f=0;s[x];x++) {
+ if(s[x] == '/')
+ if((++f) == n) {
+ res = palloc(p, x + 2);
+ strncpy (res, s, x);
+ res[x] = '/';
+ res[x+1] = '\0';
+ return res;
+ }
+ }
+
+ if (s[strlen(s) - 1] == '/')
+ return pstrdup (p, s);
+ else
+ return pstrcat (p, s, "/", NULL);
+}
+
+int count_dirs(char *path) {
+ register int x,n;
+
+ for(x=0,n=0;path[x];x++)
+ if(path[x] == '/') n++;
+ return n;
+}
+
+
+void chdir_file(char *file) {
+ int i;
+
+ if((i = rind(file,'/')) == -1)
+ return;
+ file[i] = '\0';
+ chdir(file);
+ file[i] = '/';
+}
+
+char *getword(pool* atrans, char **line, char stop) {
+ int pos = ind(*line, stop);
+ char *res;
+
+ if (pos == -1) {
+ res = pstrdup (atrans, *line);
+ *line += strlen (*line);
+ return res;
+ }
+
+ res = palloc(atrans, pos + 1);
+ strncpy (res, *line, pos);
+ res[pos] = '\0';
+
+ while ((*line)[pos] == stop) ++pos;
+
+ *line += pos;
+
+ return res;
+}
+
+/* Get a word, (new) config-file style --- quoted strings and backslashes
+ * all honored
+ */
+
+char *substring_conf (pool *p, char *start, int len)
+{
+ char *result = palloc (p, len + 2);
+ char *resp = result;
+ int i;
+
+ for (i = 0; i < len; ++i) {
+ if (start[i] == '\\')
+ *resp++ = start[++i];
+ else
+ *resp++ = start[i];
+ }
+
+ *resp++ = '\0';
+ return result;
+}
+
+char *getword_conf(pool* p, char **line) {
+ char *str = *line, *strend, *res;
+ char quote;
+
+ while (*str && isspace (*str))
+ ++str;
+
+ if (!*str) {
+ *line = str;
+ return "";
+ }
+
+ if ((quote = *str) == '"' || quote == '\'') {
+ strend = str + 1;
+ while (*strend && *strend != quote) {
+ if (*strend == '\\' && strend[1]) strend += 2;
+ else ++strend;
+ }
+ res = substring_conf (p, str + 1, strend - str - 1);
+
+ if (*strend == quote) ++strend;
+ } else {
+ strend = str;
+ while (*strend && !isspace (*strend))
+ if (*strend == '\\' && strend[1]) strend += 2;
+ else ++strend;
+
+ res = substring_conf (p, str, strend - str);
+ }
+
+ while (*strend && isspace(*strend)) ++ strend;
+ *line = strend;
+ return res;
+}
+
+void cfg_getword(char *word, char *line) {
+ int x=0,y;
+
+ for(x=0;line[x] && isspace(line[x]);x++);
+ y=0;
+ while(1) {
+ if(!(word[y] = line[x]))
+ break;
+ if(isspace(line[x]))
+ if((!x) || (line[x-1] != '\\'))
+ break;
+ if(line[x] != '\\') ++y;
+ ++x;
+ }
+ word[y] = '\0';
+ while(line[x] && isspace(line[x])) ++x;
+ for(y=0;(line[y] = line[x]);++x,++y);
+}
+
+int
+cfg_getline(char *s, int n, FILE *f) {
+ register int i=0, c;
+
+ s[0] = '\0';
+ /* skip leading whitespace */
+ do {
+ c = getc(f);
+ } while (c == '\t' || c == ' ');
+
+ while(1) {
+ if((c == '\t') || (c == ' ')) {
+ s[i++] = ' ';
+ while((c == '\t') || (c == ' '))
+ c = getc(f);
+ }
+ if(c == CR) {
+ c = getc(f);
+ }
+ if(c == EOF || c == 0x4 || c == LF || i == (n-1)) {
+ /* blast trailing whitespace */
+ while(i && (s[i-1] == ' ')) --i;
+ s[i] = '\0';
+ return (feof(f) ? 1 : 0);
+ }
+ s[i] = c;
+ ++i;
+ c = getc(f);
+ }
+}
+
+char *escape_shell_cmd(pool *p, char *s) {
+ register int x,y,l;
+ char *cmd;
+
+ l=strlen(s);
+ cmd = palloc (p, 2 * l + 1); /* Be safe */
+ strcpy (cmd, s);
+
+ for(x=0;cmd[x];x++) {
+ if(ind("&;`'\"|*?~<>^()[]{}$\\",cmd[x]) != -1){
+ for(y=l+1;y>x;y--)
+ cmd[y] = cmd[y-1];
+ l++; /* length has been increased */
+ cmd[x] = '\\';
+ x++; /* skip the character */
+ }
+ }
+
+ return cmd;
+}
+
+void plustospace(char *str) {
+ register int x;
+
+ for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
+}
+
+void spacetoplus(char *str) {
+ register int x;
+
+ for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+';
+}
+
+char x2c(char *what) {
+ register char digit;
+
+ digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
+ digit *= 16;
+ digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
+ return(digit);
+}
+
+/*
+ * Unescapes a URL.
+ * Returns 0 on success, non-zero on error
+ * Failure is due to
+ * bad % escape returns BAD_REQUEST
+ *
+ * decoding %00 -> \0
+ * decoding %2f -> / (a special character)
+ * returns NOT_FOUND
+ */
+int
+unescape_url(char *url) {
+ register int x,y, badesc, badpath;
+
+ badesc = 0;
+ badpath = 0;
+ for(x=0,y=0;url[y];++x,++y) {
+ if (url[y] != '%') url[x] = url[y];
+ else
+ {
+ if (!isxdigit(url[y+1]) || !isxdigit(url[y+2]))
+ {
+ badesc = 1;
+ url[x] = '%';
+ } else
+ {
+ url[x] = x2c(&url[y+1]);
+ y += 2;
+ if (url[x] == '/' || url[x] == '\0') badpath = 1;
+ }
+ }
+ }
+ url[x] = '\0';
+ if (badesc) return BAD_REQUEST;
+ else if (badpath) return NOT_FOUND;
+ else return OK;
+}
+
+char *construct_url(pool *p, char *uri, server_rec *s) {
+ char portnum[10]; /* Long enough. Really! */
+
+ if (s->port == 80) {
+ return pstrcat (p, "http://", s->server_hostname, uri, NULL);
+ } else {
+ sprintf (portnum, "%d", s->port);
+ return pstrcat (p, "http://", s->server_hostname, ":", portnum, uri,
+ NULL);
+ }
+}
+
+#define c2x(what,where) sprintf(where,"%%%02x",what)
+
+/*
+escape_path_segment() escapes a path segment, as defined in RFC 1808. This
+routine is (should be) OS independent.
+
+os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
+cases if a ':' occurs before the first '/' in the URL, the URL should be
+prefixed with "./" (or the ':' escaped). In the case of Unix, this means
+leaving '/' alone, but otherwise doing what escape_path_segment() does. For
+efficiency reasons, we don't use escape_path_segment(), which is provided for
+reference. Again, RFC 1808 is where this stuff is defined.
+*/
+
+char *escape_path_segment(pool *p, const char *segment) {
+ register int x,y;
+ char *copy = palloc (p, 3 * strlen (segment) + 1);
+
+ for(x=0,y=0; segment[x]; x++,y++) {
+ char c=segment[x];
+ if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9')
+ && ind("$-_.+!*'(),:@&=~",c) == -1)
+ {
+ c2x(c,©[y]);
+ y+=2;
+ }
+ else
+ copy[y]=c;
+ }
+ copy[y] = '\0';
+ return copy;
+}
+
+char *os_escape_path(pool *p,const char *path) {
+ char *copy=palloc(p,3*strlen(path)+3);
+ char *s=copy;
+ int colon=ind(path,':');
+ int slash=ind(path,'/');
+
+ if(colon >= 0 && (colon < slash || slash < 0))
+ {
+ *s++='.';
+ *s++='/';
+ }
+ for( ; *path ; ++path)
+ {
+ char c=*path;
+ if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9')
+ && ind("$-_.+!*'(),:@&=/~",c) == -1)
+ {
+ c2x(c,s);
+ s+=3;
+ }
+ else
+ *s++=c;
+ }
+ *s='\0';
+ return copy;
+}
+
+char *escape_uri(pool *p, char *uri) {
+ register int x,y;
+ char *copy = palloc (p, 3 * strlen (uri) + 1);
+
+ for(x=0,y=0; uri[x]; x++,y++) {
+ if (ind (":% ?+&",(copy[y] = uri[x])) != -1) {
+ c2x(uri[x],©[y]);
+ y+=2;
+ }
+ }
+ copy[y] = '\0';
+ return copy;
+}
+
+#ifdef NOTDEF
+
+void escape_url(char *url) {
+ register int x,y;
+ register char digit;
+ char *copy;
+
+ copy = strdup(url);
+
+ for(x=0,y=0;copy[x];x++,y++) {
+ if(ind("% ?+&",url[y] = copy[x]) != -1) {
+ c2x(copy[x],&url[y]);
+ y+=2;
+ }
+ }
+ url[y] = '\0';
+ free(copy);
+}
+
+#endif
+
+int is_directory(char *path) {
+ struct stat finfo;
+
+ if(stat(path,&finfo) == -1)
+ return 0; /* in error condition, just return no */
+
+ return(S_ISDIR(finfo.st_mode));
+}
+
+char *make_full_path(pool *a, char *src1,char *src2) {
+ register int x;
+
+ x = strlen(src1);
+ if (x == 0) return pstrcat (a, "/", src2, NULL);
+
+ if (src1[x - 1] != '/') return pstrcat (a, src1, "/", src2, NULL);
+ else return pstrcat (a, src1, src2, NULL);
+}
+
+int is_url(char *u) {
+ register int x;
+
+ for(x=0;u[x] != ':';x++)
+ if((!u[x]) || (!isalpha(u[x])))
+ return 0;
+
+ if((u[x+1] == '/') && (u[x+2] == '/'))
+ return 1;
+ else return 0;
+}
+
+int can_exec(struct stat *finfo) {
+ if(user_id == finfo->st_uid)
+ if(finfo->st_mode & S_IXUSR)
+ return 1;
+ if(group_id == finfo->st_gid)
+ if(finfo->st_mode & S_IXGRP)
+ return 1;
+ return (finfo->st_mode & S_IXOTH);
+}
+
+#ifdef NEED_STRDUP
+char *strdup (char *str)
+{
+ char *dup;
+
+ if(!(dup = (char *)malloc (strlen (str) + 1)))
+ return NULL;
+ dup = strcpy (dup, str);
+
+ return dup;
+}
+#endif
+
+/* The following two routines were donated for SVR4 by Andreas Vogel */
+#ifdef NEED_STRCASECMP
+int strcasecmp (const char *a, const char *b)
+{
+ const char *p = a;
+ const char *q = b;
+ for (p = a, q = b; *p && *q; p++, q++)
+ {
+ int diff = tolower(*p) - tolower(*q);
+ if (diff) return diff;
+ }
+ if (*p) return 1; /* p was longer than q */
+ if (*q) return -1; /* p was shorter than q */
+ return 0; /* Exact match */
+}
+
+#endif
+
+#ifdef NEED_STRNCASECMP
+int strncasecmp (const char *a, const char *b, int n)
+{
+ const char *p = a;
+ const char *q = b;
+
+ for (p = a, q = b; /*NOTHING*/; p++, q++)
+ {
+ int diff;
+ if (p == a + n) return 0; /* Match up to n characters */
+ if (!(*p && *q)) return *p - *q;
+ diff = tolower(*p) - tolower(*q);
+ if (diff) return diff;
+ }
+ /*NOTREACHED*/
+}
+#endif
+
+
+
+#ifdef NEED_INITGROUPS
+int initgroups(const char *name, gid_t basegid)
+{
+#ifdef QNX
+/* QNX does not appear to support supplementary groups.
+Ben <ben@algroup.co.uk> */
+ return 0;
+#else /* ndef QNX */
+ gid_t groups[NGROUPS_MAX];
+ struct group *g;
+ int index = 0;
+
+ groups[index++] = basegid;
+
+ while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
+ if (g->gr_gid != basegid)
+ {
+ char **names;
+
+ for (names = g->gr_mem; *names != NULL; ++names)
+ if (!strcmp(*names, name))
+ groups[index++] = g->gr_gid;
+ }
+
+ return setgroups(index, groups);
+#endif /* def QNX */
+}
+#endif /* def NEED_INITGROUPS */
+
+#ifdef NEED_WAITPID
+/* From ikluft@amdahl.com */
+/* this is not ideal but it works for SVR3 variants */
+/* httpd does not use the options so this doesn't implement them */
+int waitpid(pid_t pid, int *statusp, int options)
+{
+ int tmp_pid;
+ if ( kill ( pid,0 ) == -1) {
+ errno=ECHILD;
+ return -1;
+ }
+ while ((( tmp_pid = wait(statusp)) != pid) && ( tmp_pid != -1 ));
+ return tmp_pid;
+}
+#endif
+
+int ind(const char *s, char c) {
+ register int x;
+
+ for(x=0;s[x];x++)
+ if(s[x] == c) return x;
+
+ return -1;
+}
+
+int rind(const char *s, char c) {
+ register int x;
+
+ for(x=strlen(s)-1;x != -1;x--)
+ if(s[x] == c) return x;
+
+ return -1;
+}
+
+void str_tolower(char *str) {
+ while(*str) {
+ *str = tolower(*str);
+ ++str;
+ }
+}
+
+uid_t uname2id(char *name) {
+ struct passwd *ent;
+
+ if(name[0] == '#')
+ return(atoi(&name[1]));
+
+ if(!(ent = getpwnam(name))) {
+ fprintf(stderr,"httpd: bad user name %s\n",name);
+ exit(1);
+ }
+ else return(ent->pw_uid);
+}
+
+gid_t gname2id(char *name) {
+ struct group *ent;
+
+ if(name[0] == '#')
+ return(atoi(&name[1]));
+
+ if(!(ent = getgrnam(name))) {
+ fprintf(stderr,"httpd: bad group name %s\n",name);
+ exit(1);
+ }
+ else return(ent->gr_gid);
+}
+
+#if 0
+int get_portnum(int sd) {
+ struct sockaddr addr;
+ int len;
+
+ len = sizeof(struct sockaddr);
+ if(getsockname(sd,&addr,&len) < 0)
+ return -1;
+ return ntohs(((struct sockaddr_in *)&addr)->sin_port);
+}
+
+struct in_addr get_local_addr(int sd) {
+ struct sockaddr addr;
+ int len;
+
+ len = sizeof(struct sockaddr);
+ if(getsockname(sd,&addr,&len) < 0) {
+ fprintf (stderr, "Can't get local host address!\n");
+ perror ("getsockname");
+ exit(1);
+ }
+
+ return ((struct sockaddr_in *)&addr)->sin_addr;
+}
+#endif
+
+unsigned long get_virthost_addr (char *w, int wild_allowed) {
+ struct hostent *hep;
+ unsigned long my_addr;
+
+ if (wild_allowed && !strcmp(w, "*"))
+ return htonl(INADDR_ANY);
+
+ my_addr = inet_addr(w);
+ if (my_addr != ((unsigned long) 0xffffffff))
+ return my_addr;
+
+ hep = gethostbyname(w);
+
+ if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
+ fprintf (stderr, "Cannot resolve host name %s --- exiting!\n", w);
+ exit(1);
+ }
+
+ if (hep->h_addr_list[1]) {
+ fprintf(stderr, "Host %s has multiple addresses ---\n", w);
+ fprintf(stderr, "you must choose one explicitly for use as\n");
+ fprintf(stderr, "a virtual host. Exiting!!!\n");
+ exit(1);
+ }
+
+ return ((struct in_addr *)(hep->h_addr))->s_addr;
+}
+
+#ifdef DEBUG_ACCESS
+/* Host name and IP address used if getpeername() fails.
+ * The most frequent cause of this is running the server in inetd-mode
+ * with the tty as input and output, under the debugger.
+ */
+#define NO_SUCH_HOST_NAME "volterra.ai.mit.edu"
+#define NO_SUCH_HOST_ADDR "128.52.39.173"
+#else
+#define NO_SUCH_HOST_NAME "UNKNOWN_HOST"
+#define NO_SUCH_HOST_ADDR "UNKNOWN_IP"
+#endif
+
+void get_remote_host(conn_rec *conn)
+{
+ struct sockaddr addr;
+ int len;
+ struct in_addr *iaddr;
+#if defined(MAXIMUM_DNS) || !defined(MINIMAL_DNS)
+ struct hostent *hptr;
+#endif
+
+ len = sizeof(struct sockaddr);
+
+ if ((getpeername(fileno(conn->client), &addr, &len)) < 0) {
+ conn->remote_name = conn->remote_host = NO_SUCH_HOST_NAME;
+ conn->remote_ip = NO_SUCH_HOST_ADDR;
+ return;
+ }
+
+ iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
+#ifndef MINIMAL_DNS
+ hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET);
+ if(hptr) {
+ conn->remote_host = pstrdup(conn->pool, (void *)hptr->h_name);
+ conn->remote_name = conn->remote_host;
+ str_tolower (conn->remote_host);
+ }
+ else
+#endif
+ conn->remote_host = NULL;
+
+#ifdef MAXIMUM_DNS
+ /* Grrr. Check THAT name to make sure it's really the name of the addr. */
+ /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
+ if (conn->remote_host) {
+ char **haddr;
+
+ hptr = gethostbyname(conn->remote_host);
+ if (hptr) {
+ for(haddr=hptr->h_addr_list;*haddr;haddr++) {
+ if(((struct in_addr *)(*haddr))->s_addr == iaddr->s_addr)
+ break;
+ }
+ }
+ if((!hptr) || (!(*haddr)))
+ conn->remote_host = conn->remote_name = NULL;
+ }
+#endif
+ conn->remote_ip = pstrdup (conn->pool, inet_ntoa(*iaddr));
+ if(!conn->remote_host){
+ conn->remote_name = conn->remote_ip;
+ }
+ if (!conn->remote_name) {
+ conn->remote_name = "UNKNOWN_HOST";
+ }
+}
+
+#ifdef NOTDEF
+
+char *get_remote_logname(FILE *fd) {
+ int len;
+ char *result;
+#if defined(NEXT) || defined(BSD4_4) || defined(SOLARIS2) || defined(LINUX)
+ struct sockaddr sa_server, sa_client;
+#else
+ struct sockaddr_in sa_server,sa_client;
+#endif
+
+ len = sizeof(sa_client);
+ if(getpeername(fileno(stdout),&sa_client,&len) != -1) {
+ len = sizeof(sa_server);
+ if(getsockname(fileno(stdout),&sa_server,&len) == -1)
+ result = "unknown";
+ else
+ result = rfc931((struct sockaddr_in *) & sa_client,
+ (struct sockaddr_in *) & sa_server);
+ }
+ else result = "unknown";
+
+ return result; /* robm=pinhead */
+}
+#endif
+
+static char *find_fqdn(pool *a, struct hostent *p) {
+ int x;
+
+ if(ind(p->h_name,'.') == -1) {
+ for(x=0;p->h_aliases[x];++x) {
+ if((ind(p->h_aliases[x],'.') != -1) &&
+ (!strncmp(p->h_aliases[x],p->h_name,strlen(p->h_name))))
+ return pstrdup(a, p->h_aliases[x]);
+ }
+ return NULL;
+ } else return pstrdup(a, (void *)p->h_name);
+}
+
+char *get_local_host(pool *a)
+{
+ char str[128];
+ int len = 128;
+ char *server_hostname;
+
+ struct hostent *p;
+ gethostname(str, len);
+ if((!(p=gethostbyname(str))) || (!(server_hostname = find_fqdn(a, p)))) {
+ fprintf(stderr,"httpd: cannot determine local host name.\n");
+ fprintf(stderr,"Use ServerName to set it manually.\n");
+ exit(1);
+ }
+
+ return server_hostname;
+}
+
+/* aaaack but it's fast and const should make it shared text page. */
+const int pr2six[256]={
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
+ 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,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,64,64,64,64,64,64,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,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64
+};
+
+char *uudecode(pool *p, char *bufcoded) {
+ int nbytesdecoded;
+ register unsigned char *bufin;
+ register char *bufplain;
+ register unsigned char *bufout;
+ register int nprbytes;
+
+ /* Strip leading whitespace. */
+
+ while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
+
+ /* Figure out how many characters are in the input buffer.
+ * Allocate this many from the per-transaction pool for the result.
+ */
+ bufin = (unsigned char *)bufcoded;
+ while(pr2six[*(bufin++)] <= 63);
+ nprbytes = (char *)bufin - bufcoded - 1;
+ nbytesdecoded = ((nprbytes+3)/4) * 3;
+
+ bufplain = palloc(p, nbytesdecoded + 1);
+ bufout = (unsigned char *)bufplain;
+
+ bufin = (unsigned char *)bufcoded;
+
+ while (nprbytes > 0) {
+ *(bufout++) =
+ (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
+ *(bufout++) =
+ (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
+ *(bufout++) =
+ (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
+ bufin += 4;
+ nprbytes -= 4;
+ }
+
+ if(nprbytes & 03) {
+ if(pr2six[bufin[-2]] > 63)
+ nbytesdecoded -= 2;
+ else
+ nbytesdecoded -= 1;
+ }
+ bufplain[nbytesdecoded] = '\0';
+ return bufplain;
+}
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+#include "httpd.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "http_core.h" /* For document_root. Sigh... */
+#include "util_script.h"
+
+/*
+ * Various utility functions which are common to a whole lot of
+ * script-type extensions mechanisms, and might as well be gathered
+ * in one place (if only to avoid creating inter-module dependancies
+ * where there don't have to be).
+ */
+
+char **create_argv(pool *p, char *av0, char *args) {
+ register int x,n;
+ char **av;
+ char *w;
+
+ for(x=0,n=2;args[x];x++)
+ if(args[x] == '+') ++n;
+
+ av = (char **)palloc(p, (n+1)*sizeof(char *));
+ av[0] = av0;
+
+ for(x=1;x<n;x++) {
+ w = getword(p, &args, '+');
+ unescape_url(w);
+ av[x] = escape_shell_cmd(p, w);
+ }
+ av[n] = NULL;
+ return av;
+}
+
+static char *http2env(pool *a, char *w)
+{
+ char *res = pstrcat (a, "HTTP_", w, NULL);
+ char *cp = res;
+
+ while (*++cp)
+ if (*cp == '-') *cp = '_';
+ else *cp = toupper(*cp);
+
+ return res;
+}
+
+char **create_environment(pool *p, table *t)
+{
+ array_header *env_arr = table_elts (t);
+ table_entry *elts = (table_entry *)env_arr->elts;
+ char **env = (char **)palloc (p, (env_arr->nelts + 2) *sizeof (char *));
+ int i, j;
+ char *tz;
+
+ j = 0;
+ tz = getenv("TZ");
+ if (tz!= NULL) env[j++] = pstrcat(p, "TZ=", tz, NULL);
+ for (i = 0; i < env_arr->nelts; ++i) {
+ if (!elts[i].key) continue;
+ env[j++] = pstrcat (p, elts[i].key, "=", elts[i].val, NULL);
+ }
+
+ env[j] = NULL;
+ return env;
+}
+
+void add_common_vars(request_rec *r)
+{
+ table *e = r->subprocess_env;
+ server_rec *s = r->server;
+ conn_rec *c = r->connection;
+
+ char port[40],*env_path;
+
+ array_header *hdrs_arr = table_elts (r->headers_in);
+ table_entry *hdrs = (table_entry *)hdrs_arr->elts;
+ int i;
+
+ /* First, add environment vars from headers... this is as per
+ * CGI specs, though other sorts of scripting interfaces see
+ * the same vars...
+ */
+
+ for (i = 0; i < hdrs_arr->nelts; ++i) {
+ if (!hdrs[i].key) continue;
+
+ /* A few headers are special cased --- Authorization to prevent
+ * rogue scripts from capturing passwords; content-type and -length
+ * for no particular reason.
+ */
+
+ if (!strcasecmp (hdrs[i].key, "Content-type"))
+ table_set (e, "CONTENT_TYPE", hdrs[i].val);
+ else if (!strcasecmp (hdrs[i].key, "Content-length"))
+ table_set (e, "CONTENT_LENGTH", hdrs[i].val);
+ else if (!strcasecmp (hdrs[i].key, "Authorization"))
+ continue;
+ else
+ table_set (e, http2env (r->pool, hdrs[i].key), hdrs[i].val);
+ }
+
+ sprintf(port, "%d", s->port);
+
+ if(!(env_path = getenv("PATH")))
+ env_path=DEFAULT_PATH;
+
+ table_set (e, "PATH", env_path);
+ table_set (e, "SERVER_SOFTWARE", SERVER_VERSION);
+ table_set (e, "SERVER_NAME", s->server_hostname);
+ table_set (e, "SERVER_PORT", port);
+ table_set (e, "REMOTE_HOST", c->remote_name);
+ table_set (e, "REMOTE_ADDR", c->remote_ip);
+ table_set (e, "DOCUMENT_ROOT", document_root(r)); /* Apache */
+ table_set (e, "SERVER_ADMIN", s->server_admin); /* Apache */
+ table_set (e, "SCRIPT_FILENAME", r->filename); /* Shambhala */
+
+ if (c->user) table_set(e, "REMOTE_USER", c->user);
+ if (c->auth_type) table_set(e, "AUTH_TYPE", c->auth_type);
+ if (c->remote_logname) table_set(e, "REMOTE_IDENT", c->remote_logname);
+
+ /* Apache custom error responses. If we have redirected set two new vars */
+
+ if (r->prev) {
+ if (r->prev->args) table_set(e,"REDIRECT_QUERY_STRING", r->prev->args);
+ if (r->prev->uri) table_set (e, "REDIRECT_URL", r->prev->uri);
+ }
+}
+
+int scan_script_header(request_rec *r, FILE *f)
+{
+ char w[MAX_STRING_LEN];
+ char *l;
+ int p;
+
+ hard_timeout ("read script header", r);
+
+ while(1) {
+
+ if (fgets(w, MAX_STRING_LEN-1, f) == NULL) {
+ log_reason ("malformed header from script", r->filename, r);
+ return SERVER_ERROR;
+ }
+
+ /* Delete terminal (CR?)LF */
+
+ p = strlen(w);
+ if (p > 0 && w[p-1] == '\n')
+ {
+ if (p > 1 && w[p-2] == '\015') w[p-2] = '\0';
+ else w[p-1] = '\0';
+ }
+
+ if(w[0] == '\0') {
+ kill_timeout (r);
+ return OK;
+ }
+
+ /* if we see a bogus header don't ignore it. Shout and scream */
+
+ if(!(l = strchr(w,':'))) {
+ /* Soak up all the script output --- may save an outright kill */
+ while (fgets(w, MAX_STRING_LEN-1, f) != NULL)
+ continue;
+
+ kill_timeout (r);
+ log_reason ("malformed header from script", r->filename, r);
+ return SERVER_ERROR;
+ }
+
+ *l++ = '\0';
+ while (*l && isspace (*l)) ++l;
+
+ if(!strcasecmp(w,"Content-type")) {
+
+ /* Nuke trailing whitespace */
+
+ char *endp = l + strlen(l) - 1;
+ while (endp > l && isspace(*endp)) *endp-- = '\0';
+
+ r->content_type = pstrdup (r->pool, l);
+ }
+ else if(!strcasecmp(w,"Status")) {
+ sscanf(l, "%d", &r->status);
+ r->status_line = pstrdup(r->pool, l);
+ }
+ else {
+ table_set (r->headers_out, w, l);
+ }
+ }
+}
+
+void send_size(size_t size, request_rec *r) {
+ if(size == -1)
+ rprintf (r, " -");
+ else if(!size)
+ rprintf (r, " 0K");
+ else if(size < 1024)
+ rprintf(r, " 1K");
+ else if(size < 1048576)
+ rprintf(r, "%4dK", size / 1024);
+ else
+ rprintf(r, "%4dM", size / 1048576);
+}
+
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+
+/* Why are you even thinking about using this? */
+
+int ai_backcompat_kludge (request_rec *r)
+{
+ if (r->method_number != M_GET ||
+ (r->args && r->args[0]) || (r->path_info && r->path_info[0]))
+ {
+ char *doit_filename = pstrcat (r->pool, r->filename, ".doit", NULL);
+ struct stat finfo;
+
+ if (stat (doit_filename, &finfo) >= 0) {
+ r->filename = doit_filename;
+ r->finfo = finfo;
+ }
+ }
+
+ return DECLINED;
+}
+
+module ai_backcompat_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ NULL, /* command table */
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ ai_backcompat_kludge, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/* Netscape Cookies Fixup
+ *
+ * This is a module for Shambhala for handling Netscape cookies.
+ *
+ * On each request look for a Cookie: header.
+ * If we don't find one then send a Set-Cookie: header out with the request
+ * Future requests from the same client should keep the same Cookie line.
+ * Using the cookie log you can track the path a user takes through your
+ * files.
+ *
+ * The cookie and request are logged to a file. Use the directive
+ * "CookieLog somefilename" in one of the config files to enable.
+ *
+ * Netscape 1.0+ is the only known browser to support cookies. This
+ * code is lazy and doesn't bother creating cookies for other browsers.
+ *
+ * Mark Cox, mark@telescope.org, 6 July 95
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include <sys/time.h>
+
+module cookies_module;
+
+/* Now we have to generate something that is going to be
+ * pretty unique. We can base it on the pid, time, hostip */
+
+void make_cookie(request_rec *r)
+{
+ struct timeval tv;
+ char new_cookie[100]; /* blurgh */
+ char *dot;
+ char *rname = pstrdup(r->pool,r->connection->remote_name);
+ struct timezone tz = { 0 , 0 };
+
+ if ((dot = strchr(rname,'.'))) *dot='\0'; /* First bit of hostname */
+ gettimeofday(&tv, &tz);
+ sprintf(new_cookie,"s=%s%d%ld%d; path=/",
+ rname,
+ (int)getpid(),
+ (long)tv.tv_sec, (int)tv.tv_usec/1000 );
+
+ table_set(r->headers_out,"Set-Cookie",new_cookie);
+ return;
+}
+
+int spot_cookie(request_rec *r)
+{
+ char *cookie, *agent;
+
+ if (!(agent = table_get(r->headers_in,"User-Agent")))
+ return DECLINED; /* No user-agent = No cookie */
+ if (strncmp(agent,"Mozilla",7)) /* Don't bother creating a cookie */
+ return DECLINED; /* unless browser is Netscape fudge */
+ if ((cookie = table_get (r->headers_in, "Cookie")))
+ return DECLINED; /* Theres already a cookie, no new one */
+ make_cookie(r);
+ return OK; /* We set our cookie */
+}
+
+static int cookie_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+static mode_t cookie_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+
+typedef struct {
+ char *fname;
+ int log_fd;
+} cookie_log_state;
+
+void *make_cookie_log_state (pool *p, server_rec *s)
+{
+ cookie_log_state *cls =
+ (cookie_log_state *)palloc (p, sizeof (cookie_log_state));
+
+ cls->fname = "";
+ cls->log_fd = -1;
+
+ return (void *)cls;
+}
+
+char *set_cookie_log (cmd_parms *parms, void *dummy, char *arg)
+{
+ cookie_log_state *cls = get_module_config (parms->server->module_config,
+ &cookies_module);
+ cls->fname = arg;
+ return NULL;
+}
+
+command_rec cookie_log_cmds[] = {
+{ "CookieLog", set_cookie_log, NULL, RSRC_CONF, TAKE1,
+ "the filename of the cookie log" },
+{ NULL }
+};
+
+void open_cookie_log (server_rec *s, pool *p)
+{
+ cookie_log_state *cls = get_module_config (s->module_config,
+ &cookies_module);
+ char *fname = server_root_relative (p, cls->fname);
+
+ if (cls->log_fd > 0) return;
+ cls->log_fd = popenf(p, fname, cookie_flags, cookie_mode);
+}
+
+void init_cookie_log (server_rec *s, pool *p)
+{
+ for (; s; s = s->next) open_cookie_log (s, p);
+}
+
+int cookie_log_transaction(request_rec *orig)
+{
+ cookie_log_state *cls = get_module_config (orig->server->module_config,
+ &cookies_module);
+ char str[HUGE_STRING_LEN];
+ long timz;
+ struct tm *t;
+ char tstr[MAX_STRING_LEN],sign;
+ request_rec *r;
+ char *cookie;
+
+ for (r = orig; r->next; r = r->next)
+ continue;
+ if ((cls->log_fd)<0) /* Don't log cookies */
+ return DECLINED;
+
+ if (!(cookie = table_get (r->headers_in, "Cookie")))
+ return DECLINED; /* Theres no cookie, don't bother logging */
+ if (strncmp(cookie,"s=",2)) /* Only log cookies we generated! */
+ return DECLINED;
+ t = get_gmtoff(&timz);
+ sign = (timz < 0 ? '-' : '+');
+ if(timz < 0)
+ timz = -timz;
+
+ strftime(tstr,MAX_STRING_LEN,"%d/%b/%Y:%H:%M:%S",t);
+
+ sprintf(str,"%s \"%s\" [%s %c%02ld%02ld] ",
+ cookie+2, /* Ignore s= */
+ orig->the_request,
+ tstr,
+ sign,
+ timz/3600,
+ timz%3600);
+
+ if (r->status != -1)
+ sprintf(str,"%s%d\n",str,r->status);
+ else
+ strcat(str,"-\n");
+
+ write(cls->log_fd, str, strlen(str));
+
+ return OK;
+}
+
+
+module cookies_module = {
+ STANDARD_MODULE_STUFF,
+ init_cookie_log, /* initializer */
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ make_cookie_log_state, /* server config */
+ NULL, /* merge server configs */
+ cookie_log_cmds, /* command table */
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ spot_cookie, /* fixups */
+ cookie_log_transaction, /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+#include "httpd.h"
+#include "http_config.h"
+
+module common_log_module;
+
+static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+
+typedef struct {
+ char *fname;
+ int log_fd;
+} common_log_state;
+
+void *make_common_log_state (pool *p, server_rec *s)
+{
+ common_log_state *cls =
+ (common_log_state *)palloc (p, sizeof (common_log_state));
+
+ cls->fname = DEFAULT_XFERLOG;
+ cls->log_fd = -1;
+
+ return (void *)cls;
+}
+
+char *set_common_log (cmd_parms *parms, void *dummy, char *arg)
+{
+ common_log_state *cls = get_module_config (parms->server->module_config,
+ &common_log_module);
+
+ cls->fname = arg;
+ return NULL;
+}
+
+command_rec common_log_cmds[] = {
+{ "TransferLog", set_common_log, NULL, RSRC_CONF, TAKE1,
+ "the filename of the access log" },
+{ NULL }
+};
+
+void common_log_child (void *cmd)
+{
+ /* Child process code for 'TransferLog "|..."';
+ * may want a common framework for this, since I expect it will
+ * be common for other foo-loggers to want this sort of thing...
+ */
+
+ cleanup_for_exec();
+ signal (SIGHUP, SIG_IGN);
+ execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+ fprintf (stderr, "Exec of shell for logging failed!!!\n");
+ exit (1);
+}
+
+void open_common_log (server_rec *s, pool *p)
+{
+ common_log_state *cls = get_module_config (s->module_config,
+ &common_log_module);
+
+ char *fname = server_root_relative (p, cls->fname);
+
+ if (cls->log_fd > 0) return; /* virtual log shared w/main server */
+
+ if (*cls->fname == '|') {
+ FILE *dummy;
+
+ spawn_child(p, common_log_child, (void *)(cls->fname+1),
+ kill_after_timeout, &dummy, NULL);
+
+ if (dummy == NULL) {
+ fprintf (stderr, "Couldn't fork child for TransferLog process\n");
+ exit (1);
+ }
+
+ cls->log_fd = fileno (dummy);
+ }
+ else if((cls->log_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
+ fprintf(stderr,"httpd: could not open transfer log file %s.\n", fname);
+ perror("open");
+ exit(1);
+ }
+}
+
+void init_common_log (server_rec *s, pool *p)
+{
+ for (; s; s = s->next) open_common_log (s, p);
+}
+
+int common_log_transaction(request_rec *orig)
+{
+ common_log_state *cls = get_module_config (orig->server->module_config,
+ &common_log_module);
+
+ char str[HUGE_STRING_LEN];
+ long timz;
+ struct tm *t;
+ char tstr[MAX_STRING_LEN],sign;
+ conn_rec *c = orig->connection;
+ request_rec *r;
+
+ /* Common log format records an unholy melange of the original request
+ * and whatever it was that we actually served. Just stay compatible
+ * here; the whole point of the module scheme is to allow people to
+ * create better alternatives, but screwing up is an option we wish
+ * to preserve...
+ */
+
+ for (r = orig; r->next; r = r->next)
+ continue;
+
+ t = get_gmtoff(&timz);
+ sign = (timz < 0 ? '-' : '+');
+ if(timz < 0)
+ timz = -timz;
+
+ strftime(tstr,MAX_STRING_LEN,"%d/%b/%Y:%H:%M:%S",t);
+
+ sprintf(str,"%s %s %s [%s %c%02ld%02ld] \"%s\" ",
+ c->remote_name,
+ (c->remote_logname ? c->remote_logname : "-"),
+ (c->user ? c->user : "-"),
+ tstr,
+ sign,
+ timz/3600,
+ timz%3600,
+ (orig->the_request ? orig->the_request : "NULL") );
+
+ if (r->status != -1)
+ sprintf(str,"%s%d ",str,r->status);
+ else
+ strcat(str,"- ");
+
+ if(r->bytes_sent != -1)
+ sprintf(str,"%s%d\n",str,r->bytes_sent);
+ else
+ strcat(str,"-\n");
+
+ write(cls->log_fd, str, strlen(str));
+
+ return OK;
+}
+
+module common_log_module = {
+ STANDARD_MODULE_STUFF,
+ init_common_log, /* initializer */
+ NULL, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ make_common_log_state, /* server config */
+ NULL, /* merge server config */
+ common_log_cmds, /* command table */
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ common_log_transaction /* logger */
+};
--- /dev/null
+#include "httpd.h"
+#include "http_config.h"
+
+/*
+ * This file just tells the core what other modules have been compiled
+ * in, so it knows to go out and configure them. Someday, it might be
+ * automatically generated from a config file which is intelligible to
+ * J. Random Sysadmin...
+ */
+
+extern module core_module;
+extern module mime_module;
+extern module access_module;
+extern module alias_module;
+extern module auth_module;
+extern module dbm_auth_module;
+extern module negotiation_module;
+extern module userdir_module;
+extern module cgi_module;
+extern module includes_module;
+extern module dir_module;
+extern module common_log_module;
+extern module asis_module;
+#ifdef DLD
+extern module dld_module;
+#endif
+
+module *prelinked_modules[] = {
+ &core_module,
+ &mime_module,
+ &access_module,
+ &auth_module,
+ &dbm_auth_module,
+ &negotiation_module,
+ &includes_module,
+ &dir_module,
+ &cgi_module,
+ &userdir_module,
+ &alias_module,
+ &common_log_module,
+ &asis_module,
+#ifdef DLD
+ &dld_module,
+#endif
+ NULL,
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Security options etc.
+ *
+ * Module derived from code originally written by Rob McCool
+ *
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+
+typedef struct {
+ char *from;
+ int limited;
+} allowdeny;
+
+/* things in the 'order' array */
+#define DENY_THEN_ALLOW 0
+#define ALLOW_THEN_DENY 1
+#define MUTUAL_FAILURE 2
+
+typedef struct {
+ int order[METHODS];
+ array_header *allows;
+ array_header *denys;
+} access_dir_conf;
+
+module access_module;
+
+void *create_access_dir_config (pool *p, char *dummy)
+{
+ access_dir_conf *conf =
+ (access_dir_conf *)pcalloc(p, sizeof(access_dir_conf));
+ int i;
+
+ for (i = 0; i < METHODS; ++i) conf->order[i] = DENY_THEN_ALLOW;
+ conf->allows = make_array (p, 1, sizeof (allowdeny));
+ conf->denys = make_array (p, 1, sizeof (allowdeny));
+
+ return (void *)conf;
+}
+
+char *order (cmd_parms *cmd, void *dv, char *arg)
+{
+ access_dir_conf *d = (access_dir_conf *)dv;
+ int i, order;
+
+ if (!strcasecmp (arg, "allow,deny")) order = ALLOW_THEN_DENY;
+ else if (!strcasecmp (arg, "deny,allow")) order = DENY_THEN_ALLOW;
+ else if (!strcasecmp (arg, "mutual-failure")) order = MUTUAL_FAILURE;
+ else return "unknown order";
+
+ for (i = 0; i < METHODS; ++i)
+ if (cmd->limited & (1 << i))
+ d->order[i] = order;
+
+ return NULL;
+}
+
+char *allow_cmd (cmd_parms *cmd, void *dv, char *from, char *where)
+{
+ access_dir_conf *d = (access_dir_conf *)dv;
+ allowdeny *a;
+
+ if (strcasecmp (from, "from"))
+ return "allow and deny must be followed by 'from'";
+
+ a = (allowdeny *)push_array (cmd->info ? d->allows : d->denys);
+ a->from = pstrdup (cmd->pool, where);
+ a->limited = cmd->limited;
+ return NULL;
+}
+
+static char its_an_allow;
+
+command_rec access_cmds[] = {
+{ "order", order, NULL, OR_LIMIT, TAKE1,
+ "'allow,deny', 'deny,allow', or 'mutual-failure'" },
+{ "allow", allow_cmd, &its_an_allow, OR_LIMIT, ITERATE2,
+ "'from' followed by hostnames or IP-address wildcards" },
+{ "deny", allow_cmd, NULL, OR_LIMIT, ITERATE2,
+ "'from' followed by hostnames or IP-address wildcards" },
+{NULL}
+};
+
+int in_domain(char *domain, char *what) {
+ int dl=strlen(domain);
+ int wl=strlen(what);
+
+ if((wl-dl) >= 0) {
+ if (strcmp(domain,&what[wl-dl]) != 0) return 0;
+
+ /* Make sure we matched an *entire* subdomain --- if the user
+ * said 'allow from good.com', we don't want people from nogood.com
+ * to be able to get in.
+ */
+
+ if (wl == dl) return 1; /* matched whole thing */
+ else return (domain[0] == '.' || what[wl - dl - 1] == '.');
+ } else
+ return 0;
+}
+
+int in_ip(char *domain, char *what) {
+
+ /* Check a similar screw case to the one checked above ---
+ * "allow from 204.26.2" shouldn't let in people from 204.26.23
+ */
+
+ int l = strlen(domain);
+ if (strncmp(domain,what,l) != 0) return 0;
+ if (domain[l - 1] == '.') return 1;
+ return (what[l] == '\0' || what[l] == '.');
+}
+
+int find_allowdeny (conn_rec *c, array_header *a, int method)
+{
+ allowdeny *ap = (allowdeny *)a->elts;
+ int mmask = (1 << method);
+ int i;
+
+ for (i = 0; i < a->nelts; ++i) {
+ if (!(mmask & ap[i].limited))
+ continue;
+ if (!strcmp (ap[i].from, "all"))
+ return 1;
+ if (c->remote_host && isalpha(c->remote_host[0]))
+ if (in_domain(ap[i].from, c->remote_host))
+ return 1;
+ if (in_ip (ap[i].from, c->remote_ip))
+ return 1;
+ }
+
+ return 0;
+}
+
+int check_dir_access (request_rec *r)
+{
+ int method = r->method_number;
+ access_dir_conf *a =
+ (access_dir_conf *)
+ get_module_config (r->per_dir_config, &access_module);
+ int ret = OK;
+
+ conn_rec *c = r->connection;
+
+ if (a->order[method] == ALLOW_THEN_DENY) {
+ ret = FORBIDDEN;
+ if (find_allowdeny (c, a->allows, method))
+ ret = OK;
+ if (find_allowdeny (c, a->denys, method))
+ ret = FORBIDDEN;
+ } else if (a->order[method] == DENY_THEN_ALLOW) {
+ if (find_allowdeny (c, a->denys, method))
+ ret = FORBIDDEN;
+ if (find_allowdeny (c, a->allows, method))
+ ret = OK;
+ }
+ else {
+ if (find_allowdeny(c, a->allows, method)
+ && !find_allowdeny(c, a->denys, method))
+ ret = OK;
+ else
+ ret = FORBIDDEN;
+ }
+
+ if (ret == FORBIDDEN)
+ log_reason ("Client denied by server configuration", r->filename, r);
+
+ return ret;
+}
+
+
+
+module access_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ create_access_dir_config, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ access_cmds,
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ check_dir_access, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_alias.c: Stuff for dealing with directory aliases
+ *
+ * Original by Rob McCool, rewritten in succession by David Robinson
+ * and rst.
+ *
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+
+typedef struct {
+ char *real;
+ char *fake;
+ char *forced_type;
+} alias_entry;
+
+typedef struct {
+ array_header *aliases;
+ array_header *redirects;
+} alias_server_conf;
+
+module alias_module;
+
+void *create_alias_config (pool *p, server_rec *s)
+{
+ alias_server_conf *a =
+ (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf));
+
+ a->aliases = make_array (p, 20, sizeof(alias_entry));
+ a->redirects = make_array (p, 20, sizeof(alias_entry));
+ return a;
+}
+
+void *merge_alias_config (pool *p, void *basev, void *overridesv)
+{
+ alias_server_conf *a =
+ (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf));
+ alias_server_conf *base = (alias_server_conf *)basev,
+ *overrides = (alias_server_conf *)overridesv;
+
+ a->aliases = append_arrays (p, overrides->aliases, base->aliases);
+ a->redirects = append_arrays (p, overrides->redirects, base->redirects);
+ return a;
+}
+
+char *add_alias(cmd_parms *cmd, void *dummy, char *f, char *r)
+{
+ server_rec *s = cmd->server;
+ alias_server_conf *conf =
+ (alias_server_conf *)get_module_config(s->module_config,&alias_module);
+ alias_entry *new = push_array (conf->aliases);
+
+ /* XX r can NOT be relative to DocumentRoot here... compat bug. */
+
+ new->fake = f; new->real = r; new->forced_type = cmd->info;
+ return NULL;
+}
+
+char *add_redirect(cmd_parms *cmd, void *dummy, char *f, char *url)
+{
+ server_rec *s = cmd->server;
+ alias_server_conf *conf =
+ (alias_server_conf *)get_module_config(s->module_config,&alias_module);
+ alias_entry *new = push_array (conf->redirects);
+
+ if (!is_url (url)) return "Redirect to non-URL";
+
+ new->fake = f; new->real = url;
+ return NULL;
+}
+
+command_rec alias_cmds[] = {
+{ "Alias", add_alias, NULL, RSRC_CONF, TAKE2,
+ "a fakename and a realname"},
+{ "ScriptAlias", add_alias, CGI_MAGIC_TYPE, RSRC_CONF, TAKE2,
+ "a fakename and a realname"},
+{ "Redirect", add_redirect, NULL, RSRC_CONF, TAKE2,
+ "a document to be redirected, then the destination URL" },
+{ NULL }
+};
+
+int alias_matches (char *uri, char *alias_fakename)
+{
+ char *end_fakename = alias_fakename + strlen (alias_fakename);
+ char *aliasp = alias_fakename, *urip = uri;
+
+ while (aliasp < end_fakename) {
+ if (*aliasp == '/') {
+ /* any number of '/' in the alias matches any number in
+ * the supplied URI, but there must be at least one...
+ */
+ if (*urip != '/') return 0;
+
+ while (*aliasp == '/') ++ aliasp;
+ while (*urip == '/') ++ urip;
+ }
+ else {
+ /* Other characters are compared literally */
+ if (*urip++ != *aliasp++) return 0;
+ }
+ }
+
+ /* Check last alias path component matched all the way */
+
+ if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
+ return 0;
+
+ /* Return number of characters from URI which matched (may be
+ * greater than length of alias, since we may have matched
+ * doubled slashes)
+ */
+
+ return urip - uri;
+}
+
+char *try_alias_list (request_rec *r, array_header *aliases, int doesc)
+{
+ alias_entry *entries = (alias_entry *)aliases->elts;
+ int i;
+
+ for (i = 0; i < aliases->nelts; ++i) {
+ alias_entry *p = &entries[i];
+ int l = alias_matches (r->uri, p->fake);
+
+ if (l > 0) {
+ if (p->forced_type)
+ table_set (r->notes, "alias-forced-type", p->forced_type);
+
+ if (doesc) {
+ char *escurl;
+ /* would like to use os_escape_path here, but can't */
+ escurl = escape_uri(r->pool, r->uri + l);
+ return pstrcat(r->pool, p->real, escurl, NULL);
+ } else
+ return pstrcat(r->pool, p->real, r->uri + l, NULL);
+ }
+ }
+
+ return NULL;
+}
+
+int translate_alias_redir(request_rec *r)
+{
+ void *sconf = r->server->module_config;
+ alias_server_conf *conf =
+ (alias_server_conf *)get_module_config(sconf, &alias_module);
+ char *ret;
+
+ if (r->uri[0] != '/' && r->uri[0] != '\0')
+ return BAD_REQUEST;
+
+ if ((ret = try_alias_list (r, conf->redirects, 1)) != NULL) {
+ table_set (r->headers_out, "Location", ret);
+ return REDIRECT;
+ }
+
+ if ((ret = try_alias_list (r, conf->aliases, 0)) != NULL) {
+ r->filename = ret;
+ return OK;
+ }
+
+ return DECLINED;
+}
+
+int type_forced_alias (request_rec *r)
+{
+ char *t = table_get (r->notes, "alias-forced-type");
+ if (!t) return DECLINED;
+ r->content_type = t;
+ return OK;
+}
+
+module alias_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ create_alias_config, /* server config */
+ merge_alias_config, /* merge server configs */
+ alias_cmds, /* command table */
+ NULL, /* handlers */
+ translate_alias_redir, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ type_forced_alias, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "util_script.h"
+#include "http_main.h"
+
+int asis_handler (request_rec *r)
+{
+ FILE *f;
+
+ if (r->method_number != M_GET) return DECLINED;
+ if (r->finfo.st_mode == 0) {
+ log_reason("File does not exist", r->filename, r);
+ return NOT_FOUND;
+ }
+
+ f = fopen (r->filename, "r");
+
+ if (f == NULL) {
+ log_reason("file permissions deny server access", r->filename, r);
+ return FORBIDDEN;
+ }
+
+ scan_script_header (r, f);
+
+ soft_timeout ("send", r);
+ send_http_header (r);
+ if (!r->header_only) send_fd (f, r);
+ fclose (f);
+ return OK;
+}
+
+handler_rec asis_handlers[] = {
+{ ASIS_MAGIC_TYPE, asis_handler },
+{ NULL }
+};
+
+module asis_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ NULL, /* command table */
+ asis_handlers, /* handlers */
+ NULL, /* translate_handler */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* pre-run fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_auth: authentication
+ *
+ * Rob McCool
+ *
+ * Adapted to Shambhala by rst.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+
+typedef struct auth_config_struct {
+ char *auth_pwfile;
+ char *auth_grpfile;
+} auth_config_rec;
+
+void *create_auth_dir_config (pool *p, char *d)
+{
+ return pcalloc (p, sizeof(auth_config_rec));
+}
+
+command_rec auth_cmds[] = {
+{ "AuthUserFile", set_string_slot,
+ (void*)XtOffsetOf(auth_config_rec,auth_pwfile), OR_AUTHCFG, TAKE1, NULL },
+{ "AuthGroupFile", set_string_slot,
+ (void*)XtOffsetOf(auth_config_rec,auth_grpfile), OR_AUTHCFG, TAKE1, NULL },
+{ NULL }
+};
+
+module auth_module;
+
+char *get_pw(request_rec *r, char *user, char *auth_pwfile)
+{
+ FILE *f;
+ char l[MAX_STRING_LEN];
+ char *rpw, *w;
+
+ if(!(f=pfopen(r->pool, auth_pwfile, "r"))) {
+ log_reason ("Could not open password file", auth_pwfile, r);
+ return NULL;
+ }
+ while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
+ if((l[0] == '#') || (!l[0])) continue;
+ rpw = l;
+ w = getword(r->pool, &rpw, ':');
+
+ if(!strcmp(user,w)) {
+ pfclose(r->pool, f);
+ return pstrdup (r->pool, rpw);
+ }
+ }
+ pfclose(r->pool, f);
+ return NULL;
+}
+
+table *groups_for_user (pool *p, char *user, char *grpfile) {
+ FILE *f;
+ table *grps = make_table (p, 15);
+ pool *sp;
+ char l[MAX_STRING_LEN];
+ char *group_name, *ll, *w;
+
+ if(!(f=pfopen(p, grpfile, "r")))
+ return NULL;
+
+ sp = make_sub_pool (p);
+
+ while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
+ if((l[0] == '#') || (!l[0])) continue;
+ ll = l;
+ clear_pool (sp);
+
+ group_name = getword(sp, &ll, ':');
+
+ while(ll[0]) {
+ w = getword_conf (sp, &ll);
+ if(!strcmp(w,user)) {
+ table_set (grps, group_name, "in");
+ break;
+ }
+ }
+ }
+ pfclose(p, f);
+ destroy_pool (sp);
+ return grps;
+}
+
+/* These functions return 0 if client is OK, and proper error status
+ * if not... either AUTH_REQUIRED, if we made a check, and it failed, or
+ * SERVER_ERROR, if things are so totally confused that we couldn't
+ * figure out how to tell if the client is authorized or not.
+ *
+ * If they return DECLINED, and all other modules also decline, that's
+ * treated by the server core as a configuration error, logged and
+ * reported as such.
+ */
+
+/* Determine user ID, and check if it really is that user, for HTTP
+ * basic authentication...
+ */
+
+int authenticate_basic_user (request_rec *r)
+{
+ auth_config_rec *sec =
+ (auth_config_rec *)get_module_config (r->per_dir_config, &auth_module);
+ conn_rec *c = r->connection;
+ char *sent_pw, *real_pw;
+ char errstr[MAX_STRING_LEN];
+ int res;
+
+ if ((res = get_basic_auth_pw (r, &sent_pw))) return res;
+
+ if(!sec->auth_pwfile)
+ return DECLINED;
+
+ if (!(real_pw = get_pw(r, c->user, sec->auth_pwfile))) {
+ sprintf(errstr,"user %s not found",c->user);
+ log_reason (errstr, r->uri, r);
+ note_basic_auth_failure (r);
+ return AUTH_REQUIRED;
+ }
+ /* anyone know where the prototype for crypt is? */
+ if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) {
+ sprintf(errstr,"user %s: password mismatch",c->user);
+ log_reason (errstr, r->uri, r);
+ note_basic_auth_failure (r);
+ return AUTH_REQUIRED;
+ }
+ return OK;
+}
+
+/* Checking ID */
+
+int check_user_access (request_rec *r) {
+ auth_config_rec *sec =
+ (auth_config_rec *)get_module_config (r->per_dir_config, &auth_module);
+ char *user = r->connection->user;
+ int m = r->method_number;
+
+ register int x;
+ char *t, *w;
+ table *grpstatus;
+ array_header *reqs_arr = requires (r);
+ require_line *reqs;
+
+ /* BUG FIX: tadc, 11-Nov-1995. If there is no "requires" directive,
+ * then any user will do.
+ */
+ if (!reqs_arr)
+ return (OK);
+ reqs = (require_line *)reqs_arr->elts;
+
+ if(sec->auth_grpfile)
+ grpstatus = groups_for_user (r->pool, user, sec->auth_grpfile);
+ else
+ grpstatus = NULL;
+
+ for(x=0; x < reqs_arr->nelts; x++) {
+
+ if (! (reqs[x].method_mask & (1 << m))) continue;
+
+ t = reqs[x].requirement;
+ w = getword(r->pool, &t, ' ');
+ if(!strcmp(w,"valid-user"))
+ return OK;
+ if(!strcmp(w,"user")) {
+ while(t[0]) {
+ w = getword_conf (r->pool, &t);
+ if(!strcmp(user,w))
+ return OK;
+ }
+ }
+ else if(!strcmp(w,"group")) {
+ if(!grpstatus)
+ return DECLINED; /* DBM group? Something else? */
+
+ while(t[0]) {
+ w = getword_conf(r->pool, &t);
+ if(table_get (grpstatus, w))
+ return OK;
+ }
+ }
+ }
+
+ note_basic_auth_failure (r);
+ return AUTH_REQUIRED;
+}
+
+module auth_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ create_auth_dir_config, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ auth_cmds, /* command table */
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ authenticate_basic_user, /* check_user_id */
+ check_user_access, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_auth: authentication
+ *
+ * Rob McCool & Brian Behlendorf.
+ *
+ * Adapted to Shambhala by rst.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include <ndbm.h>
+
+typedef struct {
+
+ char *auth_dbmpwfile;
+ char *auth_dbmgrpfile;
+
+} dbm_auth_config_rec;
+
+void *create_dbm_auth_dir_config (pool *p, char *d)
+{
+ return pcalloc (p, sizeof(dbm_auth_config_rec));
+}
+
+command_rec dbm_auth_cmds[] = {
+{ "AuthDBMUserFile", set_string_slot,
+ (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile),
+ OR_AUTHCFG, TAKE1, NULL },
+{ "AuthDBMGroupFile", set_string_slot,
+ (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile),
+ OR_AUTHCFG, TAKE1, NULL },
+{ NULL }
+};
+
+module dbm_auth_module;
+
+char *get_dbm_pw(request_rec *r, char *user, char *auth_dbmpwfile) {
+ DBM *f;
+ datum d, q;
+ char *pw = NULL;
+
+ q.dptr = user;
+ q.dsize = strlen(q.dptr);
+
+ if(!(f=dbm_open(auth_dbmpwfile,O_RDONLY,0664))) {
+ log_reason ("could not open dbm auth file", auth_dbmpwfile, r);
+ return NULL;
+ }
+
+ d = dbm_fetch(f, q);
+
+ if (d.dptr) {
+ pw = palloc (r->pool, d.dsize + 1);
+ strncpy(pw,d.dptr,d.dsize);
+ pw[d.dsize] = '\0'; /* Terminate the string */
+ }
+
+ dbm_close(f);
+ return pw;
+}
+
+/* We do something strange with the group file. If the group file
+ * contains any : we assume the format is
+ * key=username value=":"groupname [":"anything here is ignored]
+ * otherwise we now (0.8.14+) assume that the format is
+ * key=username value=groupname
+ * The first allows the password and group files to be the same
+ * physical DBM file; key=username value=password":"groupname[":"anything]
+ *
+ * mark@telescope.org, 22Sep95
+ */
+
+char *get_dbm_grp(request_rec *r, char *user, char *auth_dbmgrpfile) {
+ char *grp_data = get_dbm_pw (r, user, auth_dbmgrpfile);
+ char *grp_colon; char *grp_colon2;
+
+ if (grp_data == NULL) return NULL;
+
+ if ((grp_colon = strchr(grp_data, ':'))!=NULL) {
+ grp_colon2 = strchr(++grp_colon, ':');
+ if (grp_colon2) *grp_colon2='\0';
+ return grp_colon;
+ }
+ return grp_data;
+}
+
+int dbm_authenticate_basic_user (request_rec *r)
+{
+ dbm_auth_config_rec *sec =
+ (dbm_auth_config_rec *)get_module_config (r->per_dir_config,
+ &dbm_auth_module);
+ conn_rec *c = r->connection;
+ char *sent_pw, *real_pw, *colon_pw;
+ char errstr[MAX_STRING_LEN];
+ int res;
+
+ if ((res = get_basic_auth_pw (r, &sent_pw)))
+ return res;
+
+ if(!sec->auth_dbmpwfile)
+ return DECLINED;
+
+ if(!(real_pw = get_dbm_pw(r, c->user, sec->auth_dbmpwfile))) {
+ sprintf(errstr,"DBM user %s not found", c->user);
+ log_reason (errstr, r->filename, r);
+ note_basic_auth_failure (r);
+ return AUTH_REQUIRED;
+ }
+ /* Password is up to first : if exists */
+ colon_pw = strchr(real_pw,':');
+ if (colon_pw) *colon_pw='\0';
+ /* anyone know where the prototype for crypt is? */
+ if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) {
+ sprintf(errstr,"user %s: password mismatch",c->user);
+ log_reason (errstr, r->uri, r);
+ note_basic_auth_failure (r);
+ return AUTH_REQUIRED;
+ }
+ return OK;
+}
+
+/* Checking ID */
+
+int dbm_check_auth(request_rec *r) {
+ dbm_auth_config_rec *sec =
+ (dbm_auth_config_rec *)get_module_config (r->per_dir_config,
+ &dbm_auth_module);
+ char *user = r->connection->user;
+ int m = r->method_number;
+ char errstr[MAX_STRING_LEN];
+
+ array_header *reqs_arr = requires (r);
+ require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
+
+ register int x;
+ char *t, *w;
+
+ if (!sec->auth_dbmgrpfile) return DECLINED;
+ if (!reqs_arr) return DECLINED;
+
+ for(x=0; x < reqs_arr->nelts; x++) {
+
+ if (! (reqs[x].method_mask & (1 << m))) continue;
+
+ t = reqs[x].requirement;
+ w = getword(r->pool, &t, ' ');
+
+ if(!strcmp(w,"group") && sec->auth_dbmgrpfile) {
+ char *orig_groups,*groups,*v;
+
+ if (!(groups = get_dbm_grp(r, user, sec->auth_dbmgrpfile))) {
+ sprintf(errstr,"user %s not in DBM group file %s",
+ user, sec->auth_dbmgrpfile);
+ log_reason (errstr, r->filename, r);
+ note_basic_auth_failure (r);
+ return AUTH_REQUIRED;
+ }
+ orig_groups = groups;
+ while(t[0]) {
+ w = getword(r->pool, &t, ' ');
+ groups = orig_groups;
+ while(groups[0]) {
+ v = getword(r->pool, &groups,',');
+ if(!strcmp(v,w))
+ return OK;
+ }
+ }
+ sprintf(errstr,"user %s not in right group",user);
+ log_reason (errstr, r->filename, r);
+ note_basic_auth_failure(r);
+ return AUTH_REQUIRED;
+ }
+ }
+
+ return DECLINED;
+}
+
+
+module dbm_auth_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ create_dbm_auth_dir_config, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ dbm_auth_cmds, /* command table */
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ dbm_authenticate_basic_user, /* check_user_id */
+ dbm_check_auth, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_dir.c: Handles the on-the-fly html index generation
+ *
+ * Rob McCool
+ * 3/23/93
+ *
+ * Adapted to Shambhala by rst.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_request.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_script.h"
+
+module dir_module;
+
+/****************************************************************
+ *
+ * Handling configuration directives...
+ */
+
+#define FANCY_INDEXING 1 /* Indexing options */
+#define ICONS_ARE_LINKS 2
+#define SCAN_HTML_TITLES 4
+#define SUPPRESS_LAST_MOD 8
+#define SUPPRESS_SIZE 16
+#define SUPPRESS_DESC 32
+
+struct item {
+ char *type;
+ char *apply_to;
+ char *apply_path;
+ char *data;
+};
+
+typedef struct dir_config_struct {
+
+ char *default_icon;
+ char *index_names;
+
+ array_header *icon_list, *alt_list, *desc_list, *ign_list;
+ array_header *hdr_list, *rdme_list, *opts_list;
+
+} dir_config_rec;
+
+char c_by_encoding, c_by_type, c_by_path;
+
+#define BY_ENCODING &c_by_encoding
+#define BY_TYPE &c_by_type
+#define BY_PATH &c_by_path
+
+void push_item(array_header *arr, char *type, char *to, char *path, char *data)
+{
+ struct item *p = (struct item *)push_array(arr);
+
+ if (!to) to = "";
+ if (!path) path = "";
+
+ p->type = type;
+ p->data = data ? pstrdup(arr->pool, data): NULL;
+ p->apply_path = pstrcat(arr->pool, path, "*", NULL);
+
+ if((type == BY_PATH) && (!is_matchexp(to)))
+ p->apply_to = pstrcat (arr->pool, "*", to, NULL);
+ else if (to)
+ p->apply_to = pstrdup (arr->pool, to);
+ else
+ p->apply_to = NULL;
+}
+
+char *add_alt(cmd_parms *cmd, void *d, char *alt, char *to)
+{
+ if (cmd->info == BY_PATH)
+ if(!strcmp(to,"**DIRECTORY**"))
+ to = "^^DIRECTORY^^";
+
+ push_item(((dir_config_rec *)d)->alt_list, cmd->info, to, cmd->path, alt);
+ return NULL;
+}
+
+char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to)
+{
+ char *iconbak = pstrdup (cmd->pool, icon);
+
+ if(icon[0] == '(') {
+ char *alt = getword (cmd->pool, &iconbak, ',');
+ iconbak[strlen(iconbak) - 1] = '\0'; /* Lose closing paren */
+ add_alt(cmd, d, &alt[1], to);
+ }
+ if(cmd->info == BY_PATH)
+ if(!strcmp(to,"**DIRECTORY**"))
+ to = "^^DIRECTORY^^";
+
+ push_item(((dir_config_rec *)d)->icon_list, cmd->info, to, cmd->path,
+ iconbak);
+ return NULL;
+}
+
+char *add_desc(cmd_parms *cmd, void *d, char *desc, char *to)
+{
+ push_item(((dir_config_rec *)d)->desc_list, cmd->info, to, cmd->path,desc);
+ return NULL;
+}
+
+char *add_ignore(cmd_parms *cmd, void *d, char *ext) {
+ push_item(((dir_config_rec *)d)->ign_list, 0, ext, cmd->path, NULL);
+ return NULL;
+}
+
+char *add_header(cmd_parms *cmd, void *d, char *name) {
+ push_item(((dir_config_rec *)d)->hdr_list, 0, NULL, cmd->path, name);
+ return NULL;
+}
+
+char *add_readme(cmd_parms *cmd, void *d, char *name) {
+ push_item(((dir_config_rec *)d)->rdme_list, 0, NULL, cmd->path, name);
+ return NULL;
+}
+
+
+char *add_opts_int(cmd_parms *cmd, void *d, int opts) {
+ push_item(((dir_config_rec *)d)->opts_list, (char*)opts, NULL,
+ cmd->path, NULL);
+ return NULL;
+}
+
+char *fancy_indexing (cmd_parms *cmd, void *d, int arg)
+{
+ return add_opts_int (cmd, d, arg? FANCY_INDEXING : 0);
+}
+
+char *add_opts(cmd_parms *cmd, void *d, char *optstr) {
+ char *w;
+ int opts = 0;
+
+ while(optstr[0]) {
+ w = getword_conf(cmd->pool, &optstr);
+ if(!strcasecmp(w,"FancyIndexing"))
+ opts |= FANCY_INDEXING;
+ else if(!strcasecmp(w,"IconsAreLinks"))
+ opts |= ICONS_ARE_LINKS;
+ else if(!strcasecmp(w,"ScanHTMLTitles"))
+ opts |= SCAN_HTML_TITLES;
+ else if(!strcasecmp(w,"SuppressLastModified"))
+ opts |= SUPPRESS_LAST_MOD;
+ else if(!strcasecmp(w,"SuppressSize"))
+ opts |= SUPPRESS_SIZE;
+ else if(!strcasecmp(w,"SuppressDescription"))
+ opts |= SUPPRESS_DESC;
+ else if(!strcasecmp(w,"None"))
+ opts = 0;
+ else
+ return "Invalid directory indexing option";
+ }
+ return add_opts_int(cmd, d, opts);
+}
+
+#define DIR_CMD_PERMS OR_INDEXES
+
+command_rec dir_cmds[] = {
+{ "AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+ "an icon URL followed by one or more filenames" },
+{ "AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
+ "an icon URL followed by one or more MIME types" },
+{ "AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
+ "an icon URL followed by one or more content encodings" },
+{ "AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+ "alternate descriptive text followed by one or more filenames" },
+{ "AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
+ "alternate descriptive text followed by one or more MIME types" },
+{ "AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
+ "alternate descriptive text followed by one or more content encodings" },
+{ "IndexOptions", add_opts, NULL, DIR_CMD_PERMS, RAW_ARGS,
+ "one or more index options" },
+{ "IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, ITERATE,
+ "one or more file extensions" },
+{ "AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+ "Descriptive text followed by one or more filenames" },
+{ "HeaderName", add_header, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
+{ "ReadmeName", add_readme, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
+{ "FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, FLAG, NULL },
+{ "DefaultIcon", set_string_slot,
+ (void*)XtOffsetOf(dir_config_rec, default_icon),
+ DIR_CMD_PERMS, TAKE1, "an icon URL"},
+{ "DirectoryIndex", set_string_slot,
+ (void*)XtOffsetOf(dir_config_rec, index_names),
+ DIR_CMD_PERMS, RAW_ARGS, NULL },
+{ NULL }
+};
+
+void *create_dir_config (pool *p, char *dummy)
+{
+ dir_config_rec *new =
+ (dir_config_rec *) pcalloc (p, sizeof(dir_config_rec));
+
+ new->index_names = NULL;
+ new->icon_list = make_array (p, 4, sizeof (struct item));
+ new->alt_list = make_array (p, 4, sizeof (struct item));
+ new->desc_list = make_array (p, 4, sizeof (struct item));
+ new->ign_list = make_array (p, 4, sizeof (struct item));
+ new->hdr_list = make_array (p, 4, sizeof (struct item));
+ new->rdme_list = make_array (p, 4, sizeof (struct item));
+ new->opts_list = make_array (p, 4, sizeof (struct item));
+
+ return (void *)new;
+}
+
+void *merge_dir_configs (pool *p, void *basev, void *addv)
+{
+ dir_config_rec *new=(dir_config_rec*)pcalloc (p, sizeof(dir_config_rec));
+ dir_config_rec *base = (dir_config_rec *)basev;
+ dir_config_rec *add = (dir_config_rec *)addv;
+
+ new->default_icon = add->default_icon?add->default_icon:base->default_icon;
+ new->index_names = add->index_names? add->index_names: base->index_names;
+
+ new->alt_list = append_arrays (p, add->alt_list, base->alt_list);
+ new->ign_list = append_arrays (p, add->ign_list, base->ign_list);
+ new->hdr_list = append_arrays (p, add->hdr_list, base->hdr_list);
+ new->desc_list = append_arrays (p, add->desc_list, base->desc_list);
+ new->icon_list = append_arrays (p, add->icon_list, base->icon_list);
+ new->rdme_list = append_arrays (p, add->rdme_list, base->rdme_list);
+ new->opts_list = append_arrays (p, add->opts_list, base->opts_list);
+
+ return new;
+}
+
+/****************************************************************
+ *
+ * Looking things up in config entries...
+ */
+
+/* Structure used to hold entries when we're actually building an index */
+
+struct ent {
+ char *name;
+ char *icon;
+ char *alt;
+ char *desc;
+ size_t size;
+ time_t lm;
+ struct ent *next;
+};
+
+char *find_item(request_rec *r, array_header *list, int path_only) {
+ char *content_type = r->content_type;
+ char *content_encoding = r->content_encoding;
+ char *path = r->filename;
+
+ struct item *items = (struct item *)list->elts;
+ int i;
+
+ for (i = 0; i < list->nelts; ++i) {
+ struct item *p = &items[i];
+
+ /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
+ if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) {
+ if(!*(p->apply_to))
+ return p->data;
+ else if(p->type == BY_PATH || path[0] == '^') {
+ if(!strcmp_match(path,p->apply_to))
+ return p->data;
+ } else if(!path_only) {
+ if(!content_encoding) {
+ if(p->type == BY_TYPE) {
+ if(!strcmp_match(content_type,p->apply_to))
+ return p->data;
+ }
+ } else {
+ if(p->type == BY_ENCODING) {
+ if(!strcmp_match(content_encoding,p->apply_to))
+ return p->data;
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+#define find_icon(d,p,t) find_item(p,d->icon_list,t)
+#define find_alt(d,p,t) find_item(p,d->alt_list,t)
+#define find_desc(d,p) find_item(p,d->desc_list,0)
+#define find_header(d,p) find_item(p,d->hdr_list,0)
+#define find_readme(d,p) find_item(p,d->rdme_list,0)
+
+char *find_default_icon (dir_config_rec *d, char *bogus_name)
+{
+ request_rec r;
+
+ /* Bleah. I tried to clean up find_item, and it lead to this bit
+ * of ugliness. Note that the fields initialized are precisely
+ * those that find_item looks at...
+ */
+
+ r.filename = bogus_name;
+ r.content_type = r.content_encoding = NULL;
+
+ return find_item (&r, d->icon_list, 1);
+}
+
+int ignore_entry(dir_config_rec *d, char *path) {
+ array_header *list = d->ign_list;
+ struct item *items = (struct item *)list->elts;
+ char *tt;
+ int i;
+
+ if((tt=strrchr(path,'/')) == NULL)
+ tt=path;
+ else {
+ tt++;
+ }
+
+ for (i = 0; i < list->nelts; ++i) {
+ struct item *p = &items[i];
+ char *ap;
+
+ if((ap=strrchr(p->apply_to,'/')) == NULL)
+ ap=p->apply_to;
+ else
+ ap++;
+
+ if(!strcmp_match(path,p->apply_path) && !strcmp_match(tt,ap))
+ return 1;
+ }
+ return 0;
+}
+
+int find_opts(dir_config_rec *d, request_rec *r) {
+ char *path = r->filename;
+ array_header *list = d->opts_list;
+ struct item *items = (struct item *)list->elts;
+ int i;
+
+ for (i = 0; i < list->nelts; ++i) {
+ struct item *p = &items[i];
+
+ if(!strcmp_match(path,p->apply_path))
+ return (int)p->type;
+ }
+ return 0;
+}
+
+/*****************************************************************
+ *
+ * Actually generating output
+ */
+
+
+int insert_readme(char *name, char *readme_fname, int rule, request_rec *r) {
+ char *fn;
+ FILE *f;
+ struct stat finfo;
+ int plaintext=0;
+
+ fn = make_full_path(r->pool, name, readme_fname);
+ fn = pstrcat(r->pool, fn, ".html", NULL);
+ if(stat(fn,&finfo) == -1) {
+ /* A brief fake multiviews search for README.html */
+ fn[strlen(fn)-5] = '\0';
+ if(stat(fn,&finfo) == -1)
+ return 0;
+ plaintext=1;
+ if(rule) rprintf(r,"<HR>%c",LF);
+ rprintf(r,"<PRE>%c",LF);
+ }
+ else if(rule) rprintf(r,"<HR>%c",LF);
+ if(!(f = pfopen(r->pool,fn,"r")))
+ return 0;
+ send_fd(f, r);
+ pfclose(r->pool, f);
+ if(plaintext)
+ rprintf(r,"</PRE>%c",LF);
+ return 1;
+}
+
+
+char *find_title(request_rec *r) {
+ char titlebuf[MAX_STRING_LEN], *find = "<TITLE>";
+ FILE *thefile = NULL;
+ int x,y,n,p;
+
+ if ((!strcmp(r->content_type,"text/html")) && (!r->content_encoding)) {
+ if(!(thefile = pfopen(r->pool, r->filename,"r")))
+ return NULL;
+ n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile);
+ titlebuf[n] = '\0';
+ for(x=0,p=0;titlebuf[x];x++) {
+ if(titlebuf[x] == find[p]) {
+ if(!find[++p]) {
+ if((p = ind(&titlebuf[++x],'<')) != -1)
+ titlebuf[x+p] = '\0';
+ /* Scan for line breaks for Tanmoy's secretary */
+ for(y=x;titlebuf[y];y++)
+ if((titlebuf[y] == CR) || (titlebuf[y] == LF))
+ titlebuf[y] = ' ';
+ pfclose (r->pool, thefile);
+ return pstrdup(r->pool, &titlebuf[x]);
+ }
+ } else p=0;
+ }
+ pfclose(r->pool, thefile);
+ }
+ return NULL;
+}
+
+
+#ifdef NOTDEF
+
+/* The only call to this function anyplace is commented out in the base
+ * code below. It could be fixed along the same lines as the shell_escape
+ * stuff in util.c, but for now, why bother?
+ */
+
+void escape_html(char *fn) {
+ register int x,y;
+ char copy[MAX_STRING_LEN];
+
+ strcpy(copy,fn);
+ for(x=0,y=0;copy[y];x++,y++) {
+ if(copy[y] == '<') {
+ strcpy(&fn[x],"<");
+ x+=3;
+ }
+ else if(copy[y] == '>') {
+ strcpy(&fn[x],">");
+ x+=3;
+ }
+ else if(copy[y] == '&') {
+ strcpy(&fn[x],"&");
+ x+=4;
+ }
+ else
+ fn[x] = copy[y];
+ }
+ fn[x] = '\0';
+}
+#endif
+
+struct ent *make_dir_entry(char *name, int dir_opts,
+ dir_config_rec *d, request_rec *r)
+{
+ struct ent *p;
+
+ if((name[0] == '.') && (!name[1]))
+ return(NULL);
+
+ if (ignore_entry(d, make_full_path (r->pool, r->filename, name)))
+ return(NULL);
+
+ p=(struct ent *)pcalloc(r->pool, sizeof(struct ent));
+ p->name = pstrdup (r->pool, name);
+ p->size = -1;
+ p->icon = NULL;
+ p->alt = NULL;
+ p->desc = NULL;
+ p->lm = -1;
+
+ if(dir_opts & FANCY_INDEXING) {
+ request_rec *rr = sub_req_lookup_file (name, r);
+
+ if (rr->finfo.st_mode != 0) {
+ p->lm = rr->finfo.st_mtime;
+ if(S_ISDIR(rr->finfo.st_mode)) {
+ if(!(p->icon = find_icon(d,rr,1)))
+ p->icon = find_default_icon(d,"^^DIRECTORY^^");
+ if(!(p->alt = find_alt(d,rr,1)))
+ p->alt = "DIR";
+ p->size = -1;
+ p->name = pstrcat (r->pool, name, "/", NULL);
+ }
+ else {
+ p->icon = find_icon(d, rr, 0);
+ p->alt = find_alt(d, rr, 0);
+ p->size = rr->finfo.st_size;
+ }
+ }
+
+ p->desc = find_desc(d, rr);
+
+ if((!p->desc) && (dir_opts & SCAN_HTML_TITLES))
+ p->desc = pstrdup (r->pool, find_title(rr));
+
+ destroy_sub_req (rr);
+ }
+ return(p);
+}
+
+char *terminate_description(dir_config_rec *d, char *desc, int dir_opts) {
+ int maxsize = 23;
+ register int x;
+
+ if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17;
+ if(dir_opts & SUPPRESS_SIZE) maxsize += 7;
+
+ for(x=0;desc[x] && maxsize;x++) {
+ if(desc[x] == '<') {
+ while(desc[x] != '>') {
+ if(!desc[x]) {
+ maxsize = 0;
+ break;
+ }
+ ++x;
+ }
+ }
+ else --maxsize;
+ }
+ if(!maxsize) {
+ desc[x-1] = '>'; /* Grump. */
+ desc[x] = '\0'; /* Double Grump! */
+ }
+ return desc;
+}
+
+void output_directories(struct ent **ar, int n,
+ dir_config_rec *d, request_rec *r, int dir_opts)
+{
+ int x;
+ char *name = r->uri;
+ char *tp;
+ pool *scratch = make_sub_pool (r->pool);
+
+ if(name[0] == '\0') name = "/";
+
+ if(dir_opts & FANCY_INDEXING) {
+ rprintf (r, "<PRE>");
+ if((tp = find_default_icon(d,"^^BLANKICON^^")))
+ rprintf(r, "<IMG SRC=\"%s\" ALT=\" \"> ", tp);
+ rprintf (r, "Name ");
+ if(!(dir_opts & SUPPRESS_LAST_MOD))
+ rprintf(r, "Last modified ");
+ if(!(dir_opts & SUPPRESS_SIZE))
+ rprintf(r, "Size ");
+ if(!(dir_opts & SUPPRESS_DESC))
+ rprintf(r, "Description");
+ rprintf(r,"%c<HR>%c",LF,LF);
+ }
+ else {
+ rprintf (r, "<UL>");
+ }
+
+ for(x=0;x<n;x++) {
+ char *anchor = NULL, *t = NULL, *t2 = NULL;
+
+ clear_pool (scratch);
+
+ if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) {
+ char *t = make_full_path (scratch, name, "../");
+ getparents(t);
+ if(t[0] == '\0') t = "/";
+ anchor = pstrcat (scratch, "<A HREF=\"", os_escape_path(scratch, t),
+ "\">", NULL);
+ t2 = "Parent Directory</A>";
+ }
+ else {
+ t = ar[x]->name;
+ t2 = pstrdup(scratch, t);
+ if(strlen(t2) > 21) {
+ t2[21] = '\0';
+ t2 = pstrcat (scratch, t2, "</A>..", NULL);
+ } else
+ /* screws up formatting, but some need it. should fix. */
+ /* escape_html(t2); */
+ t2 = pstrcat(scratch, t2, "</A>", NULL);
+ anchor = pstrcat (scratch, "<A HREF=\"", os_escape_path(scratch, t),
+ "\">", NULL);
+ }
+
+ if(dir_opts & FANCY_INDEXING) {
+ if(dir_opts & ICONS_ARE_LINKS)
+ rprintf (r,"%s",anchor);
+ if((ar[x]->icon) || d->default_icon) {
+ rprintf(r, "<IMG SRC=\"%s\" ALT=\"[%s]\">",
+ ar[x]->icon ? ar[x]->icon : d->default_icon,
+ ar[x]->alt ? ar[x]->alt : " ");
+ }
+ if(dir_opts & ICONS_ARE_LINKS)
+ rprintf (r, "</A>");
+
+ rprintf(r," %s%-27.29s", anchor, t2);
+ if(!(dir_opts & SUPPRESS_LAST_MOD)) {
+ if(ar[x]->lm != -1) {
+ char time[MAX_STRING_LEN];
+ struct tm *ts = localtime(&ar[x]->lm);
+ strftime(time,MAX_STRING_LEN,"%d-%b-%y %H:%M ",ts);
+ rprintf (r, "%s", time);
+ }
+ else {
+ rprintf(r, " ");
+ }
+ }
+ if(!(dir_opts & SUPPRESS_SIZE)) {
+ send_size(ar[x]->size,r);
+ rprintf (r, " ");
+ }
+ if(!(dir_opts & SUPPRESS_DESC)) {
+ if(ar[x]->desc) {
+ rprintf(r,"%s",
+ terminate_description(d, ar[x]->desc, dir_opts));
+ }
+ }
+ }
+ else
+ rprintf(r, "<LI> %s %s",anchor,t2);
+ rputc(LF,r);
+ }
+ if(dir_opts & FANCY_INDEXING) {
+ rprintf(r, "</PRE>");
+ }
+ else {
+ rprintf(r, "</UL>");
+ }
+}
+
+
+int dsortf(struct ent **s1,struct ent **s2)
+{
+ return(strcmp((*s1)->name,(*s2)->name));
+}
+
+
+int index_directory(request_rec *r, dir_config_rec *dir_conf)
+{
+ char *title_name = pstrdup (r->pool, r->uri);
+ char *title_endp;
+ char *name = r->filename;
+
+ DIR *d;
+ struct DIR_TYPE *dstruct;
+ int num_ent=0,x;
+ struct ent *head,*p;
+ struct ent **ar;
+ char *tmp;
+ int dir_opts = find_opts(dir_conf, r);
+
+ if(!(d=opendir(name))) return FORBIDDEN;
+
+ r->content_type = "text/html";
+
+ soft_timeout ("send directory", r);
+ send_http_header(r);
+
+ if (r->header_only) {
+ closedir (d);
+ return 0;
+ }
+
+ /* Spew HTML preamble */
+
+ title_endp = title_name + strlen(title_name) - 1;
+
+ while (title_endp > title_name && *title_endp == '/')
+ *title_endp-- = '\0';
+
+ rprintf (r,"<HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>%c",
+ title_name, LF);
+
+ if((!(tmp = find_header(dir_conf,r))) || (!(insert_readme(name,tmp,0,r))))
+ rprintf(r,"<H1>Index of %s</H1>%c",title_name,LF);
+
+ /*
+ * Since we don't know how many dir. entries there are, put them into a
+ * linked list and then arrayificate them so qsort can use them.
+ */
+ head=NULL;
+ while((dstruct=readdir(d))) {
+ if((p = make_dir_entry(dstruct->d_name, dir_opts, dir_conf, r))) {
+ p->next=head;
+ head=p;
+ num_ent++;
+ }
+ }
+ ar=(struct ent **) palloc(r->pool, num_ent*sizeof(struct ent *));
+ p=head;
+ x=0;
+ while(p) {
+ ar[x++]=p;
+ p = p->next;
+ }
+
+ qsort((void *)ar,num_ent,sizeof(struct ent *),
+#ifdef ULTRIX_BRAIN_DEATH
+ (int (*))dsortf);
+#else
+ (int (*)(const void *,const void *))dsortf);
+#endif
+ output_directories(ar, num_ent, dir_conf, r, dir_opts);
+ closedir(d);
+
+ if (dir_opts & FANCY_INDEXING)
+ if((tmp = find_readme(dir_conf, r)))
+ insert_readme(name,tmp,1,r);
+ else {
+ rprintf(r, "</UL>");
+ }
+
+ rprintf(r, "</BODY>");
+ return 0;
+}
+
+/* The formal handler... */
+
+int handle_dir (request_rec *r)
+{
+ dir_config_rec *d =
+ (dir_config_rec *)get_module_config (r->per_dir_config, &dir_module);
+ char *names_ptr = d->index_names ? d->index_names : DEFAULT_INDEX;
+ int allow_opts = allow_options (r);
+
+ if (r->method_number != M_GET) return NOT_IMPLEMENTED;
+
+ if (r->uri[0] == '\0' || r->uri[strlen(r->uri)-1] != '/') {
+ char* ifile = pstrcat (r->pool, r->uri, "/", NULL);
+ table_set (r->headers_out, "Location",
+ construct_url(r->pool, ifile, r->server));
+ return REDIRECT;
+ }
+
+ /* KLUDGE --- make the sub_req lookups happen in the right directory.
+ * Fixing this in the sub_req_lookup functions themselves is difficult,
+ * and would probably break virtual includes...
+ */
+
+ r->filename = pstrcat (r->pool, r->filename, "/", NULL);
+
+ while (*names_ptr) {
+
+ char *name_ptr = getword_conf (r->pool, &names_ptr);
+ request_rec *rr = sub_req_lookup_uri (name_ptr, r);
+
+ if (rr->status == 200 && rr->finfo.st_mode != 0) {
+ char *new_uri = escape_uri(r->pool, rr->uri);
+ destroy_sub_req (rr);
+ internal_redirect (new_uri, r);
+ return OK;
+ }
+
+ destroy_sub_req (rr);
+ }
+
+ /* OK, nothing easy. Trot out the heavy artillery... */
+
+ if (allow_opts & OPT_INDEXES)
+ return index_directory (r, d);
+ else
+ return FORBIDDEN;
+}
+
+
+handler_rec dir_handlers[] = {
+{ DIR_MAGIC_TYPE, handle_dir },
+{ NULL }
+};
+
+module dir_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ create_dir_config, /* dir config creater */
+ merge_dir_configs, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ dir_cmds, /* command table */
+ dir_handlers, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_script: keeps all script-related ramblings together.
+ *
+ * Compliant to CGI/1.1 spec
+ *
+ * Adapted by rst from original NCSA code by Rob McCool
+ *
+ * Apache adds some new env vars; REDIRECT_URL and REDIRECT_QUERY_STRING for
+ * custom error responses, and DOCUMENT_ROOT because we found it useful.
+ * It also adds SERVER_ADMIN - useful for scripts to know who to mail when
+ * they fail.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "util_script.h"
+
+/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
+ * in ScriptAliased directories, which means we need to know if this
+ * request came through ScriptAlias or not... so the Alias module
+ * leaves a note for us.
+ */
+
+int is_scriptaliased (request_rec *r)
+{
+ char *t = table_get (r->notes, "alias-forced-type");
+ return t && (!strcmp (t, CGI_MAGIC_TYPE));
+}
+
+/****************************************************************
+ *
+ * Actual CGI handling...
+ */
+
+void add_cgi_vars(request_rec *r)
+{
+ table *e = r->subprocess_env;
+
+ table_set (e, "GATEWAY_INTERFACE","CGI/1.1");
+ table_set (e, "SERVER_PROTOCOL", r->protocol);
+ table_set (e, "REQUEST_METHOD", r->method);
+ table_set (e, "QUERY_STRING", r->args ? r->args : "");
+
+ /* Note that the code below special-cases scripts run from includes,
+ * because it "knows" that the sub_request has been hacked to have the
+ * args and path_info of the original request, and not any that may have
+ * come with the script URI in the include command. Ugh.
+ */
+
+ if (!r->path_info || !*r->path_info || !strcmp (r->protocol, "INCLUDED")) {
+ table_set (e, "SCRIPT_NAME", r->uri);
+ } else {
+ int path_info_start = strlen (r->uri) - strlen (r->path_info);
+
+ r->uri[path_info_start] = '\0';
+ table_set (e, "SCRIPT_NAME", r->uri);
+ r->uri[path_info_start] = '/';
+ }
+
+ if (r->path_info && r->path_info[0]) {
+ /*
+ * To get PATH_TRANSLATED, treat PATH_INFO as a URI path.
+ * Need to re-escape it for this, since the entire URI was
+ * un-escaped before we determined where the PATH_INFO began.
+ */
+ request_rec *pa_req = sub_req_lookup_uri(
+ escape_uri(r->pool, r->path_info), r);
+
+ table_set (e, "PATH_INFO", r->path_info);
+
+ /* Don't bother destroying pa_req --- it's only created in
+ * child processes which are about to jettison their address
+ * space anyway. BTW, we concatenate filename and path_info
+ * from the sub_request to be compatible in case the PATH_INFO
+ * is pointing to an object which doesn't exist.
+ */
+
+ if (pa_req->filename)
+ table_set (e, "PATH_TRANSLATED",
+ pstrcat (r->pool, pa_req->filename, pa_req->path_info,
+ NULL));
+ }
+}
+
+struct cgi_child_stuff {
+ request_rec *r;
+ int nph;
+ char *argv0;
+};
+
+void cgi_child (void *child_stuff)
+{
+ struct cgi_child_stuff *cld = (struct cgi_child_stuff *)child_stuff;
+ request_rec *r = cld->r;
+ char *argv0 = cld->argv0;
+ int nph = cld->nph;
+
+#ifdef DEBUG_CGI
+ FILE *dbg = fopen ("/dev/tty", "w");
+ int i;
+#endif
+
+ char **env;
+ char err_string[HUGE_STRING_LEN];
+
+#ifdef DEBUG_CGI
+ fprintf (dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n",
+ r->filename, nph ? "NPH " : "", argv0);
+#endif
+
+ add_cgi_vars (r);
+ env = create_environment (r->pool, r->subprocess_env);
+
+#ifdef DEBUG_CGI
+ fprintf (dbg, "Environment: \n");
+ for (i = 0; env[i]; ++i) fprintf (dbg, "'%s'\n", env[i]);
+#endif
+
+ chdir_file (r->filename);
+ error_log2stderr (r->server);
+ if (nph) client_to_stdout (r->connection);
+
+ /* Transumute outselves into the script.
+ * NB only ISINDEX scripts get decoded arguments.
+ */
+
+ cleanup_for_exec();
+
+ if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0))
+ execle(r->filename, argv0, NULL, env);
+ else
+ execve(r->filename, create_argv(r->pool, argv0, r->args), env);
+
+ /* Uh oh. Still here. Where's the kaboom? There was supposed to be an
+ * EARTH-shattering kaboom!
+ *
+ * Oh, well. Muddle through as best we can...
+ *
+ * (NB we can't use log_error, or anything like that, because we
+ * just closed the file descriptor which r->server->error_log
+ * was tied to in cleanup_for_exec(). It's only available on stderr
+ * now, so that's what we use).
+ */
+
+ sprintf(err_string,
+ "exec of %s failed, errno is %d\n", r->filename, errno);
+ write(2, err_string, strlen(err_string));
+ exit(0);
+}
+
+int cgi_handler (request_rec *r)
+{
+ int nph;
+ char *argv0;
+ FILE *script_out, *script_in;
+ char argsbuffer[HUGE_STRING_LEN];
+ int is_included = !strcmp (r->protocol, "INCLUDED");
+ char *lenp = table_get (r->headers_in, "Content-length");
+
+ struct cgi_child_stuff cld;
+
+ if((argv0 = strrchr(r->filename,'/')) != NULL)
+ argv0++;
+ else argv0 = r->filename;
+
+ nph = !(strncmp(argv0,"nph-",4));
+
+ if (!(allow_options (r) & OPT_EXECCGI) && !is_scriptaliased (r)) {
+ log_reason("Options ExecCGI is off in this directory", r->filename, r);
+ return FORBIDDEN;
+ }
+ if (nph && is_included) {
+ log_reason("attempt to include NPH CGI script", r->filename, r);
+ return FORBIDDEN;
+ }
+
+ if (S_ISDIR(r->finfo.st_mode)) {
+ log_reason("attempt to invoke directory as script", r->filename, r);
+ return FORBIDDEN;
+ }
+ if (r->finfo.st_mode == 0) {
+ log_reason("script not found or unable to stat", r->filename, r);
+ return NOT_FOUND;
+ }
+ if(!can_exec(&r->finfo)) {
+ log_reason("file permissions deny server execution", r->filename, r);
+ return FORBIDDEN;
+ }
+ if ((r->method_number == M_POST || r->method_number == M_PUT)
+ && !lenp) {
+ log_reason("POST or PUT without Content-length:", r->filename, r);
+ return BAD_REQUEST;
+ }
+
+ add_common_vars (r);
+ cld.argv0 = argv0; cld.r = r; cld.nph = nph;
+
+ if (!spawn_child (r->connection->pool, cgi_child, (void *)&cld,
+ nph ? just_wait : kill_after_timeout,
+ &script_out, nph ? NULL : &script_in)) {
+ log_reason ("couldn't spawn child process", r->filename, r);
+ return SERVER_ERROR;
+ }
+
+ /* Transfer any put/post args, CERN style...
+ * Note that if a buggy script fails to read everything we throw
+ * at it, or a buggy client sends too much, we get a SIGPIPE, so
+ * we have to ignore SIGPIPE while doing this. CERN does the same
+ * (and in fact, they pretty nearly guarantee themselves a SIGPIPE
+ * on every invocation by chasing the real client data with a
+ * spurious newline).
+ */
+
+ if (r->method_number == M_POST || r->method_number == M_PUT) {
+ void (*handler)();
+ int remaining = atoi (lenp);
+
+ hard_timeout ("copy script args", r);
+ handler = signal (SIGPIPE, SIG_IGN);
+
+ while ((remaining > 0))
+ {
+ int len_read, len_to_read = remaining;
+
+ if (len_to_read > HUGE_STRING_LEN) len_to_read = HUGE_STRING_LEN;
+
+ len_read = read_client_block (r, argsbuffer, len_to_read);
+ fwrite (argsbuffer, 1, len_read, script_out);
+ remaining -= len_read;
+ }
+
+ fflush (script_out);
+ signal (SIGPIPE, handler);
+
+ kill_timeout (r);
+ }
+
+ pfclose (r->connection->pool, script_out);
+
+ /* Handle script return... */
+
+ if (script_in && !nph) {
+ char *location;
+ int ret;
+
+ if ((ret = scan_script_header(r, script_in)))
+ return ret;
+
+ location = table_get (r->headers_out, "Location");
+
+ if (location && location[0] == '/' && r->status == 200) {
+
+ /* Soak up all the script output */
+ hard_timeout ("read from script", r);
+ while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL)
+ continue;
+ kill_timeout (r);
+
+ internal_redirect (location, r);
+ return OK;
+ }
+ else if (location && r->status == 200) {
+ /* XX Note that if a script wants to produce its own Redirect
+ * body, it now has to explicitly *say* "Status: 302"
+ */
+ return REDIRECT;
+ }
+
+ hard_timeout ("send script output", r);
+ send_http_header(r);
+ if(!r->header_only) send_fd (script_in, r);
+ kill_timeout (r);
+ pfclose (r->connection->pool, script_in);
+ }
+
+ return OK; /* NOT r->status, even if it has changed. */
+}
+
+handler_rec cgi_handlers[] = {
+{ CGI_MAGIC_TYPE, cgi_handler },
+{ NULL }
+};
+
+module cgi_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ NULL, /* command table */
+ cgi_handlers, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_dir.c: Handles the on-the-fly html index generation
+ *
+ * Rob McCool
+ * 3/23/93
+ *
+ * Adapted to Shambhala by rst.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_request.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_script.h"
+
+module dir_module;
+
+/****************************************************************
+ *
+ * Handling configuration directives...
+ */
+
+#define FANCY_INDEXING 1 /* Indexing options */
+#define ICONS_ARE_LINKS 2
+#define SCAN_HTML_TITLES 4
+#define SUPPRESS_LAST_MOD 8
+#define SUPPRESS_SIZE 16
+#define SUPPRESS_DESC 32
+
+struct item {
+ char *type;
+ char *apply_to;
+ char *apply_path;
+ char *data;
+};
+
+typedef struct dir_config_struct {
+
+ char *default_icon;
+ char *index_names;
+
+ array_header *icon_list, *alt_list, *desc_list, *ign_list;
+ array_header *hdr_list, *rdme_list, *opts_list;
+
+} dir_config_rec;
+
+char c_by_encoding, c_by_type, c_by_path;
+
+#define BY_ENCODING &c_by_encoding
+#define BY_TYPE &c_by_type
+#define BY_PATH &c_by_path
+
+void push_item(array_header *arr, char *type, char *to, char *path, char *data)
+{
+ struct item *p = (struct item *)push_array(arr);
+
+ if (!to) to = "";
+ if (!path) path = "";
+
+ p->type = type;
+ p->data = data ? pstrdup(arr->pool, data): NULL;
+ p->apply_path = pstrcat(arr->pool, path, "*", NULL);
+
+ if((type == BY_PATH) && (!is_matchexp(to)))
+ p->apply_to = pstrcat (arr->pool, "*", to, NULL);
+ else if (to)
+ p->apply_to = pstrdup (arr->pool, to);
+ else
+ p->apply_to = NULL;
+}
+
+char *add_alt(cmd_parms *cmd, void *d, char *alt, char *to)
+{
+ if (cmd->info == BY_PATH)
+ if(!strcmp(to,"**DIRECTORY**"))
+ to = "^^DIRECTORY^^";
+
+ push_item(((dir_config_rec *)d)->alt_list, cmd->info, to, cmd->path, alt);
+ return NULL;
+}
+
+char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to)
+{
+ char *iconbak = pstrdup (cmd->pool, icon);
+
+ if(icon[0] == '(') {
+ char *alt = getword (cmd->pool, &iconbak, ',');
+ iconbak[strlen(iconbak) - 1] = '\0'; /* Lose closing paren */
+ add_alt(cmd, d, &alt[1], to);
+ }
+ if(cmd->info == BY_PATH)
+ if(!strcmp(to,"**DIRECTORY**"))
+ to = "^^DIRECTORY^^";
+
+ push_item(((dir_config_rec *)d)->icon_list, cmd->info, to, cmd->path,
+ iconbak);
+ return NULL;
+}
+
+char *add_desc(cmd_parms *cmd, void *d, char *desc, char *to)
+{
+ push_item(((dir_config_rec *)d)->desc_list, cmd->info, to, cmd->path,desc);
+ return NULL;
+}
+
+char *add_ignore(cmd_parms *cmd, void *d, char *ext) {
+ push_item(((dir_config_rec *)d)->ign_list, 0, ext, cmd->path, NULL);
+ return NULL;
+}
+
+char *add_header(cmd_parms *cmd, void *d, char *name) {
+ push_item(((dir_config_rec *)d)->hdr_list, 0, NULL, cmd->path, name);
+ return NULL;
+}
+
+char *add_readme(cmd_parms *cmd, void *d, char *name) {
+ push_item(((dir_config_rec *)d)->rdme_list, 0, NULL, cmd->path, name);
+ return NULL;
+}
+
+
+char *add_opts_int(cmd_parms *cmd, void *d, int opts) {
+ push_item(((dir_config_rec *)d)->opts_list, (char*)opts, NULL,
+ cmd->path, NULL);
+ return NULL;
+}
+
+char *fancy_indexing (cmd_parms *cmd, void *d, int arg)
+{
+ return add_opts_int (cmd, d, arg? FANCY_INDEXING : 0);
+}
+
+char *add_opts(cmd_parms *cmd, void *d, char *optstr) {
+ char *w;
+ int opts = 0;
+
+ while(optstr[0]) {
+ w = getword_conf(cmd->pool, &optstr);
+ if(!strcasecmp(w,"FancyIndexing"))
+ opts |= FANCY_INDEXING;
+ else if(!strcasecmp(w,"IconsAreLinks"))
+ opts |= ICONS_ARE_LINKS;
+ else if(!strcasecmp(w,"ScanHTMLTitles"))
+ opts |= SCAN_HTML_TITLES;
+ else if(!strcasecmp(w,"SuppressLastModified"))
+ opts |= SUPPRESS_LAST_MOD;
+ else if(!strcasecmp(w,"SuppressSize"))
+ opts |= SUPPRESS_SIZE;
+ else if(!strcasecmp(w,"SuppressDescription"))
+ opts |= SUPPRESS_DESC;
+ else if(!strcasecmp(w,"None"))
+ opts = 0;
+ else
+ return "Invalid directory indexing option";
+ }
+ return add_opts_int(cmd, d, opts);
+}
+
+#define DIR_CMD_PERMS OR_INDEXES
+
+command_rec dir_cmds[] = {
+{ "AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+ "an icon URL followed by one or more filenames" },
+{ "AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
+ "an icon URL followed by one or more MIME types" },
+{ "AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
+ "an icon URL followed by one or more content encodings" },
+{ "AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+ "alternate descriptive text followed by one or more filenames" },
+{ "AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
+ "alternate descriptive text followed by one or more MIME types" },
+{ "AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
+ "alternate descriptive text followed by one or more content encodings" },
+{ "IndexOptions", add_opts, NULL, DIR_CMD_PERMS, RAW_ARGS,
+ "one or more index options" },
+{ "IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, ITERATE,
+ "one or more file extensions" },
+{ "AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, ITERATE2,
+ "Descriptive text followed by one or more filenames" },
+{ "HeaderName", add_header, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
+{ "ReadmeName", add_readme, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
+{ "FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, FLAG, NULL },
+{ "DefaultIcon", set_string_slot,
+ (void*)XtOffsetOf(dir_config_rec, default_icon),
+ DIR_CMD_PERMS, TAKE1, "an icon URL"},
+{ "DirectoryIndex", set_string_slot,
+ (void*)XtOffsetOf(dir_config_rec, index_names),
+ DIR_CMD_PERMS, RAW_ARGS, NULL },
+{ NULL }
+};
+
+void *create_dir_config (pool *p, char *dummy)
+{
+ dir_config_rec *new =
+ (dir_config_rec *) pcalloc (p, sizeof(dir_config_rec));
+
+ new->index_names = NULL;
+ new->icon_list = make_array (p, 4, sizeof (struct item));
+ new->alt_list = make_array (p, 4, sizeof (struct item));
+ new->desc_list = make_array (p, 4, sizeof (struct item));
+ new->ign_list = make_array (p, 4, sizeof (struct item));
+ new->hdr_list = make_array (p, 4, sizeof (struct item));
+ new->rdme_list = make_array (p, 4, sizeof (struct item));
+ new->opts_list = make_array (p, 4, sizeof (struct item));
+
+ return (void *)new;
+}
+
+void *merge_dir_configs (pool *p, void *basev, void *addv)
+{
+ dir_config_rec *new=(dir_config_rec*)pcalloc (p, sizeof(dir_config_rec));
+ dir_config_rec *base = (dir_config_rec *)basev;
+ dir_config_rec *add = (dir_config_rec *)addv;
+
+ new->default_icon = add->default_icon?add->default_icon:base->default_icon;
+ new->index_names = add->index_names? add->index_names: base->index_names;
+
+ new->alt_list = append_arrays (p, add->alt_list, base->alt_list);
+ new->ign_list = append_arrays (p, add->ign_list, base->ign_list);
+ new->hdr_list = append_arrays (p, add->hdr_list, base->hdr_list);
+ new->desc_list = append_arrays (p, add->desc_list, base->desc_list);
+ new->icon_list = append_arrays (p, add->icon_list, base->icon_list);
+ new->rdme_list = append_arrays (p, add->rdme_list, base->rdme_list);
+ new->opts_list = append_arrays (p, add->opts_list, base->opts_list);
+
+ return new;
+}
+
+/****************************************************************
+ *
+ * Looking things up in config entries...
+ */
+
+/* Structure used to hold entries when we're actually building an index */
+
+struct ent {
+ char *name;
+ char *icon;
+ char *alt;
+ char *desc;
+ size_t size;
+ time_t lm;
+ struct ent *next;
+};
+
+char *find_item(request_rec *r, array_header *list, int path_only) {
+ char *content_type = r->content_type;
+ char *content_encoding = r->content_encoding;
+ char *path = r->filename;
+
+ struct item *items = (struct item *)list->elts;
+ int i;
+
+ for (i = 0; i < list->nelts; ++i) {
+ struct item *p = &items[i];
+
+ /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
+ if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) {
+ if(!*(p->apply_to))
+ return p->data;
+ else if(p->type == BY_PATH || path[0] == '^') {
+ if(!strcmp_match(path,p->apply_to))
+ return p->data;
+ } else if(!path_only) {
+ if(!content_encoding) {
+ if(p->type == BY_TYPE) {
+ if(!strcmp_match(content_type,p->apply_to))
+ return p->data;
+ }
+ } else {
+ if(p->type == BY_ENCODING) {
+ if(!strcmp_match(content_encoding,p->apply_to))
+ return p->data;
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+#define find_icon(d,p,t) find_item(p,d->icon_list,t)
+#define find_alt(d,p,t) find_item(p,d->alt_list,t)
+#define find_desc(d,p) find_item(p,d->desc_list,0)
+#define find_header(d,p) find_item(p,d->hdr_list,0)
+#define find_readme(d,p) find_item(p,d->rdme_list,0)
+
+char *find_default_icon (dir_config_rec *d, char *bogus_name)
+{
+ request_rec r;
+
+ /* Bleah. I tried to clean up find_item, and it lead to this bit
+ * of ugliness. Note that the fields initialized are precisely
+ * those that find_item looks at...
+ */
+
+ r.filename = bogus_name;
+ r.content_type = r.content_encoding = NULL;
+
+ return find_item (&r, d->icon_list, 1);
+}
+
+int ignore_entry(dir_config_rec *d, char *path) {
+ array_header *list = d->ign_list;
+ struct item *items = (struct item *)list->elts;
+ char *tt;
+ int i;
+
+ if((tt=strrchr(path,'/')) == NULL)
+ tt=path;
+ else {
+ tt++;
+ }
+
+ for (i = 0; i < list->nelts; ++i) {
+ struct item *p = &items[i];
+ char *ap;
+
+ if((ap=strrchr(p->apply_to,'/')) == NULL)
+ ap=p->apply_to;
+ else
+ ap++;
+
+ if(!strcmp_match(path,p->apply_path) && !strcmp_match(tt,ap))
+ return 1;
+ }
+ return 0;
+}
+
+int find_opts(dir_config_rec *d, request_rec *r) {
+ char *path = r->filename;
+ array_header *list = d->opts_list;
+ struct item *items = (struct item *)list->elts;
+ int i;
+
+ for (i = 0; i < list->nelts; ++i) {
+ struct item *p = &items[i];
+
+ if(!strcmp_match(path,p->apply_path))
+ return (int)p->type;
+ }
+ return 0;
+}
+
+/*****************************************************************
+ *
+ * Actually generating output
+ */
+
+
+int insert_readme(char *name, char *readme_fname, int rule, request_rec *r) {
+ char *fn;
+ FILE *f;
+ struct stat finfo;
+ int plaintext=0;
+
+ fn = make_full_path(r->pool, name, readme_fname);
+ fn = pstrcat(r->pool, fn, ".html", NULL);
+ if(stat(fn,&finfo) == -1) {
+ /* A brief fake multiviews search for README.html */
+ fn[strlen(fn)-5] = '\0';
+ if(stat(fn,&finfo) == -1)
+ return 0;
+ plaintext=1;
+ if(rule) rprintf(r,"<HR>%c",LF);
+ rprintf(r,"<PRE>%c",LF);
+ }
+ else if(rule) rprintf(r,"<HR>%c",LF);
+ if(!(f = pfopen(r->pool,fn,"r")))
+ return 0;
+ send_fd(f, r);
+ pfclose(r->pool, f);
+ if(plaintext)
+ rprintf(r,"</PRE>%c",LF);
+ return 1;
+}
+
+
+char *find_title(request_rec *r) {
+ char titlebuf[MAX_STRING_LEN], *find = "<TITLE>";
+ FILE *thefile = NULL;
+ int x,y,n,p;
+
+ if ((!strcmp(r->content_type,"text/html")) && (!r->content_encoding)) {
+ if(!(thefile = pfopen(r->pool, r->filename,"r")))
+ return NULL;
+ n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile);
+ titlebuf[n] = '\0';
+ for(x=0,p=0;titlebuf[x];x++) {
+ if(titlebuf[x] == find[p]) {
+ if(!find[++p]) {
+ if((p = ind(&titlebuf[++x],'<')) != -1)
+ titlebuf[x+p] = '\0';
+ /* Scan for line breaks for Tanmoy's secretary */
+ for(y=x;titlebuf[y];y++)
+ if((titlebuf[y] == CR) || (titlebuf[y] == LF))
+ titlebuf[y] = ' ';
+ pfclose (r->pool, thefile);
+ return pstrdup(r->pool, &titlebuf[x]);
+ }
+ } else p=0;
+ }
+ pfclose(r->pool, thefile);
+ }
+ return NULL;
+}
+
+
+#ifdef NOTDEF
+
+/* The only call to this function anyplace is commented out in the base
+ * code below. It could be fixed along the same lines as the shell_escape
+ * stuff in util.c, but for now, why bother?
+ */
+
+void escape_html(char *fn) {
+ register int x,y;
+ char copy[MAX_STRING_LEN];
+
+ strcpy(copy,fn);
+ for(x=0,y=0;copy[y];x++,y++) {
+ if(copy[y] == '<') {
+ strcpy(&fn[x],"<");
+ x+=3;
+ }
+ else if(copy[y] == '>') {
+ strcpy(&fn[x],">");
+ x+=3;
+ }
+ else if(copy[y] == '&') {
+ strcpy(&fn[x],"&");
+ x+=4;
+ }
+ else
+ fn[x] = copy[y];
+ }
+ fn[x] = '\0';
+}
+#endif
+
+struct ent *make_dir_entry(char *name, int dir_opts,
+ dir_config_rec *d, request_rec *r)
+{
+ struct ent *p;
+
+ if((name[0] == '.') && (!name[1]))
+ return(NULL);
+
+ if (ignore_entry(d, make_full_path (r->pool, r->filename, name)))
+ return(NULL);
+
+ p=(struct ent *)pcalloc(r->pool, sizeof(struct ent));
+ p->name = pstrdup (r->pool, name);
+ p->size = -1;
+ p->icon = NULL;
+ p->alt = NULL;
+ p->desc = NULL;
+ p->lm = -1;
+
+ if(dir_opts & FANCY_INDEXING) {
+ request_rec *rr = sub_req_lookup_file (name, r);
+
+ if (rr->finfo.st_mode != 0) {
+ p->lm = rr->finfo.st_mtime;
+ if(S_ISDIR(rr->finfo.st_mode)) {
+ if(!(p->icon = find_icon(d,rr,1)))
+ p->icon = find_default_icon(d,"^^DIRECTORY^^");
+ if(!(p->alt = find_alt(d,rr,1)))
+ p->alt = "DIR";
+ p->size = -1;
+ p->name = pstrcat (r->pool, name, "/", NULL);
+ }
+ else {
+ p->icon = find_icon(d, rr, 0);
+ p->alt = find_alt(d, rr, 0);
+ p->size = rr->finfo.st_size;
+ }
+ }
+
+ p->desc = find_desc(d, rr);
+
+ if((!p->desc) && (dir_opts & SCAN_HTML_TITLES))
+ p->desc = pstrdup (r->pool, find_title(rr));
+
+ destroy_sub_req (rr);
+ }
+ return(p);
+}
+
+char *terminate_description(dir_config_rec *d, char *desc, int dir_opts) {
+ int maxsize = 23;
+ register int x;
+
+ if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17;
+ if(dir_opts & SUPPRESS_SIZE) maxsize += 7;
+
+ for(x=0;desc[x] && maxsize;x++) {
+ if(desc[x] == '<') {
+ while(desc[x] != '>') {
+ if(!desc[x]) {
+ maxsize = 0;
+ break;
+ }
+ ++x;
+ }
+ }
+ else --maxsize;
+ }
+ if(!maxsize) {
+ desc[x-1] = '>'; /* Grump. */
+ desc[x] = '\0'; /* Double Grump! */
+ }
+ return desc;
+}
+
+void output_directories(struct ent **ar, int n,
+ dir_config_rec *d, request_rec *r, int dir_opts)
+{
+ int x;
+ char *name = r->uri;
+ char *tp;
+ pool *scratch = make_sub_pool (r->pool);
+
+ if(name[0] == '\0') name = "/";
+
+ if(dir_opts & FANCY_INDEXING) {
+ rprintf (r, "<PRE>");
+ if((tp = find_default_icon(d,"^^BLANKICON^^")))
+ rprintf(r, "<IMG SRC=\"%s\" ALT=\" \"> ", tp);
+ rprintf (r, "Name ");
+ if(!(dir_opts & SUPPRESS_LAST_MOD))
+ rprintf(r, "Last modified ");
+ if(!(dir_opts & SUPPRESS_SIZE))
+ rprintf(r, "Size ");
+ if(!(dir_opts & SUPPRESS_DESC))
+ rprintf(r, "Description");
+ rprintf(r,"%c<HR>%c",LF,LF);
+ }
+ else {
+ rprintf (r, "<UL>");
+ }
+
+ for(x=0;x<n;x++) {
+ char *anchor = NULL, *t = NULL, *t2 = NULL;
+
+ clear_pool (scratch);
+
+ if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) {
+ char *t = make_full_path (scratch, name, "../");
+ getparents(t);
+ if(t[0] == '\0') t = "/";
+ anchor = pstrcat (scratch, "<A HREF=\"", os_escape_path(scratch, t),
+ "\">", NULL);
+ t2 = "Parent Directory</A>";
+ }
+ else {
+ t = ar[x]->name;
+ t2 = pstrdup(scratch, t);
+ if(strlen(t2) > 21) {
+ t2[21] = '\0';
+ t2 = pstrcat (scratch, t2, "</A>..", NULL);
+ } else
+ /* screws up formatting, but some need it. should fix. */
+ /* escape_html(t2); */
+ t2 = pstrcat(scratch, t2, "</A>", NULL);
+ anchor = pstrcat (scratch, "<A HREF=\"", os_escape_path(scratch, t),
+ "\">", NULL);
+ }
+
+ if(dir_opts & FANCY_INDEXING) {
+ if(dir_opts & ICONS_ARE_LINKS)
+ rprintf (r,"%s",anchor);
+ if((ar[x]->icon) || d->default_icon) {
+ rprintf(r, "<IMG SRC=\"%s\" ALT=\"[%s]\">",
+ ar[x]->icon ? ar[x]->icon : d->default_icon,
+ ar[x]->alt ? ar[x]->alt : " ");
+ }
+ if(dir_opts & ICONS_ARE_LINKS)
+ rprintf (r, "</A>");
+
+ rprintf(r," %s%-27.29s", anchor, t2);
+ if(!(dir_opts & SUPPRESS_LAST_MOD)) {
+ if(ar[x]->lm != -1) {
+ char time[MAX_STRING_LEN];
+ struct tm *ts = localtime(&ar[x]->lm);
+ strftime(time,MAX_STRING_LEN,"%d-%b-%y %H:%M ",ts);
+ rprintf (r, "%s", time);
+ }
+ else {
+ rprintf(r, " ");
+ }
+ }
+ if(!(dir_opts & SUPPRESS_SIZE)) {
+ send_size(ar[x]->size,r);
+ rprintf (r, " ");
+ }
+ if(!(dir_opts & SUPPRESS_DESC)) {
+ if(ar[x]->desc) {
+ rprintf(r,"%s",
+ terminate_description(d, ar[x]->desc, dir_opts));
+ }
+ }
+ }
+ else
+ rprintf(r, "<LI> %s %s",anchor,t2);
+ rputc(LF,r);
+ }
+ if(dir_opts & FANCY_INDEXING) {
+ rprintf(r, "</PRE>");
+ }
+ else {
+ rprintf(r, "</UL>");
+ }
+}
+
+
+int dsortf(struct ent **s1,struct ent **s2)
+{
+ return(strcmp((*s1)->name,(*s2)->name));
+}
+
+
+int index_directory(request_rec *r, dir_config_rec *dir_conf)
+{
+ char *title_name = pstrdup (r->pool, r->uri);
+ char *title_endp;
+ char *name = r->filename;
+
+ DIR *d;
+ struct DIR_TYPE *dstruct;
+ int num_ent=0,x;
+ struct ent *head,*p;
+ struct ent **ar;
+ char *tmp;
+ int dir_opts = find_opts(dir_conf, r);
+
+ if(!(d=opendir(name))) return FORBIDDEN;
+
+ r->content_type = "text/html";
+
+ soft_timeout ("send directory", r);
+ send_http_header(r);
+
+ if (r->header_only) {
+ closedir (d);
+ return 0;
+ }
+
+ /* Spew HTML preamble */
+
+ title_endp = title_name + strlen(title_name) - 1;
+
+ while (title_endp > title_name && *title_endp == '/')
+ *title_endp-- = '\0';
+
+ rprintf (r,"<HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>%c",
+ title_name, LF);
+
+ if((!(tmp = find_header(dir_conf,r))) || (!(insert_readme(name,tmp,0,r))))
+ rprintf(r,"<H1>Index of %s</H1>%c",title_name,LF);
+
+ /*
+ * Since we don't know how many dir. entries there are, put them into a
+ * linked list and then arrayificate them so qsort can use them.
+ */
+ head=NULL;
+ while((dstruct=readdir(d))) {
+ if((p = make_dir_entry(dstruct->d_name, dir_opts, dir_conf, r))) {
+ p->next=head;
+ head=p;
+ num_ent++;
+ }
+ }
+ ar=(struct ent **) palloc(r->pool, num_ent*sizeof(struct ent *));
+ p=head;
+ x=0;
+ while(p) {
+ ar[x++]=p;
+ p = p->next;
+ }
+
+ qsort((void *)ar,num_ent,sizeof(struct ent *),
+#ifdef ULTRIX_BRAIN_DEATH
+ (int (*))dsortf);
+#else
+ (int (*)(const void *,const void *))dsortf);
+#endif
+ output_directories(ar, num_ent, dir_conf, r, dir_opts);
+ closedir(d);
+
+ if (dir_opts & FANCY_INDEXING)
+ if((tmp = find_readme(dir_conf, r)))
+ insert_readme(name,tmp,1,r);
+ else {
+ rprintf(r, "</UL>");
+ }
+
+ rprintf(r, "</BODY>");
+ return 0;
+}
+
+/* The formal handler... */
+
+int handle_dir (request_rec *r)
+{
+ dir_config_rec *d =
+ (dir_config_rec *)get_module_config (r->per_dir_config, &dir_module);
+ char *names_ptr = d->index_names ? d->index_names : DEFAULT_INDEX;
+ int allow_opts = allow_options (r);
+
+ if (r->method_number != M_GET) return NOT_IMPLEMENTED;
+
+ if (r->uri[0] == '\0' || r->uri[strlen(r->uri)-1] != '/') {
+ char* ifile = pstrcat (r->pool, r->uri, "/", NULL);
+ table_set (r->headers_out, "Location",
+ construct_url(r->pool, ifile, r->server));
+ return REDIRECT;
+ }
+
+ /* KLUDGE --- make the sub_req lookups happen in the right directory.
+ * Fixing this in the sub_req_lookup functions themselves is difficult,
+ * and would probably break virtual includes...
+ */
+
+ r->filename = pstrcat (r->pool, r->filename, "/", NULL);
+
+ while (*names_ptr) {
+
+ char *name_ptr = getword_conf (r->pool, &names_ptr);
+ request_rec *rr = sub_req_lookup_uri (name_ptr, r);
+
+ if (rr->status == 200 && rr->finfo.st_mode != 0) {
+ char *new_uri = escape_uri(r->pool, rr->uri);
+ destroy_sub_req (rr);
+ internal_redirect (new_uri, r);
+ return OK;
+ }
+
+ destroy_sub_req (rr);
+ }
+
+ /* OK, nothing easy. Trot out the heavy artillery... */
+
+ if (allow_opts & OPT_INDEXES)
+ return index_directory (r, d);
+ else
+ return FORBIDDEN;
+}
+
+
+handler_rec dir_handlers[] = {
+{ DIR_MAGIC_TYPE, handle_dir },
+{ NULL }
+};
+
+module dir_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ create_dir_config, /* dir config creater */
+ merge_dir_configs, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ dir_cmds, /* command table */
+ dir_handlers, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * A first stab at dynamic loading, using the GNU dld library
+ * (or at least, an embarassingly old version of it...).
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_conf_globals.h" /* server_argv0. Sigh... */
+#include <dld.h>
+
+/*
+ * The hard part of implementing LoadModule is deciding what to do about
+ * rereading the config files. This proof-of-concept implementation takes the
+ * cheap way out: we only actually load the modules the first time through.
+ */
+
+static int been_there_done_that = 0; /* Loaded the modules yet? */
+static int have_symbol_table = 0;
+
+char *insure_dld_sane()
+{
+ int errcode;
+ char *bin_name;
+
+ if (have_symbol_table) return NULL;
+
+ bin_name = dld_find_executable (server_argv0);
+
+ if ((errcode = dld_init (bin_name))) {
+ dld_perror (server_argv0);
+ return "Cannot find server binary (needed for dynamic linking).";
+ }
+
+ have_symbol_table = 1;
+ return NULL;
+}
+
+char *link_file (pool *p, char *filename)
+{
+ int errcode;
+
+ filename = server_root_relative (p, filename);
+ if ((errcode = dld_link (filename))) {
+ dld_perror (server_argv0);
+ return pstrcat (p, "Cannot load ", filename, " into server", NULL);
+ }
+ return NULL;
+}
+
+char *load_module (cmd_parms *cmd, void *dummy, char *modname, char *filename)
+{
+ char *errname;
+ module *modp;
+
+ if (been_there_done_that) return NULL;
+
+ if ((errname = insure_dld_sane())) return errname;
+ if ((errname = link_file (cmd->pool, filename))) return errname;
+ if (!(modp = (module *)dld_get_symbol (modname))) {
+ return pstrcat (cmd->pool, "Can't find module ", modname,
+ " in file ", filename, NULL);
+ }
+
+ add_module (modp);
+
+ /* Alethea Patch (rws,djw2) - need to run configuration functions
+ in new modules */
+
+ if (modp->create_server_config)
+ ((void**)cmd->server->module_config)[modp->module_index]=
+ (*modp->create_server_config)(cmd->pool, cmd->server);
+
+ if (modp->create_dir_config)
+ ((void**)cmd->server->lookup_defaults)[modp->module_index]=
+ (*modp->create_dir_config)(cmd->pool, NULL);
+
+
+ return NULL;
+}
+
+char *load_file (cmd_parms *cmd, void *dummy, char *filename)
+{
+ char *errname;
+
+ if (been_there_done_that) return NULL;
+
+ if ((errname = insure_dld_sane())) return errname;
+ if ((errname = link_file (cmd->pool, filename))) return errname;
+ return NULL;
+}
+
+void check_loaded_modules (server_rec *dummy, pool *p)
+{
+ if (been_there_done_that) return;
+
+ if (dld_undefined_sym_count > 0) {
+ /* Screwup. Do the best we can to inform the user, and exit */
+ char **bad_syms = dld_list_undefined_sym();
+ int i;
+
+ fprintf(stderr, "Dynamic linking error --- symbols left undefined.\n");
+ fprintf(stderr, "(It may help to relink libraries).\n");
+ fprintf(stderr, "Undefined symbols follow:\n");
+
+ for (i = 0; i < dld_undefined_sym_count; ++i)
+ fprintf (stderr, "%s\n", bad_syms[i]);
+
+ exit (1);
+ }
+
+ been_there_done_that = 1;
+}
+
+command_rec dld_cmds[] = {
+{ "LoadModule", load_module, NULL, RSRC_CONF, TAKE2,
+ "a module name, and the name of a file to load it from"},
+{ "LoadFile", load_file, NULL, RSRC_CONF, ITERATE,
+ "files or libraries to link into the server at runtime"},
+{ NULL }
+};
+
+module dld_module = {
+ STANDARD_MODULE_STUFF,
+ check_loaded_modules, /* initializer */
+ NULL, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ dld_cmds, /* command table */
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * This imagemap module is essentially a port of the original imagemap.c
+ * written by Rob McCool (11/13/93 robm@ncsa.uiuc.edu).
+ * This version includes the mapping algorithms found in version 1.3
+ * of imagemap.c.
+ *
+ * Contributors to this code include:
+ *
+ * Kevin Hughes, kevinh@pulua.hcc.hawaii.edu
+ *
+ * Eric Haines, erich@eye.com
+ * "macmartinized" polygon code copyright 1992 by Eric Haines, erich@eye.com
+ *
+ * Randy Terbush, randy@zyzzyva.com
+ * port to Apache module format, "base_uri" and support for relative URLs
+ *
+ * James H. Cloos, Jr., cloos@jhcloos.com
+ * Added point datatype, using code in NCSA's version 1.8 imagemap.c
+ * program, as distributed with version 1.4.1 of their server.
+ * The point code is originally added by Craig Milo Rogers, Rogers@ISI.Edu
+ *
+ */
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "util_script.h"
+
+#define IMAP_MAGIC_TYPE "application/x-httpd-imap"
+#define MAXLINE 500
+#define MAXVERTS 100
+#define X 0
+#define Y 1
+
+char *getline(char *, int, FILE *);
+
+module imap_module;
+
+int pointinrect(double point[2], double coords[MAXVERTS][2])
+{
+ return ((point[X] >= coords[0][X] && point[X] <= coords[1][X]) &&
+ (point[Y] >= coords[0][Y] && point[Y] <= coords[1][Y]));
+}
+
+int pointincircle(double point[2], double coords[MAXVERTS][2])
+{
+ int radius1, radius2;
+
+ radius1 = ((coords[0][Y] - coords[1][Y]) * (coords[0][Y] - coords[1][Y]))
+ + ((coords[0][X] - coords[1][X]) * (coords[0][X] - coords[1][X]));
+
+ radius2 = ((coords[0][Y] - point[Y]) * (coords[0][Y] - point[Y]))
+ + ((coords[0][X] - point[X]) * (coords[0][X] - point[X]));
+
+ return (radius2 <= radius1);
+}
+
+int pointinpoly(double point[2], double pgon[MAXVERTS][2])
+{
+ int i, numverts, inside_flag, xflag0;
+ int crossings;
+ double *p, *stop;
+ double tx, ty, y;
+
+ for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++);
+
+ numverts = i;
+ crossings = 0;
+
+ tx = point[X];
+ ty = point[Y];
+ y = pgon[numverts - 1][Y];
+
+ p = (double *) pgon + 1;
+ if ((y >= ty) != (*p >= ty)) {
+
+ if ((xflag0 = (pgon[numverts - 1][X] >= tx)) == (*(double *) pgon >= tx)) {
+ if (xflag0)
+ crossings++;
+ }
+ else {
+ crossings += (pgon[numverts - 1][X] - (y - ty) *
+ (*(double *) pgon - pgon[numverts - 1][X]) /
+ (*p - y)) >= tx;
+ }
+ }
+
+ stop = pgon[numverts];
+
+ for (y = *p, p += 2; p < stop; y = *p, p += 2) {
+
+ if (y >= ty) {
+
+ while ((p < stop) && (*p >= ty))
+ p += 2;
+
+ if (p >= stop)
+ break;
+ if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
+
+ if (xflag0)
+ crossings++;
+ }
+ else {
+ crossings += (*(p - 3) - (*(p - 2) - ty) *
+ (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
+ }
+ }
+ else {
+ while ((p < stop) && (*p < ty))
+ p += 2;
+
+ if (p >= stop)
+ break;
+
+ if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) {
+ if (xflag0)
+ crossings++;
+ }
+ else {
+ crossings += (*(p - 3) - (*(p - 2) - ty) *
+ (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx;
+ }
+ }
+ }
+
+ inside_flag = crossings & 0x01;
+ return (inside_flag);
+}
+
+
+void set_redirect (request_rec *r, char *base_uri, char *mapurl) {
+
+ char redirect[MAXLINE];
+ char rooturl[80];
+ char port[40];
+ char *basedir;
+ char *u,*b,*q;
+ int k;
+
+ server_rec *s = r->server;
+
+ if (s->port != 80) {
+
+ sprintf (port, "%d", s->port);
+ sprintf (rooturl, "http://%s:%s", s->server_hostname, port);
+ }
+ else {
+
+ sprintf (rooturl, "http://%s", s->server_hostname);
+ }
+
+ if ((!strncmp (mapurl, "http:", 5 )) ||
+ !strncmp (mapurl, "mailto:", 7) ||
+ !strncmp (mapurl, "ftp:", 4) ||
+ !strncmp (mapurl, "telnet:", 7) ||
+ !strncmp (mapurl, "news:", 5)) {
+
+ strcpy (redirect, mapurl);
+ }
+ else if (*base_uri) {
+
+ while ((u = strstr (mapurl, "..")) != NULL) {
+
+ if ((k = strlen(u)) > 3) {
+ mapurl = u + 3;
+ }
+ else {
+ mapurl = u + k;
+ }
+
+ b = strrchr (base_uri, '/');
+ *b = '\0';
+ }
+
+ b = strrchr (base_uri, '/'); b++;
+ *b = '\0';
+
+ sprintf (redirect, "%s%s", base_uri, mapurl);
+ }
+ else if (mapurl[0] == '/') {
+
+ sprintf (redirect, "%s%s", rooturl, mapurl);
+ }
+ else {
+
+ basedir = r->uri;
+
+ q = strrchr (basedir, '/'); q++;
+ *q = '\0';
+
+ sprintf (redirect, "%s%s%s", rooturl, basedir, mapurl);
+ }
+
+ table_set (r->headers_out, "Location", redirect);
+}
+
+
+int imap_handler (request_rec *r)
+{
+
+ char input[MAXLINE];
+ char mapdflt[MAXLINE];
+ char maptype[MAXLINE];
+ char mapurl[MAXLINE];
+ char base_uri[MAXLINE];
+ char num[10];
+ double testpoint[2], pointarray[MAXVERTS][2];
+ int i, j, k;
+ FILE *imap;
+ char *ycoord;
+ char *referer;
+ double dist = 0;
+ double mindist = 0;
+ int sawpoint = 0;
+
+
+ if (r->args == NULL) { /* Client doesn't support Imagemaps, */
+ testpoint[X] = -1; /* so fake some co-ordinates so that */
+ testpoint[Y] = -1; /* the default is picked. MJC 02Nov95 */
+ } else {
+ if (!(ycoord = strchr (r->args, ',')))
+ return BAD_REQUEST;
+ *ycoord++ = '\0';
+ testpoint[X] = (double) atoi (r->args);
+ testpoint[Y] = (double) atoi (ycoord);
+ }
+
+ if (!(imap = fopen (r->filename,"r")))
+ return SERVER_ERROR;
+
+ referer = table_get (r->headers_in, "Referer");
+ base_uri[0] = '\0';
+
+ while ((getline(input, MAXLINE, imap))) {
+
+ if ((input[0] == '#') || (!input[0]) )
+ continue;
+
+ maptype[0] = '\0';
+ mapurl[0] = '\0';
+
+ for (i = 0; (isalpha(input[i]) || input[i] == '_') && input[i]; i++ )
+ maptype[i] = input[i];
+ maptype[i] = '\0';
+
+ while (isspace(input[i])) ++i;
+
+ for (j = 0; input[i] && !isspace(input[i]); ++i,++j)
+ mapurl[j] = input[i];
+ mapurl[j] = '\0';
+
+ if (!strcmp (maptype, "base_uri")) {
+
+ if (!strcmp (mapurl, "map")) {
+
+ strcpy (base_uri, r->uri);
+ }
+ else if (!strcmp (mapurl, "referer")) {
+
+ if (referer != NULL) {
+
+ strcpy (base_uri, referer);
+ }
+ else {
+ strcpy (base_uri, r->uri);
+ }
+ }
+ else if ((mapurl[0] == '/') || (!strstr (mapurl, "://"))) {
+
+ strcpy (base_uri, mapurl);
+ }
+
+ k = strlen (base_uri);
+ base_uri[k] = '\0';
+ continue;
+ }
+
+ if (!strcmp (maptype, "default")) {
+
+ strcpy (mapdflt, mapurl);
+ continue;
+ }
+
+ k = 0;
+ while (input[i]) {
+
+ while (isspace(input[i]) || input[i] == ',') i++;
+
+ j = 0;
+
+ while (isdigit(input[i]))
+ num[j++] = input[i++];
+
+ num[j] = '\0';
+
+ if (num[0] != '\0') {
+
+ pointarray[k][X] = (double) atoi(num);
+ }
+ else
+ break;
+
+ while (isspace(input[i]) || input[i] == ',') i++;
+
+ j = 0;
+
+ while (isdigit(input[i]))
+ num[j++] = input[i++];
+
+ num[j] = '\0';
+
+ if (num[0] != '\0') {
+ pointarray[k++][Y] = (double) atoi (num);
+ }
+ else {
+ fclose (imap);
+ return SERVER_ERROR;
+ }
+ }
+
+ pointarray[k][X] = -1;
+
+ if (!strcmp (maptype,"poly")) {
+
+ if (pointinpoly (testpoint,pointarray)) {
+ set_redirect (r, base_uri, mapurl);
+ fclose (imap);
+ return REDIRECT;
+ }
+ }
+
+ if (!strcmp (maptype,"circle")) {
+
+ if(pointincircle (testpoint,pointarray)) {
+ set_redirect (r, base_uri, mapurl);
+ fclose (imap);
+ return REDIRECT;
+ }
+ }
+
+ if (!strcmp (maptype,"rect")) {
+
+ if (pointinrect (testpoint,pointarray)) {
+ set_redirect (r, base_uri, mapurl);
+ fclose (imap);
+ return REDIRECT;
+ }
+ }
+ if (!strcmp (maptype,"point")) {
+ /* Don't need to take sqaure root */
+ dist = ((testpoint[X] - pointarray[0][X])
+ * (testpoint[X] - pointarray[0][X]))
+ + ((testpoint[Y] - pointarray[0][Y])
+ * (testpoint[Y] - pointarray[0][Y]));
+ /* If this is the first point, or the nearest, set the default. */
+ if ((! sawpoint) || (dist < mindist)) {
+ mindist = dist;
+ strcpy(mapdflt,mapurl);
+ }
+ sawpoint++;
+ }
+ }
+
+ if (mapdflt[0]) {
+
+ set_redirect (r, base_uri, mapdflt);
+ fclose(imap);
+ return REDIRECT;
+ }
+
+ fclose (imap);
+ return SERVER_ERROR;
+}
+
+handler_rec imap_handlers[] = {
+{ IMAP_MAGIC_TYPE, imap_handler },
+{ NULL }
+};
+
+module imap_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ NULL, /* command table */
+ imap_handlers, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_include.c: Handles the server-parsed HTML documents
+ *
+ * Original by Rob McCool; substantial fixups by David Robinson;
+ * incorporated into the Shambhala module framework by rst.
+ *
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "util_script.h"
+
+#define STARTING_SEQUENCE "<!--#"
+#define ENDING_SEQUENCE "-->"
+#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
+#define DEFAULT_TIME_FORMAT "%A, %d-%b-%y %T %Z"
+#define SIZEFMT_BYTES 0
+#define SIZEFMT_KMG 1
+
+static void decodehtml(char *s);
+static char *get_tag(pool *p, FILE *in, char *tag, int tag_len, int dodecode);
+static int get_directive(FILE *in, char *d);
+
+/* ------------------------ Environment function -------------------------- */
+
+void add_include_vars(request_rec *r, char *timefmt)
+{
+ table *e = r->subprocess_env;
+ char *t;
+ time_t date = time(NULL);
+
+ table_set(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0));
+ table_set(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1));
+ table_set(e, "LAST_MODIFIED",ht_time(r->pool,r->finfo.st_mtime,timefmt,0));
+ table_set(e, "DOCUMENT_URI", r->uri);
+ table_set(e, "DOCUMENT_PATH_INFO", r->path_info);
+ if((t = strrchr(r->filename, '/')))
+ table_set (e, "DOCUMENT_NAME", ++t);
+ else
+ table_set (e, "DOCUMENT_NAME", r->uri);
+}
+
+#define GET_CHAR(f,c,r) \
+ { \
+ int i = getc(f); \
+ if(feof(f) || ferror(f) || (i == -1)) { \
+ fclose(f); \
+ return r; \
+ } \
+ c = (char)i; \
+ }
+
+/* --------------------------- Parser functions --------------------------- */
+
+/* Grrrr... rputc makes this slow as all-get-out. Elsewhere, it doesn't
+ * matter much, but this is an inner loop...
+ */
+
+int find_string(FILE *in,char *str, request_rec *r) {
+ int x,l=strlen(str),p;
+ char c;
+
+ p=0;
+ while(1) {
+ GET_CHAR(in,c,1);
+ if(c == str[p]) {
+ if((++p) == l)
+ return 0;
+ }
+ else {
+ if(r) {
+ if(p) {
+ for(x=0;x<p;x++) {
+ rputc(str[x],r);
+ }
+ }
+ rputc(c,r);
+ }
+ p=0;
+ }
+ }
+}
+
+/*
+ * decodes a string containing html entities or numeric character references.
+ * 's' is overwritten with the decoded string.
+ * If 's' is syntatically incorrect, then the followed fixups will be made:
+ * unknown entities will be left undecoded;
+ * references to unused numeric characters will be deleted.
+ * In particular, � will not be decoded, but will be deleted.
+ *
+ * drtr
+ */
+
+/* maximum length of any ISO-LATIN-1 HTML entity name. */
+#define MAXENTLEN (6)
+
+/* The following is a shrinking transformation, therefore safe. */
+
+static void
+decodehtml(char *s)
+{
+ int val, i, j;
+ char *p=s;
+ char *ents;
+ static char *entlist[MAXENTLEN+1]={
+ NULL, /* 0 */
+ NULL, /* 1 */
+ "lt\074gt\076", /* 2 */
+ "amp\046ETH\320eth\360", /* 3 */
+ "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml\353\
+iuml\357ouml\366uuml\374yuml\377", /* 4 */
+ "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc\333\
+THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352icirc\356ocirc\364\
+ucirc\373thorn\376", /* 5 */
+ "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311\
+Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde\325Oslash\330\
+Ugrave\331Uacute\332Yacute\335agrave\340aacute\341atilde\343ccedil\347\
+egrave\350eacute\351igrave\354iacute\355ntilde\361ograve\362oacute\363\
+otilde\365oslash\370ugrave\371uacute\372yacute\375" /* 6 */
+ };
+
+ for (; *s != '\0'; s++, p++) {
+ if (*s != '&') {
+ *p = *s;
+ continue;
+ }
+ /* find end of entity */
+ for (i=1; s[i] != ';' && s[i] != '\0'; i++)
+ continue;
+
+ if (s[i] == '\0') { /* treat as normal data */
+ *p = *s;
+ continue;
+ }
+
+ /* is it numeric ? */
+ if (s[1] == '#') {
+ for (j=2, val=0; j < i && isdigit(s[j]); j++)
+ val = val * 10 + s[j] - '0';
+ s += i;
+ if (j < i || val <= 8 || (val >= 11 && val <= 31) ||
+ (val >= 127 && val <= 160) || val >= 256)
+ p--; /* no data to output */
+ else
+ *p = val;
+ } else{
+ j = i-1;
+ if (i-1 > MAXENTLEN || entlist[i-1] == NULL) { /* wrong length */
+ *p = '&';
+ continue; /* skip it */
+ }
+ for (ents=entlist[i-1]; *ents != '\0'; ents += i)
+ if (strncmp(s+1, ents, i-1) == 0) break;
+
+ if (*ents == '\0')
+ *p = '&'; /* unknown */
+ else {
+ *p = ((const unsigned char *)ents)[i-1];
+ s += i;
+ }
+ }
+ }
+
+ *p = '\0';
+}
+
+/*
+ * extract the next tag name and value.
+ * if there are no more tags, set the tag name to 'done'
+ * the tag value is html decoded if dodecode is non-zero
+ */
+
+static char *
+get_tag(pool *p, FILE *in, char *tag, int tagbuf_len, int dodecode) {
+ char *t = tag, *tag_val, c, term;
+ int n;
+
+ n = 0;
+
+ do { /* skip whitespace */
+ GET_CHAR(in,c,NULL);
+ } while (isspace(c));
+
+ /* tags can't start with - */
+ if(c == '-') {
+ GET_CHAR(in,c,NULL);
+ if(c == '-') {
+ do {
+ GET_CHAR(in,c,NULL);
+ } while (isspace(c));
+ if(c == '>') {
+ strcpy(tag,"done");
+ return tag;
+ }
+ }
+ return NULL; /* failed */
+ }
+
+ /* find end of tag name */
+ while(1) {
+ if(++n == tagbuf_len) {
+ t[tagbuf_len - 1] = '\0';
+ return NULL;
+ }
+ if(c == '=' || isspace(c)) break;
+ *(t++) = tolower(c);
+ GET_CHAR(in,c,NULL);
+ }
+
+ *t++ = '\0';
+ tag_val = t;
+
+ while (isspace(c)) GET_CHAR(in, c, NULL); /* space before = */
+ if (c != '=') return NULL;
+
+ do {
+ GET_CHAR(in,c,NULL); /* space after = */
+ } while (isspace(c));
+
+ /* we should allow a 'name' as a value */
+
+ if (c != '"' && c != '\'') return NULL;
+ term = c;
+ while(1) {
+ GET_CHAR(in,c,NULL);
+ if(++n == tagbuf_len) {
+ t[tagbuf_len - 1] = '\0';
+ return NULL;
+ }
+ if (c == term) break;
+ *(t++) = c;
+ }
+ *t = '\0';
+ if (dodecode) decodehtml(tag_val);
+ return pstrdup (p, tag_val);
+}
+
+static int
+get_directive(FILE *in, char *d) {
+ char c;
+
+ /* skip initial whitespace */
+ while(1) {
+ GET_CHAR(in,c,1);
+ if(!isspace(c))
+ break;
+ }
+ /* now get directive */
+ while(1) {
+ *d++ = tolower(c);
+ GET_CHAR(in,c,1);
+ if(isspace(c))
+ break;
+ }
+ *d = '\0';
+ return 0;
+}
+
+/* --------------------------- Action handlers ---------------------------- */
+
+int include_cgi(char *s, request_rec *r)
+{
+ request_rec *rr = sub_req_lookup_uri (s, r);
+
+ if (rr->status != 200) return -1;
+
+ /* No hardwired path info or query allowed */
+
+ if ((rr->path_info && rr->path_info[0]) || rr->args) return -1;
+ if (rr->finfo.st_mode == 0) return -1;
+
+ /* Script gets parameters of the *document*, for back compatibility */
+
+ rr->path_info = r->path_info; /* painful to get right; see mod_cgi.c */
+ rr->args = r->args;
+
+ /* Force sub_req to be treated as a CGI request, even if ordinary
+ * typing rules would have called it something else.
+ */
+
+ rr->content_type = CGI_MAGIC_TYPE;
+
+ /* Run it. */
+
+ if (run_sub_req (rr) == REDIRECT) {
+ char *location = table_get (rr->headers_out, "Location");
+ rprintf(r,"<A HREF=\"%s\">%s</A>",location,location);
+ }
+
+ destroy_sub_req (rr);
+
+ return 0;
+}
+
+int handle_include(FILE *in, request_rec *r, char *error, int noexec) {
+ char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN];
+ char *tag_val;
+
+ while(1) {
+ if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
+ return 1;
+ if(!strcmp(tag,"file") || !strcmp (tag, "virtual")) {
+ request_rec *rr=NULL;
+ char *error_fmt = NULL;
+
+ if (tag[0] == 'f')
+ { /* be safe; only files in this directory or below allowed */
+ char tmp[MAX_STRING_LEN+2];
+ sprintf(tmp, "/%s/", tag_val);
+ if (tag_val[0] == '/' || strstr(tmp, "/../") != NULL)
+ error_fmt = "unable to include file %s in parsed file %s";
+ else
+ rr = sub_req_lookup_file (tag_val, r);
+ } else
+ rr = sub_req_lookup_uri (tag_val, r);
+
+ if (!error_fmt && rr->status != 200)
+ error_fmt = "unable to include %s in parsed file %s";
+
+ if (!error_fmt && noexec && rr->content_type
+ && (strncmp (rr->content_type, "text/", 5)))
+ error_fmt =
+ "unable to include potential exec %s in parsed file %s";
+
+ if (!error_fmt && run_sub_req (rr))
+ error_fmt = "unable to include %s in parsed file %s";
+
+ if (error_fmt) {
+ sprintf(errstr, error_fmt, tag_val, r->filename);
+ log_error (errstr, r->server);
+ rprintf(r,"%s",error);
+ }
+
+ if (rr != NULL) destroy_sub_req (rr);
+ }
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else {
+ sprintf(errstr,"unknown parameter %s to tag include in %s",tag,
+ r->filename);
+ log_error (errstr, r->server);
+ rprintf(r,"%s",error);
+ }
+ }
+}
+
+typedef struct {
+ request_rec *r;
+ char *s;
+} include_cmd_arg;
+
+void include_cmd_child (void *arg)
+{
+ request_rec *r = ((include_cmd_arg *)arg)->r;
+ char *s = ((include_cmd_arg *)arg)->s;
+ table *env = r->subprocess_env;
+#ifdef DEBUG_INCLUDE_CMD
+ FILE *dbg = fopen ("/dev/tty", "w");
+#endif
+ char err_string [MAX_STRING_LEN];
+
+#ifdef DEBUG_INCLUDE_CMD
+ fprintf (dbg, "Attempting to include command '%s'\n", s);
+#endif
+
+ if (r->path_info && r->path_info[0] != '\0')
+ {
+ request_rec *pa_req;
+
+ table_set (env, "PATH_INFO", escape_shell_cmd (r->pool, r->path_info));
+
+ pa_req = sub_req_lookup_uri(escape_uri(r->pool, r->path_info), r);
+ if (pa_req->filename)
+ table_set(env, "PATH_TRANSLATED",
+ pstrcat(r->pool, pa_req->filename, pa_req->path_info,
+ NULL));
+ }
+
+ if (r->args) {
+ table_set (env, "QUERY_STRING", r->args);
+ unescape_url (r->args);
+ table_set (env, "QUERY_STRING_UNESCAPED",
+ escape_shell_cmd (r->pool, r->args));
+ }
+
+ error_log2stderr (r->server);
+
+#ifdef DEBUG_INCLUDE_CMD
+ fprintf (dbg, "Attempting to exec '%s'\n", s);
+#endif
+ cleanup_for_exec();
+ execle(SHELL_PATH, SHELL_PATH, "-c", s, NULL,
+ create_environment (r->pool, env));
+
+ /* Oh, drat. We're still here. The log file descriptors are closed,
+ * so we have to whimper a complaint onto stderr...
+ */
+
+#ifdef DEBUG_INCLUDE_CMD
+ fprintf (dbg, "Exec failed\n");
+#endif
+ sprintf(err_string, "httpd: exec of %s failed, errno is %d\n",
+ SHELL_PATH,errno);
+ write (2, err_string, strlen(err_string));
+ exit(0);
+}
+
+int include_cmd(char *s, request_rec *r) {
+ include_cmd_arg arg;
+ FILE *f;
+
+ arg.r = r; arg.s = s;
+
+ if (!spawn_child (r->connection->pool, include_cmd_child, &arg,
+ kill_after_timeout, NULL, &f))
+ return -1;
+
+ send_fd(f,r);
+ pfclose(r->pool, f); /* will wait for zombie when
+ * r->pool is cleared
+ */
+ return 0;
+}
+
+
+int handle_exec(FILE *in, request_rec *r, char *error)
+{
+ char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN];
+ char *tag_val;
+ char *file = r->filename;
+
+ while(1) {
+ if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
+ return 1;
+ if(!strcmp(tag,"cmd")) {
+ if(include_cmd(tag_val, r) == -1) {
+ sprintf(errstr,"failed command exec %s in %s",tag_val,file);
+ log_error (errstr, r->server);
+ rprintf(r,"%s",error);
+ }
+ /* just in case some stooge changed directories */
+ chdir_file(r->filename);
+ }
+ else if(!strcmp(tag,"cgi")) {
+ if(include_cgi(tag_val, r) == -1) {
+ sprintf(errstr,"invalid CGI ref %s in %s",tag_val,file);
+ log_error (errstr, r->server);
+ rprintf(r,"%s",error);
+ }
+ /* grumble groan */
+ chdir_file(r->filename);
+ }
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else {
+ char errstr[MAX_STRING_LEN];
+ sprintf(errstr,"unknown parameter %s to tag exec in %s",tag,file);
+ log_error (errstr, r->server);
+ rprintf(r, "%s",error);
+ }
+ }
+
+}
+
+int handle_echo (FILE *in, request_rec *r, char *error) {
+ char tag[MAX_STRING_LEN];
+ char *tag_val;
+
+ while(1) {
+ if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
+ return 1;
+ if(!strcmp(tag,"var")) {
+ char *val = table_get (r->subprocess_env, tag_val);
+
+ if (val) rprintf (r, "%s", val);
+ else rprintf (r, "(none)");
+ } else if(!strcmp(tag,"done"))
+ return 0;
+ else {
+ char errstr[MAX_STRING_LEN];
+ sprintf(errstr,"unknown parameter %s to tag echo in %s",
+ tag, r->filename);
+ log_error(errstr, r->server);
+ rprintf (r, "%s", error);
+ }
+ }
+}
+
+int handle_config(FILE *in, request_rec *r, char *error, char *tf,
+ int *sizefmt) {
+ char tag[MAX_STRING_LEN];
+ char *tag_val;
+ table *env = r->subprocess_env;
+
+ while(1) {
+ if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0)))
+ return 1;
+ if(!strcmp(tag,"errmsg"))
+ strcpy(error,tag_val);
+ else if(!strcmp(tag,"timefmt")) {
+ time_t date = time(NULL);
+ strcpy(tf,tag_val);
+ table_set (env, "DATE_LOCAL", ht_time(r->pool,date,tf,0));
+ table_set (env, "DATE_GMT", ht_time(r->pool,date,tf,1));
+ table_set (env, "LAST_MODIFIED", ht_time(r->pool,r->finfo.st_mtime,tf,0));
+ }
+ else if(!strcmp(tag,"sizefmt")) {
+ decodehtml(tag_val);
+ if(!strcmp(tag_val,"bytes"))
+ *sizefmt = SIZEFMT_BYTES;
+ else if(!strcmp(tag_val,"abbrev"))
+ *sizefmt = SIZEFMT_KMG;
+ }
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else {
+ char errstr[MAX_STRING_LEN];
+ sprintf(errstr,"unknown parameter %s to tag config in %s",
+ tag, r->filename);
+ log_error(errstr, r->server);
+ rprintf (r,"%s",error);
+ }
+ }
+}
+
+
+
+int find_file(request_rec *r, char *directive, char *tag,
+ char *tag_val, struct stat *finfo, char *error)
+{
+ char errstr[MAX_STRING_LEN], dir[MAX_STRING_LEN];
+ char *to_send;
+
+ if(!strcmp(tag,"file")) {
+ getparents(tag_val); /* get rid of any nasties */
+ getwd(dir);
+ to_send = make_full_path (r->pool, dir, tag_val);
+ if(stat(to_send,finfo) == -1) {
+ sprintf(errstr,
+ "unable to get information about %s in parsed file %s",
+ to_send, r->filename);
+ log_error (errstr, r->server);
+ rprintf (r,"%s",error);
+ return -1;
+ }
+ return 0;
+ }
+ else if(!strcmp(tag,"virtual")) {
+ request_rec *rr = sub_req_lookup_uri (tag_val, r);
+
+ if (rr->status == 200 && rr->finfo.st_mode != 0) {
+ memcpy ((char*)finfo, (const char *)&rr->finfo, sizeof (struct stat));
+ destroy_sub_req (rr);
+ return 0;
+ } else {
+ sprintf(errstr,
+ "unable to get information about %s in parsed file %s",
+ tag_val, r->filename);
+ log_error(errstr, r->server);
+ rprintf(r,"%s",error);
+ destroy_sub_req (rr);
+ return -1;
+ }
+ }
+ else {
+ sprintf(errstr,"unknown parameter %s to tag %s in %s",
+ tag, directive, r->filename);
+ log_error(errstr, r->server);
+ rprintf(r,"%s",error);
+ return -1;
+ }
+}
+
+
+int handle_fsize(FILE *in, request_rec *r, char *error, int sizefmt)
+{
+ char tag[MAX_STRING_LEN];
+ char *tag_val;
+ struct stat finfo;
+
+ while(1) {
+ if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
+ return 1;
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else if(!find_file(r,"fsize",tag,tag_val,&finfo,error)) {
+ if(sizefmt == SIZEFMT_KMG) {
+ send_size(finfo.st_size, r);
+ }
+ else {
+ int l,x;
+#if defined(BSD) && BSD > 199305
+ sprintf(tag,"%qd",finfo.st_size);
+#else
+ sprintf(tag,"%ld",finfo.st_size);
+#endif
+ l = strlen(tag); /* grrr */
+ for(x=0;x<l;x++) {
+ if(x && (!((l-x) % 3))) {
+ rputc(',', r);
+ }
+ rputc (tag[x],r);
+ }
+ }
+ }
+ }
+}
+
+int handle_flastmod(FILE *in, request_rec *r, char *error, char *tf)
+{
+ char tag[MAX_STRING_LEN];
+ char *tag_val;
+ struct stat finfo;
+
+ while(1) {
+ if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
+ return 1;
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else if(!find_file(r,"flastmod",tag,tag_val,&finfo,error))
+ rprintf (r, "%s", ht_time(r->pool, finfo.st_mtime, tf, 0));
+ }
+}
+
+
+
+/* -------------------------- The main function --------------------------- */
+
+/* This is a stub which parses a file descriptor. */
+
+void send_parsed_content(FILE *f, request_rec *r)
+{
+ char directive[MAX_STRING_LEN], error[MAX_STRING_LEN];
+ char timefmt[MAX_STRING_LEN], errstr[MAX_STRING_LEN];
+ int noexec = allow_options (r) & OPT_INCNOEXEC;
+ int ret, sizefmt;
+
+ strcpy(error,DEFAULT_ERROR_MSG);
+ strcpy(timefmt,DEFAULT_TIME_FORMAT);
+ sizefmt = SIZEFMT_KMG;
+
+ chdir_file (r->filename);
+
+ while(1) {
+ if(!find_string(f,STARTING_SEQUENCE,r)) {
+ if(get_directive(f,directive))
+ return;
+ if(!strcmp(directive,"exec")) {
+ if(noexec) {
+ sprintf(errstr,"httpd: exec used but not allowed in %s",
+ r->filename);
+ log_error (errstr, r->server);
+ rprintf(r,"%s",error);
+ ret = find_string(f,ENDING_SEQUENCE,NULL);
+ } else
+ ret=handle_exec(f, r, error);
+ }
+ else if(!strcmp(directive,"config"))
+ ret=handle_config(f, r, error, timefmt, &sizefmt);
+ else if(!strcmp(directive,"include"))
+ ret=handle_include(f, r, error, noexec);
+ else if(!strcmp(directive,"echo"))
+ ret=handle_echo(f, r, error);
+ else if(!strcmp(directive,"fsize"))
+ ret=handle_fsize(f, r, error, sizefmt);
+ else if(!strcmp(directive,"flastmod"))
+ ret=handle_flastmod(f, r, error, timefmt);
+ else {
+ sprintf(errstr,"httpd: unknown directive %s in parsed doc %s",
+ directive,r->filename);
+ log_error (errstr, r->server);
+ rprintf (r,"%s",error);
+ ret=find_string(f,ENDING_SEQUENCE,NULL);
+ }
+ if(ret) {
+ sprintf(errstr,"httpd: premature EOF in parsed file %s",
+ r->filename);
+ log_error(errstr, r->server);
+ return;
+ }
+ } else
+ return;
+ }
+}
+
+/*****************************************************************
+ *
+ * XBITHACK. Sigh... NB it's configurable per-directory; the compile-time
+ * option only changes the default.
+ */
+
+module includes_module;
+enum xbithack { xbithack_off, xbithack_on, xbithack_full };
+
+#ifdef XBITHACK
+#define DEFAULT_XBITHACK xbithack_full
+#else
+#define DEFAULT_XBITHACK xbithack_off
+#endif
+
+void *create_includes_dir_config (pool *p, char *dummy)
+{
+ enum xbithack *result = (enum xbithack*)palloc(p, sizeof (enum xbithack));
+ *result = DEFAULT_XBITHACK;
+ return result;
+}
+
+char *set_xbithack (cmd_parms *cmd, void *xbp, char *arg)
+{
+ enum xbithack *state = (enum xbithack *)xbp;
+
+ if (!strcasecmp (arg, "off")) *state = xbithack_off;
+ else if (!strcasecmp (arg, "on")) *state = xbithack_on;
+ else if (!strcasecmp (arg, "full")) *state = xbithack_full;
+ else return "XBitHack must be set to Off, On, or Full";
+
+ return NULL;
+}
+
+int send_parsed_file(request_rec *r)
+{
+ FILE *f;
+ enum xbithack *state =
+ (enum xbithack *)get_module_config(r->per_dir_config,&includes_module);
+ int errstatus;
+
+ if (!(allow_options (r) & OPT_INCLUDES)) return DECLINED;
+ if (r->method_number != M_GET) return DECLINED;
+ if (r->finfo.st_mode == 0) return NOT_FOUND;
+
+ if (*state == xbithack_full
+ && (r->finfo.st_mode & S_IXGRP)
+ && (errstatus = set_last_modified (r, r->finfo.st_mtime)))
+ return errstatus;
+
+ if(!(f=pfopen(r->pool, r->filename, "r"))) {
+ log_reason("file permissions deny server access", r->filename, r);
+ return FORBIDDEN;
+ }
+
+ r->content_type = "text/html";
+
+ hard_timeout ("send", r);
+ send_http_header(r);
+
+ if (r->header_only) {
+ kill_timeout (r);
+ pfclose (r->pool, f);
+ return OK;
+ }
+
+ if (r->main) {
+ /* Kludge --- for nested includes, we want to keep the
+ * subprocess environment of the base document (for compatibility);
+ * that means torquing our own last_modified date as well so that
+ * the LAST_MODIFIED variable gets reset to the proper value if
+ * the nested document resets <!--#config timefmt-->
+ */
+ r->subprocess_env = r->main->subprocess_env;
+ r->finfo.st_mtime= r->main->finfo.st_mtime;
+ } else {
+ add_common_vars (r);
+ add_include_vars (r, DEFAULT_TIME_FORMAT);
+ }
+
+ send_parsed_content (f, r);
+
+ kill_timeout (r);
+ return OK;
+}
+
+int xbithack_handler (request_rec *r)
+{
+ enum xbithack *state;
+
+ if (!(r->finfo.st_mode & S_IXUSR)) return DECLINED;
+
+ state = (enum xbithack *)get_module_config(r->per_dir_config,
+ &includes_module);
+
+ if (*state == xbithack_off) return DECLINED;
+ return send_parsed_file (r);
+}
+
+command_rec includes_cmds[] = {
+{ "XBitHack", set_xbithack, NULL, OR_OPTIONS, TAKE1, "Off, On, or Full" },
+{ NULL }
+};
+
+handler_rec includes_handlers[] = {
+{ INCLUDES_MAGIC_TYPE, send_parsed_file },
+{ INCLUDES_MAGIC_TYPE3, send_parsed_file },
+{ "*/*", xbithack_handler },
+{ NULL }
+};
+
+module includes_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ create_includes_dir_config, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ includes_cmds, /* command table */
+ includes_handlers, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+#include "httpd.h"
+#include "http_config.h"
+
+#define DEFAULT_AGENTLOG "logs/agent_log"
+
+module agent_log_module;
+
+static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+
+typedef struct {
+ char *fname;
+ int agent_fd;
+} agent_log_state;
+
+void *make_agent_log_state (pool *p, server_rec *s)
+{
+ agent_log_state *cls =
+ (agent_log_state *)palloc (p, sizeof (agent_log_state));
+
+ cls->fname = DEFAULT_AGENTLOG;
+ cls->agent_fd = -1;
+
+
+ return (void *)cls;
+}
+
+char *set_agent_log (cmd_parms *parms, void *dummy, char *arg)
+{
+ agent_log_state *cls = get_module_config (parms->server->module_config,
+ &agent_log_module);
+
+ cls->fname = arg;
+ return NULL;
+}
+
+command_rec agent_log_cmds[] = {
+{ "AgentLog", set_agent_log, NULL, RSRC_CONF, TAKE1,
+ "the filename of the agent log" },
+{ NULL }
+};
+
+void agent_log_child (void *cmd)
+{
+ /* Child process code for 'AgentLog "|..."';
+ * may want a common framework for this, since I expect it will
+ * be common for other foo-loggers to want this sort of thing...
+ */
+
+ cleanup_for_exec();
+ signal (SIGHUP, SIG_IGN);
+ execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+ exit (1);
+}
+
+void open_agent_log (server_rec *s, pool *p)
+{
+ agent_log_state *cls = get_module_config (s->module_config,
+ &agent_log_module);
+
+ char *fname = server_root_relative (p, cls->fname);
+
+ if (cls->agent_fd > 0) return; /* virtual log shared w/main server */
+
+ if (*cls->fname == '|') {
+ FILE *dummy;
+
+ spawn_child(p, agent_log_child, (void *)(cls->fname+1),
+ kill_after_timeout, &dummy, NULL);
+
+ if (dummy == NULL) {
+ fprintf (stderr, "Couldn't fork child for AgentLog process\n");
+ exit (1);
+ }
+
+ cls->agent_fd = fileno (dummy);
+ }
+ else if((cls->agent_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
+ fprintf(stderr,"httpd: could not open transfer log file %s.\n", fname);
+ perror("open");
+ exit(1);
+ }
+}
+
+void init_agent_log (server_rec *s, pool *p)
+{
+ for (; s; s = s->next) open_agent_log (s, p);
+}
+
+int agent_log_transaction(request_rec *orig)
+{
+ agent_log_state *cls = get_module_config (orig->server->module_config,
+ &agent_log_module);
+
+ char str[HUGE_STRING_LEN];
+ char *agent;
+ request_rec *r;
+
+ if(cls->agent_fd <0)
+ return OK;
+
+ for (r = orig; r->next; r = r->next)
+ continue;
+
+ agent = table_get(orig->headers_in, "User-Agent");
+ if(agent != NULL)
+ {
+ sprintf(str, "%s\n", agent);
+ write(cls->agent_fd, str, strlen(str));
+ }
+
+ return OK;
+}
+
+module agent_log_module = {
+ STANDARD_MODULE_STUFF,
+ init_agent_log, /* initializer */
+ NULL, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ make_agent_log_state, /* server config */
+ NULL, /* merge server config */
+ agent_log_cmds, /* command table */
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ agent_log_transaction /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * This is an EXPERIMENTAL module, which implements the TransferLog directive
+ * (same as the common log module), and an additional directive, LogFormat.
+ * Bugs would not surprise me.
+ *
+ * The argument to LogFormat is a string, which can include literal
+ * characters copied into the log files, and '%' directives as follows:
+ *
+ * %...h: remote host
+ * %...l: remote logname (from identd, if supplied)
+ * %...u: remote user (from auth; may be bogus if return status (%s) is 401)
+ * %...t: time, in common log format time format
+ * %...r: first line of request
+ * %...s: status. For requests that got internally redirected, this
+ * is status of the *original* request --- %...>s for the last.
+ * %...b: bytes sent.
+ * %...{Foobar}i: The contents of Foobar: header line(s) in the request
+ * sent to the client.
+ * %...{Foobar}o: The contents of Foobar: header line(s) in the reply.
+ *
+ * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
+ * indicate conditions for inclusion of the item (which will cause it
+ * to be replaced with '-' if the condition is not met). Note that
+ * there is no escaping performed on the strings from %r, %...i and
+ * %...o; some with long memories may remember that I thought this was
+ * a bad idea, once upon a time, and I'm still not comfortable with
+ * it, but it is difficult to see how to "do the right thing" with all
+ * of '%..i', unless we URL-escape everything and break with CLF.
+ *
+ * The forms of condition are a list of HTTP status codes, which may
+ * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs
+ * User-agent: on 400 errors and 501 errors (Bad Request, Not
+ * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
+ * requests which did *not* return some sort of normal status.
+ *
+ * The default LogFormat reproduces CLF; see below.
+ *
+ * The way this is supposed to work with virtual hosts is as follows:
+ * a virtual host can have its own LogFormat, or its own TransferLog.
+ * If it doesn't have its own LogFormat, it inherits from the main
+ * server. If it doesn't have its own TransferLog, it writes to the
+ * same descriptor (meaning the same process for "| ...").
+ *
+ * That means that you can do things like:
+ *
+ * <VirtualHost hosta.com>
+ * LogFormat "hosta ..."
+ * ...
+ * </VirtualHost>
+ *
+ * <VirtualHost hosta.com>
+ * LogFormat "hostb ..."
+ * ...
+ * </VirtualHost>
+ *
+ * ... to have different virtual servers write into the same log file,
+ * but have some indication which host they came from, though a %v
+ * directive may well be a better way to handle this.
+ *
+ * --- rst
+ */
+
+#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %s %b"
+
+#include "httpd.h"
+#include "http_config.h"
+
+module config_log_module;
+
+static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+
+typedef struct {
+ char *fname;
+ array_header *format;
+ int log_fd;
+} config_log_state;
+
+/*
+ * Format items...
+ */
+
+typedef char *(*item_key_func)(request_rec *, char *);
+
+typedef struct {
+ item_key_func func;
+ char *arg;
+ int condition_sense;
+ int want_orig;
+ array_header *conditions;
+} log_format_item;
+
+char *format_integer(pool *p, int i)
+{
+ char dummy[40];
+ sprintf (dummy, "%d", i);
+ return pstrdup (p, dummy);
+}
+
+static char *pfmt(pool *p, int i)
+{
+ if (i <= 0) return "-";
+ else return format_integer (p, i);
+}
+
+char *constant_item (request_rec *dummy, char *stuff) { return stuff; }
+
+char *log_remote_host (request_rec *r, char *a)
+{ return r->connection->remote_name; }
+
+char *log_remote_logname(request_rec *r, char *a)
+{return r->connection->remote_logname;}
+
+char *log_remote_user (request_rec *r, char *a)
+{ return r->connection->user; }
+
+char *log_request_line (request_rec *r, char *a)
+{ return r->the_request; }
+
+char *log_status (request_rec *r, char *a)
+{ return pfmt(r->pool, r->status); }
+
+char *log_bytes_sent (request_rec *r, char *a)
+{ return pfmt (r->pool, r->bytes_sent); }
+
+char *log_header_in (request_rec *r, char *a)
+{ return table_get (r->headers_in, a); }
+
+char *log_header_out (request_rec *r, char *a)
+{
+ char *cp = table_get (r->headers_out, a);
+ if (cp) return cp;
+ return table_get (r->err_headers_out, a);
+}
+
+char *log_env_var (request_rec *r, char *a)
+{ return table_get (r->subprocess_env, a); }
+
+char *log_request_time (request_rec *r, char *a)
+{
+ long timz;
+ struct tm *t;
+ char tstr[MAX_STRING_LEN],sign;
+
+ t = get_gmtoff(&timz);
+ sign = (timz < 0 ? '-' : '+');
+ if(timz < 0)
+ timz = -timz;
+
+ strftime(tstr,MAX_STRING_LEN,"[%d/%b/%Y:%H:%M:%S ",t);
+
+ sprintf (tstr + strlen(tstr), "%c%02ld%02ld]",
+ sign, timz/3600, timz%3600);
+
+ return pstrdup (r->pool, tstr);
+}
+
+/*****************************************************************
+ *
+ * Parsing the log format string
+ */
+
+struct log_item_list {
+ char ch;
+ item_key_func func;
+ int want_orig_default;
+} log_item_keys[] = {
+ { 'h', log_remote_host, 0 },
+ { 'l', log_remote_logname, 0 },
+ { 'u', log_remote_user, 0 },
+ { 't', log_request_time, 0 },
+ { 'r', log_request_line, 1 },
+ { 's', log_status, 1 },
+ { 'b', log_bytes_sent, 0 },
+ { 'i', log_header_in, 0 },
+ { 'o', log_header_out, 0 },
+ { 'e', log_env_var, 0 },
+ { '\0' }
+};
+
+struct log_item_list *find_log_func (char k)
+{
+ int i;
+
+ for (i = 0; log_item_keys[i].ch; ++i)
+ if (k == log_item_keys[i].ch)
+ return &log_item_keys[i];
+
+ return NULL;
+}
+
+char *log_format_substring (pool *p, char *start, char *end)
+{
+ char *res = palloc (p, end - start + 1);
+ strncpy (res, start, end - start);
+ res[end - start] = '\0';
+ return res;
+}
+
+char *parse_log_misc_string (pool *p, log_format_item *it, char **sa)
+{
+ char *s = *sa;
+
+ it->func = constant_item;
+ it->conditions = NULL;
+
+ while (*s && *s != '%') ++s;
+ it->arg = log_format_substring (p, *sa, s);
+ *sa = s;
+
+ return NULL;
+}
+
+char *parse_log_item (pool *p, log_format_item *it, char **sa)
+{
+ char *s = *sa;
+ if (*s != '%') return parse_log_misc_string (p, it, sa);
+
+ ++s;
+ it->condition_sense = 0;
+ it->conditions = NULL;
+ it->want_orig = -1;
+ it->arg = ""; /* For safety's sake... */
+
+ while (*s) {
+ int i;
+ struct log_item_list *l;
+
+ switch (*s) {
+ case '!':
+ ++s;
+ it->condition_sense = !it->condition_sense;
+ break;
+
+ case '<':
+ ++s;
+ it->want_orig = 1;
+ break;
+
+ case '>':
+ ++s;
+ it->want_orig = 0;
+ break;
+
+ case ',':
+ ++s;
+ break;
+
+ case '{':
+ ++s;
+ it->arg = getword (p, &s, '}');
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ i = *s - '0';
+ while (isdigit (*++s)) i = i * 10 + (*s) - '0';
+ if (!it->conditions)
+ it->conditions = make_array (p, 4, sizeof(int));
+ *(int *)push_array(it->conditions) = i;
+ break;
+
+ default:
+ l = find_log_func (*s++);
+ if (!l) {
+ char dummy[] = { '\0', '\0'};
+ dummy[0] = s[-1];
+ return pstrcat (p, "Unrecognized LogFormat directive %",
+ dummy, NULL);
+ }
+ it->func = l->func;
+ if (it->want_orig == -1) it->want_orig = l->want_orig_default;
+ *sa = s;
+ return NULL;
+ }
+ }
+
+ return "Ran off end of LogFormat parsing args to some directive";
+}
+
+array_header *parse_log_string (pool *p, char *s, char **err)
+{
+ array_header *a = make_array (p, 30, sizeof (log_format_item));
+ char *res;
+
+ while (*s) {
+ if ((res = parse_log_item (p, (log_format_item *)push_array(a), &s))) {
+ *err = res;
+ return NULL;
+ }
+ }
+
+ s = "\n";
+ parse_log_item (p, (log_format_item *)push_array(a), &s);
+ return a;
+}
+
+/*****************************************************************
+ *
+ * Actually logging.
+ */
+
+char *process_item(request_rec *r, request_rec *orig, log_format_item *item)
+{
+ char *cp;
+
+ /* First, see if we need to process this thing at all... */
+
+ if (item->conditions && item->conditions->nelts != 0) {
+ int i;
+ int *conds = (int *)item->conditions->elts;
+ int in_list = 0;
+
+ for (i = 0; i < item->conditions->nelts; ++i)
+ if (r->status == conds[i]) {
+ in_list = 1;
+ break;
+ }
+
+ if ((item->condition_sense && in_list)
+ || (!item->condition_sense && !in_list))
+ {
+ return "-";
+ }
+ }
+
+ /* We do. Do it... */
+
+ cp = (*item->func)(item->want_orig ? orig : r, item->arg);
+ return cp ? cp : "-";
+}
+
+int config_log_transaction(request_rec *r)
+{
+ config_log_state *cls = get_module_config (r->server->module_config,
+ &config_log_module);
+
+ array_header *strsa= make_array(r->pool, cls->format->nelts,sizeof(char*));
+ log_format_item *items = (log_format_item *)cls->format->elts;
+ char *str, **strs, *s;
+ request_rec *orig;
+ int i;
+ int len = 0;
+
+ orig = r;
+ while (orig->prev) orig = orig->prev;
+ while (r->next) r = r->next;
+
+ for (i = 0; i < cls->format->nelts; ++i)
+ *((char**)push_array (strsa)) = process_item (r, orig, &items[i]);
+
+ strs = (char **)strsa->elts;
+
+ for (i = 0; i < cls->format->nelts; ++i)
+ len += strlen (strs[i]);
+
+ str = palloc (r->pool, len + 1);
+
+ for (i = 0, s = str; i < cls->format->nelts; ++i) {
+ strcpy (s, strs[i]);
+ s += strlen (strs[i]);
+ }
+
+ write(cls->log_fd, str, strlen(str));
+
+ return OK;
+}
+
+/*****************************************************************
+ *
+ * Module glue...
+ */
+
+void *make_config_log_state (pool *p, server_rec *s)
+{
+ config_log_state *cls =
+ (config_log_state *)palloc (p, sizeof (config_log_state));
+
+ cls->fname = NULL;
+ cls->format = NULL;
+ cls->log_fd = -1;
+
+ return (void *)cls;
+}
+
+char *set_config_log (cmd_parms *parms, void *dummy, char *arg)
+{
+ config_log_state *cls = get_module_config (parms->server->module_config,
+ &config_log_module);
+
+ cls->fname = arg;
+ return NULL;
+}
+
+char *log_format (cmd_parms *cmd, void *dummy, char *arg)
+{
+ char *err_string = NULL;
+ config_log_state *cls = get_module_config (cmd->server->module_config,
+ &config_log_module);
+
+ cls->format = parse_log_string (cmd->pool, arg, &err_string);
+ return err_string;
+}
+
+command_rec config_log_cmds[] = {
+{ "TransferLog", set_config_log, NULL, RSRC_CONF, TAKE1,
+ "the filename of the access log" },
+{ "LogFormat", log_format, NULL, RSRC_CONF, TAKE1,
+ "a log format string (see docs)" },
+{ NULL }
+};
+
+void config_log_child (void *cmd)
+{
+ /* Child process code for 'TransferLog "|..."';
+ * may want a common framework for this, since I expect it will
+ * be common for other foo-loggers to want this sort of thing...
+ */
+
+ cleanup_for_exec();
+ signal (SIGHUP, SIG_IGN);
+ execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+ fprintf (stderr, "Exec of shell for logging failed!!!\n");
+ exit (1);
+}
+
+config_log_state *open_config_log (server_rec *s, pool *p,
+ config_log_state *defaults)
+{
+ config_log_state *cls = get_module_config (s->module_config,
+ &config_log_module);
+
+ if (cls->log_fd > 0) return cls; /* virtual config shared w/main server */
+
+ if (cls->format == NULL) {
+ char *dummy;
+
+ if (defaults) cls->format = defaults->format;
+ else cls->format = parse_log_string (p, DEFAULT_LOG_FORMAT, &dummy);
+ }
+
+ if (cls->fname == NULL) {
+ if (defaults) {
+ cls->log_fd = defaults->log_fd;
+ return cls;
+ }
+ else cls->fname = DEFAULT_XFERLOG;
+ }
+
+ if (*cls->fname == '|') {
+ FILE *dummy;
+
+ spawn_child(p, config_log_child, (void *)(cls->fname+1),
+ kill_after_timeout, &dummy, NULL);
+
+ if (dummy == NULL) {
+ fprintf (stderr, "Couldn't fork child for TransferLog process\n");
+ exit (1);
+ }
+
+ cls->log_fd = fileno (dummy);
+ }
+ else {
+ char *fname = server_root_relative (p, cls->fname);
+ if((cls->log_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
+ fprintf (stderr,
+ "httpd: could not open transfer log file %s.\n", fname);
+ perror("open");
+ exit(1);
+ }
+ }
+
+ return cls;
+}
+
+void init_config_log (server_rec *s, pool *p)
+{
+ /* First, do "physical" server, which gets default log fd and format
+ * for the virtual servers, if they don't override...
+ */
+
+ config_log_state *default_conf = open_config_log (s, p, NULL);
+
+ /* Then, virtual servers */
+
+ for (s = s->next; s; s = s->next) open_config_log (s, p, default_conf);
+}
+
+module config_log_module = {
+ STANDARD_MODULE_STUFF,
+ init_config_log, /* initializer */
+ NULL, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ make_config_log_state, /* server config */
+ NULL, /* merge server config */
+ config_log_cmds, /* command table */
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ config_log_transaction /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+
+#include "httpd.h"
+#include "http_config.h"
+
+#define DEFAULT_REFERERLOG "logs/referer_log"
+
+module referer_log_module;
+
+static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT );
+static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
+
+typedef struct {
+ char *fname;
+ int referer_fd;
+ array_header *referer_ignore_list;
+} referer_log_state;
+
+void *make_referer_log_state (pool *p, server_rec *s)
+{
+ referer_log_state *cls =
+ (referer_log_state *)palloc (p, sizeof (referer_log_state));
+
+ cls->fname = DEFAULT_REFERERLOG;
+ cls->referer_fd = -1;
+ cls->referer_ignore_list = make_array(p, 1, sizeof(char *));
+ return (void *)cls;
+}
+
+char *set_referer_log (cmd_parms *parms, void *dummy, char *arg)
+{
+ referer_log_state *cls = get_module_config (parms->server->module_config,
+ &referer_log_module);
+
+ cls->fname = arg;
+ return NULL;
+}
+
+char *add_referer_ignore (cmd_parms *parms, void *dummy, char *arg)
+{
+ char **addme;
+ referer_log_state *cls = get_module_config (parms->server->module_config,
+ &referer_log_module);
+
+ addme = push_array(cls->referer_ignore_list);
+ *addme = pstrdup(cls->referer_ignore_list->pool, arg);
+ return NULL;
+}
+
+command_rec referer_log_cmds[] = {
+{ "RefererLog", set_referer_log, NULL, RSRC_CONF, TAKE1,
+ "the filename of the referer log" },
+{ "RefererIgnore", add_referer_ignore, NULL, RSRC_CONF, ITERATE,
+ "referer hostnames to ignore" },
+{ NULL }
+};
+
+void referer_log_child (void *cmd)
+{
+ /* Child process code for 'RefererLog "|..."';
+ * may want a common framework for this, since I expect it will
+ * be common for other foo-loggers to want this sort of thing...
+ */
+
+ cleanup_for_exec();
+ signal (SIGHUP, SIG_IGN);
+ execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+ fprintf (stderr, "Exec of shell for logging failed!!!\n");
+ exit (1);
+}
+
+void open_referer_log (server_rec *s, pool *p)
+{
+ referer_log_state *cls = get_module_config (s->module_config,
+ &referer_log_module);
+
+ char *fname = server_root_relative (p, cls->fname);
+
+ if (cls->referer_fd > 0) return; /* virtual log shared w/main server */
+
+ if (*cls->fname == '|') {
+ FILE *dummy;
+
+ spawn_child(p, referer_log_child, (void *)(cls->fname+1),
+ kill_after_timeout, &dummy, NULL);
+
+ if (dummy == NULL) {
+ fprintf (stderr, "Couldn't fork child for RefererLog process\n");
+ exit (1);
+ }
+
+ cls->referer_fd = fileno (dummy);
+ }
+ else if((cls->referer_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
+ fprintf(stderr,"httpd: could not open transfer log file %s.\n", fname);
+ perror("open");
+ exit(1);
+ }
+}
+
+void init_referer_log (server_rec *s, pool *p)
+{
+ for (; s; s = s->next) open_referer_log (s, p);
+}
+
+int referer_log_transaction(request_rec *orig)
+{
+ char **ptrptr, **ptrptr2;
+ referer_log_state *cls = get_module_config (orig->server->module_config,
+ &referer_log_module);
+
+ char str[HUGE_STRING_LEN];
+ char *referer;
+ request_rec *r;
+
+ if(cls->referer_fd <0)
+ return OK;
+
+ for (r = orig; r->next; r = r->next)
+ continue;
+
+ referer = table_get(orig->headers_in, "Referer");
+ if(referer != NULL)
+ {
+
+
+ /* The following is an upsetting mess of pointers, I'm sorry
+ Anyone with the motiviation and/or the time should feel free
+ to make this cleaner... */
+
+ ptrptr2 = (char **) (cls->referer_ignore_list->elts +
+ (cls->referer_ignore_list->nelts *
+ cls->referer_ignore_list->elt_size));
+
+ /* Go through each element of the ignore list and compare it to the
+ referer_host. If we get a match, return without logging */
+
+ for(ptrptr = (char **) cls->referer_ignore_list->elts;
+ ptrptr < ptrptr2;
+ ptrptr += cls->referer_ignore_list->elt_size)
+ {
+ if(strstr(referer, *ptrptr))
+ return OK;
+ }
+
+
+ sprintf(str, "%s -> %s\n", referer,
+ r->uri);
+ write(cls->referer_fd, str, strlen(str));
+ }
+
+ return OK;
+}
+
+module referer_log_module = {
+ STANDARD_MODULE_STUFF,
+ init_referer_log, /* initializer */
+ NULL, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ make_referer_log_state, /* server config */
+ NULL, /* merge server config */
+ referer_log_cmds, /* command table */
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ referer_log_transaction /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * http_mime.c: Sends/gets MIME headers for requests
+ *
+ * Rob McCool
+ *
+ */
+
+#define MIME_PRIVATE
+
+#include "httpd.h"
+#include "http_config.h"
+
+typedef struct {
+ table *forced_types; /* Additional AddTyped stuff */
+ table *encoding_types; /* Added with AddEncoding... */
+ table *language_types; /* Added with AddLanguage... */
+} mime_dir_config;
+
+module mime_module;
+
+void *create_mime_dir_config (pool *p, char *dummy)
+{
+ mime_dir_config *new =
+ (mime_dir_config *) palloc (p, sizeof(mime_dir_config));
+
+ new->forced_types = make_table (p, 4);
+ new->encoding_types = make_table (p, 4);
+ new->language_types = make_table (p, 4);
+
+ return new;
+}
+
+void *merge_mime_dir_configs (pool *p, void *basev, void *addv)
+{
+ mime_dir_config *base = (mime_dir_config *)basev;
+ mime_dir_config *add = (mime_dir_config *)addv;
+ mime_dir_config *new =
+ (mime_dir_config *)palloc (p, sizeof(mime_dir_config));
+
+ new->forced_types = overlay_tables (p, add->forced_types,
+ base->forced_types);
+ new->encoding_types = overlay_tables (p, add->encoding_types,
+ base->encoding_types);
+ new->language_types = overlay_tables (p, add->language_types,
+ base->language_types);
+
+ return new;
+}
+
+char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext)
+{
+ if (*ext == '.') ++ext;
+ table_set (m->forced_types, ext, ct);
+ return NULL;
+}
+
+char *add_encoding(cmd_parms *cmd, mime_dir_config *m, char *enc, char *ext)
+{
+ if (*ext == '.') ++ext;
+ table_set (m->encoding_types, ext, enc);
+ return NULL;
+}
+
+char *add_language(cmd_parms *cmd, mime_dir_config *m, char *lang, char *ext)
+{
+ if (*ext == '.') ++ext;
+ table_set (m->language_types, ext, lang);
+ return NULL;
+}
+
+/* The sole bit of server configuration that the MIME module has is
+ * the name of its config file, so...
+ */
+
+char *set_types_config (cmd_parms *cmd, void *dummy, char *arg)
+{
+ set_module_config (cmd->server->module_config, &mime_module,
+ pstrdup (cmd->pool, arg));
+ return NULL;
+}
+
+command_rec mime_cmds[] = {
+{ "AddType", add_type, NULL, OR_FILEINFO, ITERATE2,
+ "a mime type followed by one or more file extensions" },
+{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, ITERATE2,
+ "an encoding (e.g., gzip), followed by one or more file extensions" },
+{ "AddLanguage", add_language, NULL, OR_FILEINFO, ITERATE2,
+ "a language (e.g., fr), followed by one or more file extensions" },
+{ "TypesConfig", set_types_config, NULL, RSRC_CONF, TAKE1,
+ "the MIME types config file" },
+{ NULL }
+};
+
+/* Hash table --- only one of these per daemon; virtual hosts can
+ * get private versions through AddType...
+ */
+
+#define MIME_HASHSIZE 27
+#define hash(i) (isalpha(i) ? (tolower(i)) - 'a' : 26)
+
+static table *hash_buckets[MIME_HASHSIZE];
+
+void init_mime (server_rec *s, pool *p)
+{
+ FILE *f;
+ char l[MAX_STRING_LEN];
+ int x;
+ char *types_confname = get_module_config (s->module_config, &mime_module);
+
+ if (!types_confname) types_confname = TYPES_CONFIG_FILE;
+
+ types_confname = server_root_relative (p, types_confname);
+
+ if(!(f = fopen(types_confname,"r"))) {
+ fprintf(stderr,"httpd: could not open mime types file %s\n",
+ types_confname);
+ perror("fopen");
+ exit(1);
+ }
+
+ for(x=0;x<27;x++)
+ hash_buckets[x] = make_table (p, 10);
+
+ while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
+ char *ll = l, *ct;
+
+ if(l[0] == '#') continue;
+ ct = getword_conf (p, &ll);
+
+ while(ll[0]) {
+ char *ext = getword_conf (p, &ll);
+ str_tolower (ext); /* ??? */
+ table_set (hash_buckets[hash(ext[0])], ext, ct);
+ }
+ }
+ fclose(f);
+}
+
+int find_ct(request_rec *r)
+{
+ int i;
+ char *fn = pstrdup (r->pool, r->filename);
+ mime_dir_config *conf =
+ (mime_dir_config *)get_module_config(r->per_dir_config, &mime_module);
+ char *type;
+
+ if (S_ISDIR(r->finfo.st_mode)) {
+ r->content_type = DIR_MAGIC_TYPE;
+ return OK;
+ }
+
+ if((i=rind(fn,'.')) < 0) return DECLINED;
+ ++i;
+
+ if ((type = table_get (conf->encoding_types, &fn[i])))
+ {
+ r->content_encoding = type;
+
+ /* go back to previous extension to try to use it as a language */
+
+ fn[i-1] = '\0';
+ if((i=rind(fn,'.')) < 0) return OK;
+ ++i;
+ }
+
+ if ((type = table_get (conf->language_types, &fn[i])))
+ {
+ r->content_language = type;
+
+ /* go back to previous extension to try to use it as a type */
+
+ fn[i-1] = '\0';
+ if((i=rind(fn,'.')) < 0) return OK;
+ ++i;
+ }
+
+ if ((type = table_get (conf->forced_types, &fn[i]))
+ || (type = table_get (hash_buckets[hash(fn[i])], &fn[i])))
+ {
+ r->content_type = type;
+ }
+
+ return OK;
+}
+
+
+module mime_module = {
+ STANDARD_MODULE_STUFF,
+ init_mime, /* initializer */
+ create_mime_dir_config,
+ merge_mime_dir_configs,
+ NULL, /* server config */
+ NULL, /* merge server config */
+ mime_cmds,
+ NULL, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ find_ct, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * mod_negotiation.c: keeps track of MIME types the client is willing to
+ * accept, and contains code to handle type arbitration.
+ *
+ * rst
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_log.h"
+
+/* Commands --- configuring document caching on a per (virtual?)
+ * server basis...
+ */
+
+typedef struct {
+ array_header *language_priority;
+} neg_dir_config;
+
+module negotiation_module;
+
+void *create_neg_dir_config (pool *p, char *dummy)
+{
+ neg_dir_config *new =
+ (neg_dir_config *) palloc (p, sizeof (neg_dir_config));
+
+ new->language_priority = make_array (p, 4, sizeof (char *));
+ return new;
+}
+
+void *merge_neg_dir_configs (pool *p, void *basev, void *addv)
+{
+ neg_dir_config *base = (neg_dir_config *)basev;
+ neg_dir_config *add = (neg_dir_config *)addv;
+ neg_dir_config *new =
+ (neg_dir_config *) palloc (p, sizeof (neg_dir_config));
+
+ /* give priority to the config in the subdirectory */
+ new->language_priority = append_arrays (p, add->language_priority,
+ base->language_priority);
+ return new;
+}
+
+char *set_language_priority (cmd_parms *cmd, void *n, char *lang)
+{
+ array_header *arr = ((neg_dir_config *) n)->language_priority;
+ char **langp = (char **) push_array (arr);
+
+ *langp = pstrdup (arr->pool, lang);
+ return NULL;
+}
+
+char *cache_negotiated_docs (cmd_parms *cmd, void *dummy, char *dummy2)
+{
+ void *server_conf = cmd->server->module_config;
+
+ set_module_config (server_conf, &negotiation_module, "Cache");
+ return NULL;
+}
+
+int do_cache_negotiated_docs (server_rec *s)
+{
+ return (get_module_config (s->module_config, &negotiation_module) != NULL);
+}
+
+command_rec negotiation_cmds[] = {
+{ "CacheNegotiatedDocs", cache_negotiated_docs, NULL, RSRC_CONF, RAW_ARGS,
+ NULL },
+{ "LanguagePriority", set_language_priority, NULL, OR_FILEINFO, ITERATE,
+ NULL },
+{ NULL }
+};
+
+/*
+ * TO DO --- error code 406. Unfortunately, the specification for
+ * a 406 reply in the current draft standard is unworkable;
+ * we return 404 for these pending a workable spec.
+ */
+
+/* Record of available info on a media type specified by the client
+ * (we also use 'em for encodings and languages)
+ */
+
+typedef struct accept_rec {
+ char *type_name;
+ float quality;
+ float max_bytes;
+ float level;
+} accept_rec;
+
+/* Record of available info on a particular variant
+ *
+ * Note that a few of these fields are updated by the actual negotiation
+ * code. These are:
+ *
+ * quality --- initialized to the value of qs, and subsequently jiggered
+ * to reflect the client's preferences. In particular, it
+ * gets zeroed out if the variant has an unacceptable content
+ * encoding, or if it is in a language which the client
+ * doesn't accept and some other variant *is* in a language
+ * the client accepts.
+ *
+ * level_matched --- initialized to zero. Set to the value of level
+ * if the client actually accepts this media type at that
+ * level (and *not* if it got in on a wildcard). See level_cmp
+ * below.
+ */
+
+typedef struct var_rec {
+ request_rec *sub_req; /* May be NULL (is, for map files) */
+ char *type_name;
+ char *file_name;
+ char *content_encoding;
+ char *content_language;
+ float level; /* Auxiliary to content-type... */
+ float qs;
+ float bytes;
+ int lang_index;
+ int is_pseudo_html; /* text/html, *or* the INCLUDES_MAGIC_TYPEs */
+
+ /* Above are all written-once properties of the variant. The
+ * two fields below are changed during negotiation:
+ */
+
+ float quality;
+ float level_matched;
+} var_rec;
+
+/* Something to carry around the state of negotiation (and to keep
+ * all of this thread-safe)...
+ */
+
+typedef struct {
+ pool *pool;
+ request_rec *r;
+ char *dir_name;
+
+ array_header *accepts; /* accept_recs */
+ array_header *accept_encodings; /* accept_recs */
+ array_header *accept_langs; /* accept_recs */
+ array_header *avail_vars; /* available variants */
+} negotiation_state;
+
+/* A few functions to manipulate var_recs.
+ * Cleaning out the fields...
+ */
+
+void clean_var_rec (var_rec *mime_info)
+{
+ mime_info->sub_req = NULL;
+ mime_info->type_name = "";
+ mime_info->file_name = "";
+ mime_info->content_encoding = "";
+ mime_info->content_language = "";
+
+ mime_info->is_pseudo_html = 0.0;
+ mime_info->level = 0.0;
+ mime_info->level_matched = 0.0;
+ mime_info->qs = 0.0;
+ mime_info->quality = 0.0;
+ mime_info->bytes = 0;
+ mime_info->lang_index = -1;
+}
+
+/* Initializing the relevant fields of a variant record from the
+ * accept_info read out of its content-type, one way or another.
+ */
+
+void set_mime_fields (var_rec *var, accept_rec *mime_info)
+{
+ var->type_name = mime_info->type_name;
+ var->qs = mime_info->quality;
+ var->quality = mime_info->quality; /* Initial quality is just qs */
+ var->level = mime_info->level;
+
+ var->is_pseudo_html =
+ (!strcmp (var->type_name, "text/html")
+ || !strcmp (var->type_name, INCLUDES_MAGIC_TYPE)
+ || !strcmp (var->type_name, INCLUDES_MAGIC_TYPE3));
+}
+
+/*****************************************************************
+ *
+ * Parsing (lists of) media types and their parameters, as seen in
+ * HTTPD header lines and elsewhere.
+ */
+
+/* Retrieve a token, spacing over it and returning a pointer to
+ * the first non-white byte afterwards. Note that these tokens
+ * are delimited by semis and commas; and can also be delimited
+ * by whitespace at the caller's option.
+ */
+
+char *get_token (pool *p, char **accept_line, int accept_white)
+{
+ char *ptr = *accept_line;
+ char *tok_start;
+ char *token;
+ int tok_len;
+
+ /* Find first non-white byte */
+
+ while (*ptr && isspace(*ptr))
+ ++ptr;
+
+ tok_start = ptr;
+
+ /* find token end, skipping over quoted strings.
+ * (comments are already gone).
+ */
+
+ while (*ptr && (accept_white || !isspace(*ptr))
+ && *ptr != ';' && *ptr != ',')
+ {
+ if (*ptr++ == '"')
+ while (*ptr)
+ if (*ptr++ == '"') break;
+ }
+
+ tok_len = ptr - tok_start;
+ token = palloc (p, tok_len + 1);
+ strncpy (token, tok_start, tok_len);
+ token[tok_len] = '\0';
+
+ /* Advance accept_line pointer to the next non-white byte */
+
+ while (*ptr && isspace(*ptr))
+ ++ptr;
+
+ *accept_line = ptr;
+ return token;
+}
+
+/*
+ * Get a single mime type entry --- one media type and parameters;
+ * enter the values we recognize into the argument accept_rec
+ */
+
+char *get_entry (pool *p, accept_rec *result, char *accept_line)
+{
+ result->quality = 1.0;
+ result->max_bytes = 0.0;
+ result->level = 0.0;
+
+ /* Note that this handles what I gather is the "old format",
+ *
+ * Accept: text/html text/plain moo/zot
+ *
+ * without any compatibility kludges --- if the token after the
+ * MIME type begins with a semicolon, we know we're looking at parms,
+ * otherwise, we know we aren't. (So why all the pissing and moaning
+ * in the CERN server code? I must be missing something).
+ */
+
+ result->type_name = get_token (p, &accept_line, 0);
+ str_tolower (result->type_name); /* You want case-insensitive,
+ * you'll *get* case-insensitive.
+ */
+
+
+ /* KLUDGE!!! Default HTML to level 2.0 unless the browser
+ * *explicitly* says something else.
+ */
+
+ if (!strcmp (result->type_name, "text/html")
+ && result->level == 0.0)
+ result->level = 2.0;
+ else if (!strcmp (result->type_name, INCLUDES_MAGIC_TYPE))
+ result->level = 2.0;
+ else if (!strcmp (result->type_name, INCLUDES_MAGIC_TYPE3))
+ result->level = 3.0;
+
+ while (*accept_line == ';') {
+ /* Parameters ... */
+
+ char *parm;
+ char *cp;
+
+ ++accept_line;
+ parm = get_token (p, &accept_line, 1);
+
+ /* Look for 'var = value' --- and make sure the var is in lcase. */
+
+ for (cp = parm; *cp && !isspace(*cp) && *cp != '='; ++cp)
+ *cp = tolower(*cp);
+
+ if (!*cp) continue; /* No '='; just ignore it. */
+
+ *cp++ = '\0'; /* Delimit var */
+ while (*cp && (isspace(*cp) || *cp == '='))
+ ++cp;
+
+ if (*cp == '"') ++cp;
+
+ if (parm[0] == 'q'
+ && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0')))
+ result->quality = atof(cp);
+ else if (parm[0] == 'm' && parm[1] == 'x' &&
+ parm[2] == 'b' && parm[3] == '\0')
+ result->max_bytes = atof(cp);
+ else if (parm[0] == 'l' && !strcmp (&parm[1], "evel"))
+ result->level = atof(cp);
+ }
+
+ if (*accept_line == ',') ++accept_line;
+
+ return accept_line;
+}
+
+
+/*****************************************************************
+ *
+ * Dealing with header lines ...
+ */
+
+array_header *do_header_line (pool *p, char *accept_line)
+{
+ array_header *accept_recs = make_array (p, 40, sizeof (accept_rec));
+
+ if (!accept_line) return accept_recs;
+
+ while (*accept_line) {
+ accept_rec *new = (accept_rec *)push_array (accept_recs);
+ accept_line = get_entry (p, new, accept_line);
+ }
+
+ return accept_recs;
+}
+
+/*****************************************************************
+ *
+ * Handling header lines from clients...
+ */
+
+negotiation_state *parse_accept_headers (request_rec *r)
+{
+ negotiation_state *new =
+ (negotiation_state *)palloc (r->pool, sizeof (negotiation_state));
+ table *hdrs = r->headers_in;
+
+ new->pool = r->pool;
+ new->r = r;
+ new->dir_name = make_dirstr(r->pool, r->filename, count_dirs(r->filename));
+
+ new->accepts = do_header_line (r->pool, table_get (hdrs, "Accept"));
+ new->accept_encodings =
+ do_header_line (r->pool, table_get (hdrs, "Accept-encoding"));
+ new->accept_langs =
+ do_header_line (r->pool, table_get (hdrs, "Accept-language"));
+ new->avail_vars = make_array (r->pool, 40, sizeof (var_rec));
+
+ return new;
+}
+
+/* Sometimes clients will give us no Accept info at all; this routine sets
+ * up the standard default for that case, and also arranges for us to be
+ * willing to run a CGI script if we find one. (In fact, we set up to
+ * dramatically prefer CGI scripts in cases where that's appropriate,
+ * e.g., POST).
+ */
+
+void maybe_add_default_encodings(negotiation_state *neg, int prefer_scripts)
+{
+ accept_rec *new_accept = (accept_rec *)push_array (neg->accepts);
+
+ new_accept->type_name = CGI_MAGIC_TYPE;
+ new_accept->quality = prefer_scripts ? 1e-20 : 1e20;
+ new_accept->level = 0.0;
+ new_accept->max_bytes = 0.0;
+
+ if (neg->accepts->nelts > 1) return;
+
+ new_accept = (accept_rec *)push_array (neg->accepts);
+
+ new_accept->type_name = "*/*";
+ new_accept->quality = 1.0;
+ new_accept->level = 0.0;
+ new_accept->max_bytes = 0.0;
+}
+
+/*****************************************************************
+ *
+ * Parsing type-map files, in Roy's meta/http format augmented with
+ * #-comments.
+ */
+
+/* Reading RFC822-style header lines, ignoring #-comments and
+ * handling continuations.
+ */
+
+enum header_state { header_eof, header_seen, header_sep };
+
+enum header_state get_header_line (char *buffer, int len, FILE *map)
+{
+ char *buf_end = buffer + len;
+ char *cp;
+ int c;
+
+ /* Get a noncommented line */
+
+ do {
+ if (fgets(buffer, MAX_STRING_LEN, map) == NULL)
+ return header_eof;
+ } while (buffer[0] == '#');
+
+ /* If blank, just return it --- this ends information on this variant */
+
+ for (cp = buffer; *cp && isspace (*cp); ++cp)
+ continue;
+
+ if (*cp == '\0') return header_sep;
+
+ /* If non-blank, go looking for header lines, but note that we still
+ * have to treat comments specially...
+ */
+
+ cp += strlen(cp);
+
+ while ((c = getc(map)) != EOF)
+ {
+ if (c == '#') {
+ /* Comment line */
+ while ((c = getc(map)) != EOF && c != '\n')
+ continue;
+ } else if (isspace(c)) {
+ /* Leading whitespace. POSSIBLE continuation line
+ * Also, possibly blank --- if so, we ungetc() the final newline
+ * so that we will pick up the blank line the next time 'round.
+ */
+
+ while (c != EOF && c != '\n' && isspace(c))
+ c = getc(map);
+
+ ungetc (c, map);
+
+ if (c == '\n') return header_seen; /* Blank line */
+
+ /* Continuation */
+
+ while (cp < buf_end - 2 && (c = getc(map)) != EOF && c != '\n')
+ *cp++ = c;
+
+ *cp++ = '\n';
+ *cp = '\0';
+ } else {
+
+ /* Line beginning with something other than whitespace */
+
+ ungetc (c, map);
+ return header_seen;
+ }
+ }
+
+ return header_seen;
+}
+
+/* Stripping out RFC822 comments */
+
+void strip_paren_comments (char *hdr)
+{
+ /* Hmmm... is this correct? In Roy's latest draft, (comments) can nest! */
+
+ while (*hdr) {
+ if (*hdr == '"') {
+ while (*++hdr && *hdr != '"')
+ continue;
+ ++hdr;
+ }
+ else if (*hdr == '(') {
+ while (*hdr && *hdr != ')') *hdr++ = ' ';
+
+ if (*hdr) *hdr++ = ' ';
+ }
+ else ++hdr;
+ }
+}
+
+/* Getting to a header body from the header */
+
+char *lcase_header_name_return_body (char *header, request_rec *r)
+{
+ char *cp = header;
+
+ while (*cp && *cp != ':')
+ *cp++ = tolower(*cp);
+
+ if (!*cp) {
+ log_reason ("Syntax error in type map --- no ':'", r->filename, r);
+ return NULL;
+ }
+
+ do ++cp; while (*cp && isspace (*cp));
+
+ if (!*cp) {
+ log_reason ("Syntax error in type map --- no header body",
+ r->filename, r);
+ return NULL;
+ }
+
+ return cp;
+}
+
+int read_type_map (negotiation_state *neg, char *map_name)
+{
+ request_rec *r = neg->r;
+ FILE *map = pfopen (neg->pool, map_name, "r");
+
+ char buffer[MAX_STRING_LEN];
+ enum header_state hstate;
+ struct var_rec mime_info;
+
+ if (map == NULL) {
+ log_reason("cannot access type map file", map_name, r);
+ return FORBIDDEN;
+ }
+
+ clean_var_rec (&mime_info);
+
+ do {
+ hstate = get_header_line (buffer, MAX_STRING_LEN, map);
+
+ if (hstate == header_seen) {
+ char *body = lcase_header_name_return_body (buffer, neg->r);
+
+ if (body == NULL) return SERVER_ERROR;
+
+ strip_paren_comments (body);
+
+ if (!strncmp (buffer, "uri:", 4)) {
+ mime_info.file_name = get_token (neg->pool, &body, 0);
+ }
+ else if (!strncmp (buffer, "content-type:", 13)) {
+ struct accept_rec accept_info;
+
+ get_entry (neg->pool, &accept_info, body);
+ set_mime_fields (&mime_info, &accept_info);
+ }
+ else if (!strncmp (buffer, "content-length:", 15)) {
+ mime_info.bytes = atoi(body);
+ }
+ else if (!strncmp (buffer, "content-language:", 17)) {
+ mime_info.content_language = get_token (neg->pool, &body, 0);
+ str_tolower (mime_info.content_language);
+ }
+ else if (!strncmp (buffer, "content-encoding:", 17)) {
+ mime_info.content_encoding = get_token (neg->pool, &body, 0);
+ str_tolower (mime_info.content_encoding);
+ }
+ } else {
+ if (mime_info.quality > 0) {
+ void *new_var = push_array (neg->avail_vars);
+ memcpy (new_var, (void *)&mime_info, sizeof (var_rec));
+ }
+
+ clean_var_rec(&mime_info);
+ }
+ } while (hstate != header_eof);
+
+ pfclose (neg->pool, map);
+ return OK;
+}
+
+/*****************************************************************
+ *
+ * Same, except we use a filtered directory listing as the map...
+ */
+
+int read_types_multi (negotiation_state *neg)
+{
+ request_rec *r = neg->r;
+
+ char *filp;
+ int prefix_len;
+ DIR *dirp;
+ struct DIR_TYPE *dir_entry;
+ struct var_rec mime_info;
+ struct accept_rec accept_info;
+ void *new_var;
+
+ clean_var_rec (&mime_info);
+
+ if (!(filp = strrchr (r->filename, '/'))) return DECLINED; /* Weird... */
+
+ ++filp;
+ prefix_len = strlen (filp);
+
+ dirp = opendir (neg->dir_name); /* Not pool protected; sigh... */
+
+ if (dirp == NULL) {
+ log_reason("cannot read directory for multi", neg->dir_name, r);
+ return FORBIDDEN;
+ }
+
+ while ((dir_entry = readdir (dirp))) {
+
+ request_rec *sub_req;
+
+ /* Do we have a match? */
+
+ if (strncmp (dir_entry->d_name, filp, prefix_len)) continue;
+ if (dir_entry->d_name[prefix_len] != '.') continue;
+
+ /* Yep. See if it's something which we have access to, and
+ * which has a known type and encoding (as opposed to something
+ * which we'll be slapping default_type on later).
+ */
+
+ sub_req = sub_req_lookup_file (dir_entry->d_name, r);
+
+ if (sub_req->status != 200 || !sub_req->content_type) continue;
+
+ /* If it's a map file, we use that instead of the map
+ * we're building...
+ */
+
+ if (!strcmp (sub_req->content_type, MAP_FILE_MAGIC_TYPE)) {
+ closedir(dirp);
+
+ neg->avail_vars->nelts = 0;
+ return read_type_map (neg, sub_req->filename);
+ }
+
+ /* Have reasonable variant --- gather notes.
+ */
+
+ mime_info.sub_req = sub_req;
+ mime_info.file_name = dir_entry->d_name;
+ mime_info.content_encoding = sub_req->content_encoding;
+ mime_info.content_language = sub_req->content_language;
+
+ get_entry (neg->pool, &accept_info, sub_req->content_type);
+ set_mime_fields (&mime_info, &accept_info);
+
+ new_var = push_array (neg->avail_vars);
+ memcpy (new_var, (void *)&mime_info, sizeof (var_rec));
+
+ clean_var_rec(&mime_info);
+ }
+
+ closedir(dirp);
+ return OK;
+}
+
+
+/*****************************************************************
+ * And now for the code you've been waiting for... actually
+ * finding a match to the client's requirements.
+ */
+
+/* Matching MIME types ... the star/star and foo/star commenting conventions
+ * are implemented here. (You know what I mean by star/star, but just
+ * try mentioning those three characters in a C comment). Using strcmp()
+ * is legit, because everything has already been smashed to lowercase.
+ *
+ * Note also that if we get an exact match on the media type, we update
+ * level_matched for use in level_cmp below...
+ */
+
+int mime_match (accept_rec *accept, var_rec *avail)
+{
+ char *accept_type = accept->type_name;
+ char *avail_type = avail->type_name;
+ int len = strlen(accept_type);
+
+ if (accept_type[0] == '*') /* Anything matches star/star */
+ return 1;
+ else if (accept_type[len - 1] == '*')
+ return !strncmp (accept_type, avail_type, len - 2);
+ else if (!strcmp (accept_type, avail_type)
+ || (!strcmp (accept_type, "text/html")
+ && (!strcmp(avail_type, INCLUDES_MAGIC_TYPE)
+ || !strcmp(avail_type, INCLUDES_MAGIC_TYPE3)))) {
+ if (accept->level >= avail->level) {
+ avail->level_matched = avail->level;
+ return 1;
+ }
+ }
+
+ return OK;
+}
+
+/* This code implements a piece of the tie-breaking algorithm between
+ * variants of equal quality. This piece is the treatment of variants
+ * of the same base media type, but different levels. What we want to
+ * return is the variant at the highest level that the client explicitly
+ * claimed to accept.
+ *
+ * If all the variants available are at a higher level than that, or if
+ * the client didn't say anything specific about this media type at all
+ * and these variants just got in on a wildcard, we prefer the lowest
+ * level, on grounds that that's the one that the client is least likely
+ * to choke on.
+ *
+ * (This is all motivated by treatment of levels in HTML --- we only
+ * want to give level 3 to browsers that explicitly ask for it; browsers
+ * that don't, including HTTP/0.9 browsers that only get the implicit
+ * "Accept: * / *" [space added to avoid confusing cpp --- no, that
+ * syntax doesn't really work] should get HTML2 if available).
+ *
+ * (Note that this code only comes into play when we are choosing among
+ * variants of equal quality, where the draft standard gives us a fair
+ * bit of leeway about what to do. It ain't specified by the standard;
+ * rather, it is a choice made by this server about what to do in cases
+ * where the standard does not specify a unique course of action).
+ */
+
+int level_cmp (var_rec *var1, var_rec *var2)
+{
+ /* Levels are only comparable between matching media types */
+
+ if (var1->is_pseudo_html && !var2->is_pseudo_html)
+ return 0;
+
+ if (!var1->is_pseudo_html && strcmp (var1->type_name, var2->type_name))
+ return 0;
+
+ /* Take highest level that matched, if either did match. */
+
+ if (var1->level_matched > var2->level_matched) return 1;
+ if (var1->level_matched < var2->level_matched) return -1;
+
+ /* Neither matched. Take lowest level, if there's a difference. */
+
+ if (var1->level < var2->level) return 1;
+ if (var1->level > var2->level) return -1;
+
+ /* Tied */
+
+ return 0;
+}
+
+/* Finding languages. Note that we only match the substring specified
+ * by the Accept: line --- this is to allow "en" to match all subvariants
+ * of English.
+ *
+ * Again, strcmp() is legit because we've ditched case already.
+ */
+
+int find_lang_index (array_header *accept_langs, char *lang)
+{
+ accept_rec *accs;
+ int i;
+
+ if (!lang)
+ return -1;
+
+ accs = (accept_rec *)accept_langs->elts;
+
+ for (i = 0; i < accept_langs->nelts; ++i)
+ if (!strncmp (lang, accs[i].type_name, strlen(accs[i].type_name)))
+ return i;
+
+ return -1;
+}
+
+/* This function returns the priority of a given language
+ * according to LanguagePriority. It is used in case of a tie
+ * between several languages.
+ */
+
+int find_default_index (neg_dir_config *conf, char *lang)
+{
+ array_header *arr;
+ int nelts;
+ char **elts;
+ int i;
+
+ if (!lang)
+ return -1;
+
+ arr = conf->language_priority;
+ nelts = arr->nelts;
+ elts = (char **) arr->elts;
+
+ for (i = 0; i < nelts; ++i)
+ if (!strcasecmp (elts[i], lang))
+ return i;
+
+ return -1;
+}
+
+void find_lang_indexes (negotiation_state *neg)
+{
+ var_rec *var_recs = (var_rec*)neg->avail_vars->elts;
+ int i;
+ int found_any = 0;
+ neg_dir_config *conf = NULL;
+ int naccept = neg->accept_langs->nelts;
+
+ if (naccept == 0)
+ conf = (neg_dir_config *) get_module_config (neg->r->per_dir_config,
+ &negotiation_module);
+
+ for (i = 0; i < neg->avail_vars->nelts; ++i)
+ if (var_recs[i].quality > 0) {
+ int index;
+ if (naccept == 0) /* Client doesn't care */
+ index = find_default_index (conf,
+ var_recs[i].content_language);
+ else /* Client has Accept-Language */
+ index = find_lang_index (neg->accept_langs,
+ var_recs[i].content_language);
+
+ var_recs[i].lang_index = index;
+ if (index >= 0) found_any = 1;
+ }
+
+ /* If we have any variants in a language acceptable to the client,
+ * blow away everything that isn't.
+ */
+
+ if (found_any)
+ for (i = 0; i < neg->avail_vars->nelts; ++i)
+ if (var_recs[i].lang_index < 0)
+ var_recs[i].quality = 0;
+}
+
+/* Finding content encodings. Note that we assume that the client
+ * accepts the trivial encodings. Strcmp() is legit because... aw, hell.
+ */
+
+int is_identity_encoding (char *enc)
+{
+ return (!enc || !enc[0] || !strcmp (enc, "7bit") || !strcmp (enc, "8bit")
+ || !strcmp (enc, "binary"));
+}
+
+int find_encoding (array_header *accept_encodings, char *enc)
+{
+ accept_rec *accs = (accept_rec *)accept_encodings->elts;
+ int i;
+
+ if (is_identity_encoding(enc)) return 1.0;
+
+ for (i = 0; i < accept_encodings->nelts; ++i)
+ if (!strcmp (enc, accs[i].type_name))
+ return 1;
+
+ return 0;
+}
+
+void do_encodings (negotiation_state *neg)
+{
+ var_rec *var_recs = (var_rec*)neg->avail_vars->elts;
+ int i;
+
+ /* If no Accept-Encoding is present, everything is acceptable */
+
+ if (!neg->accept_encodings->nelts)
+ return;
+
+ /* Lose any variant with an unacceptable content encoding */
+
+ for (i = 0; i < neg->avail_vars->nelts; ++i)
+ if (var_recs[i].quality > 0
+ && !find_encoding (neg->accept_encodings,
+ var_recs[i].content_encoding))
+
+ var_recs[i].quality = 0;
+}
+
+/* Determining the content length --- if the map didn't tell us,
+ * we have to do a stat() and remember for next time.
+ *
+ * Grump. For shambhala, even the first stat here may well be
+ * redundant (for multiviews) with a stat() done by the sub_req
+ * machinery. At some point, that ought to be fixed.
+ */
+
+int find_content_length(negotiation_state *neg, var_rec *variant)
+{
+ struct stat statb;
+
+ if (variant->bytes == 0) {
+ char *fullname = make_full_path (neg->pool, neg->dir_name,
+ variant->file_name);
+
+ if (stat (fullname, &statb) >= 0) variant->bytes = statb.st_size;
+ }
+
+ return variant->bytes;
+}
+
+/* The main event. */
+
+var_rec *best_match(negotiation_state *neg)
+{
+ int i, j;
+ var_rec *best = NULL;
+ float best_quality = 0.0;
+ int levcmp;
+
+ accept_rec *accept_recs = (accept_rec *)neg->accepts->elts;
+ var_rec *avail_recs = (var_rec *)neg->avail_vars->elts;
+
+ /* Nuke variants which are unsuitable due to a content encoding,
+ * or possibly a language, which the client doesn't accept.
+ * (If we haven't *got* a variant in a language the client accepts,
+ * find_lang_indexes keeps 'em all, so we still wind up serving
+ * something...).
+ */
+
+ do_encodings (neg);
+ find_lang_indexes (neg);
+
+ for (i = 0; i < neg->accepts->nelts; ++i) {
+
+ accept_rec *type = &accept_recs[i];
+
+ for (j = 0; j < neg->avail_vars->nelts; ++j) {
+
+ var_rec *variant = &avail_recs[j];
+ float q = type->quality * variant->quality;
+
+ /* If we've already rejected this variant, don't waste time */
+
+ if (q == 0.0) continue;
+
+ /* If media types don't match, forget it.
+ * (This includes the level check).
+ */
+
+ if (!mime_match(type, variant)) continue;
+
+ /* Check maxbytes */
+
+ if (type->max_bytes > 0
+ && (find_content_length(neg, variant)
+ > type->max_bytes))
+ continue;
+
+ /* If it lasted this far, consider it ---
+ * If better quality than our current best, take it.
+ * If equal quality, *maybe* take it.
+ *
+ * Note that the current http draft specifies no particular
+ * behavior for variants which tie in quality; the server
+ * can, at its option, return a 300 response listing all
+ * of them (and perhaps the others), or choose one of the
+ * tied variants by whatever means it likes. This server
+ * breaks ties as follows, in order:
+ *
+ * By order of languages in Accept-language, to give the
+ * client a way to specify a language preference. I'd prefer
+ * to give this precedence over media type, but the standard
+ * doesn't allow for that.
+ *
+ * By level preference, as defined by level_cmp above.
+ *
+ * By order of Accept: header matched, so that the order in
+ * which media types are named by the client functions as a
+ * preference order, if the client didn't give us explicit
+ * quality values.
+ *
+ * Finally, by content_length, so that among variants which
+ * have the same quality, language and content_type (including
+ * level) we ship the one that saps the least bandwidth.
+ */
+
+ if (q > best_quality
+ || (q == best_quality
+ && (variant->lang_index < best->lang_index
+ || (variant->lang_index == best->lang_index
+ && ((levcmp = level_cmp (variant, best)) == 1
+ || (levcmp == 0
+ && !strcmp (variant->type_name,
+ best->type_name)
+ && (find_content_length(neg, variant)
+ <
+ find_content_length(neg, best))))))))
+ {
+ best = variant;
+ best_quality = q;
+ }
+ }
+ }
+
+ return best;
+}
+
+/****************************************************************
+ *
+ * Executive...
+ */
+
+int handle_map_file (request_rec *r)
+{
+ negotiation_state *neg = parse_accept_headers (r);
+ var_rec *best;
+ int res;
+
+ char *udir;
+
+ if ((res = read_type_map (neg, r->filename))) return res;
+
+ maybe_add_default_encodings(neg, 0);
+
+ if (!(best = best_match(neg))) {
+ /* Should be a 406 */
+ log_reason ("no acceptable variant", r->filename, r);
+ return NOT_FOUND;
+ }
+
+ if (!do_cache_negotiated_docs(r->server)) r->no_cache = 1;
+ udir = make_dirstr (r->pool, r->uri, count_dirs (r->uri));
+ udir = escape_uri(r->pool, udir);
+ internal_redirect (make_full_path (r->pool, udir, best->file_name), r);
+ return OK;
+}
+
+int handle_multi (request_rec *r)
+{
+ negotiation_state *neg;
+ var_rec *best;
+ request_rec *sub_req;
+ int res;
+
+ if (r->finfo.st_mode != 0 || !(allow_options (r) & OPT_MULTI))
+ return DECLINED;
+
+ neg = parse_accept_headers (r);
+
+ if ((res = read_types_multi (neg))) return res;
+
+ maybe_add_default_encodings(neg,
+ r->method_number != M_GET
+ || r->args || r->path_info);
+
+ if (neg->avail_vars->nelts == 0) return DECLINED;
+
+ if (!(best = best_match(neg))) {
+ /* Should be a 406 */
+ log_reason ("no acceptable variant", r->filename, r);
+ return NOT_FOUND;
+ }
+
+ if (! (sub_req = best->sub_req)) {
+ /* We got this out of a map file, so we don't actually have
+ * a sub_req structure yet. Get one now.
+ */
+
+ sub_req = sub_req_lookup_file (best->file_name, r);
+ if (sub_req->status != 200) return sub_req->status;
+ }
+
+ /* BLETCH --- don't multi-resolve non-ordinary files */
+
+ if (!S_ISREG(sub_req->finfo.st_mode)) return NOT_FOUND;
+
+ /* Otherwise, use it. */
+
+ if (!do_cache_negotiated_docs(r->server)) r->no_cache = 1;
+ r->filename = sub_req->filename;
+ r->content_type = sub_req->content_type;
+ r->content_encoding = sub_req->content_encoding;
+ r->content_language = sub_req->content_language;
+ r->finfo = sub_req->finfo;
+
+ return OK;
+}
+
+handler_rec negotiation_handlers[] = {
+{ MAP_FILE_MAGIC_TYPE, handle_map_file },
+{ NULL }
+};
+
+module negotiation_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ create_neg_dir_config, /* dir config creater */
+ merge_neg_dir_configs, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ negotiation_cmds, /* command table */
+ negotiation_handlers, /* handlers */
+ NULL, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ handle_multi, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * mod_userdir... implement the UserDir command. Broken away from the
+ * Alias stuff for a couple of good and not-so-good reasons:
+ *
+ * 1) It shows a real minimal working example of how to do something like
+ * this.
+ * 2) I know people who are actually interested in changing this *particular*
+ * aspect of server functionality without changing the rest of it. That's
+ * what this whole modular arrangement is supposed to be good at...
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+
+module userdir_module;
+
+/*
+ * Sever config for this module is a little unconventional...
+ * It's just one string anyway, so why pretend?
+ */
+
+void *create_userdir_config (pool *dummy, server_rec *s) {
+ return (void*)DEFAULT_USER_DIR;
+}
+
+char *set_user_dir (cmd_parms *cmd, void *dummy, char *arg)
+{
+ void *server_conf = cmd->server->module_config;
+
+ set_module_config (server_conf, &userdir_module, pstrdup (cmd->pool, arg));
+ return NULL;
+}
+
+command_rec userdir_cmds[] = {
+{ "UserDir", set_user_dir, NULL, RSRC_CONF, TAKE1,
+ "the public subdirectory in users' home directories, or 'disabled'" },
+{ NULL }
+};
+
+int translate_userdir (request_rec *r)
+{
+ void *server_conf = r->server->module_config;
+ char *userdir = (char *)get_module_config(server_conf, &userdir_module);
+ char *name = r->uri;
+
+ if (userdir != NULL && strcasecmp(userdir, "disabled") != 0 &&
+ name[0] == '/' && name[1] == '~')
+ {
+ struct passwd *pw;
+ char *w, *dname;
+
+ dname = name + 2;
+ w = getword(r->pool, &dname, '/');
+ if(!(pw=getpwnam(w)))
+ return NOT_FOUND;
+
+ /* The 'dname' funny business involves backing it up to capture
+ * the '/' delimiting the "/~user" part from the rest of the URL,
+ * in case there was one (the case where there wasn't being just
+ * "GET /~user HTTP/1.0", for which we don't want to tack on a
+ * '/' onto the filename).
+ */
+
+ if (dname[-1] == '/') --dname;
+ r->filename = pstrcat (r->pool, pw->pw_dir, "/", userdir, dname, NULL);
+
+ return OK;
+ }
+
+ return DECLINED;
+}
+
+module userdir_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ create_userdir_config, /* server config */
+ NULL, /* merge server config */
+ userdir_cmds, /* command table */
+ NULL, /* handlers */
+ translate_userdir, /*filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL /* logger */
+};
--- /dev/null
+
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED 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 APACHE GROUP OR
+ * IT'S 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * rfc931() speaks a common subset of the RFC 931, AUTH, TAP and IDENT
+ * protocols. The code queries an RFC 931 etc. compatible daemon on a remote
+ * host to look up the owner of a connection. The information should not be
+ * used for authentication purposes. This routine intercepts alarm signals.
+ *
+ * Diagnostics are reported through syslog(3).
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology,
+ * The Netherlands.
+ */
+
+/* Some small additions for Shambhala --- ditch the "sccsid" var if
+ * compiling with gcc (it *has* changed), include conf.h for the
+ * prototypes it defines on at least one system (SunlOSs) which has
+ * them missing from the standard header files, and one minor change
+ * below (extra parens around assign "if (foo = bar) ..." to shut up
+ * gcc -Wall).
+ */
+
+#include "conf.h"
+
+#ifdef NOTDEF /* Has changed slightly... */
+static char sccsid[] = "@(#) rfc931.c 1.8 93/12/13 22:23:20";
+#endif
+
+#ifndef _HPUX_SOURCE
+#define _HPUX_SOURCE
+#endif
+
+/* System libraries. */
+
+#include <stdio.h>
+#ifndef QNX
+#include <syslog.h>
+#endif
+#include <sys/types.h>
+#ifndef ULTRIX_BRAIN_DEATH
+#include <sys/socket.h>
+#endif
+#ifdef __bsdi__
+#if _BSDI_VERSION > 199312
+#include <netinet/in.h>
+#endif
+#else
+#include <netinet/in.h>
+#endif
+#include <setjmp.h>
+#include <signal.h>
+#ifndef NEXT
+#include <unistd.h>
+#endif
+
+#ifndef SCO
+extern char *strchr();
+extern char *inet_ntoa();
+#endif
+
+/* Local stuff. */
+
+/* #include "log_tcp.h" */
+
+#define RFC931_TIMEOUT 500
+#define RFC931_PORT 113 /* Semi-well-known port */
+#define ANY_PORT 0 /* Any old port will do */
+#define FROM_UNKNOWN "unknown"
+
+int rfc931_timeout = RFC931_TIMEOUT;/* Global so it can be changed */
+
+static jmp_buf timebuf;
+
+#ifdef QNX
+
+/*
+Gasp! QNX doesn't support syslog() (out of the box). Replace with output to
+stderr. Really, this module should use Apache error logging, but then it would
+need considerable hacking.
+
+9 Oct 95
+Ben Laurie <ben@algroup.co.uk>
+*/
+#include <assert.h>
+
+#define LOG_ERR 0
+
+void syslog(int err,const char *str)
+{
+ char logbuf[200];
+ int n=ind(str,'%');
+
+ assert(n >= 0);
+ memcpy(logbuf,str,n);
+ logbuf[n]='\0';
+
+ fprintf(stderr,"%ssystem error %d",logbuf,errno);
+}
+
+#endif /* def QNX */
+
+/* fsocket - open stdio stream on top of socket */
+
+static FILE *fsocket(domain, type, protocol)
+int domain;
+int type;
+int protocol;
+{
+ int s;
+ FILE *fp;
+
+ if ((s = socket(domain, type, protocol)) < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ return (0);
+ } else {
+ if ((fp = fdopen(s, "r+")) == 0) {
+ syslog(LOG_ERR, "fdopen: %m");
+ close(s);
+ }
+ return (fp);
+ }
+}
+
+/* bind_connect - bind both ends of a socket */
+
+int bind_connect(s, local, remote, length)
+int s;
+struct sockaddr *local;
+struct sockaddr *remote;
+int length;
+{
+ if (bind(s, local, length) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ return (-1);
+ } else {
+ return (connect(s, remote, length));
+ }
+}
+
+/* timeout - handle timeouts */
+
+static void timeout(sig)
+int sig;
+{
+ longjmp(timebuf, sig);
+}
+
+/* rfc931 - return remote user name, given socket structures */
+
+char *rfc931(rmt_sin, our_sin)
+struct sockaddr_in *rmt_sin;
+struct sockaddr_in *our_sin;
+{
+ unsigned rmt_port;
+ unsigned our_port;
+ struct sockaddr_in rmt_query_sin;
+ struct sockaddr_in our_query_sin;
+ static char user[256]; /* XXX */
+ char buffer[512]; /* XXX */
+ char *cp;
+ static char *result; /* XXX */
+ FILE *fp;
+
+ result = FROM_UNKNOWN;
+ /*
+ * Use one unbuffered stdio stream for writing to and for reading from
+ * the RFC931 etc. server. This is done because of a bug in the SunOS
+ * 4.1.x stdio library. The bug may live in other stdio implementations,
+ * too. When we use a single, buffered, bidirectional stdio stream ("r+"
+ * or "w+" mode) we read our own output. Such behaviour would make sense
+ * with resources that support random-access operations, but not with
+ * sockets.
+ */
+
+ if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) {
+ setbuf(fp, (char *) 0);
+
+ /*
+ * Set up a timer so we won't get stuck while waiting for the server.
+ */
+
+ if (setjmp(timebuf) == 0) {
+ signal(SIGALRM, timeout);
+ alarm(rfc931_timeout);
+
+ /*
+ * Bind the local and remote ends of the query socket to the same
+ * IP addresses as the connection under investigation. We go
+ * through all this trouble because the local or remote system
+ * might have more than one network address. The RFC931 etc.
+ * client sends only port numbers; the server takes the IP
+ * addresses from the query socket.
+ */
+
+ our_query_sin = *our_sin;
+ our_query_sin.sin_port = htons(ANY_PORT);
+ rmt_query_sin = *rmt_sin;
+ rmt_query_sin.sin_port = htons(RFC931_PORT);
+
+ if (bind_connect(fileno(fp),
+ (struct sockaddr *) & our_query_sin,
+ (struct sockaddr *) & rmt_query_sin,
+ sizeof(our_query_sin)) >= 0) {
+
+ /*
+ * Send query to server. Neglect the risk that a 13-byte
+ * write would have to be fragmented by the local system and
+ * cause trouble with buggy System V stdio libraries.
+ */
+
+ fprintf(fp, "%u,%u\r\n",
+ ntohs(rmt_sin->sin_port),
+ ntohs(our_sin->sin_port));
+ fflush(fp);
+
+ /*
+ * Read response from server. Use fgets()/sscanf() so we can
+ * work around System V stdio libraries that incorrectly
+ * assume EOF when a read from a socket returns less than
+ * requested.
+ */
+
+ if (fgets(buffer, sizeof(buffer), fp) != 0
+ && ferror(fp) == 0 && feof(fp) == 0
+ && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
+ &rmt_port, &our_port, user) == 3
+ && ntohs(rmt_sin->sin_port) == rmt_port
+ && ntohs(our_sin->sin_port) == our_port) {
+
+ /*
+ * Strip trailing carriage return. It is part of the
+ * protocol, not part of the data.
+ */
+
+ if ((cp = strchr(user, '\r')))
+ *cp = 0;
+ result = user;
+ }
+ }
+ alarm(0);
+ }
+ fclose(fp);
+ }
+ return (result);
+}
--- /dev/null
+# For gcc
+CC= gcc
+# For ANSI compilers
+#CC= cc
+
+#For Optimization
+#CFLAGS= -O2
+#For debugging
+CFLAGS= -g
+# For SCO ODT
+#EXTRA_LIBS= -lcrypt_i
+
+RM= /bin/rm -f
+#--- You shouldn't have to edit anything else. ---
+
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
+all: htpasswd unescape inc2shtml
+
+ibm: $(OBJS)
+ make all CC=gcc
+
+sun: $(OBJS)
+ make all CC=gcc
+
+hp: $(OBJS)
+ make all CC=gcc
+
+sgi: $(OBJS)
+ make all CC=cc
+
+decmips: $(OBJS)
+ make all CC=cc
+
+decaxp: $(OBJS)
+ make all CC=cc
+
+tar: htpasswd unescape
+ $(RM) htpasswd unescape
+
+htpasswd: htpasswd.c
+ $(CC) $(CFLAGS) htpasswd.c -o htpasswd $(EXTRA_LIBS)
+
+unescape: unescape.c
+ $(CC) $(CFLAGS) unescape.c -o unescape
+
+inc2shtml: inc2shtml.c
+ $(CC) $(CFLAGS) inc2shtml.c -o inc2shtml
+
+clean:
+ rm -f htpasswd unescape inc2shtml
+
--- /dev/null
+Subject: The form for change-passwd
+Newsgroups: comp.infosystems.www
+Organization: NCSA
+Summary:
+Keywords:
+
+
+I've gotten a number of requests for the form that corresponds to the
+change-passwd program that accidentally found itself in the NCSA httpd 1.0
+distribution.
+
+A brief introduction: change-passwd is a way for remote users to change
+their password for user authentication on your system without going through
+you.
+
+To use this form, you must set up user authentication on your system
+(there's a short tutorial at
+http://wintermute.ncsa.uiuc.edu:8080/auth-tutorial/tutorial.html). You will
+want to leave the form unprotected, and the script protected with ``require
+valid-user'' so that any valid user may log in.
+
+Compile change-passwd with USER_FILE set to the location of the
+AuthUserFile, and WIZARD set to the user id you would like to use to perform
+administration (as the wizard, you can change other people's passwords, and
+add new users).
+
+To install the script, place the executable somewhere on your system,
+preferably not in DocumentRoot and not in cgi-bin. Let's say you put it in
+/foo/bar/change-passwd. Add a line to srm.conf which says:
+
+ScriptAlias /change-passwd /foo/bar/change-passwd
+
+A common setup would be to have the following as /foo/bar/.htaccess:
+
+AuthType Basic
+AuthName PasswordAdmin
+AuthUserFile /usr/local/httpd/conf/.htpasswd
+
+<Limit POST>
+require valid-user
+</Limit>
+
+
+At this point, you should try the form. If the change-passwd script core
+dumps, or Mosaic does not prompt you for a user name or password after you
+click on the submit button, you have not set up user authenitcation properly.
+
+
+--
+Rob McCool, robm@ncsa.uiuc.edu
+Software Development Group, National Center for Supercomputing Applications
+It was working ten minutes ago, I swear...
+<A HREF="http://hoohoo.ncsa.uiuc.edu/~robm/sg.html">A must see.</A>
+
+
+Here's the form:
+
+
+<TITLE>Change your password</TITLE>
+<H1>Change your password</H1>
+
+<FORM ACTION="/change-passwd" METHOD="POST">
+
+This is an HTML form used to change your password for HTTP user
+authentication on this system. <P>
+<HR>
+To use this form, you must know your user name on this system, and you must
+know your current password. <P>
+
+First, enter your user name below. If you are defined to be the wizard on
+this server, and wish to change or add a user, enter their name below. <P>
+
+User name: <P><INPUT TYPE="text" NAME="user"><P>
+
+Now, enter what you want to change your password to. <P>
+
+New password: <P><INPUT
+TYPE="password" NAME="newpasswd1"><P> Re-type new password: <P><INPUT
+TYPE="password" NAME="newpasswd2"><P>
+
+When you click on the Change password button below, you will be asked to
+authenticate yourself. If you are changing your own password, use your user
+id and your <EM>old</EM> password to log on. If you are the wizard on this
+server, use your own user id and password to log in.<P>
+
+<INPUT TYPE="submit" VALUE="Change password"><P>
+<INPUT TYPE="reset" VALUE="Reset these fields"><P>
+</FORM>
+
--- /dev/null
+#!/usr/local/bin/perl
+
+# ====================================================================
+# Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+# software must display the following acknowledgment:
+# "This product includes software developed by the Apache Group
+# for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# 4. The names "Apache Server" and "Apache Group" must not be used to
+# endorse or promote products derived from this software without
+# prior written permission.
+#
+# 5. Redistributions of any form whatsoever must retain the following
+# acknowledgment:
+# "This product includes software developed by the Apache Group
+# for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+# EXPRESSED 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 APACHE GROUP OR
+# IT'S 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.
+# ====================================================================
+#
+# This software consists of voluntary contributions made by many
+# individuals on behalf of the Apache Group and was originally based
+# on public domain software written at the National Center for
+# Supercomputing Applications, University of Illinois, Urbana-Champaign.
+# For more information on the Apache Group and the Apache HTTP server
+# project, please see <http://www.apache.org/>.
+
+
+# usage: dbmmanage <DBMfile> <command> <key> <value> <group>
+#
+# commands: add, delete, view, adduser
+#
+# no values needed for delete, no keys or values needed for view.
+# to change a value, simply use "add".
+# adduser encrypts the password:
+# dbmmanage <dbm file> adduser <person> <password>
+#
+# <group> is optional, and may also be supplied to add the user
+# to a specified group:
+# dbmmanage <dbm file> adduser <person> <password> <group>
+
+if (scalar(@ARGV) < 2) {
+ print "Too few arguments.\n";
+ exit;
+}
+
+# ugly - this should be changed to be random.
+$salt="XX";
+$file=$ARGV[0];
+$command=$ARGV[1];
+$key=$ARGV[2];
+$value=$ARGV[3];
+$group=$ARGV[4];
+
+if ($command eq "add") {
+ dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+ $value .= ":$group" if $group ne "";
+ $DB{$key} = $value;
+ dbmclose(%DB);
+ print "Entry $key added with value $value.\n";
+ exit;
+}
+
+if ($command eq "adduser") {
+ $hash = crypt($value, "$salt");
+ dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+ $hash .= ":$group" if $group ne "";
+ $value .= ":$group" if $group ne "";
+ $DB{$key} = $hash;
+ dbmclose(%DB);
+ print "User $key added with password $value, encrypted to $hash\n";
+ exit;
+}
+
+if ($command eq "delete") {
+ dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+ delete($DB{$key});
+ dbmclose(%DB);
+ exit;
+}
+
+if ($command eq "view") {
+ dbmopen(%DB, $file, undef) || die "Error: $!\n";
+ $return_status = 1;
+ unless ($key) {
+ while (($nkey,$val) = each %DB) {
+ print "$nkey = $val\n";
+ }
+ } else {
+ $return_status = 0 if defined $DB{$key};
+ print "$key = $DB{$key}\n";
+ }
+ dbmclose(%DB);
+ exit($return_status);
+}
+
+print "Command unrecognized - must be one of: view, add, adduser, delete.\n";
+
--- /dev/null
+#!/usr/local/bin/perl
+
+# ====================================================================
+# Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+# software must display the following acknowledgment:
+# "This product includes software developed by the Apache Group
+# for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# 4. The names "Apache Server" and "Apache Group" must not be used to
+# endorse or promote products derived from this software without
+# prior written permission.
+#
+# 5. Redistributions of any form whatsoever must retain the following
+# acknowledgment:
+# "This product includes software developed by the Apache Group
+# for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+# EXPRESSED 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 APACHE GROUP OR
+# IT'S 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.
+# ====================================================================
+#
+# This software consists of voluntary contributions made by many
+# individuals on behalf of the Apache Group and was originally based
+# on public domain software written at the National Center for
+# Supercomputing Applications, University of Illinois, Urbana-Champaign.
+# For more information on the Apache Group and the Apache HTTP server
+# project, please see <http://www.apache.org/>.
+
+
+# usage: dbmmanage <DBMfile> <command> <key> <value>
+#
+# commands: add, delete, view, adduser
+#
+# no values needed for delete, no keys or values needed for view.
+# to change a value, simply use "add".
+# adduser encrypts the password:
+# dbmmanage <dbm file> adduser <person> <password>
+
+die "Too few arguments.\n" if (@ARGV < 2);
+
+($file,$command,$key,$value) = @ARGV;
+
+$file =~ s/\.db.?$//; # remove ".db" or ".dbX" extension if any
+$file =~ s/\.pag$//; # remove ".pag" and ".dir" as well.
+$file =~ s/\.dir$//; # these are all common DBM extensions.
+
+if ($command eq "add") {
+ dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+ $DB{$key} = $value;
+ dbmclose(%DB);
+ print "Entry $key added with value $value.\n";
+} elsif ($command eq "adduser") {
+ srand; # needs to be done only once.
+ $salt = &compute_salt(0); # change to compute_salt(1) for new crypt()
+ $hash = crypt($value, $salt);
+ dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+ $DB{$key} = $hash;
+ dbmclose(%DB);
+ print "User $key added with password ``$value'', encrypted to $hash\n";
+} elsif ($command eq "delete") {
+ dbmopen(%DB, $file, 0664) || die "Error: $!\n";
+ delete($DB{$key});
+ dbmclose(%DB);
+} elsif ($command eq "view") {
+ dbmopen(%DB, $file, undef) || die "Error: $!\n";
+ unless ($key) {
+ while (($nkey,$val) = each %DB) {
+ print "$nkey = $val\n";
+ }
+ } else {
+ print "$key = $DB{$key}\n";
+ }
+ dbmclose(%DB);
+} else {
+ print "Command unrecognized - must be one of: view, add, adduser, delete.\n";
+}
+
+exit(0);
+
+# if $newstyle is 1, then use new style salt (starts with '_' and contains
+# four bytes of iteration count and four bytes of salt). Otherwise, just use
+# the traditional two-byte salt.
+# see the man page on your system to decide if you have a newer crypt() lib.
+# I believe that 4.4BSD derived systems do (at least BSD/OS 2.0 does).
+# The new style crypt() allows up to 20 characters of the password to be
+# significant rather than only 8.
+sub compute_salt {
+ local($newstyle) = @_;
+ local($salt);
+ if ($newstyle) {
+ $salt = "_" . &randchar(1) . "a.." . &randchar(4);
+ } else {
+ $salt = &randchar(2);
+ }
+ $salt;
+}
+
+# return $count random characters
+sub randchar {
+ local($count) = @_;
+ local($str) = "";
+ local($enc) =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ while ($count--) {
+ # 64 = length($enc) in call to rand() below
+ $str .= substr($enc,int(rand(64))+1,1);
+ }
+ $str;
+}
--- /dev/null
+Two versions of the dbmmanage script are included with this release.
+One is the old faithful version, which should continue to work if you've
+been using it; the other is a newer cut, which can be easily modified to
+support the newer extended crypt routines which are present on some
+systems (including 4.4BSD derivatives); this newer version is, for the
+nonce, experimental...
--- /dev/null
+/*
+ * htpasswd.c: simple program for manipulating password file for NCSA httpd
+ *
+ * Rob McCool
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/signal.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define LF 10
+#define CR 13
+
+#define MAX_STRING_LEN 256
+
+char *tn;
+
+char *strd(char *s) {
+ char *d;
+
+ d=(char *)malloc(strlen(s) + 1);
+ strcpy(d,s);
+ return(d);
+}
+
+void getword(char *word, char *line, char stop) {
+ int x = 0,y;
+
+ for(x=0;((line[x]) && (line[x] != stop));x++)
+ word[x] = line[x];
+
+ word[x] = '\0';
+ if(line[x]) ++x;
+ y=0;
+
+ while(line[y++] = line[x++]);
+}
+
+int getline(char *s, int n, FILE *f) {
+ register int i=0;
+
+ while(1) {
+ s[i] = (char)fgetc(f);
+
+ if(s[i] == CR)
+ s[i] = fgetc(f);
+
+ if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) {
+ s[i] = '\0';
+ return (feof(f) ? 1 : 0);
+ }
+ ++i;
+ }
+}
+
+void putline(FILE *f,char *l) {
+ int x;
+
+ for(x=0;l[x];x++) fputc(l[x],f);
+ fputc('\n',f);
+}
+
+
+/* From local_passwd.c (C) Regents of Univ. of California blah blah */
+static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+to64(s, v, n)
+ register char *s;
+ register long v;
+ register int n;
+{
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+char *crypt(char *pw, char *salt); /* why aren't these prototyped in include */
+
+void add_password(char *user, FILE *f) {
+ char *pw, *cpw, salt[3];
+
+ pw = strd(getpass("New password:"));
+ if(strcmp(pw,getpass("Re-type new password:"))) {
+ fprintf(stderr,"They don't match, sorry.\n");
+ if(tn)
+ unlink(tn);
+ exit(1);
+ }
+ (void)srand((int)time((time_t *)NULL));
+ to64(&salt[0],rand(),2);
+ cpw = crypt(pw,salt);
+ free(pw);
+ fprintf(f,"%s:%s\n",user,cpw);
+}
+
+void usage() {
+ fprintf(stderr,"Usage: htpasswd [-c] passwordfile username\n");
+ fprintf(stderr,"The -c flag creates a new file.\n");
+ exit(1);
+}
+
+void interrupted() {
+ fprintf(stderr,"Interrupted.\n");
+ if(tn) unlink(tn);
+ exit(1);
+}
+
+main(int argc, char *argv[]) {
+ FILE *tfp,*f;
+ char user[MAX_STRING_LEN];
+ char line[MAX_STRING_LEN];
+ char l[MAX_STRING_LEN];
+ char w[MAX_STRING_LEN];
+ char command[MAX_STRING_LEN];
+ int found;
+
+ tn = NULL;
+ signal(SIGINT,(void (*)())interrupted);
+ if(argc == 4) {
+ if(strcmp(argv[1],"-c"))
+ usage();
+ if(!(tfp = fopen(argv[2],"w"))) {
+ fprintf(stderr,"Could not open passwd file %s for writing.\n",
+ argv[2]);
+ perror("fopen");
+ exit(1);
+ }
+ printf("Adding password for %s.\n",argv[3]);
+ add_password(argv[3],tfp);
+ fclose(tfp);
+ exit(0);
+ } else if(argc != 3) usage();
+
+ tn = tmpnam(NULL);
+ if(!(tfp = fopen(tn,"w"))) {
+ fprintf(stderr,"Could not open temp file.\n");
+ exit(1);
+ }
+
+ if(!(f = fopen(argv[1],"r"))) {
+ fprintf(stderr,
+ "Could not open passwd file %s for reading.\n",argv[1]);
+ fprintf(stderr,"Use -c option to create new one.\n");
+ exit(1);
+ }
+ strcpy(user,argv[2]);
+
+ found = 0;
+ while(!(getline(line,MAX_STRING_LEN,f))) {
+ if(found || (line[0] == '#') || (!line[0])) {
+ putline(tfp,line);
+ continue;
+ }
+ strcpy(l,line);
+ getword(w,l,':');
+ if(strcmp(user,w)) {
+ putline(tfp,line);
+ continue;
+ }
+ else {
+ printf("Changing password for user %s\n",user);
+ add_password(user,tfp);
+ found = 1;
+ }
+ }
+ if(!found) {
+ printf("Adding user %s\n",user);
+ add_password(user,tfp);
+ }
+ fclose(f);
+ fclose(tfp);
+ sprintf(command,"cp %s %s",tn,argv[1]);
+ system(command);
+ unlink(tn);
+}
--- /dev/null
+.TH httpd 1m "October 1995"
+.\" Copyright (c) 1995 David Robinson. 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. All advertising materials mentioning features or use of this
+.\" software must display the following acknowledgment:
+.\" "This product includes software developed by the Apache Group
+.\" for use in the Apache HTTP server project (http://www.apache.org/)."
+.\"
+.\" 4. The names "Apache Server" and "Apache Group" must not be used to
+.\" endorse or promote products derived from this software without
+.\" prior written permission.
+.\"
+.\" 5. Redistributions of any form whatsoever must retain the following
+.\" acknowledgment:
+.\" "This product includes software developed by the Apache Group
+.\" for use in the Apache HTTP server project (http://www.apache.org/)."
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+.\" EXPRESSED 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 APACHE GROUP OR
+.\" IT'S 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.
+.\" ====================================================================
+.\"
+.\" This software consists of voluntary contributions made by many
+.\" individuals on behalf of the Apache Group and was originally based
+.\" on public domain software written at the National Center for
+.\" Supercomputing Applications, University of Illinois, Urbana-Champaign.
+.\" For more information on the Apache Group and the Apache HTTP server
+.\" project, please see <http://www.apache.org/>.
+.SH NAME
+httpd \- Apache hypertext transfer protocol server
+.SH SYNOPSIS
+.B httpd
+[
+.B \-vX?
+] [
+.BI \-d " serverroot"
+] [
+.BI \-f " config"
+]
+.SH DESCRIPTION
+.B httpd
+is the Apache HyperText Transfer Protocol (HTTP) server process. The server may
+be invoked by the Internet daemon inetd(1M) each time a connection to the
+HTTP service is made, or alternatively it may run as a daemon.
+.SH OPTIONS
+.TP 12
+.BI \-d " serverroot"
+Set the initial value for the ServerRoot variable to \fIserverroot\fP. This
+can be overridden by the ServerRoot command in the configuration file. The
+default is \fB/usr/local/etc/httpd\fP.
+.TP
+.BI \-f " config"
+Execute the commands in the file \fIconfig\fP on startup. If \fIconfig\fP
+does not begin with a /, then it is taken to be a path relative to
+the ServerRoot. The default is \fBconf/httpd.conf\fP.
+.TP
+.B \-X
+Run in single-process mode, for internal debugging purposes only; the daemon
+does not detach from the terminal or fork any children. Do NOT use this mode
+to provide ordinary web service.
+.TP
+.B \-v
+Print the version of httpd, and then exit.
+.TP
+.B \-?
+Print a list of the httpd options, and then exit.
+.SH FILES
+.PD 0
+.B /usr/local/etc/httpd/conf/httpd.conf
+.br
+.B /usr/local/etc/httpd/conf/srm.conf
+.br
+.B /usr/local/etc/httpd/conf/access.conf
+.br
+.B /usr/local/etc/httpd/conf/mime.types
+.br
+.B /usr/local/etc/httpd/logs/error_log
+.br
+.B /usr/local/etc/httpd/logs/access_log
+.br
+.B /usr/local/etc/httpd/logs/httpd.pid
+.PD
+.SH SEE ALSO
+.BR inetd (1m).
+.PP
+Documentation for the Apache http server is available from
+http://www.apache.org
--- /dev/null
+#!/usr/local/bin/perl
+
+# ====================================================================
+# Copyright (c) 1995 The Apache Group. 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. All advertising materials mentioning features or use of this
+# software must display the following acknowledgment:
+# "This product includes software developed by the Apache Group
+# for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# 4. The names "Apache Server" and "Apache Group" must not be used to
+# endorse or promote products derived from this software without
+# prior written permission.
+#
+# 5. Redistributions of any form whatsoever must retain the following
+# acknowledgment:
+# "This product includes software developed by the Apache Group
+# for use in the Apache HTTP server project (http://www.apache.org/)."
+#
+# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+# EXPRESSED 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 APACHE GROUP OR
+# IT'S 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.
+# ====================================================================
+#
+# This software consists of voluntary contributions made by many
+# individuals on behalf of the Apache Group and was originally based
+# on public domain software written at the National Center for
+# Supercomputing Applications, University of Illinois, Urbana-Champaign.
+# For more information on the Apache Group and the Apache HTTP server
+# project, please see <http://www.apache.org/>.
+
+
+# simple script to monitor the child Apache processes
+# Usage:
+# httpd_monitor N
+# Will give you an update ever N seconds
+# If you choose 0, it might chew up lots of CPU time.
+#
+# Output explanation..
+#
+# s = sleeping but "ready to go" child
+# R = active child
+# _ = dead child (no longer needed)
+
+
+$PID_FILE = "/usr/local/httpd/logs/httpd.pid";
+$MAX_PROC = 40; # we never have (or are interested in) more than 40 children
+
+#########################################################################
+select STDOUT; $| = 1;
+
+$delay = @ARGV[0];
+
+if ($delay =~ /\-h/i) {
+ print STDERR "usage:\n$0 [i]\n i = interval in seconds (defaults to 1)\n";
+ exit(0);
+}
+
+$delay = 1 unless $delay =~ /^[0-9]+$/;
+
+open (P, "$PID_FILE") || die "Unable to open $PID_FILE";
+$PID = <P>;
+$ext = sprintf("a%05d", $PID);
+close(P);
+
+open (SB, "/tmp/htstatus.$ext") || die "Unable to open scoreboard file /tmp/htstatus.$ext";
+
+$last_len = 0;
+while (1) {
+
+ if ( ($last_mod = (stat("/tmp/htstatus.$ext"))[9]) != $before) {
+ open (SB, "/tmp/htstatus.$ext") || die "Unable to open scoreboard file /tmp/htstatus.$ext";
+ seek(SB, 2 , 0);
+
+ $len = 0; $pad =""; $running = 0; $dead = 0; $total=0;
+ for ( $child=1; $child<=$MAX_PROC; $child++) {
+
+ read(SB, $p1, 1); # 2nd word = process number
+ read(SB, $p2, 1); # 2nd word = process number
+ $p = hex(sprintf("%02X%02X", ord($p1), ord($p2)));
+
+ read(SB, $status, 1); # next byte = status
+ $status = ord($status);
+
+ read(SB, $junk, 5); # skip to next entry
+
+ $c = sprintf("%X", $child);
+
+ if ($p != 0 && $p != $PID) {
+ $total++;
+ if ($status == 1) {
+ $c = "s";
+ } else {
+ $c = "R";
+ ++$running;
+ }
+ $printed .= "$pad$c";
+
+ $pad = "";
+ $dead = 0;
+ } else {
+ $dead++;
+ $pad = "_"x$dead;
+ }
+ }
+ $printed .= " ($running/$total)";
+ $len = length($printed);
+
+ if ($last_len > $len) {
+ print "\010"x$last_len ;
+ print " "x$last_len ;
+ print "\010"x$last_len ;
+ } else {
+ print "\010"x$len ;
+ }
+ print $printed; $printed = "";
+
+ $before = $last_mod;
+ close(SB);
+ $last_len = $len;
+ }
+ sleep($delay) if $delay >0;
+}
+
+
+
--- /dev/null
+/*
+ * inc2shtml: Convert httpd <1.1 style includes to 1.2 style
+ *
+ * Rob McCool
+ *
+ * Usage: inc2shtml [filename]
+ *
+ * If filename is given, this program will open filename. If not, it will
+ * look on stdin. It will output the new shtml file on stdout.
+ */
+
+
+#include <stdio.h>
+#ifdef sony_mips_bsd
+#include <ctype.h>
+#endif
+
+#define MAX_STRING_LEN 256
+
+void usage(char *argv0) {
+ fprintf(stderr,"Usage: %s [filename]\n",argv0);
+ fprintf(stderr,"If filename is given, this program will open filename.\n");
+ fprintf(stderr,"If not, it will look on stdin for the inc file.\n");
+ fprintf(stderr,
+ "In either case, it will write the new shtml file on stdout.\n");
+ exit(1);
+}
+
+void translate_tag(char *tag, FILE *fd) {
+ char *tp = tag, *tp2;
+ int url;
+
+ url = (*tp == 'U' || *tp == 'u' ? 1 : 0);
+
+ while(*tp++ != '\"');
+ tp2 = tp + 1;
+ while(*tp2 != '\"') ++tp2;
+ *tp2 = '\0';
+ if(*tp == '|') {
+ fprintf(fd,"<!--#exec cmd=\"%s",++tp);
+ if(url) fputs(" '$QUERY_STRING_UNESCAPED'",fd);
+ fputs("\"-->",fd);
+ } else
+ fprintf(fd,"<!--#include virtual=\"%s\"-->",tp);
+}
+
+main(int argc, char *argv[]) {
+ FILE *f;
+ int c,x,p;
+ char c2;
+ char *lookfor = "<inc srv";
+
+ switch(argc) {
+ case 1:
+ f = stdin;
+ break;
+ case 2:
+ if(!(f = fopen(argv[1],"r"))) {
+ perror("fopen");
+ exit(1);
+ }
+ break;
+ default:
+ usage(argv[0]);
+ }
+
+ p=0;
+ while(1) {
+ c = fgetc(f);
+ if(c == -1) {
+ fflush(stdout);
+ exit(0);
+ }
+ c2 = (char)c;
+ if(isalpha((char)c))
+ c = tolower((char)c);
+ if(c == lookfor[p]) {
+ if(!lookfor[++p]) {
+ char tag[MAX_STRING_LEN];
+
+ x=0;
+ c = fgetc(f); /* get space */
+ while(c != '>') {
+ tag[x++] = c;
+ c = fgetc(f);
+ if(c == -1) {
+ fputs("<inc srv ",stdout);
+ fputs(tag,stdout);
+ fflush(stdout);
+ exit(1);
+ }
+ }
+ tag[x] = '\0';
+ translate_tag(tag,stdout);
+ p = 0;
+ }
+ }
+ else {
+ for(x=0;x<p;x++)
+ fputc(lookfor[x],stdout);
+ fputc(c2,stdout);
+ p=0;
+ }
+ }
+}
--- /dev/null
+/*** ***\
+
+ logresolve 1.0
+
+ Tom Rathborne - tomr@uunet.ca - http://www.uunet.ca/~tomr/
+ UUNET Canada, April 16, 1995
+
+ Usage: logresolve [arguments] < access_log > new_log
+
+ Arguments: if you give any arguments, statistics are printed to STDERR.
+
+ Notes:
+
+ To generate meaningful statistics from an HTTPD log file, it's good
+ to have the domain name of each machine that accessed your site, but
+ doing this on the fly can slow HTTPD down.
+
+ Compiling NCSA HTTPD with the -DMINIMAL_DNS flag turns IP#->hostname
+ resolution off. Before running your stats program, just run your log
+ file through this program (logresolve) and all of your IP numbers will
+ be resolved into hostnames (where possible).
+
+ logresolve takes an HTTPD access log (in the COMMON log file format,
+ or any other format that has the IP number/domain name as the first
+ field for that matter), and outputs the same file with all of the
+ domain names looked up. Where no domain name can be found, the IP
+ number is left in.
+
+ To minimize impact on your nameserver, logresolve has its very own
+ internal hash-table cache. This means that each IP number will only
+ be looked up the first time it is found in the log file. As noted
+ above, giving any command-line arguments to logresolve (anything at
+ all!) will give you some statistics on the log file and the cache,
+ printed to STDERR.
+
+\*** ***/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
+
+/* maximum line length */
+#define MAXLINE 1024
+
+/* maximum length of an IP number as a string */
+#define IPSTRLEN 16
+
+/* number of buckets in cache hash table */
+#define BUCKETS 256
+
+/*
+ * struct nsrec - record of nameservice for cache linked list
+ *
+ * ipnum - IP number hostname - hostname noname - nonzero if IP number has no
+ * hostname, i.e. hostname=IP number
+ */
+
+struct nsrec {
+ unsigned char ipnum[4];
+ char *hostname;
+ int noname;
+ struct nsrec *next;
+} *nscache[BUCKETS];
+
+/*
+ * statistics - obvious
+ */
+
+int cachehits = 0;
+int cachesize = 0;
+int entries = 0;
+int resolves = 0;
+int withname = 0;
+int yucky = 0;
+int noname = 0;
+
+/*
+ * ipsame - takes two IP numbers and returns TRUE if they're the same
+ */
+
+int
+ipsame(ipnum1, ipnum2)
+ unsigned char ipnum1[4];
+ unsigned char ipnum2[4];
+{
+ return (ipnum1[0] == ipnum2[0]
+ && ipnum1[1] == ipnum2[1]
+ && ipnum1[2] == ipnum2[2]
+ && ipnum1[3] == ipnum2[3]);
+}
+
+/*
+ * ipbuild - makes an IP number char array from 4 integers
+ */
+
+ipbuild(ipnum, a, b, c, d)
+ unsigned char ipnum[4];
+ unsigned int a, b, c, d;
+{
+ ipnum[0] = a;
+ ipnum[1] = b;
+ ipnum[2] = c;
+ ipnum[3] = d;
+}
+
+/*
+ * ipstr - converts an IP number to a string
+ */
+
+char *
+ipstr(string, ipnum)
+ char *string;
+ unsigned char ipnum[4];
+{
+ sprintf(string, "%d.%d.%d.%d", ipnum[0], ipnum[1], ipnum[2], ipnum[3]);
+ return (string);
+}
+
+/*
+ * cgethost - gets hostname by IP address, caching, and adding unresolvable
+ * IP numbers with their IP number as hostname, setting noname flag
+ */
+
+cgethost(string, ipnum)
+ char *string;
+ unsigned char ipnum[4];
+{
+ struct nsrec *current;
+ struct hostent *hostdata;
+
+ current = nscache[((ipnum[0] + ipnum[1] + ipnum[2] + ipnum[3]) % BUCKETS)];
+
+ while (current->next && !ipsame(ipnum, current->next->ipnum))
+ current = current->next;
+
+ if (!current->next) {
+ cachesize++;
+ current->next = (struct nsrec *) malloc(sizeof(struct nsrec));
+ current = current->next;
+ current->next = 0;
+ current->noname = 0;
+
+ current->ipnum[0] = ipnum[0];
+ current->ipnum[1] = ipnum[1];
+ current->ipnum[2] = ipnum[2];
+ current->ipnum[3] = ipnum[3];
+
+ if (hostdata = gethostbyaddr((const char *) ipnum, 4, AF_INET)) {
+ current->hostname = (char *) malloc(strlen(hostdata->h_name) + 1);
+ strcpy(current->hostname, hostdata->h_name);
+ } else {
+ noname++;
+ current->noname = 1;
+ current->hostname = (char *) malloc(IPSTRLEN);
+ ipstr(current->hostname, current->ipnum);
+ }
+ } else {
+ current = current->next;
+ cachehits++;
+ }
+ strcpy(string, current->hostname);
+}
+
+/*
+ * gets a line from stdin
+ */
+
+int
+getline(s, n)
+ char *s;
+ int n;
+{
+ char *cp;
+
+ if (!fgets(s, n, stdin))
+ return (1);
+ if (cp = strchr(s, '\n'))
+ *cp = '\0';
+ return (0);
+}
+
+/*
+ * prints various statistics to output
+ */
+
+stats(output)
+ FILE *output;
+{
+ int i, ipstring[IPSTRLEN];
+ struct nsrec *current;
+
+ fprintf(output, "logresolve Statistics:\n");
+
+ fprintf(output, "Entries: %d\n", entries);
+ fprintf(output, " With name : %d\n", withname);
+ fprintf(output, " Resolves : %d\n", resolves);
+ fprintf(output, " - Yucky : %d\n", yucky);
+ fprintf(output, " - No name : %d\n", noname);
+ fprintf(output, "Cache hits : %d\n", cachehits);
+ fprintf(output, "Cache size : %d\n", cachesize);
+ fprintf(output, "Cache buckets : IP number * hostname\n");
+
+ for (i = 0; i < BUCKETS; i++) {
+ current = nscache[i];
+ while (current->next) {
+ ipstr(ipstring, current->next->ipnum);
+ if (current->next->noname)
+ fprintf(output, " %3d %15s ! %s\n", i, ipstring, current->next->hostname);
+ else
+ fprintf(output, " %3d %15s - %s\n", i, ipstring, current->next->hostname);
+ current = current->next;
+ }
+ }
+}
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ unsigned char ipnum[4];
+ char *foo, *bar, hoststring[MAXLINE], ipstring[IPSTRLEN], line[MAXLINE],
+ nl[MAXLINE];
+ int i, ip;
+
+ for (i = 0; i < BUCKETS; i++) {
+ nscache[i] = (struct nsrec *) malloc(sizeof(struct nsrec));
+ nscache[i]->next = 0;
+ nscache[i]->noname = 0;
+ }
+
+ while (!getline(line, MAXLINE) && *line) {
+ entries++;
+ if ((*line < '0') || (*line > '9')) {
+ printf("%s\n", line);
+ withname++;
+ } else {
+ resolves++;
+ ip = 1;
+ strcpy(nl, line);
+ foo = nl;
+ bar = nl;
+ for (i = 0; (i < 4) && ip; i++) {
+ while (*bar != '.' && *bar != ' ')
+ bar++;
+ *bar = 0;
+ ipnum[i] = atoi(foo);
+ foo = ++bar;
+ if (((*bar < '0') || (*bar > '9')) && i < 3)
+ ip = 0;
+ }
+ if (ip) {
+ cgethost(hoststring, ipnum);
+ printf("%s %s\n", hoststring, bar);
+ } else {
+ yucky++;
+ printf("%s\n", line);
+ }
+ }
+ }
+
+ if (--argc)
+ stats(stderr);
+
+ return (0);
+}
+-- end
+
+
--- /dev/null
+/*
+ * Short program to unescape a URL string
+ *
+ * Rob McCool
+ *
+ */
+
+#include <stdio.h>
+
+void plustospace(char *str) {
+ register int x;
+
+ for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
+}
+
+char x2c(char *what) {
+ register char digit;
+
+ digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
+ digit *= 16;
+ digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
+ return(digit);
+}
+
+void unescape_url(char *url) {
+ register int x,y;
+
+ for(x=0;url[x];x++)
+ if(url[x] == '%')
+ url[x+1] = x2c(&url[x+1]);
+
+ for(x=0,y=0;url[y];++x,++y) {
+ if((url[x] = url[y]) == '%') {
+ url[x] = url[y+1];
+ y+=2;
+ }
+ }
+ url[x] = '\0';
+}
+
+int ind(char *s, char c) {
+ register int x;
+
+ for(x=0;s[x];x++)
+ if(s[x] == c) return x;
+
+ return -1;
+}
+
+void escape_shell_cmd(char *cmd) {
+ register int x,y,l;
+
+ l=strlen(cmd);
+ for(x=0;cmd[x];x++) {
+ if(ind("&;`'|*?-~<>^()[]{}$\\",cmd[x]) != -1){
+ for(y=l+1;y>x;y--)
+ cmd[y] = cmd[y-1];
+ l++; /* length has been increased */
+ cmd[x] = '\\';
+ x++; /* skip the character */
+ }
+ }
+}
+
+void usage(char *name) {
+ fprintf(stderr,"Usage:\n%s [-e] url\n",name);
+ fprintf(stderr,
+"The -e switch automatically escapes shell characters like ^ and &\n");
+ fprintf(stderr,"and url is the encoded url string\n");
+ exit(1);
+}
+
+main(int argc, char *argv[]) {
+
+ if((argc != 2) && (argc != 3))
+ usage(argv[0]);
+ else {
+ char *t;
+
+ t = (char *) malloc(sizeof(char) * (strlen(argv[argc-1])+1));
+ strcpy(t,argv[argc-1]);
+ plustospace(t);
+ unescape_url(t);
+ if(argc == 3) {
+ if(strcmp(argv[1],"-e"))
+ usage(argv[0]);
+ escape_shell_cmd(t);
+ }
+ printf("%s",t);
+ }
+}