diff --git a/BUGS b/BUGS index e8b8f8d..94b8711 100644 --- a/BUGS +++ b/BUGS @@ -1,5 +1,56 @@ +NOTE: Bugs are mentioned in the version they are found in. This doesn't +mean that they didn't exist prior to that version. + +Known Bugs in 1.5.1 +--------------------- +*) Can only use a single group on a require group +*) core dumps at random due to a free in env.c +*) Relative urls in imagemaps are broken +*) doesn't kill cgi scripts if the user aborts +*) content_length gets reset after scanning cgi headers, instead of before +*) can core dump on special case in getline (rfc822 line wrapping) + +Known Bugs in 1.5.1b3 +--------------------- +*) 299: File descriptors aren't set correctly on child_alone() +*) 301: Sending headers on HTTP/0.9 response + +Known Bugs in 1.5.1b2 +--------------------- +*) 900: ErrorDocument 401s as html files doesn't work on Mosaic/X, does on + netscape +*) 293: Socket isn't closed before CGI execution, causing client to hang + waiting for close + +Known Bugs in 1.5.1b1 +--------------------- +*) 264: imagemap fails because of invalid fgets() argument +*) 265: in_ip() broken causing all access control by ip to fail +*) 266: 301 and 204 status codes broken in set_stat_line() +*) 267: no bounds checking in access_control array + + Known Bugs in 1.5a --------------------- +*) server doesn't clean up directory indexing information added by .htaccess +*) fgets in src/imagemap.c only uses MAX_STRING_LEN, which may be too short + for complex polygons +*) If you don't have an allow or require line in .htaccess LIMIT, it won't + work (ie, just a deny) +*) Doesn't log HEAD request to automatically indexed directory +*) Can't use group and user name which are the same in flat group file +*) Off by one errors in DBM support +*) typo in LOCALHACK +*) Server core dumped if user aborted before reqInfo->remote_name set +*) Server core dumped if setuid/setgid failed +*) Bug in http_access.c which makes matchexp directories in access control + not work correctly +*) NIS group files only work if using NIS password files as well +*) Order mutual-failure is broken, does exact opposite +*) Don't strip Content-Length header from CGI scripts +*) require group will match user as postfix of another, and fails if a + prefix occurs first + Known Bugs in 1.5 diff --git a/CHANGES b/CHANGES index aaf73b3..e7af1e4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,56 @@ + +Changes for 1.5.2 +------------------ +*) Changed getline rfc822 line wrap to check for validity of the next bits + before attempting to see them +*) Changed imagemap.c so relative URLs actually work +*) Don't core dump on a method only request +*) reset errno to 0 in send_fp so we break out of loop +*) somewhere we stopped killing cgi scripts on SIGALRM and SIGPIPE +*) changed group handling support to support multiple groups again +*) reset content_length before scanning cgi headers, not after +*) don't free env var in replace (it uses allocate now) +*) Only look for path_info if its part of the requested URL (as opposed + to keep looking until you hit a real directory) +*) Make make_dirstr() in util.c return / instead of null if n = 1 +*) Added FCGI support from Openmarket +*) Added support for Linux 2.0 +*) Added support for SCO OpenServer 5 + +Changes for 1.5.1 +------------------ +*) Imagemaps (both internal and external) now add the path of the map file + for non full path urls in the map file +*) A couple logging functions didn't check reqInfo->remote_name for a NULL +*) change getuid to geteuid in httpd.c so that effectively root people can + start the server and have it change uids +*) Slight code rearrangement to make Redirects from .htaccess more + useful because the file doesn't have to exist. +*) Added support for restricted access by Referer field +*) Added OnDeny command for Limit directive which allows a redirect on + failure (esp. useful for denying by referer) +*) Added string allocating mechanism for speed +*) Added CONTENT_MD5 header support from patches by Martin Hamilton + (martin@net.lut.ac.uk) +*) Server doesn't keep creating more structures in the event of KeepAlive +*) Added bounds checking for security structures +*) Fixed Order mutual-failure +*) Support both CERN and NCSA style imagemaps (on a line by line basis) +*) Attempting to make the server thread safe +*) First attempt at allowing ErrorDocument 401s as html files (still broken) +*) Fixed string searching for user in group +*) Close csd (socket) on exec of CGI scripts so that client doesn't hang + waiting for the scripts (and their children) to finish +*) made a single interface for most output functions to make it easier + to go to different output functions (SSL is a good example) +*) remove path_args/path_alias crap, and put it in reqInfo structure +*) Why do we require full URLs in Redirect? A local (root) url should work fine +*) Redirect from .htaccess should work now (completely) +*) Added hack to allow SSI of CGI, at a great expense of speed (CGI_SSI_HACK) +*) Made getline() code re-entrant (now has its own sock_buf struct) + + + Fixes for 1.5c ------------------ *) add newline character to list of characters to strip from shell cmds @@ -12,15 +65,6 @@ Fixes for 1.5c start the server and have it change uids *) Fix group checking -Fixes for 1.5b (internal) ------------------- -*) Couple of off by one errors in the DBM support (server and support files) -*) HP/Apollo Domain/OS support updated -*) SCO ODT and SCO SVR3 support updated -*) Typo in LOCALHACK -*) No error message for NO_CONTENT default imagemap -*) clean up after directory indexing (memory leak) - Fixes for 1.5a ------------------- *) Typo/Thinko for http_access.c which makes order deny/allow not work as diff --git a/CREDITS b/CREDITS index 0821c37..4ac3ef2 100644 --- a/CREDITS +++ b/CREDITS @@ -28,9 +28,11 @@ Vince Tkac (tkac@oclc.org) Elf Sternberg (elf@aaden.spry.com) Nathan Neulinger (nneul@umr.edu) Stuart Lynne (sl@wimsey.com) +Martin Hamilton (martin@net.lut.ac.uk) +Tim Hudson (tjh@mincom.oz.au) SSL And for Porting information/help: -Alex Podlecki (a.podlecki@att.com) SVR4 +Alex Podlecki (apodlecki@lucent.com) SVR4 Sanj Kharbanda (sanj@wordsworth.com) QNX Jeffrey Ray Thieleke (thieleke@icaen.uiowa.edu) NetBSD for m68k David Cornejo (dave@dogwood.com) NetBSD @@ -46,6 +48,7 @@ Eugene Mah (eugene@raddi.uah.ualberta.ca) NeXT 3.2 m68k Kevin Steves (stevesk@mayfield.hp.com) HPUX Vincent D. Skahan (vds7789@aw101.iasl.ca.boeing.com) HP/Apollo DomainOS Achille Hui (eillihca@drizzle.stanford.edu) OSF/1 2.0 +Huw Rogers (count0@iac.co.jp) Linux Miquel van Smoorenburg (miquels@cistron.nl) Linux A. P. Harris (apharris@onshore.com) Linux Stan Johnson (johnson@mission.jsc.nasa.gov) ConvexOS 10.1 diff --git a/LICENSE.TERMS.fcgi b/LICENSE.TERMS.fcgi new file mode 100644 index 0000000..f425450 --- /dev/null +++ b/LICENSE.TERMS.fcgi @@ -0,0 +1,43 @@ +This FastCGI application library source and object code (the +"Software") and its documentation (the "Documentation") are +copyrighted by Open Market, Inc ("Open Market"). The following terms +apply to all files associated with the Software and Documentation +unless explicitly disclaimed in individual files. + +Open Market permits you to use, copy, modify, distribute, and license +this Software and the Documentation solely for the purpose of +implementing the FastCGI specification defined by Open Market or +derivative specifications publicly endorsed by Open Market and +promulgated by an open standards organization and for no other +purpose, provided that existing copyright notices are retained in all +copies and that this notice is included verbatim in any distributions. + +No written agreement, license, or royalty fee is required for any of +the authorized uses. Modifications to this Software and Documentation +may be copyrighted by their authors and need not follow the licensing +terms described here, but the modified Software and Documentation must +be used for the sole purpose of implementing the FastCGI specification +defined by Open Market or derivative specifications publicly endorsed +by Open Market and promulgated by an open standards organization and +for no other purpose. If modifications to this Software and +Documentation have new licensing terms, the new terms must protect Open +Market's proprietary rights in the Software and Documentation to the +same extent as these licensing terms and must be clearly indicated on +the first page of each file where they apply. + +Open Market shall retain all right, title and interest in and to the +Software and Documentation, including without limitation all patent, +copyright, trade secret and other proprietary rights. + +OPEN MARKET MAKES NO EXPRESS OR IMPLIED WARRANTY WITH RESPECT TO THE +SOFTWARE OR THE DOCUMENTATION, INCLUDING WITHOUT LIMITATION ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN +NO EVENT SHALL OPEN MARKET BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY +DAMAGES ARISING FROM OR RELATING TO THIS SOFTWARE OR THE +DOCUMENTATION, INCLUDING, WITHOUT LIMITATION, ANY INDIRECT, SPECIAL OR +CONSEQUENTIAL DAMAGES OR SIMILAR DAMAGES, INCLUDING LOST PROFITS OR +LOST DATA, EVEN IF OPEN MARKET HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS". +OPEN MARKET HAS NO LIABILITY IN CONTRACT, TORT, NEGLIGENCE OR +OTHERWISE ARISING OUT OF THIS SOFTWARE OR THE DOCUMENTATION. + diff --git a/Makefile b/Makefile index 6427a04..a12c527 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ all: @echo Please choose a system type. @echo Valid types are aix3, aix4, sunos, sgi4, sgi5, @echo hp-cc, hp-gcc, solaris, netbsd, svr4, linux, - @echo next, ultrix, osf1, aux, bsdi + @echo next, ultrix, osf1, aux, bsdi, sco5 @echo If you do not have one of these systems, you must edit @echo src/Makefile, src/portability.h, src/config.h, @echo cgi-src/Makefile, and support/Makefile @@ -45,6 +45,8 @@ next: osf1: cd src ; make osf1; cd ../cgi-src ; make osf1; cd ../support ; make osf1 +sco5: + cd src ; make sco5; cd ../cgi-src ; make CC=icc ; cd ../support ; make sco5 sgi4: cd src ; make sgi; cd ../cgi-src ; make sgi ; cd ../support ; make sgi4 diff --git a/README b/README index 91ad215..304bd3b 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ -NCSA HTTPd Server 1.5c +NCSA HTTPd Server 1.5.2 Copyright (c) 1995 Board of Trustees, University of Illinois @@ -70,6 +70,8 @@ support/dbmpasswd Program to make password files that use dbm support/htdigest Program to make MD5 password files (std/text) support/htpasswd Program to make password files (std/text) support/std2dbm Program to convert std files to dbm +support/webgrab Brian J. Swetland's Command Line Browser + (its almost as good as telnet) Version Number Defined --------------------------- @@ -82,3 +84,4 @@ Version Number Defined | ---- Major revisions. Probably not going to be another until 2.0 ------ Really major revisions, code overhauls, goal changes, language changes + diff --git a/README.fcgi b/README.fcgi new file mode 100644 index 0000000..bcb5d77 --- /dev/null +++ b/README.fcgi @@ -0,0 +1,24 @@ + +----------------------------------------------------------------------- +NOTE: The information in this was the information in the README for +the FCGI patch from Openmarket, and may not necessarily apply to this +version of the server. + +For more information on FastCGI, see http://www.fastcgi.com/ +----------------------------------------------------------------------- + +FastCGI Module for the NCSA HTTPd +This module has been tested on NCSA version 1.5.1 +which is available at +http://httpd.ncsa.uiuc.edu/beta-1.5/ncsa-httpd-1.5.1.tar.Z +Contained in ncsa-fastcgi.tar.Z is the source +code for the FastCGI module, documentation, and the licensing terms. + +Directions for installing and using this module are in the file +mod_fastcgi.html which is in the top level directory of the +FastCGI module kit. + + +You can obtain the FastCGI developers kit, along with pre-compiled FastCGI +capable perl-5 and tcl distributions at +http://www.fastcgi.com/. diff --git a/cgi-src/Makefile b/cgi-src/Makefile old mode 100755 new mode 100644 diff --git a/cgi-src/imagemap.c b/cgi-src/imagemap.c index c8a8e1a..9f99c72 100644 --- a/cgi-src/imagemap.c +++ b/cgi-src/imagemap.c @@ -47,6 +47,9 @@ ** ** 1.9 : Fixed bug: If you requested a new style conf file in DOCUMENT_ROOT, ** and didn't have an old style conf file, it would fail +** 1.9a: Most other imagemap programs seem to allow a non-full path as the url, +** so we'll switch to that. Any url not starting with / goes to the +** same path as the map file. */ #include @@ -80,11 +83,11 @@ static int pointincircle(double point[2], double coords[MAXVERTS][2]); static int pointinrect(double point[2], double coords[MAXVERTS][2]); int isname(char); +char input[MAXLINE], *mapname, def[MAXLINE], conf[MAXLINE], errstr[MAXLINE]; +double testpoint[2], pointarray[MAXVERTS][2]; 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; @@ -111,7 +114,7 @@ int main(int argc, char **argv) * we get the translated path, and skip reading the configuration file. */ if (strchr(mapname,'/')) { - strcpy(conf,getenv("PATH_TRANSLATED")); + strncpy(conf,getenv("PATH_TRANSLATED"),MAXLINE); goto openconf; } @@ -139,7 +142,7 @@ int main(int argc, char **argv) */ if(feof(fp)) { struct stat sbuf; - strcpy(conf,getenv("PATH_TRANSLATED")); + strncpy(conf,getenv("PATH_TRANSLATED"),MAXLINE); if (!stat(conf,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) goto openconf; else @@ -240,19 +243,39 @@ int main(int argc, char **argv) static void sendmesg(char *url) { + char *port; + char *path_info; + char path[MAXLINE]; + if (strchr(url, ':')) /*** It is a full URL ***/ - printf("Location: "); + printf("Location: %s%c%c",url,LF,LF); else { /*** It is a virtual URL ***/ - char *port; printf("Location: http://%s", getenv("SERVER_NAME")); /* only add port if it's not the default */ if ((port = getenv("SERVER_PORT")) && strcmp(port,"80")) printf(":%s",port); + + /* if its a full path, just use it, else add path from PATH_INFO */ + if (url[0] == '/') { + printf("%s%c%c",url,LF,LF); + } else { + if ((path_info = getenv("PATH_INFO"))) { + char *last = strrchr(path_info,'/'); + int x = 0; + while (((path_info+x) <= last) && (x < MAXLINE)) { + path[x] = *(path_info+x); + x++; + } + path[x] = '\0'; + } else { + strcpy(path,"/"); + } + printf("%s%s%c%c",path,url,LF,LF); } - printf("%s%c%c",url,10,10); - printf("This document has moved here%c",url,10); - exit(1); + } + printf("This document has moved here%c",url,LF); + exit(1); } static int pointinrect(double point[2], double coords[MAXVERTS][2]) @@ -341,7 +364,7 @@ static int pointinpoly(double point[2], double pgon[MAXVERTS][2]) static void servererr(char *msg) { - printf("Content-type: text/html%c%c",10,10); + printf("Content-type: text/html%c%c",LF,LF); printf("Mapping Server Error"); printf("

Mapping Server Error

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

"); diff --git a/cgi-src/phf.c b/cgi-src/phf.c old mode 100755 new mode 100644 diff --git a/cgi-src/query.c b/cgi-src/query.c old mode 100755 new mode 100644 diff --git a/cgi-src/util.c b/cgi-src/util.c index f02eb06..c3d5d65 100644 --- a/cgi-src/util.c +++ b/cgi-src/util.c @@ -139,7 +139,7 @@ void escape_shell_cmd(char *cmd) { l=strlen(cmd); for(x=0;cmd[x];x++) { - if(ind("&;`'\"|*?~<>^()[]{}$\\",cmd[x]) != -1){ + if(ind("&;`'\"|*?~<>^()[]{}$\\\x0A",cmd[x]) != -1){ for(y=l+1;y>x;y--) cmd[y] = cmd[y-1]; l++; /* length has been increased */ diff --git a/conf/httpd.conf-dist b/conf/httpd.conf-dist index ae97f4c..973b293 100644 --- a/conf/httpd.conf-dist +++ b/conf/httpd.conf-dist @@ -160,13 +160,13 @@ AccessConfig conf/access.conf LogOptions Separate -# LogDirGroupWriteOk, LogDirPublicWriteOk: Define either of these if you +# LogDirGroupWriteOk, LogDirOtherWriteOk: Define either of these if you # want the server to start even if you have write permissions on the log # directory. Having write permissions set is a potential security hole. # Only makes a difference if the server process is started by root. #LogDirGroupWriteOk -#LogDirPublicWriteOk +#LogDirOtherWriteOk # RefererIgnore: If you don't want to keep track of links from certain # servers (like your own), place it here. If you want to log them all, diff --git a/conf/srm.conf-dist b/conf/srm.conf-dist index 70881f5..1d713fb 100644 --- a/conf/srm.conf-dist +++ b/conf/srm.conf-dist @@ -43,6 +43,19 @@ Alias /icons/ /usr/local/etc/httpd/icons/ ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin/ +#=========================================================================== +# OpenMarket's FCGI Support Options (http://www.fastcgi.com/ +#--------------------------------------------------------------------------- +# FCGIScritpAlias: Same as ScriptAlias, except for FCGI scripts +# Format: FCGIScriptAlias fakename realname + +FCGIScriptAlias /fcgi-bin/ /usr/local/etc/httpd/fcgi-devel-kit/examples/ + +# Define the AppClasses. These get hit when requests come in for +# /fcgi-bin/tiny-fcgi.fcgi or /fcgi-bin/tiny-fcgi2.fcgi +AppClass /usr/local/etc/httpd/fcgi-devel-kit/examples/tiny-fcgi.fcgi -listen-queue-depth 10 -processes 2 +AppClass /usr/local/etc/httpd/fcgi-devel-kit/examples/tiny-fcgi2.fcgi -listen-queue-depth 10 -processes 2 + #=========================================================================== # Directory Indexing #--------------------------------------------------------------------------- @@ -122,8 +135,8 @@ 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 +#AddEncoding compress Z +#AddEncoding gzip gz # The following are known to the server as "Magic Mime Types" They allow # you to change how the server perceives a document by the extension @@ -137,6 +150,7 @@ DefaultType text/plain #AddType text/x-server-parsed-html .shtml #AddType text/x-imagemap .map #AddType application/x-httpd-cgi .cgi +#AddType application/x-httpd-fcgi .fcgi #=========================================================================== # Misc Server Resources diff --git a/src/CHANGES b/src/CHANGES new file mode 100644 index 0000000..7343828 --- /dev/null +++ b/src/CHANGES @@ -0,0 +1,16 @@ + +Fixes for 1.5.2 +------------------ +*) Changed getline rfc822 line wrap to check for validity of the next bits + before attempting to see them +*) Changed imagemap.c so relative URLs actually work +*) Don't core dump on a method only request +*) reset errno to 0 in send_fp so we break out of loop +*) somewhere we stopped killing cgi scripts on SIGALRM and SIGPIPE +*) changed group handling support to support multiple groups again +*) reset content_length before scanning cgi headers, not after +*) don't free env var in replace (it uses allocate now) +*) Only look for path_info if its part of the requested URL (as opposed + to keep looking until you hit a real directory) +*) Make make_dirstr() in util.c return / instead of null if n = 1 + diff --git a/src/FEATURE_REQUESTS b/src/FEATURE_REQUESTS new file mode 100644 index 0000000..2efed4f --- /dev/null +++ b/src/FEATURE_REQUESTS @@ -0,0 +1,37 @@ + +Port configurable per VirtualHost + kadow@msg.net (Kevin Kadow) +Server Parse CGI output + not feasible because SSI parser using buffered I/O, CGI uses getline() + (server buffered I/O) + But, we did it anyways. See CGI_SSI_HACK in config.h +Allow extra CGI environment variables to be specified via configuration + Kevin Kadow (kadow@msg.net) and Brian Millett (bpm@techapp.com) + Shouldn't be too hard, probably in 1.5.1b4 + Ok, maybe in 1.5.2 +AuthUserScript - Heiner Schorn (Heiner.Schorn@informatik.umu.se) + Pass a user name to a script, it returns the password to check against + the one the client sent to the server. This is safe from someone + writing a script to gather passwords, because the given password is + never sent to the script. This is unsafe on the server system because + it will return the password of a user. That could be made safer by + making the mechanism employ crypt on the password before hand.. + Shouldn't be too hard, but needs some design work. Perhaps 1.5.1b4 + Ok, maybe 1.5.2 +Have separate UID/GID per CGI script - Marc Evans (marc@destek.net) + With Patch (NF-1.5b7-marc_cgi_uid_hack) + Basically, changes calls from setuid to seteuid, so it changes the + effective user id of the server. This makes any security hole + potentially dangerous, such as the one in 1.3, since the program + that you can force to run can set the euid back to root. + Look at it for 1.5.1b4, probably always have to be a #define for the + more security conscious users of NCSA HTTPd + Push off to 1.5.2 +SHTTP + Alpha is done, but we need to test it more +SSL + Again, alpha code is in place, but it needs to be tested more +RADIUS + Ok, I was expecting something slightly different. Doesn't quite fit + the current way of doing things, but shouldn't be too hard to figure + out either. Probably 1.5.2 diff --git a/src/HTTP_HEADERS b/src/HTTP_HEADERS new file mode 100644 index 0000000..f57d1ad --- /dev/null +++ b/src/HTTP_HEADERS @@ -0,0 +1,81 @@ + +The following is NCSA HTTPd treatment of HTTP headers. By Supported, +we mean that the server explicitly manipulates the headers. This +doesn't include forwarding of headers to CGI scripts or including +headers from CGI scripts. + +In +HTTP HEADER HTTP Section Sup to/why length Used for? +Date 1.0 General N Do I care what the clients date is? +MIME-Version 1.0 General N The server isn't MIME Compliant +Pragma 1.0 General N Only no-cache is defined, and this isn't a proxy server +Authorization 1.0 Request Y reqInfo->inh_auth_line HUGE_STRING_LEN Authentication (Basic/MD5/Keberos) +From 1.0 Request N no one uses it +If-Modified-Since 1.0 Request Y reqInfo->inh_if_mod MAX_STRING_LEN 304 Use Local Copy response +Referer 1.0 Request Y reqInfo->inh_referer HUGE_STRING_LEN Logs +User-agent 1.0 Request Y reqInfo->inh_agent HUGE_STRING_LEN Logs +Allow 1.0 Entity N not clear how useful in request +Content-Encoding 1.0 Entity N +Content-Length 1.0 Entity Y reqInfo->inh_content_length int POST content length +Content-Type 1.0 Entity Y reqInfo->inh_content_type MAX_STRING_LEN POST content should be application/x-www-form-urlencoded +Expires 1.0 Entity N time request expires? +Last-Modified 1.0 Entity N last time request was modified? +Cache-Control 1.1 General N +Connection 1.1 General Y Keep-Alive +Forwarded 1.1 General N +Keep-Alive 1.1 General N max= timeout= same +Upgrade 1.1 General N +Accept 1.1 Request N +Accept-Charset 1.1 Request N +Accept-Encoding 1.1 Request N +Accept-Language 1.1 Request N +Host 1.1 Request Y reqInfo->inh_called_hostname MAX_STRING_LEN to provide virtual host support with CNAMES +Proxy-Authorization 1.1 Request N +Range 1.1 Request N +Unless 1.1 Request N +Content-Language 1.1 Entity N +Content-MD5 1.1 Entity N +Content-Range 1.1 Entity N +Content-Version 1.1 Entity N +Derived-From 1.1 Entity N +Link 1.1 Entity N +Title 1.1 Entity N +Transfer-Encoding 1.1 Entity N +URI-header 1.1 Entity N +Extension + + +Out +HTTP HEADER HTTP Section Sup from/why +Date 1.0 General Y GMT Date in rfc 822 format +MIME-Version 1.0 General N The server isn't MIME Compliant +Pragma 1.0 General N Only no-cache is defined, and this isn't a proxy server +Location 1.0 Response Y reqInfo->outh_location HUGE_STRING_LEN redirects +Server 1.0 Response Y #define SERVER_VERSION +WWW-Authenticate 1.0 Response Y reqInfo->outh_www_auth HUGE_STRING_LEN +Allow 1.0 Entity N We could make a list in evaluate_access(), but wouldn't that be a security hole? +Content-Encoding 1.0 Entity Y reqInfo->outh_content_encoding MAX_STRING_LEN AddEncoding +Content-Length 1.0 Entity Y reqInfo->outh_content_length int +Content-Type 1.0 Entity Y reqInfo->outh_content_type MAX_STRING_LEN +Expires 1.0 Entity N could add an AddExpires config option +Last-Modified 1.0 Entity Y reqInfo->outh_last_mod MAX_STRING_LEN client caching +Cache-Control 1.1 General N +Connection 1.1 General Y keep_alive. stuff Keep-Alive +Forwarded 1.1 General N +Keep-Alive 1.1 General Y max= timeout= same +Upgrade 1.1 General N +Proxy-Authenticate 1.1 Response N +Public 1.1 Response N +Retry-After 1.1 Response N +Content-Language 1.1 Entity N +Content-MD5 1.1 Entity Y reqInfo->outh_content_md5 allocated do you get what you asked for +Content-Range 1.1 Entity N +Content-Version 1.1 Entity N +Derived-From 1.1 Entity N +Link 1.1 Entity N +Title 1.1 Entity N +Transfer-Encoding 1.1 Entity N +URI-header 1.1 Entity N +Annotations-cgi reqInfo->hostInfo->annotation_server +Extension: Domain-Restricted reqInfo->bNotifyDomainRestricted && + reqInfo->bSatisfiedDomain diff --git a/src/HTTPd_REQ_PATH b/src/HTTPd_REQ_PATH new file mode 100644 index 0000000..d081916 --- /dev/null +++ b/src/HTTPd_REQ_PATH @@ -0,0 +1,212 @@ +child_main httpd.c + GetDescriptor httpd.c + setproctitle + recv_fd + GetRemoteLogName httpd.c + getpeername + rfc931 + initialize_request http_request.c + malloc + reset_security http_access.c + free + init_header_vars http_mime.c + free + RequestMain http_request.c + signal + getline + setproctitle + decode_request http_request.c + strtok + MapMethod http_request.c + get_mime_headers + getline + strchr + isspace + strcasecmp + http2cgi util.c + merge_header env.c + realloc + make_env_str env.c + malloc + realloc + unescape_url util.c + which_host_conf + get_local_addr + getsockname + get_remote_host util.c + getpeername + strdup + gethostbyaddr + gethostbyname + inet_ntoa + process_request http_request.c + translate_name http_alias.c + getparents util.c + make_full_path util.c + log_reason + malloc + log_error util.c + free + send_node http_send.c + stat + extract_path_info http_send.c + count_dirs util.c + make_dirstr util.c + stat + evaluate_access http_access.c + no2slash util.c + reset_mime_vars http_mime.c + is_matchexp util.c + strcmp_match util.c + check_dir_access http_access.c + find_allow http_access.c + in_ip http_access.c + get_remote_host_min util.c + getpeername + gethostbyaddr + in_domain http_access.c + find_deny http_access.c + in_ip http_access.c + get_remote_host_min util.c + in_domain http_access.c + parse_htaccess http_config.c + stat + FOpen fdwrap.c + parse_access_dir http_config.c + cfg_getline util.c + access_syntax_error http_config.c + cfg_getword util.c + add_type http_mime.c + malloc + strdup + add_encoding http_mime.c + malloc + strdup + add_desc http_dir.c + new_item http_dir.c + malloc + strdup + add_ignore http_dir.c + new_item http_dir.c + add_icon http_dir.c + add_alt http_dir.c + new_item http_dir.c + new_item http_dir.c + add_readme http_dir.c + new_item http_dir.c + add_header http_dir.c + new_item http_dir.c + add_opts http_dir.c + cfg_getword util.c + add_opts_int http_dir.c + new_item http_dir.c + strdup + FClose fdwrap.c + readlink + check_auth http_auth.c + auth_bong + uudecode + getword + get_pw + crypt + Digest_Check + k4_server_auth + k5_server_auth + check_krb_restrict + init_group http_auth.c + FOpen fdwrap.c + malloc + fread + FClose fdwrap.c + DBM_Open fdwrap.c + in_group http_auth.c + DBM_Close fdwrap.c + send_dir http_send.c + construct_url + escape_url + index_directory http_dir.c + Opendir + send_http_header + CloseDir + find_opts + find_header + insert_readme + make_dir_entry + malloc + qsort + output_directories + free + find_readme + insert_readme + log_transaction + probe_content_type http_mime.c + find_ct http_mime.c + send_cgi cgi.c + add_common_vars cgi.c + make_env_str env.c + cgi_stub cgi.c + can_exec util.c + Pipe fdwrap.c + fork + add_cgi_vars + error_log2stderr + execle/execve + getline util.c + write + read + scan_script_header cgi.c + getline util.c + strdup + realloc + waitpid + send_http_header http_mime.c + set_stat_line http_mime.c + free + strdup + begin_http_header http_log.c + dump_default_header http_mime.c + send_script cgi.c + alarm + getline + write + read + kill_children cgi.c + sleep + kill + waitpid + log_transaction + send_file http_send.c + set_content_type http_mime.c + find_ct http_mime.c + send_parsed_file http_include.c + FOpen fdwrap.c + set_content_length http_mime.c + set_last_modified http_mime.c + gmtime + strftime + later_than util.c + send_http_header http_mime.c + send_fd http_send.c + signal + fread + write + log_transaction http_log.c + FClose fdwrap.c + probe_content_type http_mime.c + send_cgi cgi.c + send_imagemap imagemap.c + FOpen fdwrap.c + pointinpoly imagemap.c + sendmsg imagemap.c + pointincircle imagemap.c + pointinrect imagemap.c + FClose fdwrap.c + send_file http_send.c + exec_cgi_script cgi.c + get_path_info + evaluate_access + add_common_vars + cgi_stub + CompleteRequest httpd.c + CloseAll fd_wrap.c + free_request http_request.c diff --git a/src/Makefile b/src/Makefile index 3dfc6aa..381b9b9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,12 +1,13 @@ # NCSA HTTPd 1.5 # # For normal machines with ANSI compilers -# CC= cc +#CC= cc # For Suns or other non-ANSI platforms. CC= gcc -QUANTIFY=/hdf2/pure/quantify-2.0-sunos4/quantify -PURIFY=purify - +#CC = xlc +QUANTIFY=/hdf2/pure/quantify-2.0.1-sunos4/quantify +PURIFY=/hdf2/pure/purify-3.2-sunos4/purify +#PURIFY=/X11/sgi5/purify3.1/purify # CFLAGS, compile flags. # @@ -14,12 +15,17 @@ PURIFY=purify # All other defines are in config.h # If you want to ensure that CGI scripts can't mess with the log files, # use -DSECURE_LOGS -# -CFLAGS= -g +CFLAGS= -g #CFLAGS= -pg -DPROFILE -#CFLAGS= -g -Wall -ansi -pedantic +#CFLAGS= -g -ansi -pedantic -Wall -DAIX_BROKEN_HEADERS +# FCGI Support +# +# To enable Openmarkets FCGI, uncomment the following +# Currently uses the TCL library for strings, which requires the math library + +#FCGI_CFLAGS = -DFCGI_SUPPORT -I/local/include # DIGEST AUTHENTICATION # @@ -46,8 +52,8 @@ KRB5_CFLAGS = -DKRB5 -I$(KRB5_DIR)/include -I$(KRB5_DIR)/include/krb5 # Comment out the following two lines to exclude Kerberos support -# KRB_CFLAGS = $(KRB4_CFLAGS) $(KRB5_CFLAGS) # -DKRB-ENCRYPT -# KRB_LIBS = $(KRB4_LIBS) $(KRB5_LIBS) +#KRB_CFLAGS = $(KRB4_CFLAGS) $(KRB5_CFLAGS) # -DKRB-ENCRYPT +#KRB_LIBS = $(KRB4_LIBS) $(KRB5_LIBS) # DBM @@ -81,7 +87,7 @@ LFLAGS= # -pg -DPROFILE # EXTRA_LIBS= -lresolv # For Solaris 2.x # AUX_CFLAGS= -DSOLARIS2 -# EXTRA_LIBS= -lsocket -lnsl +# 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 @@ -89,7 +95,7 @@ LFLAGS= # -pg -DPROFILE # For HP-UX # AUX_CFLAGS= -DHPUX # For AIX3 - AUX_CFLAGS= -DAIX3 +# AUX_CFLAGS= -DAIX3 -D_ALL_SOURCE # For xlc compiler # For AIX4 # AUX_CFLAGS= -DAIX4 # For Ultrix @@ -101,7 +107,8 @@ LFLAGS= # -pg -DPROFILE # For Sequent # AUX_CFLAGS= -DSEQUENT # For Linux -m486 ONLY IF YOU HAVE 486 BINARY SUPPORT IN KERNEL -# AUX_CFLAGS= -DLINUX +# AUX_CFLAGS= -DLINUX # -DFD_LINUX for Linux 1.2.13 +# DBM_LIBS = -lgdbm # For NetBSD 1.0 # May not need -lcrypt if its included in your libc # AUX_CFLAGS= -DNetBSD @@ -120,6 +127,9 @@ LFLAGS= # -pg -DPROFILE # For SCO SVR3.2 # AUX_CFLAGS= -DSCO3 # EXTRA_LIBS= -lPW -lsocket -lmalloc -lintl -lcrypt +# For SCO OpenServer 5 +# AUX_CFLAGS= -DSCO5 +# EXTRA_LIBS= -lPW -lsocket -lmalloc -lintl -lcrypt # For SVR4 # AUX_CFLAGS= -DSVR4 # EXTRA_LIBS= -lsocket -lnsl -lc @@ -142,18 +152,21 @@ LFLAGS= # -pg -DPROFILE # -------------- You shouldn't have to edit anything else ----------------- # ------------------------------------------------------------------------- -SEC_CFLAGS = $(MD5_CFLAGS) $(PGP_CFLAGS) $(KRB_CFLAGS) -SEC_LIBS = $(KRB_LIBS) +SEC_CFLAGS = $(MD5_CFLAGS) $(KRB_CFLAGS) +SEC_LIBS = $(KRB_LIBS) + +ALL_CFLAGS = $(CFLAGS) $(AUX_CFLAGS) $(SEC_CFLAGS) $(DBM_CFLAGS) $(FCGI_CFLAGS) +ALL_LIBS = $(EXTRA_LIBS) $(SEC_LIBS) $(DBM_LIBS) OBJS=httpd.o http_config.o http_request.o util.o http_dir.o \ http_alias.o http_log.o http_mime.o http_access.o http_auth.o \ http_send.o cgi.o http_include.o rfc931.o imagemap.o \ http_ipc.o digest.o md5.o md5c.o env.o host_config.o fdwrap.o \ -open_logfile.o +open_logfile.o allocate.o debug.o blackout.o fcgi.o .c.o: Makefile config.h portability.h constants.h - $(CC) -c $(CFLAGS) $(AUX_CFLAGS) $(SEC_CFLAGS) $(DBM_CFLAGS) $< + $(CC) -c $(ALL_CFLAGS) $< all: httpd @@ -176,6 +189,10 @@ hp-cc: linux: make tar AUX_CFLAGS=-DLINUX CC=gcc CFLAGS=-O2 DBM_LIBS=-lgdbm +linux2: linux +linux1: + make tar AUX_CFLAGS="-DLINUX -DFD_LINUX" CC=gcc CFLAGS=-O2 DBM_LIBS=-lgdbm + netbsd: make tar AUX_CFLAGS=-DNETBSD EXTRA_LIBS=-lcrypt CC=cc CFLAGS=-O2 @@ -185,6 +202,9 @@ next: osf1: make tar AUX_CFLAGS=-DOSF1 CC=cc CFLAGS="-O2 -Olimit 750" +sco5: + make tar AUX_CFLAGS=-DSCO5 CC=icc CFLAGS="" EXTRA_LIBS="-lPW -lsocket -lmalloc -lintl -lcrypt" DBM_LIBS=-ldbm + sgi: make tar AUX_CFLAGS=-DIRIX EXTRA_LIBS=-lsun CC=cc CFLAGS=-O2 @@ -203,21 +223,22 @@ ultrix: make tar AUX_CFLAGS=-DULTRIX CC=gcc CFLAGS=-O2 httpd: $(OBJS) - $(CC) $(LFLAGS) -o httpd $(OBJS) $(EXTRA_LIBS) $(SEC_LIBS) $(DBM_LIBS) + $(CC) $(LFLAGS) -o httpd $(OBJS) $(ALL_LIBS) +# -logfile=/X11/blong/httpd/logs/pure_log purify: $(OBJS) - $(PURIFY) -logfile=/X11/blong/httpd/logs/pure_log \ - -program-name=/X11/blong/httpd/src/httpd \ + $(PURIFY) -program-name=/X11/blong/httpd/src/httpd \ -follow-child-processes=yes \ - $(CC) $(LFLAGS) -o httpd $(OBJS) $(EXTRA_LIBS) $(SEC_LIBS) $(DBM_LIBS) + $(CC) $(LFLAGS) -o httpd $(OBJS) $(ALL_LIBS) quantify: $(OBJS) $(QUANTIFY) -record-child-process-data=yes \ - -avoid-recording-system-calls=93,113,114 \ - $(CC) $(LFLAGS) -o httpd $(OBJS) $(EXTRA_LIBS) $(SEC_LIBS) $(DBM_LIBS) + -record-data=no \ + -avoid-recording-system-calls=1,6,93,113,114 \ + $(CC) $(LFLAGS) -o httpd $(OBJS) $(ALL_LIBS) tar: $(OBJS) - $(CC) $(LFLAGS) -o ../httpd $(OBJS) $(EXTRA_LIBS) $(SEC_LIBS) $(DBM_LIBS) + $(CC) $(LFLAGS) -o ../httpd $(OBJS) $(ALL_LIBS) http_access.o: Makefile config.h portability.h constants.h http_access.h \ @@ -248,13 +269,15 @@ http_log.o: config.h portability.h constants.h http_log.h \ http_mime.o: Makefile config.h portability.h constants.h http_mime.h \ http_log.h util.h http_config.h http_access.h env.h http_request.o: Makefile config.h portability.h constants.h http_request.h \ - util.h http_mime.h http_config.h http_log.h http_auth.h \ - httpd.h http_send.h cgi.h http_access.h host_config.h \ - http_alias.h env.h -imagemap.o: Makefile constants.h imagemap.h + allocate.h cgi.h env.h http_access.h http_alias.h \ + host_config.h http_config.h http_log.h http_send.h util.h +imagemap.o: Makefile constants.h imagemap.h allocate.h cgi.o: Makefile config.h portability.h constants.h cgi.h \ http_log.h http_request.h util.h http_mime.h http_access.h \ http_auth.h http_alias.h http_config.h +fcgi.o: Makefile config.h portability.h constants.h fcgi.h \ + fdwrap.h cgi.h env.h http_request.h http_log.h http_access.h \ + http_mime.h http_config.h http_auth.h http_alias.h util.h httpd.o: Makefile config.h portability.h constants.h httpd.h \ http_request.h http_config.h http_log.h http_auth.h \ http_dir.h http_access.h util.h http_ipc.h host_config.h \ @@ -265,6 +288,8 @@ env.o: config.h portability.h constants.h http_log.h env.h rfc931.o: config.h portability.h open_logfile.o: config.h portability.h constants.h open_logfile.h \ http_config.h util.h +allocate.o: config.h portability.h constants.h host_config.h http_log.h \ + allocate.h # file descriptor scoreboarding fdwrap.o: config.h portability.h constants.h fdwrap.h @@ -282,5 +307,5 @@ SRC = $(OBJS:%.o=%.c) codecenter: #setopt ansi #setopt print_string 128 - #setopt load_flags $(CFLAGS) $(AUX_CFLAGS) $(SEC_CFLAGS) $(DBM_CFLAGS) - #load $(LFLAGS) $(SRC) $(EXTRA_LIBS) $(SEC_LIBS) $(DBM_LIBS) + #setopt load_flags $(ALL_FLAGS) + #load $(LFLAGS) $(SRC) $(ALL_LIBS) diff --git a/src/allocate.c b/src/allocate.c new file mode 100644 index 0000000..0c66607 --- /dev/null +++ b/src/allocate.c @@ -0,0 +1,267 @@ +/************************************************************************ + * NCSA HTTPd Server + * Software Development Group + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * 605 E. Springfield, Champaign, IL 61820 + * httpd@ncsa.uiuc.edu + * + * Copyright (C) 1995, Board of Trustees of the University of Illinois + * + ************************************************************************ + * + * allocate.c,v 1.5 1996/04/05 18:54:28 blong Exp + * + ************************************************************************ + * + * allocate.c: Functions to allocate data types as needed + * + */ + +#include "config.h" +#include "portability.h" + +#include +#ifndef NO_STDLIB_H +# include +#endif /* NO_STDLIB_H */ +#ifndef NO_MALLOC_H +# ifdef NEED_SYS_MALLOC_H +# include +# else +# include +# endif /* NEED_SYS_MALLOC_H */ +#endif /* NO_MALLOC_H */ +#include + +#include "constants.h" +#include "host_config.h" +#include "http_log.h" +#include "allocate.h" +#include "http_request.h" + + +string_list free_list; +string_list used_list; + +int initialize_allocate() +{ + initialize_string_allocate(); + return 0; +} + +int initialize_string_allocate() +{ + free_list.num = 0; + free_list.first = NULL; + + used_list.num = 0; + used_list.first = NULL; + + allocate_strings(&free_list,HUGE_STRING_LEN,5); + allocate_strings(&free_list,MAX_STRING_LEN,5); + return 0; +} + +int allocate_strings(string_list *slist, int length, int num) +{ + string_item *stmp; + char *S; + + + while (num) { + if (!(S = (char *) malloc(length * sizeof(char)))) + return 1; + + S[0] = '\0'; + + if (!(stmp = (string_item *) malloc(sizeof(string_item)))) + return 1; + + stmp->string = S; + stmp->length = length; + + if (slist->num == 0) { + slist->first = stmp; + stmp->next = NULL; + slist->num = 1; + } else { + stmp->next = slist->first; + slist->first = stmp; + slist->num++; + } + num--; + } + return 0; +} + +int remove_string_item(string_list *slist, string_item *sitem) +{ + string_item *stmp,*last; + int x; + + stmp = slist->first; + last = NULL; + + for(x = 0; x < slist->num ; x++) { + if (stmp == sitem) { + if (stmp == slist->first) { + slist->first = slist->first->next; + } else { + last->next = stmp->next; + } + slist->num--; + stmp->next = NULL; + return TRUE; + } + last = stmp; + stmp = stmp->next; + } + return FALSE; +} + +int add_string_item(string_list *slist, string_item *sitem) +{ + if (slist->num == 0) { + slist->first = sitem; + slist->num = 1; + } else { + sitem->next = slist->first; + slist->first = sitem; + slist->num++; + } + return TRUE; +} + + +char* newString(int length, int type) +{ + int num, x; + string_item *sitem; + + if (free_list.num == 0) { + if ((length == HUGE_STRING_LEN) || (length == MAX_STRING_LEN)) + num = 5; + else + num = 1; + allocate_strings(&free_list, length, num); + } + + sitem = free_list.first; + for(x = 0; x < free_list.num ; x++) { + if (sitem->length == length) { + remove_string_item(&free_list,sitem); + add_string_item(&used_list,sitem); + sitem->type = type; + return sitem->string; + } + sitem = sitem->next; + } + + /* Don't have a string of the correct size, make one. + * Since allocate_strings adds strings to beginning of list, just return + * first string in used_list. + * In the future, might want to just return one which is larger. + */ + + allocate_strings(&used_list, length, 1); + used_list.first->type = type; + return used_list.first->string; +} + +int freeString(char *string) +{ + int x; + string_item *sitem; + + if (string == NULL) return FALSE; + + sitem = used_list.first; + for(x = 0; x < used_list.num ; x++) { + if (sitem->string == string) { + string[0] = '\0'; + remove_string_item(&used_list,sitem); + add_string_item(&free_list,sitem); + return TRUE; + } + sitem = sitem->next; + } + log_error("Attempt to Free String not in Use",gConfiguration->error_log); + return FALSE; +} + +/* Look up allocated size of string + * Success returns lenth of string + * Failure returns -1 + */ +int sizeofString(char *string) +{ + int x; + string_item *sitem; + + if (string == NULL) return -1; + + sitem = used_list.first; + for(x = 0; x < used_list.num ; x++) { + if (sitem->string == string) { + return sitem->length; + } + sitem = sitem->next; + } +/* log_error("String not allocated.",gConfiguration->error_log); */ + return -1; +} + + +int freeAllStrings(int type) +{ + + string_item *sitem,*slast; + + slast = NULL; + sitem = used_list.first; + while (used_list.num && (sitem != NULL)) { + if (sitem->type <= type) { + sitem->string[0] = '\0'; + if (sitem == used_list.first) { + used_list.first = sitem->next; + used_list.num--; + sitem->next = NULL; + add_string_item(&free_list,sitem); + sitem = used_list.first; + } else { + used_list.num--; + slast->next = sitem->next; + add_string_item(&free_list,sitem); + sitem = slast->next; + } + } else { + slast = sitem; + sitem = sitem->next; + } + } + return TRUE; +} + +/* dupStringP() : Promotes and copies strings to MAX/HUGE in order to + * attempt to use already existing strings (no malloc). This will + * truncate strings to HUGE length. + */ +char *dupStringP(char *str_in, int type) +{ + int req_len; + char *str_out; + + req_len = strlen(str_in); + if (req_len <= MAX_STRING_LEN) + req_len = MAX_STRING_LEN; + else + req_len = HUGE_STRING_LEN; + + + str_out = newString(req_len,type); + strncpy(str_out,str_in,req_len); + str_out[req_len-1] = '\0'; + + return str_out; +} diff --git a/src/allocate.h b/src/allocate.h new file mode 100644 index 0000000..16b61ef --- /dev/null +++ b/src/allocate.h @@ -0,0 +1,61 @@ +/************************************************************************ + * NCSA HTTPd Server + * Software Development Group + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * 605 E. Springfield, Champaign, IL 61820 + * httpd@ncsa.uiuc.edu + * + * Copyright (C) 1995, Board of Trustees of the University of Illinois + * + ************************************************************************ + * + * allocate.h,v 1.2 1996/04/05 18:54:29 blong Exp + * + ************************************************************************ + * + * allocate.h: Functions to allocate data types as needed + * + */ + +#ifndef _ALLOCATE_H +#define _ALLOCATE_H 1 + +/* There are different levels of strings, depending on when they can + * be "free'd". + * STR_TMP can be free'd outside the function. + * STR_REQ can be free'd at the end of the request. + * STR_HUP can be free'd at Restart. + */ + +#define STR_TMP 0 +#define STR_REQ 2 +#define STR_HUP 5 + +typedef struct _string_item { + char *string; + int length; + int type; + struct _string_item* next; +} string_item; + +typedef struct _string_list { + string_item* first; + int num; +} string_list; + +/* Public Interface */ +int initialize_allocate(void); +char* newString(int length, int type); +char *dupStringP(char *str_in, int type); +int freeString(char *string); +int freeAllStrings(int type); +int sizeofString(char *string); + +/* Private Interface */ +int initialize_string_allocate(); +int allocate_strings(string_list *slist, int length, int num); +int remove_string_item(string_list *slist, string_item *sitem); +int add_string_item(string_list *slist, string_item *sitem); + +#endif /* _ALLOCATE_H */ diff --git a/src/blackout.c b/src/blackout.c new file mode 100644 index 0000000..ec6fdd1 --- /dev/null +++ b/src/blackout.c @@ -0,0 +1,187 @@ +/************************************************************************ + * NCSA HTTPd Server + * Software Development Group + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * 605 E. Springfield, Champaign, IL 61820 + * httpd@ncsa.uiuc.edu + * + * Copyright (C) 1995, Board of Trustees of the University of Illinois + * + ************************************************************************ + * + * blackout.c,v 1.3 1996/03/07 21:27:21 blong Exp + * + ************************************************************************ + * + */ + + +#include "config.h" +#include "portability.h" + +#include +#ifndef NO_STDLIB_H +# include +#endif /* NO_STDLIB_H */ +#include +#include +#include +#include +#include +#include +#include "constants.h" +#include "fdwrap.h" +#include "allocate.h" +#include "http_send.h" +#include "cgi.h" +#include "imagemap.h" +#include "http_mime.h" +#include "http_log.h" +#include "http_request.h" +#include "http_config.h" +#include "http_include.h" +#include "http_alias.h" +#include "http_access.h" +#include "http_dir.h" +#include "httpd.h" +#include "util.h" + +#ifdef BLACKOUT_CODE + +char *bodyTag = ""; + +/* void (*exit_callback)(void); */ + + +int realWrite(int fd, char *buf, int length) +{ + int left = length; + int sent = 0; + int off = 0; + int wrote = 0; + + while(left) { + if ((wrote = write(fd,&buf[off],left)) < 0) { + if (errno != EINTR) break; + } + left -= wrote; + off += wrote; + sent += wrote; + } + + return sent; +} + +int sendBody(per_request *reqInfo, char *buf, int length) +{ + int x = 0; + int found = 0; + int state = 0; + int begin = 0; + + while(x < length) { + switch (state) { + case 0 : + if (buf[x] == '<') { + begin = x; + state++; + } + break; + case 1 : + if ((buf[x] == 'B') || (buf[x] == 'b')) state++; + else state = 0; + break; + case 2 : + if ((buf[x] == 'O') || (buf[x] == 'o')) state++; + else state = 0; + break; + case 3 : + if ((buf[x] == 'D') || (buf[x] == 'd')) state++; + else state = 0; + break; + case 4 : + if ((buf[x] == 'Y') || (buf[x] == 'y')) state++; + else state = 0; + break; +/* case 5 : + if (buf[x] == ' ') state++; + else state = 0; + break; */ + case 5 : + if (buf[x] == '>') state++; + break; + case 6 : + realWrite(fileno(reqInfo->out), buf,begin); + realWrite(fileno(reqInfo->out), bodyTag, strlen(bodyTag)); + realWrite(fileno(reqInfo->out), buf+x,length-x); + x = length; + } + x++; + } + + if (state != 6) realWrite(fileno(reqInfo->out),buf,length); + return FALSE; +} + +/* + We'll make it return the number of bytes sent + so that we know if we need to send a body by default +*/ +long send_fp_black(per_request *reqInfo, FILE *f, void (*onexit)(void)) +{ + char *buf; + long total_bytes_sent; + register int n,o,w; + int isHTML = FALSE; + + buf = newString(IOBUFSIZE,STR_TMP); + exit_callback = onexit; + signal(SIGALRM,send_fd_timed_out); + signal(SIGPIPE,send_fd_timed_out); + + total_bytes_sent = 0; + if (!strcmp(reqInfo->outh_content_type,"text/html")) { + isHTML = TRUE; + total_bytes_sent = rprintf(reqInfo,bodyTag); + } + rflush(reqInfo); + while (1) { + alarm(timeout); + if((n=fread(buf,sizeof(char),IOBUFSIZE,f)) < 1) { + if (errno != EINTR) break; + } + + o=0; + if(reqInfo->bytes_sent != -1) + reqInfo->bytes_sent += n; + if (isHTML) { + sendBody(reqInfo,buf,n); + total_bytes_sent += n; + n = 0; + } + while(n) { +/* Seems some systems have broken fwrite's (like AIX 3.2.5 on PowerPC) + * this should be a drop in replacement, maybe even be faster. + * For now, we'll just replace, but may have to #define one or the other + * depending on the system. + */ + if ((w=write(fileno(reqInfo->out),&buf[o],n)) < 0) { + if (errno != EINTR) break; + } + n-=w; + o+=w; + total_bytes_sent += w; + } + + } + if (isHTML) + rprintf(reqInfo,"


My World Wide Web Pages are black for 48 hours to protest second-class treatment from the US Government for free speech. Read about it at this WWW page."); + alarm(0); + signal(SIGALRM,SIG_IGN); + signal(SIGPIPE,SIG_IGN); + freeString(buf); + return total_bytes_sent; +} + +#endif /* BLACKOUT_CODE */ diff --git a/src/blackout.h b/src/blackout.h new file mode 100644 index 0000000..32cb23c --- /dev/null +++ b/src/blackout.h @@ -0,0 +1,26 @@ +/************************************************************************ + * NCSA HTTPd Server + * Software Development Group + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * 605 E. Springfield, Champaign, IL 61820 + * httpd@ncsa.uiuc.edu + * + * Copyright (C) 1995, Board of Trustees of the University of Illinois + * + ************************************************************************ + * + * blackout.h,v 1.1 1996/02/08 18:01:02 blong Exp + * + ************************************************************************ + * + */ + +#ifndef _BLACKOUT_H +#define _BLACKOUT_H + +/* function prototypes */ +long send_fp_black(per_request *reqInfo, FILE *f, void (*onexit)(void)); + +#endif /* _BLACKOUT_H */ + diff --git a/src/cgi.c b/src/cgi.c index 86b8a32..631bf03 100644 --- a/src/cgi.c +++ b/src/cgi.c @@ -10,33 +10,14 @@ * ************************************************************************ * - * cgi.c,v 1.34 1995/11/28 09:01:37 blong Exp + * cgi.c,v 1.44 1996/04/05 18:54:31 blong Exp * ************************************************************************ * * cgi: keeps all script-related ramblings together. - * - * Based on NCSA HTTPd 1.3 by Rob McCool * - * 03-07-95 blong - * Added support for variable REMOTE_GROUP from access files - * - * 03-20-95 sguillory - * Moved to more dynamic memory management of environment arrays - * - * 04-03-95 blong - * Added support for variables DOCUMENT_ROOT, ERROR_REQINFO->STATUS - * ERROR_URL, ERROR_REQUEST - * - * 04-20-95 blong - * Added Apache patch "B18" from Rob Hartill to allow nondelayed redirects - * - * 05-02-95 blong - * Since Apache is using REDIRECT_ as the env variables, I've decided to - * go with this in the interest of general Internet Harmony and Peace. */ - #include "config.h" #include "portability.h" @@ -56,21 +37,34 @@ #include #include #include +#include #include "constants.h" #include "fdwrap.h" +#include "allocate.h" #include "cgi.h" #include "env.h" -#include "http_request.h" -#include "http_log.h" #include "http_access.h" -#include "http_mime.h" -#include "http_config.h" -#include "http_auth.h" #include "http_alias.h" +#include "http_auth.h" +#include "http_config.h" +#include "http_include.h" +#include "http_log.h" +#include "http_mime.h" +#include "http_request.h" +#include "http_send.h" +#include "http_include.h" +#include "httpd.h" #include "util.h" + int pid; +#ifdef KRB4 +# include +extern AUTH_DAT kerb_kdata; +# include +#endif /* KRB4 */ + void kill_children(per_request *reqInfo) { char errstr[MAX_STRING_LEN]; sprintf(errstr,"killing CGI process %d",pid); @@ -82,75 +76,87 @@ void kill_children(per_request *reqInfo) { waitpid(pid,NULL,0); } -#ifdef KRB4 -# include -extern AUTH_DAT kerb_kdata; -# include -#endif /* KRB4 */ +void kill_children_timed_out() { + kill_children(gCurrentRequest); +} char **create_argv(per_request *reqInfo,char *av0) { register int x,n; char **av; - char w[HUGE_STRING_LEN]; - char l[HUGE_STRING_LEN]; + char *str1,*str2; + + str1 = newString(HUGE_STRING_LEN,STR_TMP); + str2 = newString(HUGE_STRING_LEN,STR_TMP); for(x=0,n=2;reqInfo->args[x];x++) if(reqInfo->args[x] == '+') ++n; - if(!(av = (char **)malloc((n+1)*sizeof(char *)))) + if(!(av = (char **)malloc((n+1)*sizeof(char *)))) { + freeString(str1); + freeString(str2); die(reqInfo,SC_NO_MEMORY,"create_argv"); + } av[0] = av0; - strcpy(l,reqInfo->args); + strcpy(str2,reqInfo->args); for(x=1;xfilename); for(x=dirs_in_alias;x<=max;x++) { - make_dirstr(reqInfo->filename,x+1,t); - if(!(stat(t,finfo))) { + make_dirstr(reqInfo->filename,x+1,str); + if(!(stat(str,finfo))) { if(S_ISREG(finfo->st_mode)) { - int l=strlen(t); - strcpy(path_args,&(reqInfo->filename[l])); + int l=strlen(str); + strcpy(reqInfo->path_info,&(reqInfo->filename[l])); reqInfo->filename[l] = '\0'; - reqInfo->url[strlen(reqInfo->url) - strlen(path_args)] = '\0'; + reqInfo->url[strlen(reqInfo->url) - strlen(reqInfo->path_info)] = '\0'; + freeString(str); return; } } } for(x=dirs_in_alias - 1; (x > 0) ;--x) { - make_dirstr(reqInfo->filename,x+1,t); - if(!(stat(t,finfo))) { + make_dirstr(reqInfo->filename,x+1,str); + if(!(stat(str,finfo))) { if(S_ISREG(finfo->st_mode)) { - strcpy(path_args,&(reqInfo->filename[strlen(t)])); - strcpy(reqInfo->filename,t); - reqInfo->url[strlen(reqInfo->url) - strlen(path_args)] = '\0'; + strcpy(reqInfo->path_info,&(reqInfo->filename[strlen(str)])); + strcpy(reqInfo->filename,str); + reqInfo->url[strlen(reqInfo->url) - strlen(reqInfo->path_info)] = '\0'; + freeString(str); return; } } } - /* unmunge_name(reqInfo,reqInfo->filename); */ log_reason(reqInfo,"script does not exist",reqInfo->filename); + freeString(str); die(reqInfo,SC_NOT_FOUND,reqInfo->url); } -int add_cgi_vars(per_request *reqInfo, char *path_args, int *content) +int add_cgi_vars(per_request *reqInfo, int *content) { - char t[HUGE_STRING_LEN]; + char *str; + + str = newString(HUGE_STRING_LEN,STR_TMP); make_env_str(reqInfo,"GATEWAY_INTERFACE","CGI/1.1"); @@ -160,10 +166,10 @@ int add_cgi_vars(per_request *reqInfo, char *path_args, int *content) methods[reqInfo->method]); make_env_str(reqInfo,"SCRIPT_NAME",reqInfo->url); - if(path_args[0]) { - make_env_str(reqInfo,"PATH_INFO",path_args); - translate_name(reqInfo,path_args,t); - make_env_str(reqInfo,"PATH_TRANSLATED",t); + if(reqInfo->path_info[0]) { + make_env_str(reqInfo,"PATH_INFO",reqInfo->path_info); + translate_name(reqInfo,reqInfo->path_info,str); + make_env_str(reqInfo,"PATH_TRANSLATED",str); } make_env_str(reqInfo,"QUERY_STRING",reqInfo->args); @@ -171,18 +177,21 @@ int add_cgi_vars(per_request *reqInfo, char *path_args, int *content) *content=0; if ((reqInfo->method == M_POST) || (reqInfo->method == M_PUT)) { *content=1; - sprintf(t,"%d",content_length); - make_env_str(reqInfo,"CONTENT_TYPE",content_type_in); - make_env_str(reqInfo,"CONTENT_LENGTH",t); + sprintf(str,"%d",reqInfo->inh_content_length); + make_env_str(reqInfo,"CONTENT_TYPE",reqInfo->inh_content_type); + make_env_str(reqInfo,"CONTENT_LENGTH",str); } } + freeString(str); return TRUE; } int add_common_vars(per_request *reqInfo) { - char t[MAX_STRING_LEN],*env_path,*env_tz; + char *env_path,*env_tz; + char *str; + str = newString(HUGE_STRING_LEN,STR_TMP); if(!(env_path = getenv("PATH"))) env_path=DEFAULT_PATH; @@ -193,32 +202,32 @@ int add_common_vars(per_request *reqInfo) { make_env_str(reqInfo,"SERVER_NAME",reqInfo->hostInfo->server_hostname); make_env_str(reqInfo,"SERVER_ADMIN",reqInfo->hostInfo->server_admin); - sprintf(t,"%d",port); - make_env_str(reqInfo,"SERVER_PORT",t); + sprintf(str,"%d",port); + make_env_str(reqInfo,"SERVER_PORT",str); make_env_str(reqInfo,"REMOTE_HOST",reqInfo->remote_name); make_env_str(reqInfo,"REMOTE_ADDR",reqInfo->remote_ip); make_env_str(reqInfo,"DOCUMENT_ROOT",reqInfo->hostInfo->document_root); - if(user[0]) - make_env_str(reqInfo,"REMOTE_USER",user); + if(reqInfo->auth_user[0]) + make_env_str(reqInfo,"REMOTE_USER",reqInfo->auth_user); + if(reqInfo->auth_group[0]) + make_env_str(reqInfo,"REMOTE_GROUP",reqInfo->auth_group); + if(reqInfo->hostInfo->annotation_server[0]) make_env_str(reqInfo,"ANNOTATION_SERVER", reqInfo->hostInfo->annotation_server); - if(groupname[0]) - make_env_str(reqInfo,"REMOTE_GROUP",groupname); if (reqInfo->auth_type[0]) { #ifdef KRB4 if(strncmp(reqInfo->auth_type, "kerberos", 8) == 0) { - char buffer[1024]; make_env_str(reqInfo,"AUTH_TYPE","KERB4_MUTUAL"); make_env_str(reqInfo,"KERB4_USER",kerb_kdata.pname); make_env_str(reqInfo,"KERB4_INSTANCE",kerb_kdata.pinst); make_env_str(reqInfo,"KERB4_REALM",kerb_kdata.prealm); - sprintf (buffer, "%s.%s@%s", kerb_kdata.pname, + sprintf (str, "%s.%s@%s", kerb_kdata.pname, kerb_kdata.pinst, kerb_kdata.prealm); - make_env_str(reqInfo,"KERB4_PRINCIPAL",buffer); + make_env_str(reqInfo,"KERB4_PRINCIPAL",str); } else #endif /* KRB4 */ make_env_str(reqInfo,"AUTH_TYPE",reqInfo->auth_type); @@ -234,268 +243,356 @@ int add_common_vars(per_request *reqInfo) { make_env_str(reqInfo,"REDIRECT_STATUS",set_stat_line(reqInfo)); } + freeString(str); return TRUE; } -int scan_script_header(per_request *reqInfo, int pd) +int scan_cgi_header(per_request *reqInfo, int pd) { - char w[HUGE_STRING_LEN]; char *l; int p; - int nFirst = 1; int ret; + int options = 0; + char *str; + + str = newString(HUGE_STRING_LEN,STR_TMP); /* Don't do keepalive unless the script returns a content-length header */ keep_alive.bKeepAlive = 0; - while(1) { - if((ret = getline(pd,w,HUGE_STRING_LEN-1,nFirst,timeout)) <= 0) { - char error_msg[MAX_STRING_LEN]; - Close(pd); - sprintf(error_msg,"HTTPd: malformed header from script %s", - reqInfo->filename); - die(reqInfo,SC_SERVER_ERROR,error_msg); - } - /* turn off forced read off socket */ - if (nFirst) nFirst = 0; + reqInfo->cgi_buf = new_sock_buf(reqInfo,pd); + cgibuf_count++; + + /* ADC put in the G_SINGLE_CHAR option, so that CGI SSI's would work. + * it was: + * if((ret = getline(reqInfo->cgi_buf,str,HUGE_STRING_LEN-1,0,timeout)) <= 0) + * + * This should be cleaned up perhaps so that it only does this if SSI's are + * allowed for this script directory. ZZZZ + */ +#ifdef CGI_SSI_HACK + if (reqInfo->RequestFlags & DOING_SHTTP) + options = G_SINGLE_CHAR; +#endif /* CGI_SSI_HACK */ + + while(1) { + if((ret = getline(reqInfo->cgi_buf,str,HUGE_STRING_LEN-1,options,timeout)) <= 0) + { + char error_msg[MAX_STRING_LEN]; + Close(pd); + freeString(str); + sprintf(error_msg,"HTTPd: malformed header from script %s", + reqInfo->filename); + die(reqInfo,SC_SERVER_ERROR,error_msg); + } /* Always return zero, so as not to cause redirect+sleep3+kill */ - if(w[0] == '\0') { - if (content_type[0] == '\0') { - if (location[0] != '\0') { - strcpy(content_type,"text/html"); + if(str[0] == '\0') { + if (reqInfo->outh_content_type[0] == '\0') { + if (reqInfo->outh_location[0] != '\0') { + strcpy(reqInfo->outh_content_type,"text/html"); } else { if (local_default_type[0] != '\0') - strcpy(content_type,local_default_type); - else strcpy(content_type,reqInfo->hostInfo->default_type); + strcpy(reqInfo->outh_content_type,local_default_type); + else strcpy(reqInfo->outh_content_type, + reqInfo->hostInfo->default_type); } } + freeString(str); return 0; } - if(!(l = strchr(w,':'))) - l = w; + if(!(l = strchr(str,':'))) + l = str; *l++ = '\0'; - if(!strcasecmp(w,"Content-type")) { + if(!strcasecmp(str,"Content-type")) { /* Thanks Netscape for showing this bug to everyone */ /* delete trailing whitespace, esp. for "server push" */ char *endp = l + strlen(l) - 1; while ((endp > l) && isspace(*endp)) *endp-- = '\0'; - sscanf(l,"%s",content_type); + sscanf(l,"%s",reqInfo->outh_content_type); } - else if(!strcasecmp(w,"Location")) { + else if(!strcasecmp(str,"Location")) { /* If we don't already have a status line, make one */ - if (!&status_line[0]) { - reqInfo->status = 302; + if (!reqInfo->status_line) { + reqInfo->status = SC_REDIRECT_TEMP; set_stat_line(reqInfo); } - sscanf(l,"%s",location); + strncpy(reqInfo->outh_location,l,HUGE_STRING_LEN); + reqInfo->outh_location[HUGE_STRING_LEN-1] = '\0'; } - else if(!strcasecmp(w,"Status")) { + else if(!strcasecmp(str,"Status")) { for(p=0;isspace(l[p]);p++); - sscanf(&l[p],"%d",&reqInfo->status); - if(!(status_line = strdup(&l[p]))) { + sscanf(&l[p],"%d",&(reqInfo->status)); + if(!(reqInfo->status_line = dupStringP(&l[p],STR_REQ))) { Close(pd); - die(reqInfo,SC_NO_MEMORY,"CGI: scan_script_header"); + freeString(str); + die(reqInfo,SC_NO_MEMORY,"CGI: scan_cgi_header"); } } - else if(!strcasecmp(w,"Content-length")) { + else if(!strcasecmp(str,"Content-length")) { keep_alive.bKeepAlive = 1; + sscanf(l,"%d",&(reqInfo->outh_content_length)); } + else if(!strcasecmp(str,"WWW-Authenticate")) { + if (!reqInfo->status_line) { + reqInfo->status = SC_AUTH_REQUIRED; + set_stat_line(reqInfo); + } + strncpy(reqInfo->outh_www_auth,l,HUGE_STRING_LEN); + reqInfo->outh_www_auth[HUGE_STRING_LEN-1] = '\0'; + } else { *(--l) = ':'; - for(p=0;w[p];p++); - w[p] = LF; - w[++p] = '\0'; - if(!out_headers) { - if(!(out_headers = strdup(w))) { + for(p=0;str[p];p++); + str[p] = LF; + str[++p] = '\0'; + if(!(reqInfo->outh_cgi)) { + if(!(reqInfo->outh_cgi = strdup(str))) { Close(pd); - die(reqInfo,SC_NO_MEMORY,"CGI: scan_script_header"); + freeString(str); + die(reqInfo,SC_NO_MEMORY,"CGI: scan_cgi_header"); } } else { - int loh = strlen(out_headers); - out_headers = (char *) realloc(out_headers, - (loh+strlen(w)+1)*sizeof(char)); - if(!out_headers) { + int loh = strlen(reqInfo->outh_cgi); + reqInfo->outh_cgi = (char *) realloc(reqInfo->outh_cgi, + (loh+strlen(str)+1)*sizeof(char)); + if(!(reqInfo->outh_cgi)) { Close(pd); - die(reqInfo,SC_NO_MEMORY,"CGI: scan_script_header"); + freeString(str); + die(reqInfo,SC_NO_MEMORY,"CGI: scan_cgi_header"); } - strcpy(&out_headers[loh],w); + strcpy(&(reqInfo->outh_cgi[loh]),str); } } } } -int cgi_stub(per_request *reqInfo, char *path_args, struct stat *finfo) +void internal_redirect(per_request *reqInfo) { - int p[2], p2[2]; /* p = script-> server, p2 = server -> script */ - int content, nph; - char *argv0; - char errlog[100]; + char url[HUGE_STRING_LEN],args[HUGE_STRING_LEN],*argp; + per_request *newInfo; + + url[0] = '\0'; + args[0] = '\0'; - if(!can_exec(finfo)) { - log_reason(reqInfo, - "client denied by server configuration (CGI non-executable)", - reqInfo->filename); - die(reqInfo,SC_FORBIDDEN,reqInfo->url); - } + /* Split the location header into URL and args */ + strncpy(url,reqInfo->outh_location,HUGE_STRING_LEN); + if((argp = strchr(url,'?'))) { + *argp++ = '\0'; + strcpy(args,argp); + } + log_transaction(reqInfo); - if((argv0 = strrchr(reqInfo->filename,'/')) != NULL) - argv0++; - else argv0 = reqInfo->filename; + /* The global string the_request currently holds the request as + * read off the socket, and is used to log the information. We force + * it to this internal request here. Only redirects to GET requests + */ + sprintf(the_request,"GET "); + strncat(the_request,url,HUGE_STRING_LEN - strlen(the_request)); + if (args[0] != '\0') { + strncat(the_request,"?",HUGE_STRING_LEN - strlen(the_request)); + strncat(the_request,args, HUGE_STRING_LEN - strlen(the_request)); + } + + strncat(the_request," ",HUGE_STRING_LEN - strlen(the_request)); + /* Replace the protocal with Internal to let people know it was an + * internal redirect. + */ + /* strncat(the_request, protocals[reqInfo->http_version], + HUGE_STRING_LEN - strlen(the_request)); */ + strncat(the_request, "Internal",HUGE_STRING_LEN - strlen(the_request)); + newInfo = continue_request(reqInfo, KEEP_AUTH | FORCE_GET); + newInfo->status = SC_DOCUMENT_FOLLOWS; + set_stat_line(newInfo); + strcpy(newInfo->url, url); + strcpy(newInfo->args, args); + construct_url(newInfo->outh_location,reqInfo->hostInfo, + reqInfo->outh_location); + process_request(newInfo); +} - chdir_file(reqInfo->filename); - - if(Pipe(p) < 0) - die(reqInfo,SC_SERVER_ERROR,"HTTPd/CGI: could not create IPC pipe"); - if(Pipe(p2) < 0) { - Close(p[0]); - Close(p[1]); - die(reqInfo,SC_SERVER_ERROR,"HTTPd/CGI: could not create IPC pipe"); - } - - if((pid = fork()) < 0) { - Close(p[0]); - Close(p[1]); - Close(p2[0]); - Close(p2[1]); - sprintf(errlog,"HTTPd/CGI: could not fork new process, errno is %d", - errno); - die(reqInfo,SC_SERVER_ERROR,errlog); - } - - nph = (strncmp(argv0,"nph-",4) ? 0 : 1); - if(!pid) { - Close(p[0]); - Close(p2[1]); - standalone = 0; - add_cgi_vars(reqInfo,path_args,&content); - - /* TAKE OUT "if (nph)" THROUGH "else {" IF SHIT HAPPENS */ - if (nph) { - if (reqInfo->connection_socket != STDOUT_FILENO) { - dup2(reqInfo->connection_socket, STDOUT_FILENO); - close(reqInfo->connection_socket); - } - } - else - dup2(p[1],STDOUT_FILENO); - Close(p[1]); - dup2(p2[0],STDIN_FILENO); - Close(p2[0]); - -/* Need to close the connection for processes which spawn processes. - * is there a CLOSE_ON_EXEC_ON_EXEC ? */ -/* close(reqInfo->connection_socket); */ -/* fclose(reqInfo->out); */ - - error_log2stderr(reqInfo->hostInfo->error_log); - /* To make the signal handling work on HPUX, according to - David-Michael Lincke (dlincke@bandon.unisg.ch) */ -#ifdef HPUX - signal(SIGCHLD, SIG_DFL); -#endif /* HPUX */ - /* Only ISINDEX scripts get decoded arguments. */ - if((!reqInfo->args[0]) || (ind(reqInfo->args,'=') >= 0)) { - execle(reqInfo->filename,argv0,NULL,reqInfo->env); - } - else { - execve(reqInfo->filename,create_argv(reqInfo,argv0), - reqInfo->env); - - } - fprintf(stderr,"HTTPd/CGI: exec of %s failed, errno is %d\n", - reqInfo->filename,errno); - exit(1); - } - else { - Close(p[1]); - Close(p2[0]); - if (content_length > 0) { - /* read content off socket and write to script */ - char szBuf[IOBUFSIZE]; - int nBytes, nTotalBytes = 0; - int nDone = 0; - - signal(SIGPIPE,SIG_IGN); - nBytes=getline(reqInfo->connection_socket, szBuf,IOBUFSIZE,2, - timeout); - nTotalBytes = nBytes; - write (p2[1], szBuf, nBytes); - while (!nDone && (nTotalBytes < content_length)) { - if((nBytes=read(reqInfo->connection_socket, - szBuf,IOBUFSIZE)) < 1) { - break; - } - write (p2[1], szBuf, nBytes); - nTotalBytes += nBytes; - } - } - Close(p2[1]); - } - - if(!nph) { - content_type[0] = '\0'; - - scan_script_header(reqInfo,p[0]); - if(location[0] == '/') { - char t[HUGE_STRING_LEN],a[HUGE_STRING_LEN],*argp; - - a[0] = '\0'; - Close(p[0]); - waitpid(pid,NULL,0); - strcpy(t,location); - if((argp = strchr(t,'?'))) { - *argp++ = '\0'; - strcpy(a,argp); - } - reqInfo->status = SC_REDIRECT_TEMP; - log_transaction(reqInfo); - reqInfo->status = SC_DOCUMENT_FOLLOWS; - init_header_vars(reqInfo); /* clear location */ - sprintf(the_request,"GET "); - strncat(the_request,t,HUGE_STRING_LEN - strlen(the_request)); - if (a[0] != '\0') { - strncat(the_request,"?",HUGE_STRING_LEN - strlen(the_request)); - strncat(the_request,a, HUGE_STRING_LEN - strlen(the_request)); - } - - strncat(the_request," ",HUGE_STRING_LEN - strlen(the_request)); - strncat(the_request, protocals[reqInfo->http_version], - HUGE_STRING_LEN - strlen(the_request)); - reqInfo = continue_request(reqInfo, KEEP_AUTH | FORCE_GET); - strcpy(reqInfo->url, t); - strcpy(reqInfo->args, a); - process_request(reqInfo); - return SC_REDIRECT_LOCAL; - } - content_length = -1; - if(!no_headers) - send_http_header(reqInfo); - if(!header_only) { - /* Send a default body of text if the script - failed to produce any, but ONLY for redirects */ - if (!send_fd(reqInfo,p[0],NULL) && location[0]) { - title_html(reqInfo,"Document moved"); - fprintf(reqInfo->out, - "This document has temporarily moved here.

%c", - location,LF); - } - } else - kill_children(reqInfo); - } - else { - reqInfo->bytes_sent = -1; - /* If there is KeepAlive going on, its handled internally to the - script. This means that we want to close the connection after - the nph- script has finished. */ - keep_alive.bKeepAlive = 0; - } - - waitpid(pid,NULL,0); +int cgi_stub(per_request *reqInfo, struct stat *finfo, int allow_options) +{ + int p[2], p2[2]; /* p = script-> server, p2 = server -> script */ + int content, nph; + char *argv0; + char errlog[100]; + FILE *fp = NULL; + + if(!can_exec(finfo)) { + log_reason(reqInfo, + "client denied by server configuration (CGI non-executable)", + reqInfo->filename); + die(reqInfo,SC_FORBIDDEN,reqInfo->url); + } + + if((argv0 = strrchr(reqInfo->filename,'/')) != NULL) + argv0++; + else argv0 = reqInfo->filename; + + chdir_file(reqInfo->filename); + + if(Pipe(p) < 0) + die(reqInfo,SC_SERVER_ERROR,"HTTPd/CGI: could not create IPC pipe"); + if(Pipe(p2) < 0) { Close(p[0]); - return SC_DOCUMENT_FOLLOWS; + Close(p[1]); + die(reqInfo,SC_SERVER_ERROR,"HTTPd/CGI: could not create IPC pipe"); + } + + if((pid = fork()) < 0) { + Close(p[0]); + Close(p[1]); + Close(p2[0]); + Close(p2[1]); + sprintf(errlog,"HTTPd/CGI: could not fork new process, errno is %d", + errno); + die(reqInfo,SC_SERVER_ERROR,errlog); + } + + nph = (strncmp(argv0,"nph-",4) ? 0 : 1); + if(!pid) { + Close(p[0]); + Close(p2[1]); + standalone = 0; + add_cgi_vars(reqInfo,&content); + + /* TAKE OUT "if (nph)" THROUGH "else {" IF SHIT HAPPENS */ + if (nph) { + if (fileno(reqInfo->out) != STDOUT_FILENO) { + dup2(fileno(reqInfo->out), STDOUT_FILENO); + close(fileno(reqInfo->out)); + } + } + else + dup2(p[1],STDOUT_FILENO); + Close(p[1]); + dup2(p2[0],STDIN_FILENO); + Close(p2[0]); + + /* Close the socket so the CGI program doesn't hold it open */ + close(csd); + + error_log2stderr(reqInfo->hostInfo->error_log); + /* To make the signal handling work on HPUX, according to + * David-Michael Lincke (dlincke@bandon.unisg.ch) + */ +#ifdef HPUX + signal(SIGCHLD, SIG_DFL); +#endif /* HPUX */ + /* Only ISINDEX scripts get decoded arguments. */ + if((!reqInfo->args[0]) || (ind(reqInfo->args,'=') >= 0)) { + execle(reqInfo->filename,argv0,NULL,reqInfo->env); + } + else { + execve(reqInfo->filename,create_argv(reqInfo,argv0), + reqInfo->env); + + } + fprintf(stderr,"HTTPd/CGI: exec of %s failed, errno is %d\n", + reqInfo->filename,errno); + exit(1); + } + else { + Close(p[1]); + Close(p2[0]); + if (reqInfo->inh_content_length > 0) { + /* read content off socket and write to script */ + char szBuf[HUGE_STRING_LEN]; + int nBytes, nTotalBytes = 0; + int nDone = 0; + + signal(SIGPIPE,SIG_IGN); + nBytes=getline(reqInfo->sb, szBuf,HUGE_STRING_LEN,G_FLUSH, timeout); + nTotalBytes = nBytes; + if (nBytes >= 0) { + if (nBytes > 0) write(p2[1], szBuf, nBytes); + while (!nDone && (nTotalBytes < reqInfo->inh_content_length)) { + nBytes=read(reqInfo->in, szBuf,HUGE_STRING_LEN); + if(nBytes < 1) { + break; + } + write(p2[1], szBuf, nBytes); + nTotalBytes += nBytes; + } + } + } + Close(p2[1]); + } + + if(!nph) { + reqInfo->outh_content_type[0] = '\0'; + reqInfo->outh_content_length = -1; + + scan_cgi_header(reqInfo,p[0]); + if(reqInfo->outh_location[0] == '/') { + Close(p[0]); + waitpid(pid,NULL,0); + internal_redirect(reqInfo); + return SC_REDIRECT_LOCAL; + } + + /* Previously, this was broken because we read the results of the CGI using + * getline, but the SSI parser used buffered stdio. + * + * ADC changed scan_cgi_header so that it uses G_SINGLE_CHAR when it + * calls getline. Yes, this means pitiful performance for CGI scripts. + */ + /* Fine, parse the output of CGI scripts. Talk about useless + * overhead. . . + */ +#ifdef CGI_SSI_HACK + if (!strcasecmp(reqInfo->outh_content_type, INCLUDES_MAGIC_TYPE) && + (allow_options & OPT_INCLUDES)) { + strcpy(reqInfo->outh_content_type, "text/html"); + if(reqInfo->http_version != P_HTTP_0_9) + send_http_header(reqInfo); + if(reqInfo->method != M_HEAD) { + rflush(reqInfo); + alarm(timeout); + add_include_vars(reqInfo,DEFAULT_TIME_FORMAT); + if (!(fp = FdOpen(p[0],"r"))) { + char errstr[MAX_STRING_LEN]; + sprintf(errstr,"HTTPd/CGI/SSI: Could not fdopen() fildes, errno is %d.",errno); + die(reqInfo,SC_SERVER_ERROR,errstr); + } + send_parsed_content(reqInfo,fp,allow_options & OPT_EXECCGI); + } + } + else +#endif /* CGI_SSI_HACK */ + { /* Not Parsed, send normally */ + if(reqInfo->http_version != P_HTTP_0_9) + send_http_header(reqInfo); + if(reqInfo->method != M_HEAD) { + /* Send a default body of text if the script + * failed to produce any, but ONLY for redirects + */ + if (!send_fd(reqInfo,p[0],kill_children_timed_out) && + reqInfo->outh_location[0]) + { + title_html(reqInfo,"Document moved"); + rprintf(reqInfo, + "This document has temporarily moved here.

%c", + reqInfo->outh_location,LF); + } + } else + kill_children(reqInfo); + } + } + else { /* Is nph- script */ + reqInfo->bytes_sent = -1; + /* If there is KeepAlive going on, its handled internally to the + script. This means that we want to close the connection after + the nph- script has finished. */ + keep_alive.bKeepAlive = 0; + } + + waitpid(pid,NULL,0); + if (fp != NULL) FClose(fp); else Close(p[0]); + return SC_DOCUMENT_FOLLOWS; } /* @@ -504,23 +601,31 @@ int cgi_stub(per_request *reqInfo, char *path_args, struct stat *finfo) */ long send_fd(per_request *reqInfo, int pd, void (*onexit)(void)) { - char buf[IOBUFSIZE]; + char *buf; register int n,w,o; int fd; + buf = newString(IOBUFSIZE,STR_TMP); + + exit_callback = onexit; signal(SIGALRM,send_fd_timed_out); signal(SIGPIPE,send_fd_timed_out); /* Flush stdio pipe, since scripts now use non buffered i/o */ - fflush(reqInfo->out); + rflush(reqInfo); fd = fileno(reqInfo->out); alarm(timeout); - n=getline(pd, buf,IOBUFSIZE,2,timeout); + if (reqInfo->cgi_buf != NULL) + n=getline(reqInfo->cgi_buf, buf,IOBUFSIZE,G_FLUSH,timeout); + else + n = 0; while (1) { o=0; while(n) { - if ((w=write(fd, buf + o,n)) < 1) { + w = write(fd, buf + o,n); + + if (w < 1) { if (errno != EINTR) break; } n-=w; @@ -538,18 +643,18 @@ long send_fd(per_request *reqInfo, int pd, void (*onexit)(void)) alarm(0); signal(SIGALRM,SIG_IGN); signal(SIGPIPE,SIG_IGN); + freeString(buf); return reqInfo->bytes_sent; } /* Called for ScriptAliased directories */ void exec_cgi_script(per_request *reqInfo) { struct stat finfo; - char path_args[HUGE_STRING_LEN]; int stub_returns; int allow; char allow_options; - get_path_info(reqInfo,path_args,&finfo); + get_path_info(reqInfo,&finfo); evaluate_access(reqInfo,&finfo,&allow,&allow_options); if(!allow) { @@ -561,11 +666,11 @@ void exec_cgi_script(per_request *reqInfo) { add_common_vars(reqInfo); reqInfo->bytes_sent = 0; - stub_returns = cgi_stub(reqInfo,path_args,&finfo); + stub_returns = cgi_stub(reqInfo,&finfo,allow_options); switch (stub_returns) { case SC_REDIRECT_TEMP: - die(reqInfo,SC_REDIRECT_TEMP,location); + die(reqInfo,SC_REDIRECT_TEMP,reqInfo->outh_location); break; case SC_REDIRECT_LOCAL: break; @@ -581,8 +686,7 @@ void exec_cgi_script(per_request *reqInfo) { evaluate_access */ -void send_cgi(per_request *reqInfo,struct stat *finfo, char *path_args, - char allow_options) +void send_cgi(per_request *reqInfo,struct stat *finfo, char allow_options) { int stub_returns; @@ -594,11 +698,11 @@ void send_cgi(per_request *reqInfo,struct stat *finfo, char *path_args, add_common_vars(reqInfo); reqInfo->bytes_sent = 0; - stub_returns = cgi_stub(reqInfo,path_args,finfo); + stub_returns = cgi_stub(reqInfo,finfo,allow_options); switch (stub_returns) { case SC_REDIRECT_TEMP: - die(reqInfo,SC_REDIRECT_TEMP,location); + die(reqInfo,SC_REDIRECT_TEMP,reqInfo->outh_location); break; case SC_REDIRECT_LOCAL: break; diff --git a/src/cgi.h b/src/cgi.h index 5768c08..4e2ffc9 100644 --- a/src/cgi.h +++ b/src/cgi.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * cgi.h,v 1.6 1995/11/28 09:01:39 blong Exp + * cgi.h,v 1.9 1996/04/05 18:54:40 blong Exp * ************************************************************************ * @@ -21,25 +21,18 @@ #ifndef _HTTP_SCRIPT_H_ #define _HTTP_SCRIPT_H_ +#include + /* function prototypes */ void exec_cgi_script(per_request *reqInfo); -int cgi_stub(per_request *reqInfo, char *path_args, struct stat *finfo); +int cgi_stub(per_request *reqInfo, struct stat *finfo, int allow_options); int add_common_vars(per_request *reqInfo); -void get_path_info(per_request *reqInfo, char *path_args, struct stat *finfo); -int scan_script_header(per_request *reqInfo, int pd); +int add_cgi_vars(per_request *reqInfo, int *content); +void get_path_info(per_request *reqInfo, struct stat *finfo); +int scan_cgi_header(per_request *reqInfo, int pd); long send_fd(per_request *reqInfo, int pd, void (*onexit)(void)); long send_nph_script(per_request *reqInfo, int pd, void (*onexit)(void)); -void send_cgi(per_request *reqInfo,struct stat *finfo, char *path_args, - char allow_options); - - -void send_fd_timed_out(int); +void send_cgi(per_request *reqInfo,struct stat *finfo, char allow_options); +void internal_redirect(per_request *reqInfo); #endif /* _HTTP_SCRIPT_H_ */ - - - - - - - diff --git a/src/config.h b/src/config.h index f3b3a9d..8abcdb4 100644 --- a/src/config.h +++ b/src/config.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * config.h,v 1.16 1995/11/10 02:01:46 blong Exp + * config.h,v 1.21 1996/03/27 20:43:51 blong Exp * ************************************************************************ * @@ -32,14 +32,14 @@ on all systems, either. It is known to work under AIX3, SunOS, OSF1, FreeBSD, and NetBSD. */ -/* #define SETPROCTITLE /* */ +/* #define SETPROCTITLE */ /* If you have SETPROCTITLE enabled, and you are a stats fanatic, and your server has a few extra clock cycles to spare, defining the following will enable an RPM (requests per minute) indicator in the proc title. */ #ifdef SETPROCTITLE -#define TACHOMETER /* */ +#define TACHOMETER */ # ifdef TACHOMETER # define MAX_TACHOMETER 30 # endif @@ -51,23 +51,45 @@ #define IMAGEMAP_SUPPORT /* */ +/* To add an additional field -- request duration -- to the access_log. + This adds the duration, in seconds that the processing of this + request took. */ + +/* #define LOG_DURATION */ + /* If you want the server to check the execute bit of an HTML file to determine if the file should be parsed, uncomment the following. Using this feature will give better performance for files which are not parsed without the necessity of using the magic mime type */ -/* #define XBITHACK /* */ +/* #define XBITHACK */ + +/* If you want the server to be able to parse the output of CGI scripts, + then define the following. This will automatically be defined for + SHTTP. This does cause a performance degradation for CGI scripts, + as it requires reading the returned CGI headers off the socket one + byte at a time. */ + +/* #define CGI_SSI_HACK */ /* If you would like to ensure that CGI scripts don't mess with the log files (except the error_log file), uncomment the following. */ -/* #define SECURE_LOGS /* */ +/* #define SECURE_LOGS */ + +/* If you would like each "static" file to be sent with a Content-MD5 + header to give clients a way of telling whether the object they + requested is the one they got - and hasn't been mangled along the way. + Of course, no clients support this yet (to my knowledge) and this will + _really_ hinder performance on really big files, but that's life. */ + +/* #define CONTENT_MD5 */ /* If you would like to specify the keyword LOCAL in your access configuration file to match local address (ie, those without embedded dots), uncomment the following. */ -/* #define LOCALHACK /* */ +/* #define LOCALHACK */ /* If you would like to use NIS services for passwords and group information, uncomment the following. NOTE: DO NOT USE THIS ON OPEN NETWORKS. The @@ -75,20 +97,20 @@ password in clear text across the network on every request which requires it. */ -/* #define NIS_SUPPORT /* */ +/* #define NIS_SUPPORT */ /* If you have a REALLY heavily loaded system, and you can't afford to have a server per request(low memory?), you can compile with this i option to make max_servers a hard limit. */ -/* #define RESOURCE_LIMIT /* */ +/* #define RESOURCE_LIMIT */ /* If your system doesn't support file descriptor passing, or if you don't want to use it, defining the following will enable HTTPd to mimic the 1.3 Forking server. This should be defined in the system specific information in portability.h, and not here. */ -/* #define NO_PASS /* */ +/* #define NO_PASS */ /* defines for new muli-child approach @@ -103,12 +125,13 @@ PROFILE to set the server up to profile the code QUANTIFY is a profiler from Pure software PURIFY is a memory checker from Pure software + DEBUG compiles in extra debugging code (debug.c, mostly) */ -/* #define PROFILE /* */ - -/* #define QUANTIFY /* */ -/* #define PURIFY /* */ +/* #define DEBUG */ +/* #define PROFILE */ +/* #define QUANTIFY */ +/* #define PURIFY */ /* SHELL_PATH defines where the shell path is */ diff --git a/src/constants.h b/src/constants.h index 0928962..29ab603 100644 --- a/src/constants.h +++ b/src/constants.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * constants.h,v 1.42 1995/11/28 09:01:40 blong Exp + * constants.h,v 1.54 1996/04/05 18:54:42 blong Exp * ************************************************************************ * @@ -46,26 +46,34 @@ #define IOBUFSIZE 8192 -#define HTTP_TIME_FORMAT "%a, %d %b %Y %T GMT" +#ifdef NEXT +# define HTTP_TIME_FORMAT "%a, %d %b %Y %X" +#else +# define HTTP_TIME_FORMAT "%a, %d %b %Y %T GMT" +#endif /* NEXT */ - -#define SERVER_VERSION "NCSA/1.5" -#define SERVER_SOURCE "NCSA/1.5.0c" +#define SERVER_VERSION "NCSA/1.5.2" +#define SERVER_SOURCE "NCSA/1.5.2" #define SERVER_PROTOCOL "HTTP/1.0" /* Response Codes from HTTP/1.0 Spec all 4 digit codes are internal only */ +#define SC_CONTINUE 100 +#define SC_SWITCHING_PROTOCOLS 101 #define SC_DOCUMENT_FOLLOWS 200 #define SC_CREATED 201 #define SC_ACCEPTED 202 -#define SC_PROV_INFO 203 +#define SC_NON_AUTH_INFO 203 #define SC_NO_CONTENT 204 +#define SC_RESET_CONTENT 205 +#define SC_PARTIAL_CONTENT 206 #define SC_MULTIPLE_CHOICES 300 #define SC_REDIRECT_PERM 301 #define SC_REDIRECT_TEMP 302 #define SC_REDIRECT_LOCAL 3020 -#define SC_METHOD 303 +#define SC_SEE_OTHER 303 #define SC_USE_LOCAL_COPY 304 +#define SC_USE_PROXY 305 #define SC_BAD_REQUEST 400 #define SC_AUTH_REQUIRED 401 #define SC_PAY_REQUIRED 402 @@ -77,6 +85,8 @@ #define SC_REQUEST_TIMEOUT 408 #define SC_CONFLICT 409 #define SC_GONE 410 +#define SC_LENGTH_REQUIRED 411 +#define SC_UNLESS_TRUE 412 #define SC_SERVER_ERROR 500 #define SC_NOT_IMPLEMENTED 501 #define SC_BAD_GATEWAY 502 @@ -85,28 +95,48 @@ #define SC_NO_MEMORY 6992 #define SC_CONF_ERROR 6993 #define SC_BAD_IMAGEMAP 6994 +#define SC_AUTH_NO_WWW_AUTH 7001 -/* Supported Methods - sorta*/ -#define METHODS 7 +/* Supported Methods - sorta */ +#define METHODS 8 #define M_GET 0 #define M_HEAD 1 #define M_POST 2 #define M_PUT 3 #define M_DELETE 4 +#define M_SECURE 5 #define M_INVALID -1 /* Unsupported Methods */ -#define M_LINK 5 -#define M_UNLINK 6 +#define M_LINK 6 +#define M_UNLINK 7 +#define M_OPTIONS 8 +#define M_PATCH 9 +#define M_COPY 10 +#define M_MOVE 11 +#define M_TRACE 12 +#define M_WRAPPED 13 /* Array containing Method names */ extern char *methods[]; +/* Supported Protocals - sorta */ +#define PROTOCALS 6 +#define P_OTHER 0 +#define P_HTTP_0_9 1 +#define P_HTTP_1_0 2 +#define P_HTTP_1_1 3 +#define P_SHTTP_1_1 4 +#define P_SHTTP_1_2 5 + +extern char *protocals[]; + /* Object types */ #define A_STD_DOCUMENT 0 #define A_REDIRECT_TEMP 1 #define A_REDIRECT_PERM 2 #define A_SCRIPT_CGI 3 +#define A_SCRIPT_FCGI 4 /* Security Options */ #define OPT_NONE 0 @@ -126,14 +156,15 @@ extern char *methods[]; #define OR_AUTHCFG 8 #define OR_INDEXES 16 #define OR_REDIRECT 32 -#define OR_ALL (OR_LIMIT | OR_OPTIONS | OR_FILEINFO | OR_AUTHCFG | OR_INDEXES | OR_REDIRECT) - -/* PEM/PGP Encodings */ +#define OR_PRIVACY_ENHANCE 64 +#define OR_ALL (OR_LIMIT | OR_OPTIONS | OR_FILEINFO | OR_AUTHCFG | OR_INDEXES | OR_REDIRECT | OR_PRIVACY_ENHANCE) /* Magic MIME Types */ #define CGI_MAGIC_TYPE "application/x-httpd-cgi" +#define FCGI_MAGIC_TYPE "application/x-httpd-fcgi" #define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html" #define IMAGEMAP_MAGIC_TYPE "text/x-imagemap" +#define BLACKOUT_MAGIC_TYPE "text/x-httpd-black" /* For directory indexing */ #define BY_PATH 0 @@ -171,6 +202,7 @@ typedef struct { #define AUTHFILETYPE_STANDARD 0 #define AUTHFILETYPE_DBM 1 #define AUTHFILETYPE_NIS 2 +#define AUTHFILETYPE_RADIUS 3 typedef struct { char d[MAX_STRING_LEN]; @@ -178,13 +210,25 @@ typedef struct { char override; int order[METHODS]; + int bSatisfy; /* 0 = All, 1 = Any */ int num_allow[METHODS]; char *allow[METHODS][MAX_SECURITY]; - int bSatisfy; /* 0 = All, 1 = Any */ + int num_auth[METHODS]; char *auth[METHODS][MAX_SECURITY]; + int num_referer_allow[METHODS]; + char *referer_allow[METHODS][MAX_SECURITY]; + + int num_referer_deny[METHODS]; + char *referer_deny[METHODS][MAX_SECURITY]; + + int num_deny[METHODS]; + char *deny[METHODS][MAX_SECURITY]; + + char *on_deny[METHODS]; + char auth_type[MAX_STRING_LEN]; char auth_name[MAX_STRING_LEN]; char auth_pwfile[MAX_STRING_LEN]; @@ -196,17 +240,8 @@ typedef struct { int auth_digestfile_type; #endif /* DIGEST_AUTH */ - int num_deny[METHODS]; - char *deny[METHODS][MAX_SECURITY]; } security_data; -#define PROTOCALS 4 -#define P_OTHER 0 -#define P_HTTP_0_9 1 -#define P_HTTP_1_0 2 -#define P_HTTP_1_1 3 - -extern char *protocals[]; typedef struct _ErrorDoc { /* int Type; */ @@ -221,6 +256,20 @@ typedef struct _ErrorDoc { #define DNS_STD 2 #define DNS_MAX 3 +/* ----------- Our socket buffering routine defines ----------------- */ +#define SB_NEW 1 +#define SB_READ 2 +#define SB_FLUSHED 3 +#define SB_ERROR 4 + +typedef struct _sock_buf { + char buffer[HUGE_STRING_LEN]; + int buf_posn; + int buf_good; + int status; + int sd; +} sock_buf; + /* ------------------- per hostname configuration -------------------- */ /* These #defines are for keeping track of which options are links to @@ -273,37 +322,66 @@ typedef struct _per_host { int num_doc_errors; ErrorDoc **doc_errors; - struct _lookup *translations; struct _per_host *next; } per_host; /* --------- Per request Data Structure ------------- */ - + +/* Request Flags */ +#define DOING_PGP 1 +#define DOING_SHTTP 2 +#define DOING_SSL 3 + typedef struct _per_request { /* Information about Contents; */ - int ownURL; - int ownDNS; int ownENV; - + int ownDNS; + int ownSB; + int RequestFlags; + /* Request Information */ int status; -/* char *status_line; */ + char *status_line; long bytes_sent; - + /* request stuff to be logged */ - char agent[HUGE_STRING_LEN]; - char referer[HUGE_STRING_LEN]; - - int http_version; int method; char url[HUGE_STRING_LEN]; - char filename[HUGE_STRING_LEN]; char args[HUGE_STRING_LEN]; -/* char *content_type; */ + char path_info[HUGE_STRING_LEN]; + int http_version; + char inh_agent[HUGE_STRING_LEN]; + char inh_referer[HUGE_STRING_LEN]; + char inh_called_hostname[MAX_STRING_LEN]; + char inh_if_mod_since[MAX_STRING_LEN]; + char inh_auth_line[HUGE_STRING_LEN]; + char inh_content_type[MAX_STRING_LEN]; + int inh_content_length; + +/* Internal Info */ + char filename[HUGE_STRING_LEN]; + +/* Outgoing information */ + char outh_location[HUGE_STRING_LEN]; + char outh_last_mod[MAX_STRING_LEN]; + char outh_www_auth[HUGE_STRING_LEN]; + char outh_content_type[MAX_STRING_LEN]; + char outh_content_encoding[MAX_STRING_LEN]; + int outh_content_length; + char *outh_cgi; + +#ifdef CONTENT_MD5 + char *outh_content_md5; +#endif /* CONTENT_MD5 */ + char auth_type[MAX_STRING_LEN]; int dirs_in_alias; - + + /* Authentication Information */ + char auth_user[MAX_STRING_LEN]; + char auth_group[MAX_STRING_LEN]; + /* authentication files */ char* auth_name; char* auth_pwfile; @@ -314,32 +392,36 @@ typedef struct _per_request { char* auth_digestfile; int auth_digestfile_type; #endif /* DIGEST_AUTH */ - + /* Domain Restriction Info */ int bNotifyDomainRestricted; int bSatisfiedDomain; + int bSatisfiedReferer; int dns_host_lookup; - + int num_env; int max_env; char **env; int *env_len; - + /* Client Information */ char *remote_host; char *remote_name; char *remote_ip; /* char *remote_logname; */ - + /* Server Information */ int connection_socket; + int in; FILE *out; + sock_buf *sb; + sock_buf *cgi_buf; per_host *hostInfo; struct in_addr address_info; - + /* Linked List of requests */ struct _per_request *next; - + } per_request; - + #endif /* _CONSTANTS_H_ */ diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..2932707 --- /dev/null +++ b/src/debug.c @@ -0,0 +1,83 @@ +/* Various debugging routines */ + +#ifdef DEBUG + +#include "config.h" +#include "portability.h" + +#include "constants.h" +#include "host_config.h" +#include "http_request.h" + + +#ifdef SOLARIS2 + +#include +#include +#include + +prpsinfo_t p; +long current_process_size() +{ + int retval; + char filename[MAX_STRING_LEN]; + int fd; + int pid; + + pid = getpid(); + + fprintf(stderr,"%d\n",pid); + + if (pid < 10) { + sprintf(filename,"/proc/0000%d",pid); + } else if (pid < 100) { + sprintf(filename,"/proc/000%d",pid); + } else if (pid < 1000) { + sprintf(filename,"/proc/00%d",pid); + } else if (pid < 10000) { + sprintf(filename,"/proc/0%d",pid); + } else { + sprintf(filename,"/proc/%d",pid); + } + + +/* fprintf(stderr,filename); */ + if (!(fd = open(filename,O_RDONLY))) { + fprintf(stderr,"Error openning file %s, errno=%d\n",filename,errno); + } + retval = ioctl(fd,PIOCPSINFO,&p); + if (retval == -1) { + fprintf(stderr,"Error in ioctl, errno = %d\n", errno); + } + close(fd); + + fprintf(stderr,"%X %X\n",&p,filename); + sprintf(filename,"%d bytes memory", p.pr_bysize); + log_error(filename,gConfiguration->error_log); + +} + +#endif /* SOLARIS2 */ + +#ifdef AIX3 + +#include + +long current_process_size(char *msg) { + char S[MAX_STRING_LEN]; + struct mallinfo mi; + int memory; + + mi = mallinfo(); + + + memory = mi.usmblks+mi.uordblks; + sprintf(S,"%25s: Space in Use: %d", msg,memory); + log_error(S,gConfiguration->error_log); + + return memory; +} + +#endif /* AIX3 */ + +#endif /* DEBUG */ diff --git a/src/digest.c b/src/digest.c index 650ef75..ba7b0e9 100644 --- a/src/digest.c +++ b/src/digest.c @@ -53,6 +53,11 @@ int get_digest(per_request *reqInfo, char *user, char *realm, char *digest, char r[MAX_STRING_LEN]; if (reqInfo->auth_digestfile_type == AUTHFILETYPE_STANDARD) { + if (reqInfo->auth_digestfile == NULL) { + sprintf (errstr, "No digest file specified for URL: %s\n", + reqInfo->url); + die(reqInfo,SC_SERVER_ERROR,errstr); + } if(!(f=FOpen(reqInfo->auth_digestfile,"r"))) { sprintf(errstr,"Could not open digest file %s", reqInfo->auth_digestfile); @@ -202,7 +207,7 @@ void Digest_Check(per_request *reqInfo, char *user, security_data* sec) opaque[0] = 0; p = q = NULL; - p = auth_line; + p = reqInfo->inh_auth_line; while (isspace(*p)) { p++; } diff --git a/src/env.c b/src/env.c index 96c3bdf..cd9c196 100644 --- a/src/env.c +++ b/src/env.c @@ -10,7 +10,7 @@ * ************************************************************************ * - *env.c,v 1.17 1995/11/28 09:01:42 blong Exp + *env.c,v 1.20 1996/04/05 18:54:44 blong Exp * ************************************************************************ * @@ -28,10 +28,15 @@ #include #include "constants.h" #include "env.h" +#include "http_request.h" #include "http_log.h" +#include "allocate.h" /* Older version, required external help. Newer version should be self - contained for easier extensibility */ + * contained for easier extensibility + * updated to use string allocation structures for speed and so it doesn't + * leak + */ /* This will change the value of an environment variable to *value if found. Returns TRUE if the replace took place, FALSE otherwise */ @@ -42,7 +47,7 @@ int replace_env_str(per_request *reqInfo, char *name, char *value) for (i = 0, len = strlen(name); reqInfo->env[i]; i++) { if (strncmp(reqInfo->env[i], name, len) == 0) { - free(reqInfo->env[i]); + freeString(reqInfo->env[i]); if (i < reqInfo->num_env) { reqInfo->env[i] = reqInfo->env[--(reqInfo->num_env)]; reqInfo->env_len[i] = reqInfo->env_len[reqInfo->num_env]; @@ -63,9 +68,9 @@ int replace_env_str(per_request *reqInfo, char *name, char *value) void free_env(per_request *reqInfo) { int x; - + for(x=0;reqInfo->env[x];x++) - free(reqInfo->env[x]); + freeString(reqInfo->env[x]); free(reqInfo->env); free(reqInfo->env_len); reqInfo->env = NULL; @@ -82,7 +87,7 @@ int merge_header(per_request *reqInfo, char *header, char *value) { register int l,lt; int len, ndx; - char **t; + char **t,*tmp; len = strlen(value); @@ -94,14 +99,20 @@ int merge_header(per_request *reqInfo, char *header, char *value) if(!strncmp(*t,header,l)) { lt = strlen(*t); if ((lt + len + 2) > reqInfo->env_len[ndx]) { - int n = reqInfo->env_len[ndx] / BIG_ENV_VAR_LEN + 1; - if(!(*t = (char *) realloc(*t,n * BIG_ENV_VAR_LEN*sizeof(char)))) - die(reqInfo, SC_NO_MEMORY,"merge_header"); - reqInfo->env_len[ndx] = n * BIG_ENV_VAR_LEN; - } - (*t)[lt++] = ','; - (*t)[lt++] = ' '; - strcpy(&((*t)[lt]),value); + tmp = reqInfo->env[ndx]; + if ((lt+len+2) > HUGE_STRING_LEN) { + reqInfo->env[ndx] = newString(lt+len+2,STR_REQ); + } else { + reqInfo->env[ndx] = newString(HUGE_STRING_LEN,STR_REQ); + } + sprintf(reqInfo->env[ndx],"%s, %s",tmp,value); + freeString(tmp); + } else { + (*t)[lt++] = ','; + (*t)[lt++] = ' '; + strcpy(&((*t)[lt]),value); + } + header[l-1] = '\0'; return 1; } } @@ -116,7 +127,14 @@ int merge_header(per_request *reqInfo, char *header, char *value) int make_env_str(per_request *reqInfo, char *name, char *value) { int n; + char tmp[HUGE_STRING_LEN]; + if (value == NULL) { + /* + * I've generally protected against this, but sanity isn't a bad thing + */ + return 0; + } if (reqInfo->env == NULL) { if (!(reqInfo->env = (char **) malloc(ENV_BEG_SIZE * sizeof(char *))) || !(reqInfo->env_len = (int*) malloc(ENV_BEG_SIZE * sizeof(int)))) @@ -131,13 +149,12 @@ int make_env_str(per_request *reqInfo, char *name, char *value) die(reqInfo,SC_NO_MEMORY,"make_env_str:realloc"); reqInfo->max_env += ENV_INC_SIZE; } - if (!(reqInfo->env[reqInfo->num_env] = - (char *) malloc(n = (strlen(name) + strlen(value) + 2)))) - die(reqInfo,SC_NO_MEMORY,"make_env_str:add"); - strcpy(reqInfo->env[reqInfo->num_env], name); - strcat(reqInfo->env[reqInfo->num_env],"="); - strcat(reqInfo->env[reqInfo->num_env],value); - reqInfo->env_len[reqInfo->num_env] = n; + strncpy(tmp, name, HUGE_STRING_LEN); + strncat(tmp,"=",HUGE_STRING_LEN - strlen(tmp)); + strncat(tmp,value,HUGE_STRING_LEN - strlen(tmp)); + reqInfo->env[reqInfo->num_env] = dupStringP(tmp,STR_REQ); + reqInfo->env_len[reqInfo->num_env] = + sizeofString(reqInfo->env[reqInfo->num_env]); reqInfo->num_env++; reqInfo->env[reqInfo->num_env] = NULL; diff --git a/src/fcgi.c b/src/fcgi.c new file mode 100644 index 0000000..be836ba --- /dev/null +++ b/src/fcgi.c @@ -0,0 +1,3529 @@ +/************************************************************************ + * FCGI Interface for the NCSA HTTPd Server + * + * Copyright (C) 1995 Open Market, Inc. + * All rights reserved. + * + ************************************************************************ + * $Id: fcgi.c,v 1.3 1996/03/25 22:21:10 blong Exp $ + ************************************************************************ + * + * fcgi.c -- interface to FCGI + * + * Trung Dung + * tdung@openmarket.com + * + * 02-29-96 blong + * modified how files are included to the standard for other server + * source files for portability + * Shouldn't core dump is there isn't a configuration directive for + * the called fcgi. + * Don't send MIME-Version header (should probably look into using + * send_http_header, like everywhere else does) + * Need to turn off keepalive. Should probably conditionally set + * it back on if a content-length header is returned, but... + * + * 03-25-96 blong + * Updating to newer version of FCGI spec as provided by Trung Dung of + * Openmarket. + * + * 06-25-96 blong + * Change select to infinite + */ + +#include "config.h" +#include "portability.h" + +#ifdef FCGI_SUPPORT + + +#include +#ifndef NO_STDLIB_H +# include +#endif /* NO_STDLIB_H */ +#ifndef NO_MALLOC_H +# ifdef NEED_SYS_MALLOC_H +# include +# else +# include +# endif /* NEED_SYS_MALLOC_H */ +#endif /* NO_MALLOC_H */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef NEED_SELECT_H +# include +#endif /* NEED_SELECT_H */ +#include +#include +#include +/*--------------------------------------------------*/ +#include "constants.h" +#include "fcgi.h" +#include "fdwrap.h" +#include "cgi.h" +#include "env.h" +#include "http_request.h" +#include "http_log.h" +#include "http_access.h" +#include "http_mime.h" +#include "http_config.h" +#include "http_auth.h" +#include "http_alias.h" +#include "util.h" +/*-----------------dependent types-----------------------*/ +typedef per_request WS_Request; +#define WS_TimeOut(x) send_fd_timed_out(x) +#define SERVER_ERROR SC_SERVER_ERROR +#define HostInfo(x) x->hostInfo +#define HostName(x) x->hostInfo->server_hostname +#define HostPort(x) port +#define OK 1 +/*------------------------------------------------------------*/ +#define FCGI_MAGIC_TYPE "application/x-httpd-fcgi" +#define DEFAULT_FCGI_LISTEN_Q 5 +#define FCGI_DEFAULT_RESTART_DELAY 5 +#define FCGI_MAX_PROCESSES 20 +#define TRUE 1 +#define FALSE 0 +#define Malloc malloc +#define ASSERT assert +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +/* + * Tcl has a nice dynamic string library, but we want to insulate ourselves + * from the library names (we might not always be linked with Tcl, and we + * may want to implement our own dynamic string library in the future.) + */ +/* + * The structure defined below is used to hold dynamic strings. The only + * field that clients should use is the string field, and they should + * never modify it. + */ + +#define TCL_DSTRING_STATIC_SIZE 200 +typedef struct Tcl_DString { + char *string; /* Points to beginning of string: either + * staticSpace below or a malloc'ed array. */ + int length; /* Number of non-NULL characters in the + * string. */ + int spaceAvl; /* Total number of bytes available for the + * string and its terminating NULL char. */ + char staticSpace[TCL_DSTRING_STATIC_SIZE]; + /* Space to use in common case where string + * is small. */ +} Tcl_DString; + +#define Tcl_DStringLength(dsPtr) ((dsPtr)->length) +#define Tcl_DStringValue(dsPtr) ((dsPtr)->string) +#define Tcl_DStringTrunc Tcl_DStringSetLength + +#define DString Tcl_DString +#define DStringAppend Tcl_DStringAppend +#define DStringTrunc Tcl_DStringSetLength +#define DStringValue Tcl_DStringValue +#define DStringFree Tcl_DStringFree +#define DStringLength Tcl_DStringLength +#define DStringInit Tcl_DStringInit +#define DStringAppendElement Tcl_DStringAppendElement +#define DStringStartSublist Tcl_DStringStartSublist +#define DStringEndSublist Tcl_DStringEndSublist +/* + * Macros to extract most-significant and least-significant bytes from + * a 16-bit value. + */ +#define MSB(x) ((x)/256) +#define LSB(x) ((x)%256) + +/*------------------------------------------------------------*/ + +#define FCGI_ERROR -1 + +/* + * Listening socket file number + */ +#define FCGI_LISTENSOCK_FILENO 0 + +/* + * Value for version component of FCGI_Header + */ +#define FCGI_VERSION_1 1 + +/* + * Fast CGI protocol version. + */ +#define FCGI_VERSION FCGI_VERSION_1 +/* + * Values for type component of FCGI_Header + */ +#define FCGI_BEGIN_REQUEST 1 +#define FCGI_ABORT_REQUEST 2 +#define FCGI_END_REQUEST 3 +#define FCGI_PARAMS 4 +#define FCGI_STDIN 5 +#define FCGI_STDOUT 6 +#define FCGI_STDERR 7 +#define FCGI_DATA 8 +#define FCGI_GET_VALUES 9 +#define FCGI_GET_VALUES_RESULT 10 +#define FCGI_UNKNOWN_TYPE 11 +#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) + +/* + * The length of the Fast CGI packet header. + */ +#define FCGI_HEADER_LEN 8 + +#define FCGI_MAX_LENGTH 0xffff + + +/* + * This structure defines the layout of FastCGI packet headers. ANSI C + * compilers will guarantee the linear layout of this structure. + */ +typedef struct { + unsigned char version; + unsigned char type; + unsigned char requestIdB1; + unsigned char requestIdB0; + unsigned char contentLengthB1; + unsigned char contentLengthB0; + unsigned char paddingLength; + unsigned char reserved; +} FCGI_Header; + + +/* + * Value for requestId component of FCGI_Header + */ +#define FCGI_NULL_REQUEST_ID 0 + + +typedef struct { + unsigned char roleB1; + unsigned char roleB0; + unsigned char flags; + unsigned char reserved[5]; +} FCGI_BeginRequestBody; + +typedef struct { + FCGI_Header header; + FCGI_BeginRequestBody body; +} FCGI_BeginRequestRecord; + +/* + * Mask for flags component of FCGI_BeginRequestBody + */ +#define FCGI_KEEP_CONN 1 + +/* + * Values for role component of FCGI_BeginRequestBody + */ +#define FCGI_RESPONDER 1 +#define FCGI_AUTHORIZER 2 +#define FCGI_FILTER 3 + + +typedef struct { + unsigned char appStatusB3; + unsigned char appStatusB2; + unsigned char appStatusB1; + unsigned char appStatusB0; + unsigned char protocolStatus; + unsigned char reserved[3]; +} FCGI_EndRequestBody; + +typedef struct { + FCGI_Header header; + FCGI_EndRequestBody body; +} FCGI_EndRequestRecord; + +/* + * Values for protocolStatus component of FCGI_EndRequestBody + */ +#define FCGI_REQUEST_COMPLETE 0 +#define FCGI_CANT_MPX_CONN 1 +#define FCGI_OVERLOADED 2 +#define FCGI_UNKNOWN_ROLE 3 + + +/* + * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records + */ +#define FCGI_MAX_CONNS "FCGI_MAX_CONNS" +#define FCGI_MAX_REQS "FCGI_MAX_REQS" +#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS" + + +typedef struct { + unsigned char type; + unsigned char reserved[7]; +} FCGI_UnknownTypeBody; + +typedef struct { + FCGI_Header header; + FCGI_UnknownTypeBody body; +} FCGI_UnknownTypeRecord; + + + +/*---------------------------------------------------------------*/ +/* + * This structure implements ring buffers, used to buffer data between + * various processes and connections in the server. + */ +typedef struct Buffer { + int size; /* size of entire buffer */ + int length; /* number of bytes in current buffer */ + char *begin; /* begining of valid data */ + char *end; /* end of valid data */ + char data[1]; /* buffer data */ +} Buffer; + +/* + * Size of the ring buffers used to read/write the FastCGI application server. + */ +#define SERVER_BUFSIZE 8192 +#define MAX_WRITE 4000 +#define BufferLength(b) ((b)->length) +#define BufferFree(b) ((b)->size - (b)->length) +#define BufferSize(b) ((b)->size) + +typedef void *OS_IpcAddress; + +/* + * OS Independent IPC Address Structure. + */ +typedef struct _OS_IpcAddr { + DString bindPath; /* Path used for the socket bind point */ + struct sockaddr *serverAddr; /* server address (for connect) */ + int addrLen; /* length of server address (for connect) */ +} OS_IpcAddr; + +/* + * The variable bindPathExtInt is used to create a Unix domain bindPath + * for server managed processes. This becomes part of the bindPath name. + * See the function "OS_CreateLocalIpcFd" for it's use. + */ +static int bindPathExtInt = 1; + +/* + * The FCGI_LISTENSOCK_FILENO is the FD that the fast CGI process gets + * handed when it starts up. This is the FD that it listens to for + * incoming connections from the Web Server. + */ +#define FCGI_LISTENSOCK_FILENO 0 + +typedef struct _FcgiProcessInfo { + pid_t pid; /* pid of associated process */ + int listenFd; /* Listener socket */ + int fcgiFd; /* fcgi IPC file descriptor for + * persistent connections. + */ + OS_IpcAddress ipcAddr; /* IPC Address of FCGI app server */ + struct _FastCgiServerInfo *serverInfoPtr; /* Pointer to class parent */ +} FcgiProcessInfo; + + +/* + * This structure holds info for each Fast CGI server that's configured + * with this Web server. + */ +typedef struct _FastCgiServerInfo { + DString execPath; /* pathname of executable */ + char **envp; /* if NOT NULL, this is the env to send + * to the fcgi app when starting a server + * managed app. + */ + int listenQueueDepth; /* size of listen queue for IPC */ + int maxProcesses; /* max allowed processes of this class */ + int restartDelay; /* number of seconds to wait between + * restarts after failure. Can be zero. + */ + int restartOnExit; /* = TRUE = restart. else terminate/free */ + int numRestarts; /* Total number of restarts */ + int numFailures; /* nun restarts due to exit failure */ + OS_IpcAddress ipcAddr; /* IPC Address of FCGI app server. This + * is the address used for all processes + */ + int listenFd; /* Listener socket */ + int processPriority; /* if locally server managed process, + * this is the priority to run the + * processes in this class at. + */ + struct _FcgiProcessInfo *procInfo; /* This is a pointer to a list of + * processes related to this class. + */ + int reqRefCount; /* number of requests active for this + * server class. The refCount also + * includes processes and connections + * to fcgi servers. + */ + int freeOnZero; /* Free structure when refCount = 0 */ + time_t procStartTime; /* Process startup time */ + int restartTimerQueued; /* = TRUE = restart timer queued */ + + int keepConnection; /* = 1 = maintain connection to app */ + int fcgiFd; /* fcgi IPC file descriptor for + * persistent connections. */ + pid_t procManager; + struct _FastCgiServerInfo *next; +} FastCgiServerInfo; + +/* + * This structure holds the Fast CGI information for a particular request. + */ +typedef struct { + int fd; /* connection to Fast CGI server */ + int gotHeader; /* TRUE if reading data bytes */ + unsigned char packetType; /* type of packet */ + int dataLen; /* length of data bytes */ + int paddingLen; /* record padding after content */ + FastCgiServerInfo *serverPtr; /* Fast CGI server info */ + Buffer *inbufPtr; /* input buffer from server */ + Buffer *outbufPtr; /* output buffer to server */ + Buffer *reqInbufPtr; /* client input buffer */ + Buffer *reqOutbufPtr; /* client output buffer */ + DString *header; + DString *errorOut; + int parseHeader; + WS_Request *reqPtr; + int readingEndRequestBody; + FCGI_EndRequestBody endRequestBody; + Buffer *erBufPtr; + int exitStatus; + int exitStatusSet; + int requestId; +} FastCgiInfo; + +int fastCgiInit = 0; +static WS_Request *hackRequest = NULL; +FastCgiServerInfo *fastCgiServers = NULL; +FastCgiInfo *globalInfoPtr = NULL; +int ht_openmax = 128; +FILE *errorLogFd = NULL; +void PrepareClientSocket(WS_Request *reqPtr, int *csdIn, int *csdOut); +void MakeExtraEnvStr(WS_Request *reqPtr); +int SpawnChild(void (*func)(void *), void *data); +void SetErrorLogFd(void *inp, int type); +int WS_Access(const char *path, int mode); + +/* + *---------------------------------------------------------------------- + * + * Tcl_DStringInit -- + * + * Initializes a dynamic string, discarding any previous contents + * of the string (Tcl_DStringFree should have been called already + * if the dynamic string was previously in use). + * Input: dsptr + * Pointer to structure for dynamic string. + * + * Results: + * None. + * + * Side effects: + * The dynamic string is initialized to be empty. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DStringInit(Tcl_DString *dsPtr) + +{ + dsPtr->string = dsPtr->staticSpace; + dsPtr->length = 0; + dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; + dsPtr->staticSpace[0] = 0; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DStringAppend -- + * + * Append more characters to the current value of a dynamic string. + * Input + * Tcl_DString *dsPtr; Structure describing dynamic + * string. + * char *string; String to append. If length is + * -1 then this must be + * null-terminated. + * int length; Number of characters from string + * to append. If < 0, then append all + * of string, up to null at end. + * + * + * Results: + * The return value is a pointer to the dynamic string's new value. + * + * Side effects: + * Length bytes from string (or all of string if length is less + * than zero) are added to the current value of the string. Memory + * gets reallocated if needed to accomodate the string's new size. + * + *---------------------------------------------------------------------- + */ + +char * +Tcl_DStringAppend(Tcl_DString *dsPtr, char *string, int length) +{ + int newSize; + char *newString, *dst, *end; + + if (length < 0) { + length = strlen(string); + } + newSize = length + dsPtr->length; + + /* + * Allocate a larger buffer for the string if the current one isn't + * large enough. Allocate extra space in the new buffer so that there + * will be room to grow before we have to allocate again. + */ + + if (newSize >= dsPtr->spaceAvl) { + dsPtr->spaceAvl = newSize*2; + newString = (char *) Malloc((unsigned) dsPtr->spaceAvl); + memcpy((void *)newString, (void *) dsPtr->string, + (size_t) dsPtr->length); + if (dsPtr->string != dsPtr->staticSpace) { + free(dsPtr->string); + } + dsPtr->string = newString; + } + + /* + * Copy the new string into the buffer at the end of the old + * one. + */ + + for (dst = dsPtr->string + dsPtr->length, end = string+length; + string < end; string++, dst++) { + *dst = *string; + } + *dst = 0; + dsPtr->length += length; + return dsPtr->string; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DStringSetLength -- + * + * Change the length of a dynamic string. This can cause the + * string to either grow or shrink, depending on the value of + * length. + * Input: + * Tcl_DString *dsPtr; Structure describing dynamic string + * int length; New length for dynamic string. + * + * Results: + * None. + * + * Side effects: + * The length of dsPtr is changed to length and a null byte is + * stored at that position in the string. If length is larger + * than the space allocated for dsPtr, then a panic occurs. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DStringSetLength(Tcl_DString *dsPtr, int length) +{ + if (length < 0) { + length = 0; + } + if (length >= dsPtr->spaceAvl) { + char *newString; + + dsPtr->spaceAvl = length+1; + newString = (char *) Malloc((unsigned) dsPtr->spaceAvl); + + /* + * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string + * to a larger buffer, since there may be embedded NULLs in the + * string in some cases. + */ + + memcpy((void *) newString, (void *) dsPtr->string, + (size_t) dsPtr->length); + if (dsPtr->string != dsPtr->staticSpace) { + free(dsPtr->string); + } + dsPtr->string = newString; + } + dsPtr->length = length; + dsPtr->string[length] = 0; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_StringMatch -- + * + * See if a particular string matches a particular pattern. + * + * Results: + * The return value is 1 if string matches pattern, and + * 0 otherwise. The matching operation permits the following + * special characters in the pattern: *?\[] (see the manual + * entry for details on what these mean). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_StringMatch(string, pattern) + register char *string; /* String. */ + register char *pattern; /* Pattern, which may contain + * special characters. */ +{ + char c2; + + while (1) { + /* See if we're at the end of both the pattern and the string. + * If so, we succeeded. If we're at the end of the pattern + * but not at the end of the string, we failed. + */ + + if (*pattern == 0) { + if (*string == 0) { + return 1; + } else { + return 0; + } + } + if ((*string == 0) && (*pattern != '*')) { + return 0; + } + + /* Check for a "*" as the next pattern character. It matches + * any substring. We handle this by calling ourselves + * recursively for each postfix of string, until either we + * match or we reach the end of the string. + */ + + if (*pattern == '*') { + pattern += 1; + if (*pattern == 0) { + return 1; + } + while (1) { + if (Tcl_StringMatch(string, pattern)) { + return 1; + } + if (*string == 0) { + return 0; + } + string += 1; + } + } + + /* Check for a "?" as the next pattern character. It matches + * any single character. + */ + + if (*pattern == '?') { + goto thisCharOK; + } + + /* Check for a "[" as the next pattern character. It is followed + * by a list of characters that are acceptable, or by a range + * (two characters separated by "-"). + */ + + if (*pattern == '[') { + pattern += 1; + while (1) { + if ((*pattern == ']') || (*pattern == 0)) { + return 0; + } + if (*pattern == *string) { + break; + } + if (pattern[1] == '-') { + c2 = pattern[2]; + if (c2 == 0) { + return 0; + } + if ((*pattern <= *string) && (c2 >= *string)) { + break; + } + if ((*pattern >= *string) && (c2 <= *string)) { + break; + } + pattern += 2; + } + pattern += 1; + } + while (*pattern != ']') { + if (*pattern == 0) { + pattern--; + break; + } + pattern += 1; + } + goto thisCharOK; + } + + /* If the next pattern character is '/', just strip off the '/' + * so we do exact matching on the character that follows. + */ + + if (*pattern == '\\') { + pattern += 1; + if (*pattern == 0) { + return 0; + } + } + + /* There's no special character. Just make sure that the next + * characters of each string match. + */ + + if (*pattern != *string) { + return 0; + } + + thisCharOK: pattern += 1; + string += 1; + } +} + + +/* + *---------------------------------------------------------------------- + * + * Tcl_DStringFree -- + * + * Frees up any memory allocated for the dynamic string and + * reinitializes the string to an empty state. + * Input: + * Tcl_DString *dsPtr; Structure describing dynamic string + * + * Results: + * None. + * + * Side effects: + * The previous contents of the dynamic string are lost, and + * the new value is an empty string. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DStringFree(Tcl_DString *dsPtr) +{ + if (dsPtr->string != dsPtr->staticSpace) { + free(dsPtr->string); + } + dsPtr->string = dsPtr->staticSpace; + dsPtr->length = 0; + dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; + dsPtr->staticSpace[0] = 0; +} +/*------------------------------------------------------------*/ + +/* + *---------------------------------------------------------------------- + * + * OS_InitIpcAddr -- + * + * Initialize the OS specific IPC address used for FCGI I/O. + * + * Results: + * IPC Address is initialized. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +OS_IpcAddress OS_InitIpcAddr(void) +{ + OS_IpcAddr *ipcAddrPtr = (OS_IpcAddr *)Malloc(sizeof(OS_IpcAddr)); + DStringInit(&ipcAddrPtr->bindPath); + ipcAddrPtr->serverAddr = NULL; + ipcAddrPtr->addrLen = 0; + return (OS_IpcAddress)ipcAddrPtr; +} + +int OS_Bind(unsigned int sock, struct sockaddr *addr, int namelen) +{ + return(bind(sock, addr, namelen)); +} + +int OS_Listen(unsigned int sock, int backlog) +{ + return(listen(sock, backlog)); +} + +int OS_Socket(int addr_family, int type, int protocol) +{ + return (socket(addr_family, type, protocol)); +} + +int OS_Close(int fd) +{ + return close(fd); +} + +int OS_Dup2(int oldd,int newd) +{ + int fd; + + fd = dup2(oldd, newd); + return fd; +} + + +int OS_Fcntl(int fd, int cmd, int arg) +{ + return(fcntl(fd, cmd, arg)); +} + +int OS_Read(int fd, void *buf, size_t numBytes) +{ + int result; + + while (1) { + result = read(fd, buf, (size_t) numBytes); + if ((result != -1) || (errno != EINTR)) { + return result; + } + } +} + +int OS_Write(int fd, void *buf, size_t numBytes) +{ + int result; + + while (1) { + result = write(fd, buf, (size_t) numBytes); + if ((result != -1) || (errno != EINTR)) { + return result; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * BufferCheck -- + * + * Checks buffer for consistency with a set of assertions. + * + * If assert() is a no-op, this routine should be optimized away + * in most C compilers. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void BufferCheck(Buffer *bufPtr) +{ + ASSERT(bufPtr->size > 0); + ASSERT(bufPtr->length >= 0); + ASSERT(bufPtr->length <= bufPtr->size); + + ASSERT(bufPtr->begin >= bufPtr->data); + ASSERT(bufPtr->begin < bufPtr->data + bufPtr->size); + ASSERT(bufPtr->end >= bufPtr->data); + ASSERT(bufPtr->end < bufPtr->data + bufPtr->size); + + ASSERT(((bufPtr->end - bufPtr->begin + bufPtr->size) % bufPtr->size) + == (bufPtr->length % bufPtr->size)); +} + +/* + *---------------------------------------------------------------------- + * + * BufferReset -- + * + * Reset a buffer, losing any data that's in it. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void BufferReset(Buffer *bufPtr) +{ + bufPtr->length = 0; + bufPtr->begin = bufPtr->end = bufPtr->data; +} + +/* + *---------------------------------------------------------------------- + * + * BufferCreate -- + * + * Allocate an intialize a new buffer of the specified size. + * + * Results: + * Pointer to newly allocated buffer. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +Buffer *BufferCreate(int size) +{ + Buffer *bufPtr; + + bufPtr = (Buffer *)Malloc(sizeof(Buffer) + size); + bufPtr->size = size; + BufferReset(bufPtr); + return bufPtr; +} + +/* + *---------------------------------------------------------------------- + * + * BufferDelete -- + * + * Delete a buffer, freeing up any associated storage. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void BufferDelete(Buffer *bufPtr) +{ + BufferCheck(bufPtr); + free(bufPtr); +} + +/* + *---------------------------------------------------------------------- + * + * BufferRead -- + * + * Read bytes from an open file descriptor into a buffer. + * + * Results: + * Returns number of bytes read. + * + * Side effects: + * Data stored in buffer. + * + *---------------------------------------------------------------------- + */ +int BufferRead(Buffer *bufPtr, int fd) +{ + int len; + + BufferCheck(bufPtr); + len = min(bufPtr->size - bufPtr->length, + bufPtr->data + bufPtr->size - bufPtr->end); + + if (len > 0) { + signal(SIGPIPE,SIG_IGN); + len = OS_Read(fd, bufPtr->end, len); + if(len > 0) { + bufPtr->end += len; + if(bufPtr->end >= (bufPtr->data + bufPtr->size)) + bufPtr->end -= bufPtr->size; + bufPtr->length += len; + } + } + return len; +} + +void FcgiCleanUp(FastCgiInfo *infoPtr) +{ + char *p = DStringValue(infoPtr->errorOut); + if (p) + fprintf(errorLogFd, "%s", p); + BufferDelete(infoPtr->inbufPtr); + BufferDelete(infoPtr->outbufPtr); + BufferDelete(infoPtr->reqInbufPtr); + BufferDelete(infoPtr->reqOutbufPtr); + BufferDelete(infoPtr->erBufPtr); + DStringFree(infoPtr->header); + DStringFree(infoPtr->errorOut); + OS_Close(infoPtr->fd); + free(infoPtr); + fflush(errorLogFd); +} + +void fcgi_timed_out(int sigcode) +{ + FcgiCleanUp(globalInfoPtr); + WS_TimeOut(sigcode); +} + +/* + *---------------------------------------------------------------------- + * + * BufferWrite -- + * + * Write any bytes from the buffer to a file descriptor open for + * writing. + * + * Results: + * Returns number of bytes written. + * + * Side effects: + * Data "removed" from buffer. + * + *---------------------------------------------------------------------- + */ +int BufferWrite(Buffer *bufPtr, int fd) +{ + int len; + + ASSERT(fd >= 0); + signal(SIGALRM,fcgi_timed_out); + signal(SIGPIPE,fcgi_timed_out); + alarm(timeout); + BufferCheck(bufPtr); + len = min(bufPtr->length, bufPtr->data + bufPtr->size - bufPtr->begin); + + /* should the same fix be made in core server? */ + if (len > MAX_WRITE) + len = MAX_WRITE; + if(len > 0) { + len = OS_Write(fd, bufPtr->begin, len); + if(len > 0) { + bufPtr->begin += len; + if(bufPtr->begin >= (bufPtr->data + bufPtr->size)) + bufPtr->begin -= bufPtr->size; + bufPtr->length -= len; + } + } + alarm(0); + signal(SIGALRM,SIG_IGN); + signal(SIGPIPE,SIG_IGN); + return len; +} + +/* + *---------------------------------------------------------------------- + * + * BufferToss -- + * + * Throw away the specified number of bytes from a buffer, as if + * they had been written out. + * + * Results: + * None. + * + * Side effects: + * Data "removed" from the buffer. + * + *---------------------------------------------------------------------- + */ +void BufferToss(Buffer *bufPtr, int count) +{ + BufferCheck(bufPtr); + ASSERT(count >= 0 && count <= bufPtr->length); + + bufPtr->length -= count; + bufPtr->begin += count; + if(bufPtr->begin >= bufPtr->data + bufPtr->size) + bufPtr->begin -= bufPtr->size; +} + +/* + *---------------------------------------------------------------------- + * + * BufferExpand -- + * + * Expands the buffer by the specified number of bytes. Assumes that + * the caller has added the data to the buffer. This is typically + * used after a BufferAsyncRead() call completes, to update the buffer + * size with the number of bytes read. + * + * Results: + * None. + * + * Side effects: + * Data "added" to the buffer. + * + *---------------------------------------------------------------------- + */ +void BufferExpand(Buffer *bufPtr, int count) +{ + BufferCheck(bufPtr); + ASSERT(count >= 0 && count <= BufferFree(bufPtr)); + + bufPtr->length += count; + bufPtr->end += count; + if(bufPtr->end >= bufPtr->data + bufPtr->size) + bufPtr->end -= bufPtr->size; + + BufferCheck(bufPtr); +} + +/* + *---------------------------------------------------------------------- + * + * BufferAddData -- + * + * Adds data to a buffer, returning the number of bytes added. + * + * Results: + * Number of bytes added to the buffer. + * + * Side effects: + * Characters added to the buffer. + * + *---------------------------------------------------------------------- + */ +int BufferAddData(Buffer *bufPtr, char *data, int datalen) +{ + char *end; + int copied = 0; /* Number of bytes actually copied. */ + int canCopy; /* Number of bytes to copy in a given op. */ + + ASSERT(data != NULL); + if(datalen == 0) + return 0; + + ASSERT(datalen > 0); + + BufferCheck(bufPtr); + end = bufPtr->data + bufPtr->size; + + /* + * Copy the first part of the data: from here to the end of the + * buffer, or the end of the data, whichever comes first. + */ + datalen = min(BufferFree(bufPtr), datalen); + canCopy = min(datalen, end - bufPtr->end); + memcpy(bufPtr->end, data, canCopy); + bufPtr->length += canCopy; + bufPtr->end += canCopy; + copied += canCopy; + if (bufPtr->end >= end) + bufPtr->end = bufPtr->data; + datalen -= canCopy; + + /* + * If there's more to go, copy the second part starting from the + * beginning of the buffer. + */ + if (datalen > 0) { + data += canCopy; + memcpy(bufPtr->end, data, datalen); + bufPtr->length += datalen; + bufPtr->end += datalen; + copied += datalen; + } + return(copied); +} + +/* + *---------------------------------------------------------------------- + * + * BufferAdd -- + * + * Adds a string into a buffer, returning the number of bytes added. + * + * Results: + * Number of bytes added to the buffer. + * + * Side effects: + * Characters added to the buffer. + * + *---------------------------------------------------------------------- + */ +int BufferAdd(Buffer *bufPtr, char *str) +{ + return BufferAddData(bufPtr, str, strlen(str)); +} + +/* + *---------------------------------------------------------------------- + * + * BufferGetc -- + * + * Gets a character from a buffer. The buffer must be non-emtpy. + * + * Results: + * The character. + * + * Side effects: + * One character removed from the buffer. + * + *---------------------------------------------------------------------- + */ +char BufferGetc(Buffer *bufPtr) +{ + char c; + + BufferCheck (bufPtr); + ASSERT(BufferLength(bufPtr) != 0); + c = *bufPtr->begin++; + bufPtr->length--; + if (bufPtr->begin == bufPtr->data + bufPtr->size) { + bufPtr->begin = bufPtr->data; + } + return c; +} + +/* + *---------------------------------------------------------------------- + * + * BufferCopyTillStr -- + * + * This function moves bytes from an input buffer to an output buffer + * until either an entire match is found in the input buffer, or + * the length of the input buffer is smaller than the length of + * the match string. + * + * When the match string is found, it is "consumed" and not copied + * to the output buffer. The input buffer is left at the next + * valid character after the match string. + * + * The partially parsed state (stored as an index into the match + * string) is stored in *ppstate. + * + * Results: + * TRUE if complete match string found, FALSE otherwise. + * + * Side effects: + * Bytes moved from input to output buffer. + * + *---------------------------------------------------------------------- + */ +int BufferCopyTillStr(Buffer * in_buf, Buffer * out_buf, char *match_str, + int *ppstate) +{ + int len; + int match_str_len; + char c; + int bytes_in, bytes_out; /* keep track of the buffer's space locally */ + int l_ppstate; /* local partial parse state */ + + BufferCheck(in_buf); + BufferCheck(out_buf); + + match_str_len = strlen(match_str); + + l_ppstate = *ppstate; + bytes_out = BufferFree(out_buf) - match_str_len + 1; + bytes_in = BufferLength(in_buf); + + while (bytes_in > 0 && bytes_out > 0) { + c = BufferGetc(in_buf); + bytes_in--; + if (c == match_str[l_ppstate]) { + l_ppstate++; + if (match_str[l_ppstate] == '\0') { + *ppstate = 0; + return TRUE; + } + } else { + len = BufferAddData(out_buf, match_str, l_ppstate); + ASSERT(len == l_ppstate); + bytes_out -= l_ppstate; + if (c == match_str[0]) { + l_ppstate = 1; + } else { + len = BufferAddData(out_buf, &c, 1); + ASSERT(len == 1); + bytes_out--; + l_ppstate = 0; + } + } + } + *ppstate = l_ppstate; + return FALSE; +} + +/* + *---------------------------------------------------------------------- + * + * BufferGetData -- + * + * Gets data from a buffer, returning the number of bytes copied. + * + * Results: + * Number of bytes copied from the buffer. + * + * Side effects: + * Updates the buffer pointer. + * + *---------------------------------------------------------------------- + */ +int BufferGetData(Buffer *bufPtr, char *data, int datalen) +{ + char *end; + int copied = 0; /* Number of bytes actually copied. */ + int canCopy; /* Number of bytes to copy in a given op. */ + + ASSERT(data != NULL); + ASSERT(datalen > 0); + BufferCheck(bufPtr); + end = bufPtr->data + bufPtr->size; + + /* + * Copy the first part out of the buffer: from here to the end + * of the buffer, or all of the requested data. + */ + canCopy = min(bufPtr->length, datalen); + canCopy = min(canCopy, end - bufPtr->begin); + memcpy(data, bufPtr->begin, canCopy); + bufPtr->length -= canCopy; + bufPtr->begin += canCopy; + copied += canCopy; + if (bufPtr->begin >= end) + bufPtr->begin = bufPtr->data; + + /* + * If there's more to go, copy the second part starting from the + * beginning of the buffer. + */ + if (copied < datalen && bufPtr->length > 0) { + data += copied; + canCopy = min(bufPtr->length, datalen - copied); + memcpy(data, bufPtr->begin, canCopy); + bufPtr->length -= canCopy; + bufPtr->begin += canCopy; + copied += canCopy; + } + BufferCheck(bufPtr); + return(copied); +} + +/* + *---------------------------------------------------------------------- + * + * BufferMove -- + * + * Move the specified number of bytes from one buffer to another. + * There must be at least 'len' bytes available in the source buffer, + * and space for 'len' bytes in the destination buffer. + * + * Results: + * None. + * + * Side effects: + * Bytes moved. + * + *---------------------------------------------------------------------- + */ +void BufferMove(Buffer *toPtr, Buffer *fromPtr, int len) +{ + int fromLen, toLen, toMove; + + ASSERT(len > 0); + ASSERT(BufferLength(fromPtr) >= len); + ASSERT(BufferFree(toPtr) >= len); + + BufferCheck(toPtr); + BufferCheck(fromPtr); + + for(;;) { + fromLen = min(fromPtr->length, + fromPtr->data + fromPtr->size - fromPtr->begin); + + toLen = min(toPtr->size - toPtr->length, + toPtr->data + toPtr->size - toPtr->end); + + toMove = min(fromLen, toLen); + toMove = min(toMove, len); + + ASSERT(toMove >= 0); + if(toMove == 0) + return; + + memcpy(toPtr->end, fromPtr->begin, toMove); + BufferToss(fromPtr, toMove); + BufferExpand(toPtr, toMove); + len -= toMove; + } +} + +/* + *---------------------------------------------------------------------- + * + * BufferDStringAppend -- + * + * Append the specified number of bytes from a buffer onto the + * end of a DString. + * + * Results: + * None. + * + * Side effects: + * Bytes moved. + * + *---------------------------------------------------------------------- + */ +void BufferDStringAppend(DString *strPtr, Buffer *bufPtr, int len) +{ + int fromLen; + + BufferCheck(bufPtr); + ASSERT(len > 0); + ASSERT(len <= BufferLength(bufPtr)); + + while(len > 0) { + fromLen = min(len, bufPtr->data + bufPtr->size - bufPtr->begin); + + ASSERT(fromLen > 0); + DStringAppend(strPtr, bufPtr->begin, fromLen); + BufferToss(bufPtr, fromLen); + len -= fromLen; + } +} + +/* + *---------------------------------------------------------------------- + * + * OS_BuildSockAddrUn -- + * + * Using the pathname bindPath, fill in the sockaddr_un structure + * *servAddrPtr and the length of this structure *servAddrLen. + * + * The format of the sockaddr_un structure changed incompatibly in + * 4.3BSD Reno. + * + * Results: + * 0 for normal return, -1 for failure (bindPath too long). + * + *---------------------------------------------------------------------- + */ + +static int OS_BuildSockAddrUn(char *bindPath, + struct sockaddr_un *servAddrPtr, + int *servAddrLen) +{ + int bindPathLen = strlen(bindPath); + +#ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI */ + if(bindPathLen >= sizeof(servAddrPtr->sun_path)) + return -1; +#else /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */ + if(bindPathLen > sizeof(servAddrPtr->sun_path)) + return -1; +#endif + memset((char *) servAddrPtr, 0, sizeof(*servAddrPtr)); + servAddrPtr->sun_family = AF_UNIX; + memcpy(servAddrPtr->sun_path, bindPath, bindPathLen); +#ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI */ + *servAddrLen = sizeof(servAddrPtr->sun_len) + + sizeof(servAddrPtr->sun_family) + + bindPathLen + 1; + servAddrPtr->sun_len = *servAddrLen; +#else /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */ + *servAddrLen = sizeof(servAddrPtr->sun_family) + bindPathLen; +#endif + return 0; +} + +int Die(FastCgiInfo *infoPtr, int err_code, char *msg) +{ + FcgiCleanUp(infoPtr); + die(infoPtr->reqPtr, err_code, msg); + return SERVER_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * ConnectionError -- + * + * This routine gets called when there's an error in connecting to + * a FastCGI server. It returns an error message to the client + * and shuts down the request. + * + * Results: + * None. + * + * Side effects: + * An error message is returned, and the request is completed. + * + *---------------------------------------------------------------------- + */ +static void ConnectionError(FastCgiInfo *infoPtr, int errorCode) +{ + char error_msg[MAX_STRING_LEN]; + char *msg = strerror(errorCode); + if (msg == NULL) + msg = ""; + sprintf(error_msg, "HTTPd: error connecting to fastcgi server - filename: %s - error: %s ", + infoPtr->reqPtr->filename, msg); + Die(infoPtr,SERVER_ERROR,error_msg); +} + +/*------------------------------------------------------------*/ + +FastCgiServerInfo *FastCgiServerInfoLookup(char *suffix) +{ + FastCgiServerInfo *info; + info = fastCgiServers; + while (info) { + const char *ePath = DStringValue(&info->execPath); + if (ePath && (strcmp(ePath, suffix) == 0)) + return info; + info = info->next; + } + return NULL; +} +/*------------------------------------------------------------*/ +/* + *---------------------------------------------------------------------- + * + * SendPacketHeader -- + * + * Assembles and sends the FastCGI packet header for a given + * request. It is the caller's responsibility to make sure that + * there's enough space in the buffer, and that the data bytes + * (specified by 'len') are queued immediately following this + * header. + * + * Results: + * None. + * + * Side effects: + * Packet header queued. + * + *---------------------------------------------------------------------- + */ +static void SendPacketHeader(FastCgiInfo *infoPtr, int type, int len) +{ + FCGI_Header header; + + ASSERT(type > 0 && type <= FCGI_MAXTYPE); + ASSERT(len >= 0); + ASSERT(BufferFree(infoPtr->outbufPtr) > sizeof(FCGI_Header)); + + /* + * Assemble and queue the packet header. + */ + header.version = FCGI_VERSION; + header.type = type; + header.requestIdB1 = (infoPtr->requestId >> 8) & 0xff; + header.requestIdB0 = (infoPtr->requestId) & 0xff; + header.contentLengthB1 = MSB(len); + header.contentLengthB0 = LSB(len); + header.paddingLength = 0; + header.reserved = 0; + BufferAddData(infoPtr->outbufPtr, (char *) &header, sizeof(FCGI_Header)); +} + +/* + *---------------------------------------------------------------------- + * + * MakeBeginRequestBody -- + * + * Constructs an FCGI_BeginRequestBody record. + * + *---------------------------------------------------------------------- + */ +static void MakeBeginRequestBody(int role, + int keepConnection, + FCGI_BeginRequestBody *body) +{ + ASSERT((role >> 16) == 0); + body->roleB1 = (role >> 8) & 0xff; + body->roleB0 = (role ) & 0xff; + body->flags = (keepConnection) ? FCGI_KEEP_CONN : 0; + memset(body->reserved, 0, sizeof(body->reserved)); +} + +/* + *---------------------------------------------------------------------- + * + * SendBeginRequest - + * + * + * Results: + * None. + * + * Side effects: + * Begin request queued. + * + *---------------------------------------------------------------------- + */ +static void SendBeginRequest(FastCgiInfo *infoPtr) +{ + FCGI_BeginRequestBody body; + unsigned int bodySize; + + /* + * We should be the first ones to use this buffer. + */ + ASSERT(BufferLength(infoPtr->outbufPtr) == 0); + + bodySize = sizeof(FCGI_BeginRequestBody); + MakeBeginRequestBody(FCGI_RESPONDER, TRUE, &body); + SendPacketHeader(infoPtr, FCGI_BEGIN_REQUEST, bodySize); + BufferAddData(infoPtr->outbufPtr, (char *) &body, bodySize); +} + +/* + *---------------------------------------------------------------------- + * + * FCGIUtil_BuildNameValueHeader -- + * + * Builds a name-value pair header from the name length + * and the value length. Stores the header into *headerBuffPtr, + * and stores the length of the header into *headerLenPtr. + * + * Side effects: + * Stores header's length (at most 8) into *headerLenPtr, + * and stores the header itself into + * headerBuffPtr[0 .. *headerLenPtr - 1]. + * + *---------------------------------------------------------------------- + */ +static void FCGIUtil_BuildNameValueHeader( + int nameLen, + int valueLen, + unsigned char *headerBuffPtr, + int *headerLenPtr) { + unsigned char *startHeaderBuffPtr = headerBuffPtr; + + ASSERT(nameLen >= 0); + if(nameLen < 0x80) { + *headerBuffPtr++ = nameLen; + } else { + *headerBuffPtr++ = (nameLen >> 24) | 0x80; + *headerBuffPtr++ = (nameLen >> 16); + *headerBuffPtr++ = (nameLen >> 8); + *headerBuffPtr++ = nameLen; + } + ASSERT(valueLen >= 0); + if(valueLen < 0x80) { + *headerBuffPtr++ = valueLen; + } else { + *headerBuffPtr++ = (valueLen >> 24) | 0x80; + *headerBuffPtr++ = (valueLen >> 16); + *headerBuffPtr++ = (valueLen >> 8); + *headerBuffPtr++ = valueLen; + } + *headerLenPtr = headerBuffPtr - startHeaderBuffPtr; +} + +/* + *---------------------------------------------------------------------- + * + * SendEnvironment -- + * + * Queue the environment variables to a FastCGI server. Assumes that + * there's enough space in the output buffer to hold the variables. + * + * Results: + * None. + * + * Side effects: + * Environment variables queued for delivery. + * + *---------------------------------------------------------------------- + */ +static void SendEnvironment(WS_Request *reqPtr, FastCgiInfo *infoPtr) +{ + int headerLen, nameLen, valueLen; + char *equalPtr; + unsigned char headerBuff[8]; + int content, i; + + + /* + * Send each environment item to the FastCGI server as a + * FastCGI format name-value pair. + * + * XXX: this code will break with the environment format used on NT. + */ + + MakeExtraEnvStr(reqPtr); + add_common_vars(reqPtr); + add_cgi_vars(reqPtr, &content); + i = reqPtr->num_env - 1; + while(i >= 0) { + equalPtr = strchr(reqPtr->env[i], '='); + ASSERT(equalPtr != NULL); + nameLen = equalPtr - reqPtr->env[i]; + valueLen = strlen(equalPtr + 1); + FCGIUtil_BuildNameValueHeader( + nameLen, + valueLen, + &headerBuff[0], + &headerLen); + SendPacketHeader( + infoPtr, + FCGI_PARAMS, + headerLen + nameLen + valueLen); + BufferAddData(infoPtr->outbufPtr, (char *) &headerBuff[0], headerLen); + BufferAddData(infoPtr->outbufPtr, reqPtr->env[i], nameLen); + BufferAddData(infoPtr->outbufPtr, equalPtr + 1, valueLen); + i--; + } + SendPacketHeader(infoPtr, FCGI_PARAMS, 0); +} + + +/* + *---------------------------------------------------------------------- + * + * ClientToCgiBuffer -- + * + * Move bytes from the client to the FastCGI server as standard + * input packets. + * + * Results: + * None. + * + * Side effects: + * Bytes moved from client input to FastCGI server output. + * + *---------------------------------------------------------------------- + */ +static void ClientToCgiBuffer(FastCgiInfo *infoPtr) +{ + int maxlen; + int in_len, out_free; + + /* + * If there's no input data, or there's not enough space in the output + * buffer for any data bytes, then there's nothing we can do. + */ + in_len = BufferLength(infoPtr->reqInbufPtr); + out_free = BufferFree(infoPtr->outbufPtr) - sizeof(FCGI_Header); + maxlen = min (in_len, out_free); + + if(maxlen > 0) { + SendPacketHeader(infoPtr, FCGI_STDIN, maxlen); + BufferMove(infoPtr->outbufPtr, infoPtr->reqInbufPtr, maxlen); + } +} + +/* + *---------------------------------------------------------------------- + * + * CgiToClientBuffer -- + * + * Process packets from FastCGI server. + * + * Results: + * None. + * + * Side effects: + * Many. + * + *---------------------------------------------------------------------- + */ +static void CgiToClientBuffer(FastCgiInfo *infoPtr) +{ + FCGI_Header header; + int len; + + while(BufferLength(infoPtr->inbufPtr) > 0) { + + /* + * State #1: looking for the next complete packet header. + */ + if(infoPtr->gotHeader == FALSE) { + if(BufferLength(infoPtr->inbufPtr) < sizeof(FCGI_Header)) + return; + + BufferGetData(infoPtr->inbufPtr, (char *) &header, + sizeof(FCGI_Header)); + + /* + * XXX: Better handling of packets with other version numbers + * and other packet problems. + */ + ASSERT(header.version == FCGI_VERSION); + ASSERT(header.type <= FCGI_MAXTYPE); + + infoPtr->packetType = header.type; + infoPtr->dataLen = (header.contentLengthB1 << 8) + header.contentLengthB0; + infoPtr->gotHeader = TRUE; + infoPtr->paddingLen = header.paddingLength; + } + + /* + * State #2: got a header, and processing packet bytes. + */ + len = min(infoPtr->dataLen, BufferLength(infoPtr->inbufPtr)); + ASSERT(len >= 0); + switch(infoPtr->packetType) { + + case FCGI_STDOUT: + if(len > 0) { + if(infoPtr->parseHeader) + BufferDStringAppend(infoPtr->header, + infoPtr->inbufPtr, len); + else { + len = min(BufferFree(infoPtr->reqOutbufPtr), len); + if (len > 0) + BufferMove(infoPtr->reqOutbufPtr, infoPtr->inbufPtr, len); + else + return; + } + infoPtr->dataLen -= len; + } + break; + + case FCGI_STDERR: + if(len > 0) { + BufferDStringAppend(infoPtr->errorOut, infoPtr->inbufPtr, len); + infoPtr->dataLen -= len; + } + break; + + case FCGI_END_REQUEST: + if(!infoPtr->readingEndRequestBody) { + if(infoPtr->dataLen != sizeof(FCGI_EndRequestBody)) { + char error_msg[MAX_STRING_LEN]; + sprintf(error_msg, "HTTPd: FastCgi protocol error - End request packet size %d != FCGI_EndRequestBody size", infoPtr->dataLen); + Die(infoPtr,SERVER_ERROR,error_msg); + } + infoPtr->readingEndRequestBody = TRUE; + } + BufferMove(infoPtr->erBufPtr, infoPtr->inbufPtr, len); + infoPtr->dataLen -= len; + if(infoPtr->dataLen == 0) { + FCGI_EndRequestBody *erBody = &infoPtr->endRequestBody; + BufferGetData(infoPtr->erBufPtr, (char *) &infoPtr->endRequestBody, + sizeof(FCGI_EndRequestBody)); + if(erBody->protocolStatus != FCGI_REQUEST_COMPLETE) { + char error_msg[MAX_STRING_LEN]; + sprintf(error_msg, "HTTPd: FastCgi protocol error - end request status != FCGI_REQUEST_COMPLETE"); + Die(infoPtr,SERVER_ERROR,error_msg); + /* + * XXX: What to do with FCGI_OVERLOADED? + */ + } + infoPtr->exitStatus = (erBody->appStatusB3 << 24) + + (erBody->appStatusB2 << 16) + + (erBody->appStatusB1 << 8) + + (erBody->appStatusB0 ); + infoPtr->exitStatusSet = TRUE; + infoPtr->readingEndRequestBody = FALSE; + } + break; + case FCGI_GET_VALUES_RESULT: + /* coming soon */ + case FCGI_UNKNOWN_TYPE: + /* coming soon */ + + /* + * Ignore unknown packet types from the FastCGI server. + */ + default: + BufferToss(infoPtr->inbufPtr, len); + infoPtr->dataLen -= len; + break; + } + + if (infoPtr->dataLen == 0) { + if (infoPtr->paddingLen > 0) { + len = min(infoPtr->paddingLen, BufferLength(infoPtr->inbufPtr)); + BufferToss(infoPtr->inbufPtr, infoPtr->paddingLen); + infoPtr->paddingLen -= len; + } + /* + * If we're done with the data in the packet, then start looking for + * the next header. + */ + if (infoPtr->paddingLen <= 0) + infoPtr->gotHeader = FALSE; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * ScanLine -- + * + * Terminate a line: scan to the next newline, scan back to the + * first non-space character and store a terminating zero. Return + * the next character past the end of the newline. + * + * If the end of the string is reached, return a pointer to the + * end of the string. + * + * If continuation is set to 'TRUE', then it parses a (possible) + * sequence of RFC-822 continuation lines. + * + * Results: + * As above. + * + * Side effects: + * Termination byte stored in string. + * + *---------------------------------------------------------------------- + */ +char *ScanLine(char *start, int continuation) +{ + char *p = start; + char *end = start; + + if(*p != '\n') { + if(continuation) { + while(*p != '\0') { + if(*p == '\n' && p[1] != ' ' && p[1] != '\t') + break; + p++; + } + } else { + while(*p != '\0' && *p != '\n') + p++; + } + } + + end = p; + if(*end != '\0') + end++; + + /* + * Trim any trailing whitespace. + */ + while(isspace(p[-1]) && p > start) + p--; + + *p = '\0'; + return end; +} + +/* + *---------------------------------------------------------------------- + * + * HTTPTime -- + * + * Return the current time, in HTTP time format. + * + * Results: + * Returns pointer to time string, in static allocated array. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +#define TIMEBUFSIZE 256 +char *HTTPTime(struct tm *when) +{ + static char str[TIMEBUFSIZE]; + + strftime(str, TIMEBUFSIZE-1, "%A, %d-%b-%y %T GMT", when); + return str; +} +#undef TIMEBUFSIZE + +/* + *---------------------------------------------------------------------- + * + * SendHeader -- + * + * Queue an HTTP header line for sending back to the client. + * If this is an old HTTP request (HTTP/0.9) or an inner (nested) + * request, ignore and return. + * + * NOTE: This routine assumes that the sent data will fit in + * remaining space in the output buffer. + * + * Results: + * None. + * + * Side effects: + * Header information queued to be sent to client. + * + *---------------------------------------------------------------------- + */ +void SendHeader(FastCgiInfo *reqPtr, ...) +{ + va_list argList; + char *str; + + va_start(argList, reqPtr); + while (TRUE) { + str = va_arg(argList, char *); + if(str == NULL) + break; + BufferAdd(reqPtr->reqOutbufPtr, str); + ASSERT(BufferFree(reqPtr->reqOutbufPtr) > 0); + } + BufferAdd(reqPtr->reqOutbufPtr, "\r\n"); /* terminate */ + ASSERT(BufferFree(reqPtr->reqOutbufPtr) > 0); + va_end(argList); +} + +/* + *---------------------------------------------------------------------- + * + * AddHeaders -- + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void AddHeaders(FastCgiInfo *reqPtr, char *str) +{ + BufferAdd(reqPtr->reqOutbufPtr, str); +} + +/* + *---------------------------------------------------------------------- + * + * BeginHeader -- + * + * Begin a standard HTTP header: emits opening message + * (i.e. "200 OK") and standard header matter. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void BeginHeader(FastCgiInfo *reqPtr, char *msg) +{ + time_t now; + + ASSERT(BufferLength(reqPtr->reqOutbufPtr) == 0); + + now = time(NULL); + SendHeader(reqPtr, SERVER_PROTOCOL, " ", msg, NULL); + SendHeader(reqPtr, "Date: ", HTTPTime(gmtime(&now)), NULL); + SendHeader(reqPtr, "Server: ", SERVER_VERSION, NULL); +/* SendHeader(reqPtr, "MIME-version: 1.0", NULL); */ + + /* + * We shouldn't have run out of space in the output buffer. + */ + ASSERT(BufferFree(reqPtr->reqOutbufPtr) > 0); +} + +/* + *---------------------------------------------------------------------- + * + * EndHeader -- + * + * Marks the end of the HTTP header: sends a blank line. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +void EndHeader(FastCgiInfo *reqPtr) +{ + SendHeader(reqPtr, "", NULL); +} +void ComposeURL(WS_Request *reqPtr, char *url, DString *result) +{ + if(url[0] == '/') { + char portStr[10]; + if (HostInfo(reqPtr) && HostName(reqPtr)) { + sprintf(portStr, "%d", HostPort(reqPtr)); + DStringAppend(result, "http://", -1); + DStringAppend(result, HostName(reqPtr), -1); + DStringAppend(result, ":", -1); + DStringAppend(result, portStr, -1); + } + } + DStringAppend(result, url, -1); +} +/* + *---------------------------------------------------------------------- + * + * HT_ScanCGIHeader -- + * + * Scans the CGI header data to see if the CGI program has sent a + * complete header. If it has, then parse the header and queue + * the HTTP response header information back to the client. + * + * Results: + * TRUE if completed without error, FALSE otherwise. + * + * Side effects: + * Sets 'reqPtr->parseHeader' to TRUE if the header was parsed + * successfully. + * + *---------------------------------------------------------------------- + */ +int ScanCGIHeader(WS_Request *reqPtr, FastCgiInfo *infoPtr) +{ + DString status; + DString headers; + DString cgiLogName; + char *line, *next, *p, *data, *name; + int len, flag, sent; + int bufFree; + + ASSERT(infoPtr->parseHeader == TRUE); + + /* + * Do we have the entire header? Scan for the blank line that + * terminates the header. + */ + p = DStringValue(infoPtr->header); + len = DStringLength(infoPtr->header); + flag = 0; + while(len-- && flag < 2) { + switch(*p) { + case '\r': + break; + case '\n': + flag++; + break; + default: + flag = 0; + break; + } + p++; + } + + /* + * Return (to be called later when we have more data) if we don't have + * and entire header. + */ + if(flag < 2) + return TRUE; + + infoPtr->parseHeader = FALSE; + + DStringInit(&status); + DStringAppend(&status, "200 OK", -1); + DStringInit(&headers); + DStringInit(&cgiLogName); + next = DStringValue(infoPtr->header); + for(;;) { + next = ScanLine(line = next, TRUE); + if(*line == '\0') + break; + + if((p = strpbrk(line, " \t")) != NULL) { + data = p + 1; + *p = '\0'; + } else + data = ""; + + while(isspace(*data)) + data++; + + /* + * Handle "Location:", "Status:", and "Log-XXXX" specially. + * All other CGI headers get passed through unmodified. + */ + if(!strcasecmp(line, "Location:")) { + DStringTrunc(&status, 0); + DStringAppend(&status, "302 Redirect", -1); + DStringAppend(&headers, "Location: ", -1); + + /* + * This is a deviation from the CGI/1.1 spec. + * + * The spec says that "virtual paths" should be treated + * as if the client had accessed the file in the first + * place. This usually breaks relative references in the + * referenced document. + * + * XXX: do more research on this? + */ + ComposeURL(reqPtr, data, &headers); + DStringAppend(&headers, "\r\n", -1); + } else if(!strcasecmp(line, "Status:")) { + DStringTrunc(&status, 0); + DStringAppend(&status, data, -1); + } else if(Tcl_StringMatch(line, "[Ll][Oo][Gg]-?*:")) { + p = strchr(line, '-'); + ASSERT(p != NULL); + name = p + 1; + + p = strchr(name, ':'); + ASSERT(p != NULL); + *p = '\0'; + + DStringTrunc(&cgiLogName, 0); + DStringAppend(&cgiLogName, "cgi-", -1); + DStringAppend(&cgiLogName, name, -1); + } else { + if(data != NULL) { + DStringAppend(&headers, line, -1); + DStringAppend(&headers, " ", 1); + DStringAppend(&headers, data, -1); + DStringAppend(&headers, "\r\n", -1); + } + } + } + + /* + * We're done scanning the CGI script's header output. Now + * we have to write to the client: status, CGI header, and + * any over-read CGI output. + */ + BeginHeader(infoPtr, DStringValue(&status)); + DStringFree(&status); + + AddHeaders(infoPtr, DStringValue(&headers)); + DStringFree(&headers); + DStringFree(&cgiLogName); + EndHeader(infoPtr); + + len = next - DStringValue(infoPtr->header); + len = DStringLength(infoPtr->header) - len; + ASSERT(len >= 0); + + bufFree = BufferFree(infoPtr->reqOutbufPtr); + + if (bufFree < len) { + /* should the same fix be made in core server? */ + int bufLen = BufferLength(infoPtr->reqOutbufPtr); + Buffer *newBuf = BufferCreate(len + bufLen); + BufferMove(newBuf, infoPtr->reqOutbufPtr, bufLen); + BufferDelete(infoPtr->reqOutbufPtr); + infoPtr->reqOutbufPtr = newBuf; + } + bufFree = BufferFree(infoPtr->reqOutbufPtr); + if(bufFree == 0) + goto fail; + + /* + * Only send the body for methods other than HEAD. + */ + if(reqPtr->method != M_HEAD) { + if(len > 0) { + sent = BufferAddData(infoPtr->reqOutbufPtr, next, len); + if(sent != len) + goto fail; + } + } + return TRUE; + +fail: + return FALSE; +} + +/* + *---------------------------------------------------------------------- + * + * FastCgiDoWork -- + * + * This is the core routine for moving data between the CGI program + * and the network socket. + * + * + * Results: + * None. + * + * Side effects: + * many + * + *---------------------------------------------------------------------- + */ +static int FastCgiDoWork(WS_Request *reqPtr, FastCgiInfo *infoPtr) +{ + fd_set read_set, write_set; + int numFDs, select_status; + struct timeval timeOut; + int clientRead, fcgiRead; + int nBytes; + int csdIn, csdOut; + int contentLength; + int nFirst = 1; + int done = 0; + clientRead = fcgiRead = 1; + FD_ZERO(&read_set); + FD_ZERO(&write_set); + numFDs = infoPtr->fd + 1; + timeOut.tv_sec = timeOut.tv_usec = 0; + contentLength = reqPtr->inh_content_length; + if (contentLength <= 0) + clientRead = 0; + PrepareClientSocket(reqPtr, &csdIn, &csdOut); + while (!done) { + + if(BufferLength(infoPtr->outbufPtr)) + FD_SET(infoPtr->fd, &write_set); + else + FD_CLR(infoPtr->fd, &write_set); + + FD_SET(infoPtr->fd, &read_set); + FD_SET(csdIn, &read_set); + + if(BufferLength(infoPtr->reqOutbufPtr)) + FD_SET(csdOut, &write_set); + else + FD_CLR(csdOut, &write_set); + + select_status = select(numFDs, &read_set, &write_set, NULL, NULL); + if(select_status < 0) + break; + + /* + * Move data from the FastCGI program's standard output to the network + * socket, until we can do no more work without blocking. + */ + ClientToCgiBuffer(infoPtr); + CgiToClientBuffer(infoPtr); + + if(infoPtr->parseHeader == TRUE) { + if(ScanCGIHeader(reqPtr, infoPtr) == FALSE) { + char error_msg[MAX_STRING_LEN]; + sprintf(error_msg,"HTTPd: malformed header from script %s", + reqPtr->filename); + Die(infoPtr,SERVER_ERROR,error_msg); + return SERVER_ERROR; + } + } + + if (nFirst) { + char szBuf[IOBUFSIZE]; + nBytes=getline(reqPtr->sb, szBuf,IOBUFSIZE,G_FLUSH,0); + BufferAddData(infoPtr->reqInbufPtr, szBuf, nBytes); + if (nBytes > 0) { + BufferAddData(infoPtr->reqInbufPtr, szBuf, nBytes); + ClientToCgiBuffer(infoPtr); + } + nFirst = 0; + contentLength -= nBytes; + if (contentLength <= 0) + clientRead = 0; + } + + /* + * Move data between the buffers and the network sockets. + */ + if(FD_ISSET(csdIn, &read_set) && + (BufferFree(infoPtr->reqInbufPtr) > 0)) { + nBytes = BufferRead(infoPtr->reqInbufPtr, csdIn); + if (nBytes >= 0) + contentLength -= nBytes; + if (contentLength <= 0) + clientRead = 0; + } + + if(FD_ISSET(infoPtr->fd, &read_set) && + (BufferFree(infoPtr->inbufPtr) > 0) && + infoPtr->fd >= 0) { + if (BufferRead(infoPtr->inbufPtr, infoPtr->fd) <= 0) + fcgiRead = 0; + } + + if(FD_ISSET(csdOut, &write_set) && + (BufferLength(infoPtr->reqOutbufPtr) > 0)) { + BufferWrite(infoPtr->reqOutbufPtr, csdOut); + } + + if(FD_ISSET(infoPtr->fd, &write_set) && + (BufferLength(infoPtr->outbufPtr) > 0) && + infoPtr->fd >= 0) { + BufferWrite(infoPtr->outbufPtr, infoPtr->fd); + } + if (fcgiRead) + fcgiRead = (!infoPtr->exitStatusSet); + if (((clientRead == 0) || + !FD_ISSET(csdIn, &read_set)) && + (fcgiRead == 0) && + (BufferLength(infoPtr->reqOutbufPtr) <= 0) && + (BufferLength(infoPtr->outbufPtr) <= 0)) { + if (infoPtr->parseHeader == TRUE) { + char error_msg[MAX_STRING_LEN]; + sprintf(error_msg,"HTTPd: malformed header from script %s", + reqPtr->filename); + Die(infoPtr,SERVER_ERROR,error_msg); + } + done = 1; + } + } + FcgiCleanUp(infoPtr); + reqPtr->outh_content_length = -1; + return OK; +} + + +/* + *---------------------------------------------------------------------- + * + * ConnectionComplete -- + * + * This routine gets called when the connection completes. If + * the connection completed with an error, it generates an error + * result back to the client. Otherwise, it begins a FastCGI + * request (sending the environment variables). + * + * Results: + * None. + * + * Side effects: + * Request terminated, or continued. + * + *---------------------------------------------------------------------- + */ +static int ConnectionComplete(WS_Request *reqPtr, FastCgiInfo *infoPtr) +{ + int errorCode, len; + FastCgiServerInfo *serverInfoPtr = infoPtr->serverPtr; + + /* + * Get the connection status. + */ + len = sizeof(errorCode); + if(getsockopt(infoPtr->fd, SOL_SOCKET, SO_ERROR, + (char *) &errorCode, &len) < 0) { + ConnectionError(infoPtr, errno); + return SERVER_ERROR; + } + ASSERT(len == sizeof(errorCode)); + if(errorCode > 0) { + ASSERT(errorCode != EINPROGRESS); + ConnectionError(infoPtr, errorCode); + return SERVER_ERROR; + } + +/* Don't do keepalive unless the script returns a content-length + * header + */ + keep_alive.bKeepAlive = 0; + + SendBeginRequest(infoPtr); + SendEnvironment(reqPtr, infoPtr); + return FastCgiDoWork(reqPtr, infoPtr); +} + + + +/* + *---------------------------------------------------------------------- + * + * FastCgiHandler -- + * + * This routine gets called for a request that corresponds to + * a Fast CGI connection. It begins the connect operation to the + * FastCGI server. + * + * Results: + * None. + * + * Side effects: + * Connection to FastCGI server established. + * + *---------------------------------------------------------------------- + */ +int FastCgiHandler(WS_Request *reqPtr) +{ + FastCgiServerInfo *serverInfoPtr; + FastCgiInfo *infoPtr; + int scriptTimeout; + OS_IpcAddr *ipcAddrPtr; + struct stat finfo; + + get_path_info(reqPtr,&finfo); + + SetErrorLogFd(reqPtr, 0); + + serverInfoPtr = FastCgiServerInfoLookup(reqPtr->filename); + + /* + * Allocate FastCGI private data to hang off of the request structure. + */ + infoPtr = (FastCgiInfo *) Malloc(sizeof(FastCgiInfo)); + infoPtr->serverPtr = serverInfoPtr; + infoPtr->inbufPtr = BufferCreate(SERVER_BUFSIZE); + infoPtr->outbufPtr = BufferCreate(SERVER_BUFSIZE); + infoPtr->gotHeader = FALSE; + infoPtr->reqInbufPtr = BufferCreate(SERVER_BUFSIZE); + infoPtr->reqOutbufPtr = BufferCreate(SERVER_BUFSIZE); + infoPtr->parseHeader = TRUE; + infoPtr->header = (DString *) malloc(sizeof(DString)); + infoPtr->errorOut = (DString *) malloc(sizeof(DString)); + infoPtr->reqPtr = reqPtr; + + DStringInit(infoPtr->header); + DStringInit(infoPtr->errorOut); + infoPtr->erBufPtr = BufferCreate(sizeof(FCGI_EndRequestBody) + 1); + infoPtr->readingEndRequestBody = FALSE; + infoPtr->exitStatus = 0; + infoPtr->exitStatusSet = FALSE; + infoPtr->requestId = 1; /* XXX need to set to some meaningful value */ + globalInfoPtr = infoPtr; + + /* + * Don't core dump if the server isn't configured + */ + if (serverInfoPtr == NULL) + ConnectionError(infoPtr,0); + + /* + * synchronously open a connection to Fast CGI server. + */ + ipcAddrPtr = (OS_IpcAddr *) serverInfoPtr->ipcAddr; + if((infoPtr->fd = OS_Socket(ipcAddrPtr->serverAddr->sa_family, + SOCK_STREAM, 0)) < 0) { + ConnectionError(infoPtr, errno); + return SERVER_ERROR; + } + if(connect(infoPtr->fd, (struct sockaddr *) ipcAddrPtr->serverAddr, + ipcAddrPtr->addrLen) < 0) { + ConnectionError(infoPtr, errno); + return SERVER_ERROR; + } + return ConnectionComplete(reqPtr, infoPtr); +} + + +/* + * OS_CreateLocalIpcFd -- + * + * This procedure is responsible for creating the listener socket + * on Unix for local process communication. It will create a Unix + * domain socket, bind it, and return a file descriptor to it to the + * caller. + * + * Results: + * Listener socket created. This call returns either a valid + * file descriptor or -1 on error. + * + * Side effects: + * Listener socket and IPC address are stored in the FCGI info + * structure. + * + *---------------------------------------------------------------------- + */ +int OS_CreateLocalIpcFd(OS_IpcAddress ipcAddress, int listenQueueDepth) +{ + OS_IpcAddr *ipcAddrPtr = (OS_IpcAddr *)ipcAddress; + char bindPathExt[32]; + struct sockaddr_un *addrPtr; + int listenSock = -1; + addrPtr = NULL; + + /* + * Create a unique name to be used for the socket bind path. + * Make sure that this name is unique and that there's no process + * bound to it. + * + * Bind Path = /tmp/OM_WS_N.pid + * + */ + ASSERT(DStringLength(&ipcAddrPtr->bindPath) == 0); + DStringAppend(&ipcAddrPtr->bindPath, "/tmp/OM_WS_", -1); + sprintf(bindPathExt, "%d.%d", bindPathExtInt, (int)getpid()); + bindPathExtInt++; + DStringAppend(&ipcAddrPtr->bindPath, bindPathExt, -1); + + /* + * Build the domain socket address. + */ + addrPtr = (struct sockaddr_un *) Malloc(sizeof(struct sockaddr_un)); + ipcAddrPtr->serverAddr = (struct sockaddr *) addrPtr; + + if (OS_BuildSockAddrUn(DStringValue(&ipcAddrPtr->bindPath), addrPtr, + &ipcAddrPtr->addrLen)) { + goto GET_IPC_ERROR_EXIT; + } + + /* + * Create the listening socket to be used by the fcgi server. + */ + if((listenSock = OS_Socket(ipcAddrPtr->serverAddr->sa_family, + SOCK_STREAM, 0)) < 0) { + goto GET_IPC_ERROR_EXIT; + } + + /* + * Bind the lister socket and set it to listen. + */ + if(OS_Bind(listenSock, ipcAddrPtr->serverAddr, ipcAddrPtr->addrLen) < 0 + || OS_Listen(listenSock, listenQueueDepth) < 0) { + goto GET_IPC_ERROR_EXIT; + } + return listenSock; + +GET_IPC_ERROR_EXIT: + if(listenSock != -1) + OS_Close(listenSock); + if(addrPtr != NULL) { + free(addrPtr); + ipcAddrPtr->serverAddr = NULL; + } + return -1; +} + +/* + *---------------------------------------------------------------------- + * + * OS_FreeIpcAddr -- + * + * Free up and clean up an OS IPC address. + * + * Results: + * IPC Address is freed. + * + * Side effects: + * More memory. + * + *---------------------------------------------------------------------- + */ +void OS_FreeIpcAddr(OS_IpcAddress ipcAddress) +{ + OS_IpcAddr *ipcAddrPtr = (OS_IpcAddr *)ipcAddress; + + DStringFree(&ipcAddrPtr->bindPath); + if(ipcAddrPtr->serverAddr != NULL) + free(ipcAddrPtr->serverAddr); + ipcAddrPtr->addrLen = 0; + free(ipcAddrPtr); +} + +/* + *---------------------------------------------------------------------- + * + * OS_ExecFcgiProgram -- + * + * Fork and exec the specified fcgi process. + * + * Results: + * FCGI Program is forked and should be ready to accept + * connections. + * Returns 0 on success or a valid server error on failure. + * + * Side effects: + * Child process is transformed into the program. Sets errno + * on error. + * + *---------------------------------------------------------------------- + */ +int OS_ExecFcgiProgram(pid_t *childPid, int listenFd, int priority, + char *programName, char **envPtr) +{ + int i; + DString dirName; + char *dnEnd; + + /* + * Fork the fcgi process. + */ + *childPid = fork(); + if(*childPid < 0) { + return SERVER_ERROR; + } + if(*childPid == 0) { + if(listenFd != FCGI_LISTENSOCK_FILENO) { + OS_Dup2(listenFd, FCGI_LISTENSOCK_FILENO); + OS_Close(listenFd); + } + + DStringInit(&dirName); + dnEnd = strrchr(programName, '/'); + if(dnEnd == NULL) { + DStringAppend(&dirName, "./", 1); + } else { + DStringAppend(&dirName, programName, dnEnd - programName); + } + + /* + * We're a child. Exec the application. + */ + if(chdir(DStringValue(&dirName)) < 0) { + fprintf(errorLogFd, "exec fcgi: failed to change dir %s -- %s -- %s\n", + programName, DStringValue(&dirName), strerror(errno)); + exit(1); + } + DStringFree(&dirName); + + /* + * Set priority of the process. + */ + if (priority != 0) { + if (nice (priority) == -1) { + fprintf (errorLogFd, "exec fcgi: failed to change priority -- %s -- %s\n", + programName, strerror(errno)); + exit (1); + } + } + + /* + * Close any file descriptors we may have gotten from the parent + * process. The only FD left open is the FCGI listener socket. + */ + for(i=0; i < ht_openmax; i++) { + if(i != FCGI_LISTENSOCK_FILENO) + OS_Close(i); + } + + if(envPtr != NULL) { + execle(programName, programName, NULL, envPtr); + }else { + execl(programName, programName, NULL); + } + exit(errno); + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * OS_CleanupFcgiProgram -- + * + * Perform OS cleanup on a server managed process. + * + * Results: + * None. + * + * Side effects: + * Domain socket bindPath is unlinked. + * + *---------------------------------------------------------------------- + */ +void OS_CleanupFcgiProgram(OS_IpcAddress ipcAddress) +{ + OS_IpcAddr *ipcAddrPtr = (OS_IpcAddr *)ipcAddress; + unlink(DStringValue(&ipcAddrPtr->bindPath)); +} + +char *SkipSpace(char *inp) +{ + while (*inp == ' ') + inp++; + return inp; +} + +char **ParseAppClassArgs(char *inp, int *ac) +{ + char *input = (char *) malloc(strlen(inp) + 1); + char *ptr = input; + char *prev = ptr; + int count = 0; + char **argv = NULL; + strcpy(input, inp); + + while ((ptr = strchr(prev, ' '))) { + ptr++; + count++; + ptr = SkipSpace(ptr); + prev = ptr; + } + if (*prev) count++; + argv = (char **) malloc(sizeof(char *) * (count + 1)); + count = 1; + prev = input; + while ((ptr = strchr(prev, ' '))) { + *ptr++ = 0; + argv[count] = prev; + count++; + ptr = SkipSpace(ptr); + prev = ptr; + } + if (*prev) { + argv[count] = prev; + count++; + } + *ac = count; + return argv; +} + +/* + *------------------------------------------------------- + * OS_EnvironInit + * + * + * + *------------------------------------------------------ + */ + +char **OS_EnvironInit(int envCount) +{ + int i; + char **envPtr = (char **) Malloc(sizeof(char *) * envCount); + for (i = 0; i < envCount; ++i) + envPtr[i] = NULL; + return envPtr; +} + +void OS_EnvironFree(char **envPtr) +{ + int i; + char **tmp = envPtr; + while (*tmp) { + free(*tmp); + tmp++; + } +} + +void OS_EnvString(char **envPtr, char *name, char *value) +{ + char *buf; + int size; + buf = (char *)Malloc(strlen(name) + strlen(value) + 2); + sprintf(buf, "%s=%s", name, value); + *envPtr = buf; +} + + +/* + *---------------------------------------------------------------------- + * + * CreateFcgiServerInfo -- + * + * This routine allocates and initializes a fast cgi server info + * structure. It's called from AppClass, ExternalAppClass and + * __SendFcgiScript. This routine is responsible for adding the + * new entry to the appClassTable also. + * + * Results: + * NULL pointer is returned if the class has already been defined + * or a valid fast cgi server info pointer. + * + * Side effects: + * Fast cgi server info structure is allocated and initialized. + * This includes allocation and initialization of the per + * connection information. + * + *---------------------------------------------------------------------- + */ +static FastCgiServerInfo * CreateFcgiServerInfo(int numInstances, + char *ePath) +{ + FastCgiServerInfo *serverInfoPtr = NULL; + FcgiProcessInfo *procInfoPtr; + int i, new; + + serverInfoPtr = FastCgiServerInfoLookup(ePath); + if (serverInfoPtr) + return NULL; + + /* + * Create an info structure for the Fast CGI server (TCP type). + */ + serverInfoPtr = (FastCgiServerInfo *) Malloc(sizeof(FastCgiServerInfo)); + DStringInit(&serverInfoPtr->execPath); + serverInfoPtr->envp = NULL; + serverInfoPtr->listenQueueDepth = DEFAULT_FCGI_LISTEN_Q; + serverInfoPtr->maxProcesses = numInstances; + serverInfoPtr->restartDelay = 0; + serverInfoPtr->restartOnExit = FALSE; + serverInfoPtr->numRestarts = 0; + serverInfoPtr->numFailures = 0; + serverInfoPtr->ipcAddr = OS_InitIpcAddr(); + serverInfoPtr->processPriority = 0; + serverInfoPtr->listenFd = -1; + serverInfoPtr->reqRefCount = 0; + serverInfoPtr->freeOnZero = FALSE; + serverInfoPtr->restartTimerQueued = FALSE; + /* + * XXX: For initial testing of the new protocol, close the connection + * after each request. Once debugged, we will query the app + * to see whether or not it can maintain a persistent connection + * based on the number of connections it can support and the + * number of processes we have running. + */ + serverInfoPtr->keepConnection = FALSE; + serverInfoPtr->fcgiFd = -1; + + serverInfoPtr->procInfo = + (FcgiProcessInfo *) Malloc(sizeof(FcgiProcessInfo) * numInstances); + + procInfoPtr = serverInfoPtr->procInfo; + for(i = 0; i < numInstances; i++) { + procInfoPtr->pid = -1; + procInfoPtr->listenFd = -1; + procInfoPtr->fcgiFd = -1; + procInfoPtr->ipcAddr = OS_InitIpcAddr(); + procInfoPtr->serverInfoPtr = serverInfoPtr; + procInfoPtr++; + } + serverInfoPtr->next = fastCgiServers; + fastCgiServers = serverInfoPtr; + return serverInfoPtr; +} + +/* + *---------------------------------------------------------------------- + * + * FreeFcgiServerInfo -- + * + * This routine frees up all resources associated with a Fast CGI + * application server. It's called on error cleanup and as a result + * of a shutdown or restart. + * + * Results: + * FastCgi server and process structures freed. + * + * Side effects: + * Fast cgi info structure is deallocated and unavailable. + * + *---------------------------------------------------------------------- + */ +static void FreeFcgiServerInfo(FastCgiServerInfo *serverInfoPtr) +{ + FcgiProcessInfo *processInfoPtr; + int i; + + /* + * If there are any external references to this server structure + * set the "freeOnZero" flag so that the structure will be freed + * when both the request and role reference counts go to zero. + * + * The freeOnZero flag is set: + * + * o unconditionally for .fcgi programs. This is because a .fcgi + * program does not create a persistent process. This type of + * program only lives for a single request. + * + * o server shutdown that causes FreeRoleInfo to be called because + * mount handlers are being cleaned up. The FreeRoleInfo call + * calls this routine (FreeFcgiServerInfo) unconditionally. + */ + if(serverInfoPtr->reqRefCount != 0) { + serverInfoPtr->freeOnZero = TRUE; + return; + } + + /* + * Free up process/connection info. + */ + processInfoPtr = serverInfoPtr->procInfo; + for(i = 0; i < serverInfoPtr->maxProcesses; i ++, processInfoPtr++) { + if(processInfoPtr->pid != -1) { + kill(processInfoPtr->pid, SIGTERM); + processInfoPtr->pid = -1; + } + OS_FreeIpcAddr(processInfoPtr->ipcAddr); + } + /* + * Cleanup server info structure resources. + */ + OS_CleanupFcgiProgram(serverInfoPtr->ipcAddr); + OS_FreeIpcAddr(serverInfoPtr->ipcAddr); + DStringFree(&serverInfoPtr->execPath); + if(serverInfoPtr->listenFd != -1) { + OS_Close(serverInfoPtr->listenFd); + serverInfoPtr->listenFd = -1; + } + + free(serverInfoPtr->procInfo); + serverInfoPtr->procInfo = NULL; + + if(serverInfoPtr->envp != NULL) { + OS_EnvironFree(serverInfoPtr->envp); + free(serverInfoPtr->envp); + serverInfoPtr->envp = NULL; + } + /* XXX remove serverInfoPtr from chain */ + + if (serverInfoPtr == fastCgiServers) + fastCgiServers = fastCgiServers->next; + else { + FastCgiServerInfo *tmpPtr = fastCgiServers; + while (tmpPtr->next && (tmpPtr->next != serverInfoPtr) ) + tmpPtr = tmpPtr->next; + if (tmpPtr->next == serverInfoPtr) + tmpPtr->next = serverInfoPtr->next; + } + free(serverInfoPtr); +} + +/* + *---------------------------------------------------------------------- + * + * FcgiProgramExit -- + * + * This routine gets called when the child process for the + * program exits. The exit status is recorded in the request log. + * + * Results: + * None. + * + * Side effects: + * Status recorded in log, pid set to -1. + * + *---------------------------------------------------------------------- + */ +static void FcgiProgramExit(FcgiProcessInfo *processInfoPtr, int status) +{ + FastCgiServerInfo *serverInfoPtr = processInfoPtr->serverInfoPtr; + time_t restartTime, timeNow; + + serverInfoPtr->numFailures++; + processInfoPtr->pid = -1; + /* + * Only log the state of the process' exit if it's expected to stay + * alive. + * + * XXX: MAY want to have a different process exit routine for .fcgi + */ + if(serverInfoPtr->restartOnExit == TRUE) { + if(WIFEXITED(status) && (WEXITSTATUS(status) != 0)) { + fprintf(errorLogFd, "FastCGI process '%s' terminated due to exit", + DStringValue(&serverInfoPtr->execPath)); + } else if(WIFSIGNALED(status)) { + fprintf(errorLogFd, "FastCGI process '%s' terminated due to signal", + DStringValue(&serverInfoPtr->execPath)); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * ExecFcgiProgram -- + * + * This procedure is invoked to start a fast cgi program. It + * calls an OS specific routine to start the process and sets a + * wait handler on the process. + * + * NOTE: At the present time, the only error than can be returned is + * SERVER_UNAVAILABLE which means a fork() failed (WS_errno is set). + * + * Results: + * Returns 0 if successful or a valid server error if not. + * + * Side effects: + * Possibly many. + * + *---------------------------------------------------------------------- + */ +static int ExecFcgiProgram(FcgiProcessInfo *processInfoPtr, int priority) +{ + FastCgiServerInfo *serverInfoPtr = processInfoPtr->serverInfoPtr; + int err = FALSE; + int listenFd; + + listenFd = serverInfoPtr->listenFd; + + /* + * The call to OS_ExecFcgiProgram will only return once. It will not + * return as a result of the child's creation. + */ + + if ((err = OS_ExecFcgiProgram(&processInfoPtr->pid, listenFd, priority, + DStringValue(&serverInfoPtr->execPath), + serverInfoPtr->envp)) != 0) { + return err; + } + return 0; +} + +static void FastCGIRestart() +{ + while (fastCgiServers) { + FreeFcgiServerInfo(fastCgiServers); + } + exit(0); +} +static void FastCGISetSignals() +{ + signal(SIGTERM,(void (*)())FastCGIRestart); + signal(SIGHUP,(void (*)())FastCGIRestart); + signal(SIGKILL,(void (*)())FastCGIRestart); +} + +/* + *---------------------------------------------------------------------- + * StartFastCGIManager + * + * start the FastCGI process managers which is responsible for: + * - starting all the FastCGI proceses. + * - restart should any of these die + * - looping and call waitpid() on each child + * - clean up these processes when server restart + * + * Results: + * + * Side effects: + * Registers a new AppClass handler for FastCGI. + * + *---------------------------------------------------------------------- + */ +void RunFastCGIManager(void *data) +{ + FastCgiServerInfo *serverInfoPtr = (FastCgiServerInfo *)data; + + int i; + FcgiProcessInfo *processInfoPtr; + FastCGISetSignals(); + processInfoPtr = serverInfoPtr->procInfo; + for(i = 0; i < serverInfoPtr->maxProcesses; i++) { + if(ExecFcgiProgram(processInfoPtr, + serverInfoPtr->processPriority) != 0) { + fprintf(errorLogFd, "AppClass: failed to exec app class %s\n", + DStringValue(&serverInfoPtr->execPath)); + FreeFcgiServerInfo(serverInfoPtr); + exit(0); /* exit from procManager processes, + should also clean up XXX + */ + } + processInfoPtr++; + } + while (1) { /* looping to detect and reborn any dead child */ + int status; + + sleep(serverInfoPtr->restartDelay); + if (serverInfoPtr->restartOnExit == FALSE) + continue; + processInfoPtr = serverInfoPtr->procInfo; + for(i = 0; i < serverInfoPtr->maxProcesses; i++) { + int status; + if ((processInfoPtr->pid > 0) && + (waitpid(processInfoPtr->pid, &status, WNOHANG) > 0)) { + FcgiProgramExit(processInfoPtr, status); + if(ExecFcgiProgram(processInfoPtr, + serverInfoPtr->processPriority) != 0) { + fprintf(errorLogFd, "AppClass: failed to exec app class %s\n", + DStringValue(&serverInfoPtr->execPath)); + } + } + processInfoPtr++; + } + } +} + +int StartFastCGIManager(FastCgiServerInfo *serverInfoPtr) +{ + pid_t procManager; + + procManager = SpawnChild(RunFastCGIManager, serverInfoPtr); + if (procManager < 0) { + return SERVER_ERROR; + } + serverInfoPtr->procManager = procManager; + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * AppClassCmd -- + * + * Implements the FastCGI AppClass configuration directive. This + * command adds a fast cgi program class which will be used by the + * httpd parent to start/stop/maintain fast cgi server apps. + * + * AppClass [-processes N] \ + * [-restart-delay N] [-priority N] \ + * [-initial-env name1=value1] \ + * [-initial-env name2=value2] + * + * Default values: + * + * o numProcesses will be set to FCGI_MAX_PROCESSES (1) + * o restartDelay will be set to 5 which means the application will not + * be restarted any earlier than 5 seconds from when it was last + * invoked. If the application has been up for longer than 5 seconds + * and it fails, a single copy will be restarted immediately. Other + * restarts within that group will be inhibited until the restart-delay + * has elapsed. + * o affinity will be set to FALSE (ie. no process affinity) if not + * specified. + * + * Results: + * TCL_OK or TCL_ERROR. + * + * Side effects: + * Registers a new AppClass handler for FastCGI. + * + *---------------------------------------------------------------------- + */ +char * AppClassCmd(per_host *host, char *arg) + +{ + int numProcesses = -1; + int affinity = 0; + int restartDelay = FCGI_DEFAULT_RESTART_DELAY; + char *execPath; + char temp[200]; + FastCgiServerInfo *serverInfoPtr = NULL; + FcgiProcessInfo *processInfoPtr; + int i; + int listenFd = -1; + char *namePtr; + char *valuePtr; + char **envPtr = NULL; + char **envHead; + int priority = 0; /* Default is that of the Web Server */ + int listenQueueDepth = -1; + int argc; + char **argv; + int envCount; + int listenSock = -1; + SetErrorLogFd(host, 1); + + argv = ParseAppClassArgs(arg, &argc); + if(argc < 3) { + fprintf(errorLogFd, "AppClass: too few args\n"); + return "AppClass: directive error"; + } + /* + * Parse and validate arguments. + * + * arg 1 is the name and arg 2 is the exec-path. + */ + execPath = argv[1]; + + serverInfoPtr = FastCgiServerInfoLookup(execPath); + if (serverInfoPtr) { + if (serverInfoPtr->procManager > 0) + kill(serverInfoPtr->procManager, SIGHUP); + FreeFcgiServerInfo(serverInfoPtr); + serverInfoPtr = NULL; + } + + envCount = argc/2 + 1; + envPtr = OS_EnvironInit(envCount); + envHead = envPtr; + + if (WS_Access(execPath, X_OK)) { + fprintf(errorLogFd, "AppClass: Failed to access %s\n", execPath); + goto APP_CLASS_ERROR; + } + + for(i = 2; i < argc; i++) { + if((strcmp(argv[i], "-processes") == 0)) { + if((i + 1) == argc) { + fprintf(errorLogFd, "AppClass: missing value for -processes\n"); + goto APP_CLASS_ERROR; + } + i++; + numProcesses = atoi(argv[i]); + if((numProcesses < 1) || (numProcesses > FCGI_MAX_PROCESSES)) { + fprintf(errorLogFd, "AppClass: -processes %d is out of range. Valid range is 1 to %d", + numProcesses, FCGI_MAX_PROCESSES); + goto APP_CLASS_ERROR; + } + continue; + } else if((strcmp(argv[i], "-restart-delay") == 0)) { + if((i + 1) == argc) { + fprintf(errorLogFd, "AppClass: missing value for -restart-delay\n"); + goto APP_CLASS_ERROR; + } + i++; + restartDelay = atoi(argv[i]); + if(restartDelay < 0) { + fprintf(errorLogFd, "AppClass: negative value for -restart-delay\n"); + goto APP_CLASS_ERROR; + } + continue; + } else if((strcmp(argv[i], "-priority") == 0)) { + if((i + 1) == argc) { + fprintf(errorLogFd, "AppClass: missing value for -priority\n"); + goto APP_CLASS_ERROR; + } + i++; + priority = atoi(argv[i]); + if(priority < 0 || priority > 20) { + fprintf(errorLogFd, "AppClass: invalid value for -priority\n"); + goto APP_CLASS_ERROR; + } + continue; + } else if((strcmp(argv[i], "-initial-env") == 0)) { + if((i + 1) == argc) { + fprintf(errorLogFd, "AppClass: missing value for -initial-env\n"); + goto APP_CLASS_ERROR; + } + i++; + namePtr = argv[i]; + valuePtr = strchr(namePtr, '='); + /* + * Separate the name and value components. + */ + if(valuePtr != NULL) { + *valuePtr = '\0'; + valuePtr++; + } else { + fprintf(errorLogFd, "AppClass: invalid values for -initial-env\n"); + goto APP_CLASS_ERROR; + } + + OS_EnvString(envPtr, namePtr, valuePtr); + valuePtr--; + *valuePtr = '='; + envPtr++; + continue; + } else if((strcmp(argv[i], "-listen-queue-depth") == 0)) { + if((i + 1) == argc) { + fprintf(errorLogFd, "AppClass: missing value for -listen-queue-depth\n"); + goto APP_CLASS_ERROR; + } + i++; + listenQueueDepth = atoi(argv[i]); + if(listenQueueDepth < 1) { + fprintf(errorLogFd, "AppClass: invalid value for -listen-queue-depth\n"); + goto APP_CLASS_ERROR; + } + continue; + } else { + fprintf(errorLogFd, "AppClass: Invalid field %s\n", argv[i]); + goto APP_CLASS_ERROR; + } + } + envPtr = envHead; + if(numProcesses == -1) { + numProcesses = 1; + } + serverInfoPtr = CreateFcgiServerInfo(numProcesses, execPath); + if(serverInfoPtr == NULL) { + fprintf(errorLogFd, "AppClass: redefinition of previously defined app class\n"); + if(envPtr != NULL) { + OS_EnvironFree(envPtr); + free(envPtr); + } + return NULL; + } + + DStringAppend(&serverInfoPtr->execPath, execPath, -1); + serverInfoPtr->restartOnExit = TRUE; + serverInfoPtr->restartDelay = restartDelay; + serverInfoPtr->processPriority = priority; + serverInfoPtr->procManager = -1; + if(listenQueueDepth != -1) + serverInfoPtr->listenQueueDepth = listenQueueDepth; + serverInfoPtr->envp = envPtr; + /* + * Set envPtr to NULL so that if there is an error we don't end up + * trying to free up the environment structure twice. This will be + * freed up by FreeFcgiServerInfo. + */ + envPtr = NULL; + + /* + * Create an initial IPC path for the FCGI listener process. If + * affinity option, then we'll create a unique listener path for + * each fast cgi process being created. + * + * NOTE: The listener socket will be saved and kept in the serverInfo + * and process info structures for process restart purposes. + */ + if(affinity == FALSE) { + listenFd = OS_CreateLocalIpcFd(serverInfoPtr->ipcAddr, + serverInfoPtr->listenQueueDepth); + if(listenFd < 0) { + fprintf(errorLogFd, "AppClass: could not create local IPC socket\n"); + goto APP_CLASS_ERROR; + } else { + serverInfoPtr->listenFd = listenFd; + } + } + free(argv[1]); + free(argv); + argv = NULL; + if (StartFastCGIManager(serverInfoPtr) != 0) { + goto APP_CLASS_ERROR; + } + serverInfoPtr->procStartTime = time(NULL); + return NULL; + +APP_CLASS_ERROR: + if(serverInfoPtr != NULL) { + FreeFcgiServerInfo(serverInfoPtr); + } + if(envPtr != NULL) { + OS_EnvironFree(envPtr); + free(envPtr); + } + if (argv) { + free(argv[1]); + free(argv); + } + return "AppClass: Directive Error"; +} + + +void PrepareClientSocket(WS_Request *reqPtr, int *csdIn, int *csdOut) +{ + fflush(reqPtr->out); + *csdIn = reqPtr->connection_socket; + *csdOut = fileno(reqPtr->out); +} +void MakeExtraEnvStr(WS_Request *reqPtr) +{ + make_env_str(reqPtr,"SERVER_HOSTNAME",reqPtr->hostInfo->server_hostname); + make_env_str(reqPtr,"SERVER_ADDR", + inet_ntoa(reqPtr->hostInfo->address_info)); +} + +int SpawnChild(void (*func)(void *), void *data) +{ + pid_t pid; + + pid = fork(); + if (pid == 0) { + signal (SIGCHLD, SIG_DFL); + func (data); + exit (0); + } + return pid; +} +void SetErrorLogFd(void *inp, int type) +{ + if (type) { + per_host *host = (per_host *) inp; + if (host && host->error_log) + errorLogFd = host->error_log; + else + errorLogFd = stderr; + } + else { + WS_Request *reqPtr = (WS_Request *) inp; + if (reqPtr && HostInfo(reqPtr) && HostInfo(reqPtr)->error_log) + errorLogFd = HostInfo(reqPtr)->error_log; + else + errorLogFd = stderr; + } +} + +/* + *---------------------------------------------------------------------- + * + * WS_Access -- + * + * Determine if a user with the specified user and group id + * will be able to access the specified file. This routine depends + * on being called with enough permission to stat the file + * (e.g. root). + * + * 'mode' is the bitwise or of R_OK, W_OK, or X_OK. + * + * This call is similar to the POSIX access() call, with extra + * options for specifying the user and group ID to use for + * checking. + * + * Results: + * -1 if no access or error accessing, 0 otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +#define WS_SET_errno(x) errno = x +int WS_Access(const char *path, int mode) +{ + struct stat statBuf; + char **names; + struct group *grp; + struct passwd *usr; + uid_t uid; + gid_t gid; + + uid = geteuid(); + gid = getegid(); + + if(stat(path, &statBuf) < 0) + return -1; + + /* + * If the user owns this file, check the owner bits. + */ + if(uid == statBuf.st_uid) { + WS_SET_errno(EACCES); + if((mode & R_OK) && !(statBuf.st_mode & S_IRUSR)) + goto no_access; + + if((mode & W_OK) && !(statBuf.st_mode & S_IWUSR)) + goto no_access; + + if((mode & X_OK) && !(statBuf.st_mode & S_IXUSR)) + goto no_access; + + return 0; + } + + /* + * If the user's group owns this file, check the group bits. + */ + if(gid == statBuf.st_gid) { + WS_SET_errno(EACCES); + if((mode & R_OK) && !(statBuf.st_mode & S_IRGRP)) + goto no_access; + + if((mode & W_OK) && !(statBuf.st_mode & S_IWGRP)) + goto no_access; + + if((mode & X_OK) && !(statBuf.st_mode & S_IXGRP)) + goto no_access; + + return 0; + } + + /* + * Get the group information for the file group owner. If the + * user is a member of that group, apply the group permissions. + */ + grp = getgrgid(statBuf.st_gid); + if(grp == NULL) + return -1; + + usr = getpwuid(uid); + if(usr == NULL) + return -1; + + for(names = grp->gr_mem; *names != NULL; names++) { + if(!strcmp(*names, usr->pw_name)) { + WS_SET_errno(EACCES); + if((mode & R_OK) && !(statBuf.st_mode & S_IRGRP)) + goto no_access; + + if((mode & W_OK) && !(statBuf.st_mode & S_IWGRP)) + goto no_access; + + if((mode & X_OK) && !(statBuf.st_mode & S_IXGRP)) + goto no_access; + + return 0; + } + } + + /* + * If no matching user or group information, use 'other' + * access information. + */ + if((mode & R_OK) && !(statBuf.st_mode & S_IROTH)) + goto no_access; + + if((mode & W_OK) && !(statBuf.st_mode & S_IWOTH)) + goto no_access; + + if((mode & X_OK) && !(statBuf.st_mode & S_IXOTH)) + goto no_access; + + return 0; + +no_access: + WS_SET_errno(EACCES); + return -1; +} + +#endif /* FCGI_SUPPORT */ diff --git a/src/fcgi.h b/src/fcgi.h new file mode 100644 index 0000000..2b1511c --- /dev/null +++ b/src/fcgi.h @@ -0,0 +1,28 @@ +/************************************************************************ + * FCGI Interface for the NCSA HTTPd Server + * + * Copyright (C) 1995 Open Market, Inc. + * All rights reserved. + * + * This file contains proprietary and confidential information and + * remains the unpublished property of Open Market, Inc. Use, + * disclosure, or reproduction is prohibited except as permitted by + * express written license agreement with Open Market, Inc. + ************************************************************************ + * $Id: fcgi.h,v 1.2 1996/03/25 22:21:30 blong Exp $ + ************************************************************************ + * + * fcgi.c -- interface to FCGI + * + * Trung Dung + * tdung@openmarket.com + * + */ + +#ifndef _FCGI_H +#define _FCGI_H 1 + +/* External Functions */ +int FastCgiHandler(per_request *reqPtr); +char * AppClassCmd(per_host *host, char *arg); +#endif /* _FCGI_H */ diff --git a/src/fdwrap.c b/src/fdwrap.c index ee44ef8..dd33a81 100644 --- a/src/fdwrap.c +++ b/src/fdwrap.c @@ -10,7 +10,7 @@ * ************************************************************************ * - * fdwrap.c,v 1.11 1995/11/28 09:01:44 blong Exp + * fdwrap.c,v 1.15 1996/04/05 18:54:46 blong Exp * ************************************************************************ * @@ -18,14 +18,6 @@ * of open ones and close them when errors happen. Should * make leaks next to impossible. * - * 08-15-95 guillory - * initial code - * - * 08-16-95 blong - * added headers, etc. - * - * 09-07-97 mshapiro - * added includes for / */ #include "config.h" @@ -60,7 +52,7 @@ static int nSize; void fd_error(char *err_msg) { char S[MAX_STRING_LEN]; - sprintf(S,"fdwrap error: %s\n",err_msg); + sprintf(S,"fdwrap error: %s",err_msg); log_error(S,gConfiguration->error_log); exit(1); } @@ -68,7 +60,7 @@ void fd_error(char *err_msg) void fd_warn(char *err_msg) { char S[MAX_STRING_LEN]; - sprintf(S,"fdwrap warn: %s\n",err_msg); + sprintf(S,"fdwrap warn: %s",err_msg); log_error(S,gConfiguration->error_log); } @@ -110,6 +102,7 @@ int GrowTable (int fd) FdTab[ndx].fp = NULL; } nSize = fd + 10; + return 1; } diff --git a/src/host_config.c b/src/host_config.c index 4387ed9..7ea5a38 100644 --- a/src/host_config.c +++ b/src/host_config.c @@ -10,7 +10,7 @@ * ************************************************************************ * - *host_config.c,v 1.15 1995/11/06 20:57:59 blong Exp + *host_config.c,v 1.20 1996/04/05 18:54:47 blong Exp * ************************************************************************ * @@ -28,6 +28,7 @@ #include "http_log.h" #include "http_alias.h" #include "http_mime.h" +#include "http_request.h" #include "util.h" per_host* gConfiguration; @@ -81,7 +82,6 @@ per_host* create_host_conf(per_host *hostInfo, int virtual) { newInfo->doc_errors = hostInfo->doc_errors; newInfo->translations = hostInfo->translations; - /* thanks to Kevin Ruddy (smiles@powerdog.com) for re-teaching me how to make a linked list */ @@ -278,7 +278,10 @@ void which_host_conf(per_request *reqInfo) { while (host && !Found) { if (host->address_info.s_addr == reqInfo->address_info.s_addr) { if (!host->virtualhost && host->called_hostname) { - if (!strcasecmp(called_hostname,host->called_hostname)) Found = TRUE; + if (!strncasecmp(host->called_hostname,reqInfo->inh_called_hostname, + strlen(host->called_hostname))) { + Found = TRUE; + } } else Found = TRUE; } if (!Found) host = host->next; diff --git a/src/http_access.c b/src/http_access.c index b256453..f7a4827 100644 --- a/src/http_access.c +++ b/src/http_access.c @@ -10,21 +10,12 @@ * ************************************************************************ * - * http_access.c,v 1.69 1995/11/28 09:01:48 blong Exp + * http_access.c,v 1.78 1996/04/05 18:54:49 blong Exp * ************************************************************************ * * http_access: Security options etc. * - * Based on NCSA HTTPd 1.3 by Rob McCool - * - * 03-12-95 blong - * Added patch to fix ALLOW_THEN_DENY - * - * 10-02-95 blong - * Added patch by Maurizio Codogno (mau@beatles.cselt.stet.it) to - * allow or deny hosts using a LOCAL keyword which matches all hosts - * without a dot in their name */ @@ -47,12 +38,7 @@ #include "http_mime.h" #include "http_log.h" #include "util.h" - -#ifdef DIGEST_AUTH -int client_accepts_digest; -int assume_digest_support; -#endif /* DIGEST_AUTH */ - +#include "allocate.h" /* * Modified this bad boy so he wouldn't @@ -81,25 +67,28 @@ int in_domain(char *domain, char *what) * Address matching should really be done with subnet masks, though. * mullen@itd.nrl.navy.mil 11/16/95 * - * Forget it, the code didn't work, and we'll just change the docs to - * let everyone know how it really works. + * Returned to normal, as the patch didn't work. For now, I think + * that updating the documenation to say that you have to end in + * a . in order to prohibit other networks is better, as some people + * might like the ability to allow anything that matches 128.174.1 + * blong - 1/26/96 */ int in_ip(char *domain, char *what) { /* int dl=strlen(domain); return (!strncmp(domain,what,dl)) && - (domain[dl-1]=='.' && strlen(what)<=dl && what[dl]=='.'); -*/ - return(!strncmp(domain,what,strlen(domain))); + (domain[dl-1]=='.' && strlen(what)<=dl && what[dl]=='.'); */ + + return(!strncmp(domain,what,strlen(domain))); } -/* find_allow() +/* find_host_allow() * Hunts down list of allowed hosts and returns 1 if allowed, 0 if not * As soon as it finds an allow that matches, it returns 1 */ -int find_allow(per_request *reqInfo, int x) +int find_host_allow(per_request *reqInfo, int x) { register int y; @@ -142,11 +131,11 @@ int find_allow(per_request *reqInfo, int x) return FA_DENY; } -/* find_deny() +/* find_host_deny() * Hunts down list of denied hosts and returns 0 if denied, 1 if not * As soon as it finds a deny that matches, it returns 0 */ -int find_deny(per_request *reqInfo, int x) +int find_host_deny(per_request *reqInfo, int x) { register int y; @@ -191,8 +180,85 @@ int find_deny(per_request *reqInfo, int x) return FA_ALLOW; } +/* match_referer() + * currently matches restriction with sent for only as long as restricted + */ +int match_referer(char *restrict, char *sent) { + return !(strcmp_match(sent,restrict)); +} + +/* find_referer_allow() + * Hunts down list of allowed hosts and returns 1 if allowed, 0 if not + * As soon as it finds an allow that matches, it returns 1 + */ + +int find_referer_allow(per_request *reqInfo, int x) +{ + register int y; + + /* If no allows are specified, then allow */ + if(sec[x].num_referer_allow[reqInfo->method] == 0) + return FA_ALLOW; + + for(y=0;ymethod];y++) { + if(!strcmp("all",sec[x].referer_allow[reqInfo->method][y])) + return FA_ALLOW; +#ifdef LOCALHACK +/* I haven't quite come up with either a reason or a method for + * using the LOCALHACK with referer, so nothing for now. + */ +#endif /* LOCALHACK */ + if(match_referer(sec[x].referer_allow[reqInfo->method][y], + reqInfo->inh_referer)) + { + reqInfo->bSatisfiedReferer = TRUE; + return FA_ALLOW; + } + } + /* Default is to deny */ + return FA_DENY; +} + +/* find_referer_deny() + * Hunts down list of denied hosts and returns 0 if denied, 1 if not + * As soon as it finds a deny that matches, it returns 0 + */ +int find_referer_deny(per_request *reqInfo, int x) +{ + register int y; + + /* If there aren't any denies, then it is allowed + */ + if(sec[x].num_referer_deny[reqInfo->method] == 0) + return FA_ALLOW; + + for(y=0;ymethod];y++) { + if(!strcmp("all",sec[x].referer_deny[reqInfo->method][y])) + { + reqInfo->bSatisfiedReferer = FALSE; + return FA_DENY; + } +#ifdef LOCALHACK +/* I haven't quite come up with either a reason or a method for + * using the LOCALHACK with referer, so nothing for now. + */ +#endif /* LOCALHACK */ + if(match_referer(sec[x].referer_deny[reqInfo->method][y], + reqInfo->inh_referer)) + { + reqInfo->bSatisfiedReferer = FALSE; + return FA_DENY; + } + } + /* Default is to allow */ + reqInfo->bSatisfiedReferer = TRUE; + return FA_ALLOW; +} + + + void check_dir_access(per_request *reqInfo,int x, - int *allow, int *allow_options) + int *allow, int *allow_options, int *other) { if(sec[x].auth_name[0]) reqInfo->auth_name = sec[x].auth_name; @@ -215,32 +281,40 @@ void check_dir_access(per_request *reqInfo,int x, if(sec[x].order[reqInfo->method] == ALLOW_THEN_DENY) { *allow=FA_DENY; - if (find_allow(reqInfo,x) == FA_ALLOW) + if ((find_host_allow(reqInfo,x) == FA_ALLOW) && + (find_referer_allow(reqInfo,x) == FA_ALLOW)) *allow = FA_ALLOW; - if (find_deny(reqInfo,x) == FA_DENY) + if ((find_host_deny(reqInfo,x) == FA_DENY) || + (find_referer_deny(reqInfo,x) == FA_DENY)) *allow = FA_DENY; } else if(sec[x].order[reqInfo->method] == DENY_THEN_ALLOW) { - if (find_deny(reqInfo,x) == FA_DENY) + if ((find_host_deny(reqInfo,x) == FA_DENY) || + (find_referer_deny(reqInfo,x) == FA_DENY)) *allow = FA_DENY; - if (find_allow(reqInfo,x) == FA_ALLOW) + if ((find_host_allow(reqInfo,x) == FA_ALLOW) && + (find_referer_allow(reqInfo,x) == FA_ALLOW)) *allow = FA_ALLOW; } else { /* order == MUTUAL_FAILURE: allowed and not denied */ *allow = FA_DENY; - if ((find_allow(reqInfo,x) == FA_ALLOW) && - !(find_deny(reqInfo,x) == FA_DENY)) + if ((find_host_allow(reqInfo,x) == FA_ALLOW) && + (find_referer_allow(reqInfo,x) == FA_ALLOW) && + !(find_host_deny(reqInfo,x) == FA_DENY) && + !(find_referer_deny(reqInfo,x) == FA_DENY)) *allow = FA_ALLOW; } if(sec[x].num_auth[reqInfo->method]) *allow_options=x; + } void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, char *allow_options) { int will_allow, need_auth, num_dirs; + int need_enhance; char opts[MAX_STRING_LEN], override[MAX_STRING_LEN]; char path[MAX_STRING_LEN], d[MAX_STRING_LEN]; char errstr[MAX_STRING_LEN]; @@ -255,9 +329,10 @@ void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, num_dirs = count_dirs(path); will_allow = FA_ALLOW; need_auth = -1; + need_enhance = -1; - user[0] = '\0'; - groupname[0] = '\0'; + reqInfo->auth_user[0] = '\0'; + reqInfo->auth_group[0] = '\0'; reset_mime_vars(); for(x=0;xmethod]) { + strcpy(reqInfo->outh_location,sec[x].on_deny[reqInfo->method]); } } if((override[n]) || (!(opts[n] & OPT_SYM_LINKS)) || @@ -299,7 +377,7 @@ void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, if(lstat(d,&lfi) != 0) { - sprintf(errstr,"httpd: can't lstat %s, errno = %d",d, errno); + sprintf(errstr,"HTTPd: can't lstat %s, errno = %d",d, errno); log_error(errstr,reqInfo->hostInfo->error_log); *allow=FA_DENY; *allow_options = OPT_NONE; @@ -309,7 +387,7 @@ void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, if(opts[x] & OPT_SYM_OWNER) { if(stat(d,&fi) != 0) { - sprintf(errstr,"httpd: can't stat %s, errno = %d",d, errno); + sprintf(errstr,"HTTPd: can't stat %s, errno = %d",d, errno); log_error(errstr,reqInfo->hostInfo->error_log); *allow=FA_DENY; *allow_options = OPT_NONE; @@ -320,7 +398,7 @@ void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, } else { bong: - sprintf(errstr,"httpd: will not follow link %s",d); + sprintf(errstr,"HTTPd: will not follow link %s",d); log_error(errstr,reqInfo->hostInfo->error_log); *allow=FA_DENY; *allow_options = OPT_NONE; @@ -338,8 +416,14 @@ void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, } if ((sec[y].num_auth[reqInfo->method] > 0) || (sec[y].num_allow[reqInfo->method] > 0) || - (sec[y].num_deny[reqInfo->method] > 0)) - check_dir_access(reqInfo,y,&will_allow,&need_auth); + (sec[y].num_deny[reqInfo->method] > 0) || + (sec[y].num_referer_allow[reqInfo->method] > 0) || + (sec[y].num_referer_deny[reqInfo->method] > 0)) + check_dir_access(reqInfo,y,&will_allow,&need_auth,&need_enhance); + if (!will_allow && sec[y].on_deny[reqInfo->method]) { + strcpy(reqInfo->outh_location, + sec[y].on_deny[reqInfo->method]); + } } } } @@ -349,7 +433,7 @@ void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, struct stat fi,lfi; if(lstat(path,&fi)!=0) { - sprintf(errstr,"httpd: can't lstat %s, errno = %d",path, errno); + sprintf(errstr,"HTTPd: can't lstat %s, errno = %d",path, errno); log_error(errstr,reqInfo->hostInfo->error_log); *allow=FA_DENY; *allow_options = OPT_NONE; @@ -359,7 +443,7 @@ void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, if(opts[n] & OPT_SYM_OWNER) { if(stat(path,&lfi)!=0) { - sprintf(errstr,"httpd: can't stat %s, errno = %d",path, errno); + sprintf(errstr,"HTTPd: can't stat %s, errno = %d",path, errno); log_error(errstr,reqInfo->hostInfo->error_log); *allow=FA_DENY; *allow_options = OPT_NONE; @@ -370,7 +454,7 @@ void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, } else { gong: - sprintf(errstr,"httpd: will not follow link %s",path); + sprintf(errstr,"HTTPd: will not follow link %s",path); log_error(errstr,reqInfo->hostInfo->error_log); *allow=FA_DENY; *allow_options = OPT_NONE; @@ -381,12 +465,12 @@ void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, *allow = will_allow; if(will_allow) { *allow_options = opts[num_dirs-1]; - if ((need_auth >= 0) && !sec[need_auth].bSatisfy) { + if ((need_auth >= 0) && (sec[need_auth].bSatisfy == SATISFY_ALL)) { reqInfo->bSatisfiedDomain = 0; - check_auth(reqInfo,&sec[need_auth], auth_line); + check_auth(reqInfo,&sec[need_auth], reqInfo->inh_auth_line); } - } else if (need_auth >= 0 && sec[need_auth].bSatisfy) { - check_auth(reqInfo,&sec[need_auth], auth_line); + } else if ((need_auth >= 0) && (sec[need_auth].bSatisfy == SATISFY_ANY)) { + check_auth(reqInfo,&sec[need_auth], reqInfo->inh_auth_line); *allow_options = opts[num_dirs-1]; *allow = FA_ALLOW; } @@ -406,6 +490,11 @@ void kill_security(void) free(sec[x].deny[m][y]); for(y=0;y #include #include +#include +#include #ifdef DBM_SUPPORT # ifndef _DBMSUPPORT_H /* moronic OSs which don't protect their own include */ # define _DBMSUPPORT_H /* files from being multiply included */ # include # endif /* _DBMSUPPORT_H */ #endif /* DBM_SUPPORT */ - #ifdef NIS_SUPPORT -#include +# include #endif /* NIS_SUPPORT */ - #if defined(KRB4) || defined(KRB5) # define HAVE_KERBEROS #endif /* defined(KRB4) || defined(KRB5) */ @@ -55,29 +53,25 @@ #ifdef KRB5 # include #endif /* KRB5 */ - #include "constants.h" #include "fdwrap.h" +#include "allocate.h" #include "http_auth.h" #include "http_access.h" #include "http_mime.h" #include "http_config.h" #include "http_log.h" +#include "http_request.h" #include "util.h" #include "digest.h" - -char user[MAX_STRING_LEN]; -char groupname[MAX_STRING_LEN]; - - #ifdef HAVE_KERBEROS #define T 1 #define NIL 0 char* index(); char krb_authreply[2048]; extern char *remote_logname; -extern char out_auth_header[]; +/* extern char out_auth_header[]; */ /* Table for converting binary values to and from hexadecimal */ static char hex[] = "0123456789abcdef"; @@ -108,6 +102,12 @@ AUTH_DAT kerb_kdata; char k5_srvtab[MAX_STRING_LEN] = ""; #endif /* KRB5 */ +#ifdef RADIUS_AUTH +/* Experimental RADIUS authentication + */ +int testpass (char * user, char * clear_pw, char * servername); +#endif /* RADIUS_AUTH */ + #ifdef NIS_SUPPORT int init_nis(char **dom) @@ -220,117 +220,220 @@ int get_pw(per_request *reqInfo, char *user, char *pw, security_data* sec) return 0; } -int in_group(per_request *reqInfo, char *user, - char *group, char* pchGrps -#ifdef DBM_SUPPORT - , DBM* db -#endif /* DBM_SUPPORT */ -) { - char *mems = NULL, *endp = NULL; - char *pch; - char chSaved = '\0'; - int nlen, bFound = 0; - char l[MAX_STRING_LEN]; - int x,start; - - if (reqInfo->auth_grpfile_type == AUTHFILETYPE_STANDARD) { - nlen = strlen (group); - if ((mems = strstr (pchGrps, group)) && *(mems + nlen) == ':') { - if ((endp = strchr (mems + nlen + 1, ':'))) { - while (!isspace(*endp)) endp--; - chSaved = *endp; - *endp = '\0'; - } -/* BUG FIX: Couldn't have the same name as the group as a user because - * failed to move the string beyond the group: +/* in_list() + * Search a comma or space delimited list for a user + * return 0 if not found, 1 if found */ - mems = mems + nlen; - } - else - return 0; +int in_list(char *user, char *list) +{ + int x = 0; + int start = 0; + int Found = 0; + + while(isspace(list[x]) || (list[x] == ',')) + x++; + start = x; + while (!Found && (list[x] != '\0')) { + if ((isspace(list[x]) || (list[x] == ','))) { + Found = !strncmp(user,(list+start),x-start); + start = x+1; + } + x++; } -#ifdef DBM_SUPPORT - else if (reqInfo->auth_grpfile_type == AUTHFILETYPE_DBM) { - datum dtKey, dtRec; + if (!Found && list[x] == '\0' && (x-start > 0)) { + Found = !strncmp(user,(list+start),x-start); + } + + return Found; +} - dtKey.dptr = group; - dtKey.dsize = strlen(group); - dtRec = dbm_fetch(db, dtKey); - if (dtRec.dptr) { - strncpy(l, dtRec.dptr, dtRec.dsize); - l[dtRec.dsize] = '\0'; - mems = l; - } - else - return 0; +/* in_listn() + * Search a comma or space delimited list for a user + * Group list doesn't need to be NULL terminated (for DBM format) + * return 0 if not found, 1 if found + */ +int in_listn(char *user, char *list, int len) +{ + int x = 0; + int start = 0; + int Found = 0; + + while(isspace(list[x]) || (list[x] == ',')) + x++; + start = x; + while (!Found && (list[x] != '\0') && (x < len)) { + if ((isspace(list[x]) || (list[x] == ','))) { + Found = !strncmp(user,(list+start),x-start); + start = x+1; + } + x++; } -#endif /* DBM_SUPPORT */ + if (!Found && ((list[x] == '\0') || (x == len)) && (x-start > 0)) { + Found = !strncmp(user,(list+start),x-start); + } + + return Found; +} + +/* nis_group_lookup() + * Validate a user in an NIS group. Retrieves the group from an NIS database. + * (Default group file is webgroup) + * return 0 on failure, 1 on success + */ #ifdef NIS_SUPPORT - else if (reqInfo->auth_pwfile_type == AUTHFILETYPE_NIS) { +int nis_group_lookup(per_request *reqInfo, char *user, char *group) +{ char *domain, *grfile, *resptr, w[MAX_STRING_LEN]; int yperr, resize; - - if (init_nis(&domain) != 0) - return 0; - + + if (init_nis(&domain) != 0) { + log_error("HTTPd/NIS: init_nis() failed",reqInfo->hostInfo->error_log); + return 0; + } + if (strcmp(reqInfo->auth_grpfile, "+")) grfile = reqInfo->auth_grpfile; else grfile = "webgroup"; - + yperr = yp_match(domain, grfile, group, strlen(group), &resptr, &resize); - if (yperr != 0) - return 0; - + if (yperr != 0) { + sprintf(w,"HTTPd/NIS: yp_match() failed, yperr = %d\n",yperr); + log_error(w,reqInfo->hostInfo->error_log); + return 0; + } + getword(w, resptr, ':'); if (strcmp(w, group) != 0) return 0; - - while (*resptr && isspace(*resptr)) - resptr++; - (void) strcpy(l, resptr); - mems = l; - } -#endif /* NIS_SUPPORT */ - else { - die(reqInfo,SC_SERVER_ERROR,"Invalid group file type"); - return 0; - } - -/* Actually search the group line for the user. Can be comma or space - * delimited - */ - x = 0; - start = 0; - pch = mems; - while (!bFound && (pch[x] != '\0')) { - if ((isspace(pch[x])) || (pch[x] == ',')) { - bFound = !strncmp(user,(pch+start),x-start); - start = x+1; - } - x++; - } - if (!bFound && pch[x] == '\0' && (x-start > 0)) { - bFound = !strncmp(user,(pch+start),x-start); - } + return in_list(user,resptr); +} +#endif /* NIS_SUPPORT */ -/* Buggy, and obfuscated. */ -/* nlen = strlen (user); - nlen = strlen (user); - pch = mems; - while (!bFound && (pch = strstr(pch, user)) && - (!*(pch + nlen) || isspace (*(pch + nlen)) || *(pch + nlen) == ',')) - bFound = 1; -*/ - if (endp && *endp == '\0') *endp = chSaved; - return bFound; +/* dbm_group_lookup() + * Implicitly requires group line not to exceed HUGE_STRING_LEN because + * groups aren't stored with trailing 0. + * Searches open DBM database (db) for keypair with the group name as key + * and returns 0 if user or group not found, 1 if user is in group + */ +#ifdef DBM_SUPPORT +int dbm_group_lookup(per_request *reqInfo, char *user, char *group, DBM *db) +{ + datum dtKey, dtRec; + int Found = 0; + + dtKey.dptr = group; + dtKey.dsize = strlen(group); + dtRec = dbm_fetch(db, dtKey); + if (dtRec.dptr) { + Found = in_listn(user,dtRec.dptr,dtRec.dsize); + } + return Found; +} +#endif /* DBM_SUPPORT */ + +int mind(char *S, char *possible) +{ + int x,y; + for (x = 0; S[x]; x++) + for (y = 0; possible[y]; y++) + if (S[x] == possible[y]) return x; + return -1; } +int eoln(char *S) +{ + int x; + for (x = 0; S[x]; x++) + if (S[x] == '\n') return x; + return x; +} + +int in_group(per_request *reqInfo, char *user, + char *group, char* gfile_mem +#ifdef DBM_SUPPORT + , DBM* db +#endif /* DBM_SUPPORT */ +) +{ + int bFound = FALSE; + int Done = FALSE; + + if (reqInfo->auth_grpfile_type == AUTHFILETYPE_STANDARD) { +/* + char *cur_group = NULL; + char *cur_list = NULL; + cur_group = strtok(gfile_mem,":"); + while (!Done && !bFound) { + cur_list = strtok(NULL,"\n"); + if (!strcmp(group,cur_group)) { + bFound = in_list(user,cur_list); + } + cur_group = strtok(NULL,":"); + if (cur_group == NULL) Done = TRUE; + } +*/ + int beg_line = 0; + int end_line = 0; + int end_grp = 0; + int len = strlen(group); + while (!Done && !bFound) { + end_grp = ind(&gfile_mem[beg_line],':'); + if (end_grp != -1) { + end_line = ind(&gfile_mem[beg_line],'\n'); + if (end_line < 0) { + end_line = strlen(&gfile_mem[beg_line]); + Done = TRUE; + } + if (end_line > end_grp) { + if ((end_grp == len) && + (!strncmp(&gfile_mem[beg_line],group,len))) + { + bFound = in_listn(user,&gfile_mem[beg_line+end_grp+1],end_line - end_grp); + } + } else { + /* hmm, how to handle the backward compat with the bug in 1.5 which + * allowed a group to span multiple lines + */ + } + beg_line += end_line+1; + } else Done = TRUE; + } + } +#ifdef DBM_SUPPORT + else if (reqInfo->auth_grpfile_type == AUTHFILETYPE_DBM) { + bFound = dbm_group_lookup(reqInfo,user,group,db); + } +#endif /* DBM_SUPPORT */ +#ifdef NIS_SUPPORT + else if (reqInfo->auth_grpfile_type == AUTHFILETYPE_NIS) { + bFound = nis_group_lookup(reqInfo,user,group); + } +#endif /* NIS_SUPPORT */ + else { + die(reqInfo,SC_SERVER_ERROR,"Invalid group file type"); + return 0; + } + + return bFound; +} + +#ifdef DEBUG +int fputsn(FILE *fp,char *S,int num) { + int x; + for(x = 0 ; x < num ; x++) + fprintf(fp,"%c",S[x]); +} +#endif /* DEBUG */ + +/* init_group(): loads an entire group file into memory for parsing. + * and returns a pointer to it. + */ char* init_group(per_request *reqInfo,char* grpfile) { FILE *fp; @@ -422,54 +525,64 @@ void check_auth(per_request *reqInfo, security_data *sec, char* auth_line) KerberosInfo kdat; #endif /* HAVE_KERBEROS */ + /* Default to Auth Type Basic */ + if(!sec->auth_type[0]) strcpy(sec->auth_type, "Basic"); + + /* No authorization info, so return the 401 to retrieve it */ if(!auth_line[0]) - auth_bong(reqInfo,NULL, reqInfo->auth_name, sec->auth_type); + auth_bong(reqInfo,NULL, reqInfo->auth_name, sec->auth_type); for (x=0 ; auth_line[x] && (auth_line[x] != ' ') && x < MAX_STRING_LEN; x++) auth_type[x] = auth_line[x]; auth_type[x++] = '\0'; + + /* The authorization in the auth line is not the same which protects this + * directory. + */ if (strcmp(auth_type, sec->auth_type)) auth_bong(reqInfo,"type mismatch",reqInfo->auth_name,sec->auth_type); +/* Basic Authentication */ if(!strcasecmp(sec->auth_type,"Basic")) { if(!reqInfo->auth_name) { - sprintf(errstr,"httpd: need AuthName for %s",sec->d); + sprintf(errstr,"HTTPd: need AuthName for %s",sec->d); die(reqInfo,SC_SERVER_ERROR,errstr); } if(!reqInfo->auth_pwfile) { - sprintf(errstr,"httpd: need AuthUserFile for %s",sec->d); + sprintf(errstr,"HTTPd: need AuthUserFile for %s",sec->d); die(reqInfo,SC_SERVER_ERROR,errstr); } uudecode(auth_line + strlen(auth_type),(unsigned char *)ad,MAX_STRING_LEN); - getword(user,ad,':'); + getword(reqInfo->auth_user,ad,':'); strcpy(sent_pw,ad); - if(!get_pw(reqInfo,user,real_pw,sec)) { - sprintf(errstr,"user %s not found",user); + if(!get_pw(reqInfo,reqInfo->auth_user,real_pw,sec)) { + sprintf(errstr,"user %s not found",reqInfo->auth_user); auth_bong(reqInfo,errstr,reqInfo->auth_name,sec->auth_type); } /* anyone know where the prototype for crypt is? */ /* Yeah, in unistd.h on most systems, it seems */ if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) { - sprintf(errstr,"user %s: password mismatch",user); + sprintf(errstr,"user %s: password mismatch",reqInfo->auth_user); auth_bong(reqInfo,errstr,reqInfo->auth_name,sec->auth_type); } } +/* End Basic Authentication */ #ifdef DIGEST_AUTH else if(!strcasecmp(sec->auth_type,"Digest")) { if(!reqInfo->auth_name) { - sprintf(errstr,"httpd: need AuthName for %s",sec->d); + sprintf(errstr,"HTTPd: need AuthName for %s",sec->d); die(reqInfo,SC_SERVER_ERROR,errstr); } if(!sec->auth_digestfile) { - sprintf(errstr,"httpd: need AuthDigestFile for %s",sec->d); + sprintf(errstr,"HTTPd: need AuthDigestFile for %s",sec->d); die(reqInfo,SC_SERVER_ERROR,errstr); } - Digest_Check(reqInfo,user, sec); + Digest_Check(reqInfo,reqInfo->auth_user, sec); } #endif /* DIGEST_AUTH */ #ifdef HAVE_KERBEROS @@ -501,9 +614,8 @@ void check_auth(per_request *reqInfo, security_data *sec, char* auth_line) if (krbresult) { if (check_krb_restrict(reqInfo, sec, &kdat)) { - remote_logname = user; - out_auth_header[0] = '\0'; - sprintf(out_auth_header, "WWW-Authenticate: %s %s\r\n", + remote_logname = reqInfo->auth_user; + sprintf(reqInfo->outh_www_auth,"%s %s", sec->auth_type, krb_authreply); return; } @@ -557,7 +669,7 @@ void check_auth(per_request *reqInfo, security_data *sec, char* auth_line) t[y] = t[y+1]; } getword(w,t,' '); - if(!strcmp(user,w)) { + if(!strcmp(reqInfo->auth_user,w)) { bValid = 1; break; } @@ -572,11 +684,11 @@ void check_auth(per_request *reqInfo, security_data *sec, char* auth_line) while (t[0]) { getword(w,t,' '); #ifdef DBM_SUPPORT - if (in_group(reqInfo,user,w, pchGrpData, db)) { + if (in_group(reqInfo,reqInfo->auth_user,w, pchGrpData, db)) { #else - if (in_group(reqInfo,user,w, pchGrpData)) { + if (in_group(reqInfo,reqInfo->auth_user,w, pchGrpData)) { #endif /* DBM_SUPPORT */ - strcpy(groupname,w); + strcpy(reqInfo->auth_group,w); bValid = 1; break; } @@ -597,12 +709,11 @@ void check_auth(per_request *reqInfo, security_data *sec, char* auth_line) } /* if we didn't validate the user */ if (!bValid) { - sprintf(errstr,"user %s denied",user); + sprintf(errstr,"user %s denied",reqInfo->auth_user); auth_bong(reqInfo,errstr,reqInfo->auth_name,sec->auth_type); } } - #ifdef HAVE_KERBEROS /************************************************************************* @@ -983,6 +1094,3 @@ int krb_in_group(KerberosInfo* kdat, char *group, char* pchGrps) } #endif /* HAVE_KERBEROS */ - - - diff --git a/src/http_auth.h b/src/http_auth.h index 99f61d1..80ce336 100644 --- a/src/http_auth.h +++ b/src/http_auth.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * http_auth.h,v 1.20 1995/07/25 14:48:05 blong Exp + * http_auth.h,v 1.22 1996/03/27 20:43:57 blong Exp * ************************************************************************ * @@ -25,11 +25,10 @@ # include # endif /* _DBMSUPPORT_H */ #endif /* DBM_SUPPORT */ +#include "global.h" /* globals defined in this module */ -extern char user[]; -extern char groupname[]; /* http_auth */ @@ -44,8 +43,6 @@ int in_group(per_request *reqInfo, char *user, char *group, char* pchGrps); char* init_group(per_request *reqInfo,char* grpfile); void auth_bong(per_request *reqInfo,char *s,char* auth_name, char* auth_type); - - #if defined(KRB4) || defined(KRB5) typedef struct _krbdata { char client_name[MAX_STRING_LEN]; @@ -72,5 +69,4 @@ extern char k5_srvtab[]; int k5_server_auth(char* authline, char* reply, KerberosInfo *kdat); #endif /* KRB5 */ - #endif /* _HTTP_AUTH_H_ */ diff --git a/src/http_config.c b/src/http_config.c index 2d77c3f..e40def1 100644 --- a/src/http_config.c +++ b/src/http_config.c @@ -13,39 +13,6 @@ * http_config.c: auxillary functions for reading httpd's config file * and converting filenames into a namespace * - * Based on NCSA HTTPd 1.3 by Rob McCool - * - * 10/28/94 cvarela - * Added config options AgentLog and RefererLog for extra log info - * - * 02/19/95 blong - * Added config options MaxServers and StartServers for configuration - * defined children - * - * 03/21/95 cvarela - * Added RefererIgnore to ignore certain URIs when logging referers - * - * 06/01/95 blong - * Added patch by Conrad Damon (damon@netserver.stanford.edu) that - * avoids a cfg_getline loop if a user sets a directory as a password - * file. - * - * 09/02/95 blong - * Added patch by Kevin Ruddy (kevin.ruddy@powerdog.com) that should - * allow systems which don't recognize a numeric address to gethostbyname - * to use a numeric IP in the BindAddress and VirtualHost fields - * - * 09/10/95 mshapiro - * Added includes for and - * 09/18/95 mshapiro - * Added LogDirGroupWriteOk, LogDirPublicWriteOk - * directives - * 10/06/95 blong - * Added patch by Elf Sternberg (elf@aaden.spry.com) to configure - * the process name which SETPROCTITLE uses - * 10/06/95 blong - * Added patch by Nathan Neulinger (nneul@umr.edu) to have separate - * security permissions for Redirect in .htaccess files */ @@ -67,6 +34,8 @@ #include #include #include +#include +#include #include #include "constants.h" #include "fdwrap.h" @@ -78,8 +47,10 @@ #include "http_log.h" #include "http_dir.h" #include "util.h" -#include -#include +#ifdef FCGI_SUPPORT +# include "fcgi.h" /* for AppClassCmd() */ +#endif /* FCGI_SUPPORT */ + /* Server config globals */ @@ -191,8 +162,6 @@ void set_defaults(per_host *host, FILE *errors) timeout = DEFAULT_TIMEOUT; do_rfc931 = DEFAULT_RFC931; - /* Necessary with new configuration stuff? */ - /* default resource config stuff */ set_host_conf(host,PH_SRM_CONF,SRM_USER_DIR,DEFAULT_USER_DIR); set_host_conf(host,PH_SRM_CONF,SRM_INDEX_NAMES,DEFAULT_INDEX_NAMES); @@ -486,11 +455,9 @@ void process_server_config(per_host *host, FILE *cfg, FILE *errors, } #ifdef DIGEST_AUTH else if(!strcasecmp(w,"AssumeDigestSupport")) { - cfg_getword(w,l); - if(!strcmp(w,"on")) - assume_digest_support = TRUE; - else - assume_digest_support = FALSE; + /* Doesn't do anything anymore, but if we take it out, anyone with + * it in their configuration files would complain. *sigh* + */ } #endif /* DIGEST_AUTH */ else if(((!strcasecmp(w,"srm_confname,n,errors); config_warn("OldScriptAlias directive obsolete, ignored", host->srm_confname,n,errors); } +#ifdef FCGI_SUPPORT + else if(!strcasecmp(w,"FCGIScriptAlias")) { + cfg_getword(w,l); + cfg_getword(w2,l); + if((w[0] == '\0') || (w2[0] == '\0')) { + config_error( +"FCGIScriptAlias must be followed by a fakename, one space, then a realname", +host->srm_confname,n,errors); + } + if (!set_host_conf_value(host,PH_SRM_CONF,SRM_TRANSLATIONS)) { + host->translations = NULL; + } + add_alias(host,w,w2,A_SCRIPT_FCGI); + } + else if(!strcasecmp(w,"AppClass")) { + char *result; + if (!set_host_conf_value(host,PH_SRM_CONF,SRM_TRANSLATIONS)) { + host->translations = NULL; + } + result = AppClassCmd(host, l); + if (result) + config_error(result, host->srm_confname, n, errors); + } +#endif /* FCGI_SUPPORT */ else if(!strcasecmp(w,"UserDir")) { cfg_getword(w,l); if(!strcmp(w,"DISABLED")) @@ -655,11 +646,18 @@ host->srm_confname,n,errors); else if(!strcasecmp(w,"Redirect") || !strcasecmp(w,"RedirectTemp")) { cfg_getword(w,l); cfg_getword(w2,l); - if((w[0] == '\0') || (w2[0] == '\0') || (!is_url(w2))) { + if((w[0] == '\0') || (w2[0] == '\0') || + !(is_url(w2) || (w2[0] == '/'))) + { config_error( "Redirect must be followed by a document, one space, then a URL", host->srm_confname,n,errors); } + if (w2[0] == '/') { + char w3[MAX_STRING_LEN]; + construct_url(w3,host,w2); + strcpy(w2,w3); + } if (!set_host_conf_value(host,PH_SRM_CONF,SRM_TRANSLATIONS)) { host->translations = NULL; } @@ -668,7 +666,9 @@ host->srm_confname,n,errors); else if(!strcasecmp(w,"RedirectPermanent")) { cfg_getword(w,l); cfg_getword(w2,l); - if((w[0] == '\0') || (w2[0] == '\0') || (!is_url(w2))) { + if((w[0] == '\0') || (w2[0] == '\0') || + !(is_url(w2) || (w2[0] == '/'))) + { config_error( "RedirectPermanent must be followed by a document, one space, then a URL", host->srm_confname,n,errors); @@ -676,6 +676,11 @@ host->srm_confname,n,errors); if (!set_host_conf_value(host,PH_SRM_CONF,SRM_TRANSLATIONS)) { host->translations = NULL; } + if (w2[0] == '/') { + char w3[MAX_STRING_LEN]; + construct_url(w3,host,w2); + strcpy(w2,w3); + } add_redirect(host,w,w2,A_REDIRECT_PERM); } else if(!strcasecmp(w,"FancyIndexing")) { @@ -806,7 +811,7 @@ void access_syntax_error(per_request *reqInfo, int n, char *err, FILE *fp, else { char e[MAX_STRING_LEN]; FClose(fp); - sprintf(e,"httpd: syntax error or override violation in access control file %s, reason: %s",file,err); + sprintf(e,"HTTPd: syntax error or override violation in access control file %s, reason: %s",file,err); die(reqInfo,SC_SERVER_ERROR,e); } } @@ -821,6 +826,10 @@ int parse_access_dir(per_request *reqInfo, FILE *f, int line, char or, register int x,i; x = num_sec; + if (num_sec > MAX_SECURITY) + access_syntax_error(reqInfo,n, + "Too many security entries, increase MAX_SECURITY and recompile", + f,file); sec[x].opts=OPT_UNSET; sec[x].override = or; @@ -842,7 +851,10 @@ int parse_access_dir(per_request *reqInfo, FILE *f, int line, char or, sec[x].order[i] = DENY_THEN_ALLOW; sec[x].num_allow[i]=0; sec[x].num_deny[i]=0; + sec[x].num_referer_allow[i]=0; + sec[x].num_referer_deny[i]=0; sec[x].num_auth[i] = 0; + sec[x].on_deny[i] = NULL; } while(!(cfg_getline(l,MAX_STRING_LEN,f))) { @@ -1087,18 +1099,38 @@ int parse_access_dir(per_request *reqInfo, FILE *f, int line, char or, access_syntax_error(reqInfo,n,"override violation",f,file); cfg_getword(w,l); cfg_getword(w2,l); - if((w[0] == '\0') || (w2[0] == '\0') || (!is_url(w2))) { + if((w[0] == '\0') || (w2[0] == '\0') || + !(is_url(w2) || (w2[0] == '/'))) + { access_syntax_error(reqInfo,n, "Redirect must be followed by a document, one space, then a URL.",f,file); - } + } if(!file) { + if (w2[0] == '/') { + char w3[MAX_STRING_LEN]; + construct_url(w3,gConfiguration,w2); + strcpy(w2,w3); + } if (!set_host_conf_value(gConfiguration,PH_SRM_CONF,SRM_TRANSLATIONS)) { gConfiguration->translations = NULL; } add_redirect(gConfiguration,w,w2,A_REDIRECT_TEMP); } else { - if (!strcmp(reqInfo->url,w)) { + char tmp[HUGE_STRING_LEN]; + int len; + if (w2[0] == '/') { + construct_url(tmp,reqInfo->hostInfo,w2); + strcpy(w2,tmp); + } + strcpy(tmp,reqInfo->url); + if (reqInfo->path_info[0]) { + len = strlen(reqInfo->url); + if (reqInfo->url[len-1] == '/') + reqInfo->url[len-1] = '\0'; + strcat(tmp,reqInfo->path_info); + } + if (!strcmp(tmp,w) || !strcmp_match(tmp,w)) { FClose(f); die(reqInfo,SC_REDIRECT_TEMP,w2); } @@ -1109,20 +1141,40 @@ int parse_access_dir(per_request *reqInfo, FILE *f, int line, char or, access_syntax_error(reqInfo,n,"override violation",f,file); cfg_getword(w,l); cfg_getword(w2,l); - if((w[0] == '\0') || (w2[0] == '\0') || (!is_url(w2))) { + if((w[0] == '\0') || (w2[0] == '\0') || + !(is_url(w2) || (w2[0] == '/'))) + { access_syntax_error(reqInfo,n, "Redirect must be followed by a document, one space, then a URL.",f,file); } if(!file) { + if (w2[0] == '/') { + char w3[MAX_STRING_LEN]; + construct_url(w3,gConfiguration,w2); + strcpy(w2,w3); + } if (!set_host_conf_value(gConfiguration,PH_SRM_CONF,SRM_TRANSLATIONS)) { gConfiguration->translations = NULL; } add_redirect(gConfiguration,w,w2,A_REDIRECT_PERM); } else { - if (!strcmp(reqInfo->url,w)) { + char tmp[HUGE_STRING_LEN]; + int len; + if (w2[0] == '/') { + construct_url(tmp,reqInfo->hostInfo,w2); + strcpy(w2,tmp); + } + strcpy(tmp,reqInfo->url); + if (reqInfo->path_info[0]) { + len = strlen(reqInfo->url); + if (reqInfo->url[len-1] == '/') + reqInfo->url[len-1] = '\0'; + strcat(tmp,reqInfo->path_info); + } + if (!strcmp(tmp,w) || !strcmp_match(tmp,w)) { FClose(f); - die(reqInfo,SC_REDIRECT_PERM,w2); + die(reqInfo,SC_REDIRECT_TEMP,w2); } } } @@ -1180,15 +1232,65 @@ int parse_access_dir(per_request *reqInfo, FILE *f, int line, char or, for(i=0;i= MAX_SECURITY) + access_syntax_error(reqInfo,n, + "Too many allow entries, increase MAX_SECURITY and recompile", + f,file); if(!(sec[x].allow[i][q] = strdup(w))) die(reqInfo,SC_NO_MEMORY,"parse_access_dir"); } } } + else if(!strcasecmp(w,"referer")) { + int ref_type; + + cfg_getword(w,l); + if(!strcmp(w,"allow")) { + ref_type = FA_ALLOW; + } else if (!strcmp(w,"deny")) { + ref_type = FA_DENY; + } else access_syntax_error(reqInfo,n, + "unknown referer type.", + f,file); + cfg_getword(w,l); + if(strcmp(w,"from")) + access_syntax_error(reqInfo,n, + "allow/deny must be followed by from.", + f,file); + while(1) { + cfg_getword(w,l); + if (!w[0]) break; + for(i=0;i= MAX_SECURITY) + access_syntax_error(reqInfo,n, + "Too many referer allow entries, increase MAX_SECURITY and recompile", + f,file); + if(!(sec[x].referer_allow[i][q] = strdup(w))) + die(reqInfo,SC_NO_MEMORY,"parse_access_dir"); + } else if (ref_type == FA_DENY) { + q=sec[x].num_referer_deny[i]++; + if (q >= MAX_SECURITY) + access_syntax_error(reqInfo,n, + "Too many referer deny entries, increase MAX_SECURITY and recompile", + f,file); + if(!(sec[x].referer_deny[i][q] = strdup(w))) + die(reqInfo,SC_NO_MEMORY,"parse_access_dir"); + } + } + } + } else if(!strcasecmp(w,"require")) { for(i=0;i= MAX_SECURITY) + access_syntax_error(reqInfo,n, + "Too many require entries, increase MAX_SECURITY and recompile", + f,file); if(!(sec[x].auth[i][q] = strdup(l))) die(reqInfo,SC_NO_MEMORY,"parse_access_dir"); } @@ -1205,6 +1307,10 @@ int parse_access_dir(per_request *reqInfo, FILE *f, int line, char or, for(i=0;i= MAX_SECURITY) + access_syntax_error(reqInfo,n, + "Too many deny entries, increase MAX_SECURITY and recompile", + f,file); if(!(sec[x].deny[i][q] = strdup(w))) die(reqInfo,SC_NO_MEMORY,"parse_access_dir"); } @@ -1221,6 +1327,13 @@ int parse_access_dir(per_request *reqInfo, FILE *f, int line, char or, "Satisfy either any or all.", f,file); } + else if(!strcasecmp(w,"OnDeny")) { + for(i=0;i - * to fix missing trailing slash for parent directory */ @@ -41,15 +35,16 @@ #include #include #include "constants.h" +#include "http_request.h" #include "http_dir.h" #include "http_mime.h" #include "http_log.h" #include "http_config.h" -#include "http_request.h" #include "http_send.h" #include "http_alias.h" #include "util.h" #include "fdwrap.h" +#include "allocate.h" /* Split each item list into two lists, the 0-th entry holds items which * are valid over this request while the 1-st entry for those valids for @@ -62,21 +57,21 @@ static struct item *hdr_list[2], *rdme_list[2], *opts_list[2]; static int dir_opts; void init_indexing(int local) { - icon_list[0] = NULL; - alt_list[0] = NULL; - desc_list[0] = NULL; - ign_list[0] = NULL; - hdr_list[0] = NULL; - rdme_list[0] = NULL; - opts_list[0] = NULL; + icon_list[FI_LOCAL] = NULL; + alt_list[FI_LOCAL] = NULL; + desc_list[FI_LOCAL] = NULL; + ign_list[FI_LOCAL] = NULL; + hdr_list[FI_LOCAL] = NULL; + rdme_list[FI_LOCAL] = NULL; + opts_list[FI_LOCAL] = NULL; if (local == FI_GLOBAL) { - icon_list[1] = NULL; - alt_list[1] = NULL; - desc_list[1] = NULL; - ign_list[1] = NULL; - hdr_list[1] = NULL; - rdme_list[1] = NULL; - opts_list[1] = NULL; + icon_list[FI_GLOBAL] = NULL; + alt_list[FI_GLOBAL] = NULL; + desc_list[FI_GLOBAL] = NULL; + ign_list[FI_GLOBAL] = NULL; + hdr_list[FI_GLOBAL] = NULL; + rdme_list[FI_GLOBAL] = NULL; + opts_list[FI_GLOBAL] = NULL; } } @@ -262,38 +257,48 @@ char *find_item(per_request *reqInfo, struct item *list[2], char *path, { struct item *p = NULL; int i; + char *file_type,*file_encoding; + + file_type = newString(MAX_STRING_LEN,STR_TMP); + file_encoding = newString(MAX_STRING_LEN,STR_TMP); for (i=0; i < 2; i++) { for (p = list[i]; p; p = p->next) { /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */ if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) { - if(!(p->apply_to)) - return p->data; + if(!(p->apply_to)) + goto found_item; else if(p->type == BY_PATH) { if(!strcmp_match(path,p->apply_to)) - return p->data; + goto found_item; } else if(!path_only) { char pathbak[MAX_STRING_LEN]; strcpy(pathbak,path); - content_encoding[0] = '\0'; - set_content_type(reqInfo,pathbak); - if(!content_encoding[0]) { + get_content_type(reqInfo,pathbak,file_type,file_encoding); + if(!file_encoding[0]) { if(p->type == BY_TYPE) { - if(!strcmp_match(content_type,p->apply_to)) - return p->data; + if(!strcmp_match(file_type,p->apply_to)) + goto found_item; } } else { if(p->type == BY_ENCODING) { - if(!strcmp_match(content_encoding,p->apply_to)) - return p->data; + if(!strcmp_match(file_encoding,p->apply_to)) + goto found_item; } } } } } } + freeString(file_type); + freeString(file_encoding); return NULL; + + found_item: + freeString(file_type); + freeString(file_encoding); + return p->data; } #define find_icon(r,p,t) find_item(r,icon_list,p,t) @@ -342,16 +347,15 @@ int insert_readme(per_request *reqInfo, char *name, if(stat(fn,&finfo) == -1) return 0; plaintext=1; - if(rule) reqInfo->bytes_sent += fprintf(reqInfo->out,"
%c",LF); - reqInfo->bytes_sent += fprintf(reqInfo->out,"
%c",LF);
+        if(rule) rprintf(reqInfo,"
%c",LF); + rprintf(reqInfo,"
%c",LF);
     }
-    else if(rule) reqInfo->bytes_sent += fprintf(reqInfo->out,"
%c",LF); + else if(rule) rprintf(reqInfo,"
%c",LF); if(!(r = FOpen(fn,"r"))) return 0; send_fp(reqInfo,r,NULL); FClose(r); - if(plaintext) - reqInfo->bytes_sent += fprintf(reqInfo->out,"
%c",LF); + if(plaintext) rprintf(reqInfo,"
%c",LF); return 1; } @@ -361,15 +365,18 @@ char *find_title(per_request *reqInfo, char *filename) { char filebak[MAX_STRING_LEN]; FILE *thefile; int x,y,n,p; + char *file_type, *file_encoding; + + file_type = newString(MAX_STRING_LEN,STR_TMP); + file_encoding = newString(MAX_STRING_LEN,STR_TMP); - content_encoding[0] = '\0'; strcpy(filebak,filename); - set_content_type(reqInfo,filebak); - if(((!strcmp(content_type,"text/html")) || - (strcmp(content_type, INCLUDES_MAGIC_TYPE) == 0)) - && (!content_encoding[0])) { + get_content_type(reqInfo,filebak,file_type,file_encoding); + if(((!strcmp(file_type,"text/html")) || + (strcmp(file_type, INCLUDES_MAGIC_TYPE) == 0)) + && (!file_encoding[0])) { if(!(thefile = FOpen(filename,"r"))) - return NULL; + goto not_found; n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile); titlebuf[n] = '\0'; for(x=0,p=0;titlebuf[x];x++) { @@ -382,14 +389,17 @@ char *find_title(per_request *reqInfo, char *filename) { if((titlebuf[y] == CR) || (titlebuf[y] == LF)) titlebuf[y] = ' '; FClose(thefile); + freeString(file_type); + freeString(file_encoding); return strdup(&titlebuf[x]); } } else p=0; } FClose(thefile); - return NULL; } - content_encoding[0] = '\0'; + not_found: + freeString(file_type); + freeString(file_encoding); return NULL; } @@ -454,9 +464,10 @@ struct ent *make_dir_entry(per_request *reqInfo, char *path, p->alt = NULL; p->desc = NULL; if(S_ISDIR(finfo.st_mode)) { - if(!(p->icon = find_icon(reqInfo,t,1))) + if(!(p->icon = find_icon(reqInfo,t,1))) { if (p->icon != NULL) free(p->icon); p->icon = find_icon(reqInfo,"^^DIRECTORY^^",1); + } if(!(tmp = find_alt(reqInfo,t,1))){ p->alt = (char *) malloc(sizeof(char)*4); strcpy(p->alt,"DIR"); @@ -495,22 +506,19 @@ struct ent *make_dir_entry(per_request *reqInfo, char *path, void send_size(per_request *reqInfo, size_t size) { if(size == -1) { - fputs(" -",reqInfo->out); - reqInfo->bytes_sent += 5; + rputs(" -",reqInfo); } else { if(!size) { - fputs(" 0K",reqInfo->out); - reqInfo->bytes_sent += 5; + rputs(" 0K",reqInfo); } else if(size < 1024) { - fputs(" 1K",reqInfo->out); - reqInfo->bytes_sent += 5; + rputs(" 1K",reqInfo); } else if(size < 1048576) - reqInfo->bytes_sent += fprintf(reqInfo->out,"%4dK",size / 1024); + rprintf(reqInfo,"%4dK",size / 1024); else - reqInfo->bytes_sent += fprintf(reqInfo->out,"%4dM",size / 1048576); + rprintf(reqInfo,"%4dM",size / 1048576); } } @@ -550,30 +558,28 @@ void output_directories(per_request *reqInfo, struct ent **ar,int n,char *name) name[0] = '/'; name[1] = '\0'; } /* aaaaargh Solaris sucks. */ - fflush(reqInfo->out); + rflush(reqInfo); if(dir_opts & FANCY_INDEXING) { - fputs("
",reqInfo->out);
-        (reqInfo->bytes_sent) += 5;
+        rputs("
",reqInfo);
         if((tp = find_icon(reqInfo,"^^BLANKICON^^",1)))
-            reqInfo->bytes_sent += (fprintf(reqInfo->out,
-				   "\" ",tp));
-        reqInfo->bytes_sent += fprintf(reqInfo->out,"Name                   ");
+            rprintf(reqInfo,"\" ",tp);
+        rprintf(reqInfo,"Name                   ");
         if(!(dir_opts & SUPPRESS_LAST_MOD))
-            reqInfo->bytes_sent += fprintf(reqInfo->out,"Last modified     ");
+            rprintf(reqInfo,"Last modified     ");
         if(!(dir_opts & SUPPRESS_SIZE))
-            reqInfo->bytes_sent += fprintf(reqInfo->out,"Size  ");
+            rprintf(reqInfo,"Size  ");
         if(!(dir_opts & SUPPRESS_DESC))
-            reqInfo->bytes_sent += fprintf(reqInfo->out,"Description");
-        reqInfo->bytes_sent += fprintf(reqInfo->out,"%c
%c",LF,LF); + rprintf(reqInfo,"Description"); + rprintf(reqInfo,"%c
%c",LF,LF); } else { - fputs("
    ",reqInfo->out); - reqInfo->bytes_sent += 4; + rputs("
      ",reqInfo); } for(x=0;xname,"../")) || (!strcmp(ar[x]->name,".."))) { + int i; /* Fixes trailing slash for fancy indexing. Thanks Roy ? */ make_full_path(name,"../",t); @@ -581,6 +587,10 @@ void output_directories(per_request *reqInfo, struct ent **ar,int n,char *name) if(t[0] == '\0') { t[0] = '/'; t[1] = '\0'; } + i = strlen(t); + if(t[i-1] != '/') { + t[i-1] = '/'; t[i] = '\0'; + } escape_uri(t); sprintf(anchor,"",t); strcpy(t2,"Parent Directory"); @@ -602,59 +612,51 @@ void output_directories(per_request *reqInfo, struct ent **ar,int n,char *name) if(dir_opts & FANCY_INDEXING) { if(dir_opts & ICONS_ARE_LINKS) - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",anchor); + rprintf(reqInfo,"%s",anchor); if((ar[x]->icon) || reqInfo->hostInfo->default_icon[0] || local_default_icon[0]) { - reqInfo->bytes_sent += fprintf(reqInfo->out, - "\"[%s]\"", - ar[x]->icon ? ar[x]->icon : - local_default_icon[0] ? - local_default_icon : - reqInfo->hostInfo->default_icon, - ar[x]->alt ? ar[x]->alt : " "); + rprintf(reqInfo,"\"[%s]\"", + ar[x]->icon ? ar[x]->icon : + local_default_icon[0] ? + local_default_icon : + reqInfo->hostInfo->default_icon, + ar[x]->alt ? ar[x]->alt : " "); } if(dir_opts & ICONS_ARE_LINKS) { - fputs("",reqInfo->out); - reqInfo->bytes_sent += 4; + rputs("",reqInfo); } - reqInfo->bytes_sent += fprintf(reqInfo->out," %s",anchor); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%-27.27s",t2); + rprintf(reqInfo," %s",anchor); + rprintf(reqInfo,"%-27.27s",t2); if(!(dir_opts & SUPPRESS_LAST_MOD)) { if(ar[x]->lm != -1) { struct tm *ts = localtime(&ar[x]->lm); strftime(t,MAX_STRING_LEN,"%d-%b-%y %H:%M ",ts); - fputs(t,reqInfo->out); - reqInfo->bytes_sent += strlen(t); + rputs(t,reqInfo); } else { - fputs(" ",reqInfo->out); - reqInfo->bytes_sent += 17; + rputs(" ",reqInfo); } } if(!(dir_opts & SUPPRESS_SIZE)) { send_size(reqInfo,ar[x]->size); - fputs(" ",reqInfo->out); - reqInfo->bytes_sent += 2; + rputs(" ",reqInfo); } if(!(dir_opts & SUPPRESS_DESC)) { if(ar[x]->desc) { terminate_description(ar[x]->desc); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",ar[x]->desc); + rprintf(reqInfo,"%s",ar[x]->desc); } } } else - reqInfo->bytes_sent += fprintf(reqInfo->out,"
    • %s %s",anchor,t2); - fputc(LF,reqInfo->out); - ++(reqInfo->bytes_sent); + rprintf(reqInfo,"
    • %s %s",anchor,t2); + rputc(LF,reqInfo); } if(dir_opts & FANCY_INDEXING) { - fputs("
",reqInfo->out); - reqInfo->bytes_sent += 6; + rputs("
",reqInfo); } else { - fputs("",reqInfo->out); - reqInfo->bytes_sent += 5; + rputs("",reqInfo); } } @@ -678,12 +680,13 @@ void index_directory(per_request *reqInfo) if(!(d=Opendir(reqInfo->filename))) die(reqInfo,SC_FORBIDDEN,reqInfo->url); - strcpy(content_type,"text/html"); - if(!no_headers) + strcpy(reqInfo->outh_content_type,"text/html"); + if(reqInfo->http_version != P_HTTP_0_9) send_http_header(reqInfo); - if(header_only) { + if(reqInfo->method == M_HEAD) { Closedir(d); + log_transaction(reqInfo); return; } @@ -692,16 +695,13 @@ void index_directory(per_request *reqInfo) dir_opts = find_opts(reqInfo->filename); /* Spew HTML preamble */ - reqInfo->bytes_sent += fprintf(reqInfo->out, - "Index of %s", + rprintf(reqInfo,"Index of %s", reqInfo->url); - fputc(LF,reqInfo->out); - ++(reqInfo->bytes_sent); + rputc(LF,reqInfo); if((!(tmp = find_header(reqInfo, reqInfo->filename))) || (!(insert_readme(reqInfo,reqInfo->filename,tmp,0)))) - reqInfo->bytes_sent += fprintf(reqInfo->out, - "

Index of %s

%c",reqInfo->url,LF); + rprintf(reqInfo, "

Index of %s

%c",reqInfo->url,LF); /* * Since we don't know how many dir. entries there are, put them into a @@ -750,13 +750,10 @@ void index_directory(per_request *reqInfo) if((tmp = find_readme(reqInfo,reqInfo->filename))) insert_readme(reqInfo,reqInfo->filename,tmp,1); else { - fputs("",reqInfo->out); - reqInfo->bytes_sent += 5; + rputs("",reqInfo); } - fputs("", reqInfo->out); - fflush(reqInfo->out); - reqInfo->bytes_sent += 7; - fflush(reqInfo->out); + rputs("", reqInfo); + rflush(reqInfo); log_transaction(reqInfo); } diff --git a/src/http_include.c b/src/http_include.c index 4edd6d6..3960968 100644 --- a/src/http_include.c +++ b/src/http_include.c @@ -10,7 +10,7 @@ * ************************************************************************ * - * http_include.c,v 1.41 1995/11/28 09:02:02 blong Exp + * http_include.c,v 1.50 1996/03/27 20:44:02 blong Exp * ************************************************************************ * @@ -18,9 +18,6 @@ * * Based on NCSA HTTPd 1.3 by Rob McCool * - * 04-07-95 blong - * Fixes bug where substrings of the environment variable might be - * included first as suggested by David Robinson (drtr@ast.cam.ac.uk) */ @@ -41,6 +38,7 @@ #include #include "constants.h" #include "fdwrap.h" +#include "allocate.h" #include "http_include.h" #include "http_mime.h" #include "http_log.h" @@ -62,8 +60,10 @@ static time_t date,lm; int add_include_vars(per_request *reqInfo, char *timefmt) { struct stat finfo; - char uri[HUGE_STRING_LEN]; - char *t; + char *uri; + char *str; + + uri = newString(HUGE_STRING_LEN,STR_TMP); date = time(NULL); make_env_str(reqInfo,"DATE_LOCAL",ht_time(date,timefmt,0)); @@ -73,23 +73,24 @@ int add_include_vars(per_request *reqInfo, char *timefmt) lm = finfo.st_mtime; make_env_str(reqInfo,"LAST_MODIFIED",ht_time(lm,timefmt,0)); } - if((t = strrchr(reqInfo->filename,'/'))) - ++t; + if((str = strrchr(reqInfo->filename,'/'))) + ++str; else - t = reqInfo->url; - make_env_str(reqInfo,"DOCUMENT_NAME",t); + str = reqInfo->url; + make_env_str(reqInfo,"DOCUMENT_NAME",str); /* Jump through hoops because <=1.4 set DOCUMENT_URI to include index file name */ if (reqInfo->url[strlen(reqInfo->url)-1] == '/' ){ strncpy(uri,reqInfo->url,HUGE_STRING_LEN); - strncat(uri,t,HUGE_STRING_LEN-strlen(uri)); + strncat(uri,str,HUGE_STRING_LEN-strlen(uri)); make_env_str(reqInfo,"DOCUMENT_URI",uri); } else { make_env_str(reqInfo,"DOCUMENT_URI",reqInfo->url); } + freeString(uri); return TRUE; } @@ -119,12 +120,10 @@ int find_string(per_request *reqInfo, FILE *fp, char *str) { if(reqInfo->out) { if(p) { for(x=0;xout); - ++(reqInfo->bytes_sent); + rputc(str[x],reqInfo); } } - putc(c,reqInfo->out); - ++(reqInfo->bytes_sent); + rputc(c,reqInfo); } p=0; } @@ -211,9 +210,6 @@ int get_directive(FILE *fp, char *d) { /* --------------------------- Action handlers ---------------------------- */ -void send_parsed_content(per_request *reqInfo, FILE *f, char *path_args, - int noexec); - int send_included_file(per_request *reqInfo, char *fn) { FILE *fp; @@ -227,13 +223,14 @@ int send_included_file(per_request *reqInfo, char *fn) if(!allow) return -1; set_content_type(reqInfo,reqInfo->filename); - if((op & OPT_INCLUDES) && (!strcmp(content_type,INCLUDES_MAGIC_TYPE))) { + if((op & OPT_INCLUDES) && + (!strcmp(reqInfo->outh_content_type,INCLUDES_MAGIC_TYPE))) { if(!(fp = FOpen(reqInfo->filename,"r"))) return -1; - send_parsed_content(reqInfo,fp,"",op & OPT_INCNOEXEC); + send_parsed_content(reqInfo,fp,op & OPT_INCNOEXEC); chdir_file(fn); /* grumble */ } - else if(!strcmp(content_type,CGI_MAGIC_TYPE)) + else if(!strcmp(reqInfo->outh_content_type,CGI_MAGIC_TYPE)) return -1; else { if(!(fp=FOpen(reqInfo->filename,"r"))) @@ -245,20 +242,30 @@ int send_included_file(per_request *reqInfo, char *fn) } int handle_include(per_request *reqInfo, FILE *fp, char *error) { - char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN]; + char *tag,*errstr; char *tag_val; + tag = newString(MAX_STRING_LEN,STR_TMP); + errstr = newString(MAX_STRING_LEN,STR_TMP); + while(1) { - if(!(tag_val = get_tag(fp,tag))) + if(!(tag_val = get_tag(fp,tag))) { + freeString(tag); + freeString(errstr); return 1; + } if(!strcmp(tag,"file")) { - char dir[MAX_STRING_LEN],to_send[MAX_STRING_LEN]; + char *dir,*to_send; per_request *newInfo; + dir = newString(MAX_STRING_LEN,STR_TMP); + to_send = newString(MAX_STRING_LEN,STR_TMP); + getparents(tag_val); /* get rid of any nasties */ - getwd(dir); + getcwd(dir,MAX_STRING_LEN); make_full_path(dir,tag_val,to_send); - newInfo = continue_request(reqInfo,NEW_URL | KEEP_ENV); + newInfo = continue_request(reqInfo, KEEP_ENV | KEEP_AUTH); + newInfo->http_version = P_HTTP_0_9; strcpy(newInfo->url,tag_val); strcpy(newInfo->args,reqInfo->args); strcpy(newInfo->filename,to_send); @@ -266,18 +273,21 @@ int handle_include(per_request *reqInfo, FILE *fp, char *error) { sprintf(errstr,"unable to include %s in parsed file %s", newInfo->filename,reqInfo->filename ); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); } reqInfo->bytes_sent += newInfo->bytes_sent; free_request(newInfo,ONLY_LAST); + freeString(dir); + freeString(to_send); } else if(!strcmp(tag,"virtual")) { per_request *newInfo; - newInfo = continue_request(reqInfo, NEW_URL | KEEP_ENV); + newInfo = continue_request(reqInfo, KEEP_ENV | KEEP_AUTH); + newInfo->http_version = P_HTTP_0_9; strcpy(newInfo->url,tag_val); if(translate_name(newInfo,newInfo->url,newInfo->filename) != A_STD_DOCUMENT) { - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); sprintf(errstr,"unable to include %s in parsed file %s, non standard document",newInfo->filename, reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); } else { @@ -285,19 +295,22 @@ int handle_include(per_request *reqInfo, FILE *fp, char *error) { sprintf(errstr,"unable to include %s in parsed file %s", newInfo->filename, reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); } reqInfo->bytes_sent += newInfo->bytes_sent; } free_request(newInfo,ONLY_LAST); } - else if(!strcmp(tag,"done")) + else if(!strcmp(tag,"done")) { + freeString(tag); + freeString(errstr); return 0; + } else { sprintf(errstr,"unknown parameter %s to tag echo in %s",tag, reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); } } } @@ -305,23 +318,22 @@ int handle_include(per_request *reqInfo, FILE *fp, char *error) { #ifndef NO_YOW #include "httpy.h" -int print_yow(per_request *reqInfo, int yow_num) { +void print_yow(per_request *reqInfo, int yow_num) { int i = 0; int href_on = FALSE; int tmp; if (yow_num >= MAX_YOW) yow_num = MAX_YOW-1; while (yow_lines[yow_num][i]) { - putc(yow_lines[yow_num][i],reqInfo->out); + rputc(yow_lines[yow_num][i],reqInfo); if (yow_lines[yow_num][i] == ' ') { tmp = href_on; href_on = (rand() % 100 < 50) ? 1 : 0; if (tmp != href_on) { if (!tmp) - reqInfo->bytes_sent += fprintf(reqInfo->out,"", - reqInfo->url); + rprintf(reqInfo,"", reqInfo->url); else - reqInfo->bytes_sent += fprintf(reqInfo->out,""); + rprintf(reqInfo,""); } i++; while ((yow_lines[yow_num][i] == ' ') && yow_lines[yow_num][i++]); @@ -332,19 +344,23 @@ int print_yow(per_request *reqInfo, int yow_num) { i++; } if (href_on) { - reqInfo->bytes_sent += fprintf(reqInfo->out,""); + rprintf(reqInfo,""); } } #endif /* NO_YOW */ int handle_echo(per_request *reqInfo, FILE *fp, char *error) { - char tag[MAX_STRING_LEN]; + char *tag; char *tag_val; + tag = newString(MAX_STRING_LEN,STR_TMP); + while(1) { - if(!(tag_val = get_tag(fp,tag))) + if(!(tag_val = get_tag(fp,tag))) { + freeString(tag); return 1; + } if(!strcmp(tag,"var")) { int x,i,len; @@ -352,13 +368,12 @@ int handle_echo(per_request *reqInfo, FILE *fp, char *error) { for(x=0;reqInfo->env[x] != NULL; x++) { i = ind(reqInfo->env[x],'='); if((i == len) && !(strncmp(reqInfo->env[x],tag_val,i))) { - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s", - &(reqInfo->env[x][i+1])); + rprintf(reqInfo,"%s",&(reqInfo->env[x][i+1])); break; } } if(!(reqInfo->env[x])) - reqInfo->bytes_sent += fprintf(reqInfo->out,"(none)"); + rprintf(reqInfo,"(none)"); } #ifndef NO_YOW else if(!strcmp(tag,"yow")) { @@ -366,19 +381,26 @@ int handle_echo(per_request *reqInfo, FILE *fp, char *error) { print_yow(reqInfo,num); } #endif /* NO_YOW */ - else if(!strcmp(tag,"done")) + else if(!strcmp(tag,"done")) { + freeString(tag); return 0; + } else { - char errstr[MAX_STRING_LEN]; + char *errstr; + + errstr = newString(MAX_STRING_LEN,STR_TMP); + sprintf(errstr,"unknown parameter %s to tag echo in %s",tag, reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); + + freeString(errstr); } } } -int include_cgi(per_request *reqInfo, char *pargs) { +int include_cgi(per_request *reqInfo) { char op; int allow,check_cgiopt; struct stat finfo; @@ -390,10 +412,12 @@ int include_cgi(per_request *reqInfo, char *pargs) { return -1; check_cgiopt=0; } else { - char dir[MAX_STRING_LEN]; - getwd(dir); + char *dir; + dir = newString(MAX_STRING_LEN, STR_TMP); + getcwd(dir,MAX_STRING_LEN); make_full_path(dir,reqInfo->url,reqInfo->filename); check_cgiopt=1; + freeString(dir); } /* No hardwired path info or query allowed */ if(stat(reqInfo->filename,&finfo) == -1) @@ -404,43 +428,51 @@ int include_cgi(per_request *reqInfo, char *pargs) { if((!allow) || (check_cgiopt && (!(op & OPT_EXECCGI)))) return -1; - if(cgi_stub(reqInfo,pargs,&finfo) == SC_REDIRECT_TEMP) - reqInfo->bytes_sent += fprintf(reqInfo->out, - "%s",location,location); + if(cgi_stub(reqInfo,&finfo,op) == SC_REDIRECT_TEMP) + rprintf(reqInfo, "%s",reqInfo->outh_location, + reqInfo->outh_location); return 0; } static int ipid; void kill_include_child(void) { - char errstr[MAX_STRING_LEN]; + char *errstr; + + errstr = newString(MAX_STRING_LEN,STR_TMP); + sprintf(errstr,"killing command process %d",ipid); log_error(errstr,gCurrentRequest->hostInfo->error_log); kill(ipid,SIGKILL); waitpid(ipid,NULL,0); + + freeString(errstr); } -int include_cmd(per_request *reqInfo, char *s, char *pargs) { +int include_cmd(per_request *reqInfo, char *s) { int p[2]; - FILE *fp; if(Pipe(p) == -1) - die(reqInfo,SC_SERVER_ERROR,"httpd: could not create IPC pipe"); + die(reqInfo,SC_SERVER_ERROR,"HTTPd: could not create IPC pipe"); if((ipid = fork()) == -1) { Close(p[0]); Close(p[1]); - die(reqInfo,SC_SERVER_ERROR,"httpd: could not fork new process"); + die(reqInfo,SC_SERVER_ERROR,"HTTPd: could not fork new process"); } if(!ipid) { char *argv0; - if(pargs[0] || reqInfo->args[0]) { - if(pargs[0]) { - char p2[HUGE_STRING_LEN]; + if(reqInfo->path_info[0] || reqInfo->args[0]) { + if(reqInfo->path_info[0]) { + char *p2; - escape_shell_cmd(pargs); - make_env_str(reqInfo,"PATH_INFO",pargs); - translate_name(reqInfo,pargs,p2); + p2 = newString(HUGE_STRING_LEN,STR_TMP); + + escape_shell_cmd(reqInfo->path_info); + make_env_str(reqInfo,"PATH_INFO",reqInfo->path_info); + translate_name(reqInfo,reqInfo->path_info,p2); make_env_str(reqInfo,"PATH_TRANSLATED",p2); + + freeString(p2); } if(reqInfo->args[0]) { make_env_str(reqInfo,"QUERY_STRING",reqInfo->args); @@ -455,72 +487,76 @@ int include_cmd(per_request *reqInfo, char *s, char *pargs) { dup2(p[1],STDOUT_FILENO); Close(p[1]); } + close(reqInfo->in); close(reqInfo->connection_socket); error_log2stderr(reqInfo->hostInfo->error_log); if(!(argv0 = strrchr(SHELL_PATH,'/'))) argv0=SHELL_PATH; if(execle(SHELL_PATH,argv0,"-c",s,(char *)0,reqInfo->env) == -1) { - fprintf(stderr,"httpd: exec of %s failed, errno is %d\n", + fprintf(stderr,"HTTPd: exec of %s failed, errno is %d\n", SHELL_PATH,errno); exit(1); } } Close(p[1]); -/* if(!(fp=FdOpen(p[0],"r"))) { - waitpid(ipid,NULL,0); - return -1; - } */ send_fd(reqInfo,p[0],kill_include_child); -/* FClose(fp); */ Close(p[0]); waitpid(ipid,NULL,0); return 0; } -int handle_exec(per_request *reqInfo, FILE *fp, char *path_args, - char *error) +int handle_exec(per_request *reqInfo, FILE *fp, char *error) { - char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN]; + char *tag,*errstr; char *tag_val; + tag = newString(MAX_STRING_LEN,STR_TMP); + errstr = newString(MAX_STRING_LEN,STR_TMP); + while(1) { - if(!(tag_val = get_tag(fp,tag))) + if(!(tag_val = get_tag(fp,tag))) { + freeString(tag); + freeString(errstr); return 1; + } if(!strcmp(tag,"cmd")) { - if(include_cmd(reqInfo,tag_val,path_args) == -1) { + if(include_cmd(reqInfo,tag_val) == -1) { sprintf(errstr,"invalid command exec %s in %s",tag_val, reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); } /* just in case some stooge changed directories */ chdir_file(reqInfo->filename); } else if(!strcmp(tag,"cgi")) { per_request *newInfo; - newInfo = continue_request(reqInfo,NEW_URL | KEEP_ENV); + newInfo = continue_request(reqInfo, KEEP_ENV | KEEP_AUTH); + newInfo->http_version = P_HTTP_0_9; strcpy(newInfo->url,tag_val); - if(include_cgi(newInfo,path_args) == -1) { + if(include_cgi(newInfo) == -1) { sprintf(errstr,"invalid CGI ref %s in %s",newInfo->filename, reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); } reqInfo->bytes_sent += newInfo->bytes_sent; free_request(newInfo,ONLY_LAST); /* grumble groan */ chdir_file(reqInfo->filename); } - else if(!strcmp(tag,"done")) + else if(!strcmp(tag,"done")) { + freeString(errstr); + freeString(tag); return 0; + } else { - char errstr[MAX_STRING_LEN]; sprintf(errstr,"unknown parameter %s to tag echo in %s",tag, reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); } } @@ -528,12 +564,16 @@ int handle_exec(per_request *reqInfo, FILE *fp, char *path_args, int handle_config(per_request *reqInfo, FILE *fp, char *error, char *tf, int *sizefmt) { - char tag[MAX_STRING_LEN]; + char *tag; char *tag_val; + tag = newString(MAX_STRING_LEN,STR_TMP); + while(1) { - if(!(tag_val = get_tag(fp,tag))) + if(!(tag_val = get_tag(fp,tag))) { + freeString(tag); return 1; + } if(!strcmp(tag,"errmsg")) strcpy(error,tag_val); else if(!strcmp(tag,"timefmt")) { @@ -548,24 +588,33 @@ int handle_config(per_request *reqInfo, FILE *fp, char *error, *sizefmt = SIZEFMT_BYTES; else if(!strcmp(tag_val,"abbrev")) *sizefmt = SIZEFMT_KMG; - } - else if(!strcmp(tag,"done")) + } + else if(!strcmp(tag,"done")) { + freeString(tag); return 0; + } else { - char errstr[MAX_STRING_LEN]; + char *errstr; + + errstr = newString(MAX_STRING_LEN,STR_TMP); + sprintf(errstr,"unknown parameter %s to tag config in %s", tag, reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); + + freeString(errstr); } } } #ifndef NO_YOW int handle_yow(per_request *reqInfo, FILE *fp, char *error) { - char tag[MAX_STRING_LEN]; + char *tag; char c; + tag = newString(MAX_STRING_LEN,STR_TMP); + srand((int) (getpid() + time((long *) 0))); GET_CHAR(fp,c,1); if (c == ENDING_SEQUENCE[0]) { @@ -574,10 +623,20 @@ int handle_yow(per_request *reqInfo, FILE *fp, char *error) { GET_CHAR(fp,c,1); if (c == ENDING_SEQUENCE[2]) { print_yow(reqInfo,rand() % MAX_YOW); + freeString(tag); return 0; - } else return 1; - } else return 1; - } else return 1; + } else { + freeString(tag); + return 1; + } + } else { + freeString(tag); + return 1; + } + } else { + freeString(tag); + return 1; + } } #endif /* NO_YOW */ @@ -586,30 +645,41 @@ int handle_yow(per_request *reqInfo, FILE *fp, char *error) { int find_file(per_request *reqInfo, char *directive, char *tag, char *tag_val, struct stat *finfo, char *error) { - char errstr[MAX_STRING_LEN], dir[MAX_STRING_LEN], to_send[MAX_STRING_LEN]; + char *errstr, *dir, *to_send; + + errstr = newString(MAX_STRING_LEN,STR_TMP); + dir = newString(MAX_STRING_LEN,STR_TMP); + to_send = newString(MAX_STRING_LEN,STR_TMP); if(!strcmp(tag,"file")) { getparents(tag_val); /* get rid of any nasties */ - getwd(dir); + getcwd(dir,MAX_STRING_LEN); make_full_path(dir,tag_val,to_send); if(stat(to_send,finfo) == -1) { sprintf(errstr, "unable to get information about %s in parsed file %s", to_send,reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); + freeString(errstr); + freeString(dir); + freeString(to_send); return -1; } + freeString(errstr); + freeString(dir); + freeString(to_send); return 0; } else if(!strcmp(tag,"virtual")) { per_request *newInfo; - newInfo = continue_request(reqInfo,NEW_URL | KEEP_ENV); + newInfo = continue_request(reqInfo, KEEP_ENV | KEEP_AUTH); + newInfo->http_version = P_HTTP_0_9; strcpy(newInfo->url,tag_val); if(translate_name(newInfo,newInfo->url,newInfo->filename) != A_STD_DOCUMENT) { sprintf(errstr,"unable to get information about non standard file %s in parsed file %s",newInfo->filename,reqInfo->filename); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); log_error(errstr,reqInfo->hostInfo->error_log); } else if(stat(newInfo->filename,finfo) == -1) { @@ -617,18 +687,27 @@ int find_file(per_request *reqInfo, char *directive, char *tag, "unable to get information about %s in parsed file %s", newInfo->filename,reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); free_request(newInfo,ONLY_LAST); + freeString(errstr); + freeString(dir); + freeString(to_send); return -1; } free_request(newInfo,ONLY_LAST); + freeString(errstr); + freeString(dir); + freeString(to_send); return 0; } else { sprintf(errstr,"unknown parameter %s to tag %s in %s", tag,directive,reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); + freeString(errstr); + freeString(dir); + freeString(to_send); return -1; } } @@ -636,15 +715,21 @@ int find_file(per_request *reqInfo, char *directive, char *tag, int handle_fsize(per_request *reqInfo, FILE *fp, char *error, int sizefmt) { - char tag[MAX_STRING_LEN]; + char *tag; char *tag_val; struct stat finfo; + tag = newString(MAX_STRING_LEN,STR_TMP); + while(1) { - if(!(tag_val = get_tag(fp,tag))) + if(!(tag_val = get_tag(fp,tag))) { + freeString(tag); return 1; - else if(!strcmp(tag,"done")) + } + else if(!strcmp(tag,"done")) { + freeString(tag); return 0; + } else if(!find_file(reqInfo,"fsize",tag,tag_val,&finfo,error)) { if(sizefmt == SIZEFMT_KMG) { send_size(reqInfo,finfo.st_size); @@ -656,11 +741,9 @@ int handle_fsize(per_request *reqInfo, FILE *fp, char *error, int sizefmt) l = strlen(tag); /* grrr */ for(x=0;xout); - ++reqInfo->bytes_sent; + rputc(',',reqInfo); } - fputc(tag[x],reqInfo->out); - ++reqInfo->bytes_sent; + rputc(tag[x],reqInfo); } } } @@ -669,34 +752,41 @@ int handle_fsize(per_request *reqInfo, FILE *fp, char *error, int sizefmt) int handle_flastmod(per_request *reqInfo, FILE *fp, char *error, char *tf) { - char tag[MAX_STRING_LEN]; + char *tag; char *tag_val; struct stat finfo; + tag = newString(MAX_STRING_LEN,STR_TMP); + while(1) { - if(!(tag_val = get_tag(fp,tag))) + if(!(tag_val = get_tag(fp,tag))) { + freeString(tag); return 1; - else if(!strcmp(tag,"done")) + } + else if(!strcmp(tag,"done")) { + freeString(tag); return 0; + } else if(!find_file(reqInfo,"flastmod",tag,tag_val,&finfo,error)) - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s", - ht_time(finfo.st_mtime,tf,0)); + rprintf(reqInfo,"%s", ht_time(finfo.st_mtime,tf,0)); } } - /* -------------------------- The main function --------------------------- */ /* This is a stub which parses a file descriptor. */ -void send_parsed_content(per_request *reqInfo, FILE *fp, char *path_args, - int noexec) +void send_parsed_content(per_request *reqInfo, FILE *fp, int noexec) { - char directive[MAX_STRING_LEN], error[MAX_STRING_LEN]; - char timefmt[MAX_STRING_LEN], errstr[MAX_STRING_LEN]; + char *directive, *error, *timefmt, *errstr; int ret, sizefmt; + directive = newString(MAX_STRING_LEN,STR_TMP); + error = newString(MAX_STRING_LEN,STR_TMP); + timefmt = newString(MAX_STRING_LEN,STR_TMP); + errstr = newString(MAX_STRING_LEN,STR_TMP); + strcpy(error,DEFAULT_ERROR_MSG); strcpy(timefmt,DEFAULT_TIME_FORMAT); sizefmt = SIZEFMT_KMG; @@ -705,17 +795,22 @@ void send_parsed_content(per_request *reqInfo, FILE *fp, char *path_args, while(1) { if(!find_string(reqInfo,fp,STARTING_SEQUENCE)) { - if(get_directive(fp,directive)) + if(get_directive(fp,directive)) { + freeString(directive); + freeString(error); + freeString(timefmt); + freeString(errstr); return; + } if(!strcmp(directive,"exec")) { if(noexec) { - sprintf(errstr,"httpd: exec used but not allowed in %s", + sprintf(errstr,"HTTPd: exec used but not allowed in %s", reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); ret = find_string(reqInfo,fp,ENDING_SEQUENCE); } else - ret=handle_exec(reqInfo,fp,path_args,error); + ret=handle_exec(reqInfo,fp,error); } else if(!strcmp(directive,"config")) ret=handle_config(reqInfo,fp,error,timefmt,&sizefmt); @@ -732,26 +827,35 @@ void send_parsed_content(per_request *reqInfo, FILE *fp, char *path_args, ret=handle_yow(reqInfo,fp,error); #endif /* NO_YOW */ else { - sprintf(errstr,"httpd: unknown directive %s in parsed doc %s", + sprintf(errstr,"HTTPd: unknown directive %s in parsed doc %s", directive,reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); - reqInfo->bytes_sent += fprintf(reqInfo->out,"%s",error); + rprintf(reqInfo,"%s",error); ret=find_string(reqInfo,fp,ENDING_SEQUENCE); } if(ret) { - sprintf(errstr,"httpd: premature EOF in parsed file %s", + sprintf(errstr,"HTTPd: premature EOF in parsed file %s", reqInfo->filename); log_error(errstr,reqInfo->hostInfo->error_log); + freeString(directive); + freeString(error); + freeString(timefmt); + freeString(errstr); return; } - } else + } else { + freeString(directive); + freeString(error); + freeString(timefmt); + freeString(errstr); return; + } } } /* Called by send_file */ -void send_parsed_file(per_request *reqInfo, char *path_args, int noexec) +void send_parsed_file(per_request *reqInfo, int noexec) { FILE *fp; @@ -761,8 +865,8 @@ void send_parsed_file(per_request *reqInfo, char *path_args, int noexec) /* unmunge_name(reqInfo,reqInfo->filename); */ die(reqInfo,SC_FORBIDDEN,reqInfo->url); } - strcpy(content_type,"text/html"); - if(!no_headers) + strcpy(reqInfo->outh_content_type,"text/html"); + if(reqInfo->http_version != P_HTTP_0_9) send_http_header(reqInfo); if(reqInfo->method == M_HEAD) { FClose(fp); @@ -770,14 +874,13 @@ void send_parsed_file(per_request *reqInfo, char *path_args, int noexec) } /* Make sure no children inherit our buffers */ - fflush(reqInfo->out); - no_headers = TRUE; /* make sure no headers get inserted anymore */ + rflush(reqInfo); alarm(timeout); add_include_vars(reqInfo,DEFAULT_TIME_FORMAT); add_common_vars(reqInfo); - send_parsed_content(reqInfo,fp,path_args,noexec); + send_parsed_content(reqInfo,fp,noexec); FClose(fp); } diff --git a/src/http_include.h b/src/http_include.h index 33c0f4c..18d4c8c 100644 --- a/src/http_include.h +++ b/src/http_include.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * http_include.h,v 1.5 1995/07/25 06:43:33 blong Exp + * http_include.h,v 1.7 1996/03/27 20:44:04 blong Exp * ************************************************************************ * @@ -32,7 +32,9 @@ #define NUM_INCLUDE_VARS 5 /* http_include */ -void send_parsed_file(per_request *reqInfo, char *path_args, int noexec); +void send_parsed_file(per_request *reqInfo, int noexec); char *ht_time(time_t t, char *fmt, int gmt); +int add_include_vars(per_request *reqInfo, char *timefmt); +void send_parsed_content(per_request *reqInfo, FILE *f, int noexec); #endif /* _HTTP_INCLUDE_H_ */ diff --git a/src/http_ipc.c b/src/http_ipc.c index 6c9c4ea..8ce90fc 100644 --- a/src/http_ipc.c +++ b/src/http_ipc.c @@ -10,7 +10,7 @@ * ************************************************************************ * - * http_ipc.c,v 1.20 1995/09/21 22:50:55 blong Exp + * http_ipc.c,v 1.22 1996/02/22 23:46:59 blong Exp * ************************************************************************ * @@ -21,13 +21,6 @@ * Based (with modifications) on code by W. Richard Stevens, * in _Advanced Programming in the UNIX Environment_ * - * 03-06-95 blong - * Added #ifdefs to handle not using this at all for machines like - * Linux. - * - * 04-17-95 blong - * Added NEED_SPIPE with s_pipe from Stevens _Unix Network Programming_ - * for SVR3.2 systems without socketpair. */ @@ -49,6 +42,9 @@ #ifdef FD_BSD # include +# ifdef NEED_SYS_UN_H +# include +# endif /* NEED_SYS_UN_H */ # include # include #elif defined(FD_SYSV) @@ -103,20 +99,20 @@ int recv_fd(int servfd) dat.maxlen = IOBUFSIZE; flag = 0; if (getmsg(servfd, NULL, &dat, &flag) < 0) { - fprintf(stderr,"httpd:getmsg error recv_fd\n"); + fprintf(stderr,"HTTPd: getmsg error recv_fd\n"); perror("getmsg"); exit(1); } nread = dat.len; if (nread == 0) { - fprintf(stderr,"httpd: connection closed by server\n"); + fprintf(stderr,"HTTPd: connection closed by server\n"); exit(1); } for (ptr = buf; ptr < &buf[nread]; ) { if (*ptr++ == 0) { if (ptr != &buf[nread-1]) { - fprintf(stderr,"httpd: message format error recv_fd\n"); + fprintf(stderr,"HTTPd: message format error recv_fd\n"); perror("recv_fd"); exit(1); } @@ -266,18 +262,18 @@ int recv_fd(int servfd) { #endif /* FD_BSDRENO */ if ((nread = recvmsg(servfd, &msg, 0)) < 0) { - fprintf(stderr,"httpd: recvmsg error"); + fprintf(stderr,"HTTPd: recvmsg error"); perror("recvmsg"); exit(1); } else if (nread == 0) { - fprintf(stderr, "httpd: connection closed by server"); + fprintf(stderr, "HTTPd: connection closed by server"); exit(1); } for (ptr = buf; ptr < &buf[nread]; ) { if (*ptr++ == 0) { if (ptr != &buf[nread-1]) { - fprintf(stderr, "httpd:message format error"); + fprintf(stderr, "HTTPd: message format error"); exit(1); } status = *ptr & 255; @@ -288,7 +284,7 @@ int recv_fd(int servfd) { if (msg.msg_accrightslen != sizeof(int)) #endif /* FD_BSDRENO */ { - fprintf(stderr, "httpd: status = 0 but no fd"); + fprintf(stderr, "HTTPd: status = 0 but no fd"); exit(1); } #ifdef FD_BSDRENO diff --git a/src/http_log.c b/src/http_log.c index b0f6d25..9aac538 100644 --- a/src/http_log.c +++ b/src/http_log.c @@ -10,45 +10,12 @@ * ************************************************************************ * - * http_log.c,v 1.76 1995/11/28 09:02:04 blong Exp + * http_log.c,v 1.84 1996/04/05 18:54:59 blong Exp * ************************************************************************ * * http_log.c: Dealing with the logs and errors * - * Based on NCSA HTTPd 1.3 by Rob McCool - * - * 10/28/94 cvarela - * Added agent_log and referer_log files. - * - * 02/15/95 blong - * Added support for configuration defined error messages - * - * 03/19/95 blong - * Some modification to status lines for uniformity, and for user - * defined error messages to give the correct status. - * - * 04/11/95 blong - * Changed custom error responses to only send the error string as - * arguments to the script - * - * 05/08/95 blong - * Bowing to pressure, added patch by Paul Phillips (paulp@cerf.net) - * to set CLOSE_ON_EXEC flag for log files under #define SECURE_LOGS - * - * 06/01/95 blong - * Changed die() so that it only logs the transaction on non-ErrorDocument - * errors (errors that are handled internally to the server) - * - * 09/13/95 mshapiro - * Added log directory checking - group/public write permissions - * - * 09-28-95 blong - * Added fix by Vince Tkac (tkac@oclc.org) to check if there are any - * errordocuments defined for the virtual host in the new schema. - * - * 09-29-95 blong - * Changed error_document fix to one suggested by Tim Adam (tma@osa.com.au) */ @@ -70,8 +37,10 @@ #include #include #include "constants.h" +#include "allocate.h" #include "http_log.h" #include "http_request.h" +#include "http_send.h" #include "http_config.h" #include "host_config.h" #include "http_auth.h" @@ -83,6 +52,7 @@ const char StatLine200[] = "200 Document follows"; const char StatLine204[] = "204 No Content"; +const char StatLine206[] = "206 Partial Content"; const char StatLine301[] = "301 Moved Permanently"; const char StatLine302[] = "302 Moved Temporarily"; const char StatLine304[] = "304 Not modified"; @@ -93,6 +63,7 @@ const char StatLine404[] = "404 Not Found"; const char StatLine408[] = "408 Request Timeout"; const char StatLine500[] = "500 Server Error"; const char StatLine501[] = "501 Not Implemented"; +const char StatLine503[] = "503 Service Unavailable"; char error_msg[MAX_STRING_LEN]; /* Moved to http_request.c */ @@ -108,7 +79,7 @@ void open_logs(per_host *host) { if (host->httpd_conf & HC_ERROR_FNAME) { if(!(host->error_log = fopen_logfile(host->error_fname,"a"))) { - fprintf(stderr,"httpd: could not open error log file %s.\n", + fprintf(stderr,"HTTPd: could not open error log file %s.\n", host->error_fname); perror("fopen"); exit(1); @@ -116,7 +87,7 @@ void open_logs(per_host *host) { } if (host->httpd_conf & HC_XFER_FNAME) { if((host->xfer_log = open_logfile(host->xfer_fname,xfer_flags, xfer_mode)) < 0) { - fprintf(stderr,"httpd: could not open transfer log file %s.\n", + fprintf(stderr,"HTTPd: could not open transfer log file %s.\n", host->xfer_fname); perror("open"); exit(1); @@ -130,7 +101,7 @@ void open_logs(per_host *host) { if (!(host->log_opts & LOG_COMBINED)) { if (host->httpd_conf & HC_AGENT_FNAME) { if(!(host->agent_log = fopen_logfile(host->agent_fname,"a"))) { - fprintf(stderr,"httpd: could not open agent log file %s.\n", + fprintf(stderr,"HTTPd: could not open agent log file %s.\n", host->agent_fname); perror("fopen"); exit(1); @@ -143,7 +114,7 @@ void open_logs(per_host *host) { } if (host->httpd_conf & HC_REFERER_FNAME) { if(!(host->referer_log = fopen_logfile(host->referer_fname,"a"))) { - fprintf(stderr,"httpd: could not open referer log file %s.\n", + fprintf(stderr,"HTTPd: could not open referer log file %s.\n", host->referer_fname); perror("fopen"); exit(1); @@ -187,19 +158,29 @@ void log_pid(void) FILE *pid_file; if(!(pid_file = fopen(pid_fname,"w"))) { - fprintf(stderr,"httpd: could not log pid to file %s\n",pid_fname); + fprintf(stderr,"HTTPd: could not log pid to file %s\n",pid_fname); exit(1); } fprintf(pid_file,"%d\n",getpid()); fclose(pid_file); } +extern int num_children; + void log_transaction(per_request *reqInfo) { - char str[HUGE_STRING_LEN]; + char *str; long timz; struct tm *t; - char tstr[MAX_STRING_LEN],sign; + char *tstr,sign; +#ifdef LOG_DURATION + extern time_t request_time; + time_t duration = request_time ? (time(NULL) - request_time) : 0; +#endif /* LOG_DURATION */ + + str = newString(HUGE_STRING_LEN,STR_TMP); + tstr = newString(MAX_STRING_LEN,STR_TMP); + t = get_gmtoff(&timz); sign = (timz < 0 ? '-' : '+'); @@ -208,9 +189,9 @@ void log_transaction(per_request *reqInfo) strftime(tstr,MAX_STRING_LEN,"%d/%b/%Y:%H:%M:%S",t); sprintf(str,"%s %s %s [%s %c%02ld%02d] \"%s\" ", - reqInfo->remote_name, + (reqInfo->remote_name ? reqInfo->remote_name : "-"), (do_rfc931 ? remote_logname : "-"), - (user[0] ? user : "-"), + (reqInfo->auth_user[0] ? reqInfo->auth_user : "-"), tstr, sign, timz/3600, @@ -231,16 +212,17 @@ void log_transaction(per_request *reqInfo) else strcat(str," -"); } - if (reqInfo->hostInfo->referer_ignore && reqInfo->referer[0]) { - char str[MAX_STRING_LEN]; + if (reqInfo->hostInfo->referer_ignore && reqInfo->inh_referer[0]) { + char *str1; int bIgnore = 0; - - lim_strcpy(str, reqInfo->hostInfo->referer_ignore, 255); + + str1 = newString(MAX_STRING_LEN,STR_TMP); + lim_strcpy(str1, reqInfo->hostInfo->referer_ignore, 255); if (reqInfo->hostInfo->referer_ignore[0]) { - char* tok = strtok (str, " "); + char* tok = strtok (str1, " "); while (tok) { - if (strstr(reqInfo->referer, tok)) { + if (strstr(reqInfo->inh_referer, tok)) { bIgnore = 1; break; } @@ -248,43 +230,50 @@ void log_transaction(per_request *reqInfo) } } if (bIgnore) { - reqInfo->referer[0] = '\0'; + reqInfo->inh_referer[0] = '\0'; } + freeString(str1); } +#ifdef LOG_DURATION + sprintf(str+strlen(str), " %ld", duration); +#endif /* LOG_DURATION */ + if (!(reqInfo->hostInfo->log_opts & LOG_COMBINED)) { strcat(str,"\n"); write(reqInfo->hostInfo->xfer_log,str,strlen(str)); /* log the user agent */ - if (reqInfo->agent[0]) { + if (reqInfo->inh_agent[0]) { if (reqInfo->hostInfo->log_opts & LOG_DATE) fprintf(reqInfo->hostInfo->agent_log, "[%s] %s\n",tstr, - reqInfo->agent); + reqInfo->inh_agent); else - fprintf(reqInfo->hostInfo->agent_log, "%s\n", reqInfo->agent); + fprintf(reqInfo->hostInfo->agent_log, "%s\n", reqInfo->inh_agent); fflush(reqInfo->hostInfo->agent_log); } /* log the referer */ - if (reqInfo->referer[0]) { + if (reqInfo->inh_referer[0]) { if (reqInfo->hostInfo->log_opts & LOG_DATE) fprintf(reqInfo->hostInfo->referer_log, "[%s] %s -> %s\n",tstr, - reqInfo->referer, reqInfo->url); + reqInfo->inh_referer, reqInfo->url); else fprintf(reqInfo->hostInfo->referer_log, "%s -> %s\n", - reqInfo->referer, reqInfo->url); + reqInfo->inh_referer, reqInfo->url); fflush(reqInfo->hostInfo->referer_log); } } else { - if (reqInfo->referer[0]) - sprintf(str,"%s \"%s\"",str,reqInfo->referer); + if (reqInfo->inh_referer[0]) + sprintf(str,"%s \"%s\"",str,reqInfo->inh_referer); else strcat(str," \"\""); - if (reqInfo->agent[0]) - sprintf(str,"%s \"%s\"\n",str,reqInfo->agent); + if (reqInfo->inh_agent[0]) + sprintf(str,"%s \"%s\"\n",str,reqInfo->inh_agent); else strcat(str," \"\"\n"); write(reqInfo->hostInfo->xfer_log,str,strlen(str)); } + freeString(str); + freeString(tstr); } void log_error(char *err, FILE *fp) { @@ -296,46 +285,46 @@ void log_reason(per_request *reqInfo, char *reason, char *file) { char *buffer; - buffer = (char *)malloc(strlen(reason)+strlen(reqInfo->referer)+ - strlen(reqInfo->remote_name)+strlen(file)+50); - sprintf(buffer,"httpd: access to %s failed for %s, reason: %s from %s", + /* This might not be big enough, but since its in the heap, the + * worst that will happen is a core dump, and its faster than a + * malloc, and won't fragment the memory as badly. + */ + buffer = newString(HUGE_STRING_LEN,STR_TMP); + + sprintf(buffer,"HTTPd: access to %s failed for %s, reason: %s from %s", file,reqInfo->remote_name,reason, - ( (reqInfo->referer[0] != '\0') ? reqInfo->referer : "-")); + ( (reqInfo->inh_referer[0] != '\0') ? reqInfo->inh_referer : "-")); log_error(buffer,reqInfo->hostInfo->error_log); - free(buffer); + freeString(buffer); } -void begin_http_header(per_request *reqInfo, const char *msg) -{ - fprintf(reqInfo->out,"%s %s%c",SERVER_PROTOCOL,msg,LF); - dump_default_header(reqInfo); -} void error_head(per_request *reqInfo, const char *err) { - if(!no_headers) { - begin_http_header(reqInfo,err); - fprintf(reqInfo->out,"Content-type: text/html%c%c",LF,LF); - } + if(reqInfo->http_version != P_HTTP_0_9) { + strcpy(reqInfo->outh_content_type,"text/html"); + send_http_header(reqInfo); + } if(reqInfo->method != M_HEAD) { - fprintf(reqInfo->out,"%s%c",err,LF); - fprintf(reqInfo->out,"

%s

%c",err,LF); + rprintf(reqInfo,"%s%c",err,LF); + rprintf(reqInfo,"

%s

%c",err,LF); } } void title_html(per_request *reqInfo, char *msg) { - fprintf(reqInfo->out,"%s%c",msg,LF); - fprintf(reqInfo->out,"

%s

%c",msg,LF); + rprintf(reqInfo,"%s%c",msg,LF); + rprintf(reqInfo,"

%s

%c",msg,LF); } int die(per_request *reqInfo, int type, char *err_string) { - char arguments[MAX_STRING_LEN]; + char *arguments; int RetVal=0; int x; int die_type; + arguments = newString(MAX_STRING_LEN,STR_TMP); /* kill keepalive on errors until we figure out what to do such as compute content_length of error messages */ die_type = DIE_NORMAL; @@ -346,62 +335,57 @@ int die(per_request *reqInfo, int type, char *err_string) strcpy(failed_request,the_request); strcpy(failed_url,reqInfo->url); - /* For 1.4b4, changed to have a common message for ErrorDocument calls - We now send only error=err_string (as passed) and the CGI environment - variable ERROR_STATUS,ERROR_REQUEST,ERROR_URL contain the rest of the - relevent information */ - /* For 1.4 release, changed ERROR_ to REDIRECT_ */ - switch(type) { case SC_NO_CONTENT: reqInfo->status = SC_NO_CONTENT; - begin_http_header(reqInfo,StatLine204); - fputc(LF,reqInfo->out); + set_stat_line(reqInfo); + if (reqInfo->http_version != P_HTTP_0_9) { + send_http_header(reqInfo); + } keep_alive.bKeepAlive = 0; - header_only = 1; RetVal = SC_NO_CONTENT; log_transaction(reqInfo); break; case SC_REDIRECT_TEMP: reqInfo->status = SC_REDIRECT_TEMP; + set_stat_line(reqInfo); if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { ErrorStat = reqInfo->status; GoErrorDoc(reqInfo,x,err_string); } else { keep_alive.bKeepAlive = 0; - if(!no_headers) { - begin_http_header(reqInfo,StatLine302); - fprintf(reqInfo->out,"Location: %s%c",err_string,LF); - fprintf(reqInfo->out,"Content-type: text/html%c",LF); - fputc(LF,reqInfo->out); + if(reqInfo->http_version != P_HTTP_0_9) { + strcpy(reqInfo->outh_location,err_string); + strcpy(reqInfo->outh_content_type,"text/html"); + send_http_header(reqInfo); } if (reqInfo->method != M_HEAD) { title_html(reqInfo,"Document moved"); - fprintf(reqInfo->out, + rprintf(reqInfo, "This document has moved here.

%c", err_string,LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); } break; case SC_REDIRECT_PERM: reqInfo->status = SC_REDIRECT_PERM; + set_stat_line(reqInfo); if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { ErrorStat = reqInfo->status; GoErrorDoc(reqInfo,x,err_string); } else { keep_alive.bKeepAlive = 0; - if(!no_headers) { - begin_http_header(reqInfo,StatLine301); - fprintf(reqInfo->out,"Location: %s%c",err_string,LF); - fprintf(reqInfo->out,"Content-type: text/html%c",LF); - fputc(LF,reqInfo->out); - } + if(reqInfo->http_version != P_HTTP_0_9) { + strcpy(reqInfo->outh_location,err_string); + strcpy(reqInfo->outh_content_type,"text/html"); + send_http_header(reqInfo); + } if (reqInfo->method != M_HEAD) { title_html(reqInfo,"Document moved"); - fprintf(reqInfo->out,"This document has permanently moved "); - fprintf(reqInfo->out,"here.

%c%c", + rprintf(reqInfo,"This document has permanently moved "); + rprintf(reqInfo,"here.

%c%c", err_string,LF,LF); } log_transaction(reqInfo); @@ -409,73 +393,95 @@ int die(per_request *reqInfo, int type, char *err_string) break; case SC_USE_LOCAL_COPY: reqInfo->status = SC_USE_LOCAL_COPY; - begin_http_header(reqInfo,StatLine304); - fputc(LF,reqInfo->out); + set_stat_line(reqInfo); + if (reqInfo->http_version != P_HTTP_0_9) { + send_http_header(reqInfo); + } keep_alive.bKeepAlive = 0; - header_only = 1; RetVal = SC_USE_LOCAL_COPY; log_transaction(reqInfo); break; case SC_AUTH_REQUIRED: reqInfo->status = SC_AUTH_REQUIRED; + set_stat_line(reqInfo); + strcpy(reqInfo->outh_www_auth, err_string); if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { ErrorStat = reqInfo->status; GoErrorDoc(reqInfo,x,err_string); } else { keep_alive.bKeepAlive = 0; - if(!no_headers) { - begin_http_header(reqInfo,StatLine401); - fprintf(reqInfo->out,"Content-type: text/html%c",LF); - fprintf(reqInfo->out,"WWW-Authenticate: %s%c%c", - err_string,LF,LF); + if(reqInfo->http_version != P_HTTP_0_9) { + strcpy(reqInfo->outh_content_type,"text/html"); + send_http_header(reqInfo); } if (reqInfo->method != M_HEAD) { title_html(reqInfo,"Authorization Required"); - fprintf(reqInfo->out, - "Browser not authentication-capable or %c",LF); - fprintf(reqInfo->out,"authentication failed.%c",LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo,"Browser not authentication-capable or %c",LF); + rprintf(reqInfo,"authentication failed.%c",LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); } break; + case SC_AUTH_NO_WWW_AUTH: + reqInfo->status = SC_AUTH_REQUIRED; + set_stat_line(reqInfo); + keep_alive.bKeepAlive = 0; + if(reqInfo->http_version != P_HTTP_0_9) { + strcpy(reqInfo->outh_content_type,"text/html"); + send_http_header(reqInfo); + } + if (reqInfo->method != M_HEAD) { + title_html(reqInfo,"Authorization Required"); + rprintf(reqInfo,"You are not permitted to get this URL: %c",LF); + rprintf(reqInfo,"%s%c",err_string,LF); + rprintf(reqInfo,"%c",LF); + } + log_transaction(reqInfo); + break; case SC_BAD_REQUEST: reqInfo->status = SC_BAD_REQUEST; + set_stat_line(reqInfo); if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { ErrorStat = reqInfo->status; GoErrorDoc(reqInfo,x,err_string); } else { error_head(reqInfo,StatLine400); keep_alive.bKeepAlive = 0; - if (!header_only) { - fprintf(reqInfo->out, + if (reqInfo->method != M_HEAD) { + rprintf(reqInfo, "Your client sent a query that this server could%c",LF); - fprintf(reqInfo->out,"not understand.

%c",LF); - fprintf(reqInfo->out,"Reason: %s

%c",err_string,LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo,"not understand.

%c",LF); + rprintf(reqInfo,"Reason: %s

%c",err_string,LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); } break; case SC_BAD_IMAGEMAP: reqInfo->status = SC_BAD_REQUEST; + set_stat_line(reqInfo); if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { ErrorStat = reqInfo->status; GoErrorDoc(reqInfo,x,err_string); } else { error_head(reqInfo,StatLine400); keep_alive.bKeepAlive = 0; - if (!header_only) { - fprintf(reqInfo->out, + if (reqInfo->method != M_HEAD) { + rprintf(reqInfo, "Server encountered error processing imagemap%c",LF); - fprintf(reqInfo->out,"Reason: %s

%c",err_string,LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo,"

Reason: %s

%c",err_string,LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); } break; case SC_FORBIDDEN: - reqInfo->status = SC_FORBIDDEN; + if (reqInfo->outh_location[0]) + reqInfo->status = SC_REDIRECT_TEMP; + else + reqInfo->status = SC_FORBIDDEN; + set_stat_line(reqInfo); if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { ErrorStat = reqInfo->status; GoErrorDoc(reqInfo,x,err_string); @@ -483,17 +489,18 @@ int die(per_request *reqInfo, int type, char *err_string) error_head(reqInfo,StatLine403); keep_alive.bKeepAlive = 0; if (reqInfo->method != M_HEAD) { - fprintf(reqInfo->out, + rprintf(reqInfo, "Your client does not have permission to get URL %s ", err_string); - fprintf(reqInfo->out,"from this server.

%c",LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo,"from this server.

%c",LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); } break; case SC_NOT_FOUND: reqInfo->status = SC_NOT_FOUND; + set_stat_line(reqInfo); if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { ErrorStat = reqInfo->status; GoErrorDoc(reqInfo,x,err_string); @@ -501,16 +508,36 @@ int die(per_request *reqInfo, int type, char *err_string) error_head(reqInfo,StatLine404); keep_alive.bKeepAlive = 0; if (reqInfo->method != M_HEAD) { - fprintf(reqInfo->out, + rprintf(reqInfo, "The requested URL %s was not found on this server.%c", err_string,LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); } break; + case SC_SERVICE_UNAVAIL: + reqInfo->status = SC_SERVICE_UNAVAIL; + set_stat_line(reqInfo); + if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { + ErrorStat = reqInfo->status; + GoErrorDoc(reqInfo,x,err_string); + } else { + error_head(reqInfo,StatLine503); + keep_alive.bKeepAlive = 0; + if (reqInfo->method != M_HEAD) { + rprintf(reqInfo, + "The requested URL %s is temporarily unavailable", + err_string); + rprintf(reqInfo,"from this server.%c",LF); + rprintf(reqInfo,"%c",LF); + } + log_transaction(reqInfo); + } + break; case SC_SERVER_ERROR: reqInfo->status = SC_SERVER_ERROR; + set_stat_line(reqInfo); die_type = DIE_NORMAL; if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { ErrorStat = reqInfo->status; @@ -521,22 +548,23 @@ int die(per_request *reqInfo, int type, char *err_string) keep_alive.bKeepAlive = 0; log_error(err_string,reqInfo->hostInfo->error_log); if (reqInfo->method != M_HEAD) { - fprintf(reqInfo->out,"The server encountered an internal error or%c",LF); - fprintf(reqInfo->out,"misconfiguration and was unable to complete %c",LF); - fprintf(reqInfo->out,"your request.

%c",LF); - fprintf(reqInfo->out,"Please contact the server administrator,%c",LF); - fprintf(reqInfo->out," %s ",reqInfo->hostInfo->server_admin); - fprintf(reqInfo->out,"and inform them of the time the error occurred%c",LF); - fprintf(reqInfo->out,", and anything you might have done that may%c",LF); - fprintf(reqInfo->out,"have caused the error.

%c",LF); - fprintf(reqInfo->out,"Error: %s%c",err_string,LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo,"The server encountered an internal error or%c",LF); + rprintf(reqInfo,"misconfiguration and was unable to complete %c",LF); + rprintf(reqInfo,"your request.

%c",LF); + rprintf(reqInfo,"Please contact the server administrator,%c",LF); + rprintf(reqInfo," %s ",reqInfo->hostInfo->server_admin); + rprintf(reqInfo,"and inform them of the time the error occurred%c",LF); + rprintf(reqInfo,", and anything you might have done that may%c",LF); + rprintf(reqInfo,"have caused the error.

%c",LF); + rprintf(reqInfo,"Error: %s%c",err_string,LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); } break; case SC_NOT_IMPLEMENTED: reqInfo->status = SC_NOT_IMPLEMENTED; + set_stat_line(reqInfo); if (((x=have_doc_error(reqInfo,type)) >= 0) && (!ErrorStat)) { ErrorStat = reqInfo->status; GoErrorDoc(reqInfo,x,err_string); @@ -544,10 +572,10 @@ int die(per_request *reqInfo, int type, char *err_string) error_head(reqInfo,StatLine501); keep_alive.bKeepAlive = 0; if (reqInfo->method != M_HEAD) { - fprintf(reqInfo->out,"We are sorry to be unable to perform the method %s", + rprintf(reqInfo,"We are sorry to be unable to perform the method %s", err_string); - fprintf(reqInfo->out," at this time or to this document.

%c",LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo," at this time or to this document.

%c",LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); } @@ -555,30 +583,33 @@ int die(per_request *reqInfo, int type, char *err_string) case SC_NO_MEMORY: log_error("HTTPd: memory exhausted",reqInfo->hostInfo->error_log); reqInfo->status = SC_SERVER_ERROR; + set_stat_line(reqInfo); die_type = DIE_NORMAL; error_head(reqInfo,StatLine500); keep_alive.bKeepAlive = 0; if (reqInfo->method != M_HEAD) { - fprintf(reqInfo->out,"The server has temporarily run out of resources%c",LF); - fprintf(reqInfo->out,"for your request. Please try again at a later time.

%c",LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo,"The server has temporarily run out of resources%c",LF); + rprintf(reqInfo,"for your request. Please try again at a later time.

%c",LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); break; case SC_CONF_ERROR: reqInfo->status = SC_SERVER_ERROR; - sprintf(arguments,"httpd: configuration error = %s",err_string); + set_stat_line(reqInfo); + sprintf(arguments,"HTTPd: configuration error = %s",err_string); log_error(arguments,reqInfo->hostInfo->error_log); error_head(reqInfo,StatLine500); keep_alive.bKeepAlive = 0; if (reqInfo->method != M_HEAD) { - fprintf(reqInfo->out,"The server has encountered a misconfiguration.%c",LF); - fprintf(reqInfo->out,"The error was %s.%c",err_string,LF); - fprintf(reqInfo->out,"%c",LF); + rprintf(reqInfo,"The server has encountered a misconfiguration.%c",LF); + rprintf(reqInfo,"The error was %s.%c",err_string,LF); + rprintf(reqInfo,"%c",LF); } log_transaction(reqInfo); } - fflush(reqInfo->out); + rflush(reqInfo); + freeString(arguments); if (!RetVal) htexit(reqInfo,1,die_type); return RetVal; @@ -587,7 +618,7 @@ int die(per_request *reqInfo, int type, char *err_string) int GoErrorDoc(per_request *reqInfo, int x, char *ErrString) { per_request *newInfo; - newInfo = continue_request(reqInfo,NEW_URL | FORCE_GET | KEEP_ENV | KEEP_AUTH); + newInfo = continue_request(reqInfo, FORCE_GET | KEEP_ENV | KEEP_AUTH); strcpy(newInfo->url,reqInfo->hostInfo->doc_errors[x]->DocErrorFile); if (ErrString) sprintf(newInfo->args,"error=%s",ErrString); diff --git a/src/http_log.h b/src/http_log.h index 369f431..051897a 100644 --- a/src/http_log.h +++ b/src/http_log.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * http_log.h,v 1.15 1995/11/28 09:02:05 blong Exp + * http_log.h,v 1.18 1996/03/06 23:21:06 blong Exp * ************************************************************************ * @@ -41,6 +41,7 @@ /* globals defined in this module */ extern const char StatLine200[]; +extern const char StatLine204[]; extern const char StatLine301[]; extern const char StatLine302[]; extern const char StatLine304[]; @@ -51,6 +52,7 @@ extern const char StatLine404[]; extern const char StatLine408[]; extern const char StatLine500[]; extern const char StatLine501[]; +extern const char StatLine503[]; extern char error_msg[]; extern int ErrorStat; @@ -66,7 +68,6 @@ void close_logs(per_host *host); void error_log2stderr(FILE *error_log); void title_html(per_request *reqInfo, char *msg); -void begin_http_header(per_request *reqInfo, const char *msg); int die(per_request *reqInfo, int type, char *err_string); diff --git a/src/http_mime.c b/src/http_mime.c index 9e71b6f..0d89048 100644 --- a/src/http_mime.c +++ b/src/http_mime.c @@ -10,28 +10,14 @@ * ************************************************************************ * - * http_mime.c,v 1.98 1995/11/28 09:02:07 blong Exp + * http_mime.c,v 1.106 1996/03/13 18:28:39 blong Exp * ************************************************************************ * - * http_mime.c: Sends/gets MIME headers for requests + * http_mime.c: maintains the list of mime types, encodings. Currently + * still contains functions for setting some HTTP headers, probably be + * moved eventually. * - * Based on NCSA HTTPd 1.3 by Rob McCool - * - * 03/19/95 blong - * Added set_stat_line as part of making user config error messages work - * The correct status line should now be sent back - * - * 04/20/95 blong - * Added a modified "B18" from apache patches by Rob Hartill - * - * 08/07/95 blong - * Moved scan_script_header() function to cgi.c in an attempt at - * increased modularity of the code (at least representatively) - * - * 10/30/95 blong - * Fixed get_mime_header string length problems as suggested by - * Marc Evans (Marc@Destek.NET) */ @@ -57,11 +43,13 @@ #include #include "constants.h" #include "fdwrap.h" +#include "allocate.h" #include "http_mime.h" #include "http_log.h" #include "http_config.h" #include "http_access.h" #include "env.h" +#include "http_request.h" #include "util.h" #if defined(KRB4) || defined(KRB5) @@ -81,27 +69,6 @@ struct mime_ext *encoding_types; struct mime_ext *Saved_Forced; struct mime_ext *Saved_Encoding; -int content_length; -char content_type[MAX_STRING_LEN]; -char content_type_in[MAX_STRING_LEN]; -char content_encoding[MAX_STRING_LEN]; - -char location[MAX_STRING_LEN]; -static char last_modified[MAX_STRING_LEN]; - -char auth_line[HUGE_STRING_LEN]; - -char called_hostname[MAX_STRING_LEN]; - -char *out_headers = NULL; -char *status_line = NULL; -char ims[MAX_STRING_LEN]; /* If-modified-since */ - -#ifdef HAVE_KERBEROS -char out_auth_header[1024]; -#endif /* HAVE_KERBEROS */ - - void hash_insert(struct mime_ext *me) { register int i = hash(me->ext[0]); register struct mime_ext *p, *q; @@ -168,7 +135,7 @@ void init_mime(void) reqInfo.out = stderr; if(!(f = FOpen(types_confname,"r"))) { - fprintf(stderr,"httpd: could not open mime types file %s\n", + fprintf(stderr,"HTTPd: could not open mime types file %s\n", types_confname); perror("fopen"); exit(1); @@ -225,11 +192,10 @@ void dump_types(void) } } #endif /* DEBUG */ -int is_content_type(char *type) { - return(!strcmp(content_type,type)); -} -void find_ct(per_request *reqInfo, char *file, int store_encoding) { +void find_ct(per_request *reqInfo, char *file, + char *content_type, char *content_encoding) +{ int i,l,l2; struct mime_ext *p; char fn[MAX_STRING_LEN]; @@ -246,7 +212,7 @@ void find_ct(per_request *reqInfo, char *file, int store_encoding) { while(p) { if(!strcmp(p->ext,&fn[i])) { fn[i-1] = '\0'; - if(store_encoding) { + if(content_encoding != NULL) { if(content_encoding[0]) sprintf(content_encoding,"%s, %s",content_encoding, p->ct); @@ -299,14 +265,20 @@ void find_ct(per_request *reqInfo, char *file, int store_encoding) { void probe_content_type(per_request *reqInfo, char *file) { - find_ct(reqInfo,file,0); + find_ct(reqInfo,file,reqInfo->outh_content_type,NULL); } void set_content_type(per_request *reqInfo, char *file) { - find_ct(reqInfo,file,1); + find_ct(reqInfo,file,reqInfo->outh_content_type, + reqInfo->outh_content_encoding); } +void get_content_type(per_request *reqInfo, char *file, + char *content_type, char *content_encoding) +{ + find_ct(reqInfo,file,content_type,content_encoding); +} /* Should remove all the added types from .htaccess files when the child sticks around */ @@ -370,217 +342,76 @@ void add_encoding(per_request *reqInfo, char *fn, char *t) { } void set_content_length(per_request *reqInfo, int l) { - content_length = l; + reqInfo->outh_content_length = l; } int set_last_modified(per_request *reqInfo, time_t t) { struct tm *tms; - char ts[MAX_STRING_LEN]; +/* char ts[MAX_STRING_LEN]; */ tms = gmtime(&t); - strftime(ts,MAX_STRING_LEN,HTTP_TIME_FORMAT,tms); - strcpy(last_modified,ts); + strftime(reqInfo->outh_last_mod,MAX_STRING_LEN,HTTP_TIME_FORMAT,tms); +/* strcpy(reqInfo->outh_last_mod,ts); */ - if(!ims[0]) + if(!reqInfo->inh_if_mod_since[0]) return 0; - if(later_than(tms, ims)) + if(later_than(tms, reqInfo->inh_if_mod_since)) return die(reqInfo,SC_USE_LOCAL_COPY,NULL); return 0; } -void init_header_vars(per_request *reqInfo) -{ - content_type[0] = '\0'; - content_type_in[0] = '\0'; - last_modified[0] = '\0'; - content_length = -1; - auth_line[0] = '\0'; - content_encoding[0] = '\0'; - location[0] = '\0'; - ims[0] = '\0'; - if (status_line != NULL) free(status_line); - status_line = NULL; - if (out_headers != NULL) free(out_headers); - out_headers = NULL; - -#ifdef HAVE_KERBEROS - out_auth_header[0] = '\0'; -#endif /* HAVE_KERBEROS */ -} - -/* Globals for speed because of size, these are for get_mime_headers */ -static char field_type[HUGE_STRING_LEN]; -static char unrec_hdr[HUGE_STRING_LEN]; -static char unrec_hdr_val[HUGE_STRING_LEN]; - -void get_mime_headers(per_request *reqInfo) -{ - char *field_val; - -#ifdef DIGEST_AUTH - client_accepts_digest = assume_digest_support; -#endif /* DIGEST_AUTH */ - while(getline(reqInfo->connection_socket,field_type,HUGE_STRING_LEN-1,0, - timeout) != -1) { - if(!field_type[0]) - return; - - if(!(field_val = strchr(field_type,':'))) - continue; - *field_val++ = '\0'; - while(isspace(*field_val)) ++field_val; - - if(!strcasecmp(field_type,"Content-type")) { - strncpy(content_type_in,field_val,MAX_STRING_LEN); - content_type_in[MAX_STRING_LEN-1] = '\0'; - continue; - } - if(!strcasecmp(field_type,"Authorization")) { - strncpy(auth_line,field_val,HUGE_STRING_LEN); - auth_line[HUGE_STRING_LEN-1]='\0'; - continue; - } - if(!strcasecmp(field_type,"Host")) { - strncpy(called_hostname, field_val, MAX_STRING_LEN); - called_hostname[MAX_STRING_LEN-1] = '\0'; - } - if(!strcasecmp(field_type,"Extension")) { - if (!strcasecmp(field_val, "Notify-Domain-Restriction")) - reqInfo->bNotifyDomainRestricted = 1; -#ifdef DIGEST_AUTH - else if (!strcasecmp(field_val, "Security/Digest")) - client_accepts_digest = 1; -#endif /* DIGEST_AUTH */ - } - if(!strcasecmp(field_type,"Content-length")) { - sscanf(field_val,"%d",&content_length); - continue; - } - if(!strcasecmp(field_type,"Connection")) { - if (!strcasecmp(field_val, "Keep-Alive") && - keep_alive.bAllowKeepAlive) - keep_alive.bKeepAlive = 1; - } - if(!strcasecmp(field_type,"User-agent")) { - strncpy(reqInfo->agent, field_val, HUGE_STRING_LEN); - reqInfo->agent[HUGE_STRING_LEN-1] = '\0'; - } - if(!strcasecmp(field_type,"Referer")) { - strncpy(reqInfo->referer, field_val, HUGE_STRING_LEN); - reqInfo->referer[HUGE_STRING_LEN-1] = '\0'; - } - if(!strcasecmp(field_type,"If-modified-since")) { - strcpy(ims,field_val); - ims[MAX_STRING_LEN-1] = '\0'; - } - http2cgi(unrec_hdr, field_type); - strcpy (unrec_hdr_val, field_val); - if(reqInfo->env) { - if(!merge_header(reqInfo,unrec_hdr,field_val)) - make_env_str(reqInfo,unrec_hdr,field_val); - } - else - make_env_str(reqInfo,unrec_hdr,field_val); - } -} - - -void dump_default_header(per_request *reqInfo) -{ - fprintf(reqInfo->out,"Date: %s%c",gm_timestr_822(time(NULL)),LF); - fprintf(reqInfo->out,"Server: %s%c",SERVER_VERSION,LF); - if (reqInfo->hostInfo->annotation_server[0]) - fprintf(reqInfo->out,"Annotations-cgi: %s%c", - reqInfo->hostInfo->annotation_server,LF); - -/* Not part of HTTP spec, removed. */ -/* fprintf(fd,"MIME-version: 1.0%c",LF); */ -} - /* This needs to malloc in case a CGI script passes back its own * status_line, so we can free without problem. */ char* set_stat_line(per_request *reqInfo) { - if (status_line) free(status_line); + if (reqInfo->status_line) { + freeString(reqInfo->status_line); + } switch (reqInfo->status) { - case 302: - status_line = strdup((char *)StatLine302); + case 200: + reqInfo->status_line = dupStringP((char *)StatLine200,STR_REQ); break; - case 304: - status_line = strdup((char *)StatLine304); + case 204: + reqInfo->status_line = dupStringP((char *)StatLine204,STR_REQ); + break; + case 301: + reqInfo->status_line = dupStringP((char *)StatLine301,STR_REQ); + break; + case 302: + reqInfo->status_line = dupStringP((char *)StatLine302,STR_REQ); + break; + case 304: + reqInfo->status_line = dupStringP((char *)StatLine304,STR_REQ); break; case 400: - status_line = strdup((char *)StatLine400); + reqInfo->status_line = dupStringP((char *)StatLine400,STR_REQ); break; case 401: - status_line = strdup((char *)StatLine401); + reqInfo->status_line = dupStringP((char *)StatLine401,STR_REQ); break; case 403: - status_line = strdup((char *)StatLine403); + reqInfo->status_line = dupStringP((char *)StatLine403,STR_REQ); break; - case 404: - status_line = strdup((char *)StatLine404); + case 404: + reqInfo->status_line = dupStringP((char *)StatLine404,STR_REQ); break; case 500: - status_line = strdup((char *)StatLine500); + reqInfo->status_line = dupStringP((char *)StatLine500,STR_REQ); break; case 501: - status_line = strdup((char *)StatLine501); + reqInfo->status_line = dupStringP((char *)StatLine501,STR_REQ); + break; + case 503: + reqInfo->status_line = dupStringP((char *)StatLine503,STR_REQ); break; default: - status_line = strdup((char *)StatLine200); + reqInfo->status_line = dupStringP((char *)StatLine200,STR_REQ); break; } - return status_line; -} - - -void send_http_header(per_request *reqInfo) -{ - if(!status_line) { - if(location[0]) { - reqInfo->status = 302; - status_line = strdup((char *)StatLine302); - } - else { - set_stat_line(reqInfo); - } - } - begin_http_header(reqInfo,status_line); - if(content_type[0]) - fprintf(reqInfo->out,"Content-type: %s%c",content_type,LF); - if(last_modified[0]) - fprintf(reqInfo->out,"Last-modified: %s%c",last_modified,LF); - if(content_length >= 0) - fprintf(reqInfo->out,"Content-length: %d%c",content_length,LF); - if(location[0]) - fprintf(reqInfo->out,"Location: %s%c",location,LF); - if(content_encoding[0]) - fprintf(reqInfo->out,"Content-encoding: %s%c",content_encoding,LF); - - if (reqInfo->bNotifyDomainRestricted && reqInfo->bSatisfiedDomain) - fprintf(reqInfo->out,"Extension: Domain-Restricted%c", LF); - - keep_alive.bKeepAlive = keep_alive.bKeepAlive && (content_length >= 0); - if (keep_alive.bKeepAlive && (!keep_alive.nMaxRequests || - keep_alive.nCurrRequests + 1 < - keep_alive.nMaxRequests)) { - keep_alive.bKeepAlive = 1; - fprintf(reqInfo->out, - "Connection: Keep-Alive%cKeep-Alive: max=%d, timeout=%d%c", - LF, keep_alive.nMaxRequests, keep_alive.nTimeOut, LF); - } - if(out_headers) - fprintf(reqInfo->out,"%s",out_headers); -#ifdef HAVE_KERBEROS - if (out_auth_header[0]) - fprintf (reqInfo->out, "%s", out_auth_header); -#endif /* HAVE_KERBEROS */ - fprintf(reqInfo->out,"%c",LF); - fflush(reqInfo->out); + return reqInfo->status_line; } diff --git a/src/http_mime.h b/src/http_mime.h index 9cefd02..448b96b 100644 --- a/src/http_mime.h +++ b/src/http_mime.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * http_mime.h,v 1.16 1995/11/28 09:02:08 blong Exp + * http_mime.h,v 1.19 1996/02/22 23:47:04 blong Exp * ************************************************************************ * @@ -32,39 +32,29 @@ struct mime_ext { /* globals defined in this module */ -extern char content_type[]; -extern char content_type_in[]; -extern char content_encoding[]; -extern int content_length; -extern char location[]; -extern char auth_line[]; -extern char called_hostname[]; + extern struct mime_ext *Saved_Forced; extern struct mime_ext *Saved_Encoding; extern struct mime_ext *forced_types; extern struct mime_ext *encoding_types; -extern char *out_headers; /* http_mime function prototypes */ -void get_mime_headers(per_request *reqInfo); -void send_http_header(per_request *reqInfo); void set_content_type(per_request *reqInfo, char *fn); -int set_last_modified(per_request *reqInfo, time_t t); void probe_content_type(per_request *reqInfo, char *fn); -int scan_script_header(per_request *reqInfo, int pd); +void set_content_length(per_request *reqInfo, int l); +void get_content_type(per_request *reqInfo, char *file, + char *content_type, char *content_encoding); + +int set_last_modified(per_request *reqInfo, time_t t); + void add_type(per_request *reqInfo, char *fn, char *t); void add_encoding(per_request *reqInfo, char *fn, char *t); -void set_content_length(per_request *reqInfo, int l); void dump_types(void); void init_mime(void); void kill_mime(void); void reset_mime_vars(void); -int is_content_type(char *type); -void dump_default_header(per_request *reqInfo); -void init_header_vars(per_request *reqInfo); -extern char *status_line; char* set_stat_line(per_request *reqInfo); #endif /* _HTTP_MIME_H_ */ diff --git a/src/http_request.c b/src/http_request.c index c6602f1..b17822f 100644 --- a/src/http_request.c +++ b/src/http_request.c @@ -10,23 +10,19 @@ * ************************************************************************ * - * http_request.c,v 1.99 1995/11/06 20:58:09 blong Exp + * http_request.c,v 1.113 1996/04/05 18:55:02 blong Exp * ************************************************************************ * - * http_request.c: functions to get and process requests + * http_request.c: functions to handle the request structure and initial + * request handling including decoding * * 03-21-95 Based on NCSA HTTPd 1.3 by Rob McCool + * 05-17-95 NCSA HTTPd 1.4.1 + * 05-01-95 NCSA HTTPd 1.4.2 + * 11-10-95 NCSA HTTPd 1.5.0 + * 11-14-95 NCSA HTTPd 1.5.0a * - * 04-19-95 blong - * Forgot to remove free(remote_ip) from here, like elsewhere - * - * 04-20-95 blong - * Added patch "B18" for redirects w/o delay by Robert Hartill - * - * 05-01-95 blong - * Added patch by Steve Abatangle (sabat@enterprise.DTS.Harris.COM) - * to log SIGPIPE and timed out differently in send_fd_timed_out */ @@ -38,44 +34,61 @@ # include #endif /* NO_STDLIB_H */ #include -#include -#include #include #include +#include +#include #include "constants.h" -#include "httpd.h" +#include "allocate.h" /* for freeString() */ +#include "cgi.h" /* for exec_cgi_script() */ +#ifdef FCGI_SUPPORT +# include "fcgi.h" /* for FastCgiHandler() */ +#endif /* FCGI */ +#include "env.h" /* for free_env() */ +#include "http_access.h" /* for reset_security() */ +#include "http_alias.h" /* For translate_name() */ +#include "host_config.h" /* For which_host_conf(), gConfiguration */ +#include "http_config.h" /* For timeout */ +#include "http_log.h" /* For die(),ErrorStat */ +#include "http_send.h" /* for send_node() */ +#include "util.h" /* for strcasecmp(), etc */ #include "http_request.h" -#include "http_send.h" -#include "cgi.h" -#include "http_access.h" -#include "http_mime.h" -#include "http_config.h" -#include "host_config.h" -#include "http_log.h" -#include "http_auth.h" -#include "http_alias.h" -#include "env.h" -#include "util.h" -int no_headers; -int header_only; +int req_count = 0; +int cgibuf_count = 0; +int sockbuf_count = 0; + per_request *gCurrentRequest; - +/* *sigh* Yeah, we still have some globals left. We could probably + * move these into the request structure as well . . . its hitting + * 100k in size, though. + */ /* If RFC931 identity check is on, the remote user name */ char *remote_logname; /* Per request information */ - char the_request[HUGE_STRING_LEN]; char as_requested[HUGE_STRING_LEN]; char failed_request[HUGE_STRING_LEN]; char failed_url[HUGE_STRING_LEN]; +#ifdef LOG_DURATION +time_t request_time = 0; +#endif /* LOG_DURATION */ -char *methods[METHODS] = {"GET","HEAD","POST","PUT","DELETE","LINK","UNLINK"}; -char *protocals[PROTOCALS] = {"HTTP","HTTP/0.9","HTTP/1.0","HTTP/1.1"}; - +/* String constants for the request. Numbers are in constants.h */ +char *methods[METHODS] = {"GET","HEAD","POST","PUT","DELETE","SECURE", + "LINK","UNLINK"}; +char *protocals[PROTOCALS] = {"HTTP","HTTP/0.9","HTTP/1.0","HTTP/1.1", + "Secure-HTTP/1.1", "Secure-HTTP/1.2"}; +/* initialize_request() + * either creates, or inits a request structure passed to it. + * This assumes that a request structure passed to it was passed + * through free_request, so it doesn't have any extra pointers that + * need to be dealt with (though it still checks env, that shouldn't + * be necessary) + */ per_request *initialize_request(per_request *reqInfo) { int RealInit = 0; @@ -83,42 +96,46 @@ per_request *initialize_request(per_request *reqInfo) RealInit = (reqInfo == NULL) ? 1 : 0; - newInfo = (per_request *) malloc(sizeof(per_request)); - newInfo->hostInfo = gConfiguration; if (RealInit) { + newInfo = (per_request *) malloc(sizeof(per_request)); + req_count++; reqInfo = newInfo; - reqInfo->ownURL = TRUE; reqInfo->ownDNS = TRUE; reqInfo->dns_host_lookup = FALSE; reqInfo->remote_name = NULL; reqInfo->remote_ip = NULL; reqInfo->remote_host = NULL; reqInfo->next = NULL; - } else { - newInfo->next = reqInfo; - reqInfo = newInfo; - reqInfo->ownURL = FALSE; - reqInfo->ownDNS = FALSE; - reqInfo->dns_host_lookup = reqInfo->next->dns_host_lookup; - reqInfo->remote_name = reqInfo->next->remote_name; - reqInfo->remote_host = reqInfo->next->remote_host; - reqInfo->remote_ip = reqInfo->next->remote_ip; - reqInfo->hostInfo = reqInfo->next->hostInfo; - } + reqInfo->ownENV = TRUE; + reqInfo->env = NULL; + reqInfo->outh_cgi = NULL; + reqInfo->RequestFlags = 0; + reqInfo->sb = NULL; + reqInfo->ownSB = TRUE; + reqInfo->cgi_buf = NULL; + } + + reqInfo->hostInfo = gConfiguration; /* Can't think (now) of any case where environment should transfer from last request during KeepAlive, but in other cases, perhaps */ + if (reqInfo->ownENV && reqInfo->env) { + free_env(reqInfo); + } + reqInfo->ownENV = TRUE; reqInfo->env = NULL; reqInfo->env_len = NULL; reqInfo->num_env = 0; reqInfo->max_env = 0; + /* initialize auth stuff */ reqInfo->bNotifyDomainRestricted = 0; reqInfo->bSatisfiedDomain = 0; + reqInfo->bSatisfiedReferer = 0; reqInfo->auth_name = "ByPassword"; reqInfo->auth_pwfile = NULL; @@ -140,46 +157,70 @@ per_request *initialize_request(per_request *reqInfo) /* Initialize Error codes */ ErrorStat = 0; -/* status = 200; */ reqInfo->status = SC_DOCUMENT_FOLLOWS; -/* reqInfo->status_line = NULL; */ + reqInfo->status_line = NULL; reqInfo->bytes_sent = -1; reqInfo->auth_type[0] = '\0'; - if (!reqInfo->ownURL) { - strcpy(reqInfo->url, reqInfo->next->url); - strcpy(reqInfo->args, reqInfo->next->args); - strcpy(reqInfo->filename, reqInfo->next->filename); - } reqInfo->url[0] = '\0'; reqInfo->args[0] = '\0'; + reqInfo->path_info[0] = '\0'; reqInfo->filename[0] = '\0'; - reqInfo->agent[0] = '\0'; - reqInfo->referer[0] = '\0'; + reqInfo->inh_agent[0] = '\0'; + reqInfo->inh_referer[0] = '\0'; + reqInfo->inh_called_hostname[0] = '\0'; + reqInfo->inh_if_mod_since[0] = '\0'; + reqInfo->inh_auth_line[0] = '\0'; + reqInfo->inh_content_type[0] = '\0'; + reqInfo->inh_content_length = -1; + + reqInfo->outh_location[0] = '\0'; + reqInfo->outh_last_mod[0] = '\0'; + reqInfo->outh_www_auth[0] = '\0'; + reqInfo->outh_content_type[0] = '\0'; + reqInfo->outh_content_encoding[0] = '\0'; + reqInfo->outh_content_length = -1; +#ifdef CONTENT_MD5 + reqInfo->outh_content_md5 = NULL; +#endif /* CONTENT_MD5 */ + reqInfo->outh_cgi = NULL; - init_header_vars(reqInfo); as_requested[0] = '\0'; failed_url[0] = '\0'; failed_request[0] = '\0'; local_default_type[0] = '\0'; local_default_icon[0] = '\0'; -/* All but HEAD send more than a header */ - header_only = 0; - /* reset keep-alive, client will indicate desire on next request */ keep_alive.bKeepAlive = 0; return reqInfo; } +/* continue_request() + * Used (especially in SSI and ErrorDocs) to handle "multiple" + * internal requests. Will probably be used for SHTTP requests + * since they can be wrapped multiple times. + * Will copy over all inbound http headers, clear all outbound + * http headers except outh_www_auth which depends on KEEP_AUTH + * Option values in constants.h + * Takes as options: + * KEEP_ENV : Copy ENV from passed request + * KEEP_AUTH : Copy auth info from passed request + * FORCE_GET : Unless a HEAD request, change to GET request + * (don't POST to ErrorDoc) + * COPY_URL : Copy URL from passed request + * NEW_SOCK_BUF: Set sb to NULL to cause a new sock buf to be created + */ per_request *continue_request(per_request *reqInfo, int options) { per_request *newInfo; newInfo = (per_request *)malloc(sizeof(per_request)); + req_count++; newInfo->status = reqInfo->status; + newInfo->status_line = NULL; if (options & KEEP_ENV) { newInfo->ownENV = FALSE; @@ -197,6 +238,10 @@ per_request *continue_request(per_request *reqInfo, int options) { if (options & KEEP_AUTH) { strcpy(newInfo->auth_type,reqInfo->auth_type); + strcpy(newInfo->auth_user,reqInfo->auth_user); + strcpy(newInfo->auth_group,reqInfo->auth_group); + strcpy(newInfo->inh_auth_line,reqInfo->inh_auth_line); + strcpy(newInfo->outh_www_auth,reqInfo->outh_www_auth); newInfo->auth_name = reqInfo->auth_name; newInfo->auth_pwfile = reqInfo->auth_pwfile; newInfo->auth_grpfile = reqInfo->auth_grpfile; @@ -207,8 +252,13 @@ per_request *continue_request(per_request *reqInfo, int options) { newInfo->auth_digestfile_type = newInfo->auth_digestfile_type; #endif /* DIGEST_AUTH */ newInfo->bSatisfiedDomain = reqInfo->bSatisfiedDomain; + newInfo->bSatisfiedReferer = reqInfo->bSatisfiedReferer; } else { newInfo->auth_type[0] = '\0'; + newInfo->auth_user[0] = '\0'; + newInfo->auth_group[0] = '\0'; + newInfo->inh_auth_line[0] = '\0'; + newInfo->outh_www_auth[0] = '\0'; newInfo->auth_name = NULL; newInfo->auth_pwfile = NULL; newInfo->auth_grpfile = NULL; @@ -219,6 +269,7 @@ per_request *continue_request(per_request *reqInfo, int options) { newInfo->auth_digestfile_type = 0; #endif /* DIGEST_AUTH */ newInfo->bSatisfiedDomain = FALSE; + newInfo->bSatisfiedReferer = FALSE; } newInfo->bNotifyDomainRestricted = reqInfo->bNotifyDomainRestricted; newInfo->bytes_sent = 0; @@ -232,39 +283,53 @@ per_request *continue_request(per_request *reqInfo, int options) { newInfo->http_version = reqInfo->http_version; - if (options & NEW_DNS) { - newInfo->ownDNS = TRUE; - newInfo->dns_host_lookup = FALSE; - newInfo->remote_host = NULL; - newInfo->remote_name = NULL; - newInfo->remote_ip = NULL; - newInfo->hostInfo = NULL; - } else { - newInfo->ownDNS = FALSE; - newInfo->dns_host_lookup = reqInfo->dns_host_lookup; - newInfo->remote_host = reqInfo->remote_host; - newInfo->remote_name = reqInfo->remote_name; - newInfo->remote_ip = reqInfo->remote_ip; - newInfo->hostInfo = reqInfo->hostInfo; - } + newInfo->ownDNS = FALSE; + newInfo->dns_host_lookup = reqInfo->dns_host_lookup; + newInfo->remote_host = reqInfo->remote_host; + newInfo->remote_name = reqInfo->remote_name; + newInfo->remote_ip = reqInfo->remote_ip; + newInfo->hostInfo = reqInfo->hostInfo; - if (options & NEW_URL) { - newInfo->ownURL = TRUE; - newInfo->url[0] = '\0'; - newInfo->args[0] = '\0'; - newInfo->filename[0] = '\0'; - } else { - newInfo->ownURL = FALSE; + + if (options & COPY_URL) { strcpy(newInfo->url, reqInfo->url); strcpy(newInfo->args, reqInfo->args); + strcpy(newInfo->path_info, reqInfo->path_info); strcpy(newInfo->filename, reqInfo->filename); + } else { + newInfo->url[0] = '\0'; + newInfo->args[0] = '\0'; + newInfo->path_info[0] = '\0'; + newInfo->filename[0] = '\0'; } - strcpy(newInfo->referer,reqInfo->referer); - strcpy(newInfo->agent,reqInfo->agent); + /* Copy all in headers */ + strcpy(newInfo->inh_agent,reqInfo->inh_agent); + strcpy(newInfo->inh_referer,reqInfo->inh_referer); + strcpy(newInfo->inh_called_hostname,reqInfo->inh_called_hostname); + strcpy(newInfo->inh_if_mod_since,reqInfo->inh_if_mod_since); + strcpy(newInfo->inh_content_type,reqInfo->inh_content_type); + newInfo->inh_content_length = reqInfo->inh_content_length; + + /* Zero all out headers : outh_www_auth is handled in auth above */ + newInfo->outh_location[0] = '\0'; + newInfo->outh_last_mod[0] = '\0'; + newInfo->outh_content_type[0] = '\0'; + newInfo->outh_content_encoding[0] = '\0'; + newInfo->outh_content_length = -1; + newInfo->outh_cgi = NULL; newInfo->connection_socket = reqInfo->connection_socket; + newInfo->in = reqInfo->in; newInfo->out = reqInfo->out; + if (options & NEW_SOCK_BUF) { + newInfo->ownSB = TRUE; + newInfo->sb = NULL; + } else { + newInfo->ownSB = FALSE; + newInfo->sb = reqInfo->sb; + } + newInfo->cgi_buf = NULL; newInfo->next = reqInfo; @@ -272,27 +337,61 @@ per_request *continue_request(per_request *reqInfo, int options) { return newInfo; } +/* free_request() + * Clears the request structure linked list. + * Options: (from constants.h) + * ONLY_LAST : deletes only the top most (most recent) + * NOT_LAST : Don't delete the last one (so we don't have to malloc again) + */ void free_request(per_request *reqInfo,int options) { per_request *tmp = reqInfo; while (reqInfo != NULL) { - if (reqInfo->ownDNS) { - if (reqInfo->remote_name != NULL) free(reqInfo->remote_name); - if (reqInfo->remote_host != NULL) free(reqInfo->remote_host); - if (reqInfo->remote_ip != NULL) free(reqInfo->remote_ip); - } + /* We'll just let the freeAllStrings clean up these instead. */ + reqInfo->remote_name = NULL; + reqInfo->remote_host = NULL; + reqInfo->remote_ip = NULL; +#ifdef CONTENT_MD5 + if (reqInfo->outh_content_md5 != NULL) free(reqInfo->outh_content_md5); +#endif /* CONTENT_MD5 */ + if (reqInfo->outh_cgi != NULL) free(reqInfo->outh_cgi); + if (reqInfo->ownENV && reqInfo->env) { free_env(reqInfo); } + if (reqInfo->ownSB && reqInfo->sb) { + free(reqInfo->sb); + reqInfo->sb = NULL; + sockbuf_count--; + } + if (reqInfo->cgi_buf) { + free(reqInfo->cgi_buf); + reqInfo->cgi_buf = NULL; + cgibuf_count--; + } + /* I have no idea how this is possible, but it is happening */ + if (reqInfo == reqInfo->next) reqInfo->next = NULL; + /* Don't clear the last one */ + if ((reqInfo->next == NULL) && (options & NOT_LAST)) { + reqInfo->ownDNS = TRUE; + reqInfo->dns_host_lookup = FALSE; + return; + } tmp = reqInfo->next; free(reqInfo); + req_count--; reqInfo = tmp; gCurrentRequest = reqInfo; if (options & ONLY_LAST) return; } } +/* decode_request() + * given an HTTP request line as a string, decodes it into + * METHOD URL?ARGS PROTOCAL + * Then calls get_http_headers() to get the rfc822 style headers + */ void decode_request(per_request *reqInfo, char *request) { char *protocal; @@ -310,6 +409,7 @@ void decode_request(per_request *reqInfo, char *request) /* extract the URL, and args if present */ url = strtok (NULL, "\t\r "); + if (!url) die(reqInfo,SC_BAD_REQUEST,"Incomplete request."); if (url && (chp = strchr (url, '?'))) { *chp++ = '\0'; strcpy (reqInfo->args, chp); @@ -319,20 +419,22 @@ void decode_request(per_request *reqInfo, char *request) protocal = strtok (NULL, "\r"); if(!protocal) { - no_headers = 1; reqInfo->http_version = P_HTTP_0_9; } else { - no_headers = 0; - if (!strcmp(protocal,"HTTP/1.0")) + if (!strcmp(protocal,protocals[P_HTTP_1_0])) reqInfo->http_version = P_HTTP_1_0; - else if (!strcmp(protocal,"HTTP/1.1")) + else if (!strcmp(protocal,protocals[P_HTTP_1_0])) reqInfo->http_version = P_HTTP_1_1; + else if (!strcasecmp(protocal,protocals[P_SHTTP_1_1])) + reqInfo->http_version = P_SHTTP_1_1; + else if (!strcasecmp(protocal,protocals[P_SHTTP_1_2])) + reqInfo->http_version = P_SHTTP_1_2; else reqInfo->http_version = P_OTHER; /* dummy call to eat LF at end of protocal */ strtok (NULL, "\n"); - get_mime_headers(reqInfo); + get_http_headers(reqInfo); } /* fprintf(stderr,"method:%s url:%s args:%s prot:%s\n",method, @@ -340,61 +442,115 @@ void decode_request(per_request *reqInfo, char *request) } -void get_request(per_request *reqInfo) -{ - - signal(SIGPIPE,send_fd_timed_out); - - - if (getline(reqInfo->connection_socket, as_requested, HUGE_STRING_LEN, - 1, timeout) == -1) - return; - - if(!as_requested[0]) - return; - - strcpy(the_request, as_requested); - -#ifdef SETPROCTITLE - setproctitle(the_request); -#endif /* SETPROCTITLE */ - decode_request(reqInfo, as_requested); - unescape_url(reqInfo->url); - - /* Moved this to later so we can read the headers first for HTTP/1.1 - Host: support */ - which_host_conf(reqInfo); - if (reqInfo->ownDNS) { - /* Only when ownDNS set do we find out the remote host name info - and by which name the server was called */ - get_remote_host(reqInfo); - } - - if(reqInfo->method == M_HEAD) - header_only=1; - else if(reqInfo->method == M_GET) { - } - - process_request(reqInfo); - -} - +/* Returns a method number for a given method string. SHTTP requires + * case independent (as per standard network protocal). HTTP is broken, + * and is case dependent. + */ int MapMethod (char* method) { - if(!strcmp(method,"HEAD")) + if(!strcmp(method,methods[M_HEAD])) return M_HEAD; - else if(!strcmp(method,"GET")) + else if(!strcmp(method,methods[M_GET])) return M_GET; - else if(!strcmp(method,"POST")) + else if(!strcmp(method,methods[M_POST])) return M_POST; - else if(!strcmp(method,"PUT")) + else if(!strcmp(method,methods[M_PUT])) return M_PUT; - else if(!strcmp(method,"DELETE")) + else if(!strcmp(method,methods[M_DELETE])) return M_DELETE; + else if(!strcasecmp(method,methods[M_SECURE])) + return M_SECURE; else return M_INVALID; } +/* Globals for speed because of size, these are for get_http_headers */ +static char field_type[HUGE_STRING_LEN]; +static char unrec_hdr[HUGE_STRING_LEN]; +static char unrec_hdr_val[HUGE_STRING_LEN]; + +/* get_http_headers() (formerly get_mime_headers) + * Read line by line off from the client, and if we recognize a header, + * add it to reqInfo, otherwise let it go through to become an + * environment variable for CGI scripts. Also, SHTTP headers all start + * with SHTTP, so we pass them through to the SHTTP library. + * The Content-Type, Content-Length and Authorization headers don't get + * made into CGI variables (Content-Type, Content-Length are already + * defined in the CGI spec, and Authorization would be a security risk.) + */ +void get_http_headers(per_request *reqInfo) +{ + char *field_val; + int options = 0; + + while(getline(reqInfo->sb,field_type,HUGE_STRING_LEN-1,options, + timeout) != -1) { + + if(!field_type[0]) + return; + + if(!(field_val = strchr(field_type,':'))) + continue; + + *field_val++ = '\0'; + while(isspace(*field_val)) ++field_val; + + if(!strcasecmp(field_type,"Content-type")) { + strncpy(reqInfo->inh_content_type,field_val,MAX_STRING_LEN); + reqInfo->inh_content_type[MAX_STRING_LEN-1] = '\0'; + continue; + } else + if(!strcasecmp(field_type,"Authorization")) { + strncpy(reqInfo->inh_auth_line,field_val,HUGE_STRING_LEN); + reqInfo->inh_auth_line[HUGE_STRING_LEN-1]='\0'; + continue; + } else + if(!strcasecmp(field_type,"Host")) { + strncpy(reqInfo->inh_called_hostname, field_val, MAX_STRING_LEN); + reqInfo->inh_called_hostname[MAX_STRING_LEN-1] = '\0'; + } else + if(!strcasecmp(field_type,"Extension")) { + if (!strcasecmp(field_val, "Notify-Domain-Restriction")) + reqInfo->bNotifyDomainRestricted = 1; +#ifdef DIGEST_AUTH +/* Should we do something if we get this header? Maybe set a flag + * to know that a client doesn't accept this type of authentication? + */ +/* else if (!strcasecmp(field_val, "Security/Digest")); */ +#endif /* DIGEST_AUTH */ + } else + if(!strcasecmp(field_type,"Content-length")) { + sscanf(field_val,"%d",&(reqInfo->inh_content_length)); + continue; + } else + if(!strcasecmp(field_type,"Connection")) { + if (!strcasecmp(field_val, "Keep-Alive") && + keep_alive.bAllowKeepAlive) + keep_alive.bKeepAlive = 1; + } else + if(!strcasecmp(field_type,"User-agent")) { + strncpy(reqInfo->inh_agent, field_val, HUGE_STRING_LEN); + reqInfo->inh_agent[HUGE_STRING_LEN-1] = '\0'; + } else + if(!strcasecmp(field_type,"Referer")) { + strncpy(reqInfo->inh_referer, field_val, HUGE_STRING_LEN); + reqInfo->inh_referer[HUGE_STRING_LEN-1] = '\0'; + } else + if(!strcasecmp(field_type,"If-modified-since")) { + strncpy(reqInfo->inh_if_mod_since,field_val, MAX_STRING_LEN); + reqInfo->inh_if_mod_since[MAX_STRING_LEN-1] = '\0'; + } + http2cgi(unrec_hdr, field_type); + strcpy (unrec_hdr_val, field_val); + if(reqInfo->env) { + if(!merge_header(reqInfo,unrec_hdr,field_val)) + make_env_str(reqInfo,unrec_hdr,field_val); + } + else + make_env_str(reqInfo,unrec_hdr,field_val); + } +} + /* Split from get_request (the former process_request) so that we can call this from other places (on LOCAL_REDIRECTs and ErrorDocument handling) */ @@ -408,7 +564,6 @@ void process_request(per_request *reqInfo) case A_STD_DOCUMENT: if ((reqInfo->method == M_HEAD) && (reqInfo->http_version == P_HTTP_0_9)) { - header_only = 0; reqInfo->method = M_GET; die(reqInfo,SC_BAD_REQUEST,"Invalid HTTP/0.9 method."); } @@ -423,5 +578,71 @@ void process_request(per_request *reqInfo) case A_SCRIPT_CGI: exec_cgi_script(reqInfo); break; +#ifdef FCGI_SUPPORT + case A_SCRIPT_FCGI: + FastCgiHandler(reqInfo); + break; +#endif /* FCGI_SUPPORT */ } } + +/* RequestMain() + * The start of the request cycle. This routine starts reading off + * the socket, and also calls the messages for decoding (decode_request()), + * figuring out which virtual host (which_host_conf()), and getting the + * DNS info (get_remote_host()). It then calls process_request() to + * handle things once it has all of the information from the client + * (with the exception of an entity body). These are split so that + * process_request() can be called internally in the server to handle + * new request types (internal redirect handling and ErrorDoc) + */ +void RequestMain(per_request *reqInfo) +{ + int options = 0; + + signal(SIGPIPE,send_fd_timed_out); + +#ifdef LOG_DURATION + request_time = 0; +#endif /* LOG_DURATION */ + + if (reqInfo->sb == NULL) { + reqInfo->sb = new_sock_buf(reqInfo,reqInfo->in); + sockbuf_count++; + } + + if (getline(reqInfo->sb, as_requested, HUGE_STRING_LEN, + options, timeout) == -1) + return; + + if(!as_requested[0]) + return; + +#ifdef LOG_DURATION + request_time = time(NULL); +#endif /* LOG_DURATION */ + + strcpy(the_request, as_requested); + +#ifdef SETPROCTITLE + setproctitle(the_request); +#endif /* SETPROCTITLE */ + decode_request(reqInfo, as_requested); + unescape_url(reqInfo->url); + + /* Moved this to later so we can read the headers first for HTTP/1.1 + * Host: support + */ + which_host_conf(reqInfo); + + if (reqInfo->dns_host_lookup == FALSE) { + /* Only when we haven't done DNS do we call get_remote_host(). + * If we aren't supposed to, get_remote_host() will not do it. + */ + get_remote_host(reqInfo); + } + + process_request(reqInfo); + +} + diff --git a/src/http_request.h b/src/http_request.h index 11bb336..6f60a5c 100644 --- a/src/http_request.h +++ b/src/http_request.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * http_request.h,v 1.14 1995/11/09 01:48:21 blong Exp + * http_request.h,v 1.20 1996/04/05 18:55:04 blong Exp * ************************************************************************ * @@ -20,31 +20,37 @@ #ifndef _HTTP_REQUEST_H_ #define _HTTP_REQUEST_H_ +#include + /* globals defined in this module */ extern per_request *gCurrentRequest; -extern int no_headers; extern char *remote_logname; extern char failed_request[]; extern char failed_url[]; -extern int header_only; extern char the_request[]; /* Continue Request Options */ -#define NEW_URL 1 -#define NEW_DNS 2 -#define FORCE_GET 4 +#define COPY_URL 1 +#define FORCE_GET 2 +#define NOT_LAST 4 #define ONLY_LAST 8 #define KEEP_ENV 16 #define KEEP_AUTH 32 +#define NEW_SOCK_BUF 64 +extern int req_count; +extern int cgibuf_count; +extern int sockbuf_count; + /* function prototypes */ per_request *initialize_request(per_request *reqInfo); per_request *continue_request(per_request *reqInfo, int options); void free_request(per_request *reqInfo, int options); +void get_http_headers(per_request *reqInfo); void process_request(per_request *reqInfo); -void get_request(per_request *reqInfo); +void RequestMain(per_request *reqInfo); int MapMethod (char* method); #endif /* _HTTP_REQUEST_H_ */ diff --git a/src/http_send.c b/src/http_send.c index 535b7e3..ff13226 100644 --- a/src/http_send.c +++ b/src/http_send.c @@ -10,25 +10,14 @@ * ************************************************************************ * - * http_send.c,v 1.22 1995/11/28 09:02:09 blong Exp + * http_send.c,v 1.34 1996/04/05 18:55:06 blong Exp * ************************************************************************ * * http_send.c: handles sending of regular files and determining which * type of request it is if its not for a regular file * - * Based on NCSA HTTPd 1.3 by Rob McCool * - * 04-08-95 blong - * Fixed security hole which allowed a trailing slash on CGI_MAGIC_TYPE - * cgi anywhere scripts to send back the script contents. Now the - * trailing slash is added to the PATH_INFO, and the script is run. - * Oh yeah, and don't forget about directories. - * - * 09-01-95 blong - * Fixed bug under AIX 3.2.5 where last part of file is garbled using - * fwrite, but works fine with write. I didn't say I understood it, - * but the fix seems to work. */ @@ -39,6 +28,13 @@ #ifndef NO_STDLIB_H # include #endif /* NO_STDLIB_H */ +#ifdef HAVE_STDARG +# include +#else +# ifdef HAVE_VARARGS +# include +# endif /* HAVE_VARARGS */ +#endif /* HAVE_STDARG */ #include #include #include @@ -47,6 +43,7 @@ #include #include "constants.h" #include "fdwrap.h" +#include "allocate.h" #include "http_send.h" #include "cgi.h" #include "imagemap.h" @@ -60,17 +57,16 @@ #include "http_dir.h" #include "httpd.h" #include "util.h" +#include "blackout.h" +#ifdef FCGI_SUPPORT +# include "fcgi.h" +#endif /* FCGI_SUPPORT */ - -int num_includes; - -static void (*exit_callback)(void); +void (*exit_callback)(void); void send_node(per_request *reqInfo) { struct stat finfo; - char pa[MAX_STRING_LEN]; - int length = 0; register x = 0; int allow; char allow_options; @@ -78,32 +74,32 @@ void send_node(per_request *reqInfo) exit_callback = NULL; -/* Remove all but 1 of the trailing slashes from the filename in order - to fix security hole. Place them in the path alias (pa) array */ +/* It is no longer necessary to move all but one of the trailing slashes + * to the path_info string, since all multiple slashes are now compressed + * to one as a security precaution. + */ - - length = strlen(reqInfo->filename); - while ((length>1) && (reqInfo->filename[length-1] == '/') && - (reqInfo->filename[length-2] == '/') && (x < MAX_STRING_LEN)) { - pa[x] = '/'; - x++; - reqInfo->filename[length-1] = '\0'; - length--; - } - pa[x] = '\0'; if(stat(reqInfo->filename,&finfo) == -1) { - if ((ErrReturn = extract_path_info(reqInfo,pa,&finfo))) { - if(ErrReturn == ENOENT) { - log_reason(reqInfo,"file does not exist",reqInfo->filename); - die(reqInfo,SC_NOT_FOUND,reqInfo->url); - } else { - log_reason(reqInfo,"(3) file permissions deny server access", - reqInfo->filename); - die(reqInfo,SC_FORBIDDEN,reqInfo->url); - } - } + ErrReturn = extract_path_info(reqInfo,&finfo); } evaluate_access(reqInfo,&finfo,&allow,&allow_options); + if (ErrReturn) { + if(ErrReturn == ENOENT) { + log_reason(reqInfo,"file does not exist",reqInfo->filename); + die(reqInfo,SC_NOT_FOUND,reqInfo->url); +/* Check for AFS/NFS problems, and send back an unavailable message instead + * Larry Schwimmer (schwim@cyclone.stanford.edu) + */ + } else if ((ErrReturn == ETIMEDOUT) || (ErrReturn == ENODEV)) { + log_reason(reqInfo, "file temporarily unavailable", + reqInfo->filename); + die(reqInfo,SC_SERVICE_UNAVAIL,reqInfo->url); + } else { + log_reason(reqInfo,"(3) file permissions deny server access", + reqInfo->filename); + die(reqInfo,SC_FORBIDDEN,reqInfo->url); + } + } if(!allow) { log_reason(reqInfo,"client denied by server configuration", reqInfo->filename); @@ -111,17 +107,30 @@ void send_node(per_request *reqInfo) } if (S_ISDIR(finfo.st_mode)) { - send_dir(reqInfo,&finfo,pa,allow_options); + send_dir(reqInfo,&finfo,allow_options); } else if (S_ISREG(finfo.st_mode)) { + x = strlen(reqInfo->filename); + /* Remove the trailing slash if its not a directory */ + if (reqInfo->filename[x-1] == '/') { + if (reqInfo->path_info[0] == '\0') { + reqInfo->path_info[0] = '/'; + reqInfo->path_info[1] = '\0'; + } + reqInfo->filename[x-1] = '\0'; + } probe_content_type(reqInfo,reqInfo->filename); - if (!strcmp(content_type, CGI_MAGIC_TYPE)) - send_cgi(reqInfo,&finfo,pa,allow_options); + if (!strcmp(reqInfo->outh_content_type, CGI_MAGIC_TYPE)) + send_cgi(reqInfo,&finfo,allow_options); #ifdef IMAGEMAP_SUPPORT - else if (!strcmp(content_type, IMAGEMAP_MAGIC_TYPE)) - send_imagemap(reqInfo,&finfo,pa,allow_options); + else if (!strcmp(reqInfo->outh_content_type, IMAGEMAP_MAGIC_TYPE)) + send_imagemap(reqInfo,&finfo,allow_options); #endif /* IMAGEMAP_SUPPORT */ +#ifdef FCGI_SUPPORT + else if (!strcmp(reqInfo->outh_content_type, FCGI_MAGIC_TYPE)) + FastCgiHandler(reqInfo); +#endif /* FCGI_SUPPORT */ else - send_file(reqInfo,&finfo,pa,allow_options); + send_file(reqInfo,&finfo,allow_options); } else { log_reason(reqInfo,"improper file type",reqInfo->filename); /* device driver or pipe, no permission */ @@ -129,10 +138,12 @@ void send_node(per_request *reqInfo) } } -void send_file(per_request *reqInfo, struct stat *fi, - char *path_args, char allow_options) +void send_file(per_request *reqInfo, struct stat *fi, char allow_options) { FILE *f; +#ifdef BLACKOUT_CODE + int isblack = FALSE; +#endif /* BLACKOUT_CODE */ if ((reqInfo->method != M_GET) && (reqInfo->method != M_HEAD)) { sprintf(error_msg,"%s to non-script",methods[reqInfo->method]); @@ -140,23 +151,22 @@ void send_file(per_request *reqInfo, struct stat *fi, } set_content_type(reqInfo,reqInfo->filename); - if((allow_options & OPT_INCLUDES) && (!content_encoding[0])) { + if((allow_options & OPT_INCLUDES) && (!reqInfo->outh_content_encoding[0])) { #ifdef XBITHACK if((fi->st_mode & S_IXUSR) || - (!strcmp(content_type,INCLUDES_MAGIC_TYPE))) { + (!strcmp(reqInfo->outh_content_type,INCLUDES_MAGIC_TYPE))) { #else - if(!strcmp(content_type,INCLUDES_MAGIC_TYPE)) { + if(!strcmp(reqInfo->outh_content_type,INCLUDES_MAGIC_TYPE)) { #endif /* XBITHACK */ reqInfo->bytes_sent = 0; - send_parsed_file(reqInfo,path_args, - allow_options & OPT_INCNOEXEC); + send_parsed_file(reqInfo, allow_options & OPT_INCNOEXEC); log_transaction(reqInfo); return; } } - if (path_args[0]) { - strcat(reqInfo->filename,path_args); - strcat(reqInfo->url,path_args); + if (reqInfo->path_info[0]) { + strcat(reqInfo->filename,reqInfo->path_info); + strcat(reqInfo->url,reqInfo->path_info); sprintf(error_msg,"No file matching URL: %s",reqInfo->url); log_reason(reqInfo, error_msg, reqInfo->filename); die(reqInfo,SC_NOT_FOUND,reqInfo->url); @@ -181,49 +191,75 @@ void send_file(per_request *reqInfo, struct stat *fi, } } reqInfo->bytes_sent = 0; - if(!no_headers) { + +#ifdef BLACKOUT_CODE + if (!strcmp(reqInfo->outh_content_type,BLACKOUT_MAGIC_TYPE)) { + isblack = TRUE; + strcpy(reqInfo->outh_content_type,"text/html"); + } +#endif /* BLACKOUT_CODE */ + + if(reqInfo->http_version != P_HTTP_0_9) { + /* No length dependent headers since black is parsed */ +#ifdef BLACKOUT_CODE + if (isblack == FALSE) { +#endif /* BLACKOUT_CODE */ +#ifdef CONTENT_MD5 + reqInfo->outh_content_md5 = (unsigned char *)md5digest(f); +#endif /* CONTENT_MD5 */ set_content_length(reqInfo,fi->st_size); if (set_last_modified(reqInfo,fi->st_mtime)) { FClose(f); return; } - send_http_header(reqInfo); + } + if (reqInfo->http_version != P_HTTP_0_9) { + send_http_header(reqInfo); + } +#ifdef BLACKOUT_CODE } +#endif /* BLACKOUT_CODE */ - num_includes = 0; - if(!header_only) + if(reqInfo->method != M_HEAD) { +#ifdef BLACKOUT_CODE + if (isblack == TRUE) + send_fp_black(reqInfo,f,NULL); + else +#endif /* BLACKOUT_CODE */ send_fp(reqInfo,f,NULL); + } log_transaction(reqInfo); FClose(f); } -/* Globals for speed */ -static char ifile[HUGE_STRING_LEN]; -static char temp_name[HUGE_STRING_LEN]; -void send_dir(per_request *reqInfo,struct stat *finfo, char *pa, - char allow_options) { +void send_dir(per_request *reqInfo,struct stat *finfo, char allow_options) { char *name_ptr, *end_ptr; + char *ifile, *temp_name; + + ifile = newString(HUGE_STRING_LEN,STR_TMP); + temp_name = newString(HUGE_STRING_LEN,STR_TMP); /* Path Alias (pa) array should now have the trailing slash */ /* if (pa[0] != '/') { */ if ((reqInfo->filename[strlen(reqInfo->filename) - 1] != '/') && - (pa[0] != '/')) { - char url[HUGE_STRING_LEN]; + (reqInfo->path_info[0] != '/')) { strcpy_dir(ifile,reqInfo->url); - construct_url(url,reqInfo->hostInfo,ifile); - escape_url(url); - die(reqInfo,SC_REDIRECT_PERM,url); + construct_url(temp_name,reqInfo->hostInfo,ifile); + escape_url(temp_name); + die(reqInfo,SC_REDIRECT_PERM,temp_name); } /* Don't allow PATH_INFO to directory indexes as a compromise for error messages for files which don't exist */ - if ((pa[0] != '\0') || (strlen(pa) > 1)) { - strcat(reqInfo->filename,pa); - strcat(reqInfo->url,pa); + if ((reqInfo->path_info[0] != '\0') || (strlen(reqInfo->path_info) > 1)) { + strcat(reqInfo->filename,reqInfo->path_info); + strcat(reqInfo->url,reqInfo->path_info); sprintf(error_msg,"No file matching URL: %s",reqInfo->url); log_reason(reqInfo, error_msg, reqInfo->filename); + freeString(temp_name); + freeString(ifile); die(reqInfo,SC_NOT_FOUND,reqInfo->url); } @@ -243,30 +279,40 @@ void send_dir(per_request *reqInfo,struct stat *finfo, char *pa, make_full_path(reqInfo->filename,name_ptr,ifile); if(stat(ifile,finfo) == -1) { if(! *end_ptr && (allow_options & OPT_INDEXES)) { - if (pa[0]) { - strcat(reqInfo->filename,pa); - strcat(reqInfo->url,pa); + if (reqInfo->path_info[0]) { + strcat(reqInfo->filename,reqInfo->path_info); + strcat(reqInfo->url,reqInfo->path_info); log_reason(reqInfo,"file does not exist",reqInfo->filename); + freeString(ifile); + freeString(temp_name); die(reqInfo,SC_NOT_FOUND,reqInfo->url); } if ((reqInfo->method != M_GET) && (reqInfo->method != M_HEAD)) { sprintf(error_msg,"%s to non-script",methods[reqInfo->method]); + freeString(ifile); + freeString(temp_name); die(reqInfo,SC_NOT_IMPLEMENTED,error_msg); } index_directory(reqInfo); + freeString(ifile); + freeString(temp_name); return; } else if (! *end_ptr) { log_reason(reqInfo,"(2) file permissions deny server access", reqInfo->filename); + freeString(ifile); + freeString(temp_name); die(reqInfo,SC_FORBIDDEN,reqInfo->url); } } else { strcpy(reqInfo->filename,ifile); probe_content_type(reqInfo,reqInfo->filename); - if(!strcmp(content_type,CGI_MAGIC_TYPE)) - send_cgi(reqInfo,finfo,pa,allow_options); + if(!strcmp(reqInfo->outh_content_type,CGI_MAGIC_TYPE)) + send_cgi(reqInfo,finfo,allow_options); else - send_file(reqInfo,finfo,pa, allow_options); + send_file(reqInfo,finfo,allow_options); + freeString(ifile); + freeString(temp_name); return; } name_ptr = end_ptr; @@ -274,45 +320,162 @@ void send_dir(per_request *reqInfo,struct stat *finfo, char *pa, } /* Search down given translated URL searching for actual file name and filling - in path_args string. Doesn't make any claims about file type, must be - handled elsewhere. - Returns 0 on success, errno on failure - */ -int extract_path_info(per_request *reqInfo, char *path_args, - struct stat *finfo) + * in path_info string. Doesn't make any claims about file type, must be + * handled elsewhere. + * Returns 0 on success, errno on failure + */ +int extract_path_info(per_request *reqInfo, struct stat *finfo) { register int x,max; - char t[HUGE_STRING_LEN]; + char *str; + int l,u; + + str = newString(HUGE_STRING_LEN,STR_TMP); max=count_dirs(reqInfo->filename); for(x=max ; x > 0 ; x--) { - make_dirstr(reqInfo->filename,x+1,t); - if(!(stat(t,finfo))) { - int l=strlen(t); - strcat(path_args,&(reqInfo->filename[l])); + make_dirstr(reqInfo->filename,x+1,str); + l=strlen(str); + u=strlen(reqInfo->url); + if(!(stat(str,finfo)) && + !strcmp(reqInfo->filename+l, reqInfo->url+u-strlen(reqInfo->filename+ l))) + { + strcat(reqInfo->path_info,&(reqInfo->filename[l])); reqInfo->filename[l] = '\0'; - reqInfo->url[strlen(reqInfo->url) - strlen(path_args)] = '\0'; + reqInfo->url[strlen(reqInfo->url) - strlen(reqInfo->path_info)]='\0'; + freeString(str); return 0; } } + freeString(str); return errno; } + +/* Dump the headers of the per_request structure to the client. + * Will also set the status line if it hasn't already been set, + * will set to 302 if location, 401 if auth required, 200 otherwise. + * Will dump the following headers: + * Date GMT Date in rfc 822 format + * Server SERVER_VERSION + * Annotations-cgi reqInfo->hostInfo->annotation_server + * Location reqInfo->outh_location + * Last-modified reqInfo->outh_last_mod + * Content-type reqInfo->outh_content_type + * Content-length reqInfo->outh_content_length + * Content-encoding reqInfo->outh_content_encoding + * Content-MD5 reqInfo->outh_content_md5 + * WWW-Authenticate reqInfo->outh_www_auth + * Extension: Domain-Restricted reqInfo->bNotifyDomainRestricted && + * reqInfo->bSatisfiedDomain + * Connection: Keep-Alive keep_alive. stuff + * Keep-Alive: max= timeout= same + * other headers from CGI reqInfo->outh_cgi + * We don't dump the MIME-Version header that NCSA HTTP/1.3 did, because + * the server is not mime-compliant. + * + * Should we only give back HTTP/1.0 headers to 1.0 clients? The docs are + * unclear on this, and almost all clients (even ones supporting 1.1 features) + * are sending HTTP/1.0 anyways, so we will for now. + */ + +void send_http_header(per_request *reqInfo) +{ + if(!reqInfo->status_line) { + /* Special Cases */ + if(reqInfo->outh_location[0]) + reqInfo->status = SC_REDIRECT_TEMP; + if(reqInfo->outh_www_auth[0]) + reqInfo->status = SC_AUTH_REQUIRED; + set_stat_line(reqInfo); + } + rprintf(reqInfo,"%s %s%c%c",protocals[reqInfo->http_version], + reqInfo->status_line,CR,LF); + rprintf(reqInfo,"Date: %s%c%c",gm_timestr_822(time(NULL)),CR,LF); + rprintf(reqInfo,"Server: %s%c%c",SERVER_VERSION,CR,LF); + if (reqInfo->hostInfo->annotation_server[0]) + rprintf(reqInfo,"Annotations-cgi: %s%c%c", + reqInfo->hostInfo->annotation_server,CR,LF); + + if(reqInfo->outh_location[0]) + rprintf(reqInfo,"Location: %s%c%c", + reqInfo->outh_location,CR,LF); + if(reqInfo->outh_last_mod[0]) + rprintf(reqInfo,"Last-modified: %s%c%c", + reqInfo->outh_last_mod,CR,LF); + + if(reqInfo->outh_content_type[0]) + rprintf(reqInfo,"Content-type: %s%c%c", + reqInfo->outh_content_type,CR,LF); + +/* If we know the content_length, we can fulfill byte range requests */ + if(reqInfo->outh_content_length >= 0) { +/* Not yet, working on it */ +/* rprintf(reqInfo,"Accept-Ranges: bytes%c%c",CR,LF); */ + rprintf(reqInfo,"Content-length: %d%c%c", + reqInfo->outh_content_length,CR,LF); + } + if(reqInfo->outh_content_encoding[0]) + rprintf(reqInfo,"Content-encoding: %s%c%c", + reqInfo->outh_content_encoding,CR,LF); +#ifdef CONTENT_MD5 + if(reqInfo->outh_content_md5) + rprintf(reqInfo,"Content-MD5: %s%c%c", + reqInfo->outh_content_md5,CR,LF); +#endif /* CONTENT_MD5 */ + + if(reqInfo->outh_www_auth[0]) + rprintf(reqInfo,"WWW-Authenticate: %s%c%c", + reqInfo->outh_www_auth,CR,LF); + + if (reqInfo->bNotifyDomainRestricted && reqInfo->bSatisfiedDomain) + rprintf(reqInfo,"Extension: Domain-Restricted%c%c",CR,LF); + + keep_alive.bKeepAlive = keep_alive.bKeepAlive && + (reqInfo->outh_content_length >= 0); + if (keep_alive.bKeepAlive && (!keep_alive.nMaxRequests || + keep_alive.nCurrRequests + 1 < + keep_alive.nMaxRequests)) { + keep_alive.bKeepAlive = 1; + rprintf(reqInfo, + "Connection: Keep-Alive%c%cKeep-Alive: max=%d, timeout=%d%c%c", + CR,LF, keep_alive.nMaxRequests, keep_alive.nTimeOut,CR,LF); + } + if(reqInfo->outh_cgi) + rprintf(reqInfo,"%s",reqInfo->outh_cgi); + + rprintf(reqInfo,"%c%c",CR,LF); + +/* CLF doesn't include the headers, I don't think, so clear the information + * on what has been sent so far (byte count wise) + */ + reqInfo->bytes_sent = 0; +/* rflush(reqInfo); */ +} + + +/* Time out function for send_fd and send_fp + * Logs whether an Abort or Time out occurs, logs how much has been sent, + * Does some cleanup (CloseAll) and either exits of jumps back + */ + + void send_fd_timed_out(int sigcode) { - char errstr[MAX_STRING_LEN]; + char *errstr; + errstr = newString(HUGE_STRING_LEN,STR_TMP); if(exit_callback) (*exit_callback)(); if (sigcode != SIGPIPE) { - sprintf(errstr,"httpd: send timed out for %s, URL: %s", - (gCurrentRequest->remote_name ? - gCurrentRequest->remote_name : "remote host"), - (gCurrentRequest->url ? gCurrentRequest->url : "-")); + sprintf(errstr,"HTTPd: send timed out for %s, URL: %s", + (gCurrentRequest->remote_name ? + gCurrentRequest->remote_name : "remote host"), + (gCurrentRequest->url ? gCurrentRequest->url : "-")); } else { - sprintf(errstr,"httpd: send aborted for %s, URL: %s", - (gCurrentRequest->remote_name ? - gCurrentRequest->remote_name : "remote host"), + sprintf(errstr,"HTTPd: send aborted for %s, URL: %s", + (gCurrentRequest->remote_name ? + gCurrentRequest->remote_name : "remote host"), (gCurrentRequest->url ? gCurrentRequest->url : "-")); } log_error(errstr,gCurrentRequest->hostInfo->error_log); @@ -335,26 +498,33 @@ void send_fd_timed_out(int sigcode) } } -/* - We'll make it return the number of bytes sent - so that we know if we need to send a body by default -*/ +/* send_fp(): sends a file pointer to the socket. Uses fread to read, + * but uses non-buffered I/O for writes (write()) + * + * We'll make it return the number of bytes sent + * so that we know if we need to send a body by default + */ long send_fp(per_request *reqInfo, FILE *f, void (*onexit)(void)) { - char buf[IOBUFSIZE]; + char *buf; long total_bytes_sent; register int n,o,w; + /* ADC hack ZZZZ */ + /* blong Unused? */ + /* int i; */ + buf = newString(IOBUFSIZE,STR_TMP); exit_callback = onexit; signal(SIGALRM,send_fd_timed_out); signal(SIGPIPE,send_fd_timed_out); total_bytes_sent = 0; - fflush(reqInfo->out); + rflush(reqInfo); while (1) { alarm(timeout); if((n=fread(buf,sizeof(char),IOBUFSIZE,f)) < 1) { if (errno != EINTR) break; + else errno = 0; } o=0; @@ -366,18 +536,67 @@ long send_fp(per_request *reqInfo, FILE *f, void (*onexit)(void)) * For now, we'll just replace, but may have to #define one or the other * depending on the system. */ -/* w=fwrite(&buf[o],sizeof(char),n,reqInfo->out); */ - if ((w=write(fileno(reqInfo->out),&buf[o],n)) < 0) { + w = write(fileno(reqInfo->out),&buf[o],n); + if (w < 0) { if (errno != EINTR) break; + else errno = 0; } + /* there goes ADC again... ZZZZ */ +/* +for (i = 0; iout); */ alarm(0); signal(SIGALRM,SIG_IGN); signal(SIGPIPE,SIG_IGN); + freeString(buf); return total_bytes_sent; } + +/* rprintf() will print out to the socket, using buffered I/O + */ +int rprintf(per_request *reqInfo, char *format, ...) +{ + va_list argList; + int x; + +#ifndef HAVE_VARARGS + va_start(argList,format); +#else + va_start(argList); +#endif /* HAVE_VARARGS */ + x = vfprintf(reqInfo->out, format, argList); + + + va_end(argList); + + reqInfo->bytes_sent += x; + return x; + +} + +/* rputs() for drop into fputs(), for now. + */ +int rputs(char *string, per_request *reqInfo) +{ + reqInfo->bytes_sent += strlen(string); + return fputs(string,reqInfo->out); +} + +int rputc(int ch, per_request *reqInfo) +{ + (reqInfo->bytes_sent)++; + return putc(ch, reqInfo->out); +} + +int rflush(per_request *reqInfo) +{ + return fflush(reqInfo->out); +} diff --git a/src/http_send.h b/src/http_send.h index 1b6dc33..27ab427 100644 --- a/src/http_send.h +++ b/src/http_send.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * http_send.h,v 1.6 1995/11/28 09:02:11 blong Exp + * http_send.h,v 1.10 1996/03/27 20:44:12 blong Exp * ************************************************************************ * @@ -20,16 +20,21 @@ #ifndef _HTTP_SEND_H_ #define _HTTP_SEND_H_ +extern void (*exit_callback)(void); + /* function prototypes */ void send_node(per_request *reqInfo); -void send_file(per_request *reqInfo, struct stat *fi, - char *path_args, char allow_options); -void send_dir(per_request *reqInfo,struct stat *finfo, char *pa, - char allow_options); -int extract_path_info(per_request *reqInfo, char *path_args, - struct stat *finfo); +void send_file(per_request *reqInfo, struct stat *fi, char allow_options); +void send_dir(per_request *reqInfo,struct stat *finfo, char allow_options); +int extract_path_info(per_request *reqInfo, struct stat *finfo); long send_fp(per_request *reqInfo, FILE *f, void (*onexit)(void)); void send_fd_timed_out(int); +void send_http_header(per_request *reqInfo); + +int rprintf(per_request *reqInfo, char *format, ...); +int rputs(char *string, per_request *reqInfo); +int rputc(int ch, per_request *reqInfo); +int rflush(per_request *reqInfo); #endif /* _HTTP_SEND_H_ */ diff --git a/src/httpd.c b/src/httpd.c index 4872a15..fee4d68 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -10,7 +10,7 @@ * ************************************************************************ * - * httpd.c,v 1.115 1995/11/28 09:02:12 blong Exp + * httpd.c,v 1.131 1996/04/05 18:55:09 blong Exp * ************************************************************************ * @@ -18,36 +18,12 @@ * * * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3) + * 05-17-95 NCSA HTTPd 1.4.1 + * 05-01-95 NCSA HTTPd 1.4.2 + * 11-10-95 NCSA HTTPd 1.5.0 + * 11-14-95 NCSA HTTPd 1.5.0a + * 03-21-96 NCSA HTTPd 1.5.0c * - * 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-28-95 guillory - * Changed search pattern on child processes to better distribute load - * - * 04-30-95 blong - * added patch by Kevin Steves (stevesk@mayfield.hp.com) to fix - * rfc931 logging. We were passing sa_client, but this information - * wasn't known yet at the time of the pass to the child. Now uses - * getpeername in child_main to find this information. - * - * 08-16-95 blong - * added patch by Vince Tkac (tkac@oclc.org) to allow restart when - * a relative path is used on the command line with -f - * - * 10-26-95 blong - * added a RESOURCE_LIMIT compiletime option which limits the number - * of possible servers running to MaxServers - * - * 10-26-95 blong - * added patch by Stuart Lynne (sl@wimsey.com) to turn the proc title - * into a tachometer */ @@ -87,10 +63,11 @@ # include #endif /* NEED_SELECT_H */ #ifndef NO_SYS_RESOURCE_H -#include +# include #endif /* NO_SYS_RESOURCE_H */ #include "constants.h" #include "fdwrap.h" +#include "allocate.h" #include "httpd.h" #include "http_request.h" #include "http_config.h" @@ -101,25 +78,31 @@ #include "http_dir.h" #include "http_ipc.h" #include "http_mime.h" +#include "http_send.h" #include "util.h" -JMP_BUF jmpbuffer; JMP_BUF restart_buffer; -int servernum=0; int mainSocket; pid_t pgrp; +int debug_mode = FALSE; + +/* Current global information per child, will need to be made + * non-global for threading + */ +#ifndef NOT_READY int Child=0; int Alone=0; -int csd = -1; /* To keep from being clobbered with setjmp */ -static per_request *reqInfo = NULL; - +JMP_BUF jmpbuffer; +int csd = -1; KeepAliveData keep_alive; /* global keep alive info */ +#endif /* NOT_READY */ + +ChildInfo *Children; +int num_children = 0; #ifndef NO_PASS char donemsg[]="DONE"; -ChildInfo *Children; -int num_children = 0; #endif /* NO_PASS */ #if defined(KRB4) || defined(KRB5) @@ -135,7 +118,7 @@ void htexit(per_request *reqInfo, int status, int die_type) if(standalone || keep_alive.bKeepAlive) siglongjmp(jmpbuffer,die_type); #endif /* NO_SIGLONGJMP */ else { - fflush(reqInfo->out); + rflush(reqInfo); exit(status); } } @@ -159,20 +142,20 @@ void detach(void) if((x = fork()) > 0) exit(0); else if(x == -1) { - fprintf(stderr,"httpd: unable to fork new process\n"); + 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"); + fprintf(stderr,"HTTPd: setsid failed\n"); perror("setsid"); exit(1); } #else if((pgrp=setpgrp(getpid(),0)) == -1) { - fprintf(stderr,"httpd: setpgrp failed\n"); + fprintf(stderr,"HTTPd: setpgrp failed\n"); perror("setpgrp"); exit(1); } @@ -225,7 +208,7 @@ void seg_fault(void) close_all_logs(); chdir(core_dir); abort(); - exit(1); +/* exit(1); */ } void dump_debug(void) { @@ -234,6 +217,8 @@ void dump_debug(void) { log_error("HTTPd: caught USR1, dumping debugging information", gConfiguration->error_log); + fprintf(gConfiguration->error_log," ReqInfo: %d\tSockbuf: %d\tCGbuf: %d\n", + req_count,sockbuf_count,cgibuf_count); tmp = gCurrentRequest; while (tmp != NULL) { fprintf(gConfiguration->error_log," Status: %d \t\t Bytes: %ld\n",tmp->status, @@ -247,11 +232,11 @@ void dump_debug(void) { fprintf(gConfiguration->error_log," Host: %s \t IP: %s\n", tmp->remote_host, tmp->remote_ip); fprintf(gConfiguration->error_log," Content-type: %s \t Content-Length: %d\n", - content_type, content_length); + tmp->outh_content_type, tmp->outh_content_length); fprintf(gConfiguration->error_log," Refererer: %s\n", - tmp->referer); + tmp->inh_referer); fprintf(gConfiguration->error_log," User Agent: %s\n", - tmp->agent); + tmp->inh_agent); if (tmp->hostInfo->server_hostname) fprintf(gConfiguration->error_log," ServerName: %s\n", tmp->hostInfo->server_hostname); @@ -266,7 +251,7 @@ void dump2(void) { log_error("HTTPd: caught USR2, dumping debugging information", gConfiguration->error_log); - purify_new_leaks(); + purify_new_leaks(); } #endif /* PURIFY */ @@ -333,6 +318,9 @@ void set_group_privs(void) fakeit.out = stdout; fakeit.hostInfo = gConfiguration; + /* Only change if root. Changed to geteuid() so that setuid scripts, etc + * can start the server and change from root + */ if (!geteuid()) { /* Change standalone so that on error, we die, instead of siglongjmp */ tmp_stand = standalone; @@ -370,6 +358,7 @@ void speed_hack_libs(void) char buf[MAX_STRING_LEN]; strftime (buf, MAX_STRING_LEN, "%d/%b/%Y:%H:%M:%S", dummy_time); + strftime (buf, MAX_STRING_LEN, "%d/%b/%Y:%H:%M:%S", other_dummy_time); } /* @@ -378,7 +367,7 @@ void speed_hack_libs(void) * another request is ready, or the timeout period is up. */ -int WaitForRequest (int csd, KeepAliveData *kad) +int wait_keepalive(int csd, KeepAliveData *kad) { fd_set listen_set; struct timeval ka_timeout; @@ -401,20 +390,31 @@ int WaitForRequest (int csd, KeepAliveData *kad) } } -void CompleteRequest (per_request *reqInfo, int pipe) +void CompleteRequest(per_request *reqInfo, int pipe) { + /* Changed from shutdown(csd,2) to allow kernel to finish sending data - required on OSF/1 2.0 (Achille Hui (eillihca@drizzle.stanford.edu)) */ - shutdown(csd,0); + * required on OSF/1 2.0 (Achille Hui (eillihca@drizzle.stanford.edu)) */ +/* shutdown(csd,0); */ + shutdown(csd,2); close(csd); #ifndef NO_PASS if (pipe >= 0) { write(pipe,donemsg,sizeof(donemsg)); + if (reqInfo != NULL) reqInfo->RequestFlags = 0; + free_request(reqInfo,NOT_LAST); CloseAll(); + freeAllStrings(STR_REQ); kill_indexing(FI_LOCAL); - free_request(reqInfo,0); +/* current_process_size("CompleteRequest/2"); */ +#ifdef QUANTIFY +/* quantify_save_data(); */ +#endif /* QUANTIFY */ } else #endif /* NO_PASS */ +#ifdef QUANTIFY +/* quantify_save_data(); */ +#endif /* QUANTIFY */ #ifdef PROFILE exit (2); #else @@ -425,12 +425,20 @@ void CompleteRequest (per_request *reqInfo, int pipe) void child_alone(int csd, struct sockaddr_in *sa_server, CLIENT_SOCK_ADDR *sa_client) { +static per_request *reqInfo = NULL; +#ifndef THREADED close(mainSocket); +#endif /* THREADED */ + #ifdef PROFILE moncontrol(1); #endif /* PROFILE */ - +#ifdef QUANTIFY +/* quantify_clear_data(); */ + quantify_start_recording_data(); +#endif /* QUANTIFY */ + Child = Alone = 1; standalone = 0; keep_alive.nCurrRequests = 0; @@ -444,12 +452,12 @@ void child_alone(int csd, struct sockaddr_in *sa_server, } } - - /* this should check error status, but it's not crucial */ +#ifndef THREADED close(0); close(1); dup2(csd,0); dup2(csd,1); +#endif /* THREADED */ remote_logname = (!do_rfc931 ? NULL : rfc931((struct sockaddr_in *)sa_client, @@ -460,49 +468,46 @@ void child_alone(int csd, struct sockaddr_in *sa_server, #else if (sigsetjmp(jmpbuffer,1) != 0) { #endif /* NO_SIGLONGJMP */ - /* WaitForRequests returns 0 if timeout */ + /* wait_keepalive returns 0 if timeout */ /* CompleteRequest doesn't return */ - fflush(gCurrentRequest->out); + rflush(gCurrentRequest); kill_indexing(FI_LOCAL); if ((keep_alive.nMaxRequests && (++keep_alive.nCurrRequests >= keep_alive.nMaxRequests)) || - !WaitForRequest(csd, &keep_alive)) { + !wait_keepalive(csd, &keep_alive)) { CompleteRequest(gCurrentRequest,-1); - reqInfo = NULL; } } while (1) { reqInfo = initialize_request(reqInfo); reqInfo->connection_socket = 0; + reqInfo->in = 0; reqInfo->out = stdout; - get_request(reqInfo); - fflush(reqInfo->out); + RequestMain(reqInfo); + rflush(reqInfo); kill_indexing(FI_LOCAL); if (!keep_alive.bKeepAlive) { CompleteRequest(reqInfo,-1); - reqInfo = NULL; } else if ((keep_alive.nMaxRequests && (++keep_alive.nCurrRequests >= keep_alive.nMaxRequests)) - || !WaitForRequest(csd, &keep_alive)) { + || !wait_keepalive(csd, &keep_alive)) { CompleteRequest(reqInfo,-1); - reqInfo = NULL; } } } -#ifndef NO_PASS /* to keep from being clobbered by setjmp */ static int x; static int val; /* indicates if keep_alive should remain active */ -static int nFirst = 0; #ifdef FD_LINUX static int switch_uid = 0; #endif /* FD_LINUX */ void child_main(int parent_pipe, SERVER_SOCK_ADDR *sa_server) { + static per_request *reqInfo = NULL; close(mainSocket); #ifdef PROFILE @@ -510,7 +515,8 @@ void child_main(int parent_pipe, SERVER_SOCK_ADDR *sa_server) #endif /* PROFILE */ #ifdef QUANTIFY - quantify_clear_data(); +/* quantify_clear_data(); */ + quantify_start_recording_data(); #endif /* QUANTIFY */ /* Only try to switch if we're running as root */ @@ -547,12 +553,14 @@ void child_main(int parent_pipe, SERVER_SOCK_ADDR *sa_server) standalone = 1; } +#ifndef THREADED for(x=0;xout); + rflush(reqInfo); kill_indexing(FI_LOCAL); if (val == DIE_KEEPALIVE) { /* returns 0 if timeout during multiple request session */ if ((keep_alive.nMaxRequests && (++keep_alive.nCurrRequests >= keep_alive.nMaxRequests)) - || !WaitForRequest(csd, &keep_alive)) { + || !wait_keepalive(csd, &keep_alive)) { keep_alive.bKeepAlive = 0; CompleteRequest(reqInfo,parent_pipe); - reqInfo = NULL; } } else { /* in case it was in effect. probably a better place to reset */ keep_alive.bKeepAlive = 0; CompleteRequest(reqInfo,parent_pipe); - reqInfo = NULL; } } while (1) { alarm (0); - if (!nFirst || !keep_alive.bKeepAlive) { + if (!keep_alive.bKeepAlive) { GetDescriptor (parent_pipe); remote_logname = GetRemoteLogName(sa_server); - nFirst = 1; keep_alive.nCurrRequests = 0; + if (reqInfo != NULL) reqInfo->RequestFlags = 0; } reqInfo = initialize_request(reqInfo); reqInfo->connection_socket = 0; + reqInfo->in = 0; reqInfo->out = stdout; - get_request(reqInfo); - fflush(reqInfo->out); + RequestMain(reqInfo); + rflush(reqInfo); kill_indexing(FI_LOCAL); if (!keep_alive.bKeepAlive) { CompleteRequest(reqInfo,parent_pipe); - reqInfo = NULL; - nFirst = 0; } else if ((keep_alive.nMaxRequests && (++keep_alive.nCurrRequests >= keep_alive.nMaxRequests)) - || !WaitForRequest(csd, &keep_alive)) { + || !wait_keepalive(csd, &keep_alive)) { keep_alive.bKeepAlive = 0; - nFirst = 0; CompleteRequest(reqInfo,parent_pipe); - reqInfo = NULL; } } } -void GetDescriptor (int parent_pipe) +#ifndef NO_PASS +void GetDescriptor(int parent_pipe) { +#ifndef THREADED dup2(parent_pipe,0); dup2(parent_pipe,1); +#endif /* THREADED */ #ifdef SETPROCTITLE setproctitle("idle"); #endif /* SETPROCTITLE */ @@ -647,11 +653,15 @@ void GetDescriptor (int parent_pipe) close(parent_pipe); exit(1); } +#ifndef THREADED close(0); close(1); dup2(csd,0); dup2(csd,1); +#endif /* THREADED */ + } +#endif /* NO_PASS */ char* GetRemoteLogName (SERVER_SOCK_ADDR *sa_server) { @@ -668,15 +678,17 @@ char* GetRemoteLogName (SERVER_SOCK_ADDR *sa_server) return NULL; } +#ifndef NO_PASS int make_child(int argc, char **argv, int childnum, SERVER_SOCK_ADDR *sa_server) { int fd[2]; int pid; +#ifdef SETPROCTITLE char namestr[30]; +#endif /* SETPROCTITLE */ pid = 1; - servernum = childnum; #ifndef NEED_SPIPE if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) { #else @@ -698,20 +710,22 @@ int make_child(int argc, char **argv, int childnum, } if (!pid) { - close(Children[childnum].childfd); + /* Child */ + + close(Children[childnum].childfd); #ifdef BSD signal(SIGCHLD,(void (*)())ign); #else signal(SIGCHLD,SIG_IGN); #endif /* BSD */ - sprintf(namestr,"child %d",childnum); #ifdef SETPROCTITLE -/* inststr(argv,argc,namestr); */ + sprintf(namestr,"child %d",childnum); setproctitle(namestr); #endif /* SETPROCTITLE */ Child = 1; child_main(Children[childnum].parentfd, sa_server); } else { + /* Parent */ close(Children[childnum].parentfd); } } @@ -727,14 +741,14 @@ void initialize_socket(SERVER_SOCK_ADDR *sa_server, int keepalive_value = 1; if ((mainSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) { - fprintf(stderr,"httpd: could not get socket\n"); + fprintf(stderr,"HTTPd: could not get socket\n"); perror("socket"); exit(1); } if((setsockopt(mainSocket,SOL_SOCKET,SO_REUSEADDR,(char *)&one, sizeof(one))) == -1) { - fprintf(stderr,"httpd: could not set socket option SO_REUSEADDR\n"); + fprintf(stderr,"HTTPd: could not set socket option SO_REUSEADDR\n"); perror("setsockopt"); exit(1); } @@ -746,12 +760,12 @@ void initialize_socket(SERVER_SOCK_ADDR *sa_server, if((setsockopt(mainSocket,SOL_SOCKET,SO_KEEPALIVE,(void *)&keepalive_value, sizeof(keepalive_value))) == -1) { - fprintf(stderr,"httpd: could not set socket option SO_KEEPALIVE\n"); + fprintf(stderr,"HTTPd: could not set socket option SO_KEEPALIVE\n"); perror("setsockopt"); exit(1); } - bzero((char *) sa_server, sizeof(*sa_server)); + memset((char *)sa_server, 0, sizeof(*sa_server)); sa_server->sin_family=AF_INET; sa_server->sin_addr= gConfiguration->address_info; /* sa_server.sin_addr.s_addr=htonl(INADDR_ANY); */ @@ -761,7 +775,7 @@ void initialize_socket(SERVER_SOCK_ADDR *sa_server, fprintf(stderr,"HTTPd: cound not bind to address %s port %d\n", inet_ntoa(gConfiguration->address_info),port); else - fprintf(stderr,"httpd: could not bind to port %d\n",port); + fprintf(stderr,"HTTPd: could not bind to port %d\n",port); perror("bind"); exit(1); } @@ -781,12 +795,13 @@ void standalone_main(int argc, char **argv) static SERVER_SOCK_ADDR sa_server; static CLIENT_SOCK_ADDR sa_client; static int one = 1; + static int pid = 0; #ifdef TACHOMETER static int Requests[MAX_TACHOMETER]; static time_t Request_time = 0L; static int i; static char Request_title[64]; -#endif +#endif /* TACHOMETER */ @@ -794,9 +809,8 @@ void standalone_main(int argc, char **argv) process to ensure proper time zone settings */ tzset(); -#if !defined(PROFILE) && !defined(QUANTIFY) - detach(); -#endif /* PROFILE */ + if (debug_mode == FALSE) + detach(); sprintf(error_msg,"HTTPd: Starting as %s",argv[0]); x = 1; @@ -816,6 +830,7 @@ void standalone_main(int argc, char **argv) #endif /* SETPROCTITLE */ while(!Exit) { +/* current_process_size("Starting"); */ initialize_socket(&sa_server,&sa_client); set_signals(); speed_hack_libs(); @@ -823,9 +838,11 @@ void standalone_main(int argc, char **argv) #ifndef NO_PASS num_children = 0; - Children = (ChildInfo *) malloc(sizeof(ChildInfo)*(max_servers+1)); - while (num_children < start_servers) { - make_child(argc, argv, num_children++, &sa_server); + if (debug_mode == FALSE) { + Children = (ChildInfo *) malloc(sizeof(ChildInfo)*(max_servers+1)); + while (num_children < start_servers) { + make_child(argc, argv, num_children++, &sa_server); + } } #endif /* NO_PASS */ @@ -935,10 +952,13 @@ void standalone_main(int argc, char **argv) } /* if (make_child) else ... */ } else { /* Already have as many children as compiled for.*/ - if (!fork()) { - /* inststr(argv, argc, "httpd-alone"); */ + if (debug_mode == FALSE) + pid = fork(); + else + Exit = TRUE; + if (!pid) { child_alone(csd,&sa_server,&sa_client); - } /* fork */ + } } /* if (num_children < max_servers) ... else ... */ } else { Children[free_child].busy = 1; @@ -952,8 +972,11 @@ void standalone_main(int argc, char **argv) } else #endif /* NO_PASS */ { - if (!fork()) { - /* inststr(argv, argc, "httpd-alone"); */ + if (debug_mode == FALSE) + pid = fork(); + else + Exit = TRUE; + if (!pid) { child_alone(csd,&sa_server,&sa_client); } /* fork */ close(csd); @@ -979,7 +1002,7 @@ void standalone_main(int argc, char **argv) avg1, avg5/5, avg30/30); setproctitle(Request_title); } -#endif +#endif /* TACHOMETER */ } /* If good accept */ } /* if mainSocket ready for read */ } /* if select */ @@ -1005,6 +1028,7 @@ void standalone_main(int argc, char **argv) free(Children); #endif /* NO_PASS */ free_host_conf(); + freeAllStrings(STR_HUP); read_config(error_log); set_group_privs(); log_error("HTTPd: successful restart",error_log); @@ -1015,10 +1039,30 @@ void standalone_main(int argc, char **argv) } /* while (!Exit) */ } /* standalone_main */ +void default_banner(FILE* fout) +{ + fprintf(fout,"NCSA HTTPd %s\n",SERVER_SOURCE); + fprintf(fout,"Licensed material. Portions of this work are\n"); + fprintf(fout,"Copyright (C) 1995-1996 Board of Trustees of the University of Illinois\n"); + fprintf(fout,"Copyright (C) 1995-1996 The Apache Group\n"); +#if defined(DIGEST_AUTH) + fprintf(fout,"Copyright (C) 1989-1993 RSA Data Security, Inc.\n"); +#endif /* DIGEST_AUTH */ +#ifdef DIGEST_AUTH + fprintf(fout,"Copyright (C) 1993-1994 Carnegie Mellon University\n"); + fprintf(fout,"Copyright (C) 1991 Bell Communications Research, Inc. (Bellcore)\n"); + fprintf(fout,"Copyright (C) 1994 Spyglass, Inc.\n"); +#endif /* DIGEST_AUTH */ +#ifdef FCGI_SUPPORT + fprintf(fout,"Copyright (C) 1995 Open Market, Inc.\n"); +#endif /* FCGI_SUPPORT */ + fflush(fout); +} + void usage(char *bin) { - fprintf(stderr,"NCSA HTTPd %s\n",SERVER_SOURCE); - fprintf(stderr,"Documentation online at http://hoohoo.ncsa.uiuc.edu/\n\n"); + default_banner(stderr); + fprintf(stderr,"\nDocumentation online at http://hoohoo.ncsa.uiuc.edu/\n\n"); fprintf(stderr,"Compiled in Options:\n"); #ifdef SETPROCTITLE @@ -1036,29 +1080,42 @@ void usage(char *bin) #ifdef NO_PASS fprintf(stderr,"\tNO_PASS\n"); #endif /* NO_PASS */ +#ifdef FCGI_SUPPORT + fprintf(stderr,"\tFCGI_SUPPORT\n"); +#endif /* FCGI_SUPPORT */ #ifdef DBM_SUPPORT fprintf(stderr,"\tDBM_SUPPORT\n"); #endif /* DBM_SUPPORT */ +#ifdef NIS_SUPPORT + fprintf(stderr,"\tNIS_SUPPORT\n"); +#endif /* NIS_SUPPORT */ #ifdef DIGEST_AUTH fprintf(stderr,"\tDIGEST_AUTH\n"); #endif /* DIGEST_AUTH */ +#ifdef CONTENT_MD5 + fprintf(stderr,"\tCONTENT_MD5\n"); +#endif /* CONTENT_MD5 */ #ifdef KRB4 fprintf(stderr,"\tKRB4\n"); #endif /* KRB4 */ #ifdef KRB5 fprintf(stderr,"\tKRB5\n"); #endif /* KRB5 */ +#ifdef PEM_AUTH + fprintf(stderr,"\tPEM_AUTH\n"); +#endif /* PEM_AUTH */ fprintf(stderr,"\tHTTPD_ROOT = %s\n",HTTPD_ROOT); fprintf(stderr,"\tDOCUMENT_ROOT = %s\n", DOCUMENT_LOCATION); fprintf(stderr,"\n"); #ifdef HAVE_KERBEROS - fprintf(stderr,"Usage: %s [-d directory] [-f file] [-k file] [-K file] [-v]\n",bin); + fprintf(stderr,"Usage: %s [-d directory] [-f file] [-k file] [-K file] [-vX]\n",bin); #else - fprintf(stderr,"Usage: %s [-d directory] [-f file] [-v]\n",bin); + fprintf(stderr,"Usage: %s [-d directory] [-f file] [-vX]\n",bin); #endif /* HAVE_KERBEROS */ fprintf(stderr,"-d directory\t : specify an alternate initial ServerRoot\n"); fprintf(stderr,"-f file\t\t : specify an alternate ServerConfigFile\n"); + fprintf(stderr,"-X\t\t : Answer one request for debugging, don't fork\n"); fprintf(stderr,"-v\t\t : version information (this screen)\n"); #ifdef KRB4 fprintf(stderr,"-k file\t\t : specify an alternate Kerberos V4 svrtab file\n"); @@ -1076,6 +1133,7 @@ int main (int argc, char **argv, char **envp) { int c; +/* FIRST */ #ifdef RLIMIT_NOFILE /* If defined (not user defined, but in sys/resource.h), this will attempt * to set the max file descriptors per process as high as allowed under @@ -1102,16 +1160,20 @@ int main (int argc, char **argv, char **envp) moncontrol(0); #endif /* PROFILE */ - + /* First things first */ strcpy(server_root,HTTPD_ROOT); make_full_path(server_root,SERVER_CONFIG_FILE,server_confname); #ifdef HAVE_KERBEROS - while((c = getopt(argc,argv,"d:f:vk:K:")) != -1) { + while((c = getopt(argc,argv,"d:f:vk:K:Xs")) != -1) { #else - while((c = getopt(argc,argv,"d:f:v")) != -1) { + while((c = getopt(argc,argv,"d:f:vXs")) != -1) { #endif /* HAVE_KERBEROS */ switch(c) { + case 'X': + debug_mode = TRUE; + printf("Debug On\n"); + break; case 'd': strcpy(server_root,optarg); make_full_path(server_root,SERVER_CONFIG_FILE,server_confname); @@ -1146,20 +1208,30 @@ int main (int argc, char **argv, char **envp) break; #endif /* KRB5 */ #endif /* HAVE_KERBEROS */ - case '?': usage(argv[0]); } } + +/* Global Initialization: + * Currently for File Descriptor Table and allocater + */ InitFdTable(); + initialize_allocate(); + read_config(stderr); +/* Passed arguments stage, dump baloney */ +#ifndef SUPPRESS_BANNER + if (standalone) default_banner(stdout); +#endif /* SUPPRESS_BANNER */ #ifdef SETPROCTITLE initproctitle(process_name, argc, argv, envp); #endif /* SETPROCTITLE */ + set_group_privs(); get_local_host(); - + #ifdef __QNX__ dup2(0,1); dup2(0,2); @@ -1174,14 +1246,15 @@ int main (int argc, char **argv, char **envp) group_id = getgid(); reqInfo->connection_socket = 0; + reqInfo->in = 0; reqInfo->out = stdout; port = get_portnum(reqInfo,fileno(reqInfo->out)); if(do_rfc931) remote_logname = get_remote_logname(reqInfo->out); - get_request(reqInfo); - fflush(reqInfo->out); + RequestMain(reqInfo); + rflush(reqInfo); } close_all_logs(); diff --git a/src/httpd.h b/src/httpd.h index 000b087..9fd1c77 100644 --- a/src/httpd.h +++ b/src/httpd.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * httpd.h,v 1.91 1995/11/28 09:02:14 blong Exp + * httpd.h,v 1.97 1996/03/27 20:44:19 blong Exp * ************************************************************************ * @@ -25,16 +25,28 @@ #define _HTTPD_H_ #include +#include "http_request.h" typedef struct _ChildInfo { int parentfd; int childfd; int pid; int busy; +#ifdef NOT_READY + int status; + KeepAliveData keep_alive; /* Child's keep alive info */ + int csd; /* Current Socket Descriptor */ + JMP_BUF restart_child; /* Return buffer for siglongjmp */ + per_request *gCurrentRequest; /* Current Request of Child */ +#endif /* NOT_READY */ } ChildInfo; +#ifndef NOT_READY extern KeepAliveData keep_alive; /* global keep alive info */ -extern JMP_BUF jmpbuffer; /* Return buffer for siglongjmp */ +extern JMP_BUF jmpbuffer; /* Return buffer for siglongjmp */ +extern int csd; /* Current Socket Descriptor */ +#endif /* NOT_READY */ + /* function prototypes */ diff --git a/src/httpd.man b/src/httpd.man index 6fec49b..56cf4c8 100644 --- a/src/httpd.man +++ b/src/httpd.man @@ -6,6 +6,8 @@ httpd \- NCSA HTTPd (hypertext transfer protocol daemon) [ .B \-v ] [ +.B \-X +] [ .BI \-d " serverroot" ] [ .BI \-f " config" @@ -32,6 +34,10 @@ the ServerRoot. The default is \fBconf/httpd.conf\fP. .B \-v Print the version of httpd, including compiled defaults and command line options. +.TP +.B \-X +Execute in single request debugging mode, with no fork, no detach. +Useful for profiling and debugging. .SH FILES .PD 0 .B /usr/local/etc/httpd/conf/httpd.conf diff --git a/src/httpy.h b/src/httpy.h index c15d23b..cf70684 100644 --- a/src/httpy.h +++ b/src/httpy.h @@ -1,3 +1,4 @@ + /* zippy.c * * Print a quotation from Zippy the Pinhead. diff --git a/src/imagemap.c b/src/imagemap.c index bcfc01a..c5a1488 100644 --- a/src/imagemap.c +++ b/src/imagemap.c @@ -10,7 +10,7 @@ * ************************************************************************ * - * imagemap.c,v 1.7 1995/11/28 09:02:16 blong Exp + * imagemap.c,v 1.15 1996/04/05 19:14:19 blong Exp * ************************************************************************ * @@ -30,34 +30,60 @@ #include #include #include "constants.h" -#include "http_log.h" #include "fdwrap.h" +#include "allocate.h" +#include "http_log.h" +#include "http_config.h" +#include "http_request.h" #include "imagemap.h" +#include "cgi.h" +#include "util.h" #ifdef IMAGEMAP_SUPPORT -extern int port; +/* Error messages for imagemaps */ -int send_imagemap(per_request* reqInfo, struct stat* fi, char* path_args, - char allow_options) +#define IMAP_ERR_INCORRECT_ARGS 1 +#define IMAP_ERR_INCORRECT_COORDS 2 +#define IMAP_ERR_CERN_MISSING_RIGHT_PAREN 3 + +char *imagemap_errors[] = { +"IMAP: Imagemap request requires two coordinates as arguments", +"IMAP: Imagemap args missing y value", +"IMAP: Imagemap args missing right paren"}; + + +/* NCSA Imagemap files use: method URL coord1 coord2 + * CERN Imagemap files use: method (coord1) (coord2) URL + * This version of imagemap will probably work with either in the same file, + * as long as a full line is in one format or the other. + */ +int send_imagemap(per_request* reqInfo, struct stat* fi, char allow_options) { - char input[MAX_STRING_LEN], def[MAX_STRING_LEN]; - char szPoint[MAX_STRING_LEN]; + char *input, *def, *szPoint, *url, *type; double testpoint[2], pointarray[MAXVERTS][2]; int i, j, k; + int error_num = 0; FILE *fp; char *t; double dist, mindist = -1; int sawpoint = 0; + int sawparen = 0; + int Found = 0; + + input = newString(HUGE_STRING_LEN,STR_TMP); + def = newString(MAX_STRING_LEN,STR_TMP); + szPoint = newString(MAX_STRING_LEN,STR_TMP); + type = newString(MAX_STRING_LEN,STR_TMP); + url = newString(MAX_STRING_LEN,STR_TMP); + def[0] = '\0'; strcpy(szPoint, reqInfo->args); if(!(t = strchr(szPoint,','))) { - log_reason(reqInfo, - "Your client doesn't support image mapping properly.", - reqInfo->filename); - die(reqInfo, SC_BAD_IMAGEMAP, reqInfo->url); + error_num = IMAP_ERR_INCORRECT_ARGS; + goto imagemap_error; } *t++ = '\0'; @@ -67,70 +93,114 @@ int send_imagemap(per_request* reqInfo, struct stat* fi, char* path_args, if(!(fp=FOpen(reqInfo->filename,"r"))){ log_reason(reqInfo, "File permissions deny server access", reqInfo->filename); + freeString(input); + freeString(def); + freeString(szPoint); + freeString(url); + freeString(type); die(reqInfo, SC_FORBIDDEN, reqInfo->url); } - while (fgets(input,MAX_STRING_LEN,fp)) { - char type[MAX_STRING_LEN]; - char url[MAX_STRING_LEN]; + while (!Found && fgets(input,HUGE_STRING_LEN,fp)) { char num[10]; + /* Skip lines with # as comments and blank lines */ if((input[0] == '#') || (!input[0])) continue; type[0] = '\0';url[0] = '\0'; - for(i=0;isname(input[i]) && (input[i]);i++) + /* Copy the shape keyword into type */ + for(i=0;!isspace(input[i]) && (input[i]);i++) type[i] = input[i]; type[i] = '\0'; + /* Forward to next word */ while(isspace(input[i])) ++i; - for(j=0;input[i] && isname(input[i]);++i,++j) - url[j] = input[i]; - url[j] = '\0'; + /* If no coordinates, must be url for default, or NCSA format */ + if (input[i] != '(') { + for(j=0;input[i] && !isspace(input[i]);++i,++j) + url[j] = input[i]; + url[j] = '\0'; + } + + /* Handle default keyword */ if(!strcmp(type,"default") && !sawpoint) { strcpy(def,url); continue; } + /* Looking for Coordinates */ k=0; while (input[i]) { + /* Move over spaces and commas */ while (isspace(input[i]) || input[i] == ',') i++; + + /* Under CERN, coordinates are in parenthesis */ + if (input[i] == '(') { + sawparen = 1; + while (isspace(input[++i])); + } + + /* Copy digits into num array */ + j = 0; + while (isdigit(input[i])) + num[j++] = input[i++]; + + num[j] = '\0'; + if (!j) break; + pointarray[k][X] = (double) atoi(num); + + /* Skip to next digit */ + while (isspace(input[i]) || input[i] == ',') + i++; + /* Copy other number into num */ 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') + + if (!j && !sawparen && k > 0) { + pointarray[k++][Y] = -127; + break; + } + + if (j) pointarray[k++][Y] = (double) atoi(num); else { - FClose(fp); - log_reason(reqInfo, "Imagemap args missing y value.", - reqInfo->filename); - die(reqInfo, SC_BAD_IMAGEMAP, reqInfo->url); + error_num = IMAP_ERR_INCORRECT_COORDS; + FClose(fp); + goto imagemap_error; } + + /* End of parenthesis for coordinates under CERN */ + if (input[i] == ')') { + i++; + sawparen = 0; + } else if (sawparen) { + error_num = IMAP_ERR_CERN_MISSING_RIGHT_PAREN; + FClose(fp); + goto imagemap_error; + } + } + if (url[0] == '\0' && input[i]) { + while (isspace(input[i])) i++; + for (j = 0; input[i] && !isspace(input[i]); ++i, ++j) + url[j] = input[i]; + url[j] = '\0'; } pointarray[k][X] = -1; - if(!strcmp(type,"poly")) + if(!strncmp(type, "poly", 4)) if(pointinpoly(testpoint,pointarray)) - sendmesg(reqInfo, url, fp); - if(!strcmp(type,"circle")) + Found = 1; + if(!strncmp(type, "circ", 4)) if(pointincircle(testpoint,pointarray)) - sendmesg(reqInfo, url, fp); - if(!strcmp(type,"rect")) + Found = 1; + if(!strncmp(type, "rect", 4)) if(pointinrect(testpoint,pointarray)) - sendmesg(reqInfo, url, fp); + Found = 1; if(!strcmp(type,"point")) { /* Don't need to take square root. */ dist = ((testpoint[X] - pointarray[0][X]) @@ -145,30 +215,70 @@ int send_imagemap(per_request* reqInfo, struct stat* fi, char* path_args, sawpoint++; } } - if(def[0]) + if(Found) { + sendmesg(reqInfo, url, fp); + goto imagemap_ok; + } else { + if(def[0]) { sendmesg(reqInfo, def, fp); - - FClose(fp); + goto imagemap_ok; + } + } /* No reason to log each of these as an "error" */ /* log_reason(reqInfo, "No default defined in imagemap.", reqInfo->filename); */ + FClose(fp); + freeString(input); + freeString(def); + freeString(szPoint); + freeString(url); + freeString(type); die(reqInfo, SC_NO_CONTENT, reqInfo->url); return 0; + + imagemap_ok: + FClose(fp); + freeString(input); + freeString(def); + freeString(szPoint); + freeString(url); + freeString(type); + return 1; + + imagemap_error: + freeString(input); + freeString(def); + freeString(szPoint); + freeString(url); + freeString(type); + log_reason(reqInfo,imagemap_errors[error_num-1],reqInfo->filename); + die(reqInfo,SC_BAD_IMAGEMAP,imagemap_errors[error_num-1]); + return -1; } -void sendmesg(per_request* reqInfo, char *url, FILE* fp) +void sendmesg(per_request* reqInfo, char *url, FILE *fp) { - char loc[HUGE_STRING_LEN]; + char *loc, *furl; + + loc = newString(HUGE_STRING_LEN,STR_REQ); + furl = newString(HUGE_STRING_LEN,STR_REQ); FClose(fp); - if (!strchr(url, ':')) { /*** If not a full URL ***/ - if (port == 80) /*** It is a virtual URL ***/ - sprintf(loc, "http://%s", reqInfo->hostInfo->server_hostname); - else /* only add port if it's not the default */ - sprintf(loc, "http://%s:%d",reqInfo->hostInfo->server_hostname, - port); - strcat(loc,url); - die(reqInfo,SC_REDIRECT_TEMP,loc); + if (!strstr(url, "://")) { /*** If not a full URL ***/ + if (url[0] != '/') { /*** Relative URL ***/ + char *last = strrchr(reqInfo->url,'/'); + int x = 0, y = 0; + while (((reqInfo->url+x) <= last) && (y < HUGE_STRING_LEN)) { + loc[y] = *(reqInfo->url+x); + x++; y++; + } + loc[y] = '\0'; + strncat(loc,url,HUGE_STRING_LEN - y); + } else { + strncpy(loc,url,HUGE_STRING_LEN); + } + construct_url(furl, reqInfo->hostInfo, loc); + die(reqInfo,SC_REDIRECT_TEMP,furl); } else { die(reqInfo,SC_REDIRECT_TEMP,url); } @@ -184,11 +294,16 @@ 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])); + /* If given a radius instead of a coordinate */ + if (coords[1][Y] == -127) + radius1 = coords[1][X]; + else + 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])); + ((coords[0][X] - point[X]) * (coords[0][X] - point[X])); return (radius2 <= radius1); } @@ -258,9 +373,4 @@ int pointinpoly(double point[2], double pgon[MAXVERTS][2]) return (inside_flag); } -int isname(char c) -{ - return (!isspace(c)); -} - #endif /* IMAGEMAP_SUPPORT */ diff --git a/src/imagemap.h b/src/imagemap.h index f9a2d38..5efefc5 100644 --- a/src/imagemap.h +++ b/src/imagemap.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * imagemap.h,v 1.3 1995/10/06 19:15:56 blong Exp + * imagemap.h,v 1.6 1996/04/05 18:55:18 blong Exp * ************************************************************************ * @@ -22,11 +22,13 @@ #ifndef _IMAGEMAP_H #define _IMAGEMAP_H 1 -#define MAXLINE 500 #define MAXVERTS 100 #define X 0 #define Y 1 +#define IMAP_NCSA 1 +#define IMAP_CERN 2 + void sendmesg(per_request* reqInfo, char *url, FILE* fp); int pointinpoly(double point[2], double pgon[MAXVERTS][2]); int pointincircle(double point[2], double coords[MAXVERTS][2]); @@ -34,7 +36,6 @@ int pointinrect(double point[2], double coords[MAXVERTS][2]); int isname(char); -int send_imagemap(per_request* reqInfo, struct stat* fi, char* path_args, - char allow_options); +int send_imagemap(per_request* reqInfo, struct stat* fi, char allow_options); #endif /* _IMAGE_MAP_H */ diff --git a/src/md5.c b/src/md5.c index 05a5785..281afef 100644 --- a/src/md5.c +++ b/src/md5.c @@ -1,13 +1,46 @@ +/************************************************************************ + * NCSA HTTPd Server + * Software Development Group + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * 605 E. Springfield, Champaign, IL 61820 + * httpd@ncsa.uiuc.edu + * + * Copyright (C) 1995, Board of Trustees of the University of Illinois + * + ************************************************************************ + * + * md5.c,v 1.6 1996/03/06 23:21:21 blong Exp + * + ************************************************************************ + * + * md5.c: NCSA HTTPd code which uses the md5c.c RSA Code + * + * Original Code Copyright (C) 1994, Jeff Hostetler, Spyglass, Inc. + * Portions of Content-MD5 code Copyright (C) 1993, 1994 by Carnegie Mellon + * University (see Copyright below). + * Portions of Content-MD5 code Copyright (C) 1991 Bell Communications + * Research, Inc. (Bellcore) (see Copyright below). + * Portions extracted from mpack, John G. Myers - jgm+@cmu.edu + * Content-MD5 Code contributed by Martin Hamilton (martin@net.lut.ac.uk) + * + */ + + + /* md5.c --Module Interface to MD5. */ /* Jeff Hostetler, Spyglass, Inc., 1994. */ #include "config.h" #include "portability.h" +#include "constants.h" #include #include -#include "global.h" +#ifndef SHTTP +#include "global.h" +#endif /* SHTTP */ #include "md5.h" void md5 (unsigned char *string, char result[33]) @@ -31,3 +64,97 @@ void md5 (unsigned char *string, char result[33]) return; } + + +#ifdef CONTENT_MD5 +/* these portions extracted from mpack, John G. Myers - jgm+@cmu.edu */ + +/* (C) Copyright 1993,1994 by Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of Carnegie + * Mellon University not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. Carnegie Mellon University makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore) + * + * Permission to use, copy, modify, and distribute this material + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies, and that the name of Bellcore not be + * used in advertising or publicity pertaining to this + * material without the specific, prior written permission + * of an authorized representative of Bellcore. BELLCORE + * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY + * OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", + * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. + */ + +static char basis_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +char *md5contextTo64(context) +MD5_CTX *context; +{ + unsigned char digest[18]; + char *encodedDigest; + int i; + char *p; + + encodedDigest = (char *)malloc(25 * sizeof(char)); + + MD5Final(digest, context); + digest[sizeof(digest)-1] = digest[sizeof(digest)-2] = 0; + + p = encodedDigest; + for (i=0; i < sizeof(digest); i+=3) { + *p++ = basis_64[digest[i]>>2]; + *p++ = basis_64[((digest[i] & 0x3)<<4) | ((digest[i+1] & 0xF0)>>4)]; + *p++ = basis_64[((digest[i+1] & 0xF)<<2) | ((digest[i+2] & 0xC0)>>6)];+ *p++ = basis_64[digest[i+2] & 0x3F]; + } + *p-- = '\0'; + *p-- = '='; + *p-- = '='; + return encodedDigest; +} + + +char *md5digest(infile) +FILE *infile; +{ + MD5_CTX context; + char buf[1000]; + long length = 0; + int nbytes; + + MD5Init(&context); + while (nbytes = fread(buf, 1, sizeof(buf), infile)) { + length += nbytes; + MD5Update(&context, buf, nbytes); + } + rewind(infile); + return md5contextTo64(&context); +} + +#endif /* CONTENT_MD5 */ + + diff --git a/src/patch b/src/patch new file mode 100644 index 0000000..35a97c2 --- /dev/null +++ b/src/patch @@ -0,0 +1,7177 @@ +Only in /X11/blong/httpd/src/: .#cgi.c.1.41 +Only in /X11/blong/httpd/src/: .#fcgi.c.1.2 +Only in /X11/blong/httpd/src/: .#fcgi.h.1.1 +Only in /X11/blong/httpd/src/: .#http_auth.c.1.80 +Only in /X11/blong/httpd/src/: .#http_auth.h.1.24 +Only in /X11/blong/httpd/src/: .#http_send.c.1.30 +Only in /X11/blong/httpd/src/: .#http_shttp.h.1.3 +Only in /X11/blong/httpd/src/: .pure +Only in /X11/blong/httpd/src/: 112a.ident.patch +Only in /X11/blong/httpd/src/: BUGS +diff -brc ./CHANGES /X11/blong/httpd/src//CHANGES +*** ./CHANGES Tue Jun 25 17:18:12 1996 +--- /X11/blong/httpd/src//CHANGES Tue May 28 10:44:31 1996 +*************** +*** 1,13 **** + +- Fixes for 1.5.2 +- ------------------ + *) Changed getline rfc822 line wrap to check for validity of the next bits + before attempting to see them + *) Changed imagemap.c so relative URLs actually work + *) Don't core dump on a method only request + *) reset errno to 0 in send_fp so we break out of loop +- *) somewhere we stopped killing cgi scripts on SIGALRM and SIGPIPE +- *) changed group handling support to support multiple groups again +- *) reset content_length before scanning cgi headers, not after +- +- +--- 1,6 ---- +Only in /X11/blong/httpd/src/: CVS +Only in /X11/blong/httpd/src/: DESC +diff -brc ./Makefile /X11/blong/httpd/src//Makefile +*** ./Makefile Tue Jun 25 17:06:12 1996 +--- /X11/blong/httpd/src//Makefile Wed Jun 12 17:45:00 1996 +*************** +*** 16,24 **** + # If you want to ensure that CGI scripts can't mess with the log files, + # use -DSECURE_LOGS + + CFLAGS= -g + #CFLAGS= -pg -DPROFILE +! #CFLAGS= -g -ansi -pedantic -Wall -DAIX_BROKEN_HEADERS + + # FCGI Support + # +--- 16,26 ---- + # If you want to ensure that CGI scripts can't mess with the log files, + # use -DSECURE_LOGS + ++ #CFLAGS= -O2 + CFLAGS= -g + #CFLAGS= -pg -DPROFILE +! #CFLAGS= -g -ansi -pedantic -Wall #-DAIX_BROKEN_HEADERS +! #CFLAGS= -O2 -fullwarn -wlint,-vui + + # FCGI Support + # +*************** +*** 26,32 **** +--- 28,62 ---- + # Currently uses the TCL library for strings, which requires the math library + + #FCGI_CFLAGS = -DFCGI_SUPPORT -I/local/include ++ #FCGI_OBJS = fcgi.o ++ #FCGI_LIBS = + ++ # SHTTP Support ++ # ++ # To enable SHTTP, choose platform and uncomment the following SHTTP lines ++ ++ #PLATFORM=solaris24 ++ #PLATFORM=sunos413-export ++ #PLATFORM=sunos413 ++ #PLATFORM=irix52 ++ ++ #SHTTPDIR=/xdev/acain/kit7/libshttp/make/$(PLATFORM) ++ #SHTTP_CFLAGS = -DSHTTP -I$(SHTTPDIR) ++ #SHTTP_OBJS = $(SHTTPDIR)/compat_unix.o $(SHTTPDIR)/io_wrap.o $(SHTTPDIR)/rsa_io.o http_shttp.o ++ ++ # for SunOS: ++ #SHTTP_LIBS = -L$(SHTTPDIR) -lshttp -llwp ++ # for Solaris: ++ #SHTTP_LIBS = -L$(SHTTPDIR) -lshttp -lthread ++ ++ # SSL Support ++ # SSL changes require SSLeay ... see the README.SSL file for details ++ # http://www.psy.uq.oz.au/~ftp/Crypto/ ++ ++ # SSL_CFLAGS = -DSSL_SUPPORT -I/X11/httpd/ssleay/include ++ # SSL_OBJS = http_ssl.o ++ # SSL_LIBS = -L/X11/httpd/ssleay/sgi5/lib -lssl -lcrypto ++ + # DIGEST AUTHENTICATION + # + # To enable Message Digest Authentication, define the DIGEST_AUTH flag +*************** +*** 40,45 **** +--- 70,77 ---- + # although it's most likely that your realm supports one or the other. + # To enable DES-encryption of HTTP messages via Kerberos key exchange, + # define the KRB-ENCRYPT flag (not supported in Beta1 -- hopefully Beta2). ++ # Currently you can't have both Kerberos and SSL support because of ++ # different des routines and des.h files. + + KRB4_DIR = /xdev/mosaic/libkrb4/sun + KRB4_LIBS = -L$(KRB4_DIR)/lib -lkrb -ldes +*************** +*** 50,58 **** + KRB5_CFLAGS = -DKRB5 -I$(KRB5_DIR)/include -I$(KRB5_DIR)/include/krb5 + + +! # Comment out the following two lines to exclude Kerberos support + + #KRB_CFLAGS = $(KRB4_CFLAGS) $(KRB5_CFLAGS) # -DKRB-ENCRYPT + #KRB_LIBS = $(KRB4_LIBS) $(KRB5_LIBS) + + +--- 82,91 ---- + KRB5_CFLAGS = -DKRB5 -I$(KRB5_DIR)/include -I$(KRB5_DIR)/include/krb5 + + +! # Comment out the following three lines to exclude Kerberos support + + #KRB_CFLAGS = $(KRB4_CFLAGS) $(KRB5_CFLAGS) # -DKRB-ENCRYPT ++ #KRB_OBJS = http_kerberos.o + #KRB_LIBS = $(KRB4_LIBS) $(KRB5_LIBS) + + +*************** +*** 149,166 **** + # -------------- You shouldn't have to edit anything else ----------------- + # ------------------------------------------------------------------------- + +! SEC_CFLAGS = $(MD5_CFLAGS) $(KRB_CFLAGS) +! SEC_LIBS = $(KRB_LIBS) + + ALL_CFLAGS = $(CFLAGS) $(AUX_CFLAGS) $(SEC_CFLAGS) $(DBM_CFLAGS) $(FCGI_CFLAGS) +! ALL_LIBS = $(EXTRA_LIBS) $(SEC_LIBS) $(DBM_LIBS) + + +! OBJS=httpd.o http_config.o http_request.o util.o http_dir.o \ +! http_alias.o http_log.o http_mime.o http_access.o http_auth.o \ +! http_send.o cgi.o http_include.o rfc931.o imagemap.o \ +! http_ipc.o digest.o md5.o md5c.o env.o host_config.o fdwrap.o \ +! open_logfile.o allocate.o debug.o blackout.o fcgi.o + + .c.o: Makefile config.h portability.h constants.h + $(CC) -c $(ALL_CFLAGS) $< +--- 182,200 ---- + # -------------- You shouldn't have to edit anything else ----------------- + # ------------------------------------------------------------------------- + +! SEC_CFLAGS = $(MD5_CFLAGS) $(KRB_CFLAGS) $(SHTTP_CFLAGS) $(SSL_CFLAGS) +! SEC_LIBS = $(KRB_LIBS) $(SHTTP_LIBS) $(SSL_LIBS) + + ALL_CFLAGS = $(CFLAGS) $(AUX_CFLAGS) $(SEC_CFLAGS) $(DBM_CFLAGS) $(FCGI_CFLAGS) +! ALL_LIBS = $(EXTRA_LIBS) $(SEC_LIBS) $(DBM_LIBS) $(FCGI_LIBS) + + +! OBJS = httpd.o http_config.o http_request.o util.o http_dir.o http_alias.o \ +! http_log.o http_mime.o http_access.o http_auth.o http_send.o cgi.o \ +! http_include.o rfc931.o imagemap.o http_ipc.o digest.o md5.o md5c.o \ +! env.o host_config.o fdwrap.o open_logfile.o allocate.o debug.o \ +! blackout.o http_nis.o \ +! $(FCGI_OBJS) $(KRB_OBJS) $(SSL_OBJS) $(SHTTP_OBJS) + + .c.o: Makefile config.h portability.h constants.h + $(CC) -c $(ALL_CFLAGS) $< +diff -brc ./allocate.c /X11/blong/httpd/src//allocate.c +*** ./allocate.c Tue Jun 25 17:06:12 1996 +--- /X11/blong/httpd/src//allocate.c Wed Jun 5 21:44:08 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * allocate.c,v 1.5 1996/04/05 18:54:28 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: allocate.c,v 1.6 1996/06/06 02:44:08 blong Exp $ + * + ************************************************************************ + * +*************** +*** 70,81 **** + + + while (num) { +! if (!(S = (char *) malloc(length * sizeof(char)))) + return 1; + + S[0] = '\0'; + +! if (!(stmp = (string_item *) malloc(sizeof(string_item)))) + return 1; + + stmp->string = S; +--- 70,81 ---- + + + while (num) { +! if (!(S = (char *) Malloc(length * sizeof(char)))) + return 1; + + S[0] = '\0'; + +! if (!(stmp = (string_item *) Malloc(sizeof(string_item)))) + return 1; + + stmp->string = S; +diff -brc ./allocate.h /X11/blong/httpd/src//allocate.h +*** ./allocate.h Tue Jun 25 17:06:12 1996 +--- /X11/blong/httpd/src//allocate.h Wed Jun 5 21:44:09 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * allocate.h,v 1.2 1996/04/05 18:54:29 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: allocate.h,v 1.3 1996/06/06 02:44:09 blong Exp $ + * + ************************************************************************ + * +*************** +*** 43,48 **** +--- 43,53 ---- + string_item* first; + int num; + } string_list; ++ ++ /* #defs */ ++ #define Malloc malloc ++ #define Free free ++ #define Realloc realloc + + /* Public Interface */ + int initialize_allocate(void); +Only in /X11/blong/httpd/src/: allocate.o +diff -brc ./blackout.c /X11/blong/httpd/src//blackout.c +*** ./blackout.c Tue Jun 25 17:13:00 1996 +--- /X11/blong/httpd/src//blackout.c Tue Jun 25 17:00:02 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * blackout.c,v 1.3 1996/03/07 21:27:21 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: blackout.c,v 1.3 1996/03/07 21:27:21 blong Exp $ + * + ************************************************************************ + * +*************** +*** 51,57 **** + + char *bodyTag = ""; + +! /* void (*exit_callback)(void); */ + + + int realWrite(int fd, char *buf, int length) +--- 51,57 ---- + + char *bodyTag = ""; + +! /* static void (*exit_callback)(void); */ + + + int realWrite(int fd, char *buf, int length) +diff -brc ./blackout.h /X11/blong/httpd/src//blackout.h +*** ./blackout.h Tue Jun 25 17:06:12 1996 +--- /X11/blong/httpd/src//blackout.h Thu Feb 8 12:01:02 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * blackout.h,v 1.1 1996/02/08 18:01:02 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: blackout.h,v 1.1 1996/02/08 18:01:02 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: blackout.o +diff -brc ./cgi.c /X11/blong/httpd/src//cgi.c +*** ./cgi.c Tue Jun 25 17:19:19 1996 +--- /X11/blong/httpd/src//cgi.c Tue Jun 25 17:18:33 1996 +*************** +*** 10,23 **** + * + ************************************************************************ + * +! * cgi.c,v 1.44 1996/04/05 18:54:31 blong Exp + * + ************************************************************************ + * + * cgi: keeps all script-related ramblings together. + * + */ + + #include "config.h" + #include "portability.h" + +--- 10,26 ---- + * + ************************************************************************ + * +! * $Id: cgi.c,v 1.48 1996/06/12 20:35:21 acain Exp $ + * + ************************************************************************ + * + * cgi: keeps all script-related ramblings together. + * ++ * Based on NCSA HTTPd 1.3 by Rob McCool ++ * + */ + ++ + #include "config.h" + #include "portability.h" + +*************** +*** 34,44 **** +--- 37,52 ---- + # endif /* NEED_SYS_MALLOC_H */ + #endif /* NO_MALLOC_H */ + #include ++ #include + #include + #include + #include + #include + #include "constants.h" ++ #ifdef SHTTP ++ # include ++ # include "http_shttp.h" ++ #endif /* SHTTP */ + #include "fdwrap.h" + #include "allocate.h" + #include "cgi.h" +*************** +*** 55,60 **** +--- 63,71 ---- + #include "http_include.h" + #include "httpd.h" + #include "util.h" ++ #ifdef SSL_SUPPORT ++ # include "http_ssl.h" ++ #endif /* SSL_SUPPORT */ + + + int pid; +*************** +*** 79,85 **** + void kill_children_timed_out() { + kill_children(gCurrentRequest); + } +- + char **create_argv(per_request *reqInfo,char *av0) { + register int x,n; + char **av; +--- 90,95 ---- +*************** +*** 173,178 **** +--- 183,198 ---- + } + make_env_str(reqInfo,"QUERY_STRING",reqInfo->args); + ++ #ifdef SSL_SUPPORT ++ ssl_add_cgi_vars(reqInfo); ++ #endif /* SSL_SUPPORT */ ++ ++ #ifdef SHTTP /* added by ADC ZZZ */ ++ if (reqInfo->RequestFlags & DOING_SHTTP) { ++ shttp_add_cgi_vars(reqInfo); ++ } ++ #endif /* SHTTP */ ++ + if(content) { + *content=0; + if ((reqInfo->method == M_POST) || (reqInfo->method == M_PUT)) { +*************** +*** 342,347 **** +--- 362,374 ---- + strncpy(reqInfo->outh_www_auth,l,HUGE_STRING_LEN); + reqInfo->outh_www_auth[HUGE_STRING_LEN-1] = '\0'; + } ++ #ifdef SHTTP ++ else if(!strcasecmp(str,"Privacy-Enhancements")) { ++ if (reqInfo->privacy_enhancements != NULL) ++ freeString(reqInfo->privacy_enhancements); ++ reqInfo->privacy_enhancements = dupStringP(TSW_trimbuf(l),STR_REQ); ++ } ++ #endif /* SHTTP */ + else { + *(--l) = ':'; + for(p=0;str[p];p++); +*************** +*** 510,515 **** +--- 537,547 ---- + if (nBytes >= 0) { + if (nBytes > 0) write(p2[1], szBuf, nBytes); + while (!nDone && (nTotalBytes < reqInfo->inh_content_length)) { ++ #ifdef SSL_SUPPORT ++ if (reqInfo->RequestFlags & DOING_SSL) ++ nBytes = SSL_read(ssl_con, szBuf,HUGE_STRING_LEN); ++ else ++ #endif /* SSL_SUPPORT */ + nBytes=read(reqInfo->in, szBuf,HUGE_STRING_LEN); + if(nBytes < 1) { + break; +*************** +*** 623,628 **** +--- 655,665 ---- + while (1) { + o=0; + while(n) { ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled && (reqInfo->RequestFlags & DOING_SSL)) { ++ w = SSL_write(ssl_con,&buf[o],n); ++ } else ++ #endif /* SSL_SUPPORT */ + w = write(fd, buf + o,n); + + if (w < 1) { +diff -brc ./cgi.h /X11/blong/httpd/src//cgi.h +*** ./cgi.h Tue Jun 25 17:19:58 1996 +--- /X11/blong/httpd/src//cgi.h Wed Jun 5 21:44:12 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * cgi.h,v 1.9 1996/04/05 18:54:40 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: cgi.h,v 1.10 1996/06/06 02:44:12 blong Exp $ + * + ************************************************************************ + * +*************** +*** 26,33 **** + /* function prototypes */ + void exec_cgi_script(per_request *reqInfo); + int cgi_stub(per_request *reqInfo, struct stat *finfo, int allow_options); +- int add_common_vars(per_request *reqInfo); + int add_cgi_vars(per_request *reqInfo, int *content); + void get_path_info(per_request *reqInfo, struct stat *finfo); + int scan_cgi_header(per_request *reqInfo, int pd); + long send_fd(per_request *reqInfo, int pd, void (*onexit)(void)); +--- 26,33 ---- + /* function prototypes */ + void exec_cgi_script(per_request *reqInfo); + int cgi_stub(per_request *reqInfo, struct stat *finfo, int allow_options); + int add_cgi_vars(per_request *reqInfo, int *content); ++ int add_common_vars(per_request *reqInfo); + void get_path_info(per_request *reqInfo, struct stat *finfo); + int scan_cgi_header(per_request *reqInfo, int pd); + long send_fd(per_request *reqInfo, int pd, void (*onexit)(void)); +Only in /X11/blong/httpd/src/: cgi.o +diff -brc ./config.h /X11/blong/httpd/src//config.h +*** ./config.h Tue Jun 25 17:06:12 1996 +--- /X11/blong/httpd/src//config.h Wed Jun 12 17:51:27 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * config.h,v 1.21 1996/03/27 20:43:51 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: config.h,v 1.24 1996/06/12 22:51:27 blong Exp $ + * + ************************************************************************ + * +*************** +*** 27,42 **** + */ + + /* To enable changing of the process title to the current request being +! handled, uncomment the following. Note: Using this will cause a +! performance hit (though maybe not much of one). This doesn't work +! on all systems, either. It is known to work under AIX3, SunOS, OSF1, +! FreeBSD, and NetBSD. */ + + /* #define SETPROCTITLE */ + + /* If you have SETPROCTITLE enabled, and you are a stats fanatic, and your +! server has a few extra clock cycles to spare, defining the following +! will enable an RPM (requests per minute) indicator in the proc title. */ + + #ifdef SETPROCTITLE + #define TACHOMETER */ +--- 27,44 ---- + */ + + /* To enable changing of the process title to the current request being +! * handled, uncomment the following. Note: Using this will cause a +! * performance hit (though maybe not much of one). This doesn't work +! * on all systems, either. It is known to work under AIX3, SunOS, OSF1, +! * FreeBSD, NetBSD, and Linux. +! */ + + /* #define SETPROCTITLE */ + + /* If you have SETPROCTITLE enabled, and you are a stats fanatic, and your +! * server has a few extra clock cycles to spare, defining the following +! * will enable an RPM (requests per minute) indicator in the proc title. +! */ + + #ifdef SETPROCTITLE + #define TACHOMETER */ +*************** +*** 46,121 **** + #endif + + /* To not compile with built in imagemap support, comment out the following. +! Note: It is much faster to use this then the external program, but it +! also makes the program size of httpd larger. */ + + #define IMAGEMAP_SUPPORT /* */ + + /* To add an additional field -- request duration -- to the access_log. +! This adds the duration, in seconds that the processing of this +! request took. */ + +! /* #define LOG_DURATION */ + + /* If you want the server to check the execute bit of an HTML file to +! determine if the file should be parsed, uncomment the following. +! Using this feature will give better performance for files which +! are not parsed without the necessity of using the magic mime type */ + + /* #define XBITHACK */ + + /* If you want the server to be able to parse the output of CGI scripts, +! then define the following. This will automatically be defined for +! SHTTP. This does cause a performance degradation for CGI scripts, +! as it requires reading the returned CGI headers off the socket one +! byte at a time. */ + + /* #define CGI_SSI_HACK */ + + /* If you would like to ensure that CGI scripts don't mess with the +! log files (except the error_log file), uncomment the following. */ + + /* #define SECURE_LOGS */ + + /* If you would like each "static" file to be sent with a Content-MD5 +! header to give clients a way of telling whether the object they +! requested is the one they got - and hasn't been mangled along the way. +! Of course, no clients support this yet (to my knowledge) and this will +! _really_ hinder performance on really big files, but that's life. */ + + /* #define CONTENT_MD5 */ + + /* If you would like to specify the keyword LOCAL in your access +! configuration file to match local address (ie, those without embedded +! dots), uncomment the following. */ + + /* #define LOCALHACK */ + + /* If you would like to use NIS services for passwords and group information, +! uncomment the following. NOTE: DO NOT USE THIS ON OPEN NETWORKS. The +! security information used in Basic Authentication involves sending the +! password in clear text across the network on every request which requires +! it. */ + +! /* #define NIS_SUPPORT */ + + /* If you have a REALLY heavily loaded system, and you can't afford to +! have a server per request(low memory?), you can compile with this i +! option to make max_servers a hard limit. */ + + /* #define RESOURCE_LIMIT */ + + /* If your system doesn't support file descriptor passing, or if you +! don't want to use it, defining the following will enable HTTPd to +! mimic the 1.3 Forking server. This should be defined in the system +! specific information in portability.h, and not here. */ + + /* #define NO_PASS */ + + + /* defines for new muli-child approach +! DEFAULT_START_DAEMON defines how many children start at httpd start +! DEFAULT_MAX_DAEMON defines how many children can start + */ + + #define DEFAULT_START_DAEMON 5 +--- 48,133 ---- + #endif + + /* To not compile with built in imagemap support, comment out the following. +! * Note: It is much faster to use this then the external program, but it +! * also makes the program size of httpd larger. +! */ + + #define IMAGEMAP_SUPPORT /* */ + + /* To add an additional field -- request duration -- to the access_log. +! * This adds the duration, in seconds that the processing of this +! * request took. +! */ + +! #define LOG_TIMES /* */ + + /* If you want the server to check the execute bit of an HTML file to +! * determine if the file should be parsed, uncomment the following. +! * Using this feature will give better performance for files which +! * are not parsed without the necessity of using the magic mime type +! */ + + /* #define XBITHACK */ + + /* If you want the server to be able to parse the output of CGI scripts, +! * then define the following. This will automatically be defined for +! * SHTTP. This does cause a performance degradation for CGI scripts, +! * as it requires reading the returned CGI headers off the socket one +! * byte at a time. +! */ + + /* #define CGI_SSI_HACK */ + + /* If you would like to ensure that CGI scripts don't mess with the +! * log files (except the error_log file), uncomment the following. +! */ + + /* #define SECURE_LOGS */ + + /* If you would like each "static" file to be sent with a Content-MD5 +! * header to give clients a way of telling whether the object they +! * requested is the one they got - and hasn't been mangled along the way. +! * Of course, no clients support this yet (to my knowledge) and this will +! * _really_ hinder performance on really big files, but that's life. +! */ + + /* #define CONTENT_MD5 */ + + /* If you would like to specify the keyword LOCAL in your access +! * configuration file to match local address (ie, those without embedded +! * dots), uncomment the following. +! */ + + /* #define LOCALHACK */ + + /* If you would like to use NIS services for passwords and group information, +! * uncomment the following. NOTE: DO NOT USE THIS ON OPEN NETWORKS. The +! * security information used in Basic Authentication involves sending the +! * password in clear text across the network on every request which requires +! * it. +! */ + +! #define NIS_SUPPORT + + /* If you have a REALLY heavily loaded system, and you can't afford to +! * have a server per request(low memory?), you can compile with this i +! * option to make max_servers a hard limit. +! */ + + /* #define RESOURCE_LIMIT */ + + /* If your system doesn't support file descriptor passing, or if you +! * don't want to use it, defining the following will enable HTTPd to +! * mimic the 1.3 Forking server. This should be defined in the system +! * specific information in portability.h, and not here. +! */ + + /* #define NO_PASS */ + + + /* defines for new muli-child approach +! * DEFAULT_START_DAEMON defines how many children start at httpd start +! * DEFAULT_MAX_DAEMON defines how many children can start + */ + + #define DEFAULT_START_DAEMON 5 +*************** +*** 122,132 **** + #define DEFAULT_MAX_DAEMON 10 + + /* defines for debugging purposes +! PROFILE to set the server up to profile the code +! QUANTIFY is a profiler from Pure software +! PURIFY is a memory checker from Pure software +! DEBUG compiles in extra debugging code (debug.c, mostly) +! */ + + /* #define DEBUG */ + /* #define PROFILE */ +--- 134,144 ---- + #define DEFAULT_MAX_DAEMON 10 + + /* defines for debugging purposes +! * PROFILE to set the server up to profile the code +! * QUANTIFY is a profiler from Pure software +! * PURIFY is a memory checker from Pure software +! * DEBUG compiles in extra debugging code (debug.c, mostly) +! */ + + /* #define DEBUG */ + /* #define PROFILE */ +*************** +*** 138,149 **** + #define SHELL_PATH "/bin/sh" + + /* DEFAULT_PATH defines the default search PATH handed to CGI scripts +! if there isn't one in the environment when HTTPd runs */ + + #define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin:." + + /* The following define default values for options which can be over- +! ridden at run time via command-line or configuration files */ + + #define HTTPD_ROOT "/usr/local/etc/httpd" + +--- 150,163 ---- + #define SHELL_PATH "/bin/sh" + + /* DEFAULT_PATH defines the default search PATH handed to CGI scripts +! * if there isn't one in the environment when HTTPd runs +! */ + + #define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin:." + + /* The following define default values for options which can be over- +! * ridden at run time via command-line or configuration files +! */ + + #define HTTPD_ROOT "/usr/local/etc/httpd" + +*************** +*** 158,163 **** +--- 172,181 ---- + #define DEFAULT_PORT 80 + #define DEFAULT_USER "#-1" + #define DEFAULT_GROUP "#-1" ++ ++ #ifdef SSL_SUPPORT ++ # define DEFAULT_SSL_PORT 443 ++ #endif /* SSL_SUPPORT */ + + #define DEFAULT_XFERLOG "logs/access_log" + #define DEFAULT_AGENTLOG "logs/agent_log" +diff -brc ./constants.h /X11/blong/httpd/src//constants.h +*** ./constants.h Tue Jun 25 17:23:53 1996 +--- /X11/blong/httpd/src//constants.h Wed Jun 12 17:45:11 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * constants.h,v 1.54 1996/04/05 18:54:42 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: constants.h,v 1.58 1996/06/12 21:52:13 acain Exp $ + * + ************************************************************************ + * +*************** +*** 37,42 **** +--- 37,51 ---- + + #include + #include ++ #ifdef LOG_TIMES ++ # include ++ # include ++ # include ++ #endif /* LOG_TIMES */ ++ #include "global.h" ++ #ifdef SHTTP ++ # include ++ #endif /* SHTTP */ + + #define TRUE 1 + #define FALSE 0 +*************** +*** 52,57 **** +--- 61,76 ---- + # define HTTP_TIME_FORMAT "%a, %d %b %Y %T GMT" + #endif /* NEXT */ + ++ #ifdef SSL_SUPPORT ++ # define SSL_VERSION "SSLeay/0.5.1" ++ #else ++ # define SSL_VERSION "" ++ #endif /* SSL_SUPPORT */ ++ #ifdef SHTTP ++ # define SHTTP_TITLE "SHTTP" ++ #else ++ # define SHTTP_TITLE "" ++ #endif /* SHTTP */ + #define SERVER_VERSION "NCSA/1.5.2" + #define SERVER_SOURCE "NCSA/1.5.2" + #define SERVER_PROTOCOL "HTTP/1.0" +*************** +*** 166,171 **** +--- 185,194 ---- + #define IMAGEMAP_MAGIC_TYPE "text/x-imagemap" + #define BLACKOUT_MAGIC_TYPE "text/x-httpd-black" + ++ #ifdef SHTTP ++ #define SHTTP_MAGIC_TYPE "application/x-s-http-response" /* pre-enhanced s-http response */ ++ #endif /* SHTTP */ ++ + /* For directory indexing */ + #define BY_PATH 0 + #define BY_TYPE 1 +*************** +*** 229,234 **** +--- 252,262 ---- + + char *on_deny[METHODS]; + ++ #ifdef SHTTP ++ list_el *shttp_auth_lines; ++ char *shttp_privacy_enhancements; ++ #endif /* SHTTP */ ++ + char auth_type[MAX_STRING_LEN]; + char auth_name[MAX_STRING_LEN]; + char auth_pwfile[MAX_STRING_LEN]; +*************** +*** 277,283 **** + + #define PH_HTTPD_CONF 1 + #define PH_SRM_CONF 2 +- #define PH_PEM_CONF 3 + + + /* Configurate data structure (for what's configurable per host) +--- 305,310 ---- +*************** +*** 329,335 **** + /* --------- Per request Data Structure ------------- */ + + /* Request Flags */ +- #define DOING_PGP 1 + #define DOING_SHTTP 2 + #define DOING_SSL 3 + +--- 356,361 ---- +*************** +*** 402,408 **** + int num_env; + int max_env; + char **env; +- int *env_len; + + /* Client Information */ + char *remote_host; +--- 428,433 ---- +*************** +*** 418,423 **** +--- 443,459 ---- + sock_buf *cgi_buf; + per_host *hostInfo; + struct in_addr address_info; ++ ++ #ifdef SHTTP ++ /* S-HTTP Information */ ++ msginfo *shttp_info; ++ char *privacy_enhancements; ++ #endif /* SHTTP */ ++ ++ #ifdef LOG_TIMES ++ struct timeval time_recv, time_process, time_send; ++ struct tms times_recv; ++ #endif /* LOG_TIMES */ + + /* Linked List of requests */ + struct _per_request *next; +Only in /X11/blong/httpd/src/: core.1 +Only in /X11/blong/httpd/src/: core.2 +Only in /X11/blong/httpd/src/: debug.o +diff -brc ./digest.c /X11/blong/httpd/src//digest.c +*** ./digest.c Tue Jun 25 17:06:13 1996 +--- /X11/blong/httpd/src//digest.c Thu May 23 15:15:31 1996 +*************** +*** 25,36 **** + #endif /* NO_STDLIB_H */ + #include + #include +- #include + #include + #include + #ifdef DBM_SUPPORT +! # ifndef _DBMSUPPORT_H /* moronic OSs which don't protect their own include */ +! # define _DBMSUPPORT_H /* files from being multiply included */ + # include + # endif /* _DBMSUPPORT_H */ + #endif /* DBM_SUPPORT */ +--- 25,36 ---- + #endif /* NO_STDLIB_H */ + #include + #include + #include ++ #include + #include + #ifdef DBM_SUPPORT +! # ifndef _DBMSUPPORT_H +! # define _DBMSUPPORT_H + # include + # endif /* _DBMSUPPORT_H */ + #endif /* DBM_SUPPORT */ +*************** +*** 42,58 **** + #include "http_auth.h" + #include "http_mime.h" + #include "util.h" + + int get_digest(per_request *reqInfo, char *user, char *realm, char *digest, + security_data* sec) + { + FILE *f; +- char errstr[MAX_STRING_LEN]; + char l[MAX_STRING_LEN]; + char w[MAX_STRING_LEN]; + char r[MAX_STRING_LEN]; + +- if (reqInfo->auth_digestfile_type == AUTHFILETYPE_STANDARD) { + if (reqInfo->auth_digestfile == NULL) { + sprintf (errstr, "No digest file specified for URL: %s\n", + reqInfo->url); +--- 42,86 ---- + #include "http_auth.h" + #include "http_mime.h" + #include "util.h" ++ #include "md5.h" ++ #ifdef NIS_SUPPORT ++ # include "http_nis.h" ++ #endif /* NIS_SUPPORT */ + ++ int dbm_get_digest(per_request *reqInfo, char *user, char *realm, char *digest) ++ { ++ DBM* db; ++ datum dtKey, dtRec; ++ char szBuf[2*MAX_STRING_LEN]; ++ char errstr[MAX_STRING_LEN]; ++ ++ if(!(db = DBM_Open(reqInfo->auth_digestfile, O_RDONLY, 0))) { ++ sprintf(errstr,"Could not open user file %s",reqInfo->auth_digestfile); ++ die(reqInfo,SC_SERVER_ERROR,errstr); ++ } ++ sprintf (szBuf, "%s:%s", user, realm); ++ dtKey.dptr = szBuf; ++ dtKey.dsize = strlen(szBuf); ++ dtRec = dbm_fetch(db, dtKey); ++ DBM_Close(db); ++ if (dtRec.dptr) { ++ strncpy(digest, dtRec.dptr, dtRec.dsize); ++ digest[dtRec.dsize] = '\0'; ++ return 1; ++ } ++ return 0; ++ } ++ + int get_digest(per_request *reqInfo, char *user, char *realm, char *digest, + security_data* sec) + { ++ if (reqInfo->auth_digestfile_type == AUTHFILETYPE_STANDARD) { + FILE *f; + char l[MAX_STRING_LEN]; + char w[MAX_STRING_LEN]; + char r[MAX_STRING_LEN]; ++ char errstr[MAX_STRING_LEN]; + + if (reqInfo->auth_digestfile == NULL) { + sprintf (errstr, "No digest file specified for URL: %s\n", + reqInfo->url); +*************** +*** 88,146 **** + } + #ifdef DBM_SUPPORT + else if (reqInfo->auth_digestfile_type == AUTHFILETYPE_DBM) { +! DBM* db; +! datum dtKey, dtRec; +! char szBuf[2*MAX_STRING_LEN]; +! +! if(!(db = DBM_Open(reqInfo->auth_digestfile, O_RDONLY, 0))) { +! sprintf(errstr,"Could not open user file %s",reqInfo->auth_digestfile); +! die(reqInfo,SC_SERVER_ERROR,errstr); + } +- sprintf (szBuf, "%s:%s", user, realm); +- dtKey.dptr = szBuf; +- dtKey.dsize = strlen(szBuf); +- dtRec = dbm_fetch(db, dtKey); +- DBM_Close(db); +- if (dtRec.dptr) { +- strncpy(digest, dtRec.dptr, dtRec.dsize); +- digest[dtRec.dsize] = '\0'; +- return 1; +- } +- else +- return 0; +- } + #endif /* DBM_SUPPORT */ + #ifdef NIS_SUPPORT + else if (reqInfo->auth_pwfile_type == AUTHFILETYPE_NIS) { +! char *domain, +! *digest, +! *resptr, +! szBuf[2*MAX_STRING_LEN]; +! int yperr, +! resize; +! +! if (init_nis(&domain) != 0) +! return 0; +! +! if (strcmp(reqInfo->auth_digestfile, "+")) +! digest = reqInfo->auth_digestfile; +! else +! digest = "digest"; +! +! (void) sprintf(szBuf, "%s:%s", user, realm); +! +! yperr = yp_match(domain, digest, szBuf, strlen(szBuf), &resptr, &resize); +! if (yperr == 0) { +! getword(w, resptr, ':'); +! getword(r, resptr, ':'); +! if (strcmp(w, user) == 0 && strcmp(w, realm) == 0) { +! getword(w, resptr, ':'); +! (void) strcpy(digest, w); +! return 1; + } +- } +- return 0; +- } + #endif /* NIS_SUPPORT */ + else + die(reqInfo,SC_SERVER_ERROR,"Invalid password file type"); +--- 116,128 ---- + } + #ifdef DBM_SUPPORT + else if (reqInfo->auth_digestfile_type == AUTHFILETYPE_DBM) { +! return dbm_get_digest(reqInfo,user,realm,digest); + } + #endif /* DBM_SUPPORT */ + #ifdef NIS_SUPPORT + else if (reqInfo->auth_pwfile_type == AUTHFILETYPE_NIS) { +! return nis_get_digest(reqInfo,user,realm,digest); + } + #endif /* NIS_SUPPORT */ + else + die(reqInfo,SC_SERVER_ERROR,"Invalid password file type"); +*************** +*** 147,153 **** + return 0; + } + +! void Digest_Construct401(per_request *reqInfo, char *s, int stale, char* auth_name) + { + char timestamp[32]; + char h_opaque[33]; +--- 129,136 ---- + return 0; + } + +! void Digest_Construct401(per_request *reqInfo, char *s, int stale, +! char* auth_name) + { + char timestamp[32]; + char h_opaque[33]; +*************** +*** 154,181 **** + char opaque[MAX_STRING_LEN]; + + /* +! Note that the domain field isn't being sent at all. If +! it were to be sent, it would probably need to be read +! from the config files. +! +! We're using timestamps as our nonce value. + */ + + /* +! Grab the timestamp (for the nonce). Also, then construct +! the opaque value. + */ + sprintf(timestamp, "%d", time(NULL)); + sprintf(opaque, "%s:%s:%s", auth_name, timestamp, reqInfo->remote_ip); + md5(opaque, h_opaque); + +! if (stale) +! { + sprintf(s, "Digest realm=\"%s\" nonce=\"%s\" opaque=\"%s\" stale=TRUE", + auth_name, timestamp, h_opaque); +! } +! else +! { + sprintf(s, "Digest realm=\"%s\" nonce=\"%s\" opaque=\"%s\"", + auth_name, timestamp, h_opaque); + } +--- 137,161 ---- + char opaque[MAX_STRING_LEN]; + + /* +! * Note that the domain field isn't being sent at all. If +! * it were to be sent, it would probably need to be read +! * from the config files. +! * +! * We're using timestamps as our nonce value. + */ + + /* +! * Grab the timestamp (for the nonce). Also, then construct +! * the opaque value. + */ + sprintf(timestamp, "%d", time(NULL)); + sprintf(opaque, "%s:%s:%s", auth_name, timestamp, reqInfo->remote_ip); + md5(opaque, h_opaque); + +! if (stale) { + sprintf(s, "Digest realm=\"%s\" nonce=\"%s\" opaque=\"%s\" stale=TRUE", + auth_name, timestamp, h_opaque); +! } else { + sprintf(s, "Digest realm=\"%s\" nonce=\"%s\" opaque=\"%s\"", + auth_name, timestamp, h_opaque); + } +*************** +*** 191,212 **** + char opaque[MAX_STRING_LEN]; + char errstr[MAX_STRING_LEN]; + +! char *p; +! char *q; + + time_t time_now; + time_t time_nonce; + +! /* user[0]; */ /* assume that we won't succeed */ + +- username[0] = 0; +- realm[0] = 0; +- nonce[0] = 0; +- uri[0] = 0; +- response[0] = 0; +- opaque[0] = 0; +- p = q = NULL; +- + p = reqInfo->inh_auth_line; + while (isspace(*p)) { + p++; +--- 171,189 ---- + char opaque[MAX_STRING_LEN]; + char errstr[MAX_STRING_LEN]; + +! char *p = NULL; +! char *q = NULL; + + time_t time_now; + time_t time_nonce; + +! username[0] = '\0'; +! realm[0] = '\0'; +! nonce[0] = '\0'; +! uri[0] = '\0'; +! response[0] = '\0'; +! opaque[0] = '\0'; + + p = reqInfo->inh_auth_line; + while (isspace(*p)) { + p++; +*************** +*** 292,298 **** + } + + /* +! Skip to the next keyword value pair, or the end + */ + while (*p && (*p != ',')) { + p++; +--- 269,275 ---- + } + + /* +! * Skip to the next keyword value pair, or the end + */ + while (*p && (*p != ',')) { + p++; +*************** +*** 312,318 **** + char h_all[32 + 1]; + + /* +! First, check to make sure the nonce is not stale + */ + + time_nonce = atoi(nonce); +--- 289,295 ---- + char h_all[32 + 1]; + + /* +! * First, check to make sure the nonce is not stale + */ + + time_nonce = atoi(nonce); +*************** +*** 328,334 **** + } + + /* +! Check to make sure that the opaque string is valid. + */ + { + char h_opaque[33]; +--- 305,311 ---- + } + + /* +! * Check to make sure that the opaque string is valid. + */ + { + char h_opaque[33]; +*************** +*** 345,352 **** + } + + /* +! Here we should check to make sure that the URI +! given is valid, but a simple strcmp may not be reliable. + */ + #if 0 + if (0 != strcmp(reqInfo->url, uri)) { +--- 322,329 ---- + } + + /* +! * Here we should check to make sure that the URI +! * given is valid, but a simple strcmp may not be reliable. + */ + #if 0 + if (0 != strcmp(reqInfo->url, uri)) { +*************** +*** 357,364 **** + #endif /* 0 */ + + /* +! Now, check to make sure that the MD5 digest given +! is correct. + */ + + if (!get_digest(reqInfo,username, realm, h_a1, sec)) { +--- 334,341 ---- + #endif /* 0 */ + + /* +! * Now, check to make sure that the MD5 digest given +! * is correct. + */ + + if (!get_digest(reqInfo,username, realm, h_a1, sec)) { +Only in /X11/blong/httpd/src/: digest.o +diff -brc ./env.c /X11/blong/httpd/src//env.c +*** ./env.c Tue Jun 25 17:06:13 1996 +--- /X11/blong/httpd/src//env.c Wed Jun 5 21:44:17 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! *env.c,v 1.20 1996/04/05 18:54:44 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! *$Id: env.c,v 1.23 1996/06/06 02:44:17 blong Exp $ + * + ************************************************************************ + * +*************** +*** 31,36 **** +--- 31,37 ---- + #include "http_request.h" + #include "http_log.h" + #include "allocate.h" ++ #include "util.h" + + /* Older version, required external help. Newer version should be self + * contained for easier extensibility +*************** +*** 39,56 **** + */ + + /* This will change the value of an environment variable to *value +! if found. Returns TRUE if the replace took place, FALSE otherwise */ + + int replace_env_str(per_request *reqInfo, char *name, char *value) + { + register int i, len; + +! for (i = 0, len = strlen(name); reqInfo->env[i]; i++) { + if (strncmp(reqInfo->env[i], name, len) == 0) { +! free(reqInfo->env[i]); + if (i < reqInfo->num_env) { + reqInfo->env[i] = reqInfo->env[--(reqInfo->num_env)]; +- reqInfo->env_len[i] = reqInfo->env_len[reqInfo->num_env]; + reqInfo->env[reqInfo->num_env] = NULL; + } + else { +--- 40,58 ---- + */ + + /* This will change the value of an environment variable to *value +! * if found. Returns TRUE if the replace took place, FALSE otherwise +! */ + + int replace_env_str(per_request *reqInfo, char *name, char *value) + { + register int i, len; + +! len = strlen(name); +! for (i = 0; (reqInfo->env[i] && (i < reqInfo->num_env)); i++) { + if (strncmp(reqInfo->env[i], name, len) == 0) { +! freeString(reqInfo->env[i]); + if (i < reqInfo->num_env) { + reqInfo->env[i] = reqInfo->env[--(reqInfo->num_env)]; + reqInfo->env[reqInfo->num_env] = NULL; + } + else { +*************** +*** 69,87 **** + void free_env(per_request *reqInfo) { + int x; + +! for(x=0;reqInfo->env[x];x++) + freeString(reqInfo->env[x]); +! free(reqInfo->env); +! free(reqInfo->env_len); + reqInfo->env = NULL; + } + + + /* If the environment variable has already been set, this will append +! the value to it, of the form "name=old, new" +! Assumes that "header" is a pointer to a string that is longer than +! the string it contains +! */ + + int merge_header(per_request *reqInfo, char *header, char *value) + { +--- 71,88 ---- + void free_env(per_request *reqInfo) { + int x; + +! for(x=0;(x < reqInfo->num_env) && (reqInfo->env[x]);x++) + freeString(reqInfo->env[x]); +! Free(reqInfo->env); + reqInfo->env = NULL; + } + + + /* If the environment variable has already been set, this will append +! * the value to it, of the form "name=old, new" +! * Assumes that "header" is a pointer to a string that is longer than +! * the string it contains +! */ + + int merge_header(per_request *reqInfo, char *header, char *value) + { +*************** +*** 98,104 **** + for(ndx = 0, t=reqInfo->env; *t; ++t, ndx++) { + if(!strncmp(*t,header,l)) { + lt = strlen(*t); +! if ((lt + len + 2) > reqInfo->env_len[ndx]) { + tmp = reqInfo->env[ndx]; + if ((lt+len+2) > HUGE_STRING_LEN) { + reqInfo->env[ndx] = newString(lt+len+2,STR_REQ); +--- 99,105 ---- + for(ndx = 0, t=reqInfo->env; *t; ++t, ndx++) { + if(!strncmp(*t,header,l)) { + lt = strlen(*t); +! if ((lt + len + 2) > sizeofString(*t)) { + tmp = reqInfo->env[ndx]; + if ((lt+len+2) > HUGE_STRING_LEN) { + reqInfo->env[ndx] = newString(lt+len+2,STR_REQ); +*************** +*** 126,132 **** + + int make_env_str(per_request *reqInfo, char *name, char *value) + { +- int n; + char tmp[HUGE_STRING_LEN]; + + if (value == NULL) { +--- 127,132 ---- +*************** +*** 136,151 **** + return 0; + } + if (reqInfo->env == NULL) { +! if (!(reqInfo->env = (char **) malloc(ENV_BEG_SIZE * sizeof(char *))) +! || !(reqInfo->env_len = (int*) malloc(ENV_BEG_SIZE * sizeof(int)))) + die(reqInfo,SC_NO_MEMORY,"make_env_str:malloc"); + reqInfo->max_env = ENV_BEG_SIZE; + } + if ((reqInfo->num_env+1) >= reqInfo->max_env) { +! if (!(reqInfo->env = (char **) realloc(reqInfo->env, +! ((reqInfo->max_env+ENV_INC_SIZE) * sizeof(char *)))) +! || !(reqInfo->env_len = (int*) realloc(reqInfo->env_len, +! (reqInfo->max_env + ENV_INC_SIZE) * sizeof(int)))) + die(reqInfo,SC_NO_MEMORY,"make_env_str:realloc"); + reqInfo->max_env += ENV_INC_SIZE; + } +--- 136,148 ---- + return 0; + } + if (reqInfo->env == NULL) { +! if (!(reqInfo->env = (char **) Malloc(ENV_BEG_SIZE * sizeof(char *)))) + die(reqInfo,SC_NO_MEMORY,"make_env_str:malloc"); + reqInfo->max_env = ENV_BEG_SIZE; + } + if ((reqInfo->num_env+1) >= reqInfo->max_env) { +! if (!(reqInfo->env = (char **) Realloc(reqInfo->env, +! ((reqInfo->max_env+ENV_INC_SIZE) * sizeof(char *))))) + die(reqInfo,SC_NO_MEMORY,"make_env_str:realloc"); + reqInfo->max_env += ENV_INC_SIZE; + } +*************** +*** 153,165 **** + strncat(tmp,"=",HUGE_STRING_LEN - strlen(tmp)); + strncat(tmp,value,HUGE_STRING_LEN - strlen(tmp)); + reqInfo->env[reqInfo->num_env] = dupStringP(tmp,STR_REQ); +- reqInfo->env_len[reqInfo->num_env] = +- sizeofString(reqInfo->env[reqInfo->num_env]); +- + reqInfo->num_env++; + reqInfo->env[reqInfo->num_env] = NULL; + + return 1; + } + + /* Debugging dump of environment array */ +--- 150,176 ---- + strncat(tmp,"=",HUGE_STRING_LEN - strlen(tmp)); + strncat(tmp,value,HUGE_STRING_LEN - strlen(tmp)); + reqInfo->env[reqInfo->num_env] = dupStringP(tmp,STR_REQ); + reqInfo->num_env++; + reqInfo->env[reqInfo->num_env] = NULL; + + return 1; ++ } ++ ++ /* return_env_value() ++ * returns a pointer to the value portion of env var given ++ * the var to look for. ++ */ ++ char* return_env_value(per_request *reqInfo, char *var) ++ { ++ int len = strlen(var); ++ int x,i; ++ ++ for(x=0; reqInfo->env[x] && (x < reqInfo->num_env); x++) { ++ i = ind(reqInfo->env[x],'='); ++ if ((i == len) && !(strncmp(reqInfo->env[x],var,i))) ++ return &(reqInfo->env[x][i+1]); ++ } ++ return NULL; + } + + /* Debugging dump of environment array */ +diff -brc ./env.h /X11/blong/httpd/src//env.h +*** ./env.h Tue Jun 25 17:06:13 1996 +--- /X11/blong/httpd/src//env.h Wed Jun 12 16:11:50 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * env.h,v 1.8 1995/11/28 09:01:43 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: env.h,v 1.9 1996/06/12 18:26:08 blong Exp $ + * + ************************************************************************ + * +*************** +*** 37,42 **** +--- 37,44 ---- + int merge_header(per_request *reqInfo, char *h, char *v); + void free_env(per_request *reqInfo); + int replace_env_str(per_request *reqInfo, char *name, char *value); ++ char* return_env_value(per_request *reqInfo, char *var); ++ + + #endif /* _ENV_H_ */ + +Only in /X11/blong/httpd/src/: env.o +diff -brc ./fcgi.c /X11/blong/httpd/src//fcgi.c +*** ./fcgi.c Tue Jun 25 17:06:13 1996 +--- /X11/blong/httpd/src//fcgi.c Wed Jun 5 21:44:19 1996 +*************** +*** 4,15 **** + * Copyright (C) 1995 Open Market, Inc. + * All rights reserved. + * +- * This file contains proprietary and confidential information and +- * remains the unpublished property of Open Market, Inc. Use, +- * disclosure, or reproduction is prohibited except as permitted by +- * express written license agreement with Open Market, Inc. + ************************************************************************ +! * $Id: fcgi.c,v 1.3 1996/03/25 22:21:10 blong Exp $ + ************************************************************************ + * + * fcgi.c -- interface to FCGI +--- 4,11 ---- + * Copyright (C) 1995 Open Market, Inc. + * All rights reserved. + * + ************************************************************************ +! * $Id: fcgi.c,v 1.7 1996/06/06 02:44:19 blong Exp $ + ************************************************************************ + * + * fcgi.c -- interface to FCGI +*************** +*** 53,58 **** +--- 49,55 ---- + #include + #include + #include ++ #include + #include + #include + #include +*************** +*** 83,88 **** +--- 80,86 ---- + #include "http_config.h" + #include "http_auth.h" + #include "http_alias.h" ++ #include "http_send.h" + #include "util.h" + /*-----------------dependent types-----------------------*/ + typedef per_request WS_Request; +*************** +*** 411,417 **** + } FastCgiInfo; + + int fastCgiInit = 0; +! static WS_Request *hackRequest = NULL; + FastCgiServerInfo *fastCgiServers = NULL; + FastCgiInfo *globalInfoPtr = NULL; + int ht_openmax = 128; +--- 409,415 ---- + } FastCgiInfo; + + int fastCgiInit = 0; +! /* static WS_Request *hackRequest = NULL; */ + FastCgiServerInfo *fastCgiServers = NULL; + FastCgiInfo *globalInfoPtr = NULL; + int ht_openmax = 128; +*************** +*** 2395,2401 **** + static int ConnectionComplete(WS_Request *reqPtr, FastCgiInfo *infoPtr) + { + int errorCode, len; +! FastCgiServerInfo *serverInfoPtr = infoPtr->serverPtr; + + /* + * Get the connection status. +--- 2393,2399 ---- + static int ConnectionComplete(WS_Request *reqPtr, FastCgiInfo *infoPtr) + { + int errorCode, len; +! /* FastCgiServerInfo *serverInfoPtr = infoPtr->serverPtr; */ + + /* + * Get the connection status. +*************** +*** 2446,2452 **** + { + FastCgiServerInfo *serverInfoPtr; + FastCgiInfo *infoPtr; +! int scriptTimeout; + OS_IpcAddr *ipcAddrPtr; + struct stat finfo; + +--- 2444,2450 ---- + { + FastCgiServerInfo *serverInfoPtr; + FastCgiInfo *infoPtr; +! /* int scriptTimeout; */ + OS_IpcAddr *ipcAddrPtr; + struct stat finfo; + +*************** +*** 2776,2782 **** + + void OS_EnvironFree(char **envPtr) + { +! int i; + char **tmp = envPtr; + while (*tmp) { + free(*tmp); +--- 2774,2780 ---- + + void OS_EnvironFree(char **envPtr) + { +! /* int i; */ + char **tmp = envPtr; + while (*tmp) { + free(*tmp); +*************** +*** 2787,2793 **** + void OS_EnvString(char **envPtr, char *name, char *value) + { + char *buf; +! int size; + buf = (char *)Malloc(strlen(name) + strlen(value) + 2); + sprintf(buf, "%s=%s", name, value); + *envPtr = buf; +--- 2785,2791 ---- + void OS_EnvString(char **envPtr, char *name, char *value) + { + char *buf; +! /* int size; */ + buf = (char *)Malloc(strlen(name) + strlen(value) + 2); + sprintf(buf, "%s=%s", name, value); + *envPtr = buf; +*************** +*** 2820,2826 **** + { + FastCgiServerInfo *serverInfoPtr = NULL; + FcgiProcessInfo *procInfoPtr; +! int i, new; + + serverInfoPtr = FastCgiServerInfoLookup(ePath); + if (serverInfoPtr) +--- 2818,2825 ---- + { + FastCgiServerInfo *serverInfoPtr = NULL; + FcgiProcessInfo *procInfoPtr; +! int i; +! /* int new; */ + + serverInfoPtr = FastCgiServerInfoLookup(ePath); + if (serverInfoPtr) +*************** +*** 2976,2982 **** + static void FcgiProgramExit(FcgiProcessInfo *processInfoPtr, int status) + { + FastCgiServerInfo *serverInfoPtr = processInfoPtr->serverInfoPtr; +! time_t restartTime, timeNow; + + serverInfoPtr->numFailures++; + processInfoPtr->pid = -1; +--- 2975,2981 ---- + static void FcgiProgramExit(FcgiProcessInfo *processInfoPtr, int status) + { + FastCgiServerInfo *serverInfoPtr = processInfoPtr->serverInfoPtr; +! /* time_t restartTime, timeNow; */ + + serverInfoPtr->numFailures++; + processInfoPtr->pid = -1; +*************** +*** 3090,3096 **** + processInfoPtr++; + } + while (1) { /* looping to detect and reborn any dead child */ +! int status; + + sleep(serverInfoPtr->restartDelay); + if (serverInfoPtr->restartOnExit == FALSE) +--- 3089,3095 ---- + processInfoPtr++; + } + while (1) { /* looping to detect and reborn any dead child */ +! /* int status; */ + + sleep(serverInfoPtr->restartDelay); + if (serverInfoPtr->restartOnExit == FALSE) +*************** +*** 3165,3173 **** + int affinity = 0; + int restartDelay = FCGI_DEFAULT_RESTART_DELAY; + char *execPath; +! char temp[200]; + FastCgiServerInfo *serverInfoPtr = NULL; +! FcgiProcessInfo *processInfoPtr; + int i; + int listenFd = -1; + char *namePtr; +--- 3164,3172 ---- + int affinity = 0; + int restartDelay = FCGI_DEFAULT_RESTART_DELAY; + char *execPath; +! /* char temp[200]; */ + FastCgiServerInfo *serverInfoPtr = NULL; +! /* FcgiProcessInfo *processInfoPtr; */ + int i; + int listenFd = -1; + char *namePtr; +*************** +*** 3179,3185 **** + int argc; + char **argv; + int envCount; +! int listenSock = -1; + SetErrorLogFd(host, 1); + + argv = ParseAppClassArgs(arg, &argc); +--- 3178,3184 ---- + int argc; + char **argv; + int envCount; +! /* int listenSock = -1; */ + SetErrorLogFd(host, 1); + + argv = ParseAppClassArgs(arg, &argc); +diff -brc ./fcgi.h /X11/blong/httpd/src//fcgi.h +*** ./fcgi.h Tue Jun 25 17:06:13 1996 +--- /X11/blong/httpd/src//fcgi.h Wed May 15 16:09:49 1996 +*************** +*** 9,15 **** + * disclosure, or reproduction is prohibited except as permitted by + * express written license agreement with Open Market, Inc. + ************************************************************************ +! * $Id: fcgi.h,v 1.2 1996/03/25 22:21:30 blong Exp $ + ************************************************************************ + * + * fcgi.c -- interface to FCGI +--- 9,15 ---- + * disclosure, or reproduction is prohibited except as permitted by + * express written license agreement with Open Market, Inc. + ************************************************************************ +! * $Id: fcgi.h,v 1.3 1996/05/15 21:09:49 blong Exp $ + ************************************************************************ + * + * fcgi.c -- interface to FCGI +*************** +*** 21,26 **** +--- 21,28 ---- + + #ifndef _FCGI_H + #define _FCGI_H 1 ++ ++ #define FCGI_MAGIC_TYPE "application/x-httpd-fcgi" + + /* External Functions */ + int FastCgiHandler(per_request *reqPtr); +Only in /X11/blong/httpd/src/: fcgi.o +diff -brc ./fdwrap.c /X11/blong/httpd/src//fdwrap.c +*** ./fdwrap.c Tue Jun 25 17:06:13 1996 +--- /X11/blong/httpd/src//fdwrap.c Wed Jun 5 21:44:21 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * fdwrap.c,v 1.15 1996/04/05 18:54:46 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: fdwrap.c,v 1.16 1996/06/06 02:44:21 blong Exp $ + * + ************************************************************************ + * +*************** +*** 45,50 **** +--- 45,51 ---- + #include "fdwrap.h" + #include "host_config.h" + #include "http_log.h" ++ #include "allocate.h" + + static FDTABLE* FdTab; + static int nSize; +*************** +*** 70,76 **** + int ndx; + + /* take care of failure here */ +! FdTab = (FDTABLE*) malloc (INITIAL_TABSIZE * sizeof(FDTABLE)); + if (!FdTab) { + fprintf(stderr, + "HTTPd: Could not allocate memory for file descriptor tracking\n"); +--- 71,77 ---- + int ndx; + + /* take care of failure here */ +! FdTab = (FDTABLE*) Malloc (INITIAL_TABSIZE * sizeof(FDTABLE)); + if (!FdTab) { + fprintf(stderr, + "HTTPd: Could not allocate memory for file descriptor tracking\n"); +*************** +*** 287,291 **** + + void DestroyFdTab(void) + { +! free (FdTab); + } +--- 288,292 ---- + + void DestroyFdTab(void) + { +! Free (FdTab); + } +diff -brc ./fdwrap.h /X11/blong/httpd/src//fdwrap.h +*** ./fdwrap.h Tue Jun 25 17:06:13 1996 +--- /X11/blong/httpd/src//fdwrap.h Tue Nov 28 03:01:45 1995 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * fdwrap.h,v 1.5 1995/11/28 09:01:45 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: fdwrap.h,v 1.5 1995/11/28 09:01:45 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: fdwrap.o +diff -brc ./host_config.c /X11/blong/httpd/src//host_config.c +*** ./host_config.c Tue Jun 25 17:06:14 1996 +--- /X11/blong/httpd/src//host_config.c Wed Jun 12 16:11:50 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! *host_config.c,v 1.20 1996/04/05 18:54:47 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! *$Id: host_config.c,v 1.22 1996/06/12 20:35:23 acain Exp $ + * + ************************************************************************ + * +*************** +*** 29,34 **** +--- 29,35 ---- + #include "http_alias.h" + #include "http_mime.h" + #include "http_request.h" ++ #include "allocate.h" + #include "util.h" + + per_host* gConfiguration; +*************** +*** 36,42 **** + per_host* create_host_conf(per_host *hostInfo, int virtual) { + per_host *newInfo, *tmpInfo; + +! newInfo = (per_host *) malloc(sizeof(per_host)); + + newInfo->httpd_conf = 0; + newInfo->srm_conf = 0; +--- 37,43 ---- + per_host* create_host_conf(per_host *hostInfo, int virtual) { + per_host *newInfo, *tmpInfo; + +! newInfo = (per_host *) Malloc(sizeof(per_host)); + + newInfo->httpd_conf = 0; + newInfo->srm_conf = 0; +*************** +*** 103,128 **** + + while (host != NULL) { + close_logs(host); +! if (host->httpd_conf & HC_ERROR_FNAME) free(host->error_fname); +! if (host->httpd_conf & HC_XFER_FNAME) free(host->xfer_fname); +! if (host->httpd_conf & HC_AGENT_FNAME) free(host->agent_fname); +! if (host->httpd_conf & HC_REFERER_FNAME) free(host->referer_fname); +! if (host->httpd_conf & HC_REFERER_IGNORE) free(host->referer_ignore); +! if (host->httpd_conf & HC_SERVER_ADMIN) free(host->server_admin); +! if (host->httpd_conf & HC_SERVER_HOSTNAME) free(host->server_hostname); +! if (host->httpd_conf & HC_SRM_CONFNAME) free(host->srm_confname); +! if (host->httpd_conf & HC_ANNOT_SERVER) free(host->annotation_server); +! if (host->srm_conf & SRM_USER_DIR) free(host->user_dir); +! if (host->srm_conf & SRM_INDEX_NAMES) free(host->index_names); +! if (host->srm_conf & SRM_ACCESS_NAME) free(host->access_name); +! if (host->srm_conf & SRM_DOCUMENT_ROOT) free(host->document_root); +! if (host->srm_conf & SRM_DEFAULT_TYPE) free(host->default_type); +! if (host->srm_conf & SRM_DEFAULT_ICON) free(host->default_icon); + if (host->srm_conf & SRM_TRANSLATIONS) free_aliases(host->translations); + if (host->srm_conf & SRM_DOCERRORS) free_doc_errors(host); + + tmp = host->next; +! free(host); + host = tmp; + } + } +--- 104,129 ---- + + while (host != NULL) { + close_logs(host); +! if (host->httpd_conf & HC_ERROR_FNAME) Free(host->error_fname); +! if (host->httpd_conf & HC_XFER_FNAME) Free(host->xfer_fname); +! if (host->httpd_conf & HC_AGENT_FNAME) Free(host->agent_fname); +! if (host->httpd_conf & HC_REFERER_FNAME) Free(host->referer_fname); +! if (host->httpd_conf & HC_REFERER_IGNORE) Free(host->referer_ignore); +! if (host->httpd_conf & HC_SERVER_ADMIN) Free(host->server_admin); +! if (host->httpd_conf & HC_SERVER_HOSTNAME) Free(host->server_hostname); +! if (host->httpd_conf & HC_SRM_CONFNAME) Free(host->srm_confname); +! if (host->httpd_conf & HC_ANNOT_SERVER) Free(host->annotation_server); +! if (host->srm_conf & SRM_USER_DIR) Free(host->user_dir); +! if (host->srm_conf & SRM_INDEX_NAMES) Free(host->index_names); +! if (host->srm_conf & SRM_ACCESS_NAME) Free(host->access_name); +! if (host->srm_conf & SRM_DOCUMENT_ROOT) Free(host->document_root); +! if (host->srm_conf & SRM_DEFAULT_TYPE) Free(host->default_type); +! if (host->srm_conf & SRM_DEFAULT_ICON) Free(host->default_icon); + if (host->srm_conf & SRM_TRANSLATIONS) free_aliases(host->translations); + if (host->srm_conf & SRM_DOCERRORS) free_doc_errors(host); + + tmp = host->next; +! Free(host); + host = tmp; + } + } +*************** +*** 158,204 **** + switch (option) { + case HC_ERROR_FNAME: + if (hostInfo->httpd_conf & option) +! free(hostInfo->error_fname); + hostInfo->error_fname = tmp; + break; + case HC_XFER_FNAME: + if (hostInfo->httpd_conf & option) +! free(hostInfo->xfer_fname); + hostInfo->xfer_fname = tmp; + break; + case HC_AGENT_FNAME: + if (hostInfo->httpd_conf & option) +! free(hostInfo->agent_fname); + hostInfo->agent_fname = tmp; + break; + case HC_REFERER_FNAME: + if (hostInfo->httpd_conf & option) +! free(hostInfo->referer_fname); + hostInfo->referer_fname = tmp; + break; + case HC_REFERER_IGNORE: + if (hostInfo->httpd_conf & option) +! free(hostInfo->referer_ignore); + hostInfo->referer_ignore = tmp; + break; + case HC_SERVER_ADMIN: + if (hostInfo->httpd_conf & option) +! free(hostInfo->server_admin); + hostInfo->server_admin = tmp; + break; + case HC_SERVER_HOSTNAME: + if (hostInfo->httpd_conf & option) +! free(hostInfo->server_hostname); + hostInfo->server_hostname = tmp; + break; + case HC_SRM_CONFNAME: + if (hostInfo->httpd_conf & option) +! free(hostInfo->srm_confname); + hostInfo->srm_confname = tmp; + break; + case HC_ANNOT_SERVER: + if (hostInfo->httpd_conf & option) +! free(hostInfo->annotation_server); + hostInfo->annotation_server = tmp; + break; + } +--- 159,205 ---- + switch (option) { + case HC_ERROR_FNAME: + if (hostInfo->httpd_conf & option) +! Free(hostInfo->error_fname); + hostInfo->error_fname = tmp; + break; + case HC_XFER_FNAME: + if (hostInfo->httpd_conf & option) +! Free(hostInfo->xfer_fname); + hostInfo->xfer_fname = tmp; + break; + case HC_AGENT_FNAME: + if (hostInfo->httpd_conf & option) +! Free(hostInfo->agent_fname); + hostInfo->agent_fname = tmp; + break; + case HC_REFERER_FNAME: + if (hostInfo->httpd_conf & option) +! Free(hostInfo->referer_fname); + hostInfo->referer_fname = tmp; + break; + case HC_REFERER_IGNORE: + if (hostInfo->httpd_conf & option) +! Free(hostInfo->referer_ignore); + hostInfo->referer_ignore = tmp; + break; + case HC_SERVER_ADMIN: + if (hostInfo->httpd_conf & option) +! Free(hostInfo->server_admin); + hostInfo->server_admin = tmp; + break; + case HC_SERVER_HOSTNAME: + if (hostInfo->httpd_conf & option) +! Free(hostInfo->server_hostname); + hostInfo->server_hostname = tmp; + break; + case HC_SRM_CONFNAME: + if (hostInfo->httpd_conf & option) +! Free(hostInfo->srm_confname); + hostInfo->srm_confname = tmp; + break; + case HC_ANNOT_SERVER: + if (hostInfo->httpd_conf & option) +! Free(hostInfo->annotation_server); + hostInfo->annotation_server = tmp; + break; + } +*************** +*** 208,240 **** + switch (option) { + case SRM_USER_DIR: + if (hostInfo->srm_conf & option) +! free(hostInfo->user_dir); + hostInfo->user_dir = tmp; + break; + case SRM_INDEX_NAMES: + if (hostInfo->srm_conf & option) +! free(hostInfo->index_names); + hostInfo->index_names = tmp; + break; + case SRM_ACCESS_NAME: + if (hostInfo->srm_conf & option) +! free(hostInfo->access_name); + hostInfo->access_name = tmp; + break; + case SRM_DOCUMENT_ROOT: + if (hostInfo->srm_conf & option) +! free(hostInfo->document_root); + hostInfo->document_root = tmp; + hostInfo->doc_root_len = strlen(tmp); + break; + case SRM_DEFAULT_TYPE: + if (hostInfo->srm_conf & option) +! free(hostInfo->default_type); + hostInfo->default_type = tmp; + break; + case SRM_DEFAULT_ICON: + if (hostInfo->srm_conf & option) +! free(hostInfo->default_icon); + hostInfo->default_icon = tmp; + break; + } +--- 209,241 ---- + switch (option) { + case SRM_USER_DIR: + if (hostInfo->srm_conf & option) +! Free(hostInfo->user_dir); + hostInfo->user_dir = tmp; + break; + case SRM_INDEX_NAMES: + if (hostInfo->srm_conf & option) +! Free(hostInfo->index_names); + hostInfo->index_names = tmp; + break; + case SRM_ACCESS_NAME: + if (hostInfo->srm_conf & option) +! Free(hostInfo->access_name); + hostInfo->access_name = tmp; + break; + case SRM_DOCUMENT_ROOT: + if (hostInfo->srm_conf & option) +! Free(hostInfo->document_root); + hostInfo->document_root = tmp; + hostInfo->doc_root_len = strlen(tmp); + break; + case SRM_DEFAULT_TYPE: + if (hostInfo->srm_conf & option) +! Free(hostInfo->default_type); + hostInfo->default_type = tmp; + break; + case SRM_DEFAULT_ICON: + if (hostInfo->srm_conf & option) +! Free(hostInfo->default_icon); + hostInfo->default_icon = tmp; + break; + } +diff -brc ./host_config.h /X11/blong/httpd/src//host_config.h +*** ./host_config.h Tue Jun 25 17:06:14 1996 +--- /X11/blong/httpd/src//host_config.h Wed Jun 12 17:45:11 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * host_config.h,v 1.9 1995/11/28 09:01:47 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: host_config.h,v 1.10 1996/06/12 21:52:15 acain Exp $ + * + ************************************************************************ + * +*************** +*** 45,58 **** + #define SRM_DEFAULT_ICON 32 + #define SRM_TRANSLATIONS 64 + #define SRM_DOCERRORS 128 +- +- /* PEM_CONF OPTS */ +- #define PEMC_PEM_ENCRYPT 1 +- #define PEMC_PEM_DECRYPT 2 +- #define PEMC_PEM_ENTITY 4 +- #define PEMC_PGP_ENCRYPT 8 +- #define PEMC_PGP_DECRYPT 16 +- #define PEMC_PGP_ENTITY 32 + + /* globals defined in this module */ + extern per_host *gConfiguration; +--- 45,50 ---- +Only in /X11/blong/httpd/src/: host_config.o +diff -brc ./http_access.c /X11/blong/httpd/src//http_access.c +*** ./http_access.c Tue Jun 25 17:06:14 1996 +--- /X11/blong/httpd/src//http_access.c Wed Jun 5 21:44:24 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_access.c,v 1.78 1996/04/05 18:54:49 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_access.c,v 1.81 1996/06/06 02:44:24 blong Exp $ + * + ************************************************************************ + * +*************** +*** 307,315 **** +--- 307,351 ---- + + if(sec[x].num_auth[reqInfo->method]) + *allow_options=x; ++ #ifdef SHTTP ++ if(sec[x].shttp_privacy_enhancements) ++ *other = x; ++ #endif /* SHTTP */ + + } + ++ int check_sym_link(per_request *reqInfo, char *file, char options, ++ char *errstr) ++ { ++ struct stat lfi,fi; ++ ++ if (lstat(file,&lfi) != 0) { ++ sprintf(errstr,"HTTPd: can't lstat %s, errno = %d",file, errno); ++ return 0; ++ } ++ /* 05-15-95 blong ++ * If not a directory? Shouldn't this be S_ISLNK? ++ */ ++ /* if (!(S_ISDIR(lfi.st_mode))) { */ ++ if (S_ISLNK(lfi.st_mode)) { ++ if (options & OPT_SYM_OWNER) { ++ if (stat(file,&fi) != 0) { ++ sprintf(errstr,"HTTPd: can't stat %s, errno = %d",file, errno); ++ return 0; ++ } ++ /* Check valid for OPT_SYM_OWNER (follow link if owner) */ ++ if (fi.st_uid != lfi.st_uid) { ++ sprintf(errstr,"HTTPd: link owner doesn't match for %s",file); ++ return 0; ++ } ++ } else { ++ sprintf(errstr,"HTTPd: will not follow link %s",file); ++ return 0; ++ } ++ } ++ return 1; ++ } ++ + void evaluate_access(per_request *reqInfo,struct stat *finfo,int *allow, + char *allow_options) + { +*************** +*** 333,340 **** +--- 369,378 ---- + + reqInfo->auth_user[0] = '\0'; + reqInfo->auth_group[0] = '\0'; ++ /* Clear .htaccess content type information from previous time*/ + reset_mime_vars(); + ++ /* Clear directory info structs */ + for(x=0;xbSatisfiedDomain = 0; + + n=num_dirs-1; + for(x=0;xbSatisfiedDomain = 0; + + n=num_dirs-1; ++ /* Go through the security information structure, and if its a match, add it ++ * to the current structures (opts, override) ++ */ + for(x=0;xouth_location,sec[x].on_deny[reqInfo->method]); + } + } +! if((override[n]) || (!(opts[n] & OPT_SYM_LINKS)) || + (opts[n] & OPT_SYM_OWNER)) { + for(x=0;xhostInfo->error_log); + *allow=FA_DENY; + *allow_options = OPT_NONE; + return; + } +- if(!(S_ISDIR(lfi.st_mode))) { +- if(opts[x] & OPT_SYM_OWNER) { +- if(stat(d,&fi) != 0) +- { +- sprintf(errstr,"HTTPd: can't stat %s, errno = %d",d, errno); +- log_error(errstr,reqInfo->hostInfo->error_log); +- *allow=FA_DENY; +- *allow_options = OPT_NONE; +- return; + } +! if(fi.st_uid != lfi.st_uid) +! goto bong; +! } +! else { +! bong: +! sprintf(errstr,"HTTPd: will not follow link %s",d); +! log_error(errstr,reqInfo->hostInfo->error_log); +! *allow=FA_DENY; +! *allow_options = OPT_NONE; +! return; +! } +! } +! } + if(override[x]) { + parse_htaccess(reqInfo,d,override[x]); + if(num_sec != y) { + for(z=count_dirs(sec[y].d) - 1;zmethod] > 0) || + (sec[y].num_allow[reqInfo->method] > 0) || + (sec[y].num_deny[reqInfo->method] > 0) || + (sec[y].num_referer_allow[reqInfo->method] > 0) || +! (sec[y].num_referer_deny[reqInfo->method] > 0)) + check_dir_access(reqInfo,y,&will_allow,&need_auth,&need_enhance); + if (!will_allow && sec[y].on_deny[reqInfo->method]) { + strcpy(reqInfo->outh_location, +--- 407,444 ---- + strcpy(reqInfo->outh_location,sec[x].on_deny[reqInfo->method]); + } + } +! /* Only check local information (ie, .htaccess) if override allowed on +! * final object, if sym links are not allowed, or if owned symlinks are +! */ +! if ((override[n]) || (!(opts[n] & OPT_SYM_LINKS)) || + (opts[n] & OPT_SYM_OWNER)) { + for(x=0;xhostInfo->error_log); + *allow=FA_DENY; + *allow_options = OPT_NONE; + return; + } + } +! /* If overrides allowed for this directory, read the .htaccess file */ + if(override[x]) { + parse_htaccess(reqInfo,d,override[x]); + if(num_sec != y) { ++ /* if any security info was added, add it to our info here */ + for(z=count_dirs(sec[y].d) - 1;zmethod] > 0) || + (sec[y].num_allow[reqInfo->method] > 0) || + (sec[y].num_deny[reqInfo->method] > 0) || + (sec[y].num_referer_allow[reqInfo->method] > 0) || +! (sec[y].num_referer_deny[reqInfo->method] > 0)) */ + check_dir_access(reqInfo,y,&will_allow,&need_auth,&need_enhance); + if (!will_allow && sec[y].on_deny[reqInfo->method]) { + strcpy(reqInfo->outh_location, +*************** +*** 428,472 **** + } + } + } + if((!(S_ISDIR(finfo->st_mode))) && + ((!(opts[n] & OPT_SYM_LINKS)) || (opts[n] & OPT_SYM_OWNER))) { +! struct stat fi,lfi; +! if(lstat(path,&fi)!=0) +! { +! sprintf(errstr,"HTTPd: can't lstat %s, errno = %d",path, errno); + log_error(errstr,reqInfo->hostInfo->error_log); + *allow=FA_DENY; + *allow_options = OPT_NONE; + return; + } +- if(!(S_ISREG(fi.st_mode))) { +- if(opts[n] & OPT_SYM_OWNER) { +- if(stat(path,&lfi)!=0) +- { +- sprintf(errstr,"HTTPd: can't stat %s, errno = %d",path, errno); +- log_error(errstr,reqInfo->hostInfo->error_log); +- *allow=FA_DENY; +- *allow_options = OPT_NONE; +- return; + } +! if(fi.st_uid != lfi.st_uid) +! goto gong; + } +! else { +! gong: +! sprintf(errstr,"HTTPd: will not follow link %s",path); +! log_error(errstr,reqInfo->hostInfo->error_log); +! *allow=FA_DENY; +! *allow_options = OPT_NONE; +! return; +! } +! } +! } + *allow = will_allow; + if(will_allow) { + *allow_options = opts[num_dirs-1]; + if ((need_auth >= 0) && (sec[need_auth].bSatisfy == SATISFY_ALL)) { + reqInfo->bSatisfiedDomain = 0; + check_auth(reqInfo,&sec[need_auth], reqInfo->inh_auth_line); + } + } else if ((need_auth >= 0) && (sec[need_auth].bSatisfy == SATISFY_ANY)) { +--- 448,482 ---- + } + } + } ++ /* If the requested object isn't a directory, then test it too */ + if((!(S_ISDIR(finfo->st_mode))) && + ((!(opts[n] & OPT_SYM_LINKS)) || (opts[n] & OPT_SYM_OWNER))) { +! if (!check_sym_link(reqInfo,path,opts[n],errstr)) { + log_error(errstr,reqInfo->hostInfo->error_log); + *allow=FA_DENY; + *allow_options = OPT_NONE; + return; + } + } +! #ifdef SHTTP +! /* This needs to be done first so rejection is processed with the right +! * options. +! */ +! if (sec[need_enhance].shttp_privacy_enhancements != NULL) { +! freeString(reqInfo->privacy_enhancements); +! reqInfo->privacy_enhancements = +! dupStringP(sec[need_enhance].shttp_privacy_enhancements,STR_REQ); + } +! #endif /* SHTTP */ + *allow = will_allow; + if(will_allow) { + *allow_options = opts[num_dirs-1]; + if ((need_auth >= 0) && (sec[need_auth].bSatisfy == SATISFY_ALL)) { + reqInfo->bSatisfiedDomain = 0; ++ /* ++ * Check authorization information: If this returns, everything ++ * is ok ++ */ + check_auth(reqInfo,&sec[need_auth], reqInfo->inh_auth_line); + } + } else if ((need_auth >= 0) && (sec[need_auth].bSatisfy == SATISFY_ANY)) { +*************** +*** 482,520 **** + register int x,y,m; + + for(x=0;xnum_aliases ; x++) { +! free(trans->aliases[x].fake); +! free(trans->aliases[x].real); + } +! free(trans->aliases); +! free(trans); + } + + void add_lookup(per_host *host, char *fake, char *real, int type) { +--- 39,49 ---- + int x; + + for (x=0; x < trans->num_aliases ; x++) { +! Free(trans->aliases[x].fake); +! Free(trans->aliases[x].real); + } +! Free(trans->aliases); +! Free(trans); + } + + void add_lookup(per_host *host, char *fake, char *real, int type) { +*************** +*** 50,57 **** + int n; + + if (translations == NULL) { +! translations = (lookup *) malloc(sizeof(lookup)); +! translations->aliases = (lookupRec *) malloc(TRANS_BEG_SIZE * + sizeof(lookupRec)); + translations->num_aliases = 0; + translations->max_aliases = TRANS_BEG_SIZE; +--- 51,58 ---- + int n; + + if (translations == NULL) { +! translations = (lookup *) Malloc(sizeof(lookup)); +! translations->aliases = (lookupRec *) Malloc(TRANS_BEG_SIZE * + sizeof(lookupRec)); + translations->num_aliases = 0; + translations->max_aliases = TRANS_BEG_SIZE; +diff -brc ./http_alias.h /X11/blong/httpd/src//http_alias.h +*** ./http_alias.h Tue Jun 25 17:06:15 1996 +--- /X11/blong/httpd/src//http_alias.h Wed Feb 14 17:46:08 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_alias.h,v 1.9 1995/11/28 09:01:52 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_alias.h,v 1.9 1995/11/28 09:01:52 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: http_alias.o +diff -brc ./http_auth.c /X11/blong/httpd/src//http_auth.c +*** ./http_auth.c Tue Jun 25 17:06:14 1996 +--- /X11/blong/httpd/src//http_auth.c Wed Jun 12 16:11:51 1996 +*************** +*** 31,36 **** +--- 31,37 ---- + #endif /* NO_MALLOC_H */ + #include + #include ++ #include + #include + #include + #include +*************** +*** 41,49 **** + # include + # endif /* _DBMSUPPORT_H */ + #endif /* DBM_SUPPORT */ +- #ifdef NIS_SUPPORT +- # include +- #endif /* NIS_SUPPORT */ + #if defined(KRB4) || defined(KRB5) + # define HAVE_KERBEROS + #endif /* defined(KRB4) || defined(KRB5) */ +--- 42,47 ---- +*************** +*** 54,59 **** +--- 52,61 ---- + # include + #endif /* KRB5 */ + #include "constants.h" ++ #ifdef SHTTP ++ # include ++ # include "http_shttp.h" ++ #endif /* SHTTP */ + #include "fdwrap.h" + #include "allocate.h" + #include "http_auth.h" +*************** +*** 64,107 **** + #include "http_request.h" + #include "util.h" + #include "digest.h" +- + #ifdef HAVE_KERBEROS +! #define T 1 +! #define NIL 0 +! char* index(); +! char krb_authreply[2048]; +! extern char *remote_logname; +! /* extern char out_auth_header[]; */ +! +! /* Table for converting binary values to and from hexadecimal */ +! static char hex[] = "0123456789abcdef"; +! static char dec[256] = { +! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */ +! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 37 */ +! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ' ' - '/' */ +! 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* '0' - '?' */ +! 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '@' - 'O' */ +! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'P' - '_' */ +! 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '`' - 'o' */ +! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'p' - DEL */ +! }; + #endif /* HAVE_KERBEROS */ + +! #ifdef KRB4 +! #define MAX_KDATA_LEN MAX_KTXT_LEN +! char k4_srvtab[MAX_STRING_LEN] = ""; +! static des_cblock session; /* Our session key */ +! static des_key_schedule schedule; /* Schedule for our session key */ +! AUTH_DAT kerb_kdata; +! #endif /* KRB4 */ + +- #ifdef KRB5 +- #ifndef MAX_KDATA_LEN +- #define MAX_KDATA_LEN 2048 +- #endif /* MAX_KDATA_LEN */ +- char k5_srvtab[MAX_STRING_LEN] = ""; +- #endif /* KRB5 */ +- + #ifdef RADIUS_AUTH + /* Experimental RADIUS authentication + */ +--- 66,80 ---- + #include "http_request.h" + #include "util.h" + #include "digest.h" + #ifdef HAVE_KERBEROS +! # include "http_kerberos.h" + #endif /* HAVE_KERBEROS */ ++ #ifdef NIS_SUPPORT ++ # include "http_nis.h" ++ #endif /* NIS_SUPPORT */ + +! #define DEBUG 1 + + #ifdef RADIUS_AUTH + /* Experimental RADIUS authentication + */ +*************** +*** 108,144 **** + int testpass (char * user, char * clear_pw, char * servername); + #endif /* RADIUS_AUTH */ + +! #ifdef NIS_SUPPORT +! int +! init_nis(char **dom) +! { +! static int init = 0; +! static char *domain; +! int yperr; +! +! if (init == 0) { +! yperr = yp_get_default_domain(&domain); +! if (yperr == 0) +! init++; +! } +! +! if (init) { +! *dom = domain; +! return 0; +! } +! return 1; +! } +! #endif /* NIS_SUPPORT */ +! + int get_pw(per_request *reqInfo, char *user, char *pw, security_data* sec) + { +! FILE *f; + char errstr[MAX_STRING_LEN]; +- char l[MAX_STRING_LEN]; + char w[MAX_STRING_LEN]; + struct stat finfo; +- +- if (reqInfo->auth_pwfile_type == AUTHFILETYPE_STANDARD) { + /* From Conrad Damon (damon@netserver.standford.edu), + Don't start cfg_getline loop if auth_pwfile is a directory. */ + +--- 81,99 ---- + int testpass (char * user, char * clear_pw, char * servername); + #endif /* RADIUS_AUTH */ + +! /* get_pw() +! * Returns 0 if failure, 1 if success +! * On success, returns password in *pw +! */ + int get_pw(per_request *reqInfo, char *user, char *pw, security_data* sec) + { +! +! if (reqInfo->auth_pwfile_type == AUTHFILETYPE_STANDARD) { + char errstr[MAX_STRING_LEN]; + char w[MAX_STRING_LEN]; ++ char l[MAX_STRING_LEN]; ++ FILE *f; + struct stat finfo; + /* From Conrad Damon (damon@netserver.standford.edu), + Don't start cfg_getline loop if auth_pwfile is a directory. */ + +*************** +*** 167,219 **** + } + #ifdef DBM_SUPPORT + else if(reqInfo->auth_pwfile_type == AUTHFILETYPE_DBM) { +! DBM* db; +! datum dtKey, dtRec; +! +! if(!(db = DBM_Open(reqInfo->auth_pwfile,O_RDONLY, 0))) { +! sprintf(errstr,"Could not open user file %s",reqInfo->auth_pwfile); +! die(reqInfo,SC_SERVER_ERROR,errstr); + } +- dtKey.dptr = user; +- dtKey.dsize = strlen(user); +- dtRec = dbm_fetch(db, dtKey); +- DBM_Close(db); +- if (dtRec.dptr) { +- strncpy(pw, dtRec.dptr, dtRec.dsize); +- pw[dtRec.dsize] = '\0'; +- return 1; +- } +- else +- return 0; +- } + #endif /* DBM_SUPPORT */ + #ifdef NIS_SUPPORT + else if (reqInfo->auth_pwfile_type == AUTHFILETYPE_NIS) { +! char *domain, +! *pwfile, +! *resptr; +! int yperr, +! resize; +! +! if (init_nis(&domain) != 0) +! return 0; +! +! if (strcmp(reqInfo->auth_pwfile, "+")) +! pwfile = reqInfo->auth_pwfile; +! else +! pwfile = "passwd.byname"; +! +! yperr = yp_match(domain, pwfile, user, strlen(user), &resptr, &resize); +! if (yperr == 0) { +! getword(w, resptr, ':'); +! if (strcmp(w, user) == 0) { +! getword(w, resptr, ':'); +! (void) strcpy(pw, w); +! return 1; + } +- } +- return 0; +- } + #endif /* NIS_SUPPORT */ + else + die(reqInfo,SC_SERVER_ERROR,"Invalid password file type"); +--- 122,134 ---- + } + #ifdef DBM_SUPPORT + else if(reqInfo->auth_pwfile_type == AUTHFILETYPE_DBM) { +! return dbm_get_pw(reqInfo,user,pw); + } + #endif /* DBM_SUPPORT */ + #ifdef NIS_SUPPORT + else if (reqInfo->auth_pwfile_type == AUTHFILETYPE_NIS) { +! return nis_get_pw(reqInfo,user,pw); + } + #endif /* NIS_SUPPORT */ + else + die(reqInfo,SC_SERVER_ERROR,"Invalid password file type"); +*************** +*** 275,319 **** + return Found; + } + +! /* nis_group_lookup() +! * Validate a user in an NIS group. Retrieves the group from an NIS database. +! * (Default group file is webgroup) +! * return 0 on failure, 1 on success +! */ +! #ifdef NIS_SUPPORT +! int nis_group_lookup(per_request *reqInfo, char *user, char *group) + { +! char *domain, +! *grfile, +! *resptr, +! w[MAX_STRING_LEN]; +! int yperr, +! resize; + +! if (init_nis(&domain) != 0) { +! log_error("HTTPd/NIS: init_nis() failed",reqInfo->hostInfo->error_log); +! return 0; + } +! +! if (strcmp(reqInfo->auth_grpfile, "+")) +! grfile = reqInfo->auth_grpfile; + else +- grfile = "webgroup"; +- +- yperr = yp_match(domain, grfile, group, strlen(group), &resptr, &resize); +- if (yperr != 0) { +- sprintf(w,"HTTPd/NIS: yp_match() failed, yperr = %d\n",yperr); +- log_error(w,reqInfo->hostInfo->error_log); + return 0; +- } +- +- getword(w, resptr, ':'); +- if (strcmp(w, group) != 0) +- return 0; +- +- return in_list(user,resptr); + } +- #endif /* NIS_SUPPORT */ + + /* dbm_group_lookup() + * Implicitly requires group line not to exceed HUGE_STRING_LEN because +--- 190,218 ---- + return Found; + } + +! #ifdef DBM_SUPPORT +! int dbm_get_pw(per_request *reqInfo, char *user, char *pw) + { +! DBM* db; +! datum dtKey, dtRec; +! char errstr[MAX_STRING_LEN]; + +! if(!(db = DBM_Open(reqInfo->auth_pwfile,O_RDONLY, 0))) { +! sprintf(errstr,"Could not open user file %s",reqInfo->auth_pwfile); +! die(reqInfo,SC_SERVER_ERROR,errstr); + } +! dtKey.dptr = user; +! dtKey.dsize = strlen(user); +! dtRec = dbm_fetch(db, dtKey); +! DBM_Close(db); +! if (dtRec.dptr) { +! strncpy(pw, dtRec.dptr, dtRec.dsize); +! pw[dtRec.dsize] = '\0'; +! return 1; +! } + else + return 0; + } + + /* dbm_group_lookup() + * Implicitly requires group line not to exceed HUGE_STRING_LEN because +*************** +*** 321,327 **** + * Searches open DBM database (db) for keypair with the group name as key + * and returns 0 if user or group not found, 1 if user is in group + */ +- #ifdef DBM_SUPPORT + int dbm_group_lookup(per_request *reqInfo, char *user, char *group, DBM *db) + { + datum dtKey, dtRec; +--- 220,225 ---- +*************** +*** 337,355 **** + } + #endif /* DBM_SUPPORT */ + +! int in_group(per_request *reqInfo, char *user, +! char *group, char* gfile_mem + #ifdef DBM_SUPPORT + , DBM* db + #endif /* DBM_SUPPORT */ + ) + { +- char *cur_group = NULL; +- char *cur_list = NULL; + int bFound = FALSE; + int Done = FALSE; + + if (reqInfo->auth_grpfile_type == AUTHFILETYPE_STANDARD) { + cur_group = strtok(gfile_mem,":"); + while (!Done && !bFound) { + cur_list = strtok(NULL,"\n"); +--- 235,275 ---- + } + #endif /* DBM_SUPPORT */ + +! int mind(char *S, char *possible) +! { +! int x,y; +! for (x = 0; S[x]; x++) +! for (y = 0; possible[y]; y++) +! if (S[x] == possible[y]) return x; +! return -1; +! } +! +! int eoln(char *S) +! { +! int x; +! for (x = 0; S[x]; x++) +! if (S[x] == '\n') return x; +! return x; +! } +! +! int in_group(per_request *reqInfo, char *user, char *group, char* gfile_mem + #ifdef DBM_SUPPORT + , DBM* db + #endif /* DBM_SUPPORT */ + ) + { + int bFound = FALSE; + int Done = FALSE; + ++ /* Currently broken because it mods the current group file in memory, ++ * so you can only allow access by one group ++ */ ++ + if (reqInfo->auth_grpfile_type == AUTHFILETYPE_STANDARD) { ++ /* ++ char *cur_group = NULL; ++ char *cur_list = NULL; ++ + cur_group = strtok(gfile_mem,":"); + while (!Done && !bFound) { + cur_list = strtok(NULL,"\n"); +*************** +*** 359,365 **** +--- 279,314 ---- + cur_group = strtok(NULL,":"); + if (cur_group == NULL) Done = TRUE; + } ++ */ ++ int beg_line = 0; ++ int end_line = 0; ++ int end_grp = 0; ++ int len = strlen(group); ++ while (!Done && !bFound) { ++ end_grp = ind(&gfile_mem[beg_line],':'); ++ if (end_grp != -1) { ++ end_line = ind(&gfile_mem[beg_line],'\n'); ++ if (end_line < 0) { ++ end_line = strlen(&gfile_mem[beg_line]); ++ Done = TRUE; + } ++ if (end_line > end_grp) { ++ if ((end_grp == len) && ++ (!strncmp(&gfile_mem[beg_line],group,len))) ++ { ++ bFound = in_listn(user,&gfile_mem[beg_line+end_grp+1],end_line - end_grp); ++ /* fprintf(stderr,"User: %s\tGroup: %s\n",user,group); ++ fputsn(stderr, */ ++ } ++ } else { ++ /* hmm, how to handle the backward compat with the bug in 1.5 which ++ * allowed a group to span multiple lines ++ */ ++ } ++ beg_line += end_line+1; ++ } else Done = TRUE; ++ } ++ } + #ifdef DBM_SUPPORT + else if (reqInfo->auth_grpfile_type == AUTHFILETYPE_DBM) { + bFound = dbm_group_lookup(reqInfo,user,group,db); +*************** +*** 452,457 **** +--- 401,412 ---- + die(reqInfo,SC_AUTH_REQUIRED,errstr); + } + #endif /* KRB5 */ ++ #ifdef SHTTP ++ if(!strncasecmp(auth_type,"SHTTP",5)) { ++ sprintf(errstr,"%s [SHTTP]",s); ++ die(reqInfo,SC_AUTH_NO_WWW_AUTH,errstr); ++ } ++ #endif /* SHTTP */ + else { + sprintf(errstr,"Unknown authorization method %s",auth_type); + die(reqInfo,SC_SERVER_ERROR,errstr); +*************** +*** 485,491 **** +--- 440,474 ---- + if(!sec->auth_type[0]) + strcpy(sec->auth_type, "Basic"); + ++ #ifdef SHTTP ++ /* S-HTTP message may not have Authorization line, but ++ * we still need to check for required S-HTTP enhancements ADC ZZZZ ++ */ + ++ if (!strncasecmp(sec->auth_type,"SHTTP",5)) { ++ list_el *tmp; ++ char *err = "Must use SHTTP protocol for this URL"; ++ ++ if (!(reqInfo->RequestFlags & DOING_SHTTP)) ++ auth_bong(reqInfo,err,reqInfo->auth_name, sec->auth_type); ++ ++ /* Now do our SHTTP checks... These don't fit into McCool's ++ * framework, so we'll do it ourselves ++ */ ++ tmp=TSW_ll_first(sec->shttp_auth_lines); ++ ++ if (!tmp) /* in case we Require SHTTP, but no SHTTPAuthAccept lines */ ++ return; ++ ++ while(tmp){ ++ if(!(err=shttp_check_auth(reqInfo,(char *)TSW_ll_data(tmp)))) ++ return; ++ tmp=TSW_ll_next(tmp); ++ } ++ auth_bong(reqInfo,err,reqInfo->auth_name,sec->auth_type); ++ } ++ #endif /* SHTTP */ ++ + /* No authorization info, so return the 401 to retrieve it */ + if(!auth_line[0]) + auth_bong(reqInfo,NULL, reqInfo->auth_name, sec->auth_type); +*************** +*** 512,518 **** + die(reqInfo,SC_SERVER_ERROR,errstr); + } + +! uudecode(auth_line + strlen(auth_type),(unsigned char *)ad,MAX_STRING_LEN); + getword(reqInfo->auth_user,ad,':'); + strcpy(sent_pw,ad); + if(!get_pw(reqInfo,reqInfo->auth_user,real_pw,sec)) { +--- 495,502 ---- + die(reqInfo,SC_SERVER_ERROR,errstr); + } + +! uudecode(auth_line + strlen(auth_type),(unsigned char *)ad, +! MAX_STRING_LEN); + getword(reqInfo->auth_user,ad,':'); + strcpy(sent_pw,ad); + if(!get_pw(reqInfo,reqInfo->auth_user,real_pw,sec)) { +*************** +*** 569,577 **** + + if (krbresult) { + if (check_krb_restrict(reqInfo, sec, &kdat)) { +! remote_logname = user; + sprintf(reqInfo->outh_www_auth,"%s %s", + sec->auth_type, krb_authreply); + return; + } + else { +--- 553,566 ---- + + if (krbresult) { + if (check_krb_restrict(reqInfo, sec, &kdat)) { +! remote_logname = reqInfo->auth_user; + sprintf(reqInfo->outh_www_auth,"%s %s", + sec->auth_type, krb_authreply); ++ /* we must set status line so that it is not considered ++ a 401 by send_http_headers ++ */ ++ set_stat_line(reqInfo); ++ + return; + } + else { +*************** +*** 588,593 **** +--- 577,599 ---- + } + } + #endif /* HAVE_KERBEROS */ ++ #ifdef SHTTP ++ /* I don't think SHTTP would ever get this far . . . */ ++ else if (!strncasecmp(sec->auth_type, "SHTTP",5)) { ++ list_el *tmp; ++ char *err; ++ ++ /* Now do our SHTTP checks... These don't fit into McCool's ++ * framework, so we'll do it ourselves*/ ++ tmp=TSW_ll_first(sec->shttp_auth_lines); ++ while(tmp){ ++ if(!(err=shttp_check_auth(reqInfo,(char *)TSW_ll_data(tmp)))) ++ return; ++ tmp=TSW_ll_next(tmp); ++ } ++ auth_bong(reqInfo,err,reqInfo->auth_name,sec->auth_type); ++ } ++ #endif /* SHTTP */ + else { + sprintf(errstr,"unknown authorization type %s for %s",sec->auth_type, + sec->d); +*************** +*** 609,623 **** +--- 615,634 ---- + #endif /* DBM_SUPPORT */ + } + ++ /* Check require lines */ + bValid = 0; + for(x=0;xnum_auth[reqInfo->method] && !bValid;x++) { + strcpy(t,sec->auth[reqInfo->method][x]); + getword(w,t,' '); + if(!strcmp(w,"valid-user")) { ++ /* We've already done a user lookup (successful), so if all that's ++ * required is a valid user, return valid ++ */ + bValid = 1; + } + else if(!strcmp(w,"user")) { + while(t[0]) { ++ /* Remove quotes? must be for backward compatibility? */ + if(t[0] == '\"') { + getword(w,&t[1],'\"'); + for(y=0;t[y];y++) +*************** +*** 669,1051 **** + } + } + +- #ifdef HAVE_KERBEROS +- +- /************************************************************************* +- * kdata_to_str -- convert 8-bit char array to ascii string +- * +- * Accepts: input array and length +- * Returns: a pointer to the result, or null pointer on malloc failure +- * The caller is responsible for freeing the returned value. +- * +- * Changed to accomodate general strings with length, due to conflict between +- * KTEXT and krb5_data types ( 6/28/95 ADC) +- ************************************************************************/ +- static char *kdata_to_str(in_data, length) +- char *in_data; /* char FAR ?? */ +- int length; +- { +- char *result, *p; +- int i; +- +- p = result = malloc(length*2+1); +- if (!result) return (char *) NULL; +- +- for (i=0; i < length; i++) { +- *p++ = hex[(in_data[i]>>4)&0xf]; +- *p++ = hex[(in_data[i])&0xf]; +- } +- *p++ = '\0'; +- return result; +- } +- +- +- /************************************************************************* +- * str_to_kdata -- Converts ascii string to a (binary) char array +- * +- * Accepts: string to convert +- * pointer to output array +- * Returns: length of output array, NIL on failure +- ************************************************************************/ +- int str_to_kdata(in_str, out_str) +- char *in_str; +- char *out_str; +- { +- int inlen, outlen; +- +- inlen = strlen(in_str); +- if (inlen & 1) return NIL; /* must be even number, in this scheme */ +- inlen /= 2; +- if (inlen > MAX_KDATA_LEN) return NIL; +- +- for (outlen=0; *in_str; outlen++, in_str += 2) { +- out_str[outlen] = (dec[in_str[0]]<<4) + dec[in_str[1]]; +- } +- return outlen; +- } +- +- /************************************************************************* +- * kerberos_server_auth -- Kerberos-authenticated server log in +- * Accepts: user name string +- * password string +- * pointer to char pointer. The char pointer is set to the +- * text we want returned in the reply message. +- * Returns: T if login ok, NIL otherwise +- ************************************************************************/ +- #ifdef KRB4 +- int k4_server_auth(char* authline, char* reply,FILE* error_log, +- KerberosInfo *kdat) +- { +- char pass[HUGE_STRING_LEN]; +- int code; +- KTEXT_ST authent; +- char instance[INST_SZ]; +- static AUTH_DAT kdata; +- char realm[REALM_SZ]; +- char local_realm[REALM_SZ]; +- char *p; +- +- getword(user, authline, ' '); +- getword(pass, authline, '\0'); +- +- +- /* Convert pass to authent */ +- if ((authent.length = str_to_kdata(pass, authent.dat)) == NIL) { +- strcpy(reply,"Invalid Kerberos authenticator"); +- return NIL; +- } +- +- /* Verify authenticator */ +- strcpy(instance, "*"); /* is this ok? */ +- if (k4_srvtab[0]) { +- code = krb_rd_req(&authent, "khttp", instance, 0L, &kdata, k4_srvtab); +- } +- else { +- code = krb_rd_req(&authent, "khttp", instance, 0L, &kdata, NULL); +- } +- +- if (code) { +- sprintf(reply, krb_err_txt[code]); +- log_error(reply,error_log); +- return NIL; +- } +- +- /* Check authorization of the Kerberos user */ +- if (strncmp(kdata.pname, user, ANAME_SZ)) { +- strcpy(reply, "Permission denied; name/username mismatch."); +- return NIL; +- } +- +- if (code = krb_get_lrealm(local_realm, 1)) { +- sprintf(reply, krb_err_txt[code]); +- log_error(reply, error_log); +- return NIL; +- } +- +- /* to perform further restriction through .htaccess in check_auth */ +- strcpy (kdat->client_name, kdata.pname); +- strcpy (kdat->client_realm, kdata.prealm); +- strcpy (kdat->server_realm, local_realm); +- kdat->ver = KERBEROSV4; +- +- /* gacck: compat. with older kerb code */ +- memcpy(&kerb_kdata, &kdata, sizeof(kdata)); +- +- /* Save the session key */ +- bcopy(kdata.session, session, sizeof(des_cblock)); +- key_sched(session, schedule); +- +- /* Construct the response for mutual authentication */ +- authent.length = sizeof(des_cblock); +- bzero(authent.dat, sizeof(des_cblock)); +- *((long *)authent.dat) = htonl(kdata.checksum + 1); +- des_ecb_encrypt(authent.dat, authent.dat, schedule, 1); +- +- /* Convert response to string and place in buffer */ +- p = kdata_to_str(&authent.dat, authent.length); +- +- if (p) { +- *reply = '['; +- strcpy(reply+1, p); +- strcat(reply, "] User "); +- strcat(reply, user); +- strcat(reply, " authenticated"); +- free(p); +- } +- else { +- /* XXX Out of memory */ +- exit(1); +- } +- +- strncpy(user, user, MAX_STRING_LEN - 1); +- return T; +- } +- #endif /* KRB4 */ +- /**********************************************************************/ +- #ifdef KRB5 +- int k5_server_auth(char* authline, char* reply, KerberosInfo *kdat) +- { +- char pass[HUGE_STRING_LEN]; +- char tmpstr[MAX_KDATA_LEN]; +- char *p; +- +- krb5_context k5context; +- krb5_auth_context *k5auth_context = NULL; +- krb5_principal serverp, clientp; +- krb5_data k5authent; +- krb5_ticket *k5ticket = NULL; +- krb5_error_code code; +- krb5_keytab k5keytabid = NULL; +- krb5_data k5ap_rep_data; +- +- +- getword(user, authline, ' '); +- getword(pass, authline, '\0'); +- +- /* Convert pass to authent */ +- if ((k5authent.length = str_to_kdata(pass, tmpstr)) == NIL) { +- sprintf(reply, "Invalid authenticator"); +- return NIL; +- } +- k5authent.data = tmpstr; +- +- code = krb5_init_context(&k5context); +- if (code) { +- sprintf(reply, "krb5_init_context error: %s",error_message(code)); +- return NIL; +- } +- +- krb5_init_ets(k5context); +- +- /* find server principal name; NULL means krb libs determine my hostname */ +- +- code = krb5_sname_to_principal(k5context, NULL, "khttp", KRB5_NT_SRV_HST, +- &serverp); +- if (code) { +- sprintf(reply, "Error finding server Krb5 principal name: %s",error_message(code)); +- return NIL; +- } +- +- /* perhaps get client address? (using getpeername) */ +- +- +- /* Check for user-specified keytab */ +- +- if (k5_srvtab[0]) { +- code = krb5_kt_resolve(k5context, k5_srvtab, &k5keytabid); +- if (code) { +- sprintf(reply, "Error resolving keytab file: %s",error_message(code)); +- return NIL; +- } +- } +- +- /* and most importantly, check the client's authenticator */ +- +- code = krb5_rd_req(k5context, &k5auth_context, &k5authent, +- serverp, k5keytabid, NULL, &k5ticket); +- if (code) { +- sprintf(reply, "krb5_rd_req error: %s",error_message(code)); +- return NIL; +- } +- +- clientp = k5ticket->enc_part2->client; +- +- /* to perform further restriction through .htaccess in check_auth */ +- +- strncpy (kdat->client_name, clientp->data->data,clientp->data->length); +- strcpy (kdat->client_realm, clientp->realm.data); +- strcpy (kdat->server_realm, serverp->realm.data); +- kdat->ver = KERBEROSV5; +- +- /* make sure client username matches username submitted in Auth line */ +- +- /* removed for now; redundant and possibly buggy ADC +- if (strncmp(kdat->client_name, user, MAX_STRING_LEN)) { +- strcpy(reply, "Permission denied; name/username mismatch."); +- return NIL; +- } +- */ +- /* send an AP_REP message to complete mutual authentication */ +- +- code = krb5_mk_rep(k5context, k5auth_context, &k5ap_rep_data); +- +- if (code) { +- sprintf(reply, "krb5_mk_rep error: %s",error_message(code)); +- return NIL; +- } +- +- /* Convert response to string and place in buffer */ +- p = kdata_to_str(k5ap_rep_data.data, k5ap_rep_data.length); +- +- if (p) { +- *reply = '['; +- strcpy(reply+1, p); +- strcat(reply, "] User "); +- strcat(reply, user); +- strcat(reply, " authenticated"); +- free(p); +- } +- else { +- /* XXX Out of memory */ +- exit(1); +- } +- +- /* call any krb5_free routines?? perhaps krb_free_ticked(k5ticket) ? */ +- +- strncpy(user, user, MAX_STRING_LEN - 1); +- return T; +- } +- #endif /* KRB5 */ +- +- int check_krb_restrict(per_request* reqInfo, security_data* sec, KerberosInfo* kdat) +- { +- int grpstatus; +- char* pchGrpData = NULL; +- int ndx; +- int bValid; +- char line[MAX_STRING_LEN]; +- char errstr[MAX_STRING_LEN]; +- char* realm; +- char* tok; +- +- /* Common stuff: Check for valid user */ +- grpstatus = 0; +- if(reqInfo->auth_grpfile) { +- if (pchGrpData = init_group(reqInfo,reqInfo->auth_grpfile)) +- grpstatus = 1; +- } +- +- bValid = 0; +- for(ndx=0;ndxnum_auth[reqInfo->method] && !bValid;ndx++) { +- strcpy(line,sec->auth[reqInfo->method][ndx]); +- tok = strtok (line, " \t"); +- if(!strcmp(tok,"valid-user")) +- bValid = 1; +- else if(!strcmp(tok,"user")) { +- while(tok = strtok (NULL, " \t")) { +- if (realm = strchr (tok, '@')) +- *realm++ = '\0'; +- +- if(!strcmp(kdat->client_name,tok)) { +- if (!realm && +- !strcasecmp(kdat->server_realm, kdat->client_realm)) { +- bValid = 1; +- break; +- } +- else if (realm && !strcasecmp(realm, kdat->client_realm)) { +- bValid = 1; +- break; +- } +- } +- } +- } +- else if(!strcmp(tok,"realm")) { +- while(tok = strtok (NULL, " \t")) { +- if(!strcasecmp(kdat->client_realm,tok)) { +- bValid = 1; +- break; +- } +- } +- } +- else if(!strcmp(tok,"group")) { +- if(!grpstatus) { +- sprintf(errstr,"group required for %s, bad groupfile", +- sec->d); +- auth_bong(reqInfo,errstr,reqInfo->auth_name,sec->auth_type); +- } +- while(tok = strtok (NULL, " \t")) { +- if (krb_in_group(kdat, tok, pchGrpData)) { +- strcpy(groupname,tok); +- bValid = 1; +- break; +- } +- } +- } +- else +- auth_bong(reqInfo,"require not followed by user or group", +- reqInfo->auth_name,sec->auth_type); +- } +- +- if(grpstatus) +- free (pchGrpData); +- +- return bValid; +- } +- +- int krb_in_group(KerberosInfo* kdat, char *group, char* pchGrps) +- { +- char *mems, *endp = NULL; +- char *pch; +- char chSaved; +- int nlen, bFound = 0; +- +- nlen = strlen (group); +- if ((mems = strstr (pchGrps, group)) && *(mems + nlen) == ':') { +- if (endp = strchr (mems + nlen + 1, ':')) { +- while (!isspace(*endp)) endp--; +- chSaved = *endp; +- *endp = '\0'; +- } +- } +- else +- return 0; +- +- nlen = strlen (kdat->client_name); +- if(pch = strstr(mems, kdat->client_name)) { +- pch += nlen; +- if (!*pch || isspace(*pch) && +- !strcasecmp(kdat->client_realm, kdat->server_realm)) +- bFound = 1; +- else if (*pch == '@') { +- pch++; +- nlen = strlen (kdat->client_realm); +- if (!strncmp (kdat->client_realm, pch, nlen)) +- bFound = 1; +- } +- } +- +- if (endp && *endp == '\0') *endp = chSaved; +- return bFound; +- } +- +- #endif /* HAVE_KERBEROS */ +--- 680,682 ---- +diff -brc ./http_auth.h /X11/blong/httpd/src//http_auth.h +*** ./http_auth.h Tue Jun 25 17:06:15 1996 +--- /X11/blong/httpd/src//http_auth.h Wed Jun 12 17:51:29 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_auth.h,v 1.22 1996/03/27 20:43:57 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_auth.h,v 1.26 1996/06/12 22:51:29 blong Exp $ + * + ************************************************************************ + * +*************** +*** 25,42 **** + # include + # endif /* _DBMSUPPORT_H */ + #endif /* DBM_SUPPORT */ +- #include "global.h" + + /* globals defined in this module */ + +- +- +- /* http_auth */ + void check_auth(per_request *reqInfo, security_data *s, char* auth_line); + int get_pw(per_request *reqInfo, char *user, char *pw, security_data* sec); + #ifdef DBM_SUPPORT + int in_group(per_request *reqInfo, char *user, char *group, char* pchGrps, + DBM* db); + #else + int in_group(per_request *reqInfo, char *user, char *group, char* pchGrps); + #endif /* DBM_SUPPORT */ +--- 25,39 ---- + # include + # endif /* _DBMSUPPORT_H */ + #endif /* DBM_SUPPORT */ + + /* globals defined in this module */ + + void check_auth(per_request *reqInfo, security_data *s, char* auth_line); + int get_pw(per_request *reqInfo, char *user, char *pw, security_data* sec); + #ifdef DBM_SUPPORT + int in_group(per_request *reqInfo, char *user, char *group, char* pchGrps, + DBM* db); ++ int dbm_get_pw(per_request *reqInfo, char *user, char *pw); + #else + int in_group(per_request *reqInfo, char *user, char *group, char* pchGrps); + #endif /* DBM_SUPPORT */ +*************** +*** 43,72 **** + char* init_group(per_request *reqInfo,char* grpfile); + void auth_bong(per_request *reqInfo,char *s,char* auth_name, char* auth_type); + +! #if defined(KRB4) || defined(KRB5) +! typedef struct _krbdata { +! char client_name[MAX_STRING_LEN]; +! char client_realm[MAX_STRING_LEN]; +! char server_realm[MAX_STRING_LEN]; +! int ver; +! } KerberosInfo; +! +! #define KERBEROSV4 0 +! #define KERBEROSV5 1 +! +! int check_krb_restrict(per_request* reqInfo, security_data* sec, KerberosInfo* kdat); +! int krb_in_group(KerberosInfo* kdat, char *group, char* pchGrps); +! #endif /* KRB4 or KRB5 */ +! +! #ifdef KRB4 +! extern char k4_srvtab[]; +! int k4_server_auth(char* authline, char* reply,FILE* error_log, +! KerberosInfo *kdat); +! #endif /* KRB4 */ +! +! #ifdef KRB5 +! extern char k5_srvtab[]; +! int k5_server_auth(char* authline, char* reply, KerberosInfo *kdat); +! #endif /* KRB5 */ +! + #endif /* _HTTP_AUTH_H_ */ +--- 40,45 ---- + char* init_group(per_request *reqInfo,char* grpfile); + void auth_bong(per_request *reqInfo,char *s,char* auth_name, char* auth_type); + +! int in_list(char *user, char *list); +! int in_listn(char *user, char *list, int len); + #endif /* _HTTP_AUTH_H_ */ +Only in /X11/blong/httpd/src/: http_auth.o +diff -brc ./http_config.c /X11/blong/httpd/src//http_config.c +*** ./http_config.c Tue Jun 25 17:06:15 1996 +--- /X11/blong/httpd/src//http_config.c Wed Jun 12 16:11:52 1996 +*************** +*** 31,41 **** +--- 31,48 ---- + # endif /* NEED_SYS_MALLOC_H */ + #endif /* NO_MALLOC_H */ + #include ++ #include + #include + #include + #include ++ #include ++ #include + #include + #include "constants.h" ++ #ifdef SHTTP ++ # include ++ # include "http_shttp.h" ++ #endif /* SHTTP */ + #include "fdwrap.h" + #include "http_config.h" + #include "host_config.h" +*************** +*** 45,52 **** + #include "http_log.h" + #include "http_dir.h" + #include "util.h" +! #include +! #include + + + /* Server config globals */ +--- 52,63 ---- + #include "http_log.h" + #include "http_dir.h" + #include "util.h" +! #ifdef FCGI_SUPPORT +! # include "fcgi.h" /* for AppClassCmd() */ +! #endif /* FCGI_SUPPORT */ +! #ifdef SSL_SUPPORT +! # include "http_ssl.h" +! #endif /* SSL_SUPPORT */ + + + /* Server config globals */ +*************** +*** 69,74 **** +--- 80,92 ---- + char local_default_icon[MAX_STRING_LEN]; + int log_directory_group_write_ok = 0; + int log_directory_other_write_ok = 0; ++ #ifdef LOG_TIMES ++ unsigned long clk_ticks; ++ #endif /* LOG_TIMES */ ++ #ifdef SHTTP ++ char *shttp_server_dns = NULL; ++ char *shttp_cert_db = NULL; ++ #endif /* SHTTP */ + + /* Access Globals*/ + int num_sec; +*************** +*** 103,108 **** +--- 121,131 ---- + char tmp[MAX_STRING_LEN]; + + standalone = 1; ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled == TRUE) ++ port = DEFAULT_SSL_PORT; ++ else ++ #endif /* SSL_SUPPORT */ + port = DEFAULT_PORT; + user_id = uname2id(DEFAULT_USER); + group_id = gname2id(DEFAULT_GROUP); +*************** +*** 224,229 **** +--- 247,266 ---- + cfg_getword(w,l); + port = atoi(w); + } ++ #ifdef SSL_SUPPORT ++ else if(!strcasecmp(w,"SSLPort") && !virtual) { ++ cfg_getword(w,l); ++ if (ssl_enabled) port = atoi(w); ++ } ++ else if(!strcasecmp(w,"SSLeayCert") && !virtual) { ++ cfg_getword(w,l); ++ if (ssl_enabled) my_ssl_cert_file = strdup(w); ++ } ++ else if(!strcasecmp(w,"SSLeayKey") && !virtual) { ++ cfg_getword(w,l); ++ if (ssl_enabled) my_ssl_key_file = strdup(w); ++ } ++ #endif /* SSL_SUPPORT */ + else if(!strcasecmp(w,"BindAddress") && !virtual) { + struct hostent *hep; + unsigned long ina; +*************** +*** 355,369 **** + if (!strcasecmp(w,"Combined")) { + set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); + host->log_opts |= LOG_COMBINED; +! } else if (!strcasecmp(w,"Separate")) { + set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); + host->log_opts &= LOG_SEPARATE; +! } else if (!strcasecmp(w,"ServerName")) { + set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); + host->log_opts |= LOG_SERVERNAME; +! } else if (!strcasecmp(w,"Date")) { + set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); + host->log_opts |= LOG_DATE; + } else { + config_error("Valid LogOptions are Combined or Separate, ServerName", + server_confname,n,errors); +--- 392,427 ---- + if (!strcasecmp(w,"Combined")) { + set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); + host->log_opts |= LOG_COMBINED; +! } +! else if (!strcasecmp(w,"Separate")) { + set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); + host->log_opts &= LOG_SEPARATE; +! } +! else if (!strcasecmp(w,"ServerName")) { + set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); + host->log_opts |= LOG_SERVERNAME; +! } +! else if (!strcasecmp(w,"Date")) { + set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); + host->log_opts |= LOG_DATE; ++ } ++ #ifdef LOG_TIMES ++ else if (!strcasecmp(w,"RealTime")) { ++ set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); ++ host->log_opts |= LOG_REALTIME; ++ } ++ else if (!strcasecmp(w,"CPUTime")) { ++ set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); ++ host->log_opts |= LOG_CPUTIME; ++ } ++ #endif /* LOG_TIMES */ ++ else if (!strcasecmp(w,"Referer")) { ++ set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); ++ host->log_opts |= LOG_REFERER; ++ } ++ else if (!strcasecmp(w,"UserAgent")) { ++ set_host_conf_value(host,PH_HTTPD_CONF,HC_LOG_TYPE); ++ host->log_opts |= LOG_USERAGENT; + } else { + config_error("Valid LogOptions are Combined or Separate, ServerName", + server_confname,n,errors); +*************** +*** 456,461 **** +--- 514,527 ---- + */ + } + #endif /* DIGEST_AUTH */ ++ #ifdef SHTTP ++ else if(!strcasecmp(w,"SHTTPDistinguishedNamedb")) { ++ shttp_server_dns = strdup(TSW_trimbuf(l)); ++ } ++ else if(!strcasecmp(w,"SHTTPCertdb")) { ++ shttp_cert_db = strdup(TSW_trimbuf(l)); ++ } ++ #endif /* SHTTP */ + else if(((!strcasecmp(w,"srm_confname, n, errors); + } +! #endif /* FCGI */ + else if(!strcasecmp(w,"UserDir")) { + cfg_getword(w,l); + if(!strcmp(w,"DISABLED")) +--- 642,649 ---- + if (result) + config_error(result, host->srm_confname, n, errors); + } +! #endif /* FCGI_SUPPORT */ +! + else if(!strcasecmp(w,"UserDir")) { + cfg_getword(w,l); + if(!strcmp(w,"DISABLED")) +*************** +*** 842,847 **** +--- 909,918 ---- + #ifdef DIGEST_AUTH + sec[x].auth_digestfile[0] = '\0'; + #endif /* DIGEST_AUTH */ ++ #ifdef SHTTP ++ sec[x].shttp_auth_lines = NULL; ++ sec[x].shttp_privacy_enhancements = NULL; ++ #endif /* SHTTP */ + sec[x].auth_grpfile[0] = '\0'; + for(i=0;iapply_to) free(p->apply_to); +! if(p->apply_path) free(p->apply_path); +! if(p->data) free(p->data); + q = p; + p = p->next; +! free(q); + } + } + +--- 79,90 ---- + struct item *q; + + while(p) { +! if(p->apply_to) Free(p->apply_to); +! if(p->apply_path) Free(p->apply_path); +! if(p->data) Free(p->data); + q = p; + p = p->next; +! Free(q); + } + } + +*************** +*** 114,120 **** + char *to, char *path, char *data) { + struct item *p; + +! if(!(p = (struct item *)malloc(sizeof(struct item)))) + die(reqInfo,SC_NO_MEMORY,"new_item"); + + p->type = type; +--- 114,120 ---- + char *to, char *path, char *data) { + struct item *p; + +! if(!(p = (struct item *)Malloc(sizeof(struct item)))) + die(reqInfo,SC_NO_MEMORY,"new_item"); + + p->type = type; +*************** +*** 125,131 **** + p->data = NULL; + + if(to) { +! if(!(p->apply_to = (char *)malloc(strlen(to) + 2))) + die(reqInfo,SC_NO_MEMORY,"new_item"); + if((type == BY_PATH) && (!is_matchexp(to))) { + p->apply_to[0] = '*'; +--- 125,131 ---- + p->data = NULL; + + if(to) { +! if(!(p->apply_to = (char *)Malloc(strlen(to) + 2))) + die(reqInfo,SC_NO_MEMORY,"new_item"); + if((type == BY_PATH) && (!is_matchexp(to))) { + p->apply_to[0] = '*'; +*************** +*** 135,141 **** + } else + p->apply_to = NULL; + +! if(!(p->apply_path = (char *)malloc(strlen(path) + 2))) + die(reqInfo,SC_NO_MEMORY,"new_item"); + sprintf(p->apply_path,"%s*",path); + +--- 135,141 ---- + } else + p->apply_to = NULL; + +! if(!(p->apply_path = (char *)Malloc(strlen(path) + 2))) + die(reqInfo,SC_NO_MEMORY,"new_item"); + sprintf(p->apply_path,"%s*",path); + +*************** +*** 443,451 **** + if(ignore_entry(t)) + return(NULL); + +! if(!(p=(struct ent *)malloc(sizeof(struct ent)))) + die(reqInfo,SC_NO_MEMORY,"make_dir_entry"); +! if(!(p->name=(char *)malloc(strlen(name) + 2))) + die(reqInfo,SC_NO_MEMORY,"make_dir_entry"); + + if(dir_opts & FANCY_INDEXING) { +--- 443,451 ---- + if(ignore_entry(t)) + return(NULL); + +! if(!(p=(struct ent *)Malloc(sizeof(struct ent)))) + die(reqInfo,SC_NO_MEMORY,"make_dir_entry"); +! if(!(p->name=(char *)Malloc(strlen(name) + 2))) + die(reqInfo,SC_NO_MEMORY,"make_dir_entry"); + + if(dir_opts & FANCY_INDEXING) { +*************** +*** 464,474 **** + p->alt = NULL; + p->desc = NULL; + if(S_ISDIR(finfo.st_mode)) { +! if(!(p->icon = find_icon(reqInfo,t,1))) +! if (p->icon != NULL) free(p->icon); + p->icon = find_icon(reqInfo,"^^DIRECTORY^^",1); + if(!(tmp = find_alt(reqInfo,t,1))){ +! p->alt = (char *) malloc(sizeof(char)*4); + strcpy(p->alt,"DIR"); + } + else { +--- 464,475 ---- + p->alt = NULL; + p->desc = NULL; + if(S_ISDIR(finfo.st_mode)) { +! if(!(p->icon = find_icon(reqInfo,t,1))) { +! if (p->icon != NULL) Free(p->icon); + p->icon = find_icon(reqInfo,"^^DIRECTORY^^",1); ++ } + if(!(tmp = find_alt(reqInfo,t,1))){ +! p->alt = (char *) Malloc(sizeof(char)*4); + strcpy(p->alt,"DIR"); + } + else { +*************** +*** 714,720 **** + num_ent++; + } + } +! if(!(ar=(struct ent **) malloc(num_ent*sizeof(struct ent *)))) { + Closedir(d); + die(reqInfo,SC_NO_MEMORY,"index_directory"); + } +--- 715,721 ---- + num_ent++; + } + } +! if(!(ar=(struct ent **) Malloc(num_ent*sizeof(struct ent *)))) { + Closedir(d); + die(reqInfo,SC_NO_MEMORY,"index_directory"); + } +*************** +*** 732,747 **** + (int (*)(const void *,const void *))dsortf); + #endif /* ULTRIX_BRAIN_DEATH */ + output_directories(reqInfo,ar,num_ent,reqInfo->url); +! free(ar); + q = head; + while(q) { + p=q->next; +! free(q->name); + if(q->desc) +! free(q->desc); + if(q->alt) +! free(q->alt); +! free(q); + q=p; + } + Closedir(d); +--- 733,748 ---- + (int (*)(const void *,const void *))dsortf); + #endif /* ULTRIX_BRAIN_DEATH */ + output_directories(reqInfo,ar,num_ent,reqInfo->url); +! Free(ar); + q = head; + while(q) { + p=q->next; +! Free(q->name); + if(q->desc) +! Free(q->desc); + if(q->alt) +! Free(q->alt); +! Free(q); + q=p; + } + Closedir(d); +diff -brc ./http_dir.h /X11/blong/httpd/src//http_dir.h +*** ./http_dir.h Tue Jun 25 17:06:16 1996 +--- /X11/blong/httpd/src//http_dir.h Tue Nov 28 03:02:01 1995 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_dir.h,v 1.6 1995/11/28 09:02:01 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_dir.h,v 1.6 1995/11/28 09:02:01 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: http_dir.o +diff -brc ./http_include.c /X11/blong/httpd/src//http_include.c +*** ./http_include.c Tue Jun 25 17:06:16 1996 +--- /X11/blong/httpd/src//http_include.c Wed Jun 12 16:11:52 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_include.c,v 1.50 1996/03/27 20:44:02 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_include.c,v 1.52 1996/06/12 20:35:28 acain Exp $ + * + ************************************************************************ + * +*************** +*** 29,34 **** +--- 29,35 ---- + # include + #endif /* NO_STDLIB_H */ + #include ++ #include + #include + #include + #include +*************** +*** 37,42 **** +--- 38,47 ---- + #include + #include + #include "constants.h" ++ #ifdef SHTTP ++ # include ++ # include "http_shttp.h" ++ #endif /* SHTTP */ + #include "fdwrap.h" + #include "allocate.h" + #include "http_include.h" +*************** +*** 89,99 **** + make_env_str(reqInfo,"DOCUMENT_URI",reqInfo->url); + } + +- + freeString(uri); + return TRUE; + } + + #define GET_CHAR(f,c,r) \ + { \ + int i = getc(f); \ +--- 94,105 ---- + make_env_str(reqInfo,"DOCUMENT_URI",reqInfo->url); + } + + freeString(uri); + return TRUE; + } + ++ /* --------------------------- Parser functions --------------------------- */ ++ + #define GET_CHAR(f,c,r) \ + { \ + int i = getc(f); \ +*************** +*** 103,133 **** + c = (char)i; \ + } + +! /* --------------------------- Parser functions --------------------------- */ +! +! int find_string(per_request *reqInfo, FILE *fp, char *str) { + int x,l=strlen(str),p; + char c; + + p=0; + while(1) { +! GET_CHAR(fp,c,1); + if(c == str[p]) { +! if((++p) == l) + return 0; + } + else { + if(reqInfo->out) { + if(p) { + for(x=0;xout) { + if(p) { + for(x=0;xenv[x] != NULL; x++) { +! i = ind(reqInfo->env[x],'='); +! if((i == len) && !(strncmp(reqInfo->env[x],tag_val,i))) { +! rprintf(reqInfo,"%s",&(reqInfo->env[x][i+1])); +! break; +! } +! } +! if(!(reqInfo->env[x])) + rprintf(reqInfo,"(none)"); + } + #ifndef NO_YOW +--- 388,398 ---- + return 1; + } + if(!strcmp(tag,"var")) { +! char *val = return_env_value(reqInfo,tag_val); + +! if (val != NULL) +! rprintf(reqInfo,"%s",val); +! else + rprintf(reqInfo,"(none)"); + } + #ifndef NO_YOW +*************** +*** 578,584 **** + strcpy(error,tag_val); + else if(!strcmp(tag,"timefmt")) { + strcpy(tf,tag_val); +! /* Replace DATE* and LAST_MODIFIED (they should be first) */ + replace_env_str(reqInfo, "DATE_LOCAL", ht_time(date,tf,0)); + replace_env_str(reqInfo, "DATE_GMT", ht_time(date,tf,1)); + replace_env_str(reqInfo, "LAST_MODIFIED", ht_time(lm,tf,0)); +--- 598,604 ---- + strcpy(error,tag_val); + else if(!strcmp(tag,"timefmt")) { + strcpy(tf,tag_val); +! /* Replace DATE* and LAST_MODIFIED */ + replace_env_str(reqInfo, "DATE_LOCAL", ht_time(date,tf,0)); + replace_env_str(reqInfo, "DATE_GMT", ht_time(date,tf,1)); + replace_env_str(reqInfo, "LAST_MODIFIED", ht_time(lm,tf,0)); +*************** +*** 772,778 **** +--- 792,898 ---- + } + } + ++ #ifdef SHTTP + ++ int handle_certs(per_request *reqInfo, FILE *fp, char *error) { ++ extern int tsw_null_func(); ++ char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN]; ++ char *tag_val; ++ ++ while(1) { ++ char *outch; ++ ++ if(!(tag_val = get_tag(fp,tag))) ++ return 1; ++ if(!strcmp(tag,"name")) { ++ if(TSW_export_cert_el(&shttp_ctx,&outch,tag_val,0,tsw_null_func)) { ++ sprintf(errstr,"unable to find cert %s in parsed file %s", ++ tag_val, reqInfo->filename); ++ log_error(errstr,reqInfo->hostInfo->error_log); ++ rprintf(reqInfo,"%s",error); ++ } ++ else { ++ rprintf(reqInfo,"%s",outch); ++ Free(outch); ++ } ++ } ++ else if(!strcmp(tag,"done")) ++ return 0; ++ else { ++ sprintf(errstr,"unknown parameter %s to tag certs in %s",tag); ++ log_error(errstr,reqInfo->hostInfo->error_log); ++ rprintf(reqInfo,"%s",error); ++ } ++ } ++ } ++ ++ int handle_dn(per_request *reqInfo, FILE *fp, char *error) { ++ extern int tsw_null_func(); ++ char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN]; ++ char *tag_val; ++ ++ while(1) { ++ if(!(tag_val = get_tag(fp,tag))) ++ return 1; ++ if(!strcmp(tag,"name")) { ++ char *outch; ++ ++ if(TSW_export_dn(&shttp_ctx,&outch,tag_val)) { ++ sprintf(errstr,"unable to find DN %s in parsed file %s", ++ tag_val, reqInfo->filename); ++ log_error(errstr,reqInfo->hostInfo->error_log); ++ rprintf(reqInfo,"%s",error); ++ } ++ else { ++ rprintf(reqInfo,"%s",outch); ++ Free(outch); ++ } ++ } ++ else if(!strcmp(tag,"done")) ++ return 0; ++ else { ++ sprintf(errstr,"unknown parameter %s to tag DN in %s",tag, ++ reqInfo->filename); ++ log_error(errstr,reqInfo->hostInfo->error_log); ++ rprintf(reqInfo,"%s",error); ++ } ++ } ++ } ++ ++ int handle_skey(per_request *reqInfo, FILE *fp, char *error) { ++ char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN]; ++ char *tag_val; ++ ++ while(1) { ++ if(!(tag_val = get_tag(fp,tag))) ++ return 1; ++ if(!strcmp(tag,"alg")) { ++ char *outch; ++ ++ if(TSW_make_skey(&shttp_ctx,tag_val,&outch)) { ++ sprintf(errstr,"unable to make server key (alg %s) in parsed file %s", ++ tag_val, reqInfo->filename); ++ log_error(errstr,reqInfo->hostInfo->error_log); ++ rprintf(reqInfo,"%s",error); ++ } ++ else { ++ rprintf(reqInfo,"%s",outch); ++ Free(outch); ++ } ++ } ++ else if(!strcmp(tag,"done")) ++ return 0; ++ else { ++ sprintf(errstr,"unknown parameter %s to tag s-key in %s",tag, ++ reqInfo->filename); ++ log_error(errstr,reqInfo->hostInfo->error_log); ++ rprintf(reqInfo,"%s",error); ++ } ++ } ++ } ++ #endif /* SHTTP */ ++ ++ + /* -------------------------- The main function --------------------------- */ + + /* This is a stub which parses a file descriptor. */ +*************** +*** 822,827 **** +--- 942,955 ---- + ret=handle_fsize(reqInfo,fp,error,sizefmt); + else if(!strcmp(directive,"flastmod")) + ret=handle_flastmod(reqInfo,fp,error,timefmt); ++ #ifdef SHTTP ++ else if(!strcmp(directive,"certs")) ++ ret=handle_certs(reqInfo,fp,error); ++ else if(!strcmp(directive,"s-key")) ++ ret=handle_skey(reqInfo,fp,error); ++ else if(!strcmp(directive,"dn")) ++ ret=handle_dn(reqInfo,fp,error); ++ #endif /* SHTTP */ + #ifndef NO_YOW + else if(!strcmp(directive,"yow")) + ret=handle_yow(reqInfo,fp,error); +*************** +*** 882,886 **** +--- 1010,1015 ---- + add_common_vars(reqInfo); + + send_parsed_content(reqInfo,fp,noexec); ++ rflush(reqInfo); + FClose(fp); + } +diff -brc ./http_include.h /X11/blong/httpd/src//http_include.h +*** ./http_include.h Tue Jun 25 17:06:16 1996 +--- /X11/blong/httpd/src//http_include.h Wed Mar 27 14:44:04 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_include.h,v 1.7 1996/03/27 20:44:04 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_include.h,v 1.7 1996/03/27 20:44:04 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: http_include.o +diff -brc ./http_ipc.c /X11/blong/httpd/src//http_ipc.c +*** ./http_ipc.c Tue Jun 25 17:06:16 1996 +--- /X11/blong/httpd/src//http_ipc.c Wed Jun 5 21:44:40 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_ipc.c,v 1.22 1996/02/22 23:46:59 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_ipc.c,v 1.23 1996/06/06 02:44:40 blong Exp $ + * + ************************************************************************ + * +*************** +*** 42,47 **** +--- 42,50 ---- + + #ifdef FD_BSD + # include ++ # ifdef NEED_SYS_UN_H ++ # include ++ # endif /* NEED_SYS_UN_H */ + # include + # include + #elif defined(FD_SYSV) +diff -brc ./http_ipc.h /X11/blong/httpd/src//http_ipc.h +*** ./http_ipc.h Tue Jun 25 17:06:16 1996 +--- /X11/blong/httpd/src//http_ipc.h Mon Oct 23 13:07:14 1995 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_ipc.h,v 1.3 1995/07/25 06:43:36 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_ipc.h,v 1.3 1995/07/25 06:43:36 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: http_ipc.o +Only in /X11/blong/httpd/src/: http_kerberos.c +Only in /X11/blong/httpd/src/: http_kerberos.h +Only in /X11/blong/httpd/src/: http_kerberos.o +diff -brc ./http_log.c /X11/blong/httpd/src//http_log.c +*** ./http_log.c Tue Jun 25 17:06:16 1996 +--- /X11/blong/httpd/src//http_log.c Wed Jun 12 16:11:54 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_log.c,v 1.84 1996/04/05 18:54:59 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_log.c,v 1.86 1996/06/12 20:35:31 acain Exp $ + * + ************************************************************************ + * +*************** +*** 36,42 **** +--- 36,51 ---- + #endif /* NO_MALLOC_H */ + #include + #include ++ #include + #include "constants.h" ++ #ifdef LOG_TIMES ++ # include ++ # include ++ #endif /* LOG_TIMES */ ++ #ifdef SHTTP ++ # include ++ # include "http_shttp.h" ++ #endif /* SHTTP */ + #include "allocate.h" + #include "http_log.h" + #include "http_request.h" +*************** +*** 49,55 **** + #include "util.h" + #include "open_logfile.h" + +- + const char StatLine200[] = "200 Document follows"; + const char StatLine204[] = "204 No Content"; + const char StatLine206[] = "206 Partial Content"; +--- 58,63 ---- +*************** +*** 66,72 **** + const char StatLine503[] = "503 Service Unavailable"; + char error_msg[MAX_STRING_LEN]; + +- /* Moved to http_request.c */ + int ErrorStat=0; + + static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT ); +--- 74,79 ---- +*************** +*** 173,187 **** + long timz; + struct tm *t; + char *tstr,sign; +! #ifdef LOG_DURATION +! extern time_t request_time; +! time_t duration = request_time ? (time(NULL) - request_time) : 0; +! #endif /* LOG_DURATION */ + + str = newString(HUGE_STRING_LEN,STR_TMP); + tstr = newString(MAX_STRING_LEN,STR_TMP); + + + t = get_gmtoff(&timz); + sign = (timz < 0 ? '-' : '+'); + if(timz < 0) +--- 180,206 ---- + long timz; + struct tm *t; + char *tstr,sign; +! #ifdef LOG_TIMES +! struct tms times_end; +! struct timeval time_end; +! #endif /* LOG_TIMES */ + + str = newString(HUGE_STRING_LEN,STR_TMP); + tstr = newString(MAX_STRING_LEN,STR_TMP); + ++ #ifdef LOG_TIMES ++ if (reqInfo->hostInfo->log_opts & LOG_REALTIME) ++ gettimeofday(&time_end, NULL); + ++ if (reqInfo->hostInfo->log_opts & LOG_CPUTIME) { ++ times(×_end); ++ times_end.tms_stime -= reqInfo->times_recv.tms_stime; ++ times_end.tms_utime -= reqInfo->times_recv.tms_utime; ++ times_end.tms_cstime -= reqInfo->times_recv.tms_cstime; ++ times_end.tms_cutime -= reqInfo->times_recv.tms_cutime; ++ } ++ #endif /* LOG_TIMES */ ++ + t = get_gmtoff(&timz); + sign = (timz < 0 ? '-' : '+'); + if(timz < 0) +*************** +*** 212,218 **** + else + strcat(str," -"); + } +! if (reqInfo->hostInfo->referer_ignore && reqInfo->inh_referer[0]) { + char *str1; + int bIgnore = 0; + +--- 231,239 ---- + else + strcat(str," -"); + } +! if ((reqInfo->hostInfo->log_opts & LOG_REFERER) && +! reqInfo->hostInfo->referer_ignore && reqInfo->inh_referer[0]) +! { + char *str1; + int bIgnore = 0; + +*************** +*** 234,249 **** + } + freeString(str1); + } +- #ifdef LOG_DURATION +- sprintf(str+strlen(str), " %ld", duration); +- #endif /* LOG_DURATION */ + + if (!(reqInfo->hostInfo->log_opts & LOG_COMBINED)) { +- strcat(str,"\n"); +- write(reqInfo->hostInfo->xfer_log,str,strlen(str)); + + /* log the user agent */ +! if (reqInfo->inh_agent[0]) { + if (reqInfo->hostInfo->log_opts & LOG_DATE) + fprintf(reqInfo->hostInfo->agent_log, "[%s] %s\n",tstr, + reqInfo->inh_agent); +--- 255,267 ---- + } + freeString(str1); + } + + if (!(reqInfo->hostInfo->log_opts & LOG_COMBINED)) { + + /* log the user agent */ +! if ((reqInfo->hostInfo->log_opts & LOG_USERAGENT) && +! reqInfo->inh_agent[0]) +! { + if (reqInfo->hostInfo->log_opts & LOG_DATE) + fprintf(reqInfo->hostInfo->agent_log, "[%s] %s\n",tstr, + reqInfo->inh_agent); +*************** +*** 252,258 **** + fflush(reqInfo->hostInfo->agent_log); + } + /* log the referer */ +! if (reqInfo->inh_referer[0]) { + if (reqInfo->hostInfo->log_opts & LOG_DATE) + fprintf(reqInfo->hostInfo->referer_log, "[%s] %s -> %s\n",tstr, + reqInfo->inh_referer, reqInfo->url); +--- 270,278 ---- + fflush(reqInfo->hostInfo->agent_log); + } + /* log the referer */ +! if ((reqInfo->hostInfo->log_opts & LOG_REFERER) && +! reqInfo->inh_referer[0]) +! { + if (reqInfo->hostInfo->log_opts & LOG_DATE) + fprintf(reqInfo->hostInfo->referer_log, "[%s] %s -> %s\n",tstr, + reqInfo->inh_referer, reqInfo->url); +*************** +*** 262,277 **** + fflush(reqInfo->hostInfo->referer_log); + } + } else { +! if (reqInfo->inh_referer[0]) + sprintf(str,"%s \"%s\"",str,reqInfo->inh_referer); + else + strcat(str," \"\""); +! if (reqInfo->inh_agent[0]) +! sprintf(str,"%s \"%s\"\n",str,reqInfo->inh_agent); + else +! strcat(str," \"\"\n"); +! write(reqInfo->hostInfo->xfer_log,str,strlen(str)); + } + freeString(str); + freeString(tstr); + } +--- 282,320 ---- + fflush(reqInfo->hostInfo->referer_log); + } + } else { +! if ((reqInfo->hostInfo->log_opts & LOG_REFERER) && +! reqInfo->inh_referer[0]) + sprintf(str,"%s \"%s\"",str,reqInfo->inh_referer); + else + strcat(str," \"\""); +! if ((reqInfo->hostInfo->log_opts & LOG_USERAGENT) && +! reqInfo->inh_agent[0]) +! sprintf(str,"%s \"%s\"",str,reqInfo->inh_agent); + else +! strcat(str," \"\""); + } ++ #ifdef LOG_TIMES ++ if (reqInfo->hostInfo->log_opts & LOG_REALTIME) { ++ sprintf(str, "%s %d/%d/%d", str, ++ (((reqInfo->time_process.tv_sec*1000)+(reqInfo->time_process.tv_usec/1000)) - ++ ((reqInfo->time_recv.tv_sec*1000)+(reqInfo->time_recv.tv_usec/1000))), ++ (((reqInfo->time_send.tv_sec*1000)+(reqInfo->time_send.tv_usec/1000)) - ++ ((reqInfo->time_process.tv_sec*1000)+(reqInfo->time_process.tv_usec/1000))), ++ (((time_end.tv_sec*1000)+(time_end.tv_usec/1000)) - ++ ((reqInfo->time_send.tv_sec*1000)+(reqInfo->time_send.tv_usec/1000)))); ++ } else if (reqInfo->hostInfo->log_opts & LOG_CPUTIME) ++ strcat(str, " -"); ++ ++ if (reqInfo->hostInfo->log_opts & LOG_CPUTIME) { ++ sprintf(str, "%s %d/%d/%d", str, ++ times_end.tms_stime*1000/clk_ticks, ++ times_end.tms_utime*1000/clk_ticks, ++ (times_end.tms_cutime+times_end.tms_cstime)*1000/clk_ticks); ++ } else if (reqInfo->hostInfo->log_opts & LOG_REALTIME) ++ strcat(str, " -"); ++ #endif /* LOG_TIMES */ ++ strcat(str,"\n"); ++ write(reqInfo->hostInfo->xfer_log,str,strlen(str)); + freeString(str); + freeString(tstr); + } +*************** +*** 610,615 **** +--- 653,667 ---- + } + rflush(reqInfo); + freeString(arguments); ++ #ifdef SHTTP ++ /* SHTTP can't die here, it must be wrapped on the way out. */ ++ if (!RetVal && (reqInfo->RequestFlags & DOING_SHTTP) && shttp_jump_set) ++ #ifdef NO_SIGLONGJMP ++ longjmp(shttp_fail,1); ++ #else ++ siglongjmp(shttp_fail,1); ++ #endif /* NO_SIGLONGJMP */ ++ #endif /* SHTTP */ + if (!RetVal) + htexit(reqInfo,1,die_type); + return RetVal; +*************** +*** 636,650 **** + char *tmp; + + if (host->num_doc_errors == 0) { +! host->doc_errors = (ErrorDoc **) malloc(sizeof(ErrorDoc*)); + } else { +! host->doc_errors = (ErrorDoc **) realloc(host->doc_errors, + (host->num_doc_errors+1) * + sizeof(ErrorDoc*)); + } +! host->doc_errors[host->num_doc_errors]=(ErrorDoc *)malloc(sizeof(ErrorDoc)); + +! tmp = (char *) malloc(strlen(name)+1); + strcpy(tmp,name); + + host->doc_errors[host->num_doc_errors]->DocErrorNum = atoi(errornum); +--- 688,702 ---- + char *tmp; + + if (host->num_doc_errors == 0) { +! host->doc_errors = (ErrorDoc **) Malloc(sizeof(ErrorDoc*)); + } else { +! host->doc_errors = (ErrorDoc **) Realloc(host->doc_errors, + (host->num_doc_errors+1) * + sizeof(ErrorDoc*)); + } +! host->doc_errors[host->num_doc_errors]=(ErrorDoc *)Malloc(sizeof(ErrorDoc)); + +! tmp = (char *) Malloc(strlen(name)+1); + strcpy(tmp,name); + + host->doc_errors[host->num_doc_errors]->DocErrorNum = atoi(errornum); +*************** +*** 676,684 **** + int x=0; + + for (x = 0 ; x < host->num_doc_errors; x++) { +! free(host->doc_errors[x]->DocErrorFile); +! free(host->doc_errors[x]); + } + +! free(host->doc_errors); + } +--- 728,736 ---- + int x=0; + + for (x = 0 ; x < host->num_doc_errors; x++) { +! Free(host->doc_errors[x]->DocErrorFile); +! Free(host->doc_errors[x]); + } + +! Free(host->doc_errors); + } +diff -brc ./http_log.h /X11/blong/httpd/src//http_log.h +*** ./http_log.h Tue Jun 25 17:06:17 1996 +--- /X11/blong/httpd/src//http_log.h Wed Jun 5 21:44:44 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_log.h,v 1.18 1996/03/06 23:21:06 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_log.h,v 1.19 1996/06/06 02:44:44 blong Exp $ + * + ************************************************************************ + * +*************** +*** 33,38 **** +--- 33,42 ---- + #define LOG_SEPARATE ~(LOG_COMBINED) + #define LOG_SERVERNAME 2 + #define LOG_DATE 4 ++ #define LOG_REALTIME 8 ++ #define LOG_CPUTIME 16 ++ #define LOG_REFERER 32 ++ #define LOG_USERAGENT 64 + + #define SERVER_SUPPORT "httpd@ncsa.uiuc.edu" + +*************** +*** 68,74 **** + void error_log2stderr(FILE *error_log); + + void title_html(per_request *reqInfo, char *msg); +- void begin_http_header(per_request *reqInfo); + + int die(per_request *reqInfo, int type, char *err_string); + +--- 72,77 ---- +Only in /X11/blong/httpd/src/: http_log.o +diff -brc ./http_mime.c /X11/blong/httpd/src//http_mime.c +*** ./http_mime.c Tue Jun 25 17:06:17 1996 +--- /X11/blong/httpd/src//http_mime.c Wed Jun 5 21:44:46 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_mime.c,v 1.106 1996/03/13 18:28:39 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_mime.c,v 1.108 1996/06/06 02:44:46 blong Exp $ + * + ************************************************************************ + * +*************** +*** 52,61 **** + #include "http_request.h" + #include "util.h" + +- #if defined(KRB4) || defined(KRB5) +- #define HAVE_KERBEROS +- #endif /* defined(KRB4) || defined(KRB5) */ +- + #if 1 + #define hash(i) (isalpha(i) ? (tolower(i)) - 'a' : 26) + #else +--- 52,57 ---- +*************** +*** 99,126 **** + for(x=0;x<27;x++) { + p=types[x]; + while(p) { +! free(p->ext); +! free(p->ct); + q=p; + p=p->next; +! free(q); + } + } + p=forced_types; + while(p) { +! free(p->ext); +! free(p->ct); + q=p; + p=p->next; +! free(q); + } + p=encoding_types; + while(p) { +! free(p->ext); +! free(p->ct); + q=p; + p=p->next; +! free(q); + } + } + +--- 95,122 ---- + for(x=0;x<27;x++) { + p=types[x]; + while(p) { +! Free(p->ext); +! Free(p->ct); + q=p; + p=p->next; +! Free(q); + } + } + p=forced_types; + while(p) { +! Free(p->ext); +! Free(p->ct); + q=p; + p=p->next; +! Free(q); + } + p=encoding_types; + while(p) { +! Free(p->ext); +! Free(p->ct); + q=p; + p=p->next; +! Free(q); + } + } + +*************** +*** 149,163 **** + while(!(cfg_getline(l,MAX_STRING_LEN,f))) { + if(l[0] == '#') continue; + cfg_getword(w,l); +! if(!(ct = (char *)malloc(sizeof(char) * (strlen(w) + 1)))) + die(&reqInfo,SC_NO_MEMORY,"init_mime"); + strcpy(ct,w); + + while(l[0]) { + cfg_getword(w,l); +! if(!(me = (struct mime_ext *)malloc(sizeof(struct mime_ext)))) + die(&reqInfo,SC_NO_MEMORY,"init_mime"); +! if(!(me->ext = (char *)malloc(sizeof(char) * (strlen(w)+1)))) + die(&reqInfo,SC_NO_MEMORY,"init_mime"); + for(x=0;w[x];x++) + me->ext[x] = (islower(w[x]) ? w[x] : tolower(w[x])); +--- 145,159 ---- + while(!(cfg_getline(l,MAX_STRING_LEN,f))) { + if(l[0] == '#') continue; + cfg_getword(w,l); +! if(!(ct = (char *)Malloc(sizeof(char) * (strlen(w) + 1)))) + die(&reqInfo,SC_NO_MEMORY,"init_mime"); + strcpy(ct,w); + + while(l[0]) { + cfg_getword(w,l); +! if(!(me = (struct mime_ext *)Malloc(sizeof(struct mime_ext)))) + die(&reqInfo,SC_NO_MEMORY,"init_mime"); +! if(!(me->ext = (char *)Malloc(sizeof(char) * (strlen(w)+1)))) + die(&reqInfo,SC_NO_MEMORY,"init_mime"); + for(x=0;w[x];x++) + me->ext[x] = (islower(w[x]) ? w[x] : tolower(w[x])); +*************** +*** 167,173 **** + me->next=NULL; + hash_insert(me); + } +! free(ct); + } + FClose(f); + } +--- 163,169 ---- + me->next=NULL; + hash_insert(me); + } +! Free(ct); + } + FClose(f); + } +*************** +*** 291,299 **** + tmp = mimes; + while (mimes && (mimes != Saved_Forced)) { + mimes = mimes->next; +! free(tmp->ext); +! free(tmp->ct); +! free(tmp); + tmp = mimes; + } + +--- 287,295 ---- + tmp = mimes; + while (mimes && (mimes != Saved_Forced)) { + mimes = mimes->next; +! Free(tmp->ext); +! Free(tmp->ct); +! Free(tmp); + tmp = mimes; + } + +*************** +*** 304,312 **** + + while (mimes && (mimes != Saved_Encoding)) { + mimes = mimes->next; +! free(tmp->ext); +! free(tmp->ct); +! free(tmp); + tmp = mimes; + } + +--- 300,308 ---- + + while (mimes && (mimes != Saved_Encoding)) { + mimes = mimes->next; +! Free(tmp->ext); +! Free(tmp->ct); +! Free(tmp); + tmp = mimes; + } + +*************** +*** 316,322 **** + void add_type(per_request *reqInfo, char *fn, char *t) { + struct mime_ext *n; + +! if(!(n=(struct mime_ext *)malloc(sizeof(struct mime_ext)))) + die(reqInfo,SC_NO_MEMORY,"add_type"); + + if(!(n->ext = strdup(fn))) +--- 312,318 ---- + void add_type(per_request *reqInfo, char *fn, char *t) { + struct mime_ext *n; + +! if(!(n=(struct mime_ext *)Malloc(sizeof(struct mime_ext)))) + die(reqInfo,SC_NO_MEMORY,"add_type"); + + if(!(n->ext = strdup(fn))) +*************** +*** 330,336 **** + void add_encoding(per_request *reqInfo, char *fn, char *t) { + struct mime_ext *n; + +! if(!(n=(struct mime_ext *)malloc(sizeof(struct mime_ext)))) + die(reqInfo, SC_NO_MEMORY,"add_encoding"); + + if(!(n->ext = strdup(fn))) +--- 326,332 ---- + void add_encoding(per_request *reqInfo, char *fn, char *t) { + struct mime_ext *n; + +! if(!(n=(struct mime_ext *)Malloc(sizeof(struct mime_ext)))) + die(reqInfo, SC_NO_MEMORY,"add_encoding"); + + if(!(n->ext = strdup(fn))) +diff -brc ./http_mime.h /X11/blong/httpd/src//http_mime.h +*** ./http_mime.h Tue Jun 25 17:06:17 1996 +--- /X11/blong/httpd/src//http_mime.h Thu Feb 22 17:47:04 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_mime.h,v 1.19 1996/02/22 23:47:04 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_mime.h,v 1.19 1996/02/22 23:47:04 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: http_mime.o +Only in /X11/blong/httpd/src/: http_nis.c +Only in /X11/blong/httpd/src/: http_nis.h +Only in /X11/blong/httpd/src/: http_nis.o +Only in /X11/blong/httpd/src/: http_pem.c +diff -brc ./http_request.c /X11/blong/httpd/src//http_request.c +*** ./http_request.c Tue Jun 25 17:06:17 1996 +--- /X11/blong/httpd/src//http_request.c Wed Jun 12 16:11:54 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_request.c,v 1.113 1996/04/05 18:55:02 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_request.c,v 1.116 1996/06/12 20:35:34 acain Exp $ + * + ************************************************************************ + * +*************** +*** 39,49 **** +--- 39,56 ---- + #include + #include + #include "constants.h" ++ #ifdef SHTTP ++ # include ++ # include "http_shttp.h" ++ #endif /* SHTTP */ + #include "allocate.h" /* for freeString() */ + #include "cgi.h" /* for exec_cgi_script() */ + #ifdef FCGI_SUPPORT + # include "fcgi.h" /* for FastCgiHandler() */ + #endif /* FCGI */ ++ #ifdef SSL_SUPPORT ++ # include "http_ssl.h" /* for SSL defines */ ++ #endif /* SSL_SUPPORT */ + #include "env.h" /* for free_env() */ + #include "http_access.h" /* for reset_security() */ + #include "http_alias.h" /* For translate_name() */ +*************** +*** 72,81 **** + char as_requested[HUGE_STRING_LEN]; + char failed_request[HUGE_STRING_LEN]; + char failed_url[HUGE_STRING_LEN]; +- #ifdef LOG_DURATION +- time_t request_time = 0; +- #endif /* LOG_DURATION */ + + /* String constants for the request. Numbers are in constants.h */ + char *methods[METHODS] = {"GET","HEAD","POST","PUT","DELETE","SECURE", + "LINK","UNLINK"}; +--- 79,90 ---- + char as_requested[HUGE_STRING_LEN]; + char failed_request[HUGE_STRING_LEN]; + char failed_url[HUGE_STRING_LEN]; + ++ #ifdef SHTTP ++ JMP_BUF shttp_fail; ++ int shttp_jump_set = FALSE; ++ #endif /* SHTTP */ ++ + /* String constants for the request. Numbers are in constants.h */ + char *methods[METHODS] = {"GET","HEAD","POST","PUT","DELETE","SECURE", + "LINK","UNLINK"}; +*************** +*** 98,104 **** + + + if (RealInit) { +! newInfo = (per_request *) malloc(sizeof(per_request)); + req_count++; + reqInfo = newInfo; + reqInfo->ownDNS = TRUE; +--- 107,113 ---- + + + if (RealInit) { +! newInfo = (per_request *) Malloc(sizeof(per_request)); + req_count++; + reqInfo = newInfo; + reqInfo->ownDNS = TRUE; +*************** +*** 127,133 **** + + reqInfo->ownENV = TRUE; + reqInfo->env = NULL; +- reqInfo->env_len = NULL; + reqInfo->num_env = 0; + reqInfo->max_env = 0; + +--- 136,141 ---- +*************** +*** 187,192 **** +--- 195,213 ---- + #endif /* CONTENT_MD5 */ + reqInfo->outh_cgi = NULL; + ++ #ifdef SHTTP ++ if (!(reqInfo->shttp_info = (msginfo *)Malloc(sizeof(msginfo)))) { ++ fprintf(stderr,"\nADC ZZZ: malloc failed!!\n"); ++ fflush(stderr); ++ } ++ TSW_init_msginfo(reqInfo->shttp_info); ++ ++ reqInfo->privacy_enhancements = NULL; ++ reqInfo->shttp_info->youOpts = TSW_create_you_opts(); ++ reqInfo->shttp_info->meOpts = TSW_create_me_opts(); ++ ++ #endif /* SHTTP */ ++ + as_requested[0] = '\0'; + failed_url[0] = '\0'; + failed_request[0] = '\0'; +*************** +*** 217,223 **** + per_request *continue_request(per_request *reqInfo, int options) { + per_request *newInfo; + +! newInfo = (per_request *)malloc(sizeof(per_request)); + req_count++; + newInfo->status = reqInfo->status; + newInfo->status_line = NULL; +--- 238,244 ---- + per_request *continue_request(per_request *reqInfo, int options) { + per_request *newInfo; + +! newInfo = (per_request *)Malloc(sizeof(per_request)); + req_count++; + newInfo->status = reqInfo->status; + newInfo->status_line = NULL; +*************** +*** 225,237 **** + if (options & KEEP_ENV) { + newInfo->ownENV = FALSE; + newInfo->env = reqInfo->env; +- newInfo->env_len = reqInfo->env_len; + newInfo->num_env = reqInfo->num_env; + newInfo->max_env = reqInfo->max_env; + } else { + newInfo->ownENV = TRUE; + newInfo->env = NULL; +- newInfo->env_len = NULL; + newInfo->num_env = 0; + newInfo->max_env = 0; + } +--- 246,256 ---- +*************** +*** 302,308 **** +--- 321,341 ---- + newInfo->path_info[0] = '\0'; + newInfo->filename[0] = '\0'; + } ++ #ifdef SHTTP ++ newInfo->shttp_info = TSW_copy_msginfo(reqInfo->shttp_info); ++ if (newInfo == NULL) { ++ fprintf(stderr,"\nADC ZZZ: copy_msginfo failed!!\n"); ++ fflush(stderr); ++ } + ++ newInfo->privacy_enhancements = NULL; ++ /* for debugging ZZZZ ++ if (reqInfo->privacy_enhancements) ++ strcpy(newInfo->privacy_enhancements,reqInfo->privacy_enhancements); ++ */ ++ #endif /* SHTTP */ ++ ++ + /* Copy all in headers */ + strcpy(newInfo->inh_agent,reqInfo->inh_agent); + strcpy(newInfo->inh_referer,reqInfo->inh_referer); +*************** +*** 351,360 **** + reqInfo->remote_name = NULL; + reqInfo->remote_host = NULL; + reqInfo->remote_ip = NULL; + #ifdef CONTENT_MD5 +! if (reqInfo->outh_content_md5 != NULL) free(reqInfo->outh_content_md5); + #endif /* CONTENT_MD5 */ +! if (reqInfo->outh_cgi != NULL) free(reqInfo->outh_cgi); + + + if (reqInfo->ownENV && reqInfo->env) { +--- 384,400 ---- + reqInfo->remote_name = NULL; + reqInfo->remote_host = NULL; + reqInfo->remote_ip = NULL; ++ #ifdef SHTTP ++ if (reqInfo->privacy_enhancements != NULL) ++ freeString(reqInfo->privacy_enhancements); ++ reqInfo->privacy_enhancements = NULL; ++ ++ Free(reqInfo->shttp_info); ++ #endif /* SHTTP */ + #ifdef CONTENT_MD5 +! if (reqInfo->outh_content_md5 != NULL) Free(reqInfo->outh_content_md5); + #endif /* CONTENT_MD5 */ +! if (reqInfo->outh_cgi != NULL) Free(reqInfo->outh_cgi); + + + if (reqInfo->ownENV && reqInfo->env) { +*************** +*** 361,372 **** + free_env(reqInfo); + } + if (reqInfo->ownSB && reqInfo->sb) { +! free(reqInfo->sb); + reqInfo->sb = NULL; + sockbuf_count--; + } + if (reqInfo->cgi_buf) { +! free(reqInfo->cgi_buf); + reqInfo->cgi_buf = NULL; + cgibuf_count--; + } +--- 401,412 ---- + free_env(reqInfo); + } + if (reqInfo->ownSB && reqInfo->sb) { +! Free(reqInfo->sb); + reqInfo->sb = NULL; + sockbuf_count--; + } + if (reqInfo->cgi_buf) { +! Free(reqInfo->cgi_buf); + reqInfo->cgi_buf = NULL; + cgibuf_count--; + } +*************** +*** 379,385 **** + return; + } + tmp = reqInfo->next; +! free(reqInfo); + req_count--; + reqInfo = tmp; + gCurrentRequest = reqInfo; +--- 419,425 ---- + return; + } + tmp = reqInfo->next; +! Free(reqInfo); + req_count--; + reqInfo = tmp; + gCurrentRequest = reqInfo; +*************** +*** 409,415 **** + + /* extract the URL, and args if present */ + url = strtok (NULL, "\t\r "); +! if (url && (chp = strchr (url, '?'))) { + *chp++ = '\0'; + strcpy (reqInfo->args, chp); + } +--- 449,456 ---- + + /* extract the URL, and args if present */ + url = strtok (NULL, "\t\r "); +! if (!url) die(reqInfo,SC_BAD_REQUEST,"Incomplete request."); +! if ((chp = strchr (url, '?'))) { + *chp++ = '\0'; + strcpy (reqInfo->args, chp); + } +*************** +*** 482,487 **** +--- 523,538 ---- + char *field_val; + int options = 0; + ++ #ifdef SSL_SUPPORT ++ if (reqInfo->RequestFlags & DOING_SSL) ++ options |= G_SSL_READ; ++ #endif /* SSL_SUPPORT */ ++ ++ #ifdef SHTTP ++ if(reqInfo->method == M_SECURE) ++ options |= G_SINGLE_CHAR; ++ #endif /* SHTTP */ ++ + while(getline(reqInfo->sb,field_type,HUGE_STRING_LEN-1,options, + timeout) != -1) { + +*************** +*** 488,498 **** + if(!field_type[0]) + return; + +- /* ADC hack ZZZZ */ +- /* +- fprintf(stderr,">%s\n",field_type); +- fflush(stderr); +- */ + if(!(field_val = strchr(field_type,':'))) + continue; + +--- 539,544 ---- +*************** +*** 530,535 **** +--- 576,584 ---- + if(!strcasecmp(field_type,"Connection")) { + if (!strcasecmp(field_val, "Keep-Alive") && + keep_alive.bAllowKeepAlive) ++ #ifdef SSL_SUPPORT ++ if (!ssl_enabled) ++ #endif /* SSL_SUPPORT */ + keep_alive.bKeepAlive = 1; + } else + if(!strcasecmp(field_type,"User-agent")) { +*************** +*** 544,549 **** +--- 593,613 ---- + strncpy(reqInfo->inh_if_mod_since,field_val, MAX_STRING_LEN); + reqInfo->inh_if_mod_since[MAX_STRING_LEN-1] = '\0'; + } ++ #ifdef SHTTP ++ /* Quite frankly, this doesn't do anything, so fuq it. ZZZZZ */ ++ /* else if(!strcasecmp(field_type,"Security-Scheme")) { ++ TSW_trimbuf(field_val); ++ if (!strncasecmp(field_val,"S-HTTP",6)) { ++ } ++ } ++ */ ++ if (reqInfo->RequestFlags & DOING_SHTTP) { ++ TSW_proc_you_opt_val(&(reqInfo->shttp_info->youOpts),field_type, ++ field_val); ++ } else if (reqInfo->method == M_SECURE) { ++ TSW_shttp_parse_headerval(reqInfo->shttp_info,field_type,field_val); ++ } ++ #endif /* SHTTP */ + http2cgi(unrec_hdr, field_type); + strcpy (unrec_hdr_val, field_val); + if(reqInfo->env) { +*************** +*** 604,614 **** + { + int options = 0; + + signal(SIGPIPE,send_fd_timed_out); + +! #ifdef LOG_DURATION +! request_time = 0; +! #endif /* LOG_DURATION */ + + if (reqInfo->sb == NULL) { + reqInfo->sb = new_sock_buf(reqInfo,reqInfo->in); +--- 668,695 ---- + { + int options = 0; + ++ #ifdef LOG_TIMES ++ if (reqInfo->hostInfo->log_opts & LOG_CPUTIME) ++ times(&(reqInfo->times_recv)); ++ ++ if (reqInfo->hostInfo->log_opts & LOG_REALTIME) ++ gettimeofday(&(reqInfo->time_recv), NULL); ++ #endif /* LOG_TIMES */ ++ + signal(SIGPIPE,send_fd_timed_out); + +! #ifdef SSL_SUPPORT +! if (!(reqInfo->RequestFlags & DOING_SSL) && (ssl_enabled == TRUE)) { +! if (!ssl_request_init(reqInfo)) +! return; +! options |= G_SSL_READ; +! } +! /* ssl_fprintf calls require that this be null to test +! * for being an ssl stream +! */ +! /* if (!ssl_only_flag || !ssl_active_flag) +! ssl_con=NULL; */ +! #endif /* SSL_SUPPORT */ + + if (reqInfo->sb == NULL) { + reqInfo->sb = new_sock_buf(reqInfo,reqInfo->in); +*************** +*** 615,620 **** +--- 696,705 ---- + sockbuf_count++; + } + ++ #ifdef SHTTP ++ options |= G_SINGLE_CHAR; ++ #endif /* SHTTP */ ++ + if (getline(reqInfo->sb, as_requested, HUGE_STRING_LEN, + options, timeout) == -1) + return; +*************** +*** 622,631 **** + if(!as_requested[0]) + return; + +- #ifdef LOG_DURATION +- request_time = time(NULL); +- #endif /* LOG_DURATION */ +- + strcpy(the_request, as_requested); + + #ifdef SETPROCTITLE +--- 707,712 ---- +*************** +*** 646,652 **** + get_remote_host(reqInfo); + } + +! process_request(reqInfo); + + } + +--- 727,862 ---- + get_remote_host(reqInfo); + } + +! #ifdef SHTTP +! if(reqInfo->RequestFlags & DOING_SHTTP) { +! /* Set up temp file to put reply into, then continue. +! * Also set up here for a failure siglongjmp. +! */ + ++ reqInfo->out = TSW_secure_tmp_file(); ++ #ifdef NO_SIGLONGJMP ++ if (setjmp(shttp_fail)) { ++ #else ++ if (sigsetjmp(shttp_fail,1)) { ++ #endif /* NO_SIGLONGJMP */ ++ shttp_jump_set = FALSE; ++ return; ++ } ++ shttp_jump_set = TRUE; ++ } ++ ++ if(reqInfo->method == M_SECURE) { ++ int result; ++ int s2; ++ extern int tsw_null_func(); ++ per_request *newInfo; ++ int shttp_sugg_process = 0; ++ int shttp_allow_process = 0; ++ ++ if (reqInfo->remote_host != NULL) ++ reqInfo->shttp_info->peer_hostname = reqInfo->remote_host; ++ else ++ reqInfo->shttp_info->peer_hostname = reqInfo->remote_name; ++ reqInfo->shttp_info->peer_port = 0; ++ reqInfo->RequestFlags |= DOING_SHTTP; ++ ++ if (result = TSW_io_shttp_unwrap(&shttp_ctx,reqInfo->in,&s2,reqInfo->shttp_info, ++ 0,tsw_null_func())) ++ { ++ log_error(TSW_shttp_explain_error(result), ++ reqInfo->hostInfo->error_log); ++ fflush(reqInfo->hostInfo->error_log); ++ ++ close(s2); ++ die(reqInfo,SC_BAD_REQUEST,TSW_shttp_explain_error(result)); ++ } ++ ++ #ifdef SHTTP_DEBUG ++ if(TSW_is_encrypted(reqInfo->shttp_info)) ++ fprintf(stderr,"The request is encrypted !\n"); ++ else ++ fprintf(stderr,"The request is NOT encrypted !\n"); ++ ++ if(TSW_is_signed(reqInfo->shttp_info)) ++ fprintf(stderr,"The request is signed!\n"); ++ else ++ fprintf(stderr,"The request is NOT signed!\n"); ++ ++ if(TSW_is_authenticated(reqInfo->shttp_info)) ++ fprintf(stderr,"The request is authenticated!\n"); ++ else ++ fprintf(stderr,"The request is NOT authenticated!\n"); ++ ++ fflush(stderr); ++ #endif /* SHTTP_DEBUG */ ++ ++ strcpy(reqInfo->auth_type,"S-HTTP"); ++ /* kludge to set up info for scripts (?) */ ++ if (reqInfo->shttp_info->signed_dn) ++ strcpy(reqInfo->auth_user,reqInfo->shttp_info->signed_dn); ++ newInfo = continue_request(reqInfo,KEEP_AUTH | NEW_SOCK_BUF); ++ newInfo->in = s2; ++ ++ newInfo->RequestFlags |= DOING_SHTTP; /* added by ADC ZZZ */ ++ ++ /* the next three lines are adam debugging. they may not be needed ADC ZZZ ++ */ ++ newInfo->shttp_info->peer_hostname = reqInfo->shttp_info->peer_hostname; ++ newInfo->shttp_info->peer_port = 0; ++ newInfo->shttp_info->server = 1; ++ ++ RequestMain(newInfo); ++ close(newInfo->in); ++ ++ if (!strcmp(newInfo->outh_content_type,SHTTP_MAGIC_TYPE)) { ++ FILE *f; ++ ++ /* at this point we know file exists and is readable */ ++ ++ if(!(f = FOpen(newInfo->filename,"r"))) { ++ log_reason(newInfo,"ADC screwed up somehow ZZZZ", ++ newInfo->filename); ++ die(newInfo,SC_FORBIDDEN,newInfo->url); ++ } ++ ++ send_fp(reqInfo,f,NULL); /* writes it out reqInfo->out */ ++ log_transaction(newInfo); ++ FClose(f); ++ return; ++ } ++ ++ rflush(newInfo); ++ lseek(fileno(newInfo->out),SEEK_SET,0); ++ ++ /* We are a server, not a client */ ++ newInfo->shttp_info->server = 1; ++ ++ TSW_set_me_system_opts(&shttp_ctx,newInfo->shttp_info->meOpts,OP_SERVER | OP_KEYPAIR); ++ ++ shttp_set_masks(newInfo->privacy_enhancements, ++ &shttp_sugg_process,&shttp_allow_process); ++ TSW_set_me_privacy_enhancements(newInfo->shttp_info->meOpts, ++ shttp_sugg_process,shttp_allow_process); ++ set_shttp_authenticator(newInfo->shttp_info, ++ shttp_sugg_process,shttp_allow_process); ++ ++ /* make sure peer hostname is in newInfo->shttp_info ??? */ ++ ++ newInfo->shttp_info->process = 0; ++ ++ if (result = TSW_io_shttp_wrap(&shttp_ctx,fileno(newInfo->out), ++ fileno(reqInfo->out),newInfo->shttp_info,tsw_null_func)) ++ die(reqInfo,SC_BAD_REQUEST,TSW_shttp_explain_error(result)); ++ ++ return; ++ } ++ #endif /* SHTTP */ ++ ++ #ifdef LOG_TIMES ++ if (reqInfo->hostInfo->log_opts & LOG_REALTIME) ++ gettimeofday(&(reqInfo->time_process), NULL); ++ #endif /* LOG_TIMES */ ++ ++ process_request(reqInfo); + } + +diff -brc ./http_request.h /X11/blong/httpd/src//http_request.h +*** ./http_request.h Tue Jun 25 17:06:17 1996 +--- /X11/blong/httpd/src//http_request.h Fri Apr 5 12:55:04 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_request.h,v 1.20 1996/04/05 18:55:04 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_request.h,v 1.20 1996/04/05 18:55:04 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: http_request.o +diff -brc ./http_send.c /X11/blong/httpd/src//http_send.c +*** ./http_send.c Tue Jun 25 17:06:17 1996 +--- /X11/blong/httpd/src//http_send.c Tue Jun 25 16:59:26 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_send.c,v 1.34 1996/04/05 18:55:06 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_send.c,v 1.38 1996/06/12 20:35:36 acain Exp $ + * + ************************************************************************ + * +*************** +*** 42,47 **** +--- 42,51 ---- + #include + #include + #include "constants.h" ++ #ifdef SHTTP ++ # include ++ # include "http_shttp.h" ++ #endif /* SHTTP */ + #include "fdwrap.h" + #include "allocate.h" + #include "http_send.h" +*************** +*** 61,68 **** + #ifdef FCGI_SUPPORT + # include "fcgi.h" + #endif /* FCGI_SUPPORT */ + +! static void (*exit_callback)(void); + + void send_node(per_request *reqInfo) + { +--- 65,75 ---- + #ifdef FCGI_SUPPORT + # include "fcgi.h" + #endif /* FCGI_SUPPORT */ ++ #ifdef SSL_SUPPORT ++ # include "http_ssl.h" ++ #endif /* SSL_SUPPORT */ + +! void (*exit_callback)(void); + + void send_node(per_request *reqInfo) + { +*************** +*** 191,196 **** +--- 198,210 ---- + } + } + reqInfo->bytes_sent = 0; ++ /* wacky hack by ADC ZZZ */ ++ #ifdef SHTTP ++ if (!strcmp(reqInfo->outh_content_type,SHTTP_MAGIC_TYPE)) { ++ FClose(f); ++ return; ++ } ++ #endif /* SHTTP */ + + #ifdef BLACKOUT_CODE + if (!strcmp(reqInfo->outh_content_type,BLACKOUT_MAGIC_TYPE)) { +*************** +*** 328,333 **** +--- 342,348 ---- + { + register int x,max; + char *str; ++ int l,u; + + str = newString(HUGE_STRING_LEN,STR_TMP); + +*************** +*** 334,341 **** + max=count_dirs(reqInfo->filename); + for(x=max ; x > 0 ; x--) { + make_dirstr(reqInfo->filename,x+1,str); +! if(!(stat(str,finfo))) { +! int l=strlen(str); + strcat(reqInfo->path_info,&(reqInfo->filename[l])); + reqInfo->filename[l] = '\0'; + reqInfo->url[strlen(reqInfo->url) - strlen(reqInfo->path_info)]='\0'; +--- 349,358 ---- + max=count_dirs(reqInfo->filename); + for(x=max ; x > 0 ; x--) { + make_dirstr(reqInfo->filename,x+1,str); +! l=strlen(str); +! u=strlen(reqInfo->url); +! if(!(stat(str,finfo)) && +! !strcmp(reqInfo->filename+l, reqInfo->url+u-strlen(reqInfo->filename+l))) { + strcat(reqInfo->path_info,&(reqInfo->filename[l])); + reqInfo->filename[l] = '\0'; + reqInfo->url[strlen(reqInfo->url) - strlen(reqInfo->path_info)]='\0'; +*************** +*** 385,394 **** +--- 402,418 ---- + reqInfo->status = SC_AUTH_REQUIRED; + set_stat_line(reqInfo); + } ++ #ifdef LOG_TIMES ++ if (reqInfo->hostInfo->log_opts & LOG_REALTIME) ++ gettimeofday(&(reqInfo->time_send), NULL); ++ #endif /* LOG_TIMES */ + rprintf(reqInfo,"%s %s%c%c",protocals[reqInfo->http_version], + reqInfo->status_line,CR,LF); + rprintf(reqInfo,"Date: %s%c%c",gm_timestr_822(time(NULL)),CR,LF); + rprintf(reqInfo,"Server: %s%c%c",SERVER_VERSION,CR,LF); ++ #ifdef SHTTP ++ rprintf(reqInfo,"Security-Scheme: %s/%s%c%c",SHTTP_TITLE,SHTTP_VERSION,CR,LF); ++ #endif /* SHTTP */ + if (reqInfo->hostInfo->annotation_server[0]) + rprintf(reqInfo,"Annotations-cgi: %s%c%c", + reqInfo->hostInfo->annotation_server,CR,LF); +*************** +*** 439,445 **** +--- 463,485 ---- + } + if(reqInfo->outh_cgi) + rprintf(reqInfo,"%s",reqInfo->outh_cgi); ++ #ifdef SHTTP ++ if (reqInfo->RequestFlags & DOING_SHTTP) { ++ char *tmp; + ++ if (tmp = TSW_create_internal_headers(&shttp_ctx,reqInfo->shttp_info)) { ++ rprintf(reqInfo,"%s",tmp); ++ ++ #ifdef SHTTP_DEBUG ++ fprintf(stderr,"shttp internal headers:\n----------------\n%s",tmp); ++ fflush(stderr); ++ #endif /* SHTTP_DEBUG */ ++ ++ Free(tmp); ++ } ++ } ++ #endif /* SHTTP */ ++ + rprintf(reqInfo,"%c%c",CR,LF); + + /* CLF doesn't include the headers, I don't think, so clear the information +*************** +*** 520,525 **** +--- 560,566 ---- + alarm(timeout); + if((n=fread(buf,sizeof(char),IOBUFSIZE,f)) < 1) { + if (errno != EINTR) break; ++ else errno = 0; + } + + o=0; +*************** +*** 531,539 **** +--- 572,586 ---- + * For now, we'll just replace, but may have to #define one or the other + * depending on the system. + */ ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled && (reqInfo->RequestFlags & DOING_SSL)) { ++ w = SSL_write(ssl_con,&buf[o],n); ++ } else ++ #endif /* SSL_SUPPORT */ + w = write(fileno(reqInfo->out),&buf[o],n); + if (w < 0) { + if (errno != EINTR) break; ++ else errno = 0; + } + /* there goes ADC again... ZZZZ */ + /* +*************** +*** 566,574 **** + #else + va_start(argList); + #endif /* HAVE_VARARGS */ + x = vfprintf(reqInfo->out, format, argList); + +- + va_end(argList); + + reqInfo->bytes_sent += x; +--- 613,628 ---- + #else + va_start(argList); + #endif /* HAVE_VARARGS */ ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled && (reqInfo->RequestFlags & DOING_SSL)) { ++ char tmp[HUGE_STRING_LEN]; ++ vsprintf(tmp, format, argList); ++ x = strlen(tmp); ++ SSL_write(ssl_con,tmp,x); ++ } else ++ #endif /* SSL_SUPPORT */ + x = vfprintf(reqInfo->out, format, argList); + + va_end(argList); + + reqInfo->bytes_sent += x; +*************** +*** 581,596 **** +--- 635,682 ---- + int rputs(char *string, per_request *reqInfo) + { + reqInfo->bytes_sent += strlen(string); ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled && (reqInfo->RequestFlags & DOING_SSL)) { ++ return SSL_write(ssl_con,string,strlen(string)); ++ } else ++ #endif /* SSL_SUPPORT */ + return fputs(string,reqInfo->out); + } + ++ /* rputsn() print n characters from string (doesn't check for end of string) ++ */ ++ ++ int rputsn(per_request *reqInfo, char *string, int len) ++ { ++ reqInfo->bytes_sent += len; ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled && (reqInfo->RequestFlags & DOING_SSL)) { ++ return SSL_write(ssl_con,string,len); ++ } else ++ #endif /* SSL_SUPPORT */ ++ return fwrite(string,sizeof(char),len,reqInfo->out); ++ } ++ + int rputc(int ch, per_request *reqInfo) + { + (reqInfo->bytes_sent)++; ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled && (reqInfo->RequestFlags & DOING_SSL)) { ++ char tmp[2]; ++ tmp[0] = ch; ++ tmp[1] = '\0'; ++ return SSL_write(ssl_con,tmp,1); ++ } else ++ #endif /* SSL_SUPPORT */ + return putc(ch, reqInfo->out); + } + + int rflush(per_request *reqInfo) + { ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled && (reqInfo->RequestFlags & DOING_SSL)) { ++ return 0; ++ } else ++ #endif /* SSL_SUPPORT */ + return fflush(reqInfo->out); + } +diff -brc ./http_send.h /X11/blong/httpd/src//http_send.h +*** ./http_send.h Tue Jun 25 17:06:18 1996 +--- /X11/blong/httpd/src//http_send.h Tue Jun 25 16:59:47 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * http_send.h,v 1.10 1996/03/27 20:44:12 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: http_send.h,v 1.11 1996/06/06 02:44:52 blong Exp $ + * + ************************************************************************ + * +*************** +*** 20,25 **** +--- 20,27 ---- + #ifndef _HTTP_SEND_H_ + #define _HTTP_SEND_H_ + ++ extern void (*exit_callback)(void); ++ + /* function prototypes */ + void send_node(per_request *reqInfo); + void send_file(per_request *reqInfo, struct stat *fi, char allow_options); +*************** +*** 31,36 **** +--- 33,39 ---- + + int rprintf(per_request *reqInfo, char *format, ...); + int rputs(char *string, per_request *reqInfo); ++ int rputsn(per_request *reqInfo, char *string, int len); + int rputc(int ch, per_request *reqInfo); + int rflush(per_request *reqInfo); + +Only in /X11/blong/httpd/src/: http_send.o +Only in /X11/blong/httpd/src/: http_shttp.c +Only in /X11/blong/httpd/src/: http_shttp.h +Only in /X11/blong/httpd/src/: http_ssl.c +Only in /X11/blong/httpd/src/: http_ssl.h +diff -brc ./httpd.c /X11/blong/httpd/src//httpd.c +*** ./httpd.c Tue Jun 25 17:06:18 1996 +--- /X11/blong/httpd/src//httpd.c Wed Jun 12 16:11:56 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * httpd.c,v 1.131 1996/04/05 18:55:09 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: httpd.c,v 1.137 1996/06/12 20:35:39 acain Exp $ + * + ************************************************************************ + * +*************** +*** 66,71 **** +--- 66,75 ---- + # include + #endif /* NO_SYS_RESOURCE_H */ + #include "constants.h" ++ #ifdef SHTTP ++ # include ++ # include "http_shttp.h" ++ #endif /* SHTTP */ + #include "fdwrap.h" + #include "allocate.h" + #include "httpd.h" +*************** +*** 80,85 **** +--- 84,95 ---- + #include "http_mime.h" + #include "http_send.h" + #include "util.h" ++ #if defined(KRB4) || defined(KRB5) ++ # include "http_kerberos.h" ++ #endif /* KRB4 || KRB5 */ ++ #ifdef SSL_SUPPORT ++ # include "http_ssl.h" ++ #endif /* SSL_SUPPORT */ + + JMP_BUF restart_buffer; + int mainSocket; +*************** +*** 109,115 **** + #define HAVE_KERBEROS + #endif /* defined(KRB4) || defined(KRB5) */ + +- + void htexit(per_request *reqInfo, int status, int die_type) + { + #ifdef NO_SIGLONGJMP +--- 119,124 ---- +*************** +*** 426,431 **** +--- 435,443 ---- + CLIENT_SOCK_ADDR *sa_client) + { + static per_request *reqInfo = NULL; ++ #ifdef SHTTP ++ static int sk_size; ++ #endif /* SHTTP */ + + #ifndef THREADED + close(mainSocket); +*************** +*** 443,448 **** +--- 455,464 ---- + standalone = 0; + keep_alive.nCurrRequests = 0; + ++ #ifdef SHTTP ++ TSW_make_session_key(&shttp_ctx,HA_DES_ECB,0,&sk_size); ++ #endif /* SHTTP */ ++ + /* Only try to switch if we're running as root */ + if(!geteuid()) { + if (setuid(user_id) == -1) { +*************** +*** 559,565 **** + if (parent_pipe != Children[x].childfd) close(Children[x].childfd); + } + +! free(Children); + #endif /* THREADED */ + + #ifdef NO_SIGLONGJMP +--- 575,581 ---- + if (parent_pipe != Children[x].childfd) close(Children[x].childfd); + } + +! Free(Children); + #endif /* THREADED */ + + #ifdef NO_SIGLONGJMP +*************** +*** 687,692 **** +--- 703,711 ---- + #ifdef SETPROCTITLE + char namestr[30]; + #endif /* SETPROCTITLE */ ++ #ifdef SHTTP ++ int sk_size; ++ #endif /* SHTTP */ + + pid = 1; + #ifndef NEED_SPIPE +*************** +*** 711,716 **** +--- 730,741 ---- + + if (!pid) { + /* Child */ ++ #ifdef SHTTP ++ /* Strobe the session key generator so that different children ++ * have different key sequences. ++ */ ++ TSW_make_session_key(&shttp_ctx,HA_DES_ECB,0,&sk_size); ++ #endif /* SHTTP */ + + close(Children[childnum].childfd); + #ifdef BSD +*************** +*** 765,771 **** + exit(1); + } + +! bzero((char *) sa_server, sizeof(*sa_server)); + sa_server->sin_family=AF_INET; + sa_server->sin_addr= gConfiguration->address_info; + /* sa_server.sin_addr.s_addr=htonl(INADDR_ANY); */ +--- 790,796 ---- + exit(1); + } + +! memset(sa_server, 0, sizeof(*sa_server)); + sa_server->sin_family=AF_INET; + sa_server->sin_addr= gConfiguration->address_info; + /* sa_server.sin_addr.s_addr=htonl(INADDR_ANY); */ +*************** +*** 1025,1031 **** + close(Children[x].childfd); + kill(Children[x].pid,SIGKILL); + } +! free(Children); + #endif /* NO_PASS */ + free_host_conf(); + freeAllStrings(STR_HUP); +--- 1050,1056 ---- + close(Children[x].childfd); + kill(Children[x].pid,SIGKILL); + } +! Free(Children); + #endif /* NO_PASS */ + free_host_conf(); + freeAllStrings(STR_HUP); +*************** +*** 1039,1044 **** +--- 1064,1070 ---- + } /* while (!Exit) */ + } /* standalone_main */ + ++ + void default_banner(FILE* fout) + { + fprintf(fout,"NCSA HTTPd %s\n",SERVER_SOURCE); +*************** +*** 1045,1053 **** + fprintf(fout,"Licensed material. Portions of this work are\n"); + fprintf(fout,"Copyright (C) 1995-1996 Board of Trustees of the University of Illinois\n"); + fprintf(fout,"Copyright (C) 1995-1996 The Apache Group\n"); +! #if defined(DIGEST_AUTH) + fprintf(fout,"Copyright (C) 1989-1993 RSA Data Security, Inc.\n"); +! #endif /* DIGEST_AUTH */ + #ifdef DIGEST_AUTH + fprintf(fout,"Copyright (C) 1993-1994 Carnegie Mellon University\n"); + fprintf(fout,"Copyright (C) 1991 Bell Communications Research, Inc. (Bellcore)\n"); +--- 1071,1082 ---- + fprintf(fout,"Licensed material. Portions of this work are\n"); + fprintf(fout,"Copyright (C) 1995-1996 Board of Trustees of the University of Illinois\n"); + fprintf(fout,"Copyright (C) 1995-1996 The Apache Group\n"); +! #ifdef SHTTP +! fprintf(fout,"Copyright (C) 1994-1995 Enterprise Integration Technologies Corp.\n"); +! #endif /* SHTTP */ +! #if defined(SHTTP) || defined(DIGEST_AUTH) + fprintf(fout,"Copyright (C) 1989-1993 RSA Data Security, Inc.\n"); +! #endif /* SHTTP || DIGEST_AUTH */ + #ifdef DIGEST_AUTH + fprintf(fout,"Copyright (C) 1993-1994 Carnegie Mellon University\n"); + fprintf(fout,"Copyright (C) 1991 Bell Communications Research, Inc. (Bellcore)\n"); +*************** +*** 1056,1061 **** +--- 1085,1093 ---- + #ifdef FCGI_SUPPORT + fprintf(fout,"Copyright (C) 1995 Open Market, Inc.\n"); + #endif /* FCGI_SUPPORT */ ++ #ifdef SSL_SUPPORT ++ fprintf(fout,"Copyright (C) 1995 Tim Hudson, Eric Young\n"); ++ #endif /* SSL_SUPPORT */ + fflush(fout); + } + +*************** +*** 1071,1076 **** +--- 1103,1111 ---- + fprintf(stderr,"\tTACHOMETER\n"); + #endif /* TACHOMETER */ + #endif /* SETPROCTITLE */ ++ #ifdef LOG_TIMES ++ fprintf(stderr,"\tLOG_TIMES\n"); ++ #endif /* LOG_TIMES */ + #ifdef XBITHACK + fprintf(stderr,"\tXBITHACK\n"); + #endif /* XBITHACK */ +*************** +*** 1080,1088 **** +--- 1115,1129 ---- + #ifdef NO_PASS + fprintf(stderr,"\tNO_PASS\n"); + #endif /* NO_PASS */ ++ #ifdef FCGI_SUPPORT ++ fprintf(stderr,"\tFCGI_SUPPORT\n"); ++ #endif /* FCGI_SUPPORT */ + #ifdef DBM_SUPPORT + fprintf(stderr,"\tDBM_SUPPORT\n"); + #endif /* DBM_SUPPORT */ ++ #ifdef NIS_SUPPORT ++ fprintf(stderr,"\tNIS_SUPPORT\n"); ++ #endif /* NIS_SUPPORT */ + #ifdef DIGEST_AUTH + fprintf(stderr,"\tDIGEST_AUTH\n"); + #endif /* DIGEST_AUTH */ +*************** +*** 1095,1103 **** + #ifdef KRB5 + fprintf(stderr,"\tKRB5\n"); + #endif /* KRB5 */ +! #ifdef PEM_AUTH +! fprintf(stderr,"\tPEM_AUTH\n"); +! #endif /* PEM_AUTH */ + fprintf(stderr,"\tHTTPD_ROOT = %s\n",HTTPD_ROOT); + fprintf(stderr,"\tDOCUMENT_ROOT = %s\n", DOCUMENT_LOCATION); + +--- 1136,1147 ---- + #ifdef KRB5 + fprintf(stderr,"\tKRB5\n"); + #endif /* KRB5 */ +! #ifdef SSL_SUPPORT +! fprintf(stderr,"\tSSL_SUPPORT:%s\n",SSL_VERSION); +! #endif /* SSL_SUPPORT */ +! #ifdef SHTTP +! fprintf(stderr,"\tSHTTP:%s/%s\n",SHTTP_TITLE,SHTTP_VERSION); +! #endif /* SHTTP */ + fprintf(stderr,"\tHTTPD_ROOT = %s\n",HTTPD_ROOT); + fprintf(stderr,"\tDOCUMENT_ROOT = %s\n", DOCUMENT_LOCATION); + +*************** +*** 1178,1184 **** + } else { + char *cwd = getcwd(NULL,255); + make_full_path(cwd, optarg, server_confname); +! if (cwd) free(cwd); + } + break; + case 'v': +--- 1222,1228 ---- + } else { + char *cwd = getcwd(NULL,255); + make_full_path(cwd, optarg, server_confname); +! if (cwd) Free(cwd); + } + break; + case 'v': +*************** +*** 1202,1207 **** +--- 1246,1257 ---- + break; + #endif /* KRB5 */ + #endif /* HAVE_KERBEROS */ ++ #ifdef SSL_SUPPORT ++ case 's': ++ ssl_enabled = TRUE; ++ break; ++ #endif /* SSL_SUPPORT */ ++ + case '?': + usage(argv[0]); + } +*************** +*** 1223,1236 **** +--- 1273,1308 ---- + initproctitle(process_name, argc, argv, envp); + #endif /* SETPROCTITLE */ + ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled == TRUE) ++ ssl_init(); ++ #endif /* SSL_SUPPORT */ + set_group_privs(); + get_local_host(); + ++ #ifdef SHTTP ++ if(shttp_server_dns){ ++ int r; ++ ++ if(r=shttp_console_login("garbage",shttp_server_dns,tsw_null_func)) { ++ fprintf(stderr,"%s: aborted\n",TSW_shttp_explain_error(r)); ++ exit(1); ++ } else ++ fprintf(stderr,"password good.\n"); ++ ++ TSW_set_server_kludge(&shttp_ctx); ++ } ++ #endif /* SHTTP */ ++ + #ifdef __QNX__ + dup2(0,1); + dup2(0,2); + #endif /* __QNX */ + ++ #ifdef LOG_TIMES ++ clk_ticks = sysconf(_SC_CLK_TCK); ++ #endif /* LOG_TIMES */ ++ + if(standalone) + standalone_main(argc,argv); + else { +*************** +*** 1250,1255 **** +--- 1322,1331 ---- + RequestMain(reqInfo); + rflush(reqInfo); + } ++ ++ #ifdef SHTTP ++ TSW_crypt_term(&shttp_ctx); ++ #endif + + close_all_logs(); + fclose(stdin); +diff -brc ./httpd.h /X11/blong/httpd/src//httpd.h +*** ./httpd.h Tue Jun 25 17:06:18 1996 +--- /X11/blong/httpd/src//httpd.h Wed Mar 27 14:44:19 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * httpd.h,v 1.97 1996/03/27 20:44:19 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: httpd.h,v 1.97 1996/03/27 20:44:19 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: httpd.o +diff -brc ./imagemap.c /X11/blong/httpd/src//imagemap.c +*** ./imagemap.c Tue Jun 25 17:06:18 1996 +--- /X11/blong/httpd/src//imagemap.c Wed Jun 5 21:44:56 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * imagemap.c,v 1.15 1996/04/05 19:14:19 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: imagemap.c,v 1.19 1996/06/06 02:44:56 blong Exp $ + * + ************************************************************************ + * +*************** +*** 37,42 **** +--- 37,43 ---- + #include "http_request.h" + #include "imagemap.h" + #include "cgi.h" ++ #include "util.h" + + #ifdef IMAGEMAP_SUPPORT + +*************** +*** 257,265 **** + + void sendmesg(per_request* reqInfo, char *url, FILE *fp) + { +! char *loc; + + loc = newString(HUGE_STRING_LEN,STR_REQ); + + FClose(fp); + if (!strchr(url, ':')) { /*** If not a full URL ***/ +--- 258,267 ---- + + void sendmesg(per_request* reqInfo, char *url, FILE *fp) + { +! char *loc, *furl; + + loc = newString(HUGE_STRING_LEN,STR_REQ); ++ furl = newString(HUGE_STRING_LEN,STR_REQ); + + FClose(fp); + if (!strchr(url, ':')) { /*** If not a full URL ***/ +*************** +*** 267,281 **** + char *last = strrchr(reqInfo->url,'/'); + int x = 0, y = 0; + while (((reqInfo->url+x) <= last) && (y < HUGE_STRING_LEN)) { +! loc = *(reqInfo->url+x); + x++; y++; + } + loc[y] = '\0'; +! die(reqInfo,SC_REDIRECT_TEMP,loc); + } else { + strncpy(loc,url,HUGE_STRING_LEN); +- die(reqInfo,SC_REDIRECT_TEMP,loc); + } + } else { + die(reqInfo,SC_REDIRECT_TEMP,url); + } +--- 269,284 ---- + char *last = strrchr(reqInfo->url,'/'); + int x = 0, y = 0; + while (((reqInfo->url+x) <= last) && (y < HUGE_STRING_LEN)) { +! loc[y] = *(reqInfo->url+x); + x++; y++; + } + loc[y] = '\0'; +! strncat(loc,url,HUGE_STRING_LEN - y); + } else { + strncpy(loc,url,HUGE_STRING_LEN); + } ++ construct_url(furl, reqInfo->hostInfo, loc); ++ die(reqInfo,SC_REDIRECT_TEMP,furl); + } else { + die(reqInfo,SC_REDIRECT_TEMP,url); + } +diff -brc ./imagemap.h /X11/blong/httpd/src//imagemap.h +*** ./imagemap.h Tue Jun 25 17:06:19 1996 +--- /X11/blong/httpd/src//imagemap.h Fri Apr 5 12:55:18 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * imagemap.h,v 1.6 1996/04/05 18:55:18 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: imagemap.h,v 1.6 1996/04/05 18:55:18 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: imagemap.o +diff -brc ./md5.c /X11/blong/httpd/src//md5.c +*** ./md5.c Tue Jun 25 17:06:19 1996 +--- /X11/blong/httpd/src//md5.c Wed Jun 12 16:11:57 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * md5.c,v 1.6 1996/03/06 23:21:21 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: md5.c,v 1.7 1996/06/12 20:35:41 acain Exp $ + * + ************************************************************************ + * +*************** +*** 38,46 **** + + #include + #include +- #ifndef SHTTP +- #include "global.h" +- #endif /* SHTTP */ + #include "md5.h" + + void md5 (unsigned char *string, char result[33]) +--- 38,43 ---- +diff -brc ./md5.h /X11/blong/httpd/src//md5.h +*** ./md5.h Tue Jun 25 17:06:19 1996 +--- /X11/blong/httpd/src//md5.h Wed Jun 12 16:27:03 1996 +*************** +*** 28,35 **** + + /* MD5 context. */ + typedef struct { +! UINT4 state[4]; /* state (ABCD) */ +! UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ + } MD5_CTX; + +--- 28,35 ---- + + /* MD5 context. */ + typedef struct { +! H_UINT4 state[4]; /* state (ABCD) */ +! H_UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ + } MD5_CTX; + +Only in /X11/blong/httpd/src/: md5.o +diff -brc ./md5c.c /X11/blong/httpd/src//md5c.c +*** ./md5c.c Tue Jun 25 17:06:19 1996 +--- /X11/blong/httpd/src//md5c.c Wed Jun 12 16:28:43 1996 +*************** +*** 27,33 **** + #include "config.h" + #include "portability.h" + +- #include "global.h" + #include "md5.h" + + /* Constants for MD5Transform routine. +--- 27,32 ---- +*************** +*** 49,61 **** + #define S43 15 + #define S44 21 + +! static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); +! static void Encode PROTO_LIST +! ((unsigned char *, UINT4 *, unsigned int)); +! static void Decode PROTO_LIST +! ((UINT4 *, unsigned char *, unsigned int)); +! static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); +! static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); + + static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +--- 48,58 ---- + #define S43 15 + #define S44 21 + +! static void MD5Transform(H_UINT4 [4], unsigned char [64]); +! static void Encode(unsigned char *, H_UINT4 *, unsigned int); +! static void Decode(H_UINT4 *, unsigned char *, unsigned int); +! static void MD5_memcpy(H_POINTER, H_POINTER, unsigned int); +! static void MD5_memset(H_POINTER, int, unsigned int); + + static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +*************** +*** 78,99 **** + Rotation is separate from addition to prevent recomputation. + */ + #define FF(a, b, c, d, x, s, ac) { \ +! (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + #define GG(a, b, c, d, x, s, ac) { \ +! (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + #define HH(a, b, c, d, x, s, ac) { \ +! (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + #define II(a, b, c, d, x, s, ac) { \ +! (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +--- 75,96 ---- + Rotation is separate from addition to prevent recomputation. + */ + #define FF(a, b, c, d, x, s, ac) { \ +! (a) += F ((b), (c), (d)) + (x) + (H_UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + #define GG(a, b, c, d, x, s, ac) { \ +! (a) += G ((b), (c), (d)) + (x) + (H_UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + #define HH(a, b, c, d, x, s, ac) { \ +! (a) += H ((b), (c), (d)) + (x) + (H_UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + #define II(a, b, c, d, x, s, ac) { \ +! (a) += I ((b), (c), (d)) + (x) + (H_UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +*************** +*** 127,136 **** + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ +! if ((context->count[0] += ((UINT4)inputLen << 3)) +! < ((UINT4)inputLen << 3)) + context->count[1]++; +! context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + +--- 124,133 ---- + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ +! if ((context->count[0] += ((H_UINT4)inputLen << 3)) +! < ((H_UINT4)inputLen << 3)) + context->count[1]++; +! context->count[1] += ((H_UINT4)inputLen >> 29); + + partLen = 64 - index; + +*************** +*** 138,144 **** + */ + if (inputLen >= partLen) { + MD5_memcpy +! ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) +--- 135,141 ---- + */ + if (inputLen >= partLen) { + MD5_memcpy +! ((H_POINTER)&context->buffer[index], (H_POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) +*************** +*** 151,157 **** + + /* Buffer remaining input */ + MD5_memcpy +! ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); + } + +--- 148,154 ---- + + /* Buffer remaining input */ + MD5_memcpy +! ((H_POINTER)&context->buffer[index], (H_POINTER)&input[i], + inputLen-i); + } + +*************** +*** 181,196 **** + + /* Zeroize sensitive information. + */ +! MD5_memset ((POINTER)context, 0, sizeof (*context)); + } + + /* MD5 basic transformation. Transforms state based on block. + */ + static void MD5Transform (state, block) +! UINT4 state[4]; + unsigned char block[64]; + { +! UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + +--- 178,193 ---- + + /* Zeroize sensitive information. + */ +! MD5_memset ((H_POINTER)context, 0, sizeof (*context)); + } + + /* MD5 basic transformation. Transforms state based on block. + */ + static void MD5Transform (state, block) +! H_UINT4 state[4]; + unsigned char block[64]; + { +! H_UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + +*************** +*** 273,287 **** + + /* Zeroize sensitive information. + */ +! MD5_memset ((POINTER)x, 0, sizeof (x)); + } + +! /* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ + static void Encode (output, input, len) + unsigned char *output; +! UINT4 *input; + unsigned int len; + { + unsigned int i, j; +--- 270,284 ---- + + /* Zeroize sensitive information. + */ +! MD5_memset ((H_POINTER)x, 0, sizeof (x)); + } + +! /* Encodes input (H_UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ + static void Encode (output, input, len) + unsigned char *output; +! H_UINT4 *input; + unsigned int len; + { + unsigned int i, j; +*************** +*** 294,304 **** + } + } + +! /* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ + static void Decode (output, input, len) +! UINT4 *output; + unsigned char *input; + unsigned int len; + { +--- 291,301 ---- + } + } + +! /* Decodes input (unsigned char) into output (H_UINT4). Assumes len is + a multiple of 4. + */ + static void Decode (output, input, len) +! H_UINT4 *output; + unsigned char *input; + unsigned int len; + { +*************** +*** 305,312 **** + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) +! output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | +! (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); + } + + /* Note: Replace "for loop" with standard memcpy if possible. +--- 302,309 ---- + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) +! output[i] = ((H_UINT4)input[j]) | (((H_UINT4)input[j+1]) << 8) | +! (((H_UINT4)input[j+2]) << 16) | (((H_UINT4)input[j+3]) << 24); + } + + /* Note: Replace "for loop" with standard memcpy if possible. +*************** +*** 313,320 **** + */ + + static void MD5_memcpy (output, input, len) +! POINTER output; +! POINTER input; + unsigned int len; + { + unsigned int i; +--- 310,317 ---- + */ + + static void MD5_memcpy (output, input, len) +! H_POINTER output; +! H_POINTER input; + unsigned int len; + { + unsigned int i; +*************** +*** 326,332 **** + /* Note: Replace "for loop" with standard memset if possible. + */ + static void MD5_memset (output, value, len) +! POINTER output; + int value; + unsigned int len; + { +--- 323,329 ---- + /* Note: Replace "for loop" with standard memset if possible. + */ + static void MD5_memset (output, value, len) +! H_POINTER output; + int value; + unsigned int len; + { +Only in /X11/blong/httpd/src/: md5c.o +diff -brc ./open_logfile.c /X11/blong/httpd/src//open_logfile.c +*** ./open_logfile.c Tue Jun 25 17:06:19 1996 +--- /X11/blong/httpd/src//open_logfile.c Tue Nov 28 03:02:17 1995 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * open_logfile.c,v 1.6 1995/11/28 09:02:17 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: open_logfile.c,v 1.6 1995/11/28 09:02:17 blong Exp $ + * + ************************************************************************ + * +diff -brc ./open_logfile.h /X11/blong/httpd/src//open_logfile.h +*** ./open_logfile.h Tue Jun 25 17:06:19 1996 +--- /X11/blong/httpd/src//open_logfile.h Mon Oct 23 13:07:14 1995 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * open_logfile.h,v 1.2 1995/09/20 23:37:11 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: open_logfile.h,v 1.2 1995/09/20 23:37:11 blong Exp $ + * + ************************************************************************ + * +Only in /X11/blong/httpd/src/: open_logfile.o +Only in .: patch +diff -brc ./portability.h /X11/blong/httpd/src//portability.h +*** ./portability.h Tue Jun 25 17:06:19 1996 +--- /X11/blong/httpd/src//portability.h Wed Jun 12 17:51:32 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * portability.h,v 1.32 1996/03/27 20:44:29 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: portability.h,v 1.35 1996/06/12 22:51:32 blong Exp $ + * + ************************************************************************ + * +*************** +*** 70,75 **** +--- 70,76 ---- + #define DIR_FILENO(p) ((p)->dd_fd) + #define HEAD_CRYPT + #define MISSING_HEADERS ++ #define _H_M_WAIT + + #elif defined(AIX4) + #undef BSD +*************** +*** 204,217 **** + + + #elif defined(LINUX) +! /* This release contains a Linux file descriptor hack using the /proc filesystem. +! This is a largely unsupported feature, and will hopefully be replaced by one +! of the other file descriptor passing mechanisms when they are supported by +! the Linux kernel */ +! /* #define NO_PASS */ +! #define FD_LINUX + /* Needed for newer versions of libc (5.2.x) to use FD_LINUX hack */ + #define DIRENT_ILLEGAL_ACCESS + #undef BSD + #undef NO_KILLPG + #undef NO_SETSID +--- 205,217 ---- + + + #elif defined(LINUX) +! #define FD_BSD +! #define FD_BSDRENO + /* Needed for newer versions of libc (5.2.x) to use FD_LINUX hack */ + #define DIRENT_ILLEGAL_ACCESS ++ #define DIR_FILENO(p) ((p)->dd_fd) ++ #define CMSG_DATA(cmptr) ((cmptr)->cmsg_data) ++ #define NEED_SYS_UN_H + #undef BSD + #undef NO_KILLPG + #undef NO_SETSID +*************** +*** 426,431 **** +--- 426,442 ---- + #ifndef MAXPATHLEN + # include + #endif /* MAX_PATHLEN */ ++ ++ ++ /* RSA Portability Defns (from global.h), modified so as not to interfere */ ++ /* POINTER defines a generic pointer type */ ++ typedef unsigned char *H_POINTER; ++ ++ /* UINT2 defines a two byte word */ ++ typedef unsigned short int H_UINT2; ++ ++ /* UINT4 defines a four byte word */ ++ typedef unsigned long int H_UINT4; + + /* Some systems prefer sockaddr_in for some functions, and sock_addr + for others +Only in /X11/blong/httpd/src/: rfc1413.c +Only in /X11/blong/httpd/src/: rfc1413.h +Only in .: rfc822.c +Only in /X11/blong/httpd/src/: rfc931.o +diff -brc ./util.c /X11/blong/httpd/src//util.c +*** ./util.c Tue Jun 25 17:06:20 1996 +--- /X11/blong/httpd/src//util.c Wed May 15 16:10:10 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * util.c,v 1.115 1996/03/27 20:44:30 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: util.c,v 1.116 1996/05/15 21:10:10 blong Exp $ + * + ************************************************************************ + * +*************** +*** 62,67 **** +--- 62,70 ---- + #include "host_config.h" + #include "http_log.h" + #include "httpd.h" ++ #ifdef SSL_SUPPORT ++ # include "http_ssl.h" ++ #endif /* SSL_SUPPORT */ + + + #undef DONTCOMPILEIN +*************** +*** 615,620 **** +--- 618,632 ---- + signal(SIGALRM,getline_timed_out); + alarm(timeout); + ++ #ifdef SSL_SUPPORT ++ /* I don't think this will work with S-HTTP also, since we it ++ * would have to be able to use the SSL read command. We really ++ * need a full file I/O interface of our own. ++ */ ++ if (options & G_SSL_READ) ++ ret = SSL_read(ssl_con, sb->buffer, size); ++ else ++ #endif /* SSL_SUPPORT */ + ret=read(sb->sd, sb->buffer, size); + + if (ret <= 0) { +*************** +*** 645,652 **** + } + + c = sb->buffer[(sb->buf_posn)++]; +! if ((c == '\r') && (sb->buffer[sb->buf_posn] == '\n') && +! (sb->buf_posn + 1 < sb->buf_good) && + ((sb->buffer[sb->buf_posn + 1] == ' ') || + (sb->buffer[sb->buf_posn + 1] == '\t'))) + { +--- 657,664 ---- + } + + c = sb->buffer[(sb->buf_posn)++]; +! if ((c == '\r') && (sb->buf_posn + 1 < sb->buf_good) && +! (sb->buffer[sb->buf_posn] == '\n') && + ((sb->buffer[sb->buf_posn + 1] == ' ') || + (sb->buffer[sb->buf_posn + 1] == '\t'))) + { +*************** +*** 1266,1271 **** +--- 1278,1291 ---- + */ + void construct_url(char *full_url, per_host *host, char *url) + { ++ #ifdef SSL_SUPPORT ++ if (ssl_enabled) { ++ if (port == DEFAULT_SSL_PORT) ++ sprintf(full_url,"%s://%s%s", "https",host->server_hostname,url); ++ else ++ sprintf(full_url,"%s://%s:%d%s", "https",host->server_hostname,port,url); ++ } else ++ #endif /* SSL_SUPPORT */ + { + if (port == DEFAULT_PORT) + sprintf(full_url,"%s://%s%s", "http",host->server_hostname,url); +diff -brc ./util.h /X11/blong/httpd/src//util.h +*** ./util.h Tue Jun 25 17:06:20 1996 +--- /X11/blong/httpd/src//util.h Wed Mar 27 14:44:32 1996 +*************** +*** 10,16 **** + * + ************************************************************************ + * +! * util.h,v 1.18 1996/03/27 20:44:32 blong Exp + * + ************************************************************************ + * +--- 10,16 ---- + * + ************************************************************************ + * +! * $Id: util.h,v 1.18 1996/03/27 20:44:32 blong Exp $ + * + ************************************************************************ + * +*************** +*** 28,33 **** +--- 28,36 ---- + #define G_RESET_BUF 1 + #define G_FLUSH 2 + #define G_SINGLE_CHAR 4 ++ #ifdef SSL_SUPPORT ++ # define G_SSL_READ 8 ++ #endif /* SSL_SUPPORT */ + + + /* util function prototypes */ +Only in /X11/blong/httpd/src/: util.o diff --git a/src/portability.h b/src/portability.h index 182404f..7f4fc9f 100644 --- a/src/portability.h +++ b/src/portability.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * portability.h,v 1.29 1995/11/28 09:02:18 blong Exp + * portability.h,v 1.32 1996/03/27 20:44:29 blong Exp * ************************************************************************ * @@ -37,7 +37,6 @@ char *crypt(char *pw, char *salt); #define FD_BSD #define MIX_SOCKADDR #define bzero(a,b) memset(a,0,b) -#define getwd(d) getcwd(d,MAX_STRING_LEN) #define JMP_BUF sigjmp_buf #define DIR_FILENO(p) ((p)->dd_fd) #define NEED_CRYPT_H @@ -58,7 +57,6 @@ char *crypt(char *pw, char *salt); #ifndef _HPUX_SOURCE # define _HPUX_SOURCE #endif /* _HPUX_SOURCE */ -#define getwd(d) getcwd(d,MAX_STRING_LEN) #define JMP_BUF sigjmp_buf #define DIR_FILENO(p) ((p)->dd_fd) @@ -71,6 +69,7 @@ char *crypt(char *pw, char *salt); #define JMP_BUF sigjmp_buf #define DIR_FILENO(p) ((p)->dd_fd) #define HEAD_CRYPT +#define MISSING_HEADERS #elif defined(AIX4) #undef BSD @@ -198,28 +197,33 @@ typedef int pid_t; typedef int mode_t; #define JMP_BUF jmp_buf #define DIR_FILENO(p) ((p)->dd_fd) +/* The following might be required for some versions of NeXTStep on + * some platforms. + */ +/* #include */ #elif defined(LINUX) -/* This release contains a Linux file descriptor hack using the /proc filesystem. - This is a largely unsupported feature, and will hopefully be replaced by one - of the other file descriptor passing mechanisms when they are supported by - the Linux kernel */ -/* #define NO_PASS */ -#define FD_LINUX +#if !defined(FD_LINUX) && !defined(NO_PASS) +#define FD_BSD +#define FD_BSDRENO +#endif /* Needed for newer versions of libc (5.2.x) to use FD_LINUX hack */ #define DIRENT_ILLEGAL_ACCESS +#define DIR_FILENO(p) ((p)->dd_fd) +#define CMSG_DATA(cmptr) ((cmptr)->cmsg_data) +#define NEED_SYS_UN_H #undef BSD #undef NO_KILLPG #undef NO_SETSID #undef NEED_STRDUP #define MIX_SOCKADDR /* This are defined, in linux/time.h included from sys/time.h, as of 1.2.8 */ -#ifdef 0 +#ifdef NEVER_DEFINED # define FD_SET __FD_SET # define FD_ZERO __FD_ZERO # define FD_ISSET __FD_ISSET -#endif /* 0 */ +#endif /* NEVER_DEFINED */ #define JMP_BUF sigjmp_buf #elif defined(NETBSD) || defined(__NetBSD__) @@ -252,7 +256,15 @@ typedef int mode_t; #undef NO_SETSID #define NEED_INITGROUPS #define CALL_TZSET -#define getwd(d) getcwd(d,MAX_STRING_LEN) +#define JMP_BUF sigjmp_buf +#define MIX_SOCKADDR + +#elif defined(SCO5) +#undef BSD +#define FD_SYSV +#undef NO_KILLPG +#undef NO_SETSID +#define CALL_TZSET #define JMP_BUF sigjmp_buf #define MIX_SOCKADDR @@ -260,7 +272,6 @@ typedef int mode_t; #define BSD #define FD_BSD #define NEED_STRDUP -#define getwd(d) getcwd(d,MAX_STRING_LEN) #define NEED_SYS_MALLOC_H #include #define JMP_BUF sigjmp_buf @@ -294,7 +305,6 @@ typedef int mode_t; #define NEED_STRNCASECMP #define bzero(a,b) memset(a,0,b) #define JMP_BUF sigjmp_buf -#define getwd(d) getcwd(d,MAX_STRING_LEN) #define S_ISLNK(m) (((m)&(S_IFMT)) == (S_IFLNK)) #elif defined(__bsdi__) @@ -350,7 +360,6 @@ typedef int mode_t; #endif #define lstat stat #define strftime(buf,bufsize,fmt,tm) ascftime(buf,fmt,tm) -#define getwd(d) getcwd(d,MAX_STRING_LEN) #define readlink(a,b,c) -1 typedef int uid_t; typedef int gid_t; @@ -412,6 +421,9 @@ extern char *getenv(); # define DIR_TYPE direct #endif /* !defined(NeXT) && !defined(CONVEXOS) && !defined(APOLLO) */ +#if !defined(HAVE_STDARG) && !defined(HAVE_VARARGS) +# define HAVE_STDARG +#endif /* !defined(HAVE_STDARG) && !defined(HAVE_VARARGS) */ #ifndef JMP_BUF # define JMP_BUF sigjmp_buf @@ -435,4 +447,34 @@ typedef struct sockaddr CLIENT_SOCK_ADDR; typedef struct sockaddr_in CLIENT_SOCK_ADDR; #endif /* MIX_SOCKADDR */ +#ifdef AIX_BROKEN_HEADERS +/* string.h */ +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); +#include +int accept(int, struct sockaddr *, int *); +int bind(int, struct sockaddr *, int); +int connect(int, struct sockaddr *, int); +int getpeername(int, struct sockaddr *, int *); +int getsockname(int, struct sockaddr *, int *); +int getsockopt(int, int, int, char *, int *); +int listen(int, int); +int recv(int, char *, int, int); +int recvfrom(int, char *, int, int, struct sockaddr *, int *); +int send(int, const char *, int, int); +int sendto(int, const char *, int, int, struct sockaddr *, int); +int setsockopt(int, int, int, const char *, int); +int socket(int, int, int); +int recvmsg(int, struct msghdr *, int); +int sendmsg(int, struct msghdr *, int); +int shutdown(int, int); +int socketpair(int, int, int, int *); +int killpg(int ProcessGroup, int Signal); +int initgroups(char* User, int BaseGID); +void bzero(char* String, int Length); +int gethostname(char* Name, int NameLength); +char *crypt(char* PW, char *Salt); +#endif /* AIX_BROKEN_HEADERS */ + + #endif /* _PORTABILITY_H_ */ diff --git a/src/rfc822.c b/src/rfc822.c new file mode 100644 index 0000000..ad13ad0 --- /dev/null +++ b/src/rfc822.c @@ -0,0 +1,60 @@ +/*rfc822.c -- utilities to make httpd do rfc822 + Copyright (C) 1994 Enterprise Integration Technologies Corp + 30-Aug-94 ekr +*/ + +/*A wrapper around getline to do rfc822 line unfolding*/ +int ht_rfc822_getline(char *s,int n,int f,unsigned int timeout) + { + static char pb=0; + int len; + + if(pb){ + if(n--){ + if(pb=='\n'){ + *s=pb='\0'; + return; + } + else + *s++=pb; + } + else + return(0); + } + + while(!getline(s,n,f,timeout)){ + len=strlen(s); + s+=len; + n-=len; + if(n==1) /*If we get here, we've failed to read a full line*/ + return(0); + + /*Here's where things get heinous. We're gonna read 1 character + ahead with read(2)...McCool doesn't leave us any choice*/ + if(read(f,&pb,1)<=0){ + pb=0; + return(0); + } + + if(pb=='\r'){ + if(read(f,&pb,1)<=0){ + pb=0; + return(0); + } + } + + if(pb==' '){ /*This is a folded line*/ + /*Trim off trailing whitespace*/ + while(isspace(*--s)){ + *s='\0'; + n++; + } + s++; + n--; + *s++=pb; + pb=0; + } + else + return(0); + } + } diff --git a/src/util.c b/src/util.c index 0b462d4..58890e8 100644 --- a/src/util.c +++ b/src/util.c @@ -10,68 +10,12 @@ * ************************************************************************ * - * util.c,v 1.106 1995/11/28 09:02:21 blong Exp + * util.c,v 1.115 1996/03/27 20:44:30 blong Exp * ************************************************************************ * * util.c: string utility things, and other utilities * - * 03-23-93 Rob McCool - * Original code up to version 1.3 from Rob McCool - * - * 02-16-95 cvarela - * Fixed stack hole in strsubfirst - * - * 03-06-95 blong - * Added inststr from bdflush-1.5 for Linux to set the name of - * the running processes - * - * 03-10-95 blong - * Added buffered getline for all but POST requests as suggested by - * Robert S. Thau (rst@ai.mit.edu) - * - * 03-20-95 blong & cvarela - * Fixed make_env_str so that it doesn't modify the pointers - * - * 04-03-95 blong - * May have fixed problems (esp. under Solaris 2.3) with playing - * with library memory in get_remote_name - * - * 04-13-95 guillory - * added strncpy_dir that limits the length of a directory copy - * also added strncpy for same reason - * - * 04-29-95 blong - * added patch by Kevin Steves (stevesk@mayfield.hp.com) for inststr - * under HPUX which uses the pstat command - * - * 06-01-95 blong - * added patch by Vince Skahan (vds7789@aw101.iasl.ca.boeing.com) - * to fix Apollo DomainOS timezone handling - * - * 09-02-95 blong - * added patch by Gioacchino La Vecchia (gio@di.unipi.it) to make - * full host name in get_local_host() to keep from needing to use - * the ServerName configuration directive - * - * 09-11-95 mshapiro - * replaced atoi() in uname2id() and gname2id with scan_long() to - * convert user_id and group_id from #n to uid_t, gid_t. - * If the config file had contained #non-digit then atoi() would - * have returned 0 and the server would have been run as root. - * - * 09-12-95 blong - * removed get_local_host() patch, because its the wrong thing to - * do. Use the ServerName directive, thats what its there for. - * - * 11-02-95 mshapiro - * recoded no2slash() to perform the following replacecments - * sequences of / (//, ///, etc) with a single / - * all occurenences of /./ with a single / - * remove ./ at the beginning of the name - * replace /. at the end of the name with a single / - * - * added a call to no2slash() at the beginning of getparents() * */ @@ -111,6 +55,7 @@ # include #endif #include "constants.h" +#include "allocate.h" #include "util.h" #include "http_request.h" #include "http_config.h" @@ -486,7 +431,7 @@ void no2slash(char *name) while (s[0] == '/' && s[1] == '/') { p = s; - while (p[0] = p[1]) + while ((p[0] = p[1])) p++; } @@ -496,7 +441,7 @@ void no2slash(char *name) while (s[0] =='/' && s[1] == '.' && s[2] == '/') { p = s; - while (p[0] = p[2]) + while ((p[0] = p[2])) p++; } @@ -504,7 +449,7 @@ void no2slash(char *name) if (name[0] == '.' && name[1] == '/') { p = name; - while (p[0] = p[2]) + while ((p[0] = p[2])) p++; } @@ -523,8 +468,10 @@ void make_dirstr(char *s, int n, char *d) { for(x=0,f=0;s[x];x++) { if((d[x] = s[x]) == '/') if((++f) == n) { - d[x] = '\0'; - return; + if(x == 0) + x++; + d[x] = '\0'; + return; } } d[x] = '\0'; @@ -602,7 +549,8 @@ void getline_timed_out(int sig) { char errstr[MAX_STRING_LEN]; - sprintf(errstr,"timed out waiting for %s", gCurrentRequest->remote_name); + sprintf(errstr,"timed out waiting for %s", + gCurrentRequest->remote_name ? gCurrentRequest->remote_name : "-"); log_error(errstr,gCurrentRequest->hostInfo->error_log); if (!standalone) { fclose(stdin); @@ -617,60 +565,115 @@ void getline_timed_out(int sig) } } -int getline(int sd, char *s, int n, int reset, unsigned int timeout) +sock_buf *new_sock_buf(per_request *reqInfo, int sd) +{ + sock_buf *tmp; + if (!(tmp = (sock_buf *)malloc(sizeof(sock_buf)))) { + die(reqInfo,SC_NO_MEMORY,"new_sock_buf"); + } + tmp->status = SB_NEW; + tmp->sd = sd; + + return tmp; +} + +/* Modified by Trung Dung (tdung@OpenMarket.com) to handle RFC822 + * line wraps + * This routine is currently not thread safe. + * This routine may be thread safe. (blong 3/13/96) + */ +int getline(sock_buf *sb, char *s, int n, int options, unsigned int timeout) { char *endp = s + n - 1; int have_alarmed = 0; - static int buf_posn, buf_good; +/* static int buf_posn, buf_good; */ int buf_start; - static char buffer[HUGE_STRING_LEN]; +/* static char buffer[HUGE_STRING_LEN]; */ int c; int ret; + int size; - buf_start = buf_posn; - if (reset == 1) { - buf_start = buf_posn = buf_good = 0; - buffer[0] = '\0'; + buf_start = sb->buf_posn; + if ((options & G_RESET_BUF) || (sb->status == SB_NEW)) { + buf_start = sb->buf_posn = sb->buf_good = 0; + sb->buffer[0] = '\0'; } - else if (reset == 2) { - while (buf_posn < buf_good) - *s++ = buffer[buf_posn++]; + else if (options & G_FLUSH) { + while (sb->buf_posn < sb->buf_good) + *s++ = sb->buffer[(sb->buf_posn)++]; *s = '\0'; - return buf_posn - buf_start; + sb->status = SB_FLUSHED; + return sb->buf_posn - buf_start; + } + if (options & G_SINGLE_CHAR) { + size = 1; + } else { + size = HUGE_STRING_LEN; } do { - if (buf_posn == buf_good) { + if (sb->buf_posn == sb->buf_good) { have_alarmed = 1; signal(SIGALRM,getline_timed_out); alarm(timeout); - - if ((ret=read(sd, buffer, HUGE_STRING_LEN)) <= 0) { + + ret=read(sb->sd, sb->buffer, size); + + if (ret <= 0) { if (ret == -1 && errno == EINTR) continue; /* Solaris... */ else { + sb->status = SB_ERROR; if (have_alarmed) { alarm(0); signal(SIGALRM,SIG_IGN); } /* just always return -1, instead of 0 */ return -1; } } + sb->status = SB_READ; + + sb->buf_good = ret; + buf_start -= sb->buf_posn; + sb->buf_posn = 0; + + /* ADC hack below ZZZ */ +/* + if (ret >0) { + for (c = 0; c < ret; c++) + fputc(sb->buffer[c],stderr); + c = 0; + } +*/ - buf_good = ret; - buf_start -= buf_posn; - buf_posn = 0; } - c = buffer[buf_posn++]; - - if (c == LF) break; - if (c != CR) *s++ = c; + c = sb->buffer[(sb->buf_posn)++]; + if ((c == '\r') && (sb->buf_posn + 1 < sb->buf_good) && + (sb->buffer[sb->buf_posn] == '\n') && + ((sb->buffer[sb->buf_posn + 1] == ' ') || + (sb->buffer[sb->buf_posn + 1] == '\t'))) + { + *s++ = c; + *s++ = '\n'; + *s++ = sb->buffer[sb->buf_posn + 1]; + sb->buf_posn += 2; + } + else if ((c == '\n') && (sb->buf_posn < sb->buf_good) && + ((sb->buffer[sb->buf_posn] == ' ') || + (sb->buffer[sb->buf_posn] == '\t'))) + { + *s++ = '\n'; + *s++ = sb->buffer[sb->buf_posn]; + sb->buf_posn += 1; + } + else if (c == LF) break; + else if (c != CR) *s++ = c; } while (s < endp); if (have_alarmed) { alarm(0); signal(SIGALRM,SIG_IGN); } *s = '\0'; - - return buf_posn - buf_start; + + return sb->buf_posn - buf_start; } void splitURL(char *line, char *url, char *args) { @@ -760,7 +763,7 @@ void escape_shell_cmd(char *cmd) { l=strlen(cmd); for(x=0;cmd[x];x++) { - if(ind("&;`'\"|*?~<>^()[]{}$\\",cmd[x]) != -1){ + if(ind("&;`'\"|*?~<>^()[]{}$\\\x0A",cmd[x]) != -1){ for(y=l+1;y>x;y--) cmd[y] = cmd[y-1]; l++; /* length has been increased */ @@ -1039,14 +1042,14 @@ uid_t uname2id(char *name) { { if (!scan_long (&name[1], &id)) { - fprintf(stderr,"httpd: bad user id %s\n",name); + fprintf(stderr,"HTTPd: bad user id %s\n",name); exit(1); } return (uid_t) id ; } if(!(ent = getpwnam(name))) { - fprintf(stderr,"httpd: bad user name %s\n",name); + fprintf(stderr,"HTTPd: bad user name %s\n",name); exit(1); } return(ent->pw_uid); @@ -1060,14 +1063,14 @@ gid_t gname2id(char *name) { { if (!scan_long (&name[1], &id)) { - fprintf(stderr,"httpd: bad group id %s\n",name); + fprintf(stderr,"HTTPd: group id %s\n",name); exit(1); } return (gid_t) id ; } if(!(ent = getgrnam(name))) { - fprintf(stderr,"httpd: bad group name %s\n",name); + fprintf(stderr,"HTTPd: bad group name %s\n",name); exit(1); } return(ent->gr_gid); @@ -1102,8 +1105,6 @@ int get_remote_host_min(per_request *reqInfo) { struct in_addr *iaddr; struct hostent *hptr; - reqInfo->ownDNS = TRUE; - len = sizeof(struct sockaddr); if ((getpeername(reqInfo->connection_socket, &addr, &len)) < 0) { @@ -1113,14 +1114,20 @@ int get_remote_host_min(per_request *reqInfo) { iaddr = &(((struct sockaddr_in *)&addr)->sin_addr); hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET); if(hptr) { - if (reqInfo->remote_host) free(reqInfo->remote_host); - reqInfo->remote_host = strdup(hptr->h_name); + if (reqInfo->remote_host) { + freeString(reqInfo->remote_host); + } + reqInfo->remote_host = dupStringP(hptr->h_name,STR_REQ); str_tolower(reqInfo->remote_host); - if (reqInfo->remote_name) free(reqInfo->remote_name); - reqInfo->remote_name = strdup(reqInfo->remote_host); + if (reqInfo->remote_name) { + freeString(reqInfo->remote_name); + } + reqInfo->remote_name = dupStringP(reqInfo->remote_host,STR_REQ); } else { /* shouldn't be necessary, but just in case */ - if (reqInfo->remote_host) free(reqInfo->remote_host); + if (reqInfo->remote_host) { + freeString(reqInfo->remote_host); + } reqInfo->remote_host = NULL; } reqInfo->dns_host_lookup = TRUE; @@ -1134,15 +1141,13 @@ void get_remote_host(per_request *reqInfo) struct in_addr *iaddr; struct hostent *hptr; - reqInfo->ownDNS = TRUE; - len = sizeof(struct sockaddr); if ((getpeername(reqInfo->connection_socket, &addr, &len)) < 0) { - reqInfo->remote_name = strdup("UNKNOWN_HOST"); - reqInfo->remote_ip = strdup("UNKNOWN_IP"); - reqInfo->remote_host = strdup("UNKNOWN_HOST"); - return; + reqInfo->remote_name = dupStringP("UNKNOWN_HOST",STR_REQ); + reqInfo->remote_ip = dupStringP("UNKNOWN_IP",STR_REQ); + reqInfo->remote_host = dupStringP("UNKNOWN_HOST",STR_REQ); + return; } iaddr = &(((struct sockaddr_in *)&addr)->sin_addr); @@ -1151,14 +1156,18 @@ void get_remote_host(per_request *reqInfo) { hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET); if(hptr) { - reqInfo->remote_host = strdup(hptr->h_name); + reqInfo->remote_host = dupStringP(hptr->h_name,STR_REQ); str_tolower(reqInfo->remote_host); - if (reqInfo->remote_name) free(reqInfo->remote_name); - reqInfo->remote_name = strdup(reqInfo->remote_host); + if (reqInfo->remote_name) { + freeString(reqInfo->remote_name); + } + reqInfo->remote_name = dupStringP(reqInfo->remote_host,STR_REQ); } else reqInfo->remote_host = NULL; reqInfo->dns_host_lookup = TRUE; - } else + } else { + if (reqInfo->remote_host != NULL) freeString(reqInfo->remote_host); reqInfo->remote_host = NULL; + } if (reqInfo->hostInfo->dns_mode == DNS_MAX) { /* Grrr. Check THAT name to make sure it's really the name of the addr. */ @@ -1175,18 +1184,20 @@ void get_remote_host(per_request *reqInfo) } if((!hptr) || (!(*haddr))) if (reqInfo->remote_host) { - free(reqInfo->remote_host); + freeString(reqInfo->remote_host); reqInfo->remote_host = NULL; } } } - reqInfo->remote_ip = strdup(inet_ntoa(*iaddr)); + reqInfo->remote_ip = dupStringP(inet_ntoa(*iaddr),STR_REQ); if(!reqInfo->remote_host){ - if (reqInfo->remote_name) free(reqInfo->remote_name); - reqInfo->remote_name = strdup(reqInfo->remote_ip); + if (reqInfo->remote_name) { + freeString(reqInfo->remote_name); + } + reqInfo->remote_name = dupStringP(reqInfo->remote_ip,STR_REQ); } if (!reqInfo->remote_name){ - reqInfo->remote_name = strdup("UNKNOWN_HOST"); + reqInfo->remote_name = dupStringP("UNKNOWN_HOST",STR_REQ); } } @@ -1228,7 +1239,7 @@ void get_local_host() gethostname(str, len); if((!(p=gethostbyname(str))) || (!(gConfiguration->server_hostname = find_fqdn(p)))) { - fprintf(stderr,"httpd: cannot determine local host name.\n"); + fprintf(stderr,"HTTPd: cannot determine local host name.\n"); fprintf(stderr,"Use ServerName to set it manually.\n"); exit(1); } @@ -1251,13 +1262,18 @@ void get_local_addr(per_request *reqInfo) { sizeof(struct in_addr)); } -void construct_url(char *full_url, per_host *host, char *url) { -/* Since 80 is default port */ - if (port == 80) { - sprintf(full_url,"http://%s%s",host->server_hostname,url); - } else { - sprintf(full_url,"http://%s:%d%s",host->server_hostname,port,url); - } +/* Modified: Tue Sep 5 23:18:01 1995 + * This function now understands the "https" directive and the + * default SSL port of 443. + */ +void construct_url(char *full_url, per_host *host, char *url) +{ + { + if (port == DEFAULT_PORT) + sprintf(full_url,"%s://%s%s", "http",host->server_hostname,url); + else + sprintf(full_url,"%s://%s:%d%s", "http",host->server_hostname,port,url); + } } /* aaaack but it's fast and const should make it shared text page. */ diff --git a/src/util.h b/src/util.h index 2ba62f2..41f78e1 100644 --- a/src/util.h +++ b/src/util.h @@ -10,7 +10,7 @@ * ************************************************************************ * - * util.h,v 1.14 1995/11/28 09:02:22 blong Exp + * util.h,v 1.18 1996/03/27 20:44:32 blong Exp * ************************************************************************ * @@ -24,6 +24,12 @@ #include #include +/* getline options */ +#define G_RESET_BUF 1 +#define G_FLUSH 2 +#define G_SINGLE_CHAR 4 + + /* util function prototypes */ void inststr(char *dst[], int argc, char *src); void initproctitle(char *start, int argc, char **argv, char **envp); @@ -43,7 +49,8 @@ void getparents(char *name); void no2slash(char *name); uid_t uname2id(char *name); gid_t gname2id(char *name); -int getline(int sd, char *s, int n, int reset, unsigned int timeout); +int getline(sock_buf *sb, char *s, int n, int options, unsigned int timeout); +sock_buf *new_sock_buf(per_request *reqInfo, int sd); int eat_ws (FILE* fp); int cfg_getline(char *s, int n, FILE *f); void getword(char *word, char *line, char stop); diff --git a/support/Makefile b/support/Makefile old mode 100755 new mode 100644 index f868719..26c65eb --- a/support/Makefile +++ b/support/Makefile @@ -27,7 +27,7 @@ INCLUDES = -I../src #-------------------------------------------------------------------------- SUPPORT = htpasswd unescape inc2shtml htdigest dbm2std std2dbm dbmdigest \ - dbmgroup dbmpasswd + dbmgroup dbmpasswd webgrab .c.o: $(CC) -c $(CFLAGS) $(INCLUDES) $< @@ -60,6 +60,9 @@ next: osf1: make all CC=cc CFLAGS="-DOSF1" +sco5: + make all CC=cc CFLAGS="-DSCO5" EXTRA_LIBS="-ldbm -lsocket" + sgi4: make all CC=cc CFLAGS="-DIRIX -DHEAD_GETPASS" @@ -67,14 +70,14 @@ sgi5: make all CC=cc CFLAGS="-DIRIX" solaris: - make all CC=gcc CFLAGS="-DSOLARIS2" + make all CC=gcc CFLAGS="-DSOLARIS2" EXTRA_LIBS="-lnsl -lsocket" sunos: make all CC=gcc CFLAGS="-DSUNOS" svr4: make all CC=cc CFLAGS="-I/usr/include -I/usr/ucbinclude -DSVR4" \ - EXTRA_LIBS="-lc -L/usr/ucblib -ldbm -lucb" + EXTRA_LIBS="-lc -L/usr/ucblib -ldbm -lucb -lnsl -lsocket" ultrix: make all CC=gcc CFLAGS="-DULTRIX" @@ -114,6 +117,8 @@ unescape: unescape.c inc2shtml: inc2shtml.c $(CC) $(CFLAGS) $(INCLUDES) inc2shtml.c -o inc2shtml +webgrab: webgrab.c + $(CC) $(CFLAGS) $(INCLUDES) webgrab.c -o webgrab $(EXTRA_LIBS) clean: rm -f $(SUPPORT) $(DIGESTOBJS) tags TAGS *.o diff --git a/support/webgrab.c b/support/webgrab.c new file mode 100644 index 0000000..b254c49 --- /dev/null +++ b/support/webgrab.c @@ -0,0 +1,205 @@ +/***************************************************************************\ + * webgrab - v1.0 - Copyright 1995, Brian J. Swetland * + * * + * Free for any personal or non-comercial use. Use at your own risk. * +\***************************************************************************/ + +#include +#include + +#ifdef __bsdi__ +# include +#else +# ifndef NeXT +# include +# endif +#endif + +#include +#include + +#include +#include +#include +#include + +#include + +#define VERSION "1.3" + +/* strdup isn't portable, so we make our own. */ +char *strd(char *s) { + char *d; + + d=(char *)malloc(strlen(s) + 1); + strcpy(d,s); + return(d); +} + +/* parses URL looking like blah://host[:port][/path] + will ignore anything before the first : and terminate path when it + hits >, ", or whitespace -- returns portno or 0 if bad url */ + +int parseURL(char *url, char **host, char **path) +{ + char *p, *pp; + int port; + + p = url; + + /* skip anything up to the first : (the one after http, etc) */ + while(*p && *p!=':') p++; + if(!*p) + return 0; + + /* REQUIRE two '/'s */ + if(!(*(++p) && (*p =='/') && *(++p) && (*p == '/'))) + return 0; + + p++; + + /* mark the beginning of the hostname */ + pp = p; + /* hostname is terminated by a '/' or '>','"',or whitespace */ + while(*p && *p!=':' && *p!='/' && *p!='"' && *p!='>' && !isspace(*p)) + p++; + + *host = (char *) malloc(p-pp+1); + strncpy(*host,pp,p-pp); + (*host)[p-pp]=0; + + /* optionally read a portnumber */ + if(*p==':'){ + p++; + port = 0; + while(*p && isdigit(*p)){ + port = port*10 + (*p-'0'); + p++; + } + if(!*p || *p!='/') { + free(*host); + return 0; + } + } else { + port = 80; + } + + /* still more */ + if(*p && (*p=='/')){ + pp = p; + while(*p && *p!='"' && *p!='>' && !isspace(*p)) p++; + *p = 0; + *path = strd(pp); + } else { + *path = strd("/"); + } + return port; +} + +void usage(char *argv) +{ + printf("\nWebgrab: The Command Line Browser\tVersion %s \n",VERSION); + printf("Usage: %s [-shr] \n",argv); + printf("\t-s\t: Suppress Headers\n"); + printf("\t-h\t: Headers Only\n"); + printf("\t\t: URL to retrieve (in http:// format)\n"); + printf("\t-r\t: Read HTTP headers from stdin\n\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int s, i, port; + struct sockaddr_in sa; + struct hostent *hp; + FILE *fpo,*fpi; + char buf[1024]; + char *path,*host; + int ignore=0,head=0,readin=0; + + if(argc<2 || (argv[1][0]=='-'&&argc<3)){ + usage(argv[0]); + } + + if(argv[1][0]=='-'){ + for(path=&argv[1][1];*path;path++) + switch(*path){ + case 'r': + readin = 1; + break; + case 's': + ignore = 1; + break; + case 'h': + head = 1; + break; + } + s = 2; + } else { + s = 1; + } + + if(!(port=parseURL(argv[s], &host, &path))){ + fprintf(stderr,"error: invalid url\n"); + exit(1); + } + + /* find the server */ + if(!(hp = gethostbyname(host))) { + fprintf(stderr,"error: can't get host %s.\n",host); + exit(1); + } + + /* Setup the socket */ +/* bzero((char *)&sa, sizeof(sa)); */ + memset(&sa, 0, sizeof(sa)); + sa.sin_port = htons(port); +/* bcopy((char *)hp->h_addr, (char *)&sa.sin_addr, hp->h_length); */ + memcpy((char *)&sa.sin_addr, (char *)hp->h_addr, hp->h_length); + sa.sin_family = hp->h_addrtype; + + /* allocate the socket */ + if((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0){ + fprintf(stderr,"error: can't get socket\n"); + exit(1); + } + + /* connect to the server */ + if(connect(s, &sa, sizeof(sa)) < 0){ + close(s); + fprintf(stderr,"error: can't connect\n"); + exit(1); + } + + fpo = fdopen(s,"w"); + fpi = fdopen(s,"r"); + fprintf(fpo,"%s %s HTTP/1.0\r\n",head?"HEAD":"GET",path); + if (readin) { + /* copy headers from stdin ... */ + while(!feof(stdin)){ + i = fread(buf,1,1024,stdin); + if(i) fwrite(buf,1,i,fpo); + if(feof(stdin)) break; + } + } else { + /* send our normal header info */ + fputs("User-Agent: WebGrab/1.2 (commandline forever)\r\n",fpo); + } + fputs("\r\n",fpo); + fflush(fpo); + + /* IGNORE HEADERS */ + while(!feof(fpi)){ + fgets(buf,1024,fpi); + if(!ignore) fprintf(stdout,"%s",buf); + if(feof(fpi) || buf[0]<' ') break; + } + while(!feof(fpi)){ + i = fread(buf,1,1024,fpi); + if(i) fwrite(buf,1,i,stdout); + if(feof(fpi)) break; + } + close(s); + exit(0); +} +