From: (no author) <(no author)@unknown> Date: Sun, 14 Jan 1996 18:49:51 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create branch 'APACHE_1_0_0'. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=97ec792ae25c068c2f7c8d758ecdf0f9571c5706;p=thirdparty%2Fapache%2Fhttpd.git This commit was manufactured by cvs2svn to create branch 'APACHE_1_0_0'. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3@76316 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/APACHE_1_0_0/CHANGES b/APACHE_1_0_0/CHANGES new file mode 100644 index 00000000000..bab431d3eaf --- /dev/null +++ b/APACHE_1_0_0/CHANGES @@ -0,0 +1,92 @@ +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. + +*) is more general --- just about any srm.conf or + httpd.conf command can go in a 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). + + diff --git a/APACHE_1_0_0/LICENSE b/APACHE_1_0_0/LICENSE new file mode 100644 index 00000000000..849d606941a --- /dev/null +++ b/APACHE_1_0_0/LICENSE @@ -0,0 +1,56 @@ + +/* ==================================================================== + * 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 . + * + */ + + + + diff --git a/APACHE_1_0_0/README b/APACHE_1_0_0/README new file mode 100644 index 00000000000..2cd2c272bc1 --- /dev/null +++ b/APACHE_1_0_0/README @@ -0,0 +1,67 @@ + 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 . + +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 +. + +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. + diff --git a/APACHE_1_0_0/cgi-bin/archie b/APACHE_1_0_0/cgi-bin/archie new file mode 100755 index 00000000000..ec056df5f47 --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/archie @@ -0,0 +1,27 @@ +#!/bin/sh + +ARCHIE=/usr/local/bin/archie + + +echo Content-type: text/html +echo + +if [ -x $ARCHIE ]; then + if [ $# = 0 ]; then + cat << EOM +Archie Gateway +

Archie Gateway

+ + + +This is a gateway to archie. Type search query in your browser's search +dialog.

+EOM + else + echo \ + $ARCHIE "$*" + fi +else + echo Cannot find archie on this system. +fi + diff --git a/APACHE_1_0_0/cgi-bin/calendar b/APACHE_1_0_0/cgi-bin/calendar new file mode 100755 index 00000000000..fd340d0ee5f --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/calendar @@ -0,0 +1,28 @@ +#!/bin/sh + +CAL=/bin/cal + +echo Content-type: text/html +echo + +if [ -x $CAL ]; then + if [ $# = 0 ]; then + cat << EOM +Calendar +

Calendar

+ + + +To look up a calendar month, type the month followed by a space then the year.

+Example: 3 1993 would give the calendar for March 1993. + +EOM + else + echo \ + $CAL $* + fi +else + echo Cannot find cal on this system. +fi + + diff --git a/APACHE_1_0_0/cgi-bin/date b/APACHE_1_0_0/cgi-bin/date new file mode 100755 index 00000000000..fcdce04d197 --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/date @@ -0,0 +1,14 @@ +#!/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 + + diff --git a/APACHE_1_0_0/cgi-bin/finger b/APACHE_1_0_0/cgi-bin/finger new file mode 100755 index 00000000000..3b8d6244bd5 --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/finger @@ -0,0 +1,26 @@ +#!/bin/sh + +FINGER=/usr/ucb/finger + +echo Content-type: text/html +echo + +if [ -x $FINGER ]; then + if [ $# = 0 ]; then + cat << EOM +Finger Gateway +

Finger Gateway

+ + + +This is a gateway to "finger". Type a user@host combination in your browser's +search dialog.

+EOM + else + echo \ + $FINGER "$*" + fi +else + echo Cannot find finger on this system. +fi + diff --git a/APACHE_1_0_0/cgi-bin/fortune b/APACHE_1_0_0/cgi-bin/fortune new file mode 100755 index 00000000000..3166e970fc5 --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/fortune @@ -0,0 +1,14 @@ +#!/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 + + diff --git a/APACHE_1_0_0/cgi-bin/nph-test-cgi b/APACHE_1_0_0/cgi-bin/nph-test-cgi new file mode 100755 index 00000000000..1014bf4f46f --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/nph-test-cgi @@ -0,0 +1,29 @@ +#!/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 diff --git a/APACHE_1_0_0/cgi-bin/test-cgi b/APACHE_1_0_0/cgi-bin/test-cgi new file mode 100644 index 00000000000..97489710d9b --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/test-cgi @@ -0,0 +1,28 @@ +#!/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 diff --git a/APACHE_1_0_0/cgi-bin/test-cgi.tcl b/APACHE_1_0_0/cgi-bin/test-cgi.tcl new file mode 100755 index 00000000000..9eefdbd724d --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/test-cgi.tcl @@ -0,0 +1,56 @@ +#!/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 "" +puts "" +puts "CGI/1.0 TCL script report:" +puts "" + +puts "" +puts "

Command Line Arguments

" +puts "argc is $argc. argv is $argv." +puts "" + +puts "

Message

" +puts "
"
+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 "
" + +puts "

Environment Variables

" +puts "
" +foreach var $envvars { + if {[info exists env($var)]} { + puts -nonewline "
$var" + eval {set val $env($var)} + if {[llength $val] > 1} { + puts "
" + foreach subval [lsort $val] { + puts "$subval" + } + } else { + puts "
$val" + } + } +} +puts "
" +puts "" +puts "" +###################### +# end of tcl-cgi.tcl +###################### + diff --git a/APACHE_1_0_0/cgi-bin/uptime b/APACHE_1_0_0/cgi-bin/uptime new file mode 100755 index 00000000000..c05baea0a86 --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/uptime @@ -0,0 +1,14 @@ +#!/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 + + diff --git a/APACHE_1_0_0/cgi-bin/wais.pl b/APACHE_1_0_0/cgi-bin/wais.pl new file mode 100755 index 00000000000..f3a967ffcbe --- /dev/null +++ b/APACHE_1_0_0/cgi-bin/wais.pl @@ -0,0 +1,88 @@ +#!/usr/local/bin/perl +# +# wais.pl -- WAIS search interface +# +# wais.pl,v 1.2 1994/04/10 05:33:29 robm Exp +# +# Tony Sanders , 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 "\nIndex of ", $title, "\n\n"; + print "\n

", $title, "

\n"; + + print "This is an index of the information on this server. Please\n"; + print "type a query in the search dialog.\n

"; + print "You may use compound searches, such as: environment AND cgi\n"; + print ""; +} + +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 "\nSearch of ", $title, "\n\n"; + print "\n

", $title, "

\n"; + + print "Index \`$src\' contains the following\n"; + print "items relevant to \`$pquery\':

\n"; + print "

\n"; + + local($hits, $score, $headline, $lines, $bytes, $type, $date); + while () { + /: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 "
\n"; + + if ($hits == 0) { + print "Nothing found.\n"; + } + print "\n"; +} + +sub docdone { + if ($headline =~ /Search produced no result/) { + print "
"; + print $headline, "

\n

";
+# the following was &'safeopen
+        open(WAISCAT, "$waisd/$src.cat") || die "$src.cat: $!";
+        while () {
+            s#(Catalog for database:)\s+.*#$1 $src.src#;
+            s#Headline:\s+(.*)#Headline: $1#;
+            print;
+        }
+        close(WAISCAT);
+        print "\n
\n"; + } else { + print "
$headline\n"; + print "
Score: $score, Lines: $lines, Bytes: $bytes\n"; + } + $score = $headline = $lines = $bytes = $type = $date = ''; +} + +open (STDERR,"> /dev/null"); +eval '&do_wais'; diff --git a/APACHE_1_0_0/cgi-src/Makefile b/APACHE_1_0_0/cgi-src/Makefile new file mode 100755 index 00000000000..09f36aacad6 --- /dev/null +++ b/APACHE_1_0_0/cgi-src/Makefile @@ -0,0 +1,61 @@ +# 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 + diff --git a/APACHE_1_0_0/cgi-src/change-passwd.c b/APACHE_1_0_0/cgi-src/change-passwd.c new file mode 100644 index 00000000000..4fe86633d03 --- /dev/null +++ b/APACHE_1_0_0/cgi-src/change-passwd.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include + +#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("forms overview.%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("User Mismatch"); + printf("

User Mismatch

"); + printf("The username you gave does not correspond with the "); + printf("user you authenticated as.\n"); + exit(1); + } + if(strcmp(p1,p2)) { + printf("Password Mismatch"); + printf("

Password Mismatch

"); + 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("Successful Change"); + printf("

Successful Change

"); + printf("Your password has been successfully changed.

"); + exit(0); +} diff --git a/APACHE_1_0_0/cgi-src/imagemap.c b/APACHE_1_0_0/cgi-src/imagemap.c new file mode 100644 index 00000000000..8ae21cbe50f --- /dev/null +++ b/APACHE_1_0_0/cgi-src/imagemap.c @@ -0,0 +1,353 @@ +/* +** 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: +** +** +** New-style specification of mapfile relative to DocumentRoot: +** +** +** New-style specification of mapfile in user's public HTML directory: +** +** +** 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 +#include +#ifndef pyr +#include +#else +#include +#endif +#include +#include + +#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 instructions.

"); + + + 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 here%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("Mapping Server Error"); + printf("

Mapping Server Error

"); + printf("This server encountered an error:

"); + 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; + } +} + diff --git a/APACHE_1_0_0/cgi-src/jj.c b/APACHE_1_0_0/cgi-src/jj.c new file mode 100644 index 00000000000..53dfb5ad105 --- /dev/null +++ b/APACHE_1_0_0/cgi-src/jj.c @@ -0,0 +1,259 @@ +/* + * Submarine ordering form through FAX gateway + * + * Rob McCool + * + */ + + +#include +#include + +#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("Form for Submarine Order%c",LF); + printf("

Jimmy John's Submarine Order Form

%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.

%c",LF); + printf("


%c",LF); + printf("
%c",LF); + printf("Password:

%c",LF); + printf("

Sub Type

%c",LF); + printf("Select which you would like of the following:

%c",LF); + printf("%s:%c",sublist[0],LF); + printf("Smoked virginia ham and provolone cheese topped with lettuce, tomato, and mayo.

%c",LF); + printf("%s:%c",sublist[1],LF); + printf("Medium rare shaved roast beef topped with mayo, lettuce, and tomato.

%c",LF); + printf("%s:%c",sublist[2],LF); + printf("Tuna, mixed with celery, onions, and sauce, topped with lettuce,%c",LF); + printf("tomato, and alfalfa sprouts.

%c",LF); + printf("%s:%c",sublist[3],LF); + printf("Turkey breast topped with lettuce, mayo, alfalfa sprouts, and mayo.

%c",LF); + printf("%s:%c",sublist[4],LF); + printf("Genoa salami and provolone cheese topped with capacola, onion, lettuce, tomato, and Italian sauce.

%c",LF); + printf("%s:%c",sublist[5],LF); + printf("Layers of provolone cheese, separated by avocado, sprouts, lettuce, tomato, and mayo.

%c",LF); + printf("%s:%c",sublist[6],LF); + printf("1/4 pound of smoked ham, provolone cheese, topped with lettuce,%c",LF); + printf("tomato, and mayo.

%c",LF); + printf("%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.

%c",LF); + printf("%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.

%c",LF); + printf("%s:%c",sublist[9],LF); + printf("1/4 pound of sliced roast beef, provolone cheese, topped with lettuce, tomato, and mayo.

%c",LF); + printf("%s:%c",sublist[10],LF); + printf("Turkey breast, smoked ham, and provolonecheese topped with lettuce, tomato, and mayo.

%c",LF); + printf("%s:%c",sublist[11],LF); + printf("Turkey breast, avocado, and cheese topped with lettuce, mayo, alfalfa, and tomato.

%c",LF); + printf("

Slim Jim Subs

%c",LF); + printf("Subs without veggies or sauce.

%c",LF); + printf("%s

%c",slimlist[0],LF); + printf("%s

%c",slimlist[1],LF); + printf("%s

%c",slimlist[2],LF); + printf("%s

%c",slimlist[3],LF); + printf("%s

%c",slimlist[4],LF); + printf("%s

%c",slimlist[5],LF); + printf("

Side orders

%c",LF); + printf("%s

%c",sidelist[0],LF); + printf("%s

%c",sidelist[1],LF); + printf("

Drinks

%c",LF); + printf("%s

%c",poplist[0],LF); + printf("%s

%c",poplist[1],LF); + printf("%s

%c",poplist[2],LF); + printf("%s

%c",poplist[3],LF); + printf("

Your Address, Phone Number, and Name

%c",LF); + printf("Name

%c",LF); + printf("Address

%c",LF); + printf("Phone Number

%c",LF); + printf("%c",LF); + printf("

%c",LF); + exit(0); +} + +void print_error(char *reason) { + printf("Order Not Submitted%c",LF); + printf("

Order Not Submitted

%c",LF); + printf("Your order has not been submitted, because %s.

%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("Server Error%c",LF); + printf("

Server Error

%c",LF); + printf("Server unable to get a temporary file. Please try again later.

%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("Order Sent%c",LF); + printf("

Order Sent

%c",LF); + printf("Your order has been sent to the UIUC e-mail to FAX gateway.

%c",LF); + } else { + printf("Your Order%c",LF); + printf("

Your Order

%c",LF); + printf("This is how your order would have looked if it had been sent.

%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); +} diff --git a/APACHE_1_0_0/cgi-src/phf.c b/APACHE_1_0_0/cgi-src/phf.c new file mode 100755 index 00000000000..fbb1f427cb9 --- /dev/null +++ b/APACHE_1_0_0/cgi-src/phf.c @@ -0,0 +1,201 @@ +#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); + } +} diff --git a/APACHE_1_0_0/cgi-src/post-query.c b/APACHE_1_0_0/cgi-src/post-query.c new file mode 100644 index 00000000000..f067a876a63 --- /dev/null +++ b/APACHE_1_0_0/cgi-src/post-query.c @@ -0,0 +1,56 @@ + + + +#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); +} diff --git a/APACHE_1_0_0/cgi-src/query.c b/APACHE_1_0_0/cgi-src/query.c new file mode 100755 index 00000000000..a84f6f70a5f --- /dev/null +++ b/APACHE_1_0_0/cgi-src/query.c @@ -0,0 +1,54 @@ + + + +#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); +} diff --git a/APACHE_1_0_0/cgi-src/util.c b/APACHE_1_0_0/cgi-src/util.c new file mode 100644 index 00000000000..0901a6600c2 --- /dev/null +++ b/APACHE_1_0_0/cgi-src/util.c @@ -0,0 +1,147 @@ +#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 */ + } + } +} + diff --git a/APACHE_1_0_0/conf/access.conf-dist b/APACHE_1_0_0/conf/access.conf-dist new file mode 100644 index 00000000000..dbfc8b625a9 --- /dev/null +++ b/APACHE_1_0_0/conf/access.conf-dist @@ -0,0 +1,58 @@ +# 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. + diff --git a/APACHE_1_0_0/conf/httpd.conf-dist b/APACHE_1_0_0/conf/httpd.conf-dist new file mode 100644 index 00000000000..45a400bcb5a --- /dev/null +++ b/APACHE_1_0_0/conf/httpd.conf-dist @@ -0,0 +1,131 @@ +# 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> diff --git a/APACHE_1_0_0/conf/mime.types b/APACHE_1_0_0/conf/mime.types new file mode 100644 index 00000000000..a1c5a93ed06 --- /dev/null +++ b/APACHE_1_0_0/conf/mime.types @@ -0,0 +1,82 @@ +# 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 + diff --git a/APACHE_1_0_0/conf/srm.conf-dist b/APACHE_1_0_0/conf/srm.conf-dist new file mode 100644 index 00000000000..c76f80762f1 --- /dev/null +++ b/APACHE_1_0_0/conf/srm.conf-dist @@ -0,0 +1,171 @@ +# 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 +# diff --git a/APACHE_1_0_0/icons/back.gif b/APACHE_1_0_0/icons/back.gif new file mode 100644 index 00000000000..d3c7071fd43 Binary files /dev/null and b/APACHE_1_0_0/icons/back.gif differ diff --git a/APACHE_1_0_0/icons/binary.gif b/APACHE_1_0_0/icons/binary.gif new file mode 100644 index 00000000000..05a2a828ae4 Binary files /dev/null and b/APACHE_1_0_0/icons/binary.gif differ diff --git a/APACHE_1_0_0/icons/binhex.gif b/APACHE_1_0_0/icons/binhex.gif new file mode 100644 index 00000000000..62332e1b51a Binary files /dev/null and b/APACHE_1_0_0/icons/binhex.gif differ diff --git a/APACHE_1_0_0/icons/blank.gif b/APACHE_1_0_0/icons/blank.gif new file mode 100644 index 00000000000..c2381325591 Binary files /dev/null and b/APACHE_1_0_0/icons/blank.gif differ diff --git a/APACHE_1_0_0/icons/broken.gif b/APACHE_1_0_0/icons/broken.gif new file mode 100644 index 00000000000..33f70e7f3f9 Binary files /dev/null and b/APACHE_1_0_0/icons/broken.gif differ diff --git a/APACHE_1_0_0/icons/burst.gif b/APACHE_1_0_0/icons/burst.gif new file mode 100644 index 00000000000..0305a183052 Binary files /dev/null and b/APACHE_1_0_0/icons/burst.gif differ diff --git a/APACHE_1_0_0/icons/comp1.gif b/APACHE_1_0_0/icons/comp1.gif new file mode 100644 index 00000000000..d85b317bf46 Binary files /dev/null and b/APACHE_1_0_0/icons/comp1.gif differ diff --git a/APACHE_1_0_0/icons/comp2.gif b/APACHE_1_0_0/icons/comp2.gif new file mode 100644 index 00000000000..f4b364eab79 Binary files /dev/null and b/APACHE_1_0_0/icons/comp2.gif differ diff --git a/APACHE_1_0_0/icons/compressed.gif b/APACHE_1_0_0/icons/compressed.gif new file mode 100644 index 00000000000..2d8e56ded04 Binary files /dev/null and b/APACHE_1_0_0/icons/compressed.gif differ diff --git a/APACHE_1_0_0/icons/continued.gif b/APACHE_1_0_0/icons/continued.gif new file mode 100644 index 00000000000..52d6429fbf1 Binary files /dev/null and b/APACHE_1_0_0/icons/continued.gif differ diff --git a/APACHE_1_0_0/icons/dir.gif b/APACHE_1_0_0/icons/dir.gif new file mode 100644 index 00000000000..aea288dfe4e Binary files /dev/null and b/APACHE_1_0_0/icons/dir.gif differ diff --git a/APACHE_1_0_0/icons/dir2.gif b/APACHE_1_0_0/icons/dir2.gif new file mode 100644 index 00000000000..ad4b07d522d Binary files /dev/null and b/APACHE_1_0_0/icons/dir2.gif differ diff --git a/APACHE_1_0_0/icons/forward.gif b/APACHE_1_0_0/icons/forward.gif new file mode 100644 index 00000000000..ac5624d7588 Binary files /dev/null and b/APACHE_1_0_0/icons/forward.gif differ diff --git a/APACHE_1_0_0/icons/generic.gif b/APACHE_1_0_0/icons/generic.gif new file mode 100644 index 00000000000..e494beb7491 Binary files /dev/null and b/APACHE_1_0_0/icons/generic.gif differ diff --git a/APACHE_1_0_0/icons/generic2.gif b/APACHE_1_0_0/icons/generic2.gif new file mode 100644 index 00000000000..b2dbc6e4f88 Binary files /dev/null and b/APACHE_1_0_0/icons/generic2.gif differ diff --git a/APACHE_1_0_0/icons/generic3.gif b/APACHE_1_0_0/icons/generic3.gif new file mode 100644 index 00000000000..0769581ffbb Binary files /dev/null and b/APACHE_1_0_0/icons/generic3.gif differ diff --git a/APACHE_1_0_0/icons/image.gif b/APACHE_1_0_0/icons/image.gif new file mode 100644 index 00000000000..96452047074 Binary files /dev/null and b/APACHE_1_0_0/icons/image.gif differ diff --git a/APACHE_1_0_0/icons/image2.gif b/APACHE_1_0_0/icons/image2.gif new file mode 100644 index 00000000000..44d5a707846 Binary files /dev/null and b/APACHE_1_0_0/icons/image2.gif differ diff --git a/APACHE_1_0_0/icons/index.gif b/APACHE_1_0_0/icons/index.gif new file mode 100644 index 00000000000..f0389388986 Binary files /dev/null and b/APACHE_1_0_0/icons/index.gif differ diff --git a/APACHE_1_0_0/icons/movie.gif b/APACHE_1_0_0/icons/movie.gif new file mode 100644 index 00000000000..539e2adefba Binary files /dev/null and b/APACHE_1_0_0/icons/movie.gif differ diff --git a/APACHE_1_0_0/icons/rainbow.gif b/APACHE_1_0_0/icons/rainbow.gif new file mode 100644 index 00000000000..8216b89bade Binary files /dev/null and b/APACHE_1_0_0/icons/rainbow.gif differ diff --git a/APACHE_1_0_0/icons/sound.gif b/APACHE_1_0_0/icons/sound.gif new file mode 100644 index 00000000000..aa3b51fb3d9 Binary files /dev/null and b/APACHE_1_0_0/icons/sound.gif differ diff --git a/APACHE_1_0_0/icons/sound2.gif b/APACHE_1_0_0/icons/sound2.gif new file mode 100644 index 00000000000..6d54fe13095 Binary files /dev/null and b/APACHE_1_0_0/icons/sound2.gif differ diff --git a/APACHE_1_0_0/icons/tar.gif b/APACHE_1_0_0/icons/tar.gif new file mode 100644 index 00000000000..617e779efa5 Binary files /dev/null and b/APACHE_1_0_0/icons/tar.gif differ diff --git a/APACHE_1_0_0/icons/text.gif b/APACHE_1_0_0/icons/text.gif new file mode 100644 index 00000000000..ea678498e48 Binary files /dev/null and b/APACHE_1_0_0/icons/text.gif differ diff --git a/APACHE_1_0_0/icons/transfer.gif b/APACHE_1_0_0/icons/transfer.gif new file mode 100644 index 00000000000..6871c91223d Binary files /dev/null and b/APACHE_1_0_0/icons/transfer.gif differ diff --git a/APACHE_1_0_0/icons/unknown.gif b/APACHE_1_0_0/icons/unknown.gif new file mode 100644 index 00000000000..d3dce03a380 Binary files /dev/null and b/APACHE_1_0_0/icons/unknown.gif differ diff --git a/APACHE_1_0_0/icons/uu.gif b/APACHE_1_0_0/icons/uu.gif new file mode 100644 index 00000000000..96b39d72e48 Binary files /dev/null and b/APACHE_1_0_0/icons/uu.gif differ diff --git a/APACHE_1_0_0/src/API.html b/APACHE_1_0_0/src/API.html new file mode 100644 index 00000000000..87fc4a0d925 --- /dev/null +++ b/APACHE_1_0_0/src/API.html @@ -0,0 +1,980 @@ +<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 -&gt; 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>&lt;Directory&gt;</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-&gt;method_number != M_GET) return DECLINED; + if (r-&gt;finfo.st_mode == 0) return NOT_FOUND; + + if ((errstatus = set_content_length (r, r-&gt;finfo.st_size)) + || (errstatus = set_last_modified (r, r-&gt;finfo.st_mtime))) + return errstatus; + + f = fopen (r-&gt;filename, "r"); + + if (f == NULL) { + log_reason("file permissions deny server access", r-&gt;filename, r); + return FORBIDDEN; + } + + register_timeout ("send", r); + send_http_header (r); + + if (!r-&gt;header_only) send_fd (f, r); + pfclose (r-&gt;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-&gt;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-&gt;prev</code> and <code>r-&gt;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 -&gt; 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>&lt;Directory&gt;</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>&lt;Directory /&gt;</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>&lt;Directory&gt;</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-&gt;forced_types = make_table (p, 4); + new-&gt;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-&gt;forced_types = overlay_tables (p, subdir-&gt;forced_types, + parent_dir-&gt;forced_types); + new-&gt;encoding_types = overlay_tables (p, subdir-&gt;encoding_types, + parent_dir-&gt;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-&gt;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-&gt;module_config,&amp;alias_module); + alias_entry *new = push_array (conf-&gt;redirects); + + if (!is_url (url)) return "Redirect to non-URL"; + + new-&gt;fake = f; new-&gt;real = url; + return NULL; +} +</pre> + diff --git a/APACHE_1_0_0/src/CHANGES b/APACHE_1_0_0/src/CHANGES new file mode 100644 index 00000000000..75e74baaa0a --- /dev/null +++ b/APACHE_1_0_0/src/CHANGES @@ -0,0 +1,723 @@ +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 ;-). diff --git a/APACHE_1_0_0/src/Configuration b/APACHE_1_0_0/src/Configuration new file mode 100644 index 00000000000..651edbd23e8 --- /dev/null +++ b/APACHE_1_0_0/src/Configuration @@ -0,0 +1,160 @@ +# 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 + + diff --git a/APACHE_1_0_0/src/Configure b/APACHE_1_0_0/src/Configure new file mode 100755 index 00000000000..8d47dfacae3 --- /dev/null +++ b/APACHE_1_0_0/src/Configure @@ -0,0 +1,79 @@ +#! /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 diff --git a/APACHE_1_0_0/src/INSTALL b/APACHE_1_0_0/src/INSTALL new file mode 100644 index 00000000000..4dbebda102e --- /dev/null +++ b/APACHE_1_0_0/src/INSTALL @@ -0,0 +1,54 @@ +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. + + + diff --git a/APACHE_1_0_0/src/Makefile b/APACHE_1_0_0/src/Makefile new file mode 100644 index 00000000000..0b01145e140 --- /dev/null +++ b/APACHE_1_0_0/src/Makefile @@ -0,0 +1,128 @@ +# 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 diff --git a/APACHE_1_0_0/src/Makefile.tmpl b/APACHE_1_0_0/src/Makefile.tmpl new file mode 100644 index 00000000000..b33d251f773 --- /dev/null +++ b/APACHE_1_0_0/src/Makefile.tmpl @@ -0,0 +1,56 @@ +# 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 diff --git a/APACHE_1_0_0/src/README b/APACHE_1_0_0/src/README new file mode 100644 index 00000000000..a8fb3a32098 --- /dev/null +++ b/APACHE_1_0_0/src/README @@ -0,0 +1,142 @@ +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. + diff --git a/APACHE_1_0_0/src/TODO b/APACHE_1_0_0/src/TODO new file mode 100644 index 00000000000..af09059f1ac --- /dev/null +++ b/APACHE_1_0_0/src/TODO @@ -0,0 +1,45 @@ +*) 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_.... diff --git a/APACHE_1_0_0/src/include/alloc.h b/APACHE_1_0_0/src/include/alloc.h new file mode 100644 index 00000000000..bcad7cdd93b --- /dev/null +++ b/APACHE_1_0_0/src/include/alloc.h @@ -0,0 +1,235 @@ + +/* ==================================================================== + * 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(); diff --git a/APACHE_1_0_0/src/include/ap_config.h b/APACHE_1_0_0/src/include/ap_config.h new file mode 100644 index 00000000000..9147194459d --- /dev/null +++ b/APACHE_1_0_0/src/include/ap_config.h @@ -0,0 +1,428 @@ + +/* ==================================================================== + * 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 diff --git a/APACHE_1_0_0/src/include/conf.h b/APACHE_1_0_0/src/include/conf.h new file mode 100644 index 00000000000..9147194459d --- /dev/null +++ b/APACHE_1_0_0/src/include/conf.h @@ -0,0 +1,428 @@ + +/* ==================================================================== + * 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 diff --git a/APACHE_1_0_0/src/include/http_conf_globals.h b/APACHE_1_0_0/src/include/http_conf_globals.h new file mode 100644 index 00000000000..59990c612e7 --- /dev/null +++ b/APACHE_1_0_0/src/include/http_conf_globals.h @@ -0,0 +1,81 @@ + +/* ==================================================================== + * 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]; + diff --git a/APACHE_1_0_0/src/include/http_config.h b/APACHE_1_0_0/src/include/http_config.h new file mode 100644 index 00000000000..74637048b02 --- /dev/null +++ b/APACHE_1_0_0/src/include/http_config.h @@ -0,0 +1,260 @@ + +/* ==================================================================== + * 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 diff --git a/APACHE_1_0_0/src/include/http_core.h b/APACHE_1_0_0/src/include/http_core.h new file mode 100644 index 00000000000..dddfbe774f4 --- /dev/null +++ b/APACHE_1_0_0/src/include/http_core.h @@ -0,0 +1,160 @@ + +/* ==================================================================== + * 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 diff --git a/APACHE_1_0_0/src/include/http_log.h b/APACHE_1_0_0/src/include/http_log.h new file mode 100644 index 00000000000..ef36da9fc7c --- /dev/null +++ b/APACHE_1_0_0/src/include/http_log.h @@ -0,0 +1,61 @@ + +/* ==================================================================== + * 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); + diff --git a/APACHE_1_0_0/src/include/http_main.h b/APACHE_1_0_0/src/include/http_main.h new file mode 100644 index 00000000000..3817f4a8a9a --- /dev/null +++ b/APACHE_1_0_0/src/include/http_main.h @@ -0,0 +1,91 @@ + +/* ==================================================================== + * 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 *); + diff --git a/APACHE_1_0_0/src/include/http_protocol.h b/APACHE_1_0_0/src/include/http_protocol.h new file mode 100644 index 00000000000..26985da4545 --- /dev/null +++ b/APACHE_1_0_0/src/include/http_protocol.h @@ -0,0 +1,161 @@ + +/* ==================================================================== + * 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); diff --git a/APACHE_1_0_0/src/include/http_request.h b/APACHE_1_0_0/src/include/http_request.h new file mode 100644 index 00000000000..2cb043d7380 --- /dev/null +++ b/APACHE_1_0_0/src/include/http_request.h @@ -0,0 +1,92 @@ + +/* ==================================================================== + * 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 diff --git a/APACHE_1_0_0/src/include/httpd.h b/APACHE_1_0_0/src/include/httpd.h new file mode 100644 index 00000000000..fc96552d95c --- /dev/null +++ b/APACHE_1_0_0/src/include/httpd.h @@ -0,0 +1,446 @@ + +/* ==================================================================== + * 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); + + diff --git a/APACHE_1_0_0/src/include/scoreboard.h b/APACHE_1_0_0/src/include/scoreboard.h new file mode 100644 index 00000000000..948d7b81bb6 --- /dev/null +++ b/APACHE_1_0_0/src/include/scoreboard.h @@ -0,0 +1,86 @@ + +/* ==================================================================== + * 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 + diff --git a/APACHE_1_0_0/src/include/util_script.h b/APACHE_1_0_0/src/include/util_script.h new file mode 100644 index 00000000000..117ff0c5789 --- /dev/null +++ b/APACHE_1_0_0/src/include/util_script.h @@ -0,0 +1,60 @@ + +/* ==================================================================== + * 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); + diff --git a/APACHE_1_0_0/src/main/alloc.c b/APACHE_1_0_0/src/main/alloc.c new file mode 100644 index 00000000000..0a4f898bff3 --- /dev/null +++ b/APACHE_1_0_0/src/main/alloc.c @@ -0,0 +1,905 @@ + +/* ==================================================================== + * 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); + } +} diff --git a/APACHE_1_0_0/src/main/http_config.c b/APACHE_1_0_0/src/main/http_config.c new file mode 100644 index 00000000000..592116a0da8 --- /dev/null +++ b/APACHE_1_0_0/src/main/http_config.c @@ -0,0 +1,750 @@ + +/* ==================================================================== + * 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; +} + diff --git a/APACHE_1_0_0/src/main/http_core.c b/APACHE_1_0_0/src/main/http_core.c new file mode 100644 index 00000000000..f8f1af3ddf8 --- /dev/null +++ b/APACHE_1_0_0/src/main/http_core.c @@ -0,0 +1,704 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/main/http_log.c b/APACHE_1_0_0/src/main/http_log.c new file mode 100644 index 00000000000..195875d8f9d --- /dev/null +++ b/APACHE_1_0_0/src/main/http_log.c @@ -0,0 +1,130 @@ + +/* ==================================================================== + * 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); +} + diff --git a/APACHE_1_0_0/src/main/http_main.c b/APACHE_1_0_0/src/main/http_main.c new file mode 100644 index 00000000000..a44aabd92a2 --- /dev/null +++ b/APACHE_1_0_0/src/main/http_main.c @@ -0,0 +1,1041 @@ + +/* ==================================================================== + * 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); +} + + diff --git a/APACHE_1_0_0/src/main/http_protocol.c b/APACHE_1_0_0/src/main/http_protocol.c new file mode 100644 index 00000000000..c3e984b0c25 --- /dev/null +++ b/APACHE_1_0_0/src/main/http_protocol.c @@ -0,0 +1,699 @@ + +/* ==================================================================== + * 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); +} diff --git a/APACHE_1_0_0/src/main/http_request.c b/APACHE_1_0_0/src/main/http_request.c new file mode 100644 index 00000000000..8943d51fa45 --- /dev/null +++ b/APACHE_1_0_0/src/main/http_request.c @@ -0,0 +1,691 @@ + +/* ==================================================================== + * 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); +} + diff --git a/APACHE_1_0_0/src/main/util.c b/APACHE_1_0_0/src/main/util.c new file mode 100644 index 00000000000..0929dc9bf3a --- /dev/null +++ b/APACHE_1_0_0/src/main/util.c @@ -0,0 +1,1031 @@ + +/* ==================================================================== + * 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,&copy[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],&copy[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; +} diff --git a/APACHE_1_0_0/src/main/util_script.c b/APACHE_1_0_0/src/main/util_script.c new file mode 100644 index 00000000000..ad055d1d598 --- /dev/null +++ b/APACHE_1_0_0/src/main/util_script.c @@ -0,0 +1,259 @@ + +/* ==================================================================== + * 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); +} + diff --git a/APACHE_1_0_0/src/mod_ai_backcompat.c b/APACHE_1_0_0/src/mod_ai_backcompat.c new file mode 100644 index 00000000000..8ce1aabb9e3 --- /dev/null +++ b/APACHE_1_0_0/src/mod_ai_backcompat.c @@ -0,0 +1,94 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/mod_cookies.c b/APACHE_1_0_0/src/mod_cookies.c new file mode 100644 index 00000000000..cd7a3512dfc --- /dev/null +++ b/APACHE_1_0_0/src/mod_cookies.c @@ -0,0 +1,226 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/mod_log_common.c b/APACHE_1_0_0/src/mod_log_common.c new file mode 100644 index 00000000000..650197dff6f --- /dev/null +++ b/APACHE_1_0_0/src/mod_log_common.c @@ -0,0 +1,213 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules.c b/APACHE_1_0_0/src/modules.c new file mode 100644 index 00000000000..45376804daa --- /dev/null +++ b/APACHE_1_0_0/src/modules.c @@ -0,0 +1,46 @@ +#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, +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_access.c b/APACHE_1_0_0/src/modules/standard/mod_access.c new file mode 100644 index 00000000000..b96a265ab08 --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_access.c @@ -0,0 +1,245 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_alias.c b/APACHE_1_0_0/src/modules/standard/mod_alias.c new file mode 100644 index 00000000000..6eb730ffeee --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_alias.c @@ -0,0 +1,244 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_asis.c b/APACHE_1_0_0/src/modules/standard/mod_asis.c new file mode 100644 index 00000000000..d01def90d1d --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_asis.c @@ -0,0 +1,109 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_auth.c b/APACHE_1_0_0/src/modules/standard/mod_auth.c new file mode 100644 index 00000000000..910ebee4095 --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_auth.c @@ -0,0 +1,262 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_auth_dbm.c b/APACHE_1_0_0/src/modules/standard/mod_auth_dbm.c new file mode 100644 index 00000000000..ed0a8629d8a --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_auth_dbm.c @@ -0,0 +1,252 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_autoindex.c b/APACHE_1_0_0/src/modules/standard/mod_autoindex.c new file mode 100644 index 00000000000..60a04eb258f --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_autoindex.c @@ -0,0 +1,829 @@ + +/* ==================================================================== + * 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],"&lt;"); + x+=3; + } + else if(copy[y] == '>') { + strcpy(&fn[x],"&gt;"); + x+=3; + } + else if(copy[y] == '&') { + strcpy(&fn[x],"&amp;"); + 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_cgi.c b/APACHE_1_0_0/src/modules/standard/mod_cgi.c new file mode 100644 index 00000000000..20466080d90 --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_cgi.c @@ -0,0 +1,359 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_dir.c b/APACHE_1_0_0/src/modules/standard/mod_dir.c new file mode 100644 index 00000000000..60a04eb258f --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_dir.c @@ -0,0 +1,829 @@ + +/* ==================================================================== + * 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],"&lt;"); + x+=3; + } + else if(copy[y] == '>') { + strcpy(&fn[x],"&gt;"); + x+=3; + } + else if(copy[y] == '&') { + strcpy(&fn[x],"&amp;"); + 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_dld.c b/APACHE_1_0_0/src/modules/standard/mod_dld.c new file mode 100644 index 00000000000..65bced0df7c --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_dld.c @@ -0,0 +1,191 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_imap.c b/APACHE_1_0_0/src/modules/standard/mod_imap.c new file mode 100644 index 00000000000..46d990843a1 --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_imap.c @@ -0,0 +1,456 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_include.c b/APACHE_1_0_0/src/modules/standard/mod_include.c new file mode 100644 index 00000000000..07ad8f501b5 --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_include.c @@ -0,0 +1,873 @@ + +/* ==================================================================== + * 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, &#00; 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_log_agent.c b/APACHE_1_0_0/src/modules/standard/mod_log_agent.c new file mode 100644 index 00000000000..806218c64d1 --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_log_agent.c @@ -0,0 +1,186 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_log_config.c b/APACHE_1_0_0/src/modules/standard/mod_log_config.c new file mode 100644 index 00000000000..60fbfc98d8e --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_log_config.c @@ -0,0 +1,559 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_log_referer.c b/APACHE_1_0_0/src/modules/standard/mod_log_referer.c new file mode 100644 index 00000000000..bcffcd7e985 --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_log_referer.c @@ -0,0 +1,224 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_mime.c b/APACHE_1_0_0/src/modules/standard/mod_mime.c new file mode 100644 index 00000000000..a1e673c0029 --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_mime.c @@ -0,0 +1,257 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_negotiation.c b/APACHE_1_0_0/src/modules/standard/mod_negotiation.c new file mode 100644 index 00000000000..3796aea0e4e --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_negotiation.c @@ -0,0 +1,1139 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/modules/standard/mod_userdir.c b/APACHE_1_0_0/src/modules/standard/mod_userdir.c new file mode 100644 index 00000000000..cf71f5712fb --- /dev/null +++ b/APACHE_1_0_0/src/modules/standard/mod_userdir.c @@ -0,0 +1,143 @@ + +/* ==================================================================== + * 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 */ +}; diff --git a/APACHE_1_0_0/src/rfc931.c b/APACHE_1_0_0/src/rfc931.c new file mode 100644 index 00000000000..320d6ae1afb --- /dev/null +++ b/APACHE_1_0_0/src/rfc931.c @@ -0,0 +1,297 @@ + +/* ==================================================================== + * 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); +} diff --git a/APACHE_1_0_0/src/support/Makefile b/APACHE_1_0_0/src/support/Makefile new file mode 100755 index 00000000000..d88e0735a3c --- /dev/null +++ b/APACHE_1_0_0/src/support/Makefile @@ -0,0 +1,53 @@ +# 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 + diff --git a/APACHE_1_0_0/src/support/change-passwd.readme b/APACHE_1_0_0/src/support/change-passwd.readme new file mode 100644 index 00000000000..059376549fd --- /dev/null +++ b/APACHE_1_0_0/src/support/change-passwd.readme @@ -0,0 +1,89 @@ +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> + diff --git a/APACHE_1_0_0/src/support/dbmmanage b/APACHE_1_0_0/src/support/dbmmanage new file mode 100644 index 00000000000..aa5804d3ae1 --- /dev/null +++ b/APACHE_1_0_0/src/support/dbmmanage @@ -0,0 +1,123 @@ +#!/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"; + diff --git a/APACHE_1_0_0/src/support/dbmmanage.new b/APACHE_1_0_0/src/support/dbmmanage.new new file mode 100644 index 00000000000..ddff187231c --- /dev/null +++ b/APACHE_1_0_0/src/support/dbmmanage.new @@ -0,0 +1,133 @@ +#!/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; +} diff --git a/APACHE_1_0_0/src/support/dbmmanage.readme b/APACHE_1_0_0/src/support/dbmmanage.readme new file mode 100644 index 00000000000..3862096b1eb --- /dev/null +++ b/APACHE_1_0_0/src/support/dbmmanage.readme @@ -0,0 +1,6 @@ +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... diff --git a/APACHE_1_0_0/src/support/htpasswd.c b/APACHE_1_0_0/src/support/htpasswd.c new file mode 100644 index 00000000000..6e786985527 --- /dev/null +++ b/APACHE_1_0_0/src/support/htpasswd.c @@ -0,0 +1,180 @@ +/* + * 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); +} diff --git a/APACHE_1_0_0/src/support/httpd.1m b/APACHE_1_0_0/src/support/httpd.1m new file mode 100644 index 00000000000..83428de30a6 --- /dev/null +++ b/APACHE_1_0_0/src/support/httpd.1m @@ -0,0 +1,108 @@ +.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 diff --git a/APACHE_1_0_0/src/support/httpd_monitor b/APACHE_1_0_0/src/support/httpd_monitor new file mode 100644 index 00000000000..2b822737ad6 --- /dev/null +++ b/APACHE_1_0_0/src/support/httpd_monitor @@ -0,0 +1,147 @@ +#!/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; +} + + + diff --git a/APACHE_1_0_0/src/support/inc2shtml.c b/APACHE_1_0_0/src/support/inc2shtml.c new file mode 100644 index 00000000000..cfd205fa835 --- /dev/null +++ b/APACHE_1_0_0/src/support/inc2shtml.c @@ -0,0 +1,105 @@ +/* + * 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; + } + } +} diff --git a/APACHE_1_0_0/src/support/logresolve.c b/APACHE_1_0_0/src/support/logresolve.c new file mode 100644 index 00000000000..a245214c30e --- /dev/null +++ b/APACHE_1_0_0/src/support/logresolve.c @@ -0,0 +1,272 @@ +/*** ***\ + + 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 + + diff --git a/APACHE_1_0_0/src/support/unescape.c b/APACHE_1_0_0/src/support/unescape.c new file mode 100644 index 00000000000..076ecfff5f8 --- /dev/null +++ b/APACHE_1_0_0/src/support/unescape.c @@ -0,0 +1,91 @@ +/* + * 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); + } +}