diff options
author | Bob Beck <beck@cvs.openbsd.org> | 1998-10-01 17:25:55 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 1998-10-01 17:25:55 +0000 |
commit | 7a676a0ec6f795fb90ee4e61331a193516dc7f9d (patch) | |
tree | 3432bf197181bc72107d241251c7e25ee4db6060 /usr.sbin/httpd | |
parent | 44becabb19680fe2222a8dbb4374ec6ca8ffa42e (diff) |
unused files, thanks to apache souce tree transmogrification..
Diffstat (limited to 'usr.sbin/httpd')
80 files changed, 0 insertions, 39982 deletions
diff --git a/usr.sbin/httpd/CHANGES b/usr.sbin/httpd/CHANGES deleted file mode 100644 index 4f36295a07b..00000000000 --- a/usr.sbin/httpd/CHANGES +++ /dev/null @@ -1,128 +0,0 @@ - OVERVIEW OF NEW FEATURES IN APACHE 1.2 - -New features with this release, as extensions of the Apache functionality -For more information, see the documentation included with this release -(htdocs/manual/) or http://www.apache.org/docs/ - -In addition to a number of bug fixes and internal performance -enhancements, Apache 1.2 has the following specific new user -features: - - - *) HTTP/1.1 Compliance - Aside from the optional proxy module (which operates as HTTP/1.0), - Apache is conditionally compliant with the HTTP/1.1 proposed standard, - as approved by the IESG and the IETF HTTP working group. - HTTP/1.1 provides a much-improved protocol, and should allow for - greater performance and efficiency when transferring files. Apache - does, however, still work great with HTTP/1.0 browsers. We are very - close to being unconditionally compliant; if you note any deviance - from the proposed standard, please report it as a bug. - - *) eXtended Server Side Includes (XSSI) - A new set of server-side include directives allows the user to - better create WWW pages. This includes number of powerful new - features, such as the ability to set variables and use conditional - HTML. - - *) File-based and Regex-enabled Directive Sections - The new <Files> section allows directives to be enabled based on - full filename, not just directory and URL. In addition, <Files> - sections can appear in .htaccess files. <Files>, along with - <Directory> and <Location>, can also now be based on regular - expressions, not just simple prefix matching. - - *) Browser-based Environment Variables - Environment variables can now be set based on the User-Agent - string of the browser. Combined with XSSI, this allows you to - write browser-based conditional HTML documents. - - *) SetUID CGI Execution - Apache now supports the execution of CGI scripts as users other - than the server user. A number of security checks are built in to - try and make this as safe as possible. - - *) URL Rewriting Module - The optional mod_rewrite module is now included. This module can - provide powerful URL mapping, using regular expressions. There's - nothing this module can't do! - - *) Enhanced, Configurable Logging - The optional mod_log_config included with earlier versions of - Apache is now standard, and has been enhanced to allow logging of - much more detail about the transaction, and can be used to open - more than one log at once (each of which can have a different log - format). - - *) User Tracking (Cookies) Revisions - The mod_cookies included with previous versions of Apache has been - renamed mod_usertrack, to more accurately reflect its function - (some people inadvertently thought it enabled cookie support in - Apache, which is not true - Apache supports the use of cookies - directly). It is also now possible to disable the generation of - cookies, even when the cookie module is compiled in. Also, an - expiry time can be set on the cookies. - - *) Multiple IPs in <VirtualHost> - The <VirtualHost> directive can now take more than one IP address - or hostname. This lets a single vhost handles requests for - multiple IPs or hostnames. - - *) CGI Debugging Environment - ScriptLog allows you to now set up a log that records all input - and output to failed CGI scripts. This includes environment - variables, input headers, POST data, output, and more. This makes - CGI scripts much easier to debug. - - *) Resource Limits for CGI Scripts - New directives allow the limiting of resources used by CGI scripts - (e.g. max CPU time). This is helpful in preventing 'runaway' CGI - processes. - - *) Redirect Directive Can Return Alternate Status - The Redirect directive can return permanent or temporary redirects, - "Gone" or "See Other" HTTP status. For NCSA-compatibility, - RedirectTemp and RedirectPermanent are also implemented. - - *) Graceful Restarts - Apache can re-read the config files and re-open log files without - terminating transactions in progress. - - *) Simplified Compilation - The process of configuring Apache for compilation has been - simplified. - - *) Add or Remove Options - The Options directive can now add or remove options from those - currently in force, rather than always replacing them. - - *) Command-line Help - The -h command-line option now lists all the available directives. - - *) Optional Headers Module to Set or Remove HTTP Headers - The optional mod_headers module can be used to set custom headers - in the HTTP response. It can append to existing headers, replace - them, or remove headers from the response. - - *) Conditional Config Directives - A new <IfModule> section allows directives to be enabled only if a - given module is loaded into the server. - - *) Authorization Directives Now Use NCSA-style Syntax - The AuthUserFile, AuthGroupFile and AuthDigestFile commands now - have a syntax compatible with the NCSA server. - - *) Optional Proxy Module - An improved FTP, HTTP, and CONNECT mode SSL proxy is included with - Apache 1.2. Some of the changes visible to users: - - - Improved FTP proxy supporting PASV mode - - CONNECT mode ports are configurable from a list - - NoCache * directive for disabling proxy caching - - Numerous bug fixes - - *) Optional Example Module - An example module that demonstrates many of the aspects of the - API is now included with Apache as of version 1.2. It can be - used as a base for those who wish to write their own Apache - modules. diff --git a/usr.sbin/httpd/Makefile b/usr.sbin/httpd/Makefile deleted file mode 100644 index 0cb40323986..00000000000 --- a/usr.sbin/httpd/Makefile +++ /dev/null @@ -1,116 +0,0 @@ -MAN = httpd.8 -SUBDIR+=src -WWWROOT=/var/www -CONFFILES= \ - conf/srm.conf-dist conf/access.conf-dist conf/httpd.conf-dist \ - conf/mime.types conf/access.conf conf/httpd.conf conf/srm.conf -HTDOCS= \ - htdocs/apache_pb.gif htdocs/index.html htdocs/openbsdpower.gif -CGIFILES= \ - cgi-bin/printenv cgi-bin/test-cgi -MANUALFILES= \ - manual/images/home.gif manual/images/index.gif \ - manual/images/sub.gif manual/misc/API.html \ - manual/misc/known_bugs.html manual/misc/FAQ.html \ - manual/misc/known_client_problems.html \ - manual/misc/client_block_api.html manual/misc/nopgp.html \ - manual/misc/compat_notes.html manual/misc/perf-bsd44.html \ - manual/misc/descriptors.html manual/misc/perf-dec.html \ - manual/misc/fin_wait_2.html manual/misc/perf.html \ - manual/misc/footer.html manual/misc/security_tips.html \ - manual/misc/header.html manual/misc/vif-info.html \ - manual/misc/howto.html manual/misc/windoz_keepalive.html \ - manual/LICENSE manual/host.html manual/multilogs.html \ - manual/TODO manual/new_features_1_0.html \ - manual/bind.html manual/index.html \ - manual/new_features_1_1.html manual/cgi_path.html \ - manual/install.html manual/new_features_1_2.html \ - manual/content-negotiation.html manual/install_1_1.html \ - manual/process-model.html manual/custom-error.html \ - manual/invoking.html manual/stopping.html \ - manual/dns-caveats.html manual/keepalive.html \ - manual/suexec.html manual/env.html manual/location.html \ - manual/unixware.html manual/footer.html \ - manual/man-template.html manual/vhosts-in-depth.html \ - manual/handler.html manual/virtual-host.html \ - manual/header.html manual/mod/core.html \ - manual/mod/mod_auth_msql.html manual/mod/mod_include.html \ - manual/mod/directives.html manual/mod/mod_browser.html \ - manual/mod/mod_info.html manual/mod/footer.html \ - manual/mod/mod_cern_meta.html manual/mod/mod_log_agent.html \ - manual/mod/header.html manual/mod/mod_cgi.html \ - manual/mod/mod_log_common.html manual/mod/index.html \ - manual/mod/mod_cookies.html manual/mod/mod_log_config.html \ - manual/mod/mod_access.html manual/mod/mod_digest.html \ - manual/mod/mod_log_referer.html manual/mod/mod_actions.html \ - manual/mod/mod_dir.html manual/mod/mod_mime.html \ - manual/mod/mod_alias.html manual/mod/mod_dld.html \ - manual/mod/mod_negotiation.html manual/mod/mod_asis.html \ - manual/mod/mod_env.html manual/mod/mod_proxy.html \ - manual/mod/mod_auth.html manual/mod/mod_example.html \ - manual/mod/mod_rewrite.html manual/mod/mod_auth_anon.html \ - manual/mod/mod_expires.html manual/mod/mod_status.html \ - manual/mod/mod_auth_db.html manual/mod/mod_headers.html \ - manual/mod/mod_userdir.html manual/mod/mod_auth_dbm.html \ - manual/mod/mod_imap.html manual/mod/mod_usertrack.html -ICONFILES= \ - icons/README icons/c.gif icons/hand.right.gif icons/pie2.gif \ - icons/sphere1.gif icons/a.gif icons/comp.blue.gif \ - icons/hand.up.gif icons/pie3.gif icons/sphere2.gif \ - icons/alert.black.gif icons/comp.gray.gif icons/icon.sheet.gif \ - icons/pie4.gif icons/tar.gif icons/alert.red.gif \ - icons/compressed.gif icons/image1.gif icons/pie5.gif \ - icons/tex.gif icons/apache_pb.gif icons/continued.gif \ - icons/image2.gif icons/pie6.gif icons/text.gif icons/back.gif \ - icons/dir.gif icons/image3.gif icons/pie7.gif \ - icons/transfer.gif icons/ball.gray.gif icons/down.gif \ - icons/index.gif icons/pie8.gif icons/unknown.gif \ - icons/ball.red.gif icons/dvi.gif icons/layout.gif \ - icons/portal.gif icons/up.gif icons/binary.gif icons/f.gif \ - icons/left.gif icons/ps.gif icons/uu.gif icons/binhex.gif \ - icons/folder.gif icons/link.gif icons/quill.gif \ - icons/uuencoded.gif icons/blank.gif icons/folder.open.gif \ - icons/movie.gif icons/right.gif icons/world1.gif \ - icons/bomb.gif icons/folder.sec.gif icons/p.gif \ - icons/screw1.gif icons/world2.gif icons/box1.gif \ - icons/forward.gif icons/patch.gif icons/screw2.gif \ - icons/box2.gif icons/generic.gif icons/pdf.gif \ - icons/script.gif icons/broken.gif icons/generic.red.gif \ - icons/pie0.gif icons/sound1.gif icons/burst.gif \ - icons/generic.sec.gif icons/pie1.gif icons/sound2.gif - -distribution: - @-for i in ${CONFFILES}; do \ - j=`dirname $$i`; \ - echo "Installing ${DESTDIR}${WWWROOT}/$$i"; \ - ${INSTALL} ${INSTALL_COPY} -g ${BINGRP} -m 444 \ - ${.CURDIR}/$$i ${DESTDIR}${WWWROOT}/$$j/; \ - done - @-for i in ${HTDOCS}; do \ - j=`dirname $$i`; \ - echo "Installing ${DESTDIR}${WWWROOT}/$$i"; \ - ${INSTALL} ${INSTALL_COPY} -g ${BINGRP} -m 444 \ - ${.CURDIR}/$$i ${DESTDIR}${WWWROOT}/$$j/; \ - done - @-for i in ${MANUALFILES}; do \ - j=`dirname $$i`; \ - echo "Installing ${DESTDIR}${WWWROOT}/$$i"; \ - ${INSTALL} ${INSTALL_COPY} -g ${BINGRP} -m 444 \ - ${.CURDIR}/htdocs/$$i ${DESTDIR}${WWWROOT}/htdocs/$$j/; \ - done - @-for i in ${CGIFILES}; do \ - j=`dirname $$i`; \ - echo "Installing ${DESTDIR}${WWWROOT}/$$i"; \ - ${INSTALL} ${INSTALL_COPY} -g ${BINGRP} -m 000 \ - ${.CURDIR}/$$i ${DESTDIR}${WWWROOT}/$$j/; \ - done - @-for i in ${ICONFILES}; do \ - j=`dirname $$i`; \ - echo "Installing ${DESTDIR}${WWWROOT}/$$i"; \ - ${INSTALL} ${INSTALL_COPY} -g ${BINGRP} -m 444 \ - ${.CURDIR}/$$i ${DESTDIR}${WWWROOT}/$$j/; \ - done - -.include<bsd.obj.mk> -.include<bsd.subdir.mk> -.include<bsd.man.mk> diff --git a/usr.sbin/httpd/htdocs/manual/TODO b/usr.sbin/httpd/htdocs/manual/TODO deleted file mode 100644 index 975ac8e68ea..00000000000 --- a/usr.sbin/httpd/htdocs/manual/TODO +++ /dev/null @@ -1,4 +0,0 @@ -Documentation changes/enhancements needed: - -- Documentation for mod_expires -- Documentation for Satisfy diff --git a/usr.sbin/httpd/htdocs/manual/host.html b/usr.sbin/httpd/htdocs/manual/host.html deleted file mode 100644 index 74639a5b5fb..00000000000 --- a/usr.sbin/httpd/htdocs/manual/host.html +++ /dev/null @@ -1,185 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html><head> -<title>Apache non-IP Virtual Hosts</title> -</head> - -<!-- Background white, links blue (unvisited), navy (visited), red (active) --> -<BODY - BGCOLOR="#FFFFFF" - TEXT="#000000" - LINK="#0000FF" - VLINK="#000080" - ALINK="#FF0000" -> -<DIV ALIGN="CENTER"> - <IMG SRC="images/sub.gif" ALT="[APACHE DOCUMENTATION]"> - <H3> - Apache HTTP Server Version 1.2 - </H3> -</DIV> - -<h1 ALIGN="CENTER">Apache non-IP Virtual Hosts</h1> - -<strong>See Also:</strong> -<a href="virtual-host.html">Virtual Host Support</a> - -<hr> - -<h2>What is a Virtual Host</h2> - -<p>The "Virtual Host" refers to the practice of maintaining more than -one server on one machine, as differentiated by their apparent -hostname. For example, it is often desirable for companies sharing a -web server to have their own domains, with web servers accessible as -<code>www.company1.com</code> and <code>www.company2.com</code>, -without requiring the user to know any extra path information.</p> - -<p>Apache was one of the first servers to support virtual hosts right -out of the box, but since the base <code>HTTP</code> (HyperText -Transport Protocol) standard does not allow any method for the server -to determine the hostname it is being addressed as, Apache's virtual -host support has required a separate IP address for each -server. Documentation on using this approach (which still works very -well) <a href="virtual-host.html">is available</a>. - -<p>While the approach described above works, with the available IP -address space growing smaller, and the number of domains increasing, -it is not the most elegant solution, and is hard to implement on some -machines. The <code>HTTP/1.1</code> protocol contains a method for the -server to identify what name it is being addressed as. Apache 1.1 and -later support this approach as well as the traditional -IP-address-per-hostname method.</p> - -<p>The benefits of using the new virtual host support is a practically -unlimited number of servers, ease of configuration and use, and -requires no additional hardware or software. The main disadvantage is -that the user's browser must support this part of the protocol. The -latest versions of many browsers (including Netscape Navigator 2.0 and -later) do, but many browsers, especially older ones, do not. This can -cause problems, although a possible solution is addressed below.</p> - -<h2>Using non-IP Virtual Hosts</h2> - -<p>Using the new virtual hosts is quite easy, and superficially looks -like the old method. You simply add to one of the Apache configuration -files (most likely <code>httpd.conf</code> or <code>srm.conf</code>) -code similar to the following:</p> -<pre> - <VirtualHost www.apache.org> - ServerName www.apache.org - DocumentRoot /usr/web/apache - </VirtualHost> -</pre> - -<p>Of course, any additional directives can (and should) be placed -into the <code><VirtualHost></code> section. To make this work, -all that is needed is to make sure that the <code>www.apache.org</code> -DNS entry points to the same IP address as the main -server. Optionally, you could simply use that IP address in the -<VirtualHost> entry.</p> - -<p>Additionally, many servers may wish to be accessible by more than -one name. For example, the Apache server might want to be accessible -as <code>apache.org</code>, or <code>ftp.apache.org</code>, assuming -the IP addresses pointed to the same server. In fact, one might want it -so that all addresses at <code>apache.org</code> were picked up by the -server. This is possible with the <code>ServerAlias</code> -directive, placed inside the <VirtualHost> section. For -example:</p> - -<pre> - ServerAlias apache.org *.apache.org -</pre> - -<p>Note that you can use <code>*</code> and <code>?</code> as wild-card -characters.</p> - -<p>You also might need ServerAlias if you are serving local users who -do not always include the domain name. For example, if local users are -familiar with typing "www" or "www.physics" then you will need to add -<code>ServerAlias www www.physics</code>. It isn't possible for the -server to know what domain the client uses for their name resolution -because the client doesn't provide that information in the request.</p> - -<h2>Security Considerations</h2> - -Apache allows all virtual hosts to be made accessible via the -<code>Host:</code> header through all IP interfaces, even those which -are configured to use different IP interfaces. For example, if the -configuration for <code>www.foo.com</code> contained a virtual host -section for <code>www.bar.com</code>, and <code>www.bar.com</code> was -a separate IP interface, such that -non-<code>Host:</code>-header-supporting browsers can use it, as -before with Apache 1.0. If a request is made to -<code>www.foo.com</code> and the request includes the header -<code>Host: www.bar.com</code>, a page from <code>www.bar.com</code> -will be sent. - -<P> - -This is a security concern if you are controlling access to a -particular server based on IP-layer controls, such as from within a -firewall or router. Let's say <code>www.bar.com</code> in the above -example was instead an intra-net server called -<code>private.foo.com</code>, and the router used by foo.com only let -internal users access <code>private.foo.com</code>. Obviously, -<code>Host:</code> header functionality now allows someone who has -access to <code>www.foo.com</code> to get -<code>private.foo.com</code>, if they send a <code>Host: -private.foo.com</code> header. It is important to note that this -condition exists only if you only implement this policy at the IP -layer - all security controls used by Apache (i.e., <A -HREF="mod/mod_access.html">allow, deny from,</A> etc.) are consistently -respected. - -<h2>Compatibility with Older Browsers</h2> - -<p>As mentioned earlier, a majority of browsers do not send the -required data for the new virtual hosts to work properly. These -browsers will always be sent to the main server's pages. There is a -workaround, albeit a slightly cumbersome one:</p> - -<p>To continue the <code>www.apache.org</code> example (Note: Apache's -web server does not actually function in this manner), we might use the -new <code>ServerPath</code> directive in the <code>www.apache.org</code> virtual host, -for example: - -<pre> - ServerPath /apache -</pre> -<p>What does this mean? It means that a request for any file beginning -with "<code>/apache</code>" will be looked for in the Apache -docs. This means that the pages can be accessed as -<code>http://www.apache.org/apache/</code> for all browsers, although -new browsers can also access it as -<code>http://www.apache.org/</code>.</p> - -<p>In order to make this work, put a link on your main server's page -to <code>http://www.apache.org/apache/</code> (Note: Do not use -<code>http://www.apache.org/</code> - this would create an endless -loop). Then, in the virtual host's pages, be sure to use either purely -relative links (e.g. "<code>file.html</code>" or -"<code>../icons/image.gif</code>" or links containing the prefacing -<code>/apache/</code> -(e.g. "<code>http://www.apache.org/apache/file.html</code>" or -"<code>/apache/docs/1.1/index.html</code>").</p> - -<p>This requires a bit of -discipline, but adherence to these guidelines will, for the most part, -ensure that your pages will work with all browsers, new and old. When -a new browser contacts <code>http://www.apache.org/</code>, they will -be directly taken to the Apache pages. Older browsers will be able to -click on the link from the main server, go to -<code>http://www.apache.org/apache/</code>, and then access the -pages.</p> - -<HR> -<H3 ALIGN="CENTER"> - Apache HTTP Server Version 1.2 -</H3> - -<A HREF="./"><IMG SRC="images/index.gif" ALT="Index"></A> - -</BODY> -</HTML> - diff --git a/usr.sbin/httpd/htdocs/manual/install_1_1.html b/usr.sbin/httpd/htdocs/manual/install_1_1.html deleted file mode 100644 index f5f0f4d376c..00000000000 --- a/usr.sbin/httpd/htdocs/manual/install_1_1.html +++ /dev/null @@ -1,124 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<HTML> -<HEAD> -<TITLE>Compiling and Installing Apache</TITLE> -</HEAD> - -<!-- Background white, links blue (unvisited), navy (visited), red (active) --> -<BODY - BGCOLOR="#FFFFFF" - TEXT="#000000" - LINK="#0000FF" - VLINK="#000080" - ALINK="#FF0000" -> -<DIV ALIGN="CENTER"> - <IMG SRC="images/sub.gif" ALT="[APACHE DOCUMENTATION]"> - <H3> - Apache HTTP Server Version 1.2 - </H3> -</DIV> - -<h1 ALIGN="CENTER">Compiling and Installing Apache</h1> -<h2>Downloading Apache</h2> -<p>Information on the latest version of Apache can be found on the Apache -web server at http://www.apache.org/. This will list the current release, -any more recent beta-test release, together with details of mirror -web and anonymous ftp sites.</p> - -UnixWare users will want to consult <A HREF="unixware.html">build notes</A> -for various UnixWare versions before compiling. - -<h2>Compiling Apache</h2> -This release of Apache supports the notion of `optional modules'. -However, the server has to know which modules are compiled into it, in -order for those modules to be effective; this requires generation of a -short bit of code (`<code>modules.c</code>') which simply has a list of them. -<p> -If you are satisfied with our standard module set, and expect to -continue to be satisfied with it, then you can just edit the stock -<code>Makefile</code> and compile as you have been doing previously. If you -would -like to select optional modules, however, you need to run the -configuration script. -<p> -To do this: -<ol> -<li>Edit the file `<code>Configuration</code>'. This contains the per-machine -config settings of the Makefile, and also an additional section at -the bottom which lists the modules which have been compiled in, and -also names the files containing them. You will need to: -<ol> -<li> Select a compiler and compilation options as appropriate to -your machine. -<li> Uncomment lines corresponding to those optional modules you wish -to include (among the Module lines at the bottom of the file) -or add new lines corresponding to custom modules you have written. -<p> -Note that DBM auth has to be explicitly configured in, if you want -it; just uncomment the corresponding line. -</ol> -<li> Run the `Configure' script: -<blockquote><code> -% Configure<br> -Using 'Configuration' as config file<br> -%</code></blockquote> - -This generates new versions of the Makefile and of modules.c. If -you want to maintain multiple configurations, you can say, e.g., -<blockquote><code> -% Configure -file Configuration.ai<br> -Using alternate config file Configuration.ai<br> -%</code></blockquote> - -<li>Type `make'. -<p> -The modules we place in the Apache distribution are the ones we have -tested and are used regularly by various members of the Apache -development group. Additional modules contributed by members or third -parties with specific needs or functions are available at -<A HREF="http://www.apache.org/dist/contrib/modules/"><URL:http://www.apache.org/dist/contrib/modules/></A>. There are instructions on that page for -linking these modules into the core Apache code. -</ol> - -<h2>Installing Apache</h2> -After compilation, you will have a binary called `httpd' in the -<code>src/</code> directory. A binary distribution of Apache will supply this -file. -<p> -The next step is to edit the configuration files for the server. In -the subdirectory called `conf' you should find distribution versions -of the three configuration files: <code>srm.conf-dist</code>, -<code>access.conf-dist</code> and <code>httpd.conf-dist</code>. Copy them to -<code>srm.conf</code>, <code>access.conf</code> and <code>httpd.conf</code> -respectively. -<p> -First edit <code>httpd.conf</code>. This sets up general attributes about the -server; the port number, the user it runs as, etc. Next edit the -<code>srm.conf</code> file; this sets up the root of the document tree, -special functions like server-parsed HTML or internal imagemap parsing, etc. -Finally, edit the <code>access.conf</code> file to at least set the base cases -of access. -<p> -Finally, make a call to httpd, with a -f to the full path to the -httpd.conf file. I.e., the common case: -<blockquote><code> - /usr/local/etc/apache/src/httpd -f /usr/local/etc/apache/conf/httpd.conf -</code></blockquote> -The server should be now running. -<p> -By default the <code>srm.conf</code> and <code>access.conf</code> files are -located by name; to specifically call them by other names, use the -<A HREF="mod/core.html#accessconfig">AccessConfig</A> and -<A HREF="mod/core.html#resourceconfig">ResourceConfig</A> directives in -<code>httpd.conf</code>. - -<HR> -<H3 ALIGN="CENTER"> - Apache HTTP Server Version 1.2 -</H3> - -<A HREF="./"><IMG SRC="images/index.gif" ALT="Index"></A> - -</BODY> -</HTML> diff --git a/usr.sbin/httpd/htdocs/manual/misc/known_bugs.html b/usr.sbin/httpd/htdocs/manual/misc/known_bugs.html deleted file mode 100644 index 95bb37c705d..00000000000 --- a/usr.sbin/httpd/htdocs/manual/misc/known_bugs.html +++ /dev/null @@ -1,171 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<HTML> -<HEAD> -<TITLE>Apache HTTP Server Project</TITLE> -</HEAD> - -<!-- Background white, links blue (unvisited), navy (visited), red (active) --> -<BODY - BGCOLOR="#FFFFFF" - TEXT="#000000" - LINK="#0000FF" - VLINK="#000080" - ALINK="#FF0000" -> -<DIV ALIGN="CENTER"> - <IMG SRC="../images/sub.gif" ALT="[APACHE DOCUMENTATION]"> - <H3> - Apache HTTP Server Version 1.2 - </H3> -</DIV> - -<H1 ALIGN="CENTER">Known Bugs in Apache</H1> - -The most up-to-date resource for bug tracking and information is the -<A HREF="http://www.apache.org/bugdb.cgi">Apache bug database</A>. -Significant bugs at release time will also be noted there. -If you are running a 1.2 beta release or version 1.1.3 or earlier -and thing you have found a bug, please upgrade to 1.2. Many bugs -in early versions have been fixed in 1.2. - -<P>See Also: <A HREF="compat_notes.html">Compatibility notes</A></P> -<HR> - -<H2>Apache 1.2 Bugs</H2> - -<OL> - <LI><b>Exists in 1.2.1 only.</b> - On Solaris 2.x the server will stop running after receiving a - SIGHUP. Four workarounds exist (choose one):<p> - <ul> - <li>Retrieve <a href="http://www.apache.org/dist/patches/apply_to_1.2.1/solaris_hup.patch">this patch</a>. - <code>cd</code> to your <code>apache_1.2.1</code> directory, and - type <code>patch -s -p1 < /path/to/patchfile</code>. Then rebuild - Apache.<p> - <li>Use SIGUSR1 instead of SIGHUP, see <a href="../stopping.html"> - Stopping and Restarting Apache</a> for more details.<p> - <li>Add <code>-DNO_SLACK</code> to - <code>EXTRA_CFLAGS</code> in - your <code>Configuration</code> file, re-run <code>Configure</code> - and rebuild your server. This disables the - <a href="descriptors.html">descriptor slack workaround</a><p> - <li>(Least preferable) Use Apache 1.2.0 instead of 1.2.1.<p> - </ul> - This problem will be tracked as - <a href="http://www.apache.org/bugdb.cgi/full/832">PR#832</a>.<p> - </li> - - <LI>(Exists in 1.2.0 and in 1.2.1 after either of the - <code>NO_SLACK</code> or patch provided by the previous bug are applied.) - Solaris 2.5.1 (and probably other versions of Solaris) appear to have - a race condition completely unrelated to all the others. It is possible - during a SIGHUP that the server will fail to start because it will not - be able to re-open its sockets. To our knowledge this has only shown - up during testing when we pummel the server with as many SIGHUP requests - per second as we can. This appears unrelated to the similar sounding bug - described in <a href="http://www.apache.org/bugdb.cgi/full/832">PR#832</a>. - <p> - - <LI><a name="listenbug">On some architectures</A> - if your configuration uses multiple - <a href="../mod/core.html#listen">Listen</a> directives then it is possible - that the server will starve one of the sockets while serving hits on - another. The work-around is to add - <code>-DUSE_FLOCK_SERIALIZED_ACCEPT</code> to the - <code>EXTRA_CFLAGS</code> line in your Configuration and rebuild. - (If you encounter problems with that, you can also try - <code>-DUSE_FCNTL_SERIALIZED_ACCEPT</code>.) - This affects any architecture that doesn't use one of the - <code>USE_xxxxx_SERIALIZED_ACCEPT</code> definitions, see the - source file <code>conf.h</code> for your architecture. - This will be tracked as - <a href="http://www.apache.org/bugdb.cgi/full/467">PR#467</a>. - <P></LI> - - <LI><b>Fixed in 1.2.1.</b> - <a name="cnegbug">Apache's</A> <A HREF="../content-negotiation.html">Content - Negotiation</A> should pick the smallest variant if there - are several that are equally acceptable. A bug in 1.2 means it no - longer does this unless all the variants have character sets. - This <A HREF="../../dist/contrib/patches/1.2/conneg-bug.patch">patch</A> - fixes this problem. It also fixes the problem which makes Apache - pick the last equally acceptable variant instead of the first. - This will be tracked as - <a href="http://www.apache.org/bugdb.cgi/full/94">PR#94</a>. - <P></LI> - - <LI> - The PATH_INFO part of a request URI cannot include the sequence - <CODE>%2f</CODE>. This will be tracked as - <A HREF="http://www.apache.org/bugdb.cgi/full/543">PR#543</A>. - <P></LI> - - <LI>Users of early 1.2 betas reported problems with many - connections stuck in the FIN_WAIT_2 state due to server - timeouts. Several changes were made during the beta testing of 1.2 - to reduce this problem as much as possible, although you may still - see sockets in FIN_WAIT_2 state due to network or operating system - issues outside the control of Apache. See our <A - HREF="fin_wait_2.html">FIN_WAIT_2</A> page for more details. - - <P>SunOS4 has a kernel bug in the allocation of memory for the mbuf table. - When it fills up, the result is a Panic the next time any routine tries - to set something in an imaginary mbuf beyond the range of the table. - Due to buggy browser behavior and the lack of a FIN_WAIT_2 timeout - on SunOS4, "KeepAlive Off" is necessary to avoid filling up the mbuf - table on busy sites. - <P></LI> - - <LI>Compilation fails on SCO3 when using gcc instead of cc, complaining - with "<CODE>gcc: noinline: No such file or directory</CODE>". Fix - is given in <a href="http://www.apache.org/bugdb.cgi/full/695">PR#695</A>. - <P></LI> - - <LI>If compilation fails complaining about "unknown symbol __inet_ntoa()" - then you have probably installed version 8 of bind. You will need to - explicitly link with the bind library by adding <CODE>-lbind</CODE> - to <CODE>EXTRA_LDFLAGS</CODE> in <CODE>Configuration</CODE>. See - <A HREF="http://www.apache.org/bugdb.cgi/full/616">PR#616</A> - and the - <A HREF="FAQ.html#bind8.1">Apache FAQ</A>. - <P></LI> - - <LI>The message "<CODE>created shared memory segment #730499</CODE>" - in error_log is not an error and should be ignored. See - <a href="http://www.apache.org/bugdb.cgi/full/696">PR#696</A>. - <P></LI> - - <LI> - Compiling on Solaris 2 with SunSoft's C compiler gives the warning - <CODE>"mod_include.c", line 1123: warning: end-of-loop code not - reached</CODE>. This is a bogus warning and can be ignored. - See <A HREF="http://www.apache.org/bugdb.cgi/full/681">PR#681</A>. - <P></LI> - - <LI><a href="descriptors.html"><b>Workaround available in 1.2.1.</b></a> - There appears to be a problem on BSDI 2.1 with large numbers of - virtual hosts. This appears similar to a file-descriptor limit - but BSDI should not have this problem. This will be tracked as - <A HREF="http://www.apache.org/bugdb.cgi/full/611">PR#611</A>. - See also the <A HREF="FAQ.html#fdlim">Apache FAQ</A>. - <P></LI> - - <LI><a href="descriptors.html"><b>Workaround available in 1.2.1.</b></a> - Solaris 2 has problems with large numbers of virtual hosts. This is - because of an operating system limit of 256 file pointers, not due - to Apache. See also the <A HREF="FAQ.html#fdlim">Apache FAQ</A>. - <P></LI> - -</OL> - -<HR> -<H3 ALIGN="CENTER"> - Apache HTTP Server Version 1.2 -</H3> - -<A HREF="./"><IMG SRC="../images/index.gif" ALT="Index"></A> -<A HREF="../"><IMG SRC="../images/home.gif" ALT="Home"></A> - -</BODY> -</HTML> - diff --git a/usr.sbin/httpd/htdocs/manual/mod/mod_auth_msql.html b/usr.sbin/httpd/htdocs/manual/mod/mod_auth_msql.html deleted file mode 100644 index 9e85f5d2cdd..00000000000 --- a/usr.sbin/httpd/htdocs/manual/mod/mod_auth_msql.html +++ /dev/null @@ -1,488 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> -<title>Module mod_auth_msql</title> -</head> -<!-- Background white, links blue (unvisited), navy (visited), red (active) --> -<BODY - BGCOLOR="#FFFFFF" - TEXT="#000000" - LINK="#0000FF" - VLINK="#000080" - ALINK="#FF0000" -> -<DIV ALIGN="CENTER"> - <IMG SRC="../images/sub.gif" ALT="[APACHE DOCUMENTATION]"> - <H3> - Apache HTTP Server Version 1.2 - </H3> -</DIV> - -<H1 ALIGN="CENTER">Module mod_auth_msql</H1> - -This module is contained in the <code>mod_auth_msql.c</code> file and -is compiled in by default. It allows access control using the public -domain mSQL database <code><a -href="ftp://ftp.bond.edu.au/pub/Minerva/msql">ftp://ftp.bond.edu.au/pub/Minerva/msql</a></code>, -a fast but limited SQL engine which can be contacted over an internal -Unix domain protocol as well as over normal TCP/IP socket -communication. It is only available in Apache 1.1 and later. <p> - -<a href="#FullDescription">Full description</a> / -<a href="#Example">Example</a> / -<a href="#CompileTimeOptions">Compile time options</a> / -<a href="#RevisionHistory">RevisionHistory</a> / -<a href="#Person">Person to blame</a> / -<a href="#Sourcecode">Sourcecode</a> -<p> - -<hr><h2><a name="FullDescription">Full description of all tokens</a></h2> -<dl> - -<code><dt> -Auth_MSQLhost < FQHN | IP Address | localhost > -</dt></code><dd> - Hostname of the machine running the mSQL demon. The effective uid - of the server should be allowed access. If not given, or if it is - the magic name <code>localhost</code>, it is passed to the mSQL library as a null - pointer. This effectively forces it to use /dev/msql rather than the - (slower) socket communication. -</dd> - -<code><dt> -Auth_MSQLdatabase < mSQL database name > -</dt></code><dd> - Name of the database in which the following table(s) are contained (Quick check: use the - mSQL command <code>relshow [<hostname> dbase]</code> to verify the spelling of the - database name). -</dd> - -<code><dt> -Auth_MSQLpwd_table < mSQL table name > -</dt></code><dd> - Contains at least the fields with the username - and the (encrypted) password. Each uid should only occur once in this table and - for performance reasons should be a primary key. - Normally this table is compulsory, but it is - possible to use a fall-through to other methods - and use the mSQL module for group control only. - See the <a href="#Authoritative"><code>Auth_MSQL_Authoritative</code></a> - directive below. -</dd> - -<code><dt> -Auth_MSQLgrp_table < mSQL table name in the above database > -</dt></code><dd> - Contains at least the fields with the - username and the groupname. A user which - is in multiple groups has therefore - multiple entries. There might be some performance - problems associated with this and one - might consider to have separate tables for each - group (rather than all groups in one table) if - your directory structure allows for it. - One only need to specify this table when doing - group control. -</dd> - -<code><dt> -Auth_MSQLuid_field < mSQL field name > -</dt></code><dd> - Name of the field containing the username in the <code> - Auth_MSQLpwd_table</code> and optionally in the <code> - Auth_MSQLgrp_table</code> tables. -</dd> - -<code><dt> -Auth_MSQLpwd_field < mSQL field name > -</dt></code><dd> - Fieldname for the passwords in the <code> - Auth_MSQLpwd_table</code> table. -</dd> - -<code><dt> -Auth_MSQLgrp_field < mSQL field name > -</dt></code><dd> - Fieldname for the groupname<br> - Only the fields used need to be specified. When this - module is compiled with the - <a href="#VITEK"><code>BACKWARD_VITEK</code></a> option then - the uid and pwd field names default to 'user' and 'password'. - However you are strongly encouraged to always specify these values - explicitly given the security issues involved. -</dd> - -<code><dt> -Auth_MSQL_nopasswd < on | off > -</dt></code><dd> - Skip password comparison if passwd field is - empty, i.e. allow any password. This is 'off' - by default to ensure that an empty field - in the mSQL table does not allow people in by - default with a random password. -</dd> - -<code><dt> -<a name="Authoritative">Auth_MSQL_Authoritative < on | off ></a> -</dt></code><dd> - Default is 'on'. When set 'on', there is no - fall-through to other authorization methods. So if a - user is not in the mSQL dbase table (and perhaps - not in the right group) or has the password wrong, then - he or she is denied access. When this directive is set to - 'off', control is passed on to any other authorization - modules, such as the basic auth module with the htpasswd - file or the Unix-(g)dbm modules. The default is 'on' - to avoid nasty 'fall-through' surprises. Be sure you - know what you are doing when you decide to switch it off. -</dd> - -<code><dt> -Auth_MSQL_EncryptedPasswords < on | off > -</dt></code><dd> - Default is 'on'. When set on, the values in the - pwd_field are assumed to be crypt-ed using *your* - machines 'crypt()' function and the incoming password - is 'crypt'ed before comparison. When this function is - 'off', the comparison is done directly with the plaintext - entered password. (Yes, http-basic-auth does send the - password as plaintext over the wire :-( ). The default - is a sensible 'on', and I personally think that it is - a *very-bad-idea* to change this. However a multi - vendor or international environment (which sometimes - leads to different crypts functions) might force you to. -</dd> -</dl> - - -<hr><h2><a name="Example">Example</a></h2> - -An example mSQL table could be created with the following commands: -<pre> - % msqladmin create www <br> - % msql www <br> - -> create table user_records ( <br> - -> User_id char(32) primary key, <br> - -> Cpasswd char(32), <br> - -> Xgroup char(32) <br> - -> ) \g <br> - query OK <br> - -> \q <br> - % <br> -</pre><br> - -The <code>User_id</code> can be as long as desired. However some of the -popular web browsers truncate names at or stop the user from entering -names longer than 32 characters. Furthermore the 'crypt' function -on your platform might impose further limits. Also use of -the <code>require users uid [uid..]</code> directive in the -<code>access.conf</code> file where the uid's are separated by -spaces can possibly prohibit the use of spaces in your usernames. -Also, please note the <a href="#MAX_FIELD_LEN"><code>MAX_FIELD_LEN</code></a> -directive somewhere below. -<p> -To use the above, the following example could be in your -<code>access.conf</code> file. Also there is a more elaborate description -below this example. -<p> - -<code><directory /web/docs/private></code> -<p> - -<dl> -<dt><code> -Auth_MSQLhost localhost<br> -</code></dt> - <blockquote>or</blockquote> -<dt><code> -Auth_MSQLhost datab.machine.your.org -</code></dt><dd> - If this directive is omitted or set to <code>localhost</code>, - it is assumed that Apache and the mSQL - database run on the same (physical) machine and the faster - /dev/msql communication channel will be used. Otherwise, - it is the machine to contact by TCP/IP. Consult the mSQL - documentation for more information. -</dd> -<p> - -<dt><code> -Auth_MSQLdatabase www -</code></dt><dd> - The name of the database on the above machine, - which contains *both* the tables for group and - for user/passwords. Currently it is not possible - to have these split over two databases. Make - sure that the <code>msql.acl</code> (access control file) of - mSQL does indeed allow the effective uid of the - web server read access to this database. Check the - httpd.conf file for this uid. -</dd> - -<code><dt> -Auth_MSQLpwd_table user_records -</dt></code><dd> - This is the table which contain the uid/password combination - is specified. -</dd> - -<code><dt> -Auth_MSQLuid_field User_id <br> -Auth_MSQLpwd_field Cpasswd -</dt></code><dd> - These two directive specify the field names in the <code>user_record</code> - table. If this module is compiled with the <a href="#VITEK"><code>BACKWARD_VITEK</code></a> - compatibility switch, the defaults <code>user</code> and <code>password</code> are - assumed if you do not specify them. Currently the user_id field - *MUST* be a primary key or one must ensure that each user only - occurs <b>once</b> in the table. If a uid occurs twice access is - denied by default; but see the <code><a href="#ONLY_ONCE">ONLY_ONCE</a></code> - compiler directive for more information. -</dd> - -<code><dt> -Auth_MSQLgrp_table user_records <br> -Auth_MSQLgrp_field Xgroup <br> -</dt></code><dd> - Optionally one can also specify a table which contains the - user/group combinations. This can be the same table which - also contains the username/password combinations. However - if a user belongs to two or more groups, one will have to - use a different table with multiple entries. -</dd> - -<code><dt> -Auth_MSQL_nopasswd off <br> -Auth_MSQL_Authoritative on <br> -Auth_MSQL_EncryptedPasswords on <br> -</dt></code><dd> - These three optional fields (all set to the sensible defaults, - so you really do not have to enter them) are described in more - detail below. If you choose to set these to any other values then - the above, be very sure you understand the security implications and - do verify that Apache does what you expect it to do. -</dd> - -<code><dt> -AuthName example mSQL realm <br> -AuthType basic -</dt></code> -<dd> - Normal Apache/NCSA tokens for access control - <p> - <code><limit get post head></code><br> - <code>order deny,allow </code><br> - <code>allow from all </code><br> - <p> - <code>require valid-user </code><br> - <ul><li><code>valid-user</code>; allow in any user which has a valid uid/passwd - pair in the above pwd_table. - </ul> - or<br> - <code>require user smith jones </code><br> - <ul><li>Limit access to users who have a valid uid/passwd pair in the - above pwd_table *and* whose uid is 'smith' or 'jones'. Do note that - the uid's are separated by 'spaces' for historic (NCSA) reasons. - So allowing uids with spaces might cause problems. - </ul> - <code>require group has_paid</code><br> - <ul><li>Optionally also ensure that the uid has the value 'has_paid' in - the group field in the group table. - </ul> - <code><limit> </code><br> -</dd> -</dl> - - -<hr><h2><a name="CompileTimeOptions">Compile Time Options</a></h2> - -<dl> -<dt><code> -<a name="ONLY_ONCE">#define ONLY_ONCE 1</a> -</code></dt><dd> - If the mSQL table containing the uid/passwd combination does - not have the uid field as a primary key, it is possible for the - uid to occur more than once in the table with possibly different - passwords. When this module is compiled with the <code>ONLY_ONCE</code> - directive set, access is denied if the uid occurs more than once in the - uid/passwd table. If you choose not to set it, the software takes - the first pair returned and ignores any further pairs. The SQL - statement used for this is<br> - <p><code>"select password form pwd_table where user='UID'"</code><p> - this might lead to unpredictable results. For this reason as well - as for performance reasons you are strongly advised to make the - uid field a primary key. Use at your own peril :-) -</dd> - -<dt><code> -<a name="KEEP_MSQL_CONNECTION_OPEN">#define KEEP_MSQL_CONNECTION_OPEN</a> -</code></dt><dd> - Normally the (TCP/IP) connection with the database is opened and - closed for each SQL query. When the Apache web-server and the database - are on the same machine, and /dev/msql is used this does not - cause a serious overhead. However when your platform does not - support this (see the mSQL documentation) or when the web server - and the database are on different machines the overhead can be - considerable. When the above directive is set defined the server leaves - the connection open, i.e. no call to <code>msqlClose()</code>. - If an error occurs an attempt is made to reopen the connection for - the next http request. - <p> - This has a number of very serious drawbacks - <ul><li> It costs 2 already rare file-descriptors for each child. - <li> It costs msql-connections, typically one per child. The (compiled in) - number of connections mSQL can handle is low, typically 6 or 12. - which might prohibit access to the mSQL database for later - processes. - <li> When a child dies, it might not free that connection properly - or quick enough. - <li> When errors start to occur, connection/file-descriptor resources - might become exhausted very quickly. - </ul> - <p> - In short, use this at your own peril and only in a highly controlled and - monitored environment. -</dd> - -<dt><code> -<a name="VITEK"> -#define BACKWARD_VITEK<br></a> -#define VITEK_uid_name "user"<br> -#define VITEK_gid_name "passwd" -</code></dt><dd> - A second mSQL auth module for Apache has also been developed by Vivek Khera - <<a href="mailto:khera@kciLink.com"><code>khera@kciLink.com</code></a>> - and was subsequently distributed with some early versions of Apache. It - can be obtained from - <code><a href="ftp://ftp.kcilink.com/pub/">ftp://ftp.kcilink.com/pub/mod_auth_msql.c*</a></code>. - Older 'vitek' versions had the field/table names compiled in. Newer - versions, v.1.11 have more <code>access.conf</code> configuration - options. However these where chosen not to be in line the 'ewse' - version of this module. Also, the 'vitek' module does not give group - control or 'empty' password control. - <p> - To get things slightly more in line this version (0.9) should - be backward compatible with the 'vitek' module by: - <ul><li> Adding support for the <code>Auth_MSQL_EncryptedPasswords</code> on/off functionality - <li> Adding support for the different spelling of the 4 configuration - tokens for user-table-name, user/password-field-name and dbase-name. - <li> Setting some field names to a default which used to be hard - coded in in older 'vitek' modules. - </ul> - <p> - If this troubles you, remove the 'BACKWARD_VITEK' define. -</dd> - -<dt><code> -<a name="MAX_FIELD_LEN"> -#define MAX_FIELD_LEN (64)<br> -#define MAX_QUERY_LEN (32+24+MAX_FIELD_LEN*2+3*MSQL_FIELD_NAME_LEN+1*MSQL_TABLE_NAME_LEN)<br></a> -</code></dt><dd> - In order to avoid using the very large <code>HUGE_STRING_LENGTH</code>, the above two compile - time directives are supplies. The <code>MAX_FIELD_LEN</code> contains the maximum number of - characters in your user, password and group fields. The maximum query length is derived - from those values. - <p> - We only do the following two queries: - <ul><li>For the user/passwd combination - <p><code>"select PWDFIELD from PWDTABLE where USERFIELD='UID'"</code><br> - <li>Optionally for the user/group combination: - <p><code>"select GROUPFIELD from GROUPTABLE where USERFIELD='UID' and GROUPFIELD='GID'"</code><br> - </ul> - <p> - This leads to the above limit for the query string. We are ignoring escaping a wee bit here - assuming not more than 24 escapes.) -</dd> -</dl> - - -<hr><h2><a name="RevisionHistory">Revision History</a></h2> - -This version: 23 Nov 1995, 24 Feb 1996, 16 May 1996. - -<dl> - -<dt>Version 0.0<br></dt> - <dd>First release - </dd> -<dt>Version 0.1<br></dt> - <dd>Update to Apache 1.00 - </dd> -<dt>Version 0.2<br></dt> - <dd>Added lines which got missing God knows when - and which did the valid-user authentication no good at all ! - </dd> -<dt>Version 0.3<br></dt> - <dd>Added '<code>Auth_MSQL_nopasswd</code>' option - </dd> -<dt>Version 0.4<br></dt> - <dd>Cleaned out the error messages mess. - </dd> -<dt>Version 0.6<br></dt> - <dd>Inconsistency with gid/grp in comment/token/source - Make sure you really use '<code>Auth_MSQLgrp_field</code>' - as indicated above. - </dd> -<dt>Version 0.7<br></dt> - <dd><code>*host</code> to <code>host</code> fixed. Credits - go to Rob Stout, <stout@lava.et.tudelft.nl> for - spotting this one. - </dd> -<dt>Version 0.8<br></dt> - <dd>Authoritative directive added. See above. - </dd> -<dt>Version 0.9<br></dt> - <dd><code>palloc</code> return code check(s), should be - backward compatible with 1.11 version of Vivek Khera - <khera@kciLink.com> msql - module, fixed broken err msg in group control, changed - command table messages to make more sense when displayed - in that new module management tool. Added - <code>Auth_MSQL_EncryptedPasswords</code> on/off functionality. - msqlClose() statements added upon error. Support for - persistent connections with the mSQL database (riscy). - Escaping of ' and \. Replaced some - <code>MAX_STRING_LENGTH</code> claims. - </dd> -</dl> - - -<hr><h2><a name="Person">Contact/person to blame</a></h2> - -This module was written for the -<a href="http://ewse.ceo.org">European Wide Service Exchange</a> by -<<a href="mailto:Dirk.vanGulik@jrc.it"><code>Dirk.vanGulik@jrc.it</code></a>>. -Feel free to contact me if you have any problems, ice-creams or bugs. This -documentation, courtesy of Nick Himba, <a href="mailto:himba@cs.utwente.nl"> -<code><himba@cs.utwente.nl></code></a>. -<p> - - -<hr><h2><a NAME="Sourcecode">Sourcecode</a></h2> - -The source code can be found at <a href="http://www.apache.org"><code> -http://www.apache.org</code></a>. A snapshot of a development version -usually resides at <a href="http://me-www.jrc.it/~dirkx/mod_auth_msql.c"><code> -http://me-www.jrc.it/~dirkx/mod_auth_msql.c</code></a>. Please make sure -that you always quote the version you use when filing a bug report. -<p> -Furthermore a test/demonstration suite (which assumes that you have -both mSQL and Apache compiled and installed) is available at the contrib -section of <a href="ftp://ftp.apache.org/apache/dist/contrib"><code> -ftp://ftp.apache.org/apache/dist/contrib</code></a> or -<a href="http://me-www.jrc.it/~dirkx/apache-msql-demo.tar.gz"><code> -http://me-www.jrc.it/~dirkx/apache-msql-demo.tar.gz</code></a> and -its <a href="http://me-www.jrc.it/~dirkx/apache-msql-demo"><code> -README</code></a> file. - -<HR> -<H3 ALIGN="CENTER"> - Apache HTTP Server Version 1.2 -</H3> - -<A HREF="./"><IMG SRC="../images/index.gif" ALT="Index"></A> -<A HREF="../"><IMG SRC="../images/home.gif" ALT="Home"></A> - -</body> -</html> - diff --git a/usr.sbin/httpd/htdocs/manual/vhosts-in-depth.html b/usr.sbin/httpd/htdocs/manual/vhosts-in-depth.html deleted file mode 100644 index 0f87f775ed6..00000000000 --- a/usr.sbin/httpd/htdocs/manual/vhosts-in-depth.html +++ /dev/null @@ -1,398 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html><head> -<title>An In-Depth Discussion of VirtualHost Matching</title> -</head> - -<!-- Background white, links blue (unvisited), navy (visited), red (active) --> -<BODY - BGCOLOR="#FFFFFF" - TEXT="#000000" - LINK="#0000FF" - VLINK="#000080" - ALINK="#FF0000" -> -<DIV ALIGN="CENTER"> - <IMG SRC="images/sub.gif" ALT="[APACHE DOCUMENTATION]"> - <H3> - Apache HTTP Server Version 1.2 - </H3> -</DIV> - -<h1 ALIGN="CENTER">An In-Depth Discussion of VirtualHost Matching</h1> - -<p>This is a very rough document that was probably out of date the moment -it was written. It attempts to explain exactly what the code does when -deciding what virtual host to serve a hit from. It's provided on the -assumption that something is better than nothing. The server version -under discussion is Apache 1.2. - -<p>If you just want to "make it work" without understanding -how, there's a <a href="#whatworks">What Works</a> section at the bottom. - -<h3>Config File Parsing</h3> - -<p>There is a main_server which consists of all the definitions appearing -outside of <CODE>VirtualHost</CODE> sections. There are virtual servers, -called <EM>vhosts</EM>, which are defined by -<A - HREF="mod/core.html#virtualhost" -><SAMP>VirtualHost</SAMP></A> -sections. - -<p>The directives -<A - HREF="mod/core.html#port" -><SAMP>Port</SAMP></A>, -<A - HREF="mod/core.html#servername" -><SAMP>ServerName</SAMP></A>, -<A - HREF="mod/core.html#serverpath" -><SAMP>ServerPath</SAMP></A>, -and -<A - HREF="mod/core.html#serveralias" -><SAMP>ServerAlias</SAMP></A> -can appear anywhere within the definition of -a server. However, each appearance overrides the previous appearance -(within that server). - -<p>The default value of the <code>Port</code> field for main_server -is 80. The main_server has no default <code>ServerName</code>, -<code>ServerPath</code>, or <code>ServerAlias</code>. - -<p>In the absence of any -<A - HREF="mod/core.html#listen" -><SAMP>Listen</SAMP></A> -directives, the (final if there -are multiple) <code>Port</code> directive in the main_server indicates -which port httpd will listen on. - -<p> The <code>Port</code> and <code>ServerName</code> directives for -any server main or virtual are used when generating URLs such as during -redirects. - -<p> Each address appearing in the <code>VirtualHost</code> directive -can have an optional port. If the port is unspecified it defaults to -the value of the main_server's most recent <code>Port</code> statement. -The special port <SAMP>*</SAMP> indicates a wildcard that matches any port. -Collectively the entire set of addresses (including multiple -<SAMP>A</SAMP> record -results from DNS lookups) are called the vhost's <EM>address set</EM>. - -<p> The magic <code>_default_</code> address has significance during -the matching algorithm. It essentially matches any unspecified address. - -<p> After parsing the <code>VirtualHost</code> directive, the vhost server -is given a default <code>Port</code> equal to the port assigned to the -first name in its <code>VirtualHost</code> directive. The complete -list of names in the <code>VirtualHost</code> directive are treated -just like a <code>ServerAlias</code> (but are not overridden by any -<code>ServerAlias</code> statement). Note that subsequent <code>Port</code> -statements for this vhost will not affect the ports assigned in the -address set. - -<p> -All vhosts are stored in a list which is in the reverse order that -they appeared in the config file. For example, if the config file is: - -<blockquote><pre> - <VirtualHost A> - ... - </VirtualHost> - - <VirtualHost B> - ... - </VirtualHost> - - <VirtualHost C> - ... - </VirtualHost> -</pre></blockquote> - -Then the list will be ordered: main_server, C, B, A. Keep this in mind. - -<p> -After parsing has completed, the list of servers is scanned, and various -merges and default values are set. In particular: - -<ol> -<li>If a vhost has no - <A - HREF="mod/core.html#serveradmin" - ><code>ServerAdmin</code></A>, - <A - HREF="mod/core.html#resourceconfig" - ><code>ResourceConfig</code></A>, - <A - HREF="mod/core.html#accessconfig" - ><code>AccessConfig</code></A>, - <A - HREF="mod/core.html#timeout" - ><code>Timeout</code></A>, - <A - HREF="mod/core.html#keepalivetimeout" - ><code>KeepAliveTimeout</code></A>, - <A - HREF="mod/core.html#keepalive" - ><code>KeepAlive</code></A>, - <A - HREF="mod/core.html#maxkeepaliverequests" - ><code>MaxKeepAliveRequests</code></A>, - or - <A - HREF="mod/core.html#sendbuffersize" - ><code>SendBufferSize</code></A> - directive then the respective value is - inherited from the main_server. (That is, inherited from whatever - the final setting of that value is in the main_server.) - -<li>The "lookup defaults" that define the default directory - permissions - for a vhost are merged with those of the main server. This includes - any per-directory configuration information for any module. - -<li>The per-server configs for each module from the main_server are - merged into the vhost server. -</ol> - -Essentially, the main_server is treated as "defaults" or a -"base" on -which to build each vhost. But the positioning of these main_server -definitions in the config file is largely irrelevant -- the entire -config of the main_server has been parsed when this final merging occurs. -So even if a main_server definition appears after a vhost definition -it might affect the vhost definition. - -<p> If the main_server has no <code>ServerName</code> at this point, -then the hostname of the machine that httpd is running on is used -instead. We will call the <EM>main_server address set</EM> those IP -addresses returned by a DNS lookup on the <code>ServerName</code> of -the main_server. - -<p> Now a pass is made through the vhosts to fill in any missing -<code>ServerName</code> fields and to classify the vhost as either -an <EM>IP-based</EM> vhost or a <EM>name-based</EM> vhost. A vhost is -considered a name-based vhost if any of its address set overlaps the -main_server (the port associated with each address must match the -main_server's <code>Port</code>). Otherwise it is considered an IP-based -vhost. - -<p> For any undefined <code>ServerName</code> fields, a name-based vhost -defaults to the address given first in the <code>VirtualHost</code> -statement defining the vhost. Any vhost that includes the magic -<SAMP>_default_</SAMP> wildcard is given the same <code>ServerName</code> as -the main_server. Otherwise the vhost (which is necessarily an IP-based -vhost) is given a <code>ServerName</code> based on the result of a reverse -DNS lookup on the first address given in the <code>VirtualHost</code> -statement. - -<p> - -<h3>Vhost Matching</h3> - -<p> -The server determines which vhost to use for a request as follows: - -<p> <code>find_virtual_server</code>: When the connection is first made -by the client, the local IP address (the IP address to which the client -connected) is looked up in the server list. A vhost is matched if it -is an IP-based vhost, the IP address matches and the port matches -(taking into account wildcards). - -<p> If no vhosts are matched then the last occurrence, if it appears, -of a <SAMP>_default_</SAMP> address (which if you recall the ordering of the -server list mentioned above means that this would be the first occurrence -of <SAMP>_default_</SAMP> in the config file) is matched. - -<p> In any event, if nothing above has matched, then the main_server is -matched. - -<p> The vhost resulting from the above search is stored with data -about the connection. We'll call this the <EM>connection vhost</EM>. -The connection vhost is constant over all requests in a particular TCP/IP -session -- that is, over all requests in a KeepAlive/persistent session. - -<p> For each request made on the connection the following sequence of -events further determines the actual vhost that will be used to serve -the request. - -<p> <code>check_fulluri</code>: If the requestURI is an absoluteURI, that -is it includes <code>http://hostname/</code>, then an attempt is made to -determine if the hostname's address (and optional port) match that of -the connection vhost. If it does then the hostname portion of the URI -is saved as the <EM>request_hostname</EM>. If it does not match, then the -URI remains untouched. <STRONG>Note</STRONG>: to achieve this address -comparison, -the hostname supplied goes through a DNS lookup unless it matches the -<code>ServerName</code> or the local IP address of the client's socket. - -<p> <code>parse_uri</code>: If the URI begins with a protocol -(<EM>i.e.</EM>, <code>http:</code>, <code>ftp:</code>) then the request is -considered a proxy request. Note that even though we may have stripped -an <code>http://hostname/</code> in the previous step, this could still -be a proxy request. - -<p> <code>read_request</code>: If the request does not have a hostname -from the earlier step, then any <code>Host:</code> header sent by the -client is used as the request hostname. - -<p> <code>check_hostalias</code>: If the request now has a hostname, -then an attempt is made to match for this hostname. The first step -of this match is to compare any port, if one was given in the request, -against the <code>Port</code> field of the connection vhost. If there's -a mismatch then the vhost used for the request is the connection vhost. -(This is a bug, see observations.) - -<p> -If the port matches, then httpd scans the list of vhosts starting with -the next server <STRONG>after</STRONG> the connection vhost. This scan does not -stop if there are any matches, it goes through all possible vhosts, -and in the end uses the last match it found. The comparisons performed -are as follows: - -<ul> -<li>Compare the request hostname:port with the vhost - <code>ServerName</code> and <code>Port</code>. - -<li>Compare the request hostname against any and all addresses given in - the <code>VirtualHost</code> directive for this vhost. - -<li>Compare the request hostname against the <code>ServerAlias</code> - given for the vhost. -</ul> - -<p> -<code>check_serverpath</code>: If the request has no hostname -(back up a few paragraphs) then a scan similar to the one -in <code>check_hostalias</code> is performed to match any -<code>ServerPath</code> directives given in the vhosts. Note that the -<STRONG>last match</STRONG> is used regardless (again consider the ordering of -the virtual hosts). - -<h3>Observations</h3> - -<ul> - -<li>It is difficult to define an IP-based vhost for the machine's - "main IP address". You essentially have to create a bogus - <code>ServerName</code> for the main_server that does not match the - machine's IPs. - -<li>During the scans in both <code>check_hostalias</code> and - <code>check_serverpath</code> no check is made that the vhost being - scanned is actually a name-based vhost. This means, for example, that - it's possible to match an IP-based vhost through another address. But - because the scan starts in the vhost list at the first vhost that - matched the local IP address of the connection, not all IP-based vhosts - can be matched. - - <p>Consider the config file above with three vhosts A, B, C. Suppose - that B is a named-based vhost, and A and C are IP-based vhosts. If - a request comes in on B or C's address containing a header - "<SAMP>Host: A</SAMP>" then - it will be served from A's config. If a request comes in on A's - address then it will always be served from A's config regardless of - any Host: header. - </p> - -<li>Unless you have a <SAMP>_default_</SAMP> vhost, - it doesn't matter if you mix name-based vhosts in amongst IP-based - vhosts. During the <code>find_virtual_server</code> phase above no - named-based vhost will be matched, so the main_server will remain the - connection vhost. Then scans will cover all vhosts in the vhost list. - - <p>If you do have a <SAMP>_default_</SAMP> vhost, then you cannot place - named-based vhosts after it in the config. This is because on any - connection to the main server IPs the connection vhost will always be - the <SAMP>_default_</SAMP> vhost since none of the name-based are - considered during <code>find_virtual_server</code>. - </p> - -<li>You should never specify DNS names in <code>VirtualHost</code> - directives because it will force your server to rely on DNS to boot. - Furthermore it poses a security threat if you do not control the - DNS for all the domains listed. - <a href="dns-caveats.html"> - There's more information - available on this and the next two topics</a>.</p> - -<li><code>ServerName</code> should always be set for each vhost. Otherwise - A DNS lookup is required for each vhost.</p> - -<li>A DNS lookup is always required for the main_server's - <code>ServerName</code> (or to generate that if it isn't specified - in the config).</p> - -<li>If a <code>ServerPath</code> directive exists which is a prefix of - another <code>ServerPath</code> directive that appears later in - the configuration file, then the former will always be matched - and the latter will never be matched. (That is assuming that no - Host header was available to disambiguate the two.)</p> - -<li>If a vhost that would otherwise be a name-vhost includes a - <code>Port</code> statement that doesn't match the main_server - <code>Port</code> then it will be considered an IP-based vhost. - Then <code>find_virtual_server</code> will match it (because - the ports associated with each address in the address set default - to the port of the main_server) as the connection vhost. Then - <code>check_hostalias</code> will refuse to check any other name-based - vhost because of the port mismatch. The result is that the vhost - will steal all hits going to the main_server address.</p> - -<li>If two IP-based vhosts have an address in common, the vhost appearing - later in the file is always matched. Such a thing might happen - inadvertently. If the config has name-based vhosts and for some reason - the main_server <code>ServerName</code> resolves to the wrong address - then all the name-based vhosts will be parsed as ip-based vhosts. - Then the last of them will steal all the hits.</P> - -<li>The last name-based vhost in the config is always matched for any hit - which doesn't match one of the other name-based vhosts.</p> - -</ul> - -<h3><a name="whatworks">What Works</a></h3> - -<p>In addition to the tips on the <a href="dns-caveats.html#tips">DNS -Issues</a> page, here are some further tips: - -<ul> - -<li>Place all main_server definitions before any VirtualHost definitions. -(This is to aid the readability of the configuration -- the post-config -merging process makes it non-obvious that definitions mixed in around -virtualhosts might affect all virtualhosts.) -<p> - -<li>Arrange your VirtualHosts such -that all name-based virtual hosts come first, followed by IP-based -virtual hosts, followed by any <SAMP>_default_</SAMP> virtual host -<p> - -<li>Avoid <code>ServerPaths</code> which are prefixes of other -<code>ServerPaths</code>. If you cannot avoid this then you have to -ensure that the longer (more specific) prefix vhost appears earlier in -the configuration file than the shorter (less specific) prefix -(<EM>i.e.</EM>, "ServerPath /abc" should appear after -"ServerPath /abcdef"). -<p> - -<li>Do not use <i>port-based</i> vhosts in the same server as -name-based vhosts. A loose definition for port-based is a vhost which -is determined by the port on the server (<em>i.e.</em> one server with -ports 8000, 8080, and 80 all of which have different configurations). -<p> - -</ul> - -<HR> -<H3 ALIGN="CENTER"> - Apache HTTP Server Version 1.2 -</H3> - -<A HREF="./"><IMG SRC="images/index.gif" ALT="Index"></A> - -</BODY> -</HTML> diff --git a/usr.sbin/httpd/htdocs/manual/virtual-host.html b/usr.sbin/httpd/htdocs/manual/virtual-host.html deleted file mode 100644 index d21ac708fd8..00000000000 --- a/usr.sbin/httpd/htdocs/manual/virtual-host.html +++ /dev/null @@ -1,216 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> -<title>Apache Server Virtual Host Support</title> -</head> - -<!-- Background white, links blue (unvisited), navy (visited), red (active) --> -<BODY - BGCOLOR="#FFFFFF" - TEXT="#000000" - LINK="#0000FF" - VLINK="#000080" - ALINK="#FF0000" -> -<DIV ALIGN="CENTER"> - <IMG SRC="images/sub.gif" ALT="[APACHE DOCUMENTATION]"> - <H3> - Apache HTTP Server Version 1.2 - </H3> -</DIV> - -<h1 ALIGN="CENTER">Virtual Host Support</h1> - -<strong>See Also:</strong> -<a href="host.html">Non-IP based virtual hosts</a> - -<h2>What are virtual hosts?</h2> -This is the ability of a single machine to be a web server for multiple -domains. For example, an Internet service provider might have a machine -called <code>www.serve.com</code> which provides Web space for several -organizations including, say, <em>smallco</em> and <em>baygroup</em>. -Ordinarily, these groups would be given parts of the Web tree on www.serve.com. -So smallco's home page would have the URL -<blockquote> -http://www.serve.com/smallco/ -</blockquote> -and baygroup's home page would have the URL -<blockquote> -http://www.serve.com/baygroup/ -</blockquote> -<p> -For esthetic reasons, however, both organizations would rather their home -pages appeared under their own names rather than that of the service -provider's; but they do not want to set up their own Internet links and -servers. -<p> -Virtual hosts are the solution to this problem. smallco and baygroup would -have their own Internet name registrations, <code>www.smallco.com</code> and -<code>www.baygroup.org</code> respectively. These hostnames would both -correspond to the service provider's machine (www.serve.com). Thus -smallco's home page would now have the URL -<blockquote> -http://www.smallco.com/ -</blockquote> -and baygroup's home page would would have the URL -<blockquote> -http://www.baygroup.org/ -</blockquote> - -<h2>System requirements</h2> -Due to limitations in the HTTP/1.0 protocol, the web server <strong>must have a -different IP address for each virtual host</strong>. This can be achieved -by the machine having several physical network connections, or by use -of a <a href="misc/vif-info.html">virtual interface</a> on some operating systems. - -<h2>How to set up Apache</h2> -There are two ways of configuring apache to support multiple hosts. -Either by running a separate httpd daemon for each hostname, or by running a -single daemon which supports all the virtual hosts. -<p> -Use multiple daemons when: -<ul> -<li>The different virtual hosts need very different httpd configurations, such - as different values for: <A HREF="mod/core.html#servertype">ServerType</A>, - <A HREF="mod/core.html#user">User</A>, - <A HREF="mod/core.html#group">Group</A>, - <A HREF="mod/mod_mime.html#typesconfig">TypesConfig</A> or - <A HREF="mod/core.html#serverroot">ServerRoot</A>. -<li>The machine does not process a very high request rate. -</ul> -Use a single daemon when: -<ul> -<li>Sharing of the httpd configuration between virtual hosts is acceptable. -<li>The machine services a large number of requests, and so the performance - loss in running separate daemons may be significant. -</ul> - -<h2>Setting up multiple daemons</h2> -Create a separate httpd installation for each virtual host. -For each installation, use the -<A HREF="mod/core.html#bindaddress">BindAddress</A> directive in the configuration -file to select which IP address (or virtual host) that daemon services. -e.g. -<blockquote><code>BindAddress www.smallco.com</code></blockquote> -This hostname can also be given as an IP address. - -<h2>Setting up a single daemon</h2> -For this case, a single httpd will service requests for all the virtual hosts. -The <A HREF="mod/core.html#virtualhost">VirtualHost</A> directive in the - configuration file is used to set the values of -<A HREF="mod/core.html#serveradmin">ServerAdmin</A>, -<A HREF="mod/core.html#servername">ServerName</A>, -<A HREF="mod/core.html#documentroot">DocumentRoot</A>, -<A HREF="mod/core.html#errorlog">ErrorLog</A> and -<A HREF="mod/mod_log_common.html#transferlog">TransferLog</A> configuration -directives to different values for each virtual host. -e.g. -<blockquote><code> -<VirtualHost www.smallco.com><br> -ServerAdmin webmaster@mail.smallco.com<br> -DocumentRoot /groups/smallco/www<br> -ServerName www.smallco.com<br> -ErrorLog /groups/smallco/logs/error_log<br> -TransferLog /groups/smallco/logs/access_log<br> -</VirtualHost><br> -<br> -<VirtualHost www.baygroup.org><br> -ServerAdmin webmaster@mail.baygroup.org<br> -DocumentRoot /groups/baygroup/www<br> -ServerName www.baygroup.org<br> -ErrorLog /groups/baygroup/logs/error_log<br> -TransferLog /groups/baygroup/logs/access_log<br> -</VirtualHost><br> -</code></blockquote> - -This VirtualHost hostnames can also be given as IP addresses. - -<P> - -Almost <strong>ANY</strong> configuration directive can be put -in the VirtualHost directive, with the exception of -<A HREF="mod/core.html#servertype">ServerType</A>, -<A HREF="mod/core.html#user">User</A>, -<A HREF="mod/core.html#group">Group</A>, -<A HREF="mod/core.html#startservers">StartServers</A>, -<A HREF="mod/core.html#maxspareservers">MaxSpareServers</A>, -<A HREF="mod/core.html#minspareservers">MinSpareServers</A>, -<A HREF="mod/core.html#maxrequestsperchild">MaxRequestsPerChild</A>, -<A HREF="mod/core.html#bindaddress">BindAddress</A>, -<A HREF="mod/core.html#pidfile">PidFile</A>, -<A HREF="mod/mod_mime.html#typesconfig">TypesConfig</A>, and -<A HREF="mod/core.html#serverroot">ServerRoot</A>. - -<P> - -<EM>SECURITY:</EM> When specifying where to write log files, be aware -of some security risks which are present if anyone other than the -user that starts Apache has write access to the directory where they -are written. See the <A HREF="misc/security_tips.html">security -tips</A> document for details. - -<P> - -<H2>File Handle/Resource Limits:</H2> -When using a large number of Virtual Hosts, Apache may run out of available -file descriptors if each Virtual Host specifies different log files. -The total number of file descriptors used by Apache is one for each distinct -error log file, one for every other log file directive, plus 10-20 for -internal use. Unix operating systems limit the number of file descriptors that -may be used by a process; the limit is typically 64, and may usually be -increased up to a large hard-limit. -<p> -Although Apache attempts to increase the limit as required, this -may not work if: -<ol> -<li>Your system does not provide the setrlimit() system call. -<li>The setrlimit(RLIMIT_NOFILE) call does not function on your system - (such as Solaris 2.3) -<li>The number of file descriptors required exceeds the hard limit. -<li>Your system imposes other limits on file descriptors, such as a limit -on stdio streams only using file descriptors below 256. (Solaris 2) -</ol> - -In the event of problems you can: -<ul> -<li>Reduce the number of log files; don't specify log files in the VirtualHost -sections, but only log to the main log files. -<li>If you system falls into 1 or 2 (above), then increase the file descriptor -limit before starting Apache, using a script like -<blockquote><code> -#!/bin/sh <br> -ulimit -S -n 100 <br> -exec httpd</code></blockquote> -</ul> - -The have been reports that Apache may start running out of resources allocated -for the root process. This will exhibit itself as errors in the error log like -"unable to fork". There are two ways you can bump this up: - -<OL> -<LI>Have a <code>csh</code> script wrapper around httpd which sets the -"rlimit" to some large number, like 512. -<LI>Edit http_main.c to add calls to setrlimit() from main(), along the lines of -<PRE> - struct rlimit rlp; - - rlp.rlim_cur = rlp.rlim_max = 512; - if (setrlimit(RLIMIT_NPROC, &rlp)) { - fprintf(stderr, "setrlimit(RLIMIT_NPROC) failed.\n"); - exit(1); - } -</PRE> -(thanks to "Aaron Gifford <agifford@InfoWest.COM>" for the patch) -</OL> - -The latter will probably manifest itself in a later version of Apache. - -<HR> -<H3 ALIGN="CENTER"> - Apache HTTP Server Version 1.2 -</H3> - -<A HREF="./"><IMG SRC="images/index.gif" ALT="Index"></A> - -</body></html> - diff --git a/usr.sbin/httpd/src/.indent.pro b/usr.sbin/httpd/src/.indent.pro deleted file mode 100644 index 77b65f3d6a7..00000000000 --- a/usr.sbin/httpd/src/.indent.pro +++ /dev/null @@ -1 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs diff --git a/usr.sbin/httpd/src/alloc.c b/usr.sbin/httpd/src/alloc.c deleted file mode 100644 index d002a6f8f8c..00000000000 --- a/usr.sbin/httpd/src/alloc.c +++ /dev/null @@ -1,1142 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - - -/* - * Resource allocation code... the code here is responsible for making - * sure that nothing leaks. - * - * rst --- 4/95 --- 6/95 - */ - -#include "httpd.h" - -#include <stdarg.h> - -/***************************************************************** - * - * Managing free storage blocks... - */ - -union align -{ - /* Types which are likely to have the longest RELEVANT alignment - * restrictions... - */ - - char *cp; - void (*f)(); - long l; - FILE *fp; - double d; -}; - -#define CLICK_SZ (sizeof(union align)) - -union block_hdr -{ - union align a; - - /* Actual header... */ - - struct { - char *endp; - union block_hdr *next; - char *first_avail; - } h; -}; - -union block_hdr *block_freelist = NULL; - - - -/* Get a completely new block from the system pool. Note that we rely on -malloc() to provide aligned memory. */ - -union block_hdr *malloc_block (int size) -{ - union block_hdr *blok = - (union block_hdr *)malloc(size + sizeof(union block_hdr)); - - if (blok == NULL) { - fprintf (stderr, "Ouch! malloc failed in malloc_block()\n"); - exit (1); - } - blok->h.next = NULL; - blok->h.first_avail = (char *)(blok + 1); - blok->h.endp = size + blok->h.first_avail; - - return blok; -} - - - -void chk_on_blk_list (union block_hdr *blok, union block_hdr *free_blk) -{ - /* Debugging code. Left in for the moment. */ - - while (free_blk) { - if (free_blk == blok) { - fprintf (stderr, "Ouch! Freeing free block\n"); - exit (1); - } - free_blk = free_blk->h.next; - } -} - -/* Free a chain of blocks --- must be called with alarms blocked. */ - -void free_blocks (union block_hdr *blok) -{ - /* First, put new blocks at the head of the free list --- - * we'll eventually bash the 'next' pointer of the last block - * in the chain to point to the free blocks we already had. - */ - - union block_hdr *old_free_list = block_freelist; - - if (blok == NULL) return; /* Sanity check --- freeing empty pool? */ - - block_freelist = blok; - - /* - * Next, adjust first_avail pointers of each block --- have to do it - * sooner or later, and it simplifies the search in new_block to do it - * now. - */ - - while (blok->h.next != NULL) { - chk_on_blk_list (blok, old_free_list); - blok->h.first_avail = (char *)(blok + 1); - blok = blok->h.next; - } - - chk_on_blk_list (blok, old_free_list); - blok->h.first_avail = (char *)(blok + 1); - - /* Finally, reset next pointer to get the old free blocks back */ - - blok->h.next = old_free_list; -} - - - - -/* Get a new block, from our own free list if possible, from the system - * if necessary. Must be called with alarms blocked. - */ - -union block_hdr *new_block (int min_size) -{ - union block_hdr **lastptr = &block_freelist; - union block_hdr *blok = block_freelist; - - /* First, see if we have anything of the required size - * on the free list... - */ - - while (blok != NULL) { - if (min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) { - *lastptr = blok->h.next; - blok->h.next = NULL; - return blok; - } - else { - lastptr = &blok->h.next; - blok = blok->h.next; - } - } - - /* Nope. */ - - min_size += BLOCK_MINFREE; - return malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC); -} - - - -/* Accounting */ - -long bytes_in_block_list (union block_hdr *blok) -{ - long size = 0; - - while (blok) { - size += blok->h.endp - (char *)(blok + 1); - blok = blok->h.next; - } - - return size; -} - - -/***************************************************************** - * - * Pool internals and management... - * NB that subprocesses are not handled by the generic cleanup code, - * basically because we don't want cleanups for multiple subprocesses - * to result in multiple three-second pauses. - */ - -struct process_chain; -struct cleanup; - -static void run_cleanups (struct cleanup *); -static void free_proc_chain (struct process_chain *); - -struct pool { - union block_hdr *first; - union block_hdr *last; - struct cleanup *cleanups; - struct process_chain *subprocesses; - struct pool *sub_pools; - struct pool *sub_next; - struct pool *sub_prev; - struct pool *parent; - char *free_first_avail; -}; - -pool *permanent_pool; - -/* Each pool structure is allocated in the start of its own first block, - * so we need to know how many bytes that is (once properly aligned...). - * This also means that when a pool's sub-pool is destroyed, the storage - * associated with it is *completely* gone, so we have to make sure it - * gets taken off the parent's sub-pool list... - */ - -#define POOL_HDR_CLICKS (1 + ((sizeof(struct pool) - 1) / CLICK_SZ)) -#define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ) - -struct pool *make_sub_pool (struct pool *p) -{ - union block_hdr *blok; - pool *new_pool; - - block_alarms(); - - blok = new_block (0); - new_pool = (pool *)blok->h.first_avail; - blok->h.first_avail += POOL_HDR_BYTES; - - memset ((char *)new_pool, '\0', sizeof (struct pool)); - new_pool->free_first_avail = blok->h.first_avail; - new_pool->first = new_pool->last = blok; - - if (p) { - new_pool->parent = p; - new_pool->sub_next = p->sub_pools; - if (new_pool->sub_next) new_pool->sub_next->sub_prev = new_pool; - p->sub_pools = new_pool; - } - - unblock_alarms(); - - return new_pool; -} - -void init_alloc() { permanent_pool = make_sub_pool (NULL); } - -void clear_pool (struct pool *a) -{ - block_alarms(); - - while (a->sub_pools) - destroy_pool (a->sub_pools); - - a->sub_pools = NULL; - - run_cleanups (a->cleanups); a->cleanups = NULL; - free_proc_chain (a->subprocesses); a->subprocesses = NULL; - free_blocks (a->first->h.next); a->first->h.next = NULL; - - a->last = a->first; - a->first->h.first_avail = a->free_first_avail; - - unblock_alarms(); -} - -void destroy_pool (pool *a) -{ - block_alarms(); - clear_pool (a); - - if (a->parent) { - if (a->parent->sub_pools == a) a->parent->sub_pools = a->sub_next; - if (a->sub_prev) a->sub_prev->sub_next = a->sub_next; - if (a->sub_next) a->sub_next->sub_prev = a->sub_prev; - } - - free_blocks (a->first); - unblock_alarms(); -} - -long bytes_in_pool (pool *p) { return bytes_in_block_list (p->first); } -long bytes_in_free_blocks () { return bytes_in_block_list (block_freelist); } - -/***************************************************************** - * - * Allocating stuff... - */ - - -void *palloc (struct pool *a, int reqsize) -{ - /* Round up requested size to an even number of alignment units (core clicks) - */ - - int nclicks = 1 + ((reqsize - 1) / CLICK_SZ); - int size = nclicks * CLICK_SZ; - - /* First, see if we have space in the block most recently - * allocated to this pool - */ - - union block_hdr *blok = a->last; - char *first_avail = blok->h.first_avail; - char *new_first_avail; - - if(reqsize <= 0) - return NULL; - - new_first_avail = first_avail + size; - - if (new_first_avail <= blok->h.endp) { - blok->h.first_avail = new_first_avail; - return (void *)first_avail; - } - - /* Nope --- get a new one that's guaranteed to be big enough */ - - block_alarms(); - blok = new_block (size); - a->last->h.next = blok; - a->last = blok; - unblock_alarms(); - - first_avail = blok->h.first_avail; - blok->h.first_avail += size; - - return (void *)first_avail; -} - -void *pcalloc(struct pool *a, int size) -{ - void *res = palloc (a, size); - memset (res, '\0', size); - return res; -} - -char *pstrdup(struct pool *a, const char *s) -{ - char *res; - if (s == NULL) return NULL; - res = palloc (a, strlen(s) + 1); - strcpy (res, s); - return res; -} - -char *pstrndup(struct pool *a, const char *s, int n) -{ - char *res; - if (s == NULL) return NULL; - res = palloc (a, n + 1); - strncpy (res, s, n); - res[n] = '\0'; - return res; -} - -char *pstrcat(pool *a, ...) -{ - char *cp, *argp, *res; - - /* Pass one --- find length of required string */ - - int len = 0; - va_list adummy; - - va_start (adummy, a); - - while ((cp = va_arg (adummy, char *)) != NULL) - len += strlen(cp); - - va_end (adummy); - - /* Allocate the required string */ - - res = (char *)palloc(a, len + 1); - cp = res; - - /* Pass two --- copy the argument strings into the result space */ - - va_start (adummy, a); - - while ((argp = va_arg (adummy, char *)) != NULL) { - strcpy (cp, argp); - cp += strlen(argp); - } - - va_end (adummy); - - /* Return the result string */ - - return res; -} - - -/***************************************************************** - * - * The 'array' functions... - */ - -array_header *make_array (pool *p, int nelts, int elt_size) -{ - array_header *res = (array_header *)palloc(p, sizeof(array_header)); - - if (nelts < 1) nelts = 1; /* Assure sanity if someone asks for - * array of zero elts. - */ - - res->elts = pcalloc (p, nelts * elt_size); - - res->pool = p; - res->elt_size = elt_size; - res->nelts = 0; /* No active elements yet... */ - res->nalloc = nelts; /* ...but this many allocated */ - - return res; -} - -void *push_array (array_header *arr) -{ - if (arr->nelts == arr->nalloc) { - int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2; - char *new_data; - - new_data = pcalloc (arr->pool, arr->elt_size * new_size); - - memcpy (new_data, arr->elts, arr->nalloc * arr->elt_size); - arr->elts = new_data; - arr->nalloc = new_size; - } - - ++arr->nelts; - return arr->elts + (arr->elt_size * (arr->nelts - 1)); -} - -void array_cat (array_header *dst, const array_header *src) -{ - int elt_size = dst->elt_size; - - if (dst->nelts + src->nelts > dst->nalloc) { - int new_size = (dst->nalloc <= 0) ? 1 : dst->nalloc * 2; - char *new_data; - - while (dst->nelts + src->nelts > new_size) - new_size *= 2; - - new_data = pcalloc (dst->pool, elt_size * new_size); - memcpy (new_data, dst->elts, dst->nalloc * elt_size); - - dst->elts = new_data; - dst->nalloc = new_size; - } - - memcpy (dst->elts + dst->nelts * elt_size, src->elts, elt_size * src->nelts); - dst->nelts += src->nelts; -} - -array_header *copy_array (pool *p, const array_header *arr) -{ - array_header *res = make_array (p, arr->nalloc, arr->elt_size); - - memcpy (res->elts, arr->elts, arr->elt_size * arr->nelts); - res->nelts = arr->nelts; - return res; -} - -/* This cute function copies the array header *only*, but arranges - * for the data section to be copied on the first push or arraycat. - * It's useful when the elements of the array being copied are - * read only, but new stuff *might* get added on the end; we have the - * overhead of the full copy only where it is really needed. - */ - -array_header *copy_array_hdr (pool *p, const array_header *arr) -{ - array_header *res = (array_header *)palloc(p, sizeof(array_header)); - - res->elts = arr->elts; - - res->pool = p; - res->elt_size = arr->elt_size; - res->nelts = arr->nelts; - res->nalloc = arr->nelts; /* Force overflow on push */ - - return res; -} - -/* The above is used here to avoid consing multiple new array bodies... */ - -array_header *append_arrays (pool *p, - const array_header *first, - const array_header *second) -{ - array_header *res = copy_array_hdr (p, first); - - array_cat (res, second); - return res; -} - - -/***************************************************************** - * - * The "table" functions. - */ - -table *make_table (pool *p, int nelts) { - return make_array (p, nelts, sizeof (table_entry)); -} - -table *copy_table (pool *p, const table *t) { - return copy_array (p, t); -} - -void clear_table (table *t) -{ - t->nelts = 0; -} - -array_header *table_elts (table *t) { return t; } - -char *table_get (const table *t, const char *key) -{ - table_entry *elts = (table_entry *)t->elts; - int i; - - if (key == NULL) return NULL; - - for (i = 0; i < t->nelts; ++i) - if (!strcasecmp (elts[i].key, key)) - return elts[i].val; - - return NULL; -} - -void table_set (table *t, const char *key, const char *val) -{ - register int i, j, k; - table_entry *elts = (table_entry *)t->elts; - int done = 0; - - for (i = 0; i < t->nelts;) { - if (!strcasecmp (elts[i].key, key)) { - if (!done) { - elts[i].val = pstrdup(t->pool, val); - done = 1; - ++i; - } - else { /* delete an extraneous element */ - for (j = i, k = i + 1; k < t->nelts; ++j, ++k) { - elts[j].key = elts[k].key; - elts[j].val = elts[k].val; - } - --t->nelts; - } - } - else { - ++i; - } - } - - if (!done) { - elts = (table_entry *)push_array(t); - elts->key = pstrdup (t->pool, key); - elts->val = pstrdup (t->pool, val); - } -} - -void table_unset( table *t, const char *key ) -{ - register int i, j, k; - table_entry *elts = (table_entry *)t->elts; - - for (i = 0; i < t->nelts;) { - if (!strcasecmp (elts[i].key, key)) { - - /* found an element to skip over - * there are any number of ways to remove an element from - * a contiguous block of memory. I've chosen one that - * doesn't do a memcpy/bcopy/array_delete, *shrug*... - */ - for (j = i, k = i + 1; k < t->nelts; ++j, ++k) { - elts[j].key = elts[k].key; - elts[j].val = elts[k].val; - } - --t->nelts; - } - else { - ++i; - } - } -} - -void table_merge (table *t, const char *key, const char *val) -{ - table_entry *elts = (table_entry *)t->elts; - int i; - - for (i = 0; i < t->nelts; ++i) - if (!strcasecmp (elts[i].key, key)) { - elts[i].val = pstrcat (t->pool, elts[i].val, ", ", val, NULL); - return; - } - - elts = (table_entry *)push_array(t); - elts->key = pstrdup (t->pool, key); - elts->val = pstrdup (t->pool, val); -} - -void table_add (table *t, const char *key, const char *val) -{ - table_entry *elts = (table_entry *)t->elts; - - elts = (table_entry *)push_array(t); - elts->key = pstrdup (t->pool, key); - elts->val = pstrdup (t->pool, val); -} - -table* overlay_tables (pool *p, const table *overlay, const table *base) -{ - return append_arrays (p, overlay, base); -} - -/* And now for something completely abstract ... - * - * For each key value given as a vararg: - * run the function pointed to as - * int comp(void *r, char *key, char *value); - * on each valid key-value pair in the table t that matches the vararg key, - * or once for every valid key-value pair if the vararg list is empty, - * until the function returns false (0) or we finish the table. - * - * Note that we restart the traversal for each vararg, which means that - * duplicate varargs will result in multiple executions of the function - * for each matching key. Note also that if the vararg list is empty, - * only one traversal will be made and will cut short if comp returns 0. - * - * Note that the table_get and table_merge functions assume that each key in - * the table is unique (i.e., no multiple entries with the same key). This - * function does not make that assumption, since it (unfortunately) isn't - * true for some of Apache's tables. - * - * Note that rec is simply passed-on to the comp function, so that the - * caller can pass additional info for the task. - */ -void table_do (int (*comp)(void *, const char *, const char *), void *rec, - const table *t, ...) -{ - va_list vp; - char *argp; - table_entry *elts = (table_entry *)t->elts; - int rv, i; - - va_start(vp, t); - - argp = va_arg(vp, char *); - - do { - for (rv = 1, i = 0; rv && (i < t->nelts); ++i) { - if (elts[i].key && (!argp || !strcasecmp(elts[i].key, argp))) { - rv = (*comp)(rec, elts[i].key, elts[i].val); - } - } - } while (argp && ((argp = va_arg(vp, char *)) != NULL)); - - va_end(vp); -} - -/***************************************************************** - * - * Managing generic cleanups. - */ - -struct cleanup { - void *data; - void (*plain_cleanup)(void *); - void (*child_cleanup)(void *); - struct cleanup *next; -}; - -void register_cleanup (pool *p, void *data, void (*plain_cleanup)(void *), - void (*child_cleanup)(void *)) -{ - struct cleanup *c = (struct cleanup *)palloc(p, sizeof (struct cleanup)); - c->data = data; - c->plain_cleanup = plain_cleanup; - c->child_cleanup = child_cleanup; - c->next = p->cleanups; - p->cleanups = c; -} - -void kill_cleanup (pool *p, void *data, void (*cleanup)(void *)) -{ - struct cleanup *c = p->cleanups; - struct cleanup **lastp = &p->cleanups; - - while (c) { - if (c->data == data && c->plain_cleanup == cleanup) { - *lastp = c->next; - break; - } - - lastp = &c->next; - c = c->next; - } -} - -void run_cleanup (pool *p, void *data, void (*cleanup)(void *)) -{ - block_alarms(); /* Run cleanup only once! */ - (*cleanup)(data); - kill_cleanup (p, data, cleanup); - unblock_alarms(); -} - -static void run_cleanups (struct cleanup *c) -{ - while (c) { - (*c->plain_cleanup)(c->data); - c = c->next; - } -} - -static void run_child_cleanups (struct cleanup *c) -{ - while (c) { - (*c->child_cleanup)(c->data); - c = c->next; - } -} - -static void cleanup_pool_for_exec (pool *p) -{ - run_child_cleanups (p->cleanups); - p->cleanups = NULL; - - for (p = p->sub_pools; p; p = p->sub_next) - cleanup_pool_for_exec (p); -} - -void cleanup_for_exec() -{ - block_alarms(); - cleanup_pool_for_exec (permanent_pool); - unblock_alarms(); -} - -/***************************************************************** - * - * Files and file descriptors; these are just an application of the - * generic cleanup interface. - */ - -static void fd_cleanup (void *fdv) { close ((int)fdv); } - -void note_cleanups_for_fd (pool *p, int fd) { - register_cleanup (p, (void *)fd, fd_cleanup, fd_cleanup); -} - -void kill_cleanups_for_fd(pool *p,int fd) - { - kill_cleanup(p,(void *)fd,fd_cleanup); - } - -int popenf(pool *a, const char *name, int flg, int mode) -{ - int fd; - int save_errno; - - block_alarms(); - fd = open(name, flg, mode); - save_errno = errno; - if (fd >= 0) { - fd = ap_slack (fd, AP_SLACK_HIGH); - note_cleanups_for_fd (a, fd); - } - unblock_alarms(); - errno = save_errno; - return fd; -} - -int pclosef(pool *a, int fd) -{ - int res; - int save_errno; - - block_alarms(); - res = close(fd); - save_errno = errno; - kill_cleanup(a, (void *)fd, fd_cleanup); - unblock_alarms(); - errno = save_errno; - return res; -} - -/* Note that we have separate plain_ and child_ cleanups for FILE *s, - * since fclose() would flush I/O buffers, which is extremely undesirable; - * we just close the descriptor. - */ - -static void file_cleanup (void *fpv) { fclose ((FILE *)fpv); } -static void file_child_cleanup (void *fpv) { close (fileno ((FILE *)fpv)); } - -void note_cleanups_for_file (pool *p, FILE *fp) { - register_cleanup (p, (void *)fp, file_cleanup, file_child_cleanup); -} - -FILE *pfopen(pool *a, const char *name, const char *mode) -{ - FILE *fd = NULL; - int baseFlag, desc; - - block_alarms(); - - if (*mode == 'a') { - /* Work around faulty implementations of fopen */ - baseFlag = (*(mode+1) == '+') ? O_RDWR : O_WRONLY; - desc = open(name, baseFlag | O_APPEND | O_CREAT, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (desc >= 0) { - desc = ap_slack(desc, AP_SLACK_LOW); - fd = fdopen(desc, mode); - } - } else { - fd = fopen(name, mode); - } - - if (fd != NULL) note_cleanups_for_file (a, fd); - unblock_alarms(); - return fd; -} - -FILE *pfdopen(pool *a,int fd, const char *mode) -{ - FILE *f; - - block_alarms(); - f=fdopen(fd,mode); - if(f != NULL) - note_cleanups_for_file(a,f); - unblock_alarms(); - return f; -} - - -int pfclose(pool *a, FILE *fd) -{ - int res; - - block_alarms(); - res = fclose(fd); - kill_cleanup(a, (void *)fd, file_cleanup); - unblock_alarms(); - return res; -} - -/* - * Here's a pool-based interface to POSIX regex's regcomp(). - * Note that we return regex_t instead of being passed one. - * The reason is that if you use an already-used regex_t structure, - * the memory that you've already allocated gets forgotten, and - * regfree() doesn't clear it. So we don't allow it. - */ - -static void regex_cleanup (void *preg) { regfree ((regex_t *)preg); } - -regex_t *pregcomp(pool *p, const char *pattern, int cflags) { - regex_t *preg = palloc(p, sizeof(regex_t)); - - if (regcomp(preg, pattern, cflags)) - return NULL; - - register_cleanup (p, (void *)preg, regex_cleanup, regex_cleanup); - - return preg; -} - - -void pregfree(pool *p, regex_t *reg) -{ - block_alarms(); - regfree (reg); - kill_cleanup (p, (void *)reg, regex_cleanup); - unblock_alarms(); -} - -/***************************************************************** - * - * More grotty system stuff... subprocesses. Frump. These don't use - * the generic cleanup interface because I don't want multiple - * subprocesses to result in multiple three-second pauses; the - * subprocesses have to be "freed" all at once. If someone comes - * along with another resource they want to allocate which has the - * same property, we might want to fold support for that into the - * generic interface, but for now, it's a special case - */ - -struct process_chain { - pid_t pid; - enum kill_conditions kill_how; - struct process_chain *next; -}; - -void note_subprocess (pool *a, int pid, enum kill_conditions how) -{ - struct process_chain *new = - (struct process_chain *)palloc(a, sizeof(struct process_chain)); - - new->pid = pid; - new->kill_how = how; - new->next = a->subprocesses; - a->subprocesses = new; -} - -int spawn_child_err (pool *p, void (*func)(void *), void *data, - enum kill_conditions kill_how, - FILE **pipe_in, FILE **pipe_out, FILE **pipe_err) -{ - int pid; - int in_fds[2]; - int out_fds[2]; - int err_fds[2]; - int save_errno; - - block_alarms(); - - if (pipe_in && pipe (in_fds) < 0) - { - save_errno = errno; - unblock_alarms(); - errno = save_errno; - return 0; - } - - if (pipe_out && pipe (out_fds) < 0) { - save_errno = errno; - if (pipe_in) { - close (in_fds[0]); close (in_fds[1]); - } - unblock_alarms(); - errno = save_errno; - return 0; - } - - if (pipe_err && pipe (err_fds) < 0) { - save_errno = errno; - if (pipe_in) { - close (in_fds[0]); close (in_fds[1]); - } - if (pipe_out) { - close (out_fds[0]); close (out_fds[1]); - } - unblock_alarms(); - errno = save_errno; - return 0; - } - - if ((pid = fork()) < 0) { - save_errno = errno; - if (pipe_in) { - close (in_fds[0]); close (in_fds[1]); - } - if (pipe_out) { - close (out_fds[0]); close (out_fds[1]); - } - if (pipe_err) { - close (err_fds[0]); close (err_fds[1]); - } - unblock_alarms(); - errno = save_errno; - return 0; - } - - if (!pid) { - /* Child process */ - - if (pipe_out) { - close (out_fds[0]); - dup2 (out_fds[1], STDOUT_FILENO); - close (out_fds[1]); - } - - if (pipe_in) { - close (in_fds[1]); - dup2 (in_fds[0], STDIN_FILENO); - close (in_fds[0]); - } - - if (pipe_err) { - close (err_fds[0]); - dup2 (err_fds[1], STDERR_FILENO); - close (err_fds[1]); - } - - /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */ - signal (SIGCHLD, SIG_DFL); /* Was that it? */ - - func (data); - exit (0); /* Should never get here... */ - } - - /* Parent process */ - - note_subprocess (p, pid, kill_how); - - if (pipe_out) { - close (out_fds[1]); -#ifdef __EMX__ - /* Need binary mode set for OS/2. */ - *pipe_out = fdopen (out_fds[0], "rb"); -#else - *pipe_out = fdopen (out_fds[0], "r"); -#endif - - if (*pipe_out) note_cleanups_for_file (p, *pipe_out); - } - - if (pipe_in) { - close (in_fds[0]); -#ifdef __EMX__ - /* Need binary mode set for OS/2 */ - *pipe_in = fdopen (in_fds[1], "wb"); -#else - *pipe_in = fdopen (in_fds[1], "w"); -#endif - - if (*pipe_in) note_cleanups_for_file (p, *pipe_in); - } - - if (pipe_err) { - close (err_fds[1]); -#ifdef __EMX__ - /* Need binary mode set for OS/2. */ - *pipe_err = fdopen (err_fds[0], "rb"); -#else - *pipe_err = fdopen (err_fds[0], "r"); -#endif - - if (*pipe_err) note_cleanups_for_file (p, *pipe_err); - } - - unblock_alarms(); - return pid; -} - -static void free_proc_chain (struct process_chain *procs) -{ - /* Dispose of the subprocesses we've spawned off in the course of - * whatever it was we're cleaning up now. This may involve killing - * some of them off... - */ - - struct process_chain *p; - int need_timeout = 0; - int status; - - if (procs == NULL) return; /* No work. Whew! */ - - /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL - * dance with any of the processes we're cleaning up. If we've got - * any kill-on-sight subprocesses, ditch them now as well, so they - * don't waste any more cycles doing whatever it is that they shouldn't - * be doing anymore. - */ - -#ifndef NEED_WAITPID - /* Pick up all defunct processes */ - for (p = procs; p; p = p->next) { - if (waitpid (p->pid, (int *) 0, WNOHANG) > 0) { - p->kill_how = kill_never; - } - } -#endif - - for (p = procs; p; p = p->next) { - if (p->kill_how == kill_after_timeout) { - /* Subprocess may be dead already. Only need the timeout if not. */ - if (kill (p->pid, SIGTERM) != -1) - need_timeout = 1; - } else if (p->kill_how == kill_always) { - kill (p->pid, SIGKILL); - } - } - - /* Sleep only if we have to... */ - - if (need_timeout) sleep (3); - - /* OK, the scripts we just timed out for have had a chance to clean up - * --- now, just get rid of them, and also clean up the system accounting - * goop... - */ - - for (p = procs; p; p = p->next){ - - if (p->kill_how == kill_after_timeout) - kill (p->pid, SIGKILL); - - if (p->kill_how != kill_never) - waitpid (p->pid, &status, 0); - } -} - diff --git a/usr.sbin/httpd/src/alloc.h b/usr.sbin/httpd/src/alloc.h deleted file mode 100644 index 858bf2cb549..00000000000 --- a/usr.sbin/httpd/src/alloc.h +++ /dev/null @@ -1,252 +0,0 @@ - -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * Resource allocation routines... - * - * designed so that we don't have to keep track of EVERYTHING so that - * it can be explicitly freed later (a fundamentally unsound strategy --- - * particularly in the presence of die()). - * - * Instead, we maintain pools, and allocate items (both memory and I/O - * handlers) from the pools --- currently there are two, one for per - * transaction info, and one for config info. When a transaction is over, - * we can delete everything in the per-transaction pool without fear, and - * without thinking too hard about it either. - * - * rst - */ - -/* Arenas for configuration info and transaction info - * --- actual layout of the pool structure is private to - * alloc.c. - */ - -typedef struct pool pool; - -extern pool *permanent_pool; -void init_alloc(); /* Set up everything */ -pool *make_sub_pool (pool *); /* All pools are subpools of permanent_pool */ -void destroy_pool (pool *); - -/* Clearing out EVERYTHING in an pool... destroys any sub-pools */ - -void clear_pool (struct pool *); - -/* Preparing for exec() --- close files, etc., but *don't* flush I/O - * buffers, *don't* wait for subprocesses, and *don't* free any memory. - */ - -void cleanup_for_exec (); - -/* routines to allocate memory from an pool... */ - -void *palloc(struct pool *, int nbytes); -void *pcalloc(struct pool *, int nbytes); -extern char *pstrdup(struct pool *, const char *s); -extern char *pstrndup(struct pool *, const char *s, int n); -char *pstrcat(struct pool *, ...); /* all '...' must be char* */ - -/* array and alist management... keeping lists of things. - * Common enough to want common support code ... - */ - -typedef struct { - pool *pool; - int elt_size; - int nelts; - int nalloc; - char *elts; -} array_header; - -array_header *make_array (pool *p, int nelts, int elt_size); -void *push_array (array_header *); -void array_cat (array_header *dst, const array_header *src); -array_header *append_arrays (pool *, const array_header *, - const array_header *); - -/* copy_array copies the *entire* array. copy_array_hdr just copies - * the header, and arranges for the elements to be copied if (and only - * if) the code subsequently does a push or arraycat. - */ - -array_header *copy_array (pool *p, const array_header *src); -array_header *copy_array_hdr (pool *p, const array_header *src); - - -/* Tables. Implemented alist style, for now, though we try to keep - * it so that imposing a hash table structure on top in the future - * wouldn't be *too* hard... - * - * Note that key comparisons for these are case-insensitive, largely - * because that's what's appropriate and convenient everywhere they're - * currently being used... - */ - -typedef array_header table; - -typedef struct { - char *key; /* maybe NULL in future; - * check when iterating thru table_elts - */ - char *val; -} table_entry; - -table *make_table (pool *p, int nelts); -table *copy_table (pool *p, const table *); -void clear_table (table *); -char *table_get (const table *, const char *); -void table_set (table *, const char *name, const char *val); -void table_merge (table *, const char *name, const char *more_val); -void table_unset (table *, const char *key); -void table_add (table *, const char *name, const char *val); -void table_do (int (*comp)(void *, const char *, const char *), void *rec, - const table *t, ...); - -table *overlay_tables (pool *p, const table *overlay, const table *base); - -array_header *table_elts (table *); - -#define is_empty_table(t) (((t) == NULL)||((t)->nelts == 0)) - -/* routines to remember allocation of other sorts of things... - * generic interface first. Note that we want to have two separate - * cleanup functions in the general case, one for exec() preparation, - * to keep CGI scripts and the like from inheriting access to things - * they shouldn't be able to touch, and one for actually cleaning up, - * when the actual server process wants to get rid of the thing, - * whatever it is. - * - * kill_cleanup disarms a cleanup, presumably because the resource in - * question has been closed, freed, or whatever, and it's scarce - * enough to want to reclaim (e.g., descriptors). It arranges for the - * resource not to be cleaned up a second time (it might have been - * reallocated). run_cleanup does the same, but runs it first. - * - * Cleanups are identified for purposes of finding & running them off by the - * plain_cleanup and data, which should presumably be unique. - * - * NB any code which invokes register_cleanup or kill_cleanup directly - * is a critical section which should be guarded by block_alarms() and - * unblock_alarms() below... - */ - -void register_cleanup (pool *p, void *data, - void (*plain_cleanup)(void *), - void (*child_cleanup)(void *)); - -void kill_cleanup (pool *p, void *data, void (*plain_cleanup)(void *)); -void run_cleanup (pool *p, void *data, void (*cleanup)(void *)); - -/* The time between when a resource is actually allocated, and when it - * its cleanup is registered is a critical section, during which the - * resource could leak if we got interrupted or timed out. So, anything - * which registers cleanups should bracket resource allocation and the - * cleanup registry with these. (This is done internally by run_cleanup). - * - * NB they are actually implemented in http_main.c, since they are bound - * up with timeout handling in general... - */ - -extern void block_alarms(); -extern void unblock_alarms(); - -/* Common cases which want utility support.. - * the note_cleanups_for_foo routines are for - */ - -FILE *pfopen(struct pool *, const char *name, const char *fmode); -FILE *pfdopen(struct pool *, int fd, const char *fmode); -int popenf(struct pool *, const char *name, int flg, int mode); - -void note_cleanups_for_file (pool *, FILE *); -void note_cleanups_for_fd (pool *, int); -void kill_cleanups_for_fd (pool *p, int fd); - -regex_t *pregcomp (pool *p, const char *pattern, int cflags); -void pregfree (pool *p, regex_t *reg); - -/* routines to note closes... file descriptors are constrained enough - * on some systems that we want to support this. - */ - -int pfclose(struct pool *, FILE *); -int pclosef(struct pool *, int fd); - -/* ... even child processes (which we may want to wait for, - * or to kill outright, on unexpected termination). - * - * spawn_child is a utility routine which handles an awful lot of - * the rigamarole associated with spawning a child --- it arranges - * for pipes to the child's stdin and stdout, if desired (if not, - * set the associated args to NULL). It takes as args a function - * to call in the child, and an argument to be passed to the function. - */ - -enum kill_conditions { kill_never, kill_always, kill_after_timeout, just_wait}; - -int spawn_child_err (pool *, void (*)(void *), void *, - enum kill_conditions, FILE **pipe_in, FILE **pipe_out, - FILE **pipe_err); -#define spawn_child(p,f,v,k,in,out) spawn_child_err(p,f,v,k,in,out,NULL) - -/* magic numbers --- min free bytes to consider a free pool block useable, - * and the min amount to allocate if we have to go to malloc() */ - -#define BLOCK_MINFREE 4096 -#define BLOCK_MINALLOC 8192 - -/* Finally, some accounting */ - -long bytes_in_pool(pool *p); -long bytes_in_free_blocks(); diff --git a/usr.sbin/httpd/src/buff.c b/usr.sbin/httpd/src/buff.c deleted file mode 100644 index 48872043359..00000000000 --- a/usr.sbin/httpd/src/buff.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#include "conf.h" -#include "alloc.h" -#include "buff.h" - -#include <errno.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#ifndef NO_UNISTD_H -#include <unistd.h> -#endif -#ifndef NO_WRITEV -#include <sys/types.h> -#include <sys/uio.h> -#endif - -#ifdef HAVE_BSTRING_H -#include <bstring.h> /* for IRIX, FD_SET calls bzero() */ -#endif - -#define DEFAULT_BUFSIZE (4096) -/* This must be enough to represent (DEFAULT_BUFSIZE - 3) in hex, - * plus two extra characters. - */ -#define CHUNK_HEADER_SIZE (5) - -/* - * Buffered I/O routines. - * These are a replacement for the stdio routines. - * Advantages: - * Known semantics for handling of file-descriptors (on close etc.) - * No problems reading and writing simultanously to the same descriptor - * No limits on the number of open file handles. - * Only uses memory resources; no need to ensure the close routine - * is called. - * Extra code could be inserted between the buffered and un-buffered routines. - * Timeouts could be handled by using select or poll before read or write. - * Extra error handling could be introduced; e.g. - * keep an address to which we should longjump(), or - * keep a stack of routines to call on error. - */ - -/* Notes: - * On reading EOF, EOF will set in the flags and no further Input will - * be done. - * - * On an error except for EAGAIN, ERROR will be set in the flags and no - * futher I/O will be done - */ - -static void -doerror(BUFF *fb, int err) -{ - int errsave = errno; /* Save errno to prevent overwriting it below */ - - if (err == B_RD) - fb->flags |= B_RDERR; - else - fb->flags |= B_WRERR; - if (fb->error != NULL) (*fb->error)(fb, err, fb->error_data); - - errno = errsave; -} - -/* Buffering routines */ -/* - * Create a new buffered stream - */ -BUFF * -bcreate(pool *p, int flags) -{ - BUFF *fb; - - fb = palloc(p, sizeof(BUFF)); - fb->pool=p; - fb->bufsiz = DEFAULT_BUFSIZE; - fb->flags = flags & B_RDWR; - - if (flags & B_RD) fb->inbase = palloc(p, fb->bufsiz); - else fb->inbase = NULL; - - /* overallocate so that we can put a chunk trailer of CRLF into this - * buffer */ - if (flags & B_WR) fb->outbase = palloc(p, fb->bufsiz + 2); - else fb->outbase = NULL; - - fb->inptr = fb->inbase; - - fb->incnt = 0; - fb->outcnt = 0; - fb->outchunk = -1; - fb->error = NULL; - fb->bytes_sent = 0L; - - fb->fd = -1; - fb->fd_in = -1; - - return fb; -} - -/* - * Push some I/O file descriptors onto the stream - */ -void -bpushfd(BUFF *fb, int fd_in, int fd_out) -{ - fb->fd = fd_out; - fb->fd_in = fd_in; -} - -int -bsetopt(BUFF *fb, int optname, const void *optval) -{ - if (optname == BO_BYTECT) - { - fb->bytes_sent = *(const long int *)optval - (long int)fb->outcnt;; - return 0; - } else - { - errno = EINVAL; - return -1; - } -} - -int -bgetopt(BUFF *fb, int optname, void *optval) -{ - if (optname == BO_BYTECT) - { - long int bs=fb->bytes_sent + fb->outcnt; - if (bs < 0L) bs = 0L; - *(long int *)optval = bs; - return 0; - } else - { - errno = EINVAL; - return -1; - } -} - - -static int bflush_core(BUFF *fb); - -/* - * Start chunked encoding. - * - * Note that in order for bputc() to be an efficient macro we have to - * guarantee that start_chunk() has always been called on the buffer before we - * leave any routine in this file. Said another way, if a routine here uses - * end_chunk() and writes something on the wire, then it has to call - * start_chunk() or set an error condition before returning. - */ -static void -start_chunk( BUFF *fb ) -{ - if (fb->outchunk != -1) { - /* already chunking */ - return; - } - if (!(fb->flags & B_WR) || (fb->flags & (B_WRERR|B_EOUT))) { - /* unbuffered writes */ - return; - } - - /* we need at least the header_len + at least 1 data byte - * remember that we've overallocated fb->outbase so that we can always - * fit the two byte CRLF trailer - */ - if( fb->bufsiz - fb->outcnt < CHUNK_HEADER_SIZE + 1 ) { - bflush_core(fb); - } - /* assume there's enough space now */ - fb->outchunk = fb->outcnt; - fb->outcnt += CHUNK_HEADER_SIZE; -} - - -/* - * end a chunk -- tweak the chunk_header from start_chunk, and add a trailer - */ -static void -end_chunk( BUFF *fb ) -{ - int i; - char *strp; - - if( fb->outchunk == -1 ) { - /* not chunking */ - return; - } - - if( fb->outchunk + CHUNK_HEADER_SIZE == fb->outcnt ) { - /* nothing was written into this chunk, and we can't write a 0 size - * chunk because that signifies EOF, so just erase it - */ - fb->outcnt = fb->outchunk; - fb->outchunk = -1; - return; - } - - /* we know this will fit because of how we wrote it in start_chunk() */ - i = ap_snprintf( (char *)&fb->outbase[fb->outchunk], - CHUNK_HEADER_SIZE, - "%x", fb->outcnt - fb->outchunk - CHUNK_HEADER_SIZE ); - - /* we may have to tack some trailing spaces onto the number we just wrote - * in case it was smaller than our estimated size. We've also written - * a \0 into the buffer with ap_snprintf so we might have to put a - * \r back in. - */ - strp = &fb->outbase[fb->outchunk + i]; - while (i < CHUNK_HEADER_SIZE - 2) { - *strp++ = ' '; - ++i; - } - *strp++ = '\015'; - *strp = '\012'; - - /* tack on the trailing CRLF, we've reserved room for this */ - fb->outbase[fb->outcnt++] = '\015'; - fb->outbase[fb->outcnt++] = '\012'; - - fb->outchunk = -1; -} - - -/* - * Set a flag on (1) or off (0). - */ -int bsetflag(BUFF *fb, int flag, int value) -{ - if (value) { - fb->flags |= flag; - if( flag & B_CHUNK ) { - start_chunk(fb); - } - } else { - fb->flags &= ~flag; - if( flag & B_CHUNK ) { - end_chunk(fb); - } - } - return value; -} - - -/* - * This is called instead of read() everywhere in here. It implements - * the B_SAFEREAD functionality -- which is to force a flush() if a read() - * would block. It also deals with the EINTR errno result from read(). - * return code is like read() except EINTR is eliminated. - */ -static int -saferead( BUFF *fb, void *buf, int nbyte ) -{ - int rv; - - if( fb->flags & B_SAFEREAD ) { - fd_set fds; - struct timeval tv; - - /* test for a block */ - do { - FD_ZERO( &fds ); - FD_SET( fb->fd_in, &fds ); - tv.tv_sec = 0; - tv.tv_usec = 0; -#ifdef SELECT_NEEDS_CAST - rv = select( fb->fd_in + 1, (int *)&fds, NULL, NULL, &tv ); -#else - rv = select( fb->fd_in + 1, &fds, NULL, NULL, &tv ); -#endif - } while( rv < 0 && errno == EINTR ); - /* treat any error as if it would block as well */ - if( rv != 1 ) { - bflush(fb); - } - } - do { - rv = read( fb->fd_in, buf, nbyte ); - } while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT)); - return( rv ); -} - - -/* - * Read up to nbyte bytes into buf. - * If fewer than byte bytes are currently available, then return those. - * Returns 0 for EOF, -1 for error. - */ -int -bread(BUFF *fb, void *buf, int nbyte) -{ - int i, nrd; - - if (fb->flags & B_RDERR) return -1; - if (nbyte == 0) return 0; - - if (!(fb->flags & B_RD)) - { -/* Unbuffered reading */ - i = saferead( fb, buf, nbyte ); - if (i == -1 && errno != EAGAIN) doerror(fb, B_RD); - return i; - } - - nrd = fb->incnt; -/* can we fill the buffer */ - if (nrd >= nbyte) - { - memcpy(buf, fb->inptr, nbyte); - fb->incnt = nrd - nbyte; - fb->inptr += nbyte; - return nbyte; - } - - if (nrd > 0) - { - memcpy(buf, fb->inptr, nrd); - nbyte -= nrd; - buf = nrd + (char *)buf; - fb->incnt = 0; - } - if (fb->flags & B_EOF) return nrd; - -/* do a single read */ - if (nbyte >= fb->bufsiz) - { -/* read directly into buffer */ - i = saferead( fb, buf, nbyte ); - if (i == -1) - { - if (nrd == 0) - { - if (errno != EAGAIN) doerror(fb, B_RD); - return -1; - } - else return nrd; - } else if (i == 0) fb->flags |= B_EOF; - } else - { -/* read into hold buffer, then memcpy */ - fb->inptr = fb->inbase; - i = saferead( fb, fb->inptr, fb->bufsiz ); - if (i == -1) - { - if (nrd == 0) - { - if (errno != EAGAIN) doerror(fb, B_RD); - return -1; - } - else return nrd; - } else if (i == 0) fb->flags |= B_EOF; - fb->incnt = i; - if (i > nbyte) i = nbyte; - memcpy(buf, fb->inptr, i); - fb->incnt -= i; - fb->inptr += i; - } - return nrd + i; -} - - -/* - * Reads from the stream into the array pointed to by buff, until - * a (CR)LF sequence is read, or end-of-file condition is encountered - * or until n-1 bytes have been stored in buff. If a CRLF sequence is - * read, it is replaced by a newline character. The string is then - * terminated with a null character. - * - * Returns the number of bytes stored in buff, or zero on end of - * transmission, or -1 on an error. - * - * Notes: - * If null characters are exepected in the data stream, then - * buff should not be treated as a null terminated C string; instead - * the returned count should be used to determine the length of the - * string. - * CR characters in the byte stream not immediately followed by a LF - * will be preserved. - */ -int -bgets(char *buff, int n, BUFF *fb) -{ - int i, ch, ct; - -/* Can't do bgets on an unbuffered stream */ - if (!(fb->flags & B_RD)) - { - errno = EINVAL; - return -1; - } - if (fb->flags & B_RDERR) return -1; - - ct = 0; - i = 0; - for (;;) - { - if (i == fb->incnt) - { -/* no characters left */ - fb->inptr = fb->inbase; - fb->incnt = 0; - if (fb->flags & B_EOF) break; - i = saferead( fb, fb->inptr, fb->bufsiz ); - if (i == -1) - { - buff[ct] = '\0'; - if (ct == 0) - { - if (errno != EAGAIN) doerror(fb, B_RD); - return -1; - } - else return ct; - } - fb->incnt = i; - if (i == 0) - { - fb->flags |= B_EOF; - break; /* EOF */ - } - i = 0; - continue; /* restart with the new data */ - } - - ch = fb->inptr[i++]; - if (ch == '\012') /* got LF */ - { - if (ct == 0) buff[ct++] = '\n'; -/* if just preceeded by CR, replace CR with LF */ - else if (buff[ct-1] == '\015') buff[ct-1] = '\n'; - else if (ct < n-1) buff[ct++] = '\n'; - else i--; /* no room for LF */ - break; - } - if (ct == n-1) - { - i--; /* push back ch */ - break; - } - - buff[ct++] = ch; - } - fb->incnt -= i; - fb->inptr += i; - - buff[ct] = '\0'; - return ct; -} - -/* - * Looks at the stream fb and places the first character into buff - * without removing it from the stream buffer. - * - * Returns 1 on success, zero on end of transmission, or -1 on an error. - * - */ -int blookc(char *buff, BUFF *fb) -{ - int i; - - *buff = '\0'; - - if (!(fb->flags & B_RD)) { /* Can't do blookc on an unbuffered stream */ - errno = EINVAL; - return -1; - } - if (fb->flags & B_RDERR) return -1; - - if (fb->incnt == 0) { /* no characters left in stream buffer */ - fb->inptr = fb->inbase; - if (fb->flags & B_EOF) - return 0; - - i = saferead( fb, fb->inptr, fb->bufsiz ); - - if (i == -1) { - if (errno != EAGAIN) - doerror(fb, B_RD); - return -1; - } - if (i == 0) { - fb->flags |= B_EOF; - return 0; /* EOF */ - } - else fb->incnt = i; - } - - *buff = fb->inptr[0]; - return 1; -} - -/* - * Skip data until a linefeed character is read - * Returns 1 on success, 0 if no LF found, or -1 on error - */ -int -bskiplf(BUFF *fb) -{ - unsigned char *x; - int i; - -/* Can't do bskiplf on an unbuffered stream */ - if (!(fb->flags & B_RD)) - { - errno = EINVAL; - return -1; - } - if (fb->flags & B_RDERR) return -1; - - for (;;) - { - x = (unsigned char *)memchr(fb->inptr, '\012', fb->incnt); - if (x != NULL) - { - x++; - fb->incnt -= x - fb->inptr; - fb->inptr = x; - return 1; - } - - fb->inptr = fb->inbase; - fb->incnt = 0; - if (fb->flags & B_EOF) return 0; - i = saferead( fb, fb->inptr, fb->bufsiz ); - if (i == 0) fb->flags |= B_EOF; - if (i == -1 && errno != EAGAIN) doerror(fb, B_RD); - if (i == 0 || i == -1) return i; - fb->incnt = i; - } -} - -/* - * Emtpy the buffer after putting a single character in it - */ -int -bflsbuf(int c, BUFF *fb) -{ - char ss[1]; - - ss[0] = c; - return bwrite(fb, ss, 1); -} - -/* - * Fill the buffer and read a character from it - */ -int -bfilbuf(BUFF *fb) -{ - int i; - char buf[1]; - - i = bread(fb, buf, 1); - if (i == 0) errno = 0; /* no error; EOF */ - if (i != 1) return EOF; - else return buf[0]; -} - - -/* - * When doing chunked encodings we really have to write everything in the - * chunk before proceeding onto anything else. This routine either writes - * nbytes and returns 0 or returns -1 indicating a failure. - * - * This is *seriously broken* if used on a non-blocking fd. It will poll. - */ -static int -write_it_all(BUFF *fb, const void *buf, int nbyte) -{ - int i; - - if (fb->flags & (B_WRERR|B_EOUT)) - return -1; - - while (nbyte > 0) { - i = write(fb->fd, buf, nbyte); - if (i < 0) { - if (errno != EAGAIN && errno != EINTR) { - doerror (fb, B_WR); - return -1; - } - } - else { - nbyte -= i; - buf = i + (const char *)buf; - } - if (fb->flags & B_EOUT) - return -1; - } - return 0; -} - - -/* - * A hook to write() that deals with chunking. This is really a protocol- - * level issue, but we deal with it here because it's simpler; this is - * an interim solution pending a complete rewrite of all this stuff in - * 2.0, using something like sfio stacked disciplines or BSD's funopen(). - */ -static int -bcwrite(BUFF *fb, const void *buf, int nbyte) -{ - char chunksize[16]; /* Big enough for practically anything */ - int rv; -#ifndef NO_WRITEV - struct iovec vec[3]; - int i; -#endif - - if (fb->flags & (B_WRERR|B_EOUT)) - return -1; - - if (!(fb->flags & B_CHUNK)) { - do rv = write(fb->fd, buf, nbyte); - while (rv == -1 && errno == EINTR && !(fb->flags & B_EOUT)); - if (rv == -1) { - if (errno != EAGAIN) { - doerror (fb, B_WR); - } - return -1; - } else if (rv == 0) { - errno = EAGAIN; - } - return rv; - } - -#ifdef NO_WRITEV - /* without writev() this has poor performance, too bad */ - - ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", nbyte); - if (write_it_all(fb, chunksize, strlen(chunksize)) == -1) - return -1; - if (write_it_all(fb, buf, nbyte) == -1) - return -1; - if (write_it_all(fb, "\015\012", 2) == -1) - return -1; - return nbyte; -#else - -#define NVEC (sizeof(vec)/sizeof(vec[0])) - - vec[0].iov_base = chunksize; - vec[0].iov_len = ap_snprintf(chunksize, sizeof(chunksize), "%x\015\012", - nbyte); - vec[1].iov_base = (void *)buf; /* cast is to avoid const warning */ - vec[1].iov_len = nbyte; - vec[2].iov_base = "\r\n"; - vec[2].iov_len = 2; - /* while it's nice an easy to build the vector and crud, it's painful - * to deal with a partial writev() - */ - for( i = 0; i < NVEC; ) { - do { - rv = writev( fb->fd, &vec[i], NVEC - i ); - } while ((rv <= 0) - && !(fb->flags & B_EOUT) - && (errno == EINTR || errno == EAGAIN || rv == 0)); - if (rv == -1) { - doerror (fb, B_WR); - return -1; - } - /* recalculate vec to deal with partial writes */ - while (rv > 0) { - if( rv <= vec[i].iov_len ) { - vec[i].iov_base = (char *)vec[i].iov_base + rv; - vec[i].iov_len -= rv; - rv = 0; - if( vec[i].iov_len == 0 ) { - ++i; - } - } else { - rv -= vec[i].iov_len; - ++i; - } - } - if (fb->flags & B_EOUT) - return -1; - } - /* if we got here, we wrote it all */ - return nbyte; -#undef NVEC -#endif -} - - -/* - * Write nbyte bytes. - * Only returns fewer than nbyte if an error ocurred. - * Returns -1 if no bytes were written before the error ocurred. - * It is worth noting that if an error occurs, the buffer is in an unknown - * state. - */ -int -bwrite(BUFF *fb, const void *buf, int nbyte) -{ - int i, nwr, useable_bufsiz; - - if (fb->flags & (B_WRERR|B_EOUT)) return -1; - if (nbyte == 0) return 0; - - if (!(fb->flags & B_WR)) - { -/* unbuffered write -- have to use bcwrite since we aren't taking care - * of chunking any other way */ - i = bcwrite(fb, buf, nbyte); - if (i <= 0) { - return -1; - } - fb->bytes_sent += i; - if (fb->flags & B_EOUT) - return -1; - else - return i; - } - -/* - * Whilst there is data in the buffer, keep on adding to it and writing it - * out - */ - nwr = 0; - while (fb->outcnt > 0) - { -/* can we accept some data? */ - i = fb->bufsiz - fb->outcnt; - if (i > 0) - { - if (i > nbyte) i = nbyte; - memcpy(fb->outbase + fb->outcnt, buf, i); - fb->outcnt += i; - nbyte -= i; - buf = i + (const char *)buf; - nwr += i; - if (nbyte == 0) return nwr; /* return if none left */ - } - -/* the buffer must be full */ - if (fb->flags & B_CHUNK) { - end_chunk(fb); - /* it is just too painful to try to re-cram the buffer while - * chunking - */ - if (write_it_all(fb, fb->outbase, fb->outcnt) == -1) { - /* we cannot continue after a chunked error */ - return -1; - } - fb->bytes_sent += fb->outcnt; - fb->outcnt = 0; - break; - } - do { - i = write(fb->fd, fb->outbase, fb->outcnt); - } while (i == -1 && errno == EINTR && !(fb->flags & B_EOUT)); - if (i <= 0) { - if (i == 0) /* return of 0 means non-blocking */ - errno = EAGAIN; - if (nwr == 0) { - if (errno != EAGAIN) doerror(fb, B_WR); - return -1; - } - else return nwr; - } - fb->bytes_sent += i; - - /* deal with a partial write */ - if (i < fb->outcnt) - { - int j, n=fb->outcnt; - unsigned char *x=fb->outbase; - for (j=i; j < n; j++) x[j-i] = x[j]; - fb->outcnt -= i; - } - else - fb->outcnt = 0; - - if (fb->flags & B_EOUT) - return -1; - } -/* we have emptied the file buffer. Now try to write the data from the - * original buffer until there is less than bufsiz left. Note that we - * use bcwrite() to do this for us, it will do the chunking so that - * we don't have to dink around building a chunk in our own buffer. - * Remember we may not be able to use the entire buffer if we're - * chunking. - */ - useable_bufsiz = fb->bufsiz; - if (fb->flags & B_CHUNK) useable_bufsiz -= CHUNK_HEADER_SIZE; - while (nbyte >= useable_bufsiz) - { - i = bcwrite(fb, buf, nbyte); - if (i <= 0) { - if (nwr == 0) { - return -1; - } - else return nwr; - } - fb->bytes_sent += i; - - buf = i + (const char *)buf; - nwr += i; - nbyte -= i; - - if (fb->flags & B_EOUT) - return -1; - } -/* copy what's left to the file buffer */ - fb->outcnt = 0; - if( fb->flags & B_CHUNK ) start_chunk( fb ); - if (nbyte > 0) memcpy(fb->outbase + fb->outcnt, buf, nbyte); - fb->outcnt += nbyte; - nwr += nbyte; - return nwr; -} - -static int bflush_core(BUFF *fb) -{ - int i; - - while (fb->outcnt > 0) - { - do { - i = write(fb->fd, fb->outbase, fb->outcnt); - } while ((i <= 0) - && !(fb->flags & B_EOUT) - && (errno == EINTR || errno == EAGAIN || i == 0)); - - if (i == 0) { - errno = EAGAIN; - return -1; /* return of 0 means B_EOUT and non-blocking */ - } - else if (i < 0) { - if (errno != EAGAIN) doerror(fb, B_WR); - return -1; - } - fb->bytes_sent += i; - - /* - * We should have written all the data, but if the fd was in a - * strange (non-blocking) mode, then we might not have done so. - */ - if (i < fb->outcnt) - { - int j, n=fb->outcnt; - unsigned char *x=fb->outbase; - for (j=i; j < n; j++) x[j-i] = x[j]; - } - fb->outcnt -= i; - - /* If a soft timeout occurs while flushing, the handler should - * have set the buffer flag B_EOUT. - */ - if (fb->flags & B_EOUT) - return -1; - } - - return 0; -} - -/* - * Flushes the buffered stream. - * Returns 0 on success or -1 on error - */ -int bflush(BUFF *fb) -{ - int ret; - - if (!(fb->flags & B_WR) || (fb->flags & B_EOUT)) return 0; - - if (fb->flags & B_WRERR) return -1; - - if (fb->flags & B_CHUNK) end_chunk(fb); - - ret = bflush_core(fb); - - if (ret == 0 && (fb->flags & B_CHUNK)) { - start_chunk(fb); - } - - return ret; -} - -/* - * Flushes and closes the file, even if an error occurred. - * Discards an data that was not read, or not written by bflush() - * Sets the EOF flag to indicate no futher data can be read, - * and the EOUT flag to indicate no further data can be written. - */ -int -bclose(BUFF *fb) -{ - int rc1, rc2, rc3; - - if (fb->flags & B_WR) rc1 = bflush(fb); - else rc1 = 0; - rc2 = close(fb->fd); - if (fb->fd_in != fb->fd) rc3 = close(fb->fd_in); - else rc3 = 0; - - fb->inptr = fb->inbase; - fb->incnt = 0; - fb->outcnt = 0; - - fb->flags |= B_EOF | B_EOUT; - fb->fd = -1; - fb->fd_in = -1; - - if (rc1 != 0) return rc1; - else if (rc2 != 0) return rc2; - else return rc3; -} - -/* - * returns the number of bytes written or -1 on error - */ -int -bputs(const char *x, BUFF *fb) -{ - int i, j=strlen(x); - i = bwrite(fb, x, j); - if (i != j) return -1; - else return j; -} - -/* - * returns the number of bytes written or -1 on error - */ -int -bvputs(BUFF *fb, ...) -{ - int i, j, k; - va_list v; - const char *x; - - va_start(v, fb); - for (k=0;;) - { - x = va_arg(v, const char *); - if (x == NULL) break; - j = strlen(x); - i = bwrite(fb, x, j); - if (i != j) - { - va_end(v); - return -1; - } - k += i; - } - - va_end(v); - - return k; -} - -void -bonerror(BUFF *fb, void (*error)(BUFF *, int, void *), void *data) -{ - fb->error = error; - fb->error_data = data; -} diff --git a/usr.sbin/httpd/src/buff.h b/usr.sbin/httpd/src/buff.h deleted file mode 100644 index aa1926723d3..00000000000 --- a/usr.sbin/httpd/src/buff.h +++ /dev/null @@ -1,139 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#include <stdarg.h> - -/* Reading is buffered */ -#define B_RD (1) -/* Writing is buffered */ -#define B_WR (2) -#define B_RDWR (3) -/* At end of file, or closed stream; no further input allowed */ -#define B_EOF (4) -/* No further output possible */ -#define B_EOUT (8) -/* A read error has occurred */ -#define B_RDERR (16) -/* A write error has occurred */ -#define B_WRERR (32) -#ifdef B_ERROR /* in SVR4: sometimes defined in /usr/include/sys/buf.h */ -#undef B_ERROR /* avoid "warning: `B_ERROR' redefined" */ -#endif -#define B_ERROR (48) -/* Use chunked writing */ -#define B_CHUNK (64) -/* bflush() if a read would block */ -#define B_SAFEREAD (128) - -typedef struct buff_struct BUFF; - -struct buff_struct -{ - int flags; /* flags */ - unsigned char *inptr; /* pointer to next location to read */ - int incnt; /* number of bytes left to read from input buffer; - * always 0 if had a read error */ - int outchunk; /* location of chunk header when chunking */ - int outcnt; /* number of byte put in output buffer */ - unsigned char *inbase; - unsigned char *outbase; - int bufsiz; - void (*error)(BUFF *fb, int op, void *data); - void *error_data; - long int bytes_sent; /* number of bytes actually written */ - - pool *pool; - -/* could also put pointers to the basic I/O routines here */ - int fd; /* the file descriptor */ - int fd_in; /* input file descriptor, if different */ -}; - -/* Options to bset/getopt */ -#define BO_BYTECT (1) - -/* Stream creation and modification */ -extern BUFF *bcreate(pool *p, int flags); -extern void bpushfd(BUFF *fb, int fd_in, int fd_out); -extern int bsetopt(BUFF *fb, int optname, const void *optval); -extern int bgetopt(BUFF *fb, int optname, void *optval); -extern int bsetflag(BUFF *fb, int flag, int value); -extern int bclose(BUFF *fb); - -#define bgetflag(fb, flag) ((fb)->flags & (flag)) - -/* Error handling */ -extern void bonerror(BUFF *fb, void (*error)(BUFF *, int, void *), - void *data); - -/* I/O */ -extern int bread(BUFF *fb, void *buf, int nbyte); -extern int bgets(char *s, int n, BUFF *fb); -extern int blookc(char *buff, BUFF *fb); -extern int bskiplf(BUFF *fb); -extern int bwrite(BUFF *fb, const void *buf, int nbyte); -extern int bflush(BUFF *fb); -extern int bputs(const char *x, BUFF *fb); -extern int bvputs(BUFF *fb, ...); -extern int bprintf(BUFF *fb,const char *fmt,...); -extern int vbprintf(BUFF *fb,const char *fmt,va_list vlist); - -/* Internal routines */ -extern int bflsbuf(int c, BUFF *fb); -extern int bfilbuf(BUFF *fb); - -#define bgetc(fb) ( ((fb)->incnt == 0) ? bfilbuf(fb) : \ - ((fb)->incnt--, *((fb)->inptr++)) ) - -#define bputc(c, fb) ((((fb)->flags & (B_EOUT|B_WRERR|B_WR)) != B_WR || \ - (fb)->outcnt == (fb)->bufsiz) ? bflsbuf(c, (fb)) : \ - ((fb)->outbase[(fb)->outcnt++] = (c), 0)) diff --git a/usr.sbin/httpd/src/conf.h b/usr.sbin/httpd/src/conf.h deleted file mode 100644 index 03c90748dfe..00000000000 --- a/usr.sbin/httpd/src/conf.h +++ /dev/null @@ -1,763 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * conf.h: system-dependant #defines and includes... - * See PORTING for a listing of what they mean - */ - -#if !defined(QNX) && !defined(MPE) -#include <sys/param.h> -#endif - -/* Define one of these according to your system. */ -#if defined(MPE) -#include <sys/times.h> -#define JMP_BUF sigjmp_buf -#define NO_SETSID -#define NO_KILLPG -#define NO_WRITEV -#define NEED_INITGROUPS -#define NEED_STRCASECMP -#define NEED_STRDUP -#define NEED_STRNCASECMP -extern void GETPRIVMODE(); -extern void GETUSERMODE(); -extern char *inet_ntoa(); -#define NO_SLACK - -#elif defined(SUNOS4) -#define HAVE_GMTOFF -#define HAVE_SYS_RESOURCE_H -#undef NO_KILLPG -#undef NO_SETSID -char *crypt(const char *pw, const char *salt); -char *mktemp(char *template); -#define JMP_BUF sigjmp_buf -#define HAVE_MMAP -#include <sys/time.h> -#define NEED_STRERROR -typedef int rlim_t; -#define memmove(a,b,c) bcopy(b,a,c) -#define NO_LINGCLOSE -#define USE_FLOCK_SERIALIZED_ACCEPT - -#elif defined(SOLARIS2) -#undef HAVE_GMTOFF -#define NO_KILLPG -#undef NO_SETSID -#define HAVE_SYS_RESOURCE_H -#define bzero(a,b) memset(a,0,b) -#define JMP_BUF sigjmp_buf -#define USE_FCNTL_SERIALIZED_ACCEPT -#define HAVE_MMAP -#define HAVE_CRYPT_H -int gethostname(char *name, int namelen); - -#elif defined(IRIX) -#undef HAVE_GMTOFF -/* IRIX has killpg, but it's only in _BSD_COMPAT, so don't use it in case - * there's some weird conflict with non-BSD signals */ -#define NO_KILLPG -#undef NO_SETSID -#define JMP_BUF sigjmp_buf -#define USE_FCNTL_SERIALIZED_ACCEPT -#define HAVE_SHMGET -#define HAVE_CRYPT_H -#define NO_LONG_DOUBLE -#define HAVE_BSTRING_H -#define NO_LINGCLOSE - -#elif defined(HIUX) -#define HAVE_SYS_RESOURCE_H -#undef HAVE_GMTOFF -#define NO_KILLPG -#undef NO_SETSID -#ifndef _HIUX_SOURCE -#define _HIUX_SOURCE -#endif -#define JMP_BUF sigjmp_buf -#define HAVE_SHMGET -#define SELECT_NEEDS_CAST - -#elif defined(HPUX) || defined(HPUX10) -#define HAVE_SYS_RESOURCE_H -#undef HAVE_GMTOFF -#define NO_KILLPG -#undef NO_SETSID -#ifndef _HPUX_SOURCE -#define _HPUX_SOURCE -#endif -#define JMP_BUF sigjmp_buf -#define HAVE_SHMGET -#ifndef HPUX10 -#define SELECT_NEEDS_CAST -typedef int rlim_t; -#endif - -#elif defined(AIX) -#undef HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#define HAVE_SYS_SELECT_H -#define JMP_BUF sigjmp_buf -#ifndef __ps2__ -#define HAVE_MMAP -#define DEFAULT_GROUP "nobody" -#endif -#define DEFAULT_USER "nobody" -#ifdef NEED_RLIM_T -typedef int rlim_t; -#endif - -#elif defined(ULTRIX) -#define HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#define ULTRIX_BRAIN_DEATH -#define NEED_STRDUP -/* If you have Ultrix 4.3, and are using cc, const is broken */ -#ifndef __ultrix__ /* Hack to check for pre-Ultrix 4.4 cc */ -#define const /* Not implemented */ -#endif -#define JMP_BUF sigjmp_buf - -#elif defined(OSF1) -#define HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#define JMP_BUF sigjmp_buf -#define HAVE_MMAP -#define HAVE_CRYPT_H -#define NO_LONG_DOUBLE - -#elif defined(PARAGON) -#define HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#define JMP_BUF sigjmp_buf -#define HAVE_MMAP -#define HAVE_CRYPT_H -#define NO_LONG_DOUBLE -typedef int rlim_t; - -#elif defined(SEQUENT) -#define HAVE_GMTOFF -#undef NO_KILLPG -#define NO_SETSID -#define NEED_STRDUP -#define tolower(c) (isupper(c) ? tolower(c) : c) - -#elif defined(NEXT) -typedef unsigned short mode_t; -#define HAVE_GMTOFF -#undef NO_KILLPG -#define NO_SETSID -#define NEED_STRDUP -#define NO_LINGCLOSE -#define NO_UNISTD_H -#undef _POSIX_SOURCE -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif -#ifndef S_ISDIR -#define S_ISDIR(m) (((m)&(S_IFMT)) == (S_IFDIR)) -#endif -#ifndef S_ISREG -#define S_ISREG(m) (((m)&(S_IFMT)) == (S_IFREG)) -#endif -#ifndef S_IXUSR -#define S_IXUSR 00100 -#endif -#ifndef S_IRGRP -#define S_IRGRP 00040 -#endif -#ifndef S_IXGRP -#define S_IXGRP 00010 -#endif -#ifndef S_IROTH -#define S_IROTH 00004 -#endif -#ifndef S_IXOTH -#define S_IXOTH 00001 -#endif -#ifndef S_IRUSR -#define S_IRUSR S_IREAD -#endif -#ifndef S_IWUSR -#define S_IWUSR S_IWRITE -#endif -#ifndef S_IWGRP -#define S_IWGRP 000020 -#endif -#ifndef S_IWOTH -#define S_IWOTH 000002 -#ifndef rlim_t -typedef int rlim_t; -#endif -typedef u_long n_long; -#endif - -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 -#define waitpid(a,b,c) wait4((a) == -1 ? 0 : (a),(union wait *)(b),c,NULL) -typedef int pid_t; -#define JMP_BUF jmp_buf -#define USE_LONGJMP -#define NO_USE_SIGACTION - -#elif defined(LINUX) -#if LINUX > 1 -#define HAVE_SHMGET -#define HAVE_SYS_RESOURCE_H -typedef int rlim_t; -#endif -#define USE_FCNTL_SERIALIZED_ACCEPT -#undef HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#undef NEED_STRDUP -#define JMP_BUF sigjmp_buf -#include <sys/time.h> - -#elif defined(SCO) -#undef HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#define NEED_INITGROUPS -#define NO_WRITEV -#define JMP_BUF sigjmp_buf -#define SIGURG SIGUSR1 /* but note, this signal will be sent to a process group if enabled (for OOB data). It is not currently enabled. */ -#include <sys/time.h> - -#elif defined(SCO5) - -#define JMP_BUF sigjmp_buf -#define SIGURG SIGUSR1 -#define HAVE_SYS_SELECT_H -#define USE_FCNTL_SERIALIZED_ACCEPT -#define HAVE_MMAP -#define HAVE_SYS_RESOURCE_H -#define SecureWare - -/* Although SCO 5 defines these in <strings.h> (note the "s") they don't have -consts. Sigh. */ -extern int strcasecmp(const char *,const char *); -extern int strncasecmp(const char *,const char *,unsigned); - -#elif defined(AUX) -/* These are to let -Wall compile more cleanly */ -extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *,const char *,unsigned); -extern int set42sig(), getopt(), getpeername(), bzero(); -extern int listen(), bind(), socket(), getsockname(); -extern int accept(), gethostname(), connect(), lstat(); -extern int select(), killpg(), shutdown(); -extern int initgroups(), setsockopt(); -extern char *shmat(); -extern int shmctl(); -extern int shmget(); -extern char *sbrk(); -extern char *crypt(); -#include <sys/time.h> -#undef HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#define NEED_STRDUP -#define JMP_BUF sigjmp_buf -/* fcntl() locking is expensive with NFS */ -#define USE_FLOCK_SERIALIZED_ACCEPT -#define HAVE_SHMGET -/* - * NOTE: If when you run Apache under A/UX and you get a warning - * that httpd couldn't move break, then the below value for - * MOVEBREAK (64megs) is too large for your setup. Try reducing - * to 0x2000000 which is still PLENTY of space. I doubt if - * even on heavy systems sbrk() would be called at all... - */ -#define MOVEBREAK 0x4000000 -#define NO_LINGCLOSE -#define NO_SLACK - -#elif defined(SVR4) -#define NO_KILLPG -#undef NO_SETSID -#undef NEED_STRDUP -#define NEED_STRCASECMP -#define NEED_STRNCASECMP -#define bzero(a,b) memset(a,0,b) -#define JMP_BUF sigjmp_buf -/* A lot of SVR4 systems need this */ -#define USE_FCNTL_SERIALIZED_ACCEPT - -#elif defined(UW) -#define NO_LINGCLOSE -#define NO_KILLPG -#undef NO_SETSID -#undef NEED_STRDUP -#define NEED_STRCASECMP -#define NEED_STRNCASECMP -#define bzero(a,b) memset(a,0,b) -#define JMP_BUF sigjmp_buf -#define HAVE_RESOURCE -#define HAVE_MMAP -#define HAVE_SHMGET -#define HAVE_CRYPT_H -#define HAVE_SYS_SELECT_H -#define HAVE_SYS_RESOURCE_H -#include <sys/time.h> -#define _POSIX_SOURCE - -#elif defined(DGUX) -#define NO_KILLPG -#undef NO_SETSID -#undef NEED_STRDUP -#define NEED_STRCASECMP -#define NEED_STRNCASECMP -#define bzero(a,b) memset(a,0,b) -#define JMP_BUF sigjmp_buf -/* A lot of SVR4 systems need this */ -#define USE_FCNTL_SERIALIZED_ACCEPT - -#elif defined(__NetBSD__) || defined(__OpenBSD__) -#define HAVE_SYS_RESOURCE_H -#define HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#define JMP_BUF sigjmp_buf -#define DEFAULT_USER "nobody" -#define DEFAULT_GROUP "nogroup" -#define HAVE_MMAP -#define USE_FLOCK_SERIALIZED_ACCEPT - - -#elif defined(UTS21) -#undef HAVE_GMTOFF -#undef NO_KILLPG -#define NO_SETSID -#define NEED_WAITPID -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 -#define strftime(buf,bufsize,fmt,tm) ascftime(buf,fmt,tm) -#include <sys/types.h> - -#elif defined(APOLLO) -#undef HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID - -#elif defined(__FreeBSD__) || defined(__bsdi__) -#if defined(__FreeBSD__) -#include <osreldate.h> -#endif -#define HAVE_SYS_RESOURCE_H -#define HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#define JMP_BUF sigjmp_buf -#define HAVE_MMAP -#define DEFAULT_USER "nobody" -#define DEFAULT_GROUP "nogroup" -#if defined(__bsdi__) || \ -(defined(__FreeBSD_version) && (__FreeBSD_version < 220000)) -typedef quad_t rlim_t; -#endif -#define USE_FLOCK_SERIALIZED_ACCEPT - -#elif defined(QNX) -#ifndef crypt -char *crypt(const char *pw, const char *salt); -#endif -#ifndef initgroups -int initgroups (char *, int); -#endif -#ifndef strncasecmp -#define strncasecmp strnicmp -#endif -#undef NO_KILLPG -#undef NO_SETSID -#define NEED_INITGROUPS -#define NEED_SELECT_H -#define NEED_PROCESS_H -#define HAVE_SYS_SELECT_H -#include <unix.h> -#define JMP_BUF sigjmp_buf - -#elif defined(LYNXOS) -#undef NO_KILLPG -#undef NO_SETSID -#define NEED_STRCASECMP -#define NEED_STRNCASECMP -#define NEED_INITGROUPS -#define JMP_BUF jmp_buf - -#elif defined(UXPDS) -#undef NEED_STRCASECMP -#undef NEED_STRNCASECMP -#undef NEED_STRDUP -#undef HAVE_GMTOFF -#define NO_KILLPG -#undef NO_SETSID -#define HAVE_RESOURCE 1 -#define bzero(a,b) memset(a,0,b) -#define JMP_BUF sigjmp_buf -#define USE_FCNTL_SERIALIZED_ACCEPT -#define HAVE_MMAP -#define HAVE_CRYPT_H - -#elif defined(__EMX__) -/* Defines required for EMX OS/2 port. */ -#define JMP_BUF sigjmp_buf -#define NO_KILLPG -#define NEED_STRCASECMP -#define NEED_STRNCASECMP -#define NO_SETSID -/* Add some drive name support */ -#define chdir _chdir2 -#include <sys/time.h> -#define MAXSOCKETS 4096 -#define HAVE_MMAP - -#elif defined(__MACHTEN__) -typedef int rlim_t; -#define JMP_BUF sigjmp_buf -#undef NO_KILLPG -#define NO_SETSID -#define HAVE_GMTOFF -#ifndef __MACHTEN_PPC__ -#ifndef __MACHTEN_68K__ -#define __MACHTEN_68K__ -#endif -#define USE_FLOCK_SERIALIZED_ACCEPT -#define NO_USE_SIGACTION -#define USE_LONGJMP -#undef NEED_STRDUP -#else -#define HAVE_SHMGET -#define USE_FCNTL_SERIALIZED_ACCEPT -#endif - -/* Convex OS v11 */ -#elif defined(CONVEXOS11) -#undef HAVE_GMTOFF -#undef NO_KILLPG -#undef NO_SETSID -#undef NEED_STRDUP -#define HAVE_MMAP - -#define NO_TIMEZONE -#include <stdio.h> -#include <sys/types.h> -#define JMP_BUF jmp_buf -typedef int rlim_t; - -#elif defined(ISC) -#include <net/errno.h> -#define NO_KILLPG -#undef NO_SETSID -#define HAVE_SHMGET -#define SIGURG SIGUSR1 -#define JMP_BUF sigjmp_buf -#define USE_FCNTL_SERIALIZED_ACCEPT - -/* Unknown system - Edit these to match */ -#else -#ifdef BSD -#define HAVE_GMTOFF -#else -#undef HAVE_GMTOFF -#endif -/* NO_KILLPG is set on systems that don't have killpg */ -#undef NO_KILLPG -/* NO_SETSID is set on systems that don't have setsid */ -#undef NO_SETSID -/* NEED_STRDUP is set on stupid systems that don't have strdup. */ -#undef NEED_STRDUP -#endif - -/* Do we have sys/resource.h; assume that BSD does. */ -#ifndef HAVE_SYS_RESOURCE_H -#ifdef BSD -#define HAVE_SYS_RESOURCE_H -#endif -#endif /* HAVE_SYS_RESOURCE_H */ - -/* - * The particular directory style your system supports. If you have dirent.h - * in /usr/include (POSIX) or /usr/include/sys (SYSV), #include - * that file and define DIR_TYPE to be dirent. Otherwise, if you have - * /usr/include/sys/dir.h, define DIR_TYPE to be direct and include that - * file. If you have neither, I'm confused. - */ - -#include <sys/types.h> -#include <stdarg.h> -/* - * We use snprintf() to avoid overflows, but we include - * our own version (ap_snprintf). Allow for people to use their - * snprintf() if they want - */ -#ifdef HAVE_SNPRINTF -#define ap_snprintf snprintf -#define ap_vsnprintf vsnprintf -#else -int ap_snprintf(char *buf, size_t len, const char *format,...); -int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap); -#endif - -#if !defined(NEXT) -#include <dirent.h> -#define DIR_TYPE dirent -#else -#include <sys/dir.h> -#define DIR_TYPE direct -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#ifndef MPE -#include <sys/file.h> -#endif -#include <sys/socket.h> -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif -#include <ctype.h> -#include <netinet/in.h> -#include <netdb.h> -#include <sys/ioctl.h> -#ifndef MPE -#include <arpa/inet.h> /* for inet_ntoa */ -#endif -#include <time.h> /* for ctime */ -#include <signal.h> -#include <errno.h> -#include <sys/wait.h> -#include <pwd.h> -#include <grp.h> -#include <fcntl.h> -#include <limits.h> -#if !defined(QNX) && !defined(CONVEXOS11) && !defined(NEXT) -#include <memory.h> -#endif -#ifdef NEED_PROCESS_H -#include <process.h> -#endif - -#include <regex.h> - -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> -#ifdef SUNOS4 -int getrlimit( int, struct rlimit *); -int setrlimit( int, struct rlimit *); -#endif -#endif -#ifdef HAVE_MMAP -#ifndef __EMX__ -/* This file is not needed for OS/2 */ -#include <sys/mman.h> -#endif -#endif -#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) -#define MAP_ANON MAP_ANONYMOUS -#endif - -#if defined(HAVE_MMAP) && defined(NO_MMAP) -#undef HAVE_MMAP -#endif - -#ifndef LOGNAME_MAX -#define LOGNAME_MAX 25 -#endif - -#ifndef NEXT -#include <unistd.h> -#endif - -#ifdef ultrix -#define ULTRIX_BRAIN_DEATH -#endif - -#ifndef S_ISLNK -#ifndef __EMX__ -/* Don't define this for OS/2 */ -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif -#endif - -#ifndef INADDR_NONE -#define INADDR_NONE ((unsigned long) -1) -#endif - -/* - * Replace signal function with sigaction equivalent - */ -#ifndef NO_USE_SIGACTION -typedef void Sigfunc(int); - -#if defined(SIG_IGN) && !defined(SIG_ERR) -#define SIG_ERR ((Sigfunc *)-1) -#endif - -/* - * For some strange reason, QNX defines signal to signal. Eliminate it. - */ -#ifdef signal -#undef signal -#endif -#define signal(s,f) ap_signal(s,f) -Sigfunc *signal(int signo, Sigfunc *func); -#endif - -#include <setjmp.h> - -#if defined(USE_LONGJMP) -#define ap_longjmp(x, y) longjmp((x), (y)) -#define ap_setjmp(x) setjmp(x) -#else -#define ap_longjmp(x, y) siglongjmp((x), (y)) -#define ap_setjmp(x) sigsetjmp((x), 1) -#endif - -/* Finding offsets of elements within structures. - * Taken from the X code... they've sweated portability of this stuff - * so we don't have to. Sigh... - */ - -#if defined(CRAY) || defined(__arm) -#if __STDC__ -#define XtOffset(p_type,field) _Offsetof(p_type,field) -#else -#ifdef CRAY2 -#define XtOffset(p_type,field) \ - (sizeof(int)*((unsigned int)&(((p_type)NULL)->field))) - -#else /* !CRAY2 */ - -#define XtOffset(p_type,field) ((unsigned int)&(((p_type)NULL)->field)) - -#endif /* !CRAY2 */ -#endif /* __STDC__ */ -#else /* ! (CRAY || __arm) */ - -#define XtOffset(p_type,field) \ - ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL))) - -#endif /* !CRAY */ - -#ifdef offsetof -#define XtOffsetOf(s_type,field) offsetof(s_type,field) -#else -#define XtOffsetOf(s_type,field) XtOffset(s_type*,field) -#endif - -#ifdef SUNOS_LIB_PROTOTYPES -/* Prototypes needed to get a clean compile with gcc -Wall. - * Believe it or not, these do have to be declared, at least on SunOS, - * because they aren't mentioned in the relevant system headers. - * Sun Quality Software. Gotta love it. - */ - -int getopt (int, char **, char *); - -int strcasecmp (char *, char *); -int strncasecmp (char *, char *, int); -int toupper(int); -int tolower(int); - -int printf (char *, ...); -int fprintf (FILE *, char *, ...); -int fputs (char *, FILE *); -int fread (char *, int, int, FILE *); -int fwrite (char *, int, int, FILE *); -int fflush (FILE *); -int fclose (FILE *); -int ungetc (int, FILE *); -int _filbuf (FILE *); /* !!! */ -int _flsbuf (unsigned char, FILE *); /* !!! */ -int sscanf (char *, char *, ...); -void setbuf (FILE *, char *); -void perror (char *); - -time_t time (time_t *); -int strftime (char *, int, char *, struct tm *); - -int initgroups (char *, int); -int wait3 (int *, int, void*); /* Close enough for us... */ -int lstat (const char *, struct stat *); -int stat (const char *, struct stat *); -int flock (int, int); -#ifndef NO_KILLPG -int killpg(int, int); -#endif -int socket (int, int, int); -int setsockopt (int, int, int, const char*, int); -int listen (int, int); -int bind (int, struct sockaddr *, int); -int connect (int, struct sockaddr *, int); -int accept (int, struct sockaddr *, int *); -int shutdown (int, int); - -int getsockname (int s, struct sockaddr *name, int *namelen); -int getpeername (int s, struct sockaddr *name, int *namelen); -int gethostname (char *name, int namelen); -void syslog (int, char *, ...); -char *mktemp (char *); - -long vfprintf (FILE *, char *, va_list); - -#endif diff --git a/usr.sbin/httpd/src/explain.c b/usr.sbin/httpd/src/explain.c deleted file mode 100644 index 6490c940522..00000000000 --- a/usr.sbin/httpd/src/explain.c +++ /dev/null @@ -1,14 +0,0 @@ -#include <stdio.h> -#include <stdarg.h> -#include "explain.h" - -void _Explain(const char *szFile,int nLine,const char *szFmt,...) - { - va_list vlist; - - fprintf(stderr,"%s(%d): ",szFile,nLine); - va_start(vlist,szFmt); - vfprintf(stderr,szFmt,vlist); - va_end(vlist); - fputc('\n',stderr); - } diff --git a/usr.sbin/httpd/src/explain.h b/usr.sbin/httpd/src/explain.h deleted file mode 100644 index 5912502585e..00000000000 --- a/usr.sbin/httpd/src/explain.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef EXPLAIN -#define DEF_Explain -#define Explain0(f) -#define Explain1(f,a1) -#define Explain2(f,a1,a2) -#define Explain3(f,a1,a2,a3) -#define Explain4(f,a1,a2,a3,a4) -#define Explain5(f,a1,a2,a3,a4,a5) -#define Explain6(f,a1,a2,a3,a4,a5,a6) -#else -#define DEF_Explain static const char *__ExplainFile=__FILE__; -void _Explain(const char *szFile,int nLine,const char *szFmt,...); -#define Explain0(f) _Explain(__ExplainFile,__LINE__,f) -#define Explain1(f,a1) _Explain(__ExplainFile,__LINE__,f,a1) -#define Explain2(f,a1,a2) _Explain(__ExplainFile,__LINE__,f,a1,a2) -#define Explain3(f,a1,a2,a3) _Explain(__ExplainFile,__LINE__,f,a1,a2,a3) -#define Explain4(f,a1,a2,a3,a4) _Explain(__ExplainFile,__LINE__,f,a1,a2,a3,a4) -#define Explain5(f,a1,a2,a3,a4,a5) \ - _Explain(__ExplainFile,__LINE__,f,a1,a2,a3,a4,a5) -#define Explain6(f,a1,a2,a3,a4,a5,a6) \ - _Explain(__ExplainFile,__LINE__,f,a1,a2,a3,a4,a5,a6) - -#endif diff --git a/usr.sbin/httpd/src/http_bprintf.c b/usr.sbin/httpd/src/http_bprintf.c deleted file mode 100644 index 3035b759ccf..00000000000 --- a/usr.sbin/httpd/src/http_bprintf.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * printf() style routines stolen from FastCGI - * Copyright (c) 1996 Open Market, Inc. - */ - -/* - * Modified to work with Apache buffering routines by Ben Laurie - * <ben@algroup.co.uk>. - * - * Modifications Copyright (C) 1996 Ben Laurie. - * - * History: - * 18 May 1996 Initial revision [Ben Laurie] - * - */ - -#include <assert.h> -#include <math.h> -#include "conf.h" -#include "alloc.h" -#include "buff.h" - -#if !defined(max) -#define max(a,b) (a > b ? a : b) -#endif - -#ifdef NO_LONG_DOUBLE -#define LONG_DOUBLE double -#else -#define LONG_DOUBLE long double -#endif - -#define FALSE 0 -#define TRUE 1 - -#define PRINTF_BUFFLEN 100 - /* - * More than sufficient space for all unmodified conversions - * except %s and %f. - */ -#define FMT_BUFFLEN 25 - /* - * Max size of a format specifier is 1 + 5 + 7 + 7 + 2 + 1 + slop - */ -#define NULL_STRING "(null)" - /* - * String displayed if given a NULL pointer. - */ - -/* - * Copy n characters from *srcPtr to *destPtr, then increment - * both *srcPtr and *destPtr by n. - */ -static void CopyAndAdvance(char **destPtr, const char **srcPtr, int n) - { - char *dest = *destPtr; - const char *src = *srcPtr; - int i; - - for (i = 0; i < n; i++) - *dest++ = *src++; - *destPtr = dest; - *srcPtr = src; - } - -int vbprintf(BUFF *bp, const char *format, va_list arg) - { - const char *f,*fStop,*percentPtr,*p; - char *fmtBuffPtr, *buffPtr; - int op, performedOp, sizeModifier, buffLen, specifierLength; - int fastPath, n, buffReqd, minWidth, precision, exp; - int buffCount = 0; - int auxBuffLen = 0; - char *auxBuffPtr = NULL; - int streamCount = 0; - char fmtBuff[FMT_BUFFLEN]; - char buff[PRINTF_BUFFLEN]; - - int intArg; - short shortArg; - long longArg; - unsigned unsignedArg; - unsigned long uLongArg; - unsigned short uShortArg; - char *charPtrArg = NULL; - void *voidPtrArg; - int *intPtrArg; - long *longPtrArg; - short *shortPtrArg; - double doubleArg = 0.0; - LONG_DOUBLE lDoubleArg = 0.0; - - fmtBuff[0] = '%'; - f=format; - fStop = f + strlen(f); - while (f != fStop) - { - percentPtr = memchr(f, '%', fStop - f); - if(percentPtr == NULL) percentPtr = fStop; - if(percentPtr != f) - { - if(bwrite(bp,f,percentPtr - f) < 0) - goto ErrorReturn; - streamCount += percentPtr - f; - f = percentPtr; - if(f == fStop) - break; - } - fastPath = TRUE; - /* - * The following loop always executes either once or twice. - */ - for (;;) - { - if(fastPath) - { - /* - * Fast path: Scan optimistically, hoping that no flags, - * minimum field width, or precision are specified. - * Use the preallocated buffer, which is large enough - * for all fast path cases. If the conversion specifier - * is really more complex, run the loop a second time - * using the slow path. - * Note that fast path execution of %s bypasses the buffer - * and %f is not attempted on the fast path due to - * its large buffering requirements. - */ - op = percentPtr[1]; - switch(op) - { - case 'l': - case 'L': - case 'h': - sizeModifier = op; - op = percentPtr[2]; - fmtBuff[1] = sizeModifier; - fmtBuff[2] = op; - fmtBuff[3] = '\0'; - specifierLength = 3; - break; - default: - sizeModifier = ' '; - fmtBuff[1] = op; - fmtBuff[2] = '\0'; - specifierLength = 2; - break; - } - buffPtr = buff; - buffLen = PRINTF_BUFFLEN; - } - else - { - /* - * Slow path: Scan the conversion specifier and construct - * a new format string, compute an upper bound on the - * amount of buffering that sprintf will require, - * and allocate a larger buffer if necessary. - */ - p = percentPtr + 1; - fmtBuffPtr = &fmtBuff[1]; - /* - * Scan flags - */ - n = strspn(p, "-0+ #"); - if(n > 5) - goto ErrorReturn; - CopyAndAdvance(&fmtBuffPtr, &p, n); - - /* Optimiser bug in SCO 5 - p is not advanced here under -O2. - * -K noinline fixes it. Ben. - */ - - /* - * Scan minimum field width - */ - n = strspn(p, "0123456789"); - if(n == 0) - { - if(*p == '*') - { - minWidth = va_arg(arg, int); - if(abs(minWidth) > 999999) goto ErrorReturn; - /* - * The following use of strlen rather than the - * value returned from sprintf is because SUNOS4 - * returns a char * instead of an int count. - */ - sprintf(fmtBuffPtr, "%d", minWidth); - fmtBuffPtr += strlen(fmtBuffPtr); - p++; - } - else - minWidth = 0; - } - else if(n <= 6) - { - minWidth = strtol(p, NULL, 10); - CopyAndAdvance(&fmtBuffPtr, &p, n); - } - else - goto ErrorReturn; - /* - * Scan precision - */ - if(*p == '.') - { - p++; - n = strspn(p, "0123456789"); - if(n == 0) - { - if(*p == '*') - { - precision = va_arg(arg, int); - if(precision < 0) precision = 0; - if(precision > 999999) goto ErrorReturn; - /* - * The following use of strlen rather than the - * value returned from sprintf is because SUNOS4 - * returns a char * instead of an int count. - */ - sprintf(fmtBuffPtr, ".%d", precision); - fmtBuffPtr += strlen(fmtBuffPtr); - p++; - } - else - precision = 0; - } - else if(n <= 6) - { - precision = strtol(p, NULL, 10); - *fmtBuffPtr++='.'; - CopyAndAdvance(&fmtBuffPtr, &p, n); - } - else - goto ErrorReturn; - } - else - precision = -1; - /* - * Scan size modifier and conversion operation - */ - switch(*p) - { - case 'l': - case 'L': - case 'h': - sizeModifier = *p; - CopyAndAdvance(&fmtBuffPtr, &p, 1); - break; - - default: - sizeModifier = ' '; - break; - } - op = *p; - CopyAndAdvance(&fmtBuffPtr, &p, 1); - assert(fmtBuffPtr - fmtBuff < FMT_BUFFLEN); - *fmtBuffPtr = '\0'; - /* - bwrite(bp,"[",1); - bwrite(bp,fmtBuff,strlen(fmtBuff)); - bwrite(bp,"]",1); - */ - specifierLength = p - percentPtr; - /* - * Bound the required buffer size. For s and f - * conversions this requires examining the argument. - */ - switch(op) - { - case 'd': - case 'i': - case 'u': - case 'o': - case 'x': - case 'X': - case 'c': - case 'p': - buffReqd = max(precision, 46); - break; - - case 's': - charPtrArg = va_arg(arg, char *); - if (charPtrArg == NULL) { - charPtrArg = NULL_STRING; - }; - if(precision == -1) - buffReqd = strlen(charPtrArg); - else - { - p = memchr(charPtrArg, '\0', precision); - if (p == NULL) - buffReqd = precision; - else - buffReqd = p - charPtrArg; - } - break; - - case 'f': - switch(sizeModifier) - { - case ' ': - doubleArg = va_arg(arg, double); - frexp(doubleArg, &exp); - break; - - case 'L': - lDoubleArg = va_arg(arg, LONG_DOUBLE); - frexp(lDoubleArg, &exp); - break; - - default: - goto ErrorReturn; - } - if(precision == -1) - precision = 6; - buffReqd = precision + 3 + ((exp > 0) ? exp/3 : 0); - break; - - case 'e': - case 'E': - case 'g': - case 'G': - if(precision == -1) - precision = 6; - buffReqd = precision + 8; - break; - - case 'n': - case '%': - default: - goto ErrorReturn; - } - buffReqd = max(buffReqd + 10, minWidth); - /* - * Allocate the buffer - */ - if(buffReqd <= PRINTF_BUFFLEN) - { - buffPtr = buff; - buffLen = PRINTF_BUFFLEN; - } - else - { - if(auxBuffPtr == NULL || buffReqd > auxBuffLen) - { - if(auxBuffPtr != NULL) free(auxBuffPtr); - auxBuffPtr = malloc(buffReqd); - auxBuffLen = buffReqd; - if(auxBuffPtr == NULL) - goto ErrorReturn; - } - buffPtr = auxBuffPtr; - buffLen = auxBuffLen; - } - } - /* - * This giant switch statement requires the following variables - * to be set up: op, sizeModifier, arg, buffPtr, fmtBuff. - * When fastPath == FALSE and op == 's' or 'f', the argument - * has been read into charPtrArg, doubleArg, or lDoubleArg. - * The statement produces the boolean performedOp, TRUE iff - * the op/sizeModifier were executed and argument consumed; - * if performedOp, the characters written into buffPtr[] - * and the character count buffCount (== EOF meaning error). - * - * The switch cases are arranged in the same order as in the - * description of fprintf in section 15.11 of Harbison and Steele. - */ - performedOp = TRUE; - switch(op) - { - case 'd': - case 'i': - switch(sizeModifier) - { - case ' ': - intArg = va_arg(arg, int); - sprintf(buffPtr, fmtBuff, intArg); - buffCount = strlen(buffPtr); - break; - - case 'l': - longArg = va_arg(arg, long); - sprintf(buffPtr, fmtBuff, longArg); - buffCount = strlen(buffPtr); - break; - - case 'h': - shortArg = va_arg(arg, short); - sprintf(buffPtr, fmtBuff, shortArg); - buffCount = strlen(buffPtr); - break; - - default: - goto ErrorReturn; - } - break; - - case 'u': - case 'o': - case 'x': - case 'X': - switch(sizeModifier) - { - case ' ': - unsignedArg = va_arg(arg, unsigned); - sprintf(buffPtr, fmtBuff, unsignedArg); - buffCount = strlen(buffPtr); - break; - - case 'l': - uLongArg = va_arg(arg, unsigned long); - sprintf(buffPtr, fmtBuff, uLongArg); - buffCount = strlen(buffPtr); - break; - - case 'h': - uShortArg = va_arg(arg, unsigned short); - sprintf(buffPtr, fmtBuff, uShortArg); - buffCount = strlen(buffPtr); - break; - - default: - goto ErrorReturn; - } - break; - - case 'c': - switch(sizeModifier) - { - case ' ': - intArg = va_arg(arg, int); - sprintf(buffPtr, fmtBuff, intArg); - buffCount = strlen(buffPtr); - break; - - case 'l': - /* - * XXX: Allowed by ISO C Amendment 1, but - * many platforms don't yet support wint_t - */ - goto ErrorReturn; - - default: - goto ErrorReturn; - } - break; - - case 's': - switch(sizeModifier) - { - case ' ': - if(fastPath) - { - buffPtr = va_arg(arg, char *); - if (buffPtr == NULL) { - buffPtr = NULL_STRING; - }; - buffCount = strlen(buffPtr); - buffLen = buffCount + 1; - } - else - { - sprintf(buffPtr, fmtBuff, charPtrArg); - buffCount = strlen(buffPtr); - } - break; - - case 'l': - /* - * XXX: Don't know how to convert a sequence - * of wide characters into a byte stream, or - * even how to predict the buffering required. - */ - goto ErrorReturn; - - default: - goto ErrorReturn; - } - break; - - case 'p': - if(sizeModifier != ' ') - goto ErrorReturn; - voidPtrArg = va_arg(arg, void *); - sprintf(buffPtr, fmtBuff, voidPtrArg); - buffCount = strlen(buffPtr); - break; - - case 'n': - switch(sizeModifier) - { - case ' ': - intPtrArg = va_arg(arg, int *); - *intPtrArg = streamCount; - break; - - case 'l': - longPtrArg = va_arg(arg, long *); - *longPtrArg = streamCount; - break; - - case 'h': - shortPtrArg = va_arg(arg, short *); - *shortPtrArg = streamCount; - break; - - default: - goto ErrorReturn; - } - buffCount = 0; - break; - - case 'f': - if(fastPath) - { - performedOp = FALSE; - break; - } - - switch(sizeModifier) - { - case ' ': - sprintf(buffPtr, fmtBuff, doubleArg); - buffCount = strlen(buffPtr); - break; - - case 'L': - sprintf(buffPtr, fmtBuff, lDoubleArg); - buffCount = strlen(buffPtr); - break; - - default: - goto ErrorReturn; - } - break; - /* FIXME: Used to flow through here? Should it? Ben */ - - case 'e': - case 'E': - case 'g': - case 'G': - switch(sizeModifier) - { - case ' ': - doubleArg = va_arg(arg, double); - sprintf(buffPtr, fmtBuff, doubleArg); - buffCount = strlen(buffPtr); - break; - - case 'L': - lDoubleArg = va_arg(arg, LONG_DOUBLE); - sprintf(buffPtr, fmtBuff, lDoubleArg); - buffCount = strlen(buffPtr); - break; - - default: - goto ErrorReturn; - } - break; - - case '%': - if(sizeModifier != ' ') - goto ErrorReturn; - buff[0] = '%'; - buffCount = 1; - break; - - case '\0': - goto ErrorReturn; - - default: - performedOp = FALSE; - break; - } /* switch(op) */ - - if(performedOp) - break; - if(!fastPath) - goto ErrorReturn; - fastPath = FALSE; - } /* for (;;) */ - assert(buffCount < buffLen); - if(buffCount > 0) - { - if(bwrite(bp,buffPtr,buffCount) < 0) - goto ErrorReturn; - streamCount += buffCount; - } - else if(buffCount < 0) - goto ErrorReturn; - f += specifierLength; - } /* while(f != fStop) */ - goto NormalReturn; -ErrorReturn: - streamCount = -1; -NormalReturn: - if(auxBuffPtr != NULL) - free(auxBuffPtr); - return streamCount; - } diff --git a/usr.sbin/httpd/src/http_conf_globals.h b/usr.sbin/httpd/src/http_conf_globals.h deleted file mode 100644 index 3a60e7db77b..00000000000 --- a/usr.sbin/httpd/src/http_conf_globals.h +++ /dev/null @@ -1,86 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * Process config --- what the process ITSELF is doing - */ - -extern int standalone; -extern uid_t user_id; -extern char *user_name; -extern gid_t group_id; -#ifdef MULTIPLE_GROUPS -extern gid_t group_id_list[NGROUPS_MAX]; -#endif -extern int max_requests_per_child; -extern struct in_addr bind_address; -extern listen_rec *listeners; -extern int daemons_to_start; -extern int daemons_min_free; -extern int daemons_max_free; -extern int daemons_limit; -extern int suexec_enabled; - -extern char *pid_fname; -extern char *scoreboard_fname; -extern char *lock_fname; -extern char *server_argv0; - -/* Trying to allocate these in the config pool gets us into some *nasty* - * chicken-and-egg problems in http_main.c --- where do you stick them - * when pconf gets cleared? Better to just allocate a little space - * statically... - */ - -extern char server_root[MAX_STRING_LEN]; -extern char server_confname[MAX_STRING_LEN]; - diff --git a/usr.sbin/httpd/src/http_config.c b/usr.sbin/httpd/src/http_config.c deleted file mode 100644 index d39af86994c..00000000000 --- a/usr.sbin/httpd/src/http_config.c +++ /dev/null @@ -1,1213 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_config.c: once was auxillary functions for reading httpd's config - * file and converting filenames into a namespace - * - * Rob McCool - * - * Wall-to-wall rewrite for Apache... commands which are part of the - * server core can now be found next door in "http_core.c". Now contains - * general command loop, and functions which do bookkeeping for the new - * Apache config stuff (modules and configuration vectors). - * - * rst - * - */ - -#define CORE_PRIVATE - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" /* for errors in parse_htaccess */ -#include "http_request.h" /* for default_handler (see invoke_handler) */ -#include "http_conf_globals.h" /* Sigh... */ -#include "explain.h" - -DEF_Explain - -/**************************************************************** - * - * We begin with the functions which deal with the linked list - * of modules which control just about all of the server operation. - */ - -/* num_modules is the number of currently active modules. */ -static int num_modules = 0; -/* total_modules is the number of modules linked in. */ -static int total_modules = 0; -module *top_module = NULL; - -typedef int (*handler)(request_rec *); -typedef void *(*maker)(pool *); -typedef void *(*dir_maker)(pool *, char *); -typedef void *(*merger)(pool *, void *, void *); - -/* Dealing with config vectors. These are associated with per-directory, - * per-server, and per-request configuration, and have a void* pointer for - * each modules. The nature of the structure pointed to is private to the - * module in question... the core doesn't (and can't) know. However, there - * are defined interfaces which allow it to create instances of its private - * per-directory and per-server structures, and to merge the per-directory - * structures of a directory and its subdirectory (producing a new one in - * which the defaults applying to the base directory have been properly - * overridden). - */ - -void * -get_module_config (void *conf_vector, module *m) -{ - void **confv = (void**)conf_vector; - return confv[m->module_index]; -} - -void -set_module_config (void *conf_vector, module *m, void *val) -{ - void **confv = (void**)conf_vector; - confv[m->module_index] = val; -} - -void * -create_empty_config (pool *p) -{ - void **conf_vector = (void **)pcalloc(p, sizeof(void*) * total_modules); - return (void *)conf_vector; -} - -void * -create_default_per_dir_config (pool *p) -{ - void **conf_vector = (void **)pcalloc(p, sizeof(void*) * (total_modules+DYNAMIC_MODULE_LIMIT)); - module *modp; - - for (modp = top_module; modp; modp = modp->next) { - dir_maker df = modp->create_dir_config; - - if (df) conf_vector[modp->module_index] = (*df)(p, NULL); - } - - return (void*)conf_vector; -} - -void * -merge_per_dir_configs (pool *p, void *base, void *new) -{ - void **conf_vector = (void **)pcalloc(p, sizeof(void*) * total_modules); - void **base_vector = (void **) base; - void **new_vector = (void **) new; - module *modp; - - for (modp = top_module; modp; modp = modp->next) { - merger df = modp->merge_dir_config; - int i = modp->module_index; - - if (df && new_vector[i]) - conf_vector[i] = (*df)(p, base_vector[i], new_vector[i]); - else - conf_vector[i] = new_vector[i]? new_vector[i] : base_vector[i]; - } - - return (void*)conf_vector; -} - -void * -create_server_config (pool *p, server_rec *s) -{ - void **conf_vector = (void **)pcalloc(p, sizeof(void*) * (total_modules+DYNAMIC_MODULE_LIMIT)); - module *modp; - - for (modp = top_module; modp; modp = modp->next) { - if (modp->create_server_config) - conf_vector[modp->module_index]=(*modp->create_server_config)(p,s); - } - - return (void*)conf_vector; -} - -void merge_server_configs (pool *p, void *base, void *virt) -{ - /* Can reuse the 'virt' vector for the spine of it, since we don't - * have to deal with the moral equivalent of .htaccess files here... - */ - - void **base_vector = (void **)base; - void **virt_vector = (void **)virt; - module *modp; - - for (modp = top_module; modp; modp = modp->next) { - merger df = modp->merge_server_config; - int i = modp->module_index; - - if (!virt_vector[i]) - virt_vector[i] = base_vector[i]; - else if (df) - virt_vector[i] = (*df)(p, base_vector[i], virt_vector[i]); - } -} - -void *create_connection_config (pool *p) { - return create_empty_config (p); -} - -void *create_request_config (pool *p) { - return create_empty_config (p); -} - -void *create_per_dir_config (pool *p) { - return create_empty_config (p); -} - -#ifdef EXPLAIN - -struct - { - int offset; - char *method; - } aMethods[]= - { -#define m(meth) { XtOffsetOf(module,meth),#meth } - m(translate_handler), - m(check_user_id), - m(auth_checker), - m(type_checker), - m(fixer_upper), - m(logger), - { -1,"?" }, -#undef m - }; - -char *ShowMethod(module *modp,int offset) - { - int n; - static char buf[200]; - - for(n=0 ; aMethods[n].offset >= 0 ; ++n) - if(aMethods[n].offset == offset) - break; - ap_snprintf(buf, sizeof(buf), "%s:%s",modp->name,aMethods[n].method); - return buf; - } -#else -#define ShowMethod(modp,offset) -#endif - -/**************************************************************** - * - * Dispatch through the modules to find handlers for various phases - * of request handling. These are invoked by http_request.c to actually - * do the dirty work of slogging through the module structures. - */ - -int -run_method (request_rec *r, int offset, int run_all) -{ - module *modp; - for (modp = top_module; modp; modp = modp->next) { - handler mod_handler = *(handler *)(offset + (char *)(modp)); - - if (mod_handler) { - int result; - - Explain1("Run %s",ShowMethod(modp,offset)); - result = (*mod_handler)(r); - - Explain2("%s returned %d",ShowMethod(modp,offset),result); - if (result != DECLINED && (!run_all || result != OK)) - return result; - } - } - - return run_all ? OK : DECLINED; -} - -int translate_name(request_rec *r) { - return run_method (r, XtOffsetOf (module, translate_handler), 0); -} - -int check_access(request_rec *r) { - return run_method (r, XtOffsetOf (module, access_checker), 1); -} - -int find_types (request_rec *r) { - return run_method (r, XtOffsetOf (module, type_checker), 0); -} - -int run_fixups (request_rec *r) { - return run_method (r, XtOffsetOf (module, fixer_upper), 1); -} - -int log_transaction (request_rec *r) { - return run_method (r, XtOffsetOf (module, logger), 1); -} - -int header_parse (request_rec *r) { - return run_method (r, XtOffsetOf (module, header_parser), 1); -} - -/* Auth stuff --- anything that defines one of these will presumably - * want to define something for the other. Note that check_auth is - * separate from check_access to make catching some config errors easier. - */ - -int check_user_id (request_rec *r) { - return run_method (r, XtOffsetOf (module, check_user_id), 0); -} - -int check_auth (request_rec *r) { - return run_method (r, XtOffsetOf (module, auth_checker), 0); -} - -int invoke_handler (request_rec *r) -{ - module *modp; - handler_rec *handp; - char *content_type = r->content_type ? r->content_type : default_type (r); - char *handler, *p; - - if ((p = strchr(content_type, ';')) != NULL) { /* MIME type arguments */ - while (p > content_type && p[-1] == ' ') --p; /* strip trailing spaces */ - content_type = pstrndup(r->pool, content_type, p - content_type); - } - handler = r->handler ? r->handler : content_type; - - /* Pass one --- direct matches */ - - for (modp = top_module; modp; modp = modp->next) - { - if (!modp->handlers) continue; - - for (handp = modp->handlers; handp->content_type; ++handp) { - if (!strcasecmp (handler, handp->content_type)) { - int result = (*handp->handler)(r); - - if (result != DECLINED) return result; - } - } - } - - /* Pass two --- wildcard matches */ - - for (modp = top_module; modp; modp = modp->next) - { - if (!modp->handlers) continue; - - for (handp = modp->handlers; handp->content_type; ++handp) { - char *starp = strchr (handp->content_type, '*'); - int len; - - if (!starp) continue; - - len = starp - handp->content_type; - - if (!len || !strncasecmp (handler, handp->content_type, len)) - { - int result = (*handp->handler)(r); - - if (result != DECLINED) return result; - } - } - } - - return NOT_IMPLEMENTED; -} - -/* One-time setup for precompiled modules --- NOT to be done on restart */ - -void add_module (module *m) -{ - /* This could be called from an AddModule httpd.conf command, - * after the file has been linked and the module structure within it - * teased out... - */ - - /* At some point, we may want to offer back-compatibility for - * loading modules that are for older versions of Apache. For now, - * though, we don't. - */ - - if (m->version != MODULE_MAGIC_NUMBER) { - fprintf(stderr, "httpd: module \"%s\" is not compatible with this " - "version of Apache.\n", m->name); - fprintf(stderr, "Please contact the author for the correct version.\n"); - exit(1); - } - - if (m->next == NULL) { - m->next = top_module; - top_module = m; - } - if (m->module_index == -1) { - m->module_index = num_modules++; - } -} - -void setup_prelinked_modules () -{ - extern module *prelinked_modules[], *preloaded_modules[]; - module **m; - - /* First, set all module indices, and init total_modules. */ - total_modules = 0; - for (m = preloaded_modules; *m; ++m, ++total_modules) { - (*m)->module_index = total_modules; - } - - for (m = prelinked_modules; *m; ++m) { - add_module (*m); - } -} - -const char *find_module_name (module *m) -{ - return m->name; -} - -module *find_linked_module (const char *name) -{ - module *modp; - - for (modp = top_module; modp; modp = modp->next) { - if (strcmp(modp->name, name) == 0) - return modp; - } - return NULL; -} - -/* Add a named module. Returns 1 if module found, 0 otherwise. */ -int add_named_module (const char *name) -{ - extern module *preloaded_modules[]; - module *modp; - int i = 0; - - for (modp = preloaded_modules[i]; modp; modp = preloaded_modules[++i]) { - if (strcmp(modp->name, name) == 0) { - /* Only add modules that are not already enabled. */ - if (modp->next == NULL) { - add_module(modp); - } - return 1; - } - } - - return 0; -} - -/* Clear the internal list of modules, in preparation for starting over. */ -void clear_module_list () -{ - module **m = &top_module; - module **next_m; - - while (*m) { - next_m = &((*m)->next); - *m = NULL; - m = next_m; - } - - num_modules = 0; - - /* This is required; so we add it always. */ - add_named_module ("http_core.c"); -} - -/***************************************************************** - * - * Resource, access, and .htaccess config files now parsed by a common - * command loop. - * - * Let's begin with the basics; parsing the line and - * invoking the function... - */ - -const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms, void *mconfig, - const char *args) -{ - char *w, *w2, *w3; - const char *errmsg; - - if ((parms->override & cmd->req_override) == 0) - return pstrcat (parms->pool, cmd->name, " not allowed here", NULL); - - parms->info = cmd->cmd_data; - parms->cmd = cmd; - - switch (cmd->args_how) { - case RAW_ARGS: - return (*cmd->func) (parms, mconfig, args); - - case NO_ARGS: - if (*args != 0) - return pstrcat (parms->pool, cmd->name, " takes no arguments", - NULL); - - return (*cmd->func) (parms, mconfig); - - case TAKE1: - w = getword_conf (parms->pool, &args); - - if (*w == '\0' || *args != 0) - return pstrcat (parms->pool, cmd->name, " takes one argument", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return (*cmd->func) (parms, mconfig, w); - - case TAKE2: - - w = getword_conf (parms->pool, &args); - w2 = getword_conf (parms->pool, &args); - - if (*w == '\0' || *w2 == '\0' || *args != 0) - return pstrcat (parms->pool, cmd->name, " takes two arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return (*cmd->func) (parms, mconfig, w, w2); - - case TAKE12: - - w = getword_conf (parms->pool, &args); - w2 = getword_conf (parms->pool, &args); - - if (*w == '\0' || *args != 0) - return pstrcat (parms->pool, cmd->name, " takes 1-2 arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return (*cmd->func) (parms, mconfig, w, *w2 ? w2 : NULL); - - case TAKE3: - - w = getword_conf (parms->pool, &args); - w2 = getword_conf (parms->pool, &args); - w3 = getword_conf (parms->pool, &args); - - if (*w == '\0' || *w2 == '\0' || *w3 == '\0' || *args != 0) - return pstrcat (parms->pool, cmd->name, " takes three arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return (*cmd->func) (parms, mconfig, w, w2, w3); - - case TAKE23: - - w = getword_conf (parms->pool, &args); - w2 = getword_conf (parms->pool, &args); - w3 = *args ? getword_conf (parms->pool, &args) : NULL; - - if (*w == '\0' || *w2 == '\0' || *args != 0) - return pstrcat (parms->pool, cmd->name, " takes two or three arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return (*cmd->func) (parms, mconfig, w, w2, w3); - - case TAKE123: - - w = getword_conf (parms->pool, &args); - w2 = *args ? getword_conf (parms->pool, &args) : NULL; - w3 = *args ? getword_conf (parms->pool, &args) : NULL; - - if (*w == '\0' || *args != 0) - return pstrcat (parms->pool, cmd->name, " takes one, two or three arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return (*cmd->func) (parms, mconfig, w, w2, w3); - - case TAKE13: - - w = getword_conf (parms->pool, &args); - w2 = *args ? getword_conf (parms->pool, &args) : NULL; - w3 = *args ? getword_conf (parms->pool, &args) : NULL; - - if (*w == '\0' || (*w2 && !w3) || *args != 0) - return pstrcat (parms->pool, cmd->name, " takes one or three arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return (*cmd->func) (parms, mconfig, w, w2, w3); - - case ITERATE: - - while (*(w = getword_conf (parms->pool, &args)) != '\0') - if ((errmsg = (*cmd->func) (parms, mconfig, w))) - return errmsg; - - return NULL; - - case ITERATE2: - - w = getword_conf (parms->pool, &args); - - if (*w == '\0' || *args == 0) - return pstrcat(parms->pool, cmd->name, - " requires at least two arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - - while (*(w2 = getword_conf (parms->pool, &args)) != '\0') - if ((errmsg = (*cmd->func) (parms, mconfig, w, w2))) - return errmsg; - - return NULL; - - case FLAG: - - w = getword_conf (parms->pool, &args); - - if (*w == '\0' || (strcasecmp(w, "on") && strcasecmp (w, "off"))) - return pstrcat (parms->pool, cmd->name, " must be On or Off", - NULL); - - return (*cmd->func) (parms, mconfig, strcasecmp (w, "off") != 0); - - default: - - return pstrcat (parms->pool, cmd->name, - " is improperly configured internally (server bug)", - NULL); - } -} - -const command_rec *find_command (const char *name, const command_rec *cmds) -{ - while (cmds->name) - if (!strcasecmp (name, cmds->name)) - return cmds; - else - ++cmds; - - return NULL; -} - -const command_rec *find_command_in_modules (const char *cmd_name, module **mod) -{ - const command_rec *cmdp; - module *modp; - - for (modp = *mod; modp; modp = modp->next) - if (modp->cmds && (cmdp = find_command (cmd_name, modp->cmds))) { - *mod = modp; - return cmdp; - } - - return NULL; -} - -const char *handle_command (cmd_parms *parms, void *config, const char *l) -{ - const char *args, *cmd_name, *retval; - const command_rec *cmd; - module *mod = top_module; - - ++parms->config_line; - if((l[0] == '#') || (!l[0])) return NULL; - - args = l; - cmd_name = getword_conf (parms->temp_pool, &args); - if (*cmd_name == '\0') return NULL; - - do { - if (!(cmd = find_command_in_modules (cmd_name, &mod))) { - return pstrcat (parms->pool, "Invalid command ", cmd_name, NULL); - } - else { - void *mconfig = get_module_config (config, mod); - void *sconfig = - get_module_config (parms->server->module_config, mod); - - if (!mconfig && mod->create_dir_config) { - mconfig = (*mod->create_dir_config) (parms->pool, parms->path); - set_module_config (config, mod, mconfig); - } - - if (!sconfig && mod->create_server_config) { - sconfig = - (*mod->create_server_config)(parms->pool, parms->server); - set_module_config (parms->server->module_config, mod, sconfig); - } - - retval = invoke_cmd (cmd, parms, mconfig, args); - mod = mod->next; /* Next time around, skip this one */ - } - } while (retval && !strcmp(retval, DECLINE_CMD)); - - return retval; -} - -const char *srm_command_loop (cmd_parms *parms, void *config) -{ - char l[MAX_STRING_LEN]; - - while (!(cfg_getline (l, MAX_STRING_LEN, parms->infile))) { - const char *errmsg = handle_command (parms, config, l); - if (errmsg) return errmsg; - } - - return NULL; -} - -/* - * Generic command functions... - */ - -const char *set_string_slot (cmd_parms *cmd, char *struct_ptr, char *arg) -{ - /* This one's pretty generic... */ - - int offset = (int)cmd->info; - *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg); - return NULL; -} - -const char *set_flag_slot (cmd_parms *cmd, char *struct_ptr, int arg) -{ - /* This one's pretty generic too... */ - - int offset = (int)cmd->info; - *(int *)(struct_ptr + offset) = arg ? 1 : 0; - return NULL; -} - -/***************************************************************** - * - * Reading whole config files... - */ - -cmd_parms default_parms = { NULL, 0, -1, NULL, 0, NULL, NULL, NULL, NULL }; - -char *server_root_relative (pool *p, char *file) -{ -#ifdef __EMX__ - /* Add support for OS/2 drive names */ - if ((file[0] == '/') || (file[1] == ':')) return file; -#else - if (file[0] == '/') return file; -#endif - return make_full_path (p, server_root, file); -} - -void process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp) -{ - FILE *cfg; - const char *errmsg; - cmd_parms parms; - struct stat finfo; - - fname = server_root_relative (p, fname); - - if (!(strcmp(fname, server_root_relative(p, RESOURCE_CONFIG_FILE))) || - !(strcmp(fname, server_root_relative(p, ACCESS_CONFIG_FILE)))) { - if (stat(fname, &finfo) == -1) - return; - } - - /* GCC's initialization extensions are soooo nice here... */ - - parms = default_parms; - parms.config_file = fname; - parms.pool = p; - parms.temp_pool = ptemp; - parms.server = s; - parms.override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT); - - if(!(cfg = fopen(fname, "r"))) { - perror("fopen"); - fprintf(stderr,"httpd: could not open document config file %s\n", - fname); - exit(1); - } - - parms.infile = cfg; - - errmsg = srm_command_loop (&parms, s->lookup_defaults); - - if (errmsg) { - fprintf (stderr, "Syntax error on line %d of %s:\n", - parms.config_line, fname); - fprintf (stderr, "%s\n", errmsg); - exit(1); - } - - fclose(cfg); -} - - -int parse_htaccess(void **result, request_rec *r, int override, - char *d, char *filename) -{ - FILE *f; - cmd_parms parms; - const char *errmsg; - const struct htaccess_result *cache; - struct htaccess_result *new; - void *dc; - -/* firstly, search cache */ - for (cache=r->htaccess; cache != NULL; cache=cache->next) - if (cache->override == override && strcmp(cache->dir, d) == 0) - { - if (cache->htaccess != NULL) *result = cache->htaccess; - return OK; - } - - parms = default_parms; - parms.override = override; - parms.pool = r->pool; - parms.temp_pool = r->pool; - parms.server = r->server; - parms.path = d; - - if((f=pfopen(r->pool, filename, "r"))) { - dc = create_per_dir_config (r->pool); - - parms.infile = f; - parms.config_file = filename; - - errmsg = srm_command_loop (&parms, dc); - - pfclose(r->pool, f); - - if (errmsg) { - log_reason (errmsg, filename, r); - return SERVER_ERROR; - } - - *result = dc; - } else { - if (errno == ENOENT || errno == ENOTDIR) - dc = NULL; - else { - log_unixerr("pfopen", filename, - "unable to check htaccess file, ensure it is readable", - r->server); - return HTTP_FORBIDDEN; - } - } - -/* cache it */ - new = palloc(r->pool, sizeof(struct htaccess_result)); - new->dir = pstrdup(r->pool, d); - new->override = override; - new->htaccess = dc; -/* add to head of list */ - new->next = r->htaccess; - r->htaccess = new; - - return OK; -} - -/***************************************************************** - * - * Virtual host stuff; note that the commands that invoke this stuff - * are with the command table in http_core.c. - */ - -/* - * Parses a host of the form <address>[:port] - * paddr is used to create a list in the order of input - * **paddr is the ->next pointer of the last entry (or s->addrs) - * *paddr is the variable used to keep track of **paddr between calls - * port is the default port to assume - */ -static void get_addresses (pool *p, char *w, server_addr_rec ***paddr, unsigned port) -{ - struct hostent *hep; - unsigned long my_addr; - server_addr_rec *sar; - char *t; - int i, is_an_ip_addr; - - if( *w == 0 ) return; - - t = strchr(w, ':'); - if (t) { - if( strcmp(t+1,"*") == 0 ) { - port = 0; - } else if( (i = atoi(t+1)) ) { - port = i; - } else { - fprintf( stderr, "Port must be numeric\n" ); - } - *t = 0; - } - - is_an_ip_addr = 0; - if (strcmp(w, "*") == 0) { - my_addr = htonl(INADDR_ANY); - is_an_ip_addr = 1; - } else if( strcasecmp(w, "_default_") == 0 - || strcmp(w, "255.255.255.255") == 0 ) { - my_addr = DEFAULT_VHOST_ADDR; - is_an_ip_addr = 1; - } else if( -#ifdef DGUX - ( my_addr = inet_network(w) ) -#else - ( my_addr = inet_addr(w) ) -#endif - != INADDR_NONE ) { - is_an_ip_addr = 1; - } - if( is_an_ip_addr ) { - sar = pcalloc( p, sizeof( server_addr_rec ) ); - **paddr = sar; - *paddr = &sar->next; - sar->host_addr.s_addr = my_addr; - sar->host_port = port; - sar->virthost = pstrdup(p, w); - if (t != NULL) *t = ':'; - return; - } - - hep = gethostbyname(w); - - if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) { - fprintf (stderr, "Cannot resolve host name %s --- ignoring!\n", w); - if (t != NULL) *t = ':'; - return; - } - - for( i = 0; hep->h_addr_list[i]; ++i ) { - sar = pcalloc( p, sizeof( server_addr_rec ) ); - **paddr = sar; - *paddr = &sar->next; - sar->host_addr = *(struct in_addr *)hep->h_addr_list[i]; - sar->host_port = port; - sar->virthost = pstrdup(p, w); - } - - if (t != NULL) *t = ':'; -} - -server_rec *init_virtual_host (pool *p, const char *hostname, - server_rec *main_server) -{ - server_rec *s = (server_rec *)pcalloc (p, sizeof (server_rec)); - server_addr_rec **addrs; - -#ifdef RLIMIT_NOFILE - struct rlimit limits; - - getrlimit ( RLIMIT_NOFILE, &limits ); - if ( limits.rlim_cur < limits.rlim_max ) { - limits.rlim_cur += 2; - if ( setrlimit ( RLIMIT_NOFILE, &limits ) < 0 ) { - perror ("setrlimit(RLIMIT_NOFILE)"); - fprintf (stderr, "Cannot exceed hard limit for open files"); - } - } -#endif - - s->server_admin = NULL; - s->server_hostname = NULL; - s->error_fname = NULL; - s->srm_confname = NULL; - s->access_confname = NULL; - s->timeout = 0; - s->keep_alive_timeout = 0; - s->keep_alive = -1; - s->keep_alive_max = -1; - s->error_log = main_server->error_log; - /* start the list of addreses */ - addrs = &s->addrs; - while( hostname[0] ) { - get_addresses( p, getword_conf( p, &hostname ), &addrs, - main_server->port ); - } - /* terminate the list */ - *addrs = NULL; - if( s->addrs ) { - if (s->addrs->host_port) { - s->port = s->addrs->host_port; /* set them the same, by default */ - } else { - /* otherwise we get a port of 0 on redirects */ - s->port = main_server->port; - } - } - s->next = NULL; - - s->is_virtual = 1; - s->names = NULL; - - s->module_config = create_empty_config (p); - s->lookup_defaults = create_per_dir_config (p); - - s->server_uid = user_id; - s->server_gid = group_id; - - return s; -} - -int is_virtual_server (server_rec *s) -{ - return s->is_virtual; -} - -void fixup_virtual_hosts (pool *p, server_rec *main_server) -{ - server_rec *virt; - - for (virt = main_server->next; virt; virt = virt->next) { - merge_server_configs (p, main_server->module_config, - virt->module_config); - - virt->lookup_defaults = - merge_per_dir_configs (p, main_server->lookup_defaults, - virt->lookup_defaults); - - if (virt->server_admin == NULL) - virt->server_admin = main_server->server_admin; - - if (virt->srm_confname == NULL) - virt->srm_confname = main_server->srm_confname; - - if (virt->access_confname == NULL) - virt->access_confname = main_server->access_confname; - - if (virt->timeout == 0) - virt->timeout = main_server->timeout; - - if (virt->keep_alive_timeout == 0) - virt->keep_alive_timeout = main_server->keep_alive_timeout; - - if (virt->keep_alive == -1) - virt->keep_alive = main_server->keep_alive; - - if (virt->keep_alive_max == -1) - virt->keep_alive_max = main_server->keep_alive_max; - - if (virt->send_buffer_size == 0) - virt->send_buffer_size = main_server->send_buffer_size; - } -} - -/***************************************************************** - * - * Getting *everything* configured... - */ - -void init_config_globals (pool *p) -{ - /* ServerRoot, server_confname set in httpd.c */ - - standalone = 1; - user_name = DEFAULT_USER; - user_id = uname2id(DEFAULT_USER); - group_id = gname2id(DEFAULT_GROUP); - daemons_to_start = DEFAULT_START_DAEMON; - daemons_min_free = DEFAULT_MIN_FREE_DAEMON; - daemons_max_free = DEFAULT_MAX_FREE_DAEMON; - daemons_limit = HARD_SERVER_LIMIT; - pid_fname = DEFAULT_PIDLOG; - scoreboard_fname = DEFAULT_SCOREBOARD; - lock_fname = DEFAULT_LOCKFILE; - max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - bind_address.s_addr = htonl(INADDR_ANY); - listeners = NULL; -} - -server_rec *init_server_config(pool *p) -{ - server_rec *s = (server_rec *)pcalloc (p, sizeof (server_rec)); - - s->port = DEFAULT_PORT; - s->server_admin = DEFAULT_ADMIN; - s->server_hostname = NULL; - s->error_fname = DEFAULT_ERRORLOG; - s->error_log = stderr; - s->srm_confname = RESOURCE_CONFIG_FILE; - s->access_confname = ACCESS_CONFIG_FILE; - s->timeout = DEFAULT_TIMEOUT; - s->keep_alive_timeout = DEFAULT_KEEPALIVE_TIMEOUT; - s->keep_alive_max = DEFAULT_KEEPALIVE; - s->keep_alive = 1; - s->next = NULL; - s->addrs = pcalloc(p, sizeof (server_addr_rec)); - s->addrs->host_addr.s_addr = htonl (INADDR_ANY); /* NOT virtual host; - * don't match any real network - * interface. - */ - s->addrs->host_port = 0; /* matches any port */ - - s->module_config = create_server_config (p, s); - s->lookup_defaults = create_default_per_dir_config (p); - - return s; -} - -server_rec *read_config(pool *p, pool *ptemp, char *confname) -{ - server_rec *s = init_server_config(p); - - init_config_globals(p); - - /* All server-wide config files now have the SAME syntax... */ - - process_resource_config (s, confname, p, ptemp); - process_resource_config (s, s->srm_confname, p, ptemp); - process_resource_config (s, s->access_confname, p, ptemp); - - fixup_virtual_hosts (p, s); - - return s; -} - - -void init_modules(pool *p, server_rec *s) -{ - module *m; - - for (m = top_module; m; m = m->next) - if (m->init) - (*m->init) (s, p); -} - - -/******************************************************************** - * Configuration directives are restricted in terms of where they may - * appear in the main configuration files and/or .htaccess files according - * to the bitmask req_override in the command_rec structure. - * If any of the overrides set in req_override are also allowed in the - * context in which the command is read, then the command is allowed. - * The context is determined as follows: - * - * inside *.conf --> override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT); - * within <Directory> or <Location> --> override = OR_ALL|ACCESS_CONF; - * within .htaccess --> override = AllowOverride for current directory; - * - * the result is, well, a rather confusing set of possibilities for when - * a particular directive is allowed to be used. This procedure prints - * in English where the given (pc) directive can be used. - */ -void show_overrides(command_rec *pc, module *pm) -{ - int n = 0; - - printf("\tAllowed in *.conf "); - if ((pc->req_override & (OR_OPTIONS|OR_FILEINFO|OR_INDEXES)) || - ((pc->req_override & RSRC_CONF) && - ((pc->req_override & (ACCESS_CONF|OR_AUTHCFG|OR_LIMIT))))) - printf("anywhere"); - else if (pc->req_override & RSRC_CONF) - printf("only outside <Directory> or <Location>"); - else - printf("only inside <Directory> or <Location>"); - - /* Warn if the directive is allowed inside <Directory> or .htaccess - * but module doesn't support per-dir configuration */ - - if ((pc->req_override & (OR_ALL|ACCESS_CONF)) && !pm->create_dir_config) - printf(" [no per-dir config]"); - - if (pc->req_override & OR_ALL) { - printf(" and in .htaccess\n\twhen AllowOverride"); - - if ((pc->req_override & OR_ALL) == OR_ALL) - printf(" isn't None"); - else { - printf(" includes "); - - if (pc->req_override & OR_AUTHCFG) { - if (n++) printf(" or "); - printf("AuthConfig"); - } - if (pc->req_override & OR_LIMIT) { - if (n++) printf(" or "); - printf("Limit"); - } - if (pc->req_override & OR_OPTIONS) { - if (n++) printf(" or "); - printf("Options"); - } - if (pc->req_override & OR_FILEINFO) { - if (n++) printf(" or "); - printf("FileInfo"); - } - if (pc->req_override & OR_INDEXES) { - if (n++) printf(" or "); - printf("Indexes"); - } - } - } - printf("\n"); -} - -/* Show the preloaded configuration directives, the help string explaining - * the directive arguments, in what module they are handled, and in - * what parts of the configuration they are allowed. Used for httpd -h. - */ -void show_directives() -{ - extern module *preloaded_modules[]; - command_rec *pc; - int n; - - for (n = 0; preloaded_modules[n]; ++n) - for (pc = preloaded_modules[n]->cmds; pc && pc->name; ++pc) { - printf("%s\n", pc->name); - if (pc->errmsg) - printf("\t%s\n", pc->errmsg); - printf("\t%s\n", preloaded_modules[n]->name); - show_overrides(pc, preloaded_modules[n]); - } -} - -/* Show the preloaded module names. Used for httpd -l. */ -void show_modules() -{ - extern module *preloaded_modules[]; - int n; - - printf ("Compiled-in modules:\n"); - for (n = 0; preloaded_modules[n]; ++n) - printf (" %s\n", preloaded_modules[n]->name); -} - diff --git a/usr.sbin/httpd/src/http_config.h b/usr.sbin/httpd/src/http_config.h deleted file mode 100644 index 02d041854d3..00000000000 --- a/usr.sbin/httpd/src/http_config.h +++ /dev/null @@ -1,298 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * The central data structures around here... - */ - -/* Command dispatch structures... */ - -enum cmd_how { - RAW_ARGS, /* cmd_func parses command line itself */ - TAKE1, /* one argument only */ - TAKE2, /* two arguments only */ - ITERATE, /* one argument, occuring multiple times - * (e.g., IndexIgnore) - */ - ITERATE2, /* two arguments, 2nd occurs multiple times - * (e.g., AddIcon) - */ - FLAG, /* One of 'On' or 'Off' */ - NO_ARGS, /* No args at all, e.g. </Directory> */ - TAKE12, /* one or two arguments */ - TAKE3, /* three arguments only */ - TAKE23, /* two or three arguments */ - TAKE123, /* one, two or three arguments */ - TAKE13 /* one or three arguments */ -}; - -typedef struct command_struct { - char *name; /* Name of this command */ - const char *(*func)(); /* Function invoked */ - void *cmd_data; /* Extra data, for functions which - * implement multiple commands... - */ - int req_override; /* What overrides need to be allowed to - * enable this command. - */ - enum cmd_how args_how; /* What the command expects as arguments */ - - char *errmsg; /* 'usage' message, in case of syntax errors */ -} command_rec; - -/* The allowed locations for a configuration directive are the union of - * those indicated by each set bit in the req_override mask. - * - * (req_override & RSRC_CONF) => *.conf outside <Directory> or <Location> - * (req_override & ACCESS_CONF) => *.conf inside <Directory> or <Location> - * (req_override & OR_AUTHCFG) => *.conf inside <Directory> or <Location> - * and .htaccess when AllowOverride AuthConfig - * (req_override & OR_LIMIT) => *.conf inside <Directory> or <Location> - * and .htaccess when AllowOverride Limit - * (req_override & OR_OPTIONS) => *.conf anywhere - * and .htaccess when AllowOverride Options - * (req_override & OR_FILEINFO) => *.conf anywhere - * and .htaccess when AllowOverride FileInfo - * (req_override & OR_INDEXES) => *.conf anywhere - * and .htaccess when AllowOverride Indexes - */ -#define OR_NONE 0 -#define OR_LIMIT 1 -#define OR_OPTIONS 2 -#define OR_FILEINFO 4 -#define OR_AUTHCFG 8 -#define OR_INDEXES 16 -#define OR_UNSET 32 -#define ACCESS_CONF 64 -#define RSRC_CONF 128 -#define OR_ALL (OR_LIMIT|OR_OPTIONS|OR_FILEINFO|OR_AUTHCFG|OR_INDEXES) - -/* This can be returned by a function if they don't wish to handle - * a command. Make it something not likely someone will actually use - * as an error code. - */ - -#define DECLINE_CMD "\a\b" - -/* - * This structure is passed to a command which is being invoked, - * to carry a large variety of miscellaneous data which is all of - * use to *somebody*... - */ - -typedef struct { - void *info; /* Argument to command from cmd_table */ - int override; /* Which allow-override bits are set */ - int limited; /* Which methods are <Limit>ed */ - - char *config_file; /* Filename cmd read from */ - int config_line; /* Line cmd read from */ - FILE *infile; /* fd for more lines (not currently used) */ - - pool *pool; /* Pool to allocate new storage in */ - pool *temp_pool; /* Pool for scratch memory; persists during - * configuration, but wiped before the first - * request is served... - */ - server_rec *server; /* Server_rec being configured for */ - char *path; /* If configuring for a directory, - * pathname of that directory. - */ - const command_rec *cmd; /* configuration command */ -} cmd_parms; - -/* This structure records the existence of handlers in a module... */ - -typedef struct { - char *content_type; - int (*handler) (request_rec *); -} handler_rec; - -/* - * Module structures. Just about everything is dispatched through - * these, directly or indirectly (through the command and handler - * tables). - */ - -typedef struct module_struct { - int version; /* API version, *not* module version; - * check that module is compatible with this - * version of the server. - */ - int module_index; /* Index to this modules structures in - * config vectors. - */ - - const char *name; - - struct module_struct *next; - -#ifdef ULTRIX_BRAIN_DEATH - void (*init)(); - void *(*create_dir_config)(); - void *(*merge_dir_config)(); - void *(*create_server_config)(); - void *(*merge_server_config)(); -#else - void (*init)(server_rec *, pool *); - void *(*create_dir_config)(pool *p, char *dir); - void *(*merge_dir_config)(pool *p, void *base_conf, void *new_conf); - void *(*create_server_config)(pool *p, server_rec *s); - void *(*merge_server_config)(pool *p, void *base_conf, void *new_conf); -#endif - - command_rec *cmds; - handler_rec *handlers; - - /* Hooks for getting into the middle of server ops... - * - * translate_handler --- translate URI to filename - * access_checker --- check access by host address, etc. All of these - * run; if all decline, that's still OK. - * check_user_id --- get and validate user id from the HTTP request - * auth_checker --- see if the user (from check_user_id) is OK *here*. - * If all of *these* decline, the request is rejected - * (as a SERVER_ERROR, since the module which was - * supposed to handle this was configured wrong). - * type_checker --- Determine MIME type of the requested entity; - * sets content_type, _encoding and _language fields. - * logger --- log a transaction. Not supported yet out of sheer - * laziness on my part. - */ - - int (*translate_handler)(request_rec *); - int (*check_user_id)(request_rec *); - int (*auth_checker)(request_rec *); - int (*access_checker)(request_rec *); - int (*type_checker)(request_rec *); - int (*fixer_upper)(request_rec *); - int (*logger)(request_rec *); - int (*header_parser)(request_rec *); -} module; - -/* Initializer for the first few module slots, which are only - * really set up once we start running. Note that the first word - * is a version check; this should allow us to deal with changes to - * the API (the server can detect an old-format module, and either - * handle it back-compatibly, or at least signal an error). - */ - -#define MODULE_MAGIC_NUMBER 19970622 -#define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, -1, __FILE__, NULL - -/* Generic accessors for other modules to get at their own module-specific - * data - */ - -void *get_module_config (void *conf_vector, module *m); -void set_module_config (void *conf_vector, module *m, void *val); - -/* Generic command handling function... */ - -const char *set_string_slot (cmd_parms *, char *, char *); -const char *set_flag_slot (cmd_parms *, char *, int); - -/* For modules which need to read config files, open logs, etc. ... - * this returns the fname argument if it begins with '/'; otherwise - * it relativizes it wrt server_root. - */ - -char *server_root_relative (pool *p, char *fname); - -/* Finally, the hook for dynamically loading modules in... */ - -void add_module (module *m); -int add_named_module (const char *name); -void clear_module_list (); -const char *find_module_name (module *m); -module *find_linked_module (const char *name); - -#ifdef CORE_PRIVATE - -/* For http_main.c... */ - -server_rec *read_config (pool *conf_pool, pool *temp_pool, char *config_name); -void init_modules(pool *p, server_rec *s); -void setup_prelinked_modules(); -void show_directives(); -void show_modules(); - -/* For http_request.c... */ - -void *create_request_config (pool *p); -void *create_per_dir_config (pool *p); -void *merge_per_dir_configs (pool *p, void *base, void *new); - -/* For http_core.c... (<Directory> command and virtual hosts) */ - -int parse_htaccess(void **result, request_rec *r, int override, - char *path, char *file); -const char *srm_command_loop (cmd_parms *parms, void *config); - -server_rec *init_virtual_host (pool *p, const char *hostname, server_rec *main_server); -int is_virtual_server (server_rec *); -void process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp); - -/* Module-method dispatchers, also for http_request.c */ - -int translate_name (request_rec *); -int directory_walk (request_rec *); /* check symlinks, get per-dir config */ -int check_access (request_rec *); /* check access on non-auth basis */ -int check_user_id (request_rec *); /* obtain valid username from client auth */ -int check_auth (request_rec *); /* check (validated) user is authorized here */ -int find_types (request_rec *); /* identify MIME type */ -int run_fixups (request_rec *); /* poke around for other metainfo, etc.... */ -int invoke_handler (request_rec *); -int log_transaction (request_rec *r); -int header_parse (request_rec *); - -#endif diff --git a/usr.sbin/httpd/src/http_core.c b/usr.sbin/httpd/src/http_core.c deleted file mode 100644 index ce44d64eea2..00000000000 --- a/usr.sbin/httpd/src/http_core.c +++ /dev/null @@ -1,1413 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_protocol.h" /* For index_of_response(). Grump. */ -#include "http_conf_globals.h" - -#include "http_main.h" /* For the default_handler below... */ -#include "http_log.h" -#include "rfc1413.h" -#include "util_md5.h" -#include "scoreboard.h" - -/* Server core module... This module provides support for really basic - * server operations, including options and commands which control the - * operation of other modules. Consider this the bureaucracy module. - * - * The core module also defines handlers, etc., do handle just enough - * to allow a server with the core module ONLY to actually serve documents - * (though it slaps DefaultType on all of 'em); this was useful in testing, - * but may not be worth preserving. - * - * This file could almost be mod_core.c, except for the stuff which affects - * the http_conf_globals. - */ - -void *create_core_dir_config (pool *a, char *dir) -{ - core_dir_config *conf = - (core_dir_config *)pcalloc(a, sizeof(core_dir_config)); - - if (!dir || dir[strlen(dir) - 1] == '/') conf->d = dir; - else if (strncmp(dir,"proxy:",6)==0) conf->d = pstrdup (a, dir); - else conf->d = pstrcat (a, dir, "/", NULL); - conf->d_is_matchexp = conf->d ? is_matchexp( conf->d ) : 0; - - - conf->opts = dir ? OPT_UNSET : OPT_ALL; - conf->opts_add = conf->opts_remove = OPT_NONE; - conf->override = dir ? OR_UNSET : OR_ALL; - - conf->content_md5 = 2; - - conf->hostname_lookups = 2;/* binary, but will use 2 as an "unset = on" */ - conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */ - conf->satisfy = SATISFY_NOSPEC; - -#ifdef RLIMIT_CPU - conf->limit_cpu = NULL; -#endif -#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) - conf->limit_mem = NULL; -#endif -#ifdef RLIMIT_NPROC - conf->limit_nproc = NULL; -#endif - - conf->sec = make_array (a, 2, sizeof(void *)); - - return (void *)conf; -} - -void *merge_core_dir_configs (pool *a, void *basev, void *newv) -{ - core_dir_config *base = (core_dir_config *)basev; - core_dir_config *new = (core_dir_config *)newv; - core_dir_config *conf = - (core_dir_config *)pcalloc (a, sizeof(core_dir_config)); - int i; - - memcpy ((char *)conf, (const char *)base, sizeof(core_dir_config)); - if( base->response_code_strings ) { - conf->response_code_strings = palloc(a, - sizeof(*conf->response_code_strings) * RESPONSE_CODES ); - memcpy( conf->response_code_strings, base->response_code_strings, - sizeof(*conf->response_code_strings) * RESPONSE_CODES ); - } - - conf->d = new->d; - conf->d_is_matchexp = new->d_is_matchexp; - conf->r = new->r; - - if (new->opts != OPT_UNSET) conf->opts = new->opts; - if (new->opts_add) conf->opts |= new->opts_add; - if (new->opts_remove) conf->opts &= ~(new->opts_remove); - - if (new->override != OR_UNSET) conf->override = new->override; - if (new->default_type) conf->default_type = new->default_type; - - if (new->auth_type) conf->auth_type = new->auth_type; - if (new->auth_name) conf->auth_name = new->auth_name; - if (new->requires) conf->requires = new->requires; - - if( new->response_code_strings ) { - if( conf->response_code_strings == NULL ) { - conf->response_code_strings = palloc(a, - sizeof(*conf->response_code_strings) * RESPONSE_CODES ); - memcpy( conf->response_code_strings, new->response_code_strings, - sizeof(*conf->response_code_strings) * RESPONSE_CODES ); - } else { - for (i = 0; i < RESPONSE_CODES; ++i) - if (new->response_code_strings[i] != NULL) - conf->response_code_strings[i] = new->response_code_strings[i]; - } - } - if (new->hostname_lookups != 2) - conf->hostname_lookups = new->hostname_lookups; - if ((new->do_rfc1413 & 2) == 0) conf->do_rfc1413 = new->do_rfc1413; - if ((new->content_md5 & 2) == 0) conf->content_md5 = new->content_md5; - -#ifdef RLIMIT_CPU - if (new->limit_cpu) conf->limit_cpu = new->limit_cpu; -#endif -#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) - if (new->limit_mem) conf->limit_mem = new->limit_mem; -#endif -#ifdef RLIMIT_NPROC - if (new->limit_nproc) conf->limit_nproc = new->limit_nproc; -#endif - - conf->sec = append_arrays (a, base->sec, new->sec); - - if (new->satisfy != SATISFY_NOSPEC) conf->satisfy = new->satisfy; - return (void*)conf; -} - -void *create_core_server_config (pool *a, server_rec *s) -{ - core_server_config *conf = - (core_server_config *)pcalloc(a, sizeof(core_server_config)); - int is_virtual = s->is_virtual; - - conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME; - conf->document_root = is_virtual ? NULL : DOCUMENT_LOCATION; - conf->sec = make_array (a, 40, sizeof(void *)); - conf->sec_url = make_array (a, 40, sizeof(void *)); - - return (void *)conf; -} - -void *merge_core_server_configs (pool *p, void *basev, void *virtv) -{ - core_server_config *base = (core_server_config *)basev; - core_server_config *virt = (core_server_config *)virtv; - core_server_config *conf = - (core_server_config *)pcalloc(p, sizeof(core_server_config)); - - *conf = *virt; - if (!conf->access_name) conf->access_name = base->access_name; - if (!conf->document_root) conf->document_root = base->document_root; - conf->sec = append_arrays (p, base->sec, virt->sec); - conf->sec_url = append_arrays (p, base->sec_url, virt->sec_url); - - return conf; -} - -/* Add per-directory configuration entry (for <directory> section); - * these are part of the core server config. - */ - -void add_per_dir_conf (server_rec *s, void *dir_config) -{ - core_server_config *sconf = get_module_config (s->module_config, - &core_module); - void **new_space = (void **) push_array (sconf->sec); - - *new_space = dir_config; -} - -void add_per_url_conf (server_rec *s, void *url_config) -{ - core_server_config *sconf = get_module_config (s->module_config, - &core_module); - void **new_space = (void **) push_array (sconf->sec_url); - - *new_space = url_config; -} - -void add_file_conf (core_dir_config *conf, void *url_config) -{ - void **new_space = (void **) push_array (conf->sec); - - *new_space = url_config; -} - -/***************************************************************** - * - * There are some elements of the core config structures in which - * other modules have a legitimate interest (this is ugly, but necessary - * to preserve NCSA back-compatibility). So, we have a bunch of accessors - * here... - */ - -int allow_options (request_rec *r) -{ - core_dir_config *conf = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - - return conf->opts; -} - -int allow_overrides (request_rec *r) -{ - core_dir_config *conf = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - - return conf->override; -} - -char *auth_type (request_rec *r) -{ - core_dir_config *conf = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - - return conf->auth_type; -} - -char *auth_name (request_rec *r) -{ - core_dir_config *conf = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - - return conf->auth_name; -} - -char *default_type (request_rec *r) -{ - core_dir_config *conf = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - - return conf->default_type ? conf->default_type : DEFAULT_TYPE; -} - -char *document_root (request_rec *r) /* Don't use this!!! */ -{ - core_server_config *conf = - (core_server_config *)get_module_config(r->server->module_config, - &core_module); - - return conf->document_root; -} - -array_header *requires (request_rec *r) -{ - core_dir_config *conf = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - - return conf->requires; -} - -int satisfies (request_rec *r) -{ - core_dir_config *conf = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - - return conf->satisfy; -} - -/* Should probably just get rid of this... the only code that cares is - * part of the core anyway (and in fact, it isn't publicised to other - * modules). - */ - -char *response_code_string (request_rec *r, int error_index) -{ - core_dir_config *conf = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - - if( conf->response_code_strings == NULL ) { - return NULL; - } - return conf->response_code_strings[error_index]; -} - -const char * -get_remote_host(conn_rec *conn, void *dir_config, int type) -{ - struct in_addr *iaddr; - struct hostent *hptr; -#ifdef MAXIMUM_DNS - char **haddr; -#endif - core_dir_config *dir_conf = NULL; - -/* If we haven't checked the host name, and we want to */ - if (dir_config) - dir_conf = (core_dir_config *)get_module_config(dir_config, &core_module); - - if ((!dir_conf) || (type != REMOTE_NOLOOKUP && conn->remote_host == NULL && dir_conf->hostname_lookups)) - { -#ifdef STATUS - int old_stat = update_child_status(conn->child_num, - SERVER_BUSY_DNS, - (request_rec*)NULL); -#endif /* STATUS */ - iaddr = &(conn->remote_addr.sin_addr); - hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET); - if (hptr != NULL) - { - conn->remote_host = pstrdup(conn->pool, (void *)hptr->h_name); - str_tolower (conn->remote_host); - -#ifdef MAXIMUM_DNS - /* Grrr. Check THAT name to make sure it's really the name of the addr. */ - /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */ - - hptr = gethostbyname(conn->remote_host); - if (hptr) - { - for(haddr=hptr->h_addr_list; *haddr; haddr++) - if(((struct in_addr *)(*haddr))->s_addr == iaddr->s_addr) - break; - } - if((!hptr) || (!(*haddr))) - conn->remote_host = NULL; -#endif - } -/* if failed, set it to the NULL string to indicate error */ - if (conn->remote_host == NULL) conn->remote_host = ""; -#ifdef STATUS - (void)update_child_status(conn->child_num,old_stat,(request_rec*)NULL); -#endif /* STATUS */ - } - -/* - * Return the desired information; either the remote DNS name, if found, - * or either NULL (if the hostname was requested) or the IP address - * (if any identifier was requested). - */ - if (conn->remote_host != NULL && conn->remote_host[0] != '\0') - return conn->remote_host; - else - { - if (type == REMOTE_HOST) return NULL; - else return conn->remote_ip; - } -} - -const char * -get_remote_logname(request_rec *r) -{ - core_dir_config *dir_conf; - - if (r->connection->remote_logname != NULL) - return r->connection->remote_logname; - -/* If we haven't checked the identity, and we want to */ - dir_conf = (core_dir_config *) - get_module_config(r->per_dir_config, &core_module); - - if (dir_conf->do_rfc1413 & 1) - return rfc1413(r->connection, r->server); - else - return NULL; -} - -/***************************************************************** - * - * Commands... this module handles almost all of the NCSA httpd.conf - * commands, but most of the old srm.conf is in the the modules. - */ - -const char *set_access_name (cmd_parms *cmd, void *dummy, char *arg) -{ - void *sconf = cmd->server->module_config; - core_server_config *conf = get_module_config (sconf, &core_module); - - conf->access_name = arg; - return NULL; -} - -const char *set_document_root (cmd_parms *cmd, void *dummy, char *arg) -{ - void *sconf = cmd->server->module_config; - core_server_config *conf = get_module_config (sconf, &core_module); - - if (!is_directory (arg)) - if (cmd->server->is_virtual) - fprintf (stderr, "Warning: DocumentRoot [%s] does not exist\n", arg); - else - return "DocumentRoot must be a directory"; - - conf->document_root = arg; - return NULL; -} - -const char *set_error_document (cmd_parms *cmd, core_dir_config *conf, - char *line) -{ - int error_number, index_number, idx500; - char *w; - - /* 1st parameter should be a 3 digit number, which we recognize; - * convert it into an array index - */ - - w = getword_conf_nc (cmd->pool, &line); - error_number = atoi(w); - - idx500 = index_of_response(HTTP_INTERNAL_SERVER_ERROR); - - if (error_number == HTTP_INTERNAL_SERVER_ERROR) - index_number = idx500; - else if ((index_number = index_of_response(error_number)) == idx500) - return pstrcat(cmd->pool, "Unsupported HTTP response code ", w, NULL); - - /* Store it... */ - - if( conf->response_code_strings == NULL ) { - conf->response_code_strings = pcalloc(cmd->pool, - sizeof(*conf->response_code_strings) * RESPONSE_CODES ); - } - conf->response_code_strings[index_number] = pstrdup (cmd->pool, line); - - return NULL; -} - -/* access.conf commands... - * - * The *only* thing that can appear in access.conf at top level is a - * <Directory> section. NB we need to have a way to cut the srm_command_loop - * invoked by dirsection (i.e., <Directory>) short when </Directory> is seen. - * We do that by returning an error, which dirsection itself recognizes and - * discards as harmless. Cheesy, but it works. - */ - -const char *set_override (cmd_parms *cmd, core_dir_config *d, const char *l) -{ - char *w; - - d->override = OR_NONE; - while(l[0]) { - w = getword_conf (cmd->pool, &l); - if(!strcasecmp(w,"Limit")) - d->override |= OR_LIMIT; - else if(!strcasecmp(w,"Options")) - d->override |= OR_OPTIONS; - else if(!strcasecmp(w,"FileInfo")) - d->override |= OR_FILEINFO; - else if(!strcasecmp(w,"AuthConfig")) - d->override |= OR_AUTHCFG; - else if(!strcasecmp(w,"Indexes")) - d->override |= OR_INDEXES; - else if(!strcasecmp(w,"None")) - d->override = OR_NONE; - else if(!strcasecmp(w,"All")) - d->override = OR_ALL; - else - return pstrcat (cmd->pool, "Illegal override option ", w, NULL); - } - - return NULL; -} - -const char *set_options (cmd_parms *cmd, core_dir_config *d, const char *l) -{ - char opt; - int first = 1; - char action; - - while(l[0]) { - char *w = getword_conf(cmd->pool, &l); - action = '\0'; - - if (*w == '+' || *w == '-') - action = *(w++); - else if (first) { - d->opts = OPT_NONE; - first = 0; - } - - if(!strcasecmp(w,"Indexes")) - opt = OPT_INDEXES; - else if(!strcasecmp(w,"Includes")) - opt = OPT_INCLUDES; - else if(!strcasecmp(w,"IncludesNOEXEC")) - opt = (OPT_INCLUDES | OPT_INCNOEXEC); - else if(!strcasecmp(w,"FollowSymLinks")) - opt = OPT_SYM_LINKS; - else if(!strcasecmp(w,"SymLinksIfOwnerMatch")) - opt = OPT_SYM_OWNER; - else if(!strcasecmp(w,"execCGI")) - opt = OPT_EXECCGI; - else if (!strcasecmp(w,"MultiViews")) - opt = OPT_MULTI; - else if (!strcasecmp(w,"RunScripts")) /* AI backcompat. Yuck */ - opt = OPT_MULTI|OPT_EXECCGI; - else if(!strcasecmp(w,"None")) - opt = OPT_NONE; - else if(!strcasecmp(w,"All")) - opt = OPT_ALL; - else - return pstrcat (cmd->pool, "Illegal option ", w, NULL); - - if (action == '-') - d->opts_remove |= opt; - else if (action == '+') - d->opts_add |= opt; - else - d->opts |= opt; - } - - return NULL; -} - -const char *satisfy (cmd_parms *cmd, core_dir_config *c, char *arg) -{ - if(!strcasecmp(arg,"all")) - c->satisfy = SATISFY_ALL; - else if(!strcasecmp(arg,"any")) - c->satisfy = SATISFY_ANY; - else - return "Satisfy either 'any' or 'all'."; - return NULL; -} - -const char *require (cmd_parms *cmd, core_dir_config *c, char *arg) -{ - require_line *r; - - if (!c->requires) - c->requires = make_array (cmd->pool, 2, sizeof(require_line)); - - r = (require_line *)push_array (c->requires); - r->requirement = pstrdup (cmd->pool, arg); - r->method_mask = cmd->limited; - return NULL; -} - -const char *limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *limited_methods = getword(cmd->pool,&arg,'>'); - int limited = 0; - - if (cmd->limited > 0) return "Can't nest <Limit> sections"; - - while(limited_methods[0]) { - char *method = getword_conf (cmd->pool, &limited_methods); - if(!strcasecmp(method,"GET")) limited |= (1 << M_GET); - else if(!strcasecmp(method,"PUT")) limited |= (1 << M_PUT); - else if(!strcasecmp(method,"POST")) limited |= (1 << M_POST); - else if(!strcasecmp(method,"DELETE")) limited |= (1 << M_DELETE); - else if(!strcasecmp(method,"CONNECT")) limited |= (1 << M_CONNECT); - else if(!strcasecmp(method,"OPTIONS")) limited |= (1 << M_OPTIONS); - else return "unknown method in <Limit>"; - } - - cmd->limited = limited; - return NULL; -} - -const char *endlimit (cmd_parms *cmd, void *dummy, void *dummy2) -{ - if (cmd->limited == -1) return "</Limit> unexpected"; - - cmd->limited = -1; - return NULL; -} - -static const char end_dir_magic[] = "</Directory> outside of any <Directory> section"; - -const char *end_dirsection (cmd_parms *cmd, void *dummy) { - return end_dir_magic; -} - -const char *dirsection (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *errmsg; - char *endp = strrchr (arg, '>'); - int old_overrides = cmd->override; - char *old_path = cmd->path; - core_dir_config *conf; - void *new_dir_conf = create_per_dir_config (cmd->pool); - regex_t *r = NULL; - - if (endp) *endp = '\0'; - - if (cmd->path) return "<Directory> sections don't nest"; - if (cmd->limited != -1) return "Can't have <Directory> within <Limit>"; - - cmd->path = getword_conf (cmd->pool, &arg); -#ifdef __EMX__ - /* Fix OS/2 HPFS filename case problem. */ - cmd->path = strlwr(cmd->path); -#endif - cmd->override = OR_ALL|ACCESS_CONF; - - if (!strcmp(cmd->path, "~")) { - cmd->path = getword_conf (cmd->pool, &arg); - r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED); - } - - errmsg = srm_command_loop (cmd, new_dir_conf); - if (errmsg != end_dir_magic) return errmsg; - - conf = (core_dir_config *)get_module_config(new_dir_conf, &core_module); - conf->r = r; - - add_per_dir_conf (cmd->server, new_dir_conf); - - cmd->path = old_path; - cmd->override = old_overrides; - - return NULL; -} - -static const char end_url_magic[] = "</Location> outside of any <Location> section"; - -const char *end_urlsection (cmd_parms *cmd, void *dummy) { - return end_url_magic; -} - -const char *urlsection (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *errmsg; - char *endp = strrchr (arg, '>'); - int old_overrides = cmd->override; - char *old_path = cmd->path; - core_dir_config *conf; - regex_t *r = NULL; - - void *new_url_conf = create_per_dir_config (cmd->pool); - - if (endp) *endp = '\0'; - - if (cmd->path) return "<Location> sections don't nest"; - if (cmd->limited != -1) return "Can't have <Location> within <Limit>"; - - cmd->path = getword_conf (cmd->pool, &arg); - cmd->override = OR_ALL|ACCESS_CONF; - - if (!strcmp(cmd->path, "~")) { - cmd->path = getword_conf (cmd->pool, &arg); - r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED); - } - - errmsg = srm_command_loop (cmd, new_url_conf); - if (errmsg != end_url_magic) return errmsg; - - conf = (core_dir_config *)get_module_config(new_url_conf, &core_module); - conf->d = pstrdup(cmd->pool, cmd->path); /* No mangling, please */ - conf->d_is_matchexp = is_matchexp( conf->d ); - conf->r = r; - - add_per_url_conf (cmd->server, new_url_conf); - - cmd->path = old_path; - cmd->override = old_overrides; - - return NULL; -} - -static char *end_file_magic = "</Files> outside of any <Files> section"; - -const char *end_filesection (cmd_parms *cmd, void *dummy) { - return end_file_magic; -} - -const char *filesection (cmd_parms *cmd, core_dir_config *c, const char *arg) -{ - const char *errmsg; - char *endp = strrchr (arg, '>'); - int old_overrides = cmd->override; - char *old_path = cmd->path; - core_dir_config *conf; - regex_t *r = NULL; - - void *new_file_conf = create_per_dir_config (cmd->pool); - - if (endp) *endp = '\0'; - - if (cmd->limited != -1) return "Can't have <Files> within <Limit>"; - - cmd->path = getword_conf (cmd->pool, &arg); - /* Only if not an .htaccess file */ - if (cmd->path) - cmd->override = OR_ALL|ACCESS_CONF; - - if (!strcmp(cmd->path, "~")) { - cmd->path = getword_conf (cmd->pool, &arg); - if (old_path && cmd->path[0] != '/' && cmd->path[0] != '^') - cmd->path = pstrcat(cmd->pool, "^", old_path, cmd->path, NULL); - r = pregcomp(cmd->pool, cmd->path, REG_EXTENDED); - } - else if (old_path && cmd->path[0] != '/') - cmd->path = pstrcat(cmd->pool, old_path, cmd->path, NULL); - - errmsg = srm_command_loop (cmd, new_file_conf); - if (errmsg != end_file_magic) return errmsg; - - conf = (core_dir_config *)get_module_config(new_file_conf, &core_module); - conf->d = pstrdup(cmd->pool, cmd->path); - conf->d_is_matchexp = is_matchexp( conf->d ); - conf->r = r; - - add_file_conf (c, new_file_conf); - - cmd->path = old_path; - cmd->override = old_overrides; - - return NULL; -} - -const char *end_ifmod (cmd_parms *cmd, void *dummy) { - return NULL; -} - -const char *start_ifmod (cmd_parms *cmd, void *dummy, char *arg) -{ - char *endp = strrchr (arg, '>'); - char l[MAX_STRING_LEN]; - int not = (arg[0] == '!'); - module *found; - int nest = 1; - - if (endp) *endp = '\0'; - if (not) arg++; - - found = find_linked_module(arg); - - if ((!not && found) || (not && !found)) - return NULL; - - while (nest && !(cfg_getline (l, MAX_STRING_LEN, cmd->infile))) { - if (!strncasecmp(l, "<IfModule", 9)) - nest++; - if (!strcasecmp(l, "</IfModule>")) - nest--; - } - - return NULL; -} - -/* httpd.conf commands... beginning with the <VirtualHost> business */ - -const char end_virthost_magic[] = "</Virtualhost> out of place"; - -const char *end_virtualhost_section (cmd_parms *cmd, void *dummy) -{ - return end_virthost_magic; -} - -const char *virtualhost_section (cmd_parms *cmd, void *dummy, char *arg) -{ - server_rec *main_server = cmd->server, *s; - const char *errmsg; - char *endp = strrchr (arg, '>'); - pool *p = cmd->pool, *ptemp = cmd->temp_pool; - - if (endp) *endp = '\0'; - - /* FIXME: There's another feature waiting to happen here -- since you - can now put multiple addresses/names on a single <VirtualHost> - you might want to use it to group common definitions and then - define other "subhosts" with their individual differences. But - personally I'd rather just do it with a macro preprocessor. -djg */ - if (main_server->is_virtual) - return "<VirtualHost> doesn't nest!"; - - s = init_virtual_host (p, arg, main_server); - s->next = main_server->next; - main_server->next = s; - - cmd->server = s; - errmsg = srm_command_loop (cmd, s->lookup_defaults); - cmd->server = main_server; - - if (s->srm_confname) - process_resource_config (s, s->srm_confname, p, ptemp); - - if (s->access_confname) - process_resource_config (s, s->access_confname, p, ptemp); - - if (errmsg == end_virthost_magic) return NULL; - return errmsg; -} - -const char *add_module_command (cmd_parms *cmd, void *dummy, char *arg) -{ - if (add_named_module (arg)) - return NULL; - return "required module not found"; -} - -const char *clear_module_list_command (cmd_parms *cmd, void *dummy) -{ - clear_module_list (); - return NULL; -} - -const char *set_server_string_slot (cmd_parms *cmd, void *dummy, char *arg) -{ - /* This one's pretty generic... */ - - int offset = (int)cmd->info; - char *struct_ptr = (char *)cmd->server; - - *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg); - return NULL; -} - -const char *server_type (cmd_parms *cmd, void *dummy, char *arg) -{ - if (!strcasecmp (arg, "inetd")) standalone = 0; - else if (!strcasecmp (arg, "standalone")) standalone = 1; - else return "ServerType must be either 'inetd' or 'standalone'"; - - return NULL; -} - -const char *server_port (cmd_parms *cmd, void *dummy, char *arg) { - cmd->server->port = atoi (arg); - return NULL; -} - -const char *set_send_buffer_size (cmd_parms *cmd, void *dummy, char *arg) { - int s = atoi (arg); - if (s < 512 && s != 0) { - return "SendBufferSize must be >= 512 bytes, or 0 for system default."; - } - cmd->server->send_buffer_size = s; - return NULL; -} - -const char *set_user (cmd_parms *cmd, void *dummy, char *arg) -{ - if (!cmd->server->is_virtual) { - user_name = pstrdup (cmd->pool, arg); - cmd->server->server_uid = user_id = uname2id(arg); - } - else { - if (suexec_enabled) - cmd->server->server_uid = uname2id(arg); - else { - cmd->server->server_uid = user_id; - fprintf(stderr, - "Warning: User directive in <VirtualHost> " - "requires SUEXEC wrapper.\n"); - } - } -#if !defined (BIG_SECURITY_HOLE) - if (cmd->server->server_uid == 0) { - fprintf (stderr, -"Error:\tApache has not been designed to serve pages while running\n" -"\tas root. There are known race conditions that will allow any\n" -"\tlocal user to read any file on the system. Should you still\n" -"\tdesire to serve pages as root then add -DBIG_SECURITY_HOLE to\n" -"\tthe EXTRA_CFLAGS line in your src/Configuration file and rebuild\n" -"\tthe server. It is strongly suggested that you instead modify the\n" -"\tUser directive in your httpd.conf file to list a non-root user.\n"); - exit (1); - } -#endif - - return NULL; -} - -const char *set_group (cmd_parms *cmd, void *dummy, char *arg) -{ - if (!cmd->server->is_virtual) - cmd->server->server_gid = group_id = gname2id(arg); - else { - if (suexec_enabled) - cmd->server->server_gid = gname2id(arg); - else { - cmd->server->server_gid = group_id; - fprintf(stderr, - "Warning: Group directive in <VirtualHost> requires SUEXEC wrapper.\n"); - } - } - - return NULL; -} - -const char *set_server_root (cmd_parms *cmd, void *dummy, char *arg) { - if (!is_directory (arg)) return "ServerRoot must be a valid directory"; - strncpy (server_root, arg, sizeof(server_root)-1); - server_root[sizeof(server_root)-1] = '\0'; - return NULL; -} - -const char *set_timeout (cmd_parms *cmd, void *dummy, char *arg) { - cmd->server->timeout = atoi (arg); - return NULL; -} - -const char *set_keep_alive_timeout (cmd_parms *cmd, void *dummy, char *arg) { - cmd->server->keep_alive_timeout = atoi (arg); - return NULL; -} - -const char *set_keep_alive (cmd_parms *cmd, void *dummy, char *arg) { - /* We've changed it to On/Off, but used to use numbers - * so we accept anything but "Off" or "0" as "On" - */ - if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) - cmd->server->keep_alive = 0; - else - cmd->server->keep_alive = 1; - return NULL; -} - -const char *set_keep_alive_max (cmd_parms *cmd, void *dummy, char *arg) { - cmd->server->keep_alive_max = atoi (arg); - return NULL; -} - -const char *set_pidfile (cmd_parms *cmd, void *dummy, char *arg) { - pid_fname = pstrdup (cmd->pool, arg); - return NULL; -} - -const char *set_scoreboard (cmd_parms *cmd, void *dummy, char *arg) { - scoreboard_fname = pstrdup (cmd->pool, arg); - return NULL; -} - -const char *set_lockfile (cmd_parms *cmd, void *dummy, char *arg) { - lock_fname = pstrdup (cmd->pool, arg); - return NULL; -} - -const char *set_idcheck (cmd_parms *cmd, core_dir_config *d, int arg) { - d->do_rfc1413 = arg; - return NULL; -} - -const char *set_hostname_lookups (cmd_parms *cmd, core_dir_config *d, int arg) -{ - d->hostname_lookups = arg; - return NULL; -} - -const char *set_serverpath (cmd_parms *cmd, void *dummy, char *arg) { - cmd->server->path = pstrdup (cmd->pool, arg); - cmd->server->pathlen = strlen (arg); - return NULL; -} - -const char *set_content_md5 (cmd_parms *cmd, core_dir_config *d, int arg) { - d->content_md5 = arg; - return NULL; -} - -const char *set_daemons_to_start (cmd_parms *cmd, void *dummy, char *arg) { - daemons_to_start = atoi (arg); - return NULL; -} - -const char *set_min_free_servers (cmd_parms *cmd, void *dummy, char *arg) { - daemons_min_free = atoi (arg); - if (daemons_min_free <= 0) { - fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n"); - fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n"); - fprintf(stderr, "Please read the documentation.\n"); - daemons_min_free = 1; - } - - return NULL; -} - -const char *set_max_free_servers (cmd_parms *cmd, void *dummy, char *arg) { - daemons_max_free = atoi (arg); - return NULL; -} - -const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) { - daemons_limit = atoi (arg); - if (daemons_limit > HARD_SERVER_LIMIT) { - fprintf(stderr, "WARNING: MaxClients of %d exceeds compile time limit " - "of %d servers,\n", daemons_limit, HARD_SERVER_LIMIT); - fprintf(stderr, " lowering MaxClients to %d. To increase, please " - "see the\n", HARD_SERVER_LIMIT); - fprintf(stderr, " HARD_SERVER_LIMIT define in src/httpd.h.\n"); - daemons_limit = HARD_SERVER_LIMIT; - } else if (daemons_limit < 1) { - fprintf (stderr, "WARNING: Require MaxClients > 0, setting to 1\n"); - daemons_limit = 1; - } - return NULL; -} - -const char *set_max_requests (cmd_parms *cmd, void *dummy, char *arg) { - max_requests_per_child = atoi (arg); - return NULL; -} - -#if defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) -static void set_rlimit(cmd_parms *cmd, struct rlimit **plimit, const char *arg, - const char * arg2, int type) -{ - char *str; - struct rlimit *limit; - /* If your platform doesn't define rlim_t then typedef it in conf.h */ - rlim_t cur = 0; - rlim_t max = 0; - - *plimit=(struct rlimit *)pcalloc(cmd->pool,sizeof **plimit); - limit=*plimit; - if ((getrlimit(type, limit)) != 0) - { - *plimit = NULL; - log_unixerr("getrlimit",cmd->cmd->name,"failed",cmd->server); - return; - } - - if ((str = getword_conf(cmd->pool, &arg))) - if (!strcasecmp(str, "max")) - cur = limit->rlim_max; - else - cur = atol(str); - else { - log_printf(cmd->server, "Invalid parameters for %s", cmd->cmd->name); - return; - } - - if (arg2 && (str = getword_conf(cmd->pool, &arg2))) - max = atol(str); - - /* if we aren't running as root, cannot increase max */ - if (geteuid()) { - limit->rlim_cur = cur; - if (max) - log_printf(cmd->server, "Must be uid 0 to raise maximum %s", - cmd->cmd->name); - } - else { - if (cur) - limit->rlim_cur = cur; - if (max) - limit->rlim_max = max; - } -} -#endif - -#if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM)) || !defined (RLIMIT_NPROC) -static const char *no_set_limit (cmd_parms *cmd, core_dir_config *conf, - char *arg, char *arg2) -{ - log_printf(cmd->server, "%s not supported on this platform", - cmd->cmd->name); - return NULL; -} -#endif - -#ifdef RLIMIT_CPU -const char *set_limit_cpu (cmd_parms *cmd, core_dir_config *conf, char *arg, char *arg2) -{ - set_rlimit(cmd,&conf->limit_cpu,arg,arg2,RLIMIT_CPU); - return NULL; -} -#endif - -#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) -const char *set_limit_mem (cmd_parms *cmd, core_dir_config *conf, char *arg, char * arg2) -{ -#ifdef RLIMIT_DATA - set_rlimit(cmd,&conf->limit_mem,arg,arg2,RLIMIT_DATA); -#else - set_rlimit(cmd,&conf->limit_mem,arg,arg2,RLIMIT_VMEM); -#endif - return NULL; -} -#endif - -#ifdef RLIMIT_NPROC -const char *set_limit_nproc (cmd_parms *cmd, core_dir_config *conf, char *arg, char * arg2) -{ - set_rlimit(cmd,&conf->limit_nproc,arg,arg2,RLIMIT_NPROC); - return NULL; -} -#endif - -const char *set_bind_address (cmd_parms *cmd, void *dummy, char *arg) { - bind_address.s_addr = get_virthost_addr (arg, NULL); - return NULL; -} - -const char *set_listener(cmd_parms *cmd, void *dummy, char *ips) -{ - listen_rec *new; - char *ports; - unsigned port; - - if (cmd->server->is_virtual) return "Listen not allowed in <VirtualHost>"; - ports=strchr(ips, ':'); - if (ports != NULL) - { - if (ports == ips) return "Missing IP address"; - else if (ports[0] == '\0') - return "Address must end in :<port-number>"; - *(ports++) = '\0'; - } else - ports = ips; - - new=pcalloc(cmd->pool, sizeof(listen_rec)); - new->local_addr.sin_family = AF_INET; - if (ports == ips) /* no address */ - new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - else - new->local_addr.sin_addr.s_addr = get_virthost_addr(ips, NULL); - port=atoi(ports); - if(!port) - return "Port must be numeric"; - new->local_addr.sin_port = htons(port); - new->fd = -1; - new->used = 0; - new->next = listeners; - listeners = new; - return NULL; -} - -/* Note --- ErrorDocument will now work from .htaccess files. - * The AllowOverride of Fileinfo allows webmasters to turn it off - */ - -command_rec core_cmds[] = { - -/* Old access config file commands */ - -{ "<Directory", dirsection, NULL, RSRC_CONF, RAW_ARGS, "Container for directives affecting resources located in the specified directories" }, -{ "</Directory>", end_dirsection, NULL, ACCESS_CONF, NO_ARGS, NULL }, -{ "<Location", urlsection, NULL, RSRC_CONF, RAW_ARGS, "Container for directives affecting resources accessed through the specified URL paths" }, -{ "</Location>", end_urlsection, NULL, ACCESS_CONF, NO_ARGS, NULL }, -{ "<VirtualHost", virtualhost_section, NULL, RSRC_CONF, RAW_ARGS, "Container to map directives to a particular virtual host" }, -{ "</VirtualHost>", end_virtualhost_section, NULL, RSRC_CONF, NO_ARGS, NULL }, -{ "<Files", filesection, NULL, OR_ALL, RAW_ARGS, "Container for directives affecting files matching specified patterns" }, -{ "</Files>", end_filesection, NULL, OR_ALL, NO_ARGS, NULL }, -{ "<Limit", limit, NULL, OR_ALL, RAW_ARGS, "Container for authentication directives when accessed using specified HTTP methods" }, -{ "</Limit>", endlimit, NULL, OR_ALL, RAW_ARGS, NULL }, -{ "<IfModule", start_ifmod, NULL, OR_ALL, RAW_ARGS, "Container for directives based on existance of specified modules" }, -{ "</IfModule>", end_ifmod, NULL, OR_ALL, NO_ARGS, NULL }, -{ "AuthType", set_string_slot, (void*)XtOffsetOf(core_dir_config, auth_type), - OR_AUTHCFG, TAKE1, "An HTTP authorization type (e.g., \"Basic\")" }, -{ "AuthName", set_string_slot, (void*)XtOffsetOf(core_dir_config, auth_name), - OR_AUTHCFG, RAW_ARGS, "The authentication realm (e.g. \"Members Only\")" }, -{ "Require", require, NULL, OR_AUTHCFG, RAW_ARGS, "Selects which authenticated users or groups may access a protected space" }, -{ "Satisfy", satisfy, NULL, OR_AUTHCFG, TAKE1, - "access policy if both allow and require used ('all' or 'any')" }, - -/* Old resource config file commands */ - -{ "AccessFileName", set_access_name, NULL, RSRC_CONF, TAKE1, "Name of per-directory config files (default: .htaccess)" }, -{ "DocumentRoot", set_document_root, NULL, RSRC_CONF, TAKE1, "Root directory of the document tree" }, -{ "ErrorDocument", set_error_document, NULL, OR_FILEINFO, RAW_ARGS, "Change responses for HTTP errors" }, -{ "AllowOverride", set_override, NULL, ACCESS_CONF, RAW_ARGS, "Controls what groups of directives can be configured by per-directory config files" }, -{ "Options", set_options, NULL, OR_OPTIONS, RAW_ARGS, "Set a number of attributes for a given directory" }, -{ "DefaultType", set_string_slot, - (void*)XtOffsetOf (core_dir_config, default_type), - OR_FILEINFO, TAKE1, "the default MIME type for untypable files" }, - -/* Old server config file commands */ - -{ "ServerType", server_type, NULL, RSRC_CONF, TAKE1,"'inetd' or 'standalone'"}, -{ "Port", server_port, NULL, RSRC_CONF, TAKE1, "A TCP port number"}, -{ "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, FLAG, "\"on\" to enable or \"off\" to disable reverse DNS lookups" }, -{ "User", set_user, NULL, RSRC_CONF, TAKE1, "Effective user id for this server"}, -{ "Group", set_group, NULL, RSRC_CONF, TAKE1, "Effective group id for this server"}, -{ "ServerAdmin", set_server_string_slot, - (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1, - "The email address of the server administrator" }, -{ "ServerName", set_server_string_slot, - (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF, TAKE1, - "The hostname of the server" }, -{ "ServerRoot", set_server_root, NULL, RSRC_CONF, TAKE1, "Common directory of server-related files (logs, confs, etc)" }, -{ "ErrorLog", set_server_string_slot, - (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1, - "The filename of the error log" }, -{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1, - "A file for logging the server process ID"}, -{ "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1, - "A file for Apache to maintain runtime process management information"}, -{ "LockFile", set_lockfile, NULL, RSRC_CONF, TAKE1, - "The lockfile used when Apache needs to lock the accept() call"}, -{ "AccessConfig", set_server_string_slot, - (void *)XtOffsetOf (server_rec, access_confname), RSRC_CONF, TAKE1, - "The filename of the access config file" }, -{ "ResourceConfig", set_server_string_slot, - (void *)XtOffsetOf (server_rec, srm_confname), RSRC_CONF, TAKE1, - "The filename of the resource config file" }, -{ "ServerAlias", set_server_string_slot, - (void *)XtOffsetOf (server_rec, names), RSRC_CONF, RAW_ARGS, - "A name or names alternately used to access the server" }, -{ "ServerPath", set_serverpath, NULL, RSRC_CONF, TAKE1, - "The pathname the server can be reached at" }, -{ "Timeout", set_timeout, NULL, RSRC_CONF, TAKE1, "Timeout duration (sec)"}, -{ "KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF, TAKE1, "Keep-Alive timeout duration (sec)"}, -{ "MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF, TAKE1, "Maximum number of Keep-Alive requests per connection, or 0 for infinite" }, -{ "KeepAlive", set_keep_alive, NULL, RSRC_CONF, TAKE1, "Whether persistent connections should be On or Off" }, -{ "IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF, FLAG, "Enable identd (RFC 1413) user lookups - SLOW" }, -{ "ContentDigest", set_content_md5, NULL, RSRC_CONF|ACCESS_CONF|OR_AUTHCFG, FLAG, "whether or not to send a Content-MD5 header with each request" }, -{ "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1, "Number of child processes launched at server startup" }, -{ "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1, "Minimum number of idle children, to handle request spikes" }, -{ "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, "Maximum number of idle children" }, -{ "MaxServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, "Deprecated equivalent to MaxSpareServers" }, -{ "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1, "Deprecated equivalent to MaxClients" }, -{ "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1, "Maximum number of children alive at the same time" }, -{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1, "Maximum number of requests a particular child serves before dying." }, -{ "RLimitCPU", -#ifdef RLIMIT_CPU - set_limit_cpu, (void*)XtOffsetOf(core_dir_config, limit_cpu), -#else - no_set_limit, NULL, -#endif - OR_ALL, TAKE12, "soft/hard limits for max CPU usage in seconds" }, -{ "RLimitMEM", -#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) - set_limit_mem, (void*)XtOffsetOf(core_dir_config, limit_mem), -#else - no_set_limit, NULL, -#endif - OR_ALL, TAKE12, "soft/hard limits for max memory usage per process" }, -{ "RLimitNPROC", -#ifdef RLIMIT_NPROC - set_limit_nproc, (void*)XtOffsetOf(core_dir_config, limit_nproc), -#else - no_set_limit, NULL, -#endif - OR_ALL, TAKE12, "soft/hard limits for max number of processes per uid" }, -{ "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1, - "'*', a numeric IP address, or the name of a host with a unique IP address"}, -{ "Listen", set_listener, NULL, RSRC_CONF, TAKE1, - "a port number or a numeric IP address and a port number"}, -{ "SendBufferSize", set_send_buffer_size, NULL, RSRC_CONF, TAKE1, "send buffer size in bytes"}, -{ "AddModule", add_module_command, NULL, RSRC_CONF, ITERATE, - "the name of a module" }, -{ "ClearModuleList", clear_module_list_command, NULL, RSRC_CONF, NO_ARGS, NULL }, -{ NULL }, -}; - -/***************************************************************** - * - * Core handlers for various phases of server operation... - */ - -int core_translate (request_rec *r) -{ - void *sconf = r->server->module_config; - core_server_config *conf = get_module_config (sconf, &core_module); - - if (r->proxyreq) return HTTP_FORBIDDEN; - if ((r->uri[0] != '/') && strcmp(r->uri, "*")) { - log_printf(r->server, "Invalid URI in request %s", r->the_request); - return BAD_REQUEST; - } - - if (r->server->path && - !strncmp(r->uri, r->server->path, r->server->pathlen) && - (r->server->path[r->server->pathlen - 1] == '/' || - r->uri[r->server->pathlen] == '/' || - r->uri[r->server->pathlen] == '\0')) - r->filename = pstrcat (r->pool, conf->document_root, - (r->uri + r->server->pathlen), NULL); - else - r->filename = pstrcat (r->pool, conf->document_root, r->uri, NULL); - - return OK; -} - -int do_nothing (request_rec *r) { return OK; } - -/* - * Default handler for MIME types without other handlers. Only GET - * and OPTIONS at this point... anyone who wants to write a generic - * handler for PUT or POST is free to do so, but it seems unwise to provide - * any defaults yet... So, for now, we assume that this will always be - * the last handler called and return 405 or 501. - */ - -int default_handler (request_rec *r) -{ - core_dir_config *d = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - int rangestatus, errstatus; - FILE *f; - - /* This handler has no use for a request body (yet), but we still - * need to read and discard it if the client sent one. - */ - if ((errstatus = discard_request_body(r)) != OK) - return errstatus; - - r->allowed |= (1 << M_GET) | (1 << M_OPTIONS); - - if (r->method_number == M_INVALID) { - log_printf(r->server, "Invalid method in request %s", r->the_request); - return NOT_IMPLEMENTED; - } - if (r->method_number == M_OPTIONS) return send_http_options(r); - if (r->method_number == M_PUT) return METHOD_NOT_ALLOWED; - - if (r->finfo.st_mode == 0 || (r->path_info && *r->path_info)) { - log_reason("File does not exist", - r->path_info ? pstrcat(r->pool, r->filename, r->path_info, NULL) - : r->filename, r); - return NOT_FOUND; - } - if (r->method_number != M_GET) return METHOD_NOT_ALLOWED; - -#ifdef __EMX__ - /* Need binary mode for OS/2 */ - f = pfopen (r->pool, r->filename, "rb"); -#else - f = pfopen (r->pool, r->filename, "r"); -#endif - - if (f == NULL) { - log_reason("file permissions deny server access", r->filename, r); - return FORBIDDEN; - } - - if ((errstatus = set_last_modified (r, r->finfo.st_mtime)) - || (errstatus = set_content_length (r, r->finfo.st_size))) - return errstatus; - - if (d->content_md5 & 1) { - table_set (r->headers_out, "Content-MD5", md5digest(r->pool, f)); - } - - rangestatus = set_byterange(r); - send_http_header (r); - - if (!r->header_only) { - if (!rangestatus) - send_fd (f, r); - else { - long offset, length; - while (each_byterange(r, &offset, &length)) { - fseek(f, offset, SEEK_SET); - send_fd_length(f, r, length); - } - } - } - - pfclose(r->pool, f); - return OK; -} - -handler_rec core_handlers[] = { -{ "*/*", default_handler }, -{ NULL } -}; - -module core_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_core_dir_config, /* create per-directory config structure */ - merge_core_dir_configs, /* merge per-directory config structures */ - create_core_server_config, /* create per-server config structure */ - merge_core_server_configs, /* merge per-server config structures */ - core_cmds, /* command table */ - core_handlers, /* handlers */ - core_translate, /* translate_handler */ - NULL, /* check_user_id */ - NULL, /* check auth */ - do_nothing, /* check access */ - do_nothing, /* type_checker */ - NULL, /* pre-run fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/http_core.h b/usr.sbin/httpd/src/http_core.h deleted file mode 100644 index 8454b81ad11..00000000000 --- a/usr.sbin/httpd/src/http_core.h +++ /dev/null @@ -1,205 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/***************************************************************** - * - * The most basic server code is encapsulated in a single module - * known as the core, which is just *barely* functional enough to - * serve documents, though not terribly well. - * - * Largely for NCSA back-compatibility reasons, the core needs to - * make pieces of its config structures available to other modules. - * The accessors are declared here, along with the interpretation - * of one of them (allow_options). - */ - -#define OPT_NONE 0 -#define OPT_INDEXES 1 -#define OPT_INCLUDES 2 -#define OPT_SYM_LINKS 4 -#define OPT_EXECCGI 8 -#define OPT_UNSET 16 -#define OPT_INCNOEXEC 32 -#define OPT_SYM_OWNER 64 -#define OPT_MULTI 128 -#define OPT_ALL (OPT_INDEXES|OPT_INCLUDES|OPT_SYM_LINKS|OPT_EXECCGI) - -/* options for get_remote_host() */ -#define REMOTE_HOST (0) -#define REMOTE_NAME (1) -#define REMOTE_NOLOOKUP (2) - -#define SATISFY_ALL 0 -#define SATISFY_ANY 1 -#define SATISFY_NOSPEC 2 - -int allow_options (request_rec *); -int allow_overrides (request_rec *); -char *default_type (request_rec *); -char *document_root (request_rec *); /* Don't use this! If your request went - * through a Userdir, or something like - * that, it'll screw you. But it's - * back-compatible... - */ -extern const char *get_remote_host(conn_rec *conn, void *dir_config, int type); -extern const char *get_remote_logname(request_rec *r); - -/* Authentication stuff. This is one of the places where compatibility - * with the old config files *really* hurts; they don't discriminate at - * all between different authentication schemes, meaning that we need - * to maintain common state for all of them in the core, and make it - * available to the other modules through interfaces. - */ - -typedef struct { - int method_mask; - char *requirement; -} require_line; - -char *auth_type (request_rec *); -char *auth_name (request_rec *); -int satisfies (request_rec *r); -array_header *requires (request_rec *); - -#ifdef CORE_PRIVATE - -/* - * Core is also unlike other modules in being implemented in more than - * one file... so, data structures are declared here, even though most of - * the code that cares really is in http_core.c. Also, anothre accessor. - */ - -char *response_code_string (request_rec *r, int error_index); - -extern module core_module; - -/* Per-directory configuration */ - -typedef char allow_options_t; -typedef char overrides_t; - -typedef struct { - char *d; - /* since is_matchexp(conf->d) was being called so frequently in - * directory_walk() and its relatives, this field was created and - * is set to the result of that call. - */ - int d_is_matchexp; - - allow_options_t opts; - allow_options_t opts_add; - allow_options_t opts_remove; - overrides_t override; - - /* MIME typing --- the core doesn't do anything at all with this, - * but it does know what to slap on a request for a document which - * goes untyped by other mechanisms before it slips out the door... - */ - - char *default_type; - - /* Authentication stuff. Groan... */ - - int satisfy; - char *auth_type; - char *auth_name; - array_header *requires; - - int content_md5; - - /* Custom response config. These can contain text or a URL to redirect to. - * if response_code_strings is NULL then there are none in the config, - * if it's not null then it's allocated to sizeof(char*)*RESPONSE_CODES. - * This lets us do quick merges in merge_core_dir_configs(). - */ - - char **response_code_strings; - - /* Hostname resolution etc */ - int hostname_lookups; - int do_rfc1413; /* See if client is advertising a username? */ - - /* System Resource Control */ -#ifdef RLIMIT_CPU - struct rlimit *limit_cpu; -#endif -#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) - struct rlimit *limit_mem; -#endif -#ifdef RLIMIT_NPROC - struct rlimit *limit_nproc; -#endif - - /* Access control */ - array_header *sec; - regex_t *r; - -} core_dir_config; - -/* Per-server core configuration */ - -typedef struct { - - /* Name translations --- we want the core to be able to do *something* - * so it's at least a minimally functional web server on its own (and - * can be tested that way). But let's keep it to the bare minimum: - */ - char *document_root; - - /* Access control */ - - char *access_name; - array_header *sec; - array_header *sec_url; -} core_server_config; - -#endif diff --git a/usr.sbin/httpd/src/http_log.c b/usr.sbin/httpd/src/http_log.c deleted file mode 100644 index 896c0a8dc59..00000000000 --- a/usr.sbin/httpd/src/http_log.c +++ /dev/null @@ -1,197 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_log.c: Dealing with the logs and errors - * - * Rob McCool - * - */ - - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" - -#include <stdarg.h> - -void error_log_child (void *cmd) -{ - /* Child process code for 'ErrorLog "|..."'; - * may want a common framework for this, since I expect it will - * be common for other foo-loggers to want this sort of thing... - */ - - cleanup_for_exec(); - signal (SIGHUP, SIG_IGN); -#ifdef __EMX__ - /* For OS/2 we need to use a '/' */ - execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); -#else - execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); -#endif - exit (1); -} - -void open_error_log(server_rec *s, pool *p) -{ - char *fname; - - fname = server_root_relative (p, s->error_fname); - - if (*s->error_fname == '|') { - FILE *dummy; - - if (!spawn_child (p, error_log_child, (void *)(s->error_fname+1), - kill_after_timeout, &dummy, NULL)) { - perror ("spawn_child"); - fprintf (stderr, "Couldn't fork child for ErrorLog process\n"); - exit (1); - } - - s->error_log = dummy; - } else { - if(!(s->error_log = pfopen(p, fname, "a"))) { - perror("fopen"); - fprintf(stderr,"httpd: could not open error log file %s.\n", fname); - exit(1); - } - } -} - -void open_logs (server_rec *s_main, pool *p) -{ - server_rec *virt, *q; - - open_error_log (s_main, p); - - for (virt = s_main->next; virt; virt = virt->next) { - if (virt->error_fname) - { - for (q=s_main; q != virt; q = q->next) - if (q->error_fname != NULL && - strcmp(q->error_fname, virt->error_fname) == 0) - break; - if (q == virt) open_error_log (virt, p); - else virt->error_log = q->error_log; - } - else - virt->error_log = s_main->error_log; - } -} - -void error_log2stderr(server_rec *s) { - if(fileno(s->error_log) != STDERR_FILENO) - dup2(fileno(s->error_log),STDERR_FILENO); -} - -void log_pid(pool *p, char *pid_fname) { - FILE *pid_file; - - if (!pid_fname) return; - pid_fname = server_root_relative (p, pid_fname); - if(!(pid_file = fopen(pid_fname,"w"))) { - perror("fopen"); - fprintf(stderr,"httpd: could not log pid to file %s\n", pid_fname); - exit(1); - } - fprintf(pid_file,"%ld\n",(long)getpid()); - fclose(pid_file); -} - -void log_error(char *err, server_rec *s) { - fprintf(s->error_log, "[%s] %s\n",get_time(),err); - fflush(s->error_log); -} - -void -log_unixerr(const char *routine, const char *file, const char *msg, - server_rec *s) -{ - const char *p, *q; - - p = strerror(errno); - q = get_time(); - - if (file != NULL) - fprintf(s->error_log, "[%s] %s: %s: %s\n", q, routine, file, p); - else - fprintf(s->error_log, "[%s] %s: %s\n", q, routine, p); - if (msg != NULL) fprintf(s->error_log, "[%s] - %s\n", q, msg); - - fflush(s->error_log); -} - -void -log_printf(const server_rec *s, const char *fmt, ...) -{ - va_list args; - - fprintf(s->error_log, "[%s] ", get_time()); - va_start (args, fmt); - vfprintf (s->error_log, fmt, args); - va_end (args); - - fputc('\n', s->error_log); - fflush(s->error_log); -} - -void log_reason(const char *reason, const char *file, request_rec *r) { - fprintf (r->server->error_log, - "[%s] access to %s failed for %s, reason: %s\n", - get_time(), file, - get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME), - reason); - fflush (r->server->error_log); -} - diff --git a/usr.sbin/httpd/src/http_log.h b/usr.sbin/httpd/src/http_log.h deleted file mode 100644 index e30324db61d..00000000000 --- a/usr.sbin/httpd/src/http_log.h +++ /dev/null @@ -1,62 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -void open_logs (server_rec *, pool *p); -void error_log2stderr (server_rec *); - -void log_pid (pool *p, char *pid_fname); -void log_error(char *err, server_rec *s); -extern void log_unixerr(const char *routine, const char *file, - const char *msg, server_rec *s); -void log_printf(const server_rec *s, const char *fmt, ...); -void log_reason(const char *reason, const char *fname, request_rec *r); - diff --git a/usr.sbin/httpd/src/http_main.c b/usr.sbin/httpd/src/http_main.c deleted file mode 100644 index e553a2d3636..00000000000 --- a/usr.sbin/httpd/src/http_main.c +++ /dev/null @@ -1,2620 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * httpd.c: simple http daemon for answering WWW file requests - * - * - * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3) - * - * 03-06-95 blong - * changed server number for child-alone processes to 0 and changed name - * of processes - * - * 03-10-95 blong - * Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu) - * including set group before fork, and call gettime before to fork - * to set up libraries. - * - * 04-14-95 rst / rh - * Brandon's code snarfed from NCSA 1.4, but tinkered to work with the - * Apache server, and also to have child processes do accept() directly. - * - * April-July '95 rst - * Extensive rework for Apache. - */ - -#define CORE_PRIVATE - -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" /* for read_config */ -#include "http_protocol.h" /* for read_request */ -#include "http_request.h" /* for process_request */ -#include "http_conf_globals.h" -#include "http_core.h" /* for get_remote_host */ -#include "scoreboard.h" -#include <assert.h> -#include <sys/stat.h> -#ifdef HAVE_SHMGET -#include <sys/types.h> -#include <sys/ipc.h> -#include <sys/shm.h> -#endif -#ifdef SecureWare -#include <sys/security.h> -#include <sys/audit.h> -#include <prot.h> -#endif -#include <netinet/tcp.h> - -#ifdef HAVE_BSTRING_H -#include <bstring.h> /* for IRIX, FD_SET calls bzero() */ -#endif - -#include "explain.h" - -#if !defined(max) -#define max(a,b) (a > b ? a : b) -#endif - -#ifdef __EMX__ - /* Add MMAP style functionality to OS/2 */ - #ifdef HAVE_MMAP - #define INCL_DOSMEMMGR - #include <os2.h> - #include <umalloc.h> - #include <stdio.h> - caddr_t create_shared_heap (const char *, size_t); - caddr_t get_shared_heap (const char *); - #endif -#endif - - -DEF_Explain - -/* - * Actual definitions of config globals... here because this is - * for the most part the only code that acts on 'em. (Hmmm... mod_main.c?) - */ - -int standalone; -uid_t user_id; -char *user_name; -gid_t group_id; -#ifdef MULTIPLE_GROUPS -gid_t group_id_list[NGROUPS_MAX]; -#endif -int max_requests_per_child; -char *pid_fname; -char *scoreboard_fname; -char *lock_fname; -char *server_argv0; -struct in_addr bind_address; -listen_rec *listeners; -int daemons_to_start; -int daemons_min_free; -int daemons_max_free; -int daemons_limit; -time_t restart_time; -int suexec_enabled = 0; - -char server_root[MAX_STRING_LEN]; -char server_confname[MAX_STRING_LEN]; - -/* *Non*-shared http_main globals... */ - -server_rec *server_conf; -JMP_BUF jmpbuffer; -int sd; -static fd_set listenfds; -static int listenmaxfd; -pid_t pgrp; - -/* one_process --- debugging mode variable; can be set from the command line - * with the -X flag. If set, this gets you the child_main loop running - * in the process which originally started up (no detach, no make_child), - * which is a pretty nice debugging environment. (You'll get a SIGHUP - * early in standalone_main; just continue through. This is the server - * trying to kill off any child processes which it might have lying - * around --- Apache doesn't keep track of their pids, it just sends - * SIGHUP to the process group, ignoring it in the root process. - * Continue through and you'll be fine.). - */ - -int one_process = 0; - -/* small utility macros to make things easier to read */ - -#ifdef NO_KILLPG -#define ap_killpg(x, y) (kill (-(x), (y))) -#else -#define ap_killpg(x, y) (killpg ((x), (y))) -#endif - -#if defined(USE_FCNTL_SERIALIZED_ACCEPT) || defined(USE_FLOCK_SERIALIZED_ACCEPT) -static void expand_lock_fname(pool *p) -{ - char buf[20]; - - ap_snprintf( buf, sizeof(buf), ".%u", getpid() ); - lock_fname = pstrcat (p, server_root_relative (p, lock_fname), buf, NULL); -} -#endif - -#if defined(USE_FCNTL_SERIALIZED_ACCEPT) -static struct flock lock_it; -static struct flock unlock_it; - -static int lock_fd=-1; - -/* - * Initialize mutex lock. - * Must be safe to call this on a restart. - */ -void -accept_mutex_init(pool *p) -{ - - lock_it.l_whence = SEEK_SET; /* from current point */ - lock_it.l_start = 0; /* -"- */ - lock_it.l_len = 0; /* until end of file */ - lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ - lock_it.l_pid = 0; /* pid not actually interesting */ - unlock_it.l_whence = SEEK_SET; /* from current point */ - unlock_it.l_start = 0; /* -"- */ - unlock_it.l_len = 0; /* until end of file */ - unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */ - unlock_it.l_pid = 0; /* pid not actually interesting */ - - expand_lock_fname (p); - lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY | O_EXCL, 0644); - if (lock_fd == -1) - { - perror ("open"); - fprintf (stderr, "Cannot open lock file: %s\n", lock_fname); - exit (1); - } - unlink(lock_fname); -} - -void accept_mutex_on() -{ - int ret; - - while ((ret = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR) - continue; - - if (ret < 0) { - log_unixerr("fcntl", "F_SETLKW", "Error getting accept lock. Exiting!" - "Perhaps you need to use the LockFile directive to place " - "your lock file on a local disk!", server_conf); - exit(1); - } -} - -void accept_mutex_off() -{ - if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0) - { - log_unixerr("fcntl", "F_SETLKW", "Error freeing accept lock. Exiting!" - "Perhaps you need to use the LockFile directive to place " - "your lock file on a local disk!", server_conf); - exit(1); - } -} -#elif defined(USE_FLOCK_SERIALIZED_ACCEPT) - -static int lock_fd=-1; - -/* - * Initialize mutex lock. - * Must be safe to call this on a restart. - */ -void -accept_mutex_init(pool *p) -{ - - expand_lock_fname (p); - lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY | O_EXCL, 0644); - if (lock_fd == -1) - { - perror ("open"); - fprintf (stderr, "Cannot open lock file: %s\n", lock_fname); - exit (1); - } - unlink(lock_fname); -} - -void accept_mutex_on() -{ - int ret; - - while ((ret = flock(lock_fd, LOCK_EX)) < 0 && errno == EINTR) - continue; - - if (ret < 0) { - log_unixerr("flock", "LOCK_EX", "Error getting accept lock. Exiting!", - server_conf); - exit(1); - } -} - -void accept_mutex_off() -{ - if (flock (lock_fd, LOCK_UN) < 0) - { - log_unixerr("flock", "LOCK_UN", "Error freeing accept lock. Exiting!", - server_conf); - exit(1); - } -} -#else -/* Default --- no serialization. Other methods *could* go here, - * as #elifs... - */ -#define accept_mutex_init(x) -#define accept_mutex_on() -#define accept_mutex_off() -#endif - -void usage(char *bin) -{ - fprintf(stderr,"Usage: %s [-d directory] [-f file] [-v] [-h] [-l]\n",bin); - fprintf(stderr,"-d directory : specify an alternate initial ServerRoot\n"); - fprintf(stderr,"-f file : specify an alternate ServerConfigFile\n"); - fprintf(stderr,"-v : show version number\n"); - fprintf(stderr,"-h : list directives\n"); - fprintf(stderr,"-l : list modules\n"); - exit(1); -} - -/***************************************************************** - * - * Timeout handling. DISTINCTLY not thread-safe, but all this stuff - * has to change for threads anyway. Note that this code allows only - * one timeout in progress at a time... - */ - -static conn_rec *current_conn; -static request_rec *timeout_req; -static char *timeout_name = NULL; -static int alarms_blocked = 0; -static int alarm_pending = 0; - -#ifndef NO_USE_SIGACTION -/* - * Replace standard signal() with the more reliable sigaction equivalent - * from W. Richard Stevens' "Advanced Programming in the UNIX Environment" - * (the version that does not automatically restart system calls). - */ -Sigfunc *signal(int signo, Sigfunc *func) -{ - struct sigaction act, oact; - - act.sa_handler = func; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; -#ifdef SA_INTERRUPT /* SunOS */ - act.sa_flags |= SA_INTERRUPT; -#endif - if (sigaction(signo, &act, &oact) < 0) - return SIG_ERR; - return oact.sa_handler; -} -#endif - -void timeout(int sig) /* Also called on SIGPIPE */ -{ - char errstr[MAX_STRING_LEN]; - void *dirconf; - - signal(SIGPIPE, SIG_IGN); /* Block SIGPIPE */ - if (alarms_blocked) { - alarm_pending = 1; - return; - } - - if (!current_conn) { - ap_longjmp (jmpbuffer, 1); - } - - if (timeout_req != NULL) dirconf = timeout_req->per_dir_config; - else dirconf = current_conn->server->lookup_defaults; - if (sig == SIGPIPE) { - ap_snprintf(errstr, sizeof(errstr), "%s lost connection to client %s", - timeout_name ? timeout_name : "request", - get_remote_host(current_conn, dirconf, REMOTE_NAME)); - } else { - ap_snprintf(errstr, sizeof(errstr), "%s timed out for %s", - timeout_name ? timeout_name : "request", - get_remote_host(current_conn, dirconf, REMOTE_NAME)); - } - - if (!current_conn->keptalive) - log_error(errstr, current_conn->server); - - if (timeout_req) { - /* Someone has asked for this transaction to just be aborted - * if it times out... - */ - - request_rec *log_req = timeout_req; - - while (log_req->main || log_req->prev) { - /* Get back to original request... */ - if (log_req->main) log_req = log_req->main; - else log_req = log_req->prev; - } - - if (!current_conn->keptalive) - log_transaction(log_req); - - bsetflag(timeout_req->connection->client, B_EOUT, 1); - bclose(timeout_req->connection->client); - - if (!standalone) exit(0); - - ap_longjmp (jmpbuffer, 1); - } - else { /* abort the connection */ - bsetflag(current_conn->client, B_EOUT, 1); - current_conn->aborted = 1; - } -} - -/* - * These two called from alloc.c to protect its critical sections... - * Note that they can nest (as when destroying the sub_pools of a pool - * which is itself being cleared); we have to support that here. - */ - -void block_alarms() { - ++alarms_blocked; -} - -void unblock_alarms() { - --alarms_blocked; - if (alarms_blocked == 0 && alarm_pending) { - alarm_pending = 0; - timeout(0); - } -} - -void keepalive_timeout (char *name, request_rec *r) -{ - timeout_req = r; - timeout_name = name; - - signal(SIGALRM, timeout); - if (r->connection->keptalive) - alarm (r->server->keep_alive_timeout); - else - alarm (r->server->timeout); -} - -void hard_timeout (char *name, request_rec *r) -{ - timeout_req = r; - timeout_name = name; - - signal(SIGALRM, timeout); - alarm (r->server->timeout); -} - -void soft_timeout (char *name, request_rec *r) -{ - timeout_name = name; - - signal(SIGALRM, timeout); - alarm (r->server->timeout); -} - -void kill_timeout (request_rec *dummy) { - alarm (0); - timeout_req = NULL; - timeout_name = NULL; -} - -/* reset_timeout (request_rec *) resets the timeout in effect, - * as long as it hasn't expired already. - */ - -void reset_timeout (request_rec *r) { - int i; - - if (timeout_name) { /* timeout has been set */ - i = alarm(r->server->timeout); - if (i == 0) /* timeout already expired, so set it back to 0 */ - alarm(0); - } -} - -/* - * More machine-dependent networking gooo... on some systems, - * you've got to be *really* sure that all the packets are acknowledged - * before closing the connection, since the client will not be able - * to see the last response if their TCP buffer is flushed by a RST - * packet from us, which is what the server's TCP stack will send - * if it receives any request data after closing the connection. - * - * In an ideal world, this function would be accomplished by simply - * setting the socket option SO_LINGER and handling it within the - * server's TCP stack while the process continues on to the next request. - * Unfortunately, it seems that most (if not all) operating systems - * block the server process on close() when SO_LINGER is used. - * For those that don't, see USE_SO_LINGER below. For the rest, - * we have created a home-brew lingering_close. - * - * Many operating systems tend to block, puke, or otherwise mishandle - * calls to shutdown only half of the connection. You should define - * NO_LINGCLOSE in conf.h if such is the case for your system. - */ -#ifndef MAX_SECS_TO_LINGER -#define MAX_SECS_TO_LINGER 30 -#endif - -#ifdef USE_SO_LINGER -#define NO_LINGCLOSE /* The two lingering options are exclusive */ - -static void sock_enable_linger (int s) -{ - struct linger li; - - li.l_onoff = 1; - li.l_linger = MAX_SECS_TO_LINGER; - - if (setsockopt(s, SOL_SOCKET, SO_LINGER, - (char *)&li, sizeof(struct linger)) < 0) { - log_unixerr("setsockopt", "(SO_LINGER)", NULL, server_conf); - /* not a fatal error */ - } -} - -#else -#define sock_enable_linger(s) /* NOOP */ -#endif /* USE_SO_LINGER */ - -#ifndef NO_LINGCLOSE - -/* Special version of timeout for lingering_close */ - -static void lingerout(sig) -int sig; -{ - if (alarms_blocked) { - alarm_pending = 1; - return; - } - - if (!current_conn) { - ap_longjmp (jmpbuffer, 1); - } - bsetflag(current_conn->client, B_EOUT, 1); - current_conn->aborted = 1; -} - -static void linger_timeout () -{ - timeout_name = "lingering close"; - - signal(SIGALRM, lingerout); - alarm(MAX_SECS_TO_LINGER); -} - -/* Since many clients will abort a connection instead of closing it, - * attempting to log an error message from this routine will only - * confuse the webmaster. There doesn't seem to be any portable way to - * distinguish between a dropped connection and something that might be - * worth logging. - */ -static void lingering_close (request_rec *r) -{ - int dummybuf[512]; - struct timeval tv; - fd_set lfds, fds_read, fds_err; - int select_rv = 0, read_rv = 0; - int lsd; - - /* Prevent a slow-drip client from holding us here indefinitely */ - - linger_timeout(); - - /* Send any leftover data to the client, but never try to again */ - - if (bflush(r->connection->client) == -1) { - kill_timeout(r); - bclose(r->connection->client); - return; - } - bsetflag(r->connection->client, B_EOUT, 1); - - /* Close our half of the connection --- send the client a FIN */ - - lsd = r->connection->client->fd; - - if ((shutdown(lsd, 1) != 0) || r->connection->aborted) { - kill_timeout(r); - bclose(r->connection->client); - return; - } - - /* Set up to wait for readable data on socket... */ - - FD_ZERO(&lfds); - FD_SET(lsd, &lfds); - - /* Wait for readable data or error condition on socket; - * slurp up any data that arrives... We exit when we go for - * an interval of tv length without getting any more data, get an - * error from select(), get an exception on lsd, get an error or EOF - * on a read, or the timer expires. - */ - - do { - /* We use a 2 second timeout because current (Feb 97) browsers - * fail to close a connection after the server closes it. Thus, - * to avoid keeping the child busy, we are only lingering long enough - * for a client that is actively sending data on a connection. - * This should be sufficient unless the connection is massively - * losing packets, in which case we might have missed the RST anyway. - * These parameters are reset on each pass, since they might be - * changed by select. - */ - tv.tv_sec = 2; - tv.tv_usec = 0; - read_rv = 0; - fds_read = lfds; - fds_err = lfds; - -#ifdef SELECT_NEEDS_CAST - select_rv = select(lsd+1, (int*)&fds_read, NULL, (int*)&fds_err, &tv); -#else - select_rv = select(lsd+1, &fds_read, NULL, &fds_err, &tv); -#endif - } while ((select_rv > 0) && /* Something to see on socket */ - !FD_ISSET(lsd, &fds_err) && /* that isn't an error condition */ - FD_ISSET(lsd, &fds_read) && /* and is worth trying to read */ - ((read_rv = read(lsd, dummybuf, sizeof dummybuf)) > 0)); - - /* Should now have seen final ack. Safe to finally kill socket */ - - bclose(r->connection->client); - - kill_timeout(r); -} -#endif /* ndef NO_LINGCLOSE */ - -/***************************************************************** - * - * Dealing with the scoreboard... a lot of these variables are global - * only to avoid getting clobbered by the longjmp() that happens when - * a hard timeout expires... - * - * We begin with routines which deal with the file itself... - */ - -#if defined(HAVE_MMAP) -static scoreboard *scoreboard_image=NULL; - -static void setup_shared_mem(void) -{ - caddr_t m; - -#ifdef __EMX__ - char errstr[MAX_STRING_LEN]; - int rc; - - m = (caddr_t)create_shared_heap("\\SHAREMEM\\SCOREBOARD", HARD_SERVER_LIMIT*sizeof(short_score)); - if(m == 0) { - fprintf(stderr, "httpd: Could not create OS/2 Shared memory pool.\n"); - exit(1); - } - - rc = _uopen((Heap_t)m); - if(rc != 0) { - fprintf(stderr, "httpd: Could not uopen() newly created OS/2 Shared memory pool.\n"); - } - -#elif defined(MAP_ANON) || defined(MAP_FILE) -/* BSD style */ -#ifdef CONVEXOS11 - /* - * 9-Aug-97 - Jeff Venters (venters@convex.hp.com) - * ConvexOS maps address space as follows: - * 0x00000000 - 0x7fffffff : Kernel - * 0x80000000 - 0xffffffff : User - * Start mmapped area 1GB above start of text. - * - * Also, the length requires a pointer as the actual length is - * returned (rounded up to a page boundary). - */ - { - unsigned len = SCOREBOARD_SIZE; - - m = mmap((caddr_t)0xC0000000, &len, - PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, NOFD, 0); - } -#else - m = mmap((caddr_t)0, SCOREBOARD_SIZE, - PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); -#endif - if (m == (caddr_t)-1) - { - perror("mmap"); - fprintf(stderr, "httpd: Could not mmap memory\n"); - exit(1); - } -#else -/* Sun style */ - int fd; - - fd = open("/dev/zero", O_RDWR); - if (fd == -1) - { - perror("open"); - fprintf(stderr, "httpd: Could not open /dev/zero\n"); - exit(1); - } - m = mmap((caddr_t)0, SCOREBOARD_SIZE, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (m == (caddr_t)-1) - { - perror("mmap"); - fprintf(stderr, "httpd: Could not mmap /dev/zero\n"); - exit(1); - } - close(fd); -#endif - scoreboard_image = (scoreboard *)m; - scoreboard_image->global.exit_generation=0; -} - -#elif defined(HAVE_SHMGET) -static scoreboard *scoreboard_image=NULL; -static key_t shmkey = IPC_PRIVATE; -static int shmid = -1; - -static void setup_shared_mem(void) -{ - char errstr[MAX_STRING_LEN]; - struct shmid_ds shmbuf; -#ifdef MOVEBREAK - char *obrk; -#endif - - if ((shmid = shmget(shmkey, SCOREBOARD_SIZE, IPC_CREAT|SHM_R|SHM_W)) == -1) - { -#ifdef LINUX - if (errno == ENOSYS) { - fprintf(stderr, - "httpd: Your kernel was built without CONFIG_SYSVIPC\n" - "httpd: please consult the Apache FAQ for details\n"); - } -#endif - perror("shmget"); - fprintf(stderr, "httpd: Could not call shmget\n"); - exit(1); - } - - ap_snprintf(errstr, sizeof(errstr), "created shared memory segment #%d", shmid); - log_error(errstr, server_conf); - -#ifdef MOVEBREAK - /* - * Some SysV systems place the shared segment WAY too close - * to the dynamic memory break point (sbrk(0)). This severely - * limits the use of malloc/sbrk in the program since sbrk will - * refuse to move past that point. - * - * To get around this, we move the break point "way up there", - * attach the segment and then move break back down. Ugly - */ - if ((obrk=sbrk(MOVEBREAK)) == (char *)-1) - { - perror("sbrk"); - fprintf(stderr, "httpd: Could not move break\n"); - } -#endif - -#define BADSHMAT ((scoreboard *)(-1)) - if ((scoreboard_image = (scoreboard *)shmat(shmid, 0, 0)) == BADSHMAT) - { - perror("shmat"); - fprintf(stderr, "httpd: Could not call shmat\n"); - /* - * We exit below, after we try to remove the segment - */ - } - else /* only worry about permissions if we attached the segment */ - { - if (shmctl(shmid, IPC_STAT, &shmbuf) != 0) { - perror("shmctl"); - fprintf(stderr, "httpd: Could not stat segment #%d\n", shmid); - } - else - { - shmbuf.shm_perm.uid = user_id; - shmbuf.shm_perm.gid = group_id; - if (shmctl(shmid, IPC_SET, &shmbuf) != 0) { - perror("shmctl"); - fprintf(stderr, "httpd: Could not set segment #%d\n", shmid); - } - } - } - /* - * We must avoid leaving segments in the kernel's - * (small) tables. - */ - if (shmctl(shmid, IPC_RMID, NULL) != 0) { - perror("shmctl"); - fprintf(stderr, "httpd: Could not delete segment #%d\n", shmid); - ap_snprintf(errstr, sizeof(errstr), "could not remove shared memory segment #%d", shmid); - log_unixerr("shmctl","IPC_RMID",errstr, server_conf); - } - if (scoreboard_image == BADSHMAT) /* now bailout */ - exit(1); - -#ifdef MOVEBREAK - if (obrk == (char *)-1) - return; /* nothing else to do */ - if (sbrk(-(MOVEBREAK)) == (char *)-1) - { - perror("sbrk"); - fprintf(stderr, "httpd: Could not move break back\n"); - } -#endif - scoreboard_image->global.exit_generation=0; -} - -#else -#define SCOREBOARD_FILE -static scoreboard _scoreboard_image; -static scoreboard *scoreboard_image=&_scoreboard_image; -static int scoreboard_fd; - -/* XXX: things are seriously screwed if we ever have to do a partial - * read or write ... we could get a corrupted scoreboard - */ -static int force_write (int fd, char *buffer, int bufsz) -{ - int rv, orig_sz = bufsz; - - do { - rv = write (fd, buffer, bufsz); - if (rv > 0) { - buffer += rv; - bufsz -= rv; - } - } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR)); - - return rv < 0? rv : orig_sz - bufsz; -} - -static int force_read (int fd, char *buffer, int bufsz) -{ - int rv, orig_sz = bufsz; - - do { - rv = read (fd, buffer, bufsz); - if (rv > 0) { - buffer += rv; - bufsz -= rv; - } - } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR)); - - return rv < 0? rv : orig_sz - bufsz; -} -#endif - -/* Called by parent process */ -void reinit_scoreboard (pool *p) -{ - int exit_gen=0; - if(scoreboard_image) - exit_gen=scoreboard_image->global.exit_generation; - -#ifndef SCOREBOARD_FILE - if (scoreboard_image == NULL) - { - setup_shared_mem(); - } - memset(scoreboard_image, 0, SCOREBOARD_SIZE); - scoreboard_image->global.exit_generation=exit_gen; -#else - scoreboard_fname = server_root_relative (p, scoreboard_fname); - -#ifdef __EMX__ - /* OS/2 needs binary mode set. */ - scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_BINARY|O_RDWR, 0644); -#else - scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0644); -#endif - if (scoreboard_fd == -1) - { - perror (scoreboard_fname); - fprintf (stderr, "Cannot open scoreboard file:\n"); - exit (1); - } - - memset ((char*)scoreboard_image, 0, sizeof(*scoreboard_image)); - scoreboard_image->global.exit_generation=exit_gen; - force_write (scoreboard_fd, (char*)scoreboard_image, - sizeof(*scoreboard_image)); -#endif -} - -/* called by child */ -void reopen_scoreboard (pool *p) -{ -#ifdef SCOREBOARD_FILE - if (scoreboard_fd != -1) pclosef (p, scoreboard_fd); - -#ifdef __EMX__ - /* OS/2 needs binary mode set. */ - scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_BINARY|O_RDWR, 0666); -#else - scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0666); -#endif - if (scoreboard_fd == -1) - { - perror (scoreboard_fname); - fprintf (stderr, "Cannot open scoreboard file:\n"); - exit (1); - } -#else -#ifdef __EMX__ -#ifdef HAVE_MMAP - caddr_t m; - int rc; - - m = (caddr_t)get_shared_heap("\\SHAREMEM\\SCOREBOARD"); - if(m == 0) { - fprintf(stderr, "httpd: Could not find existing OS/2 Shared memory pool.\n"); - exit(1); - } - - rc = _uopen((Heap_t)m); - scoreboard_image = (scoreboard *)m; -#endif -#endif -#endif -} - -void cleanup_scoreboard () -{ -#ifdef SCOREBOARD_FILE - unlink (scoreboard_fname); -#endif -} - -/* Routines called to deal with the scoreboard image - * --- note that we do *not* need write locks, since update_child_status - * only updates a *single* record in place, and only one process writes to - * a given scoreboard slot at a time (either the child process owning that - * slot, or the parent, noting that the child has died). - * - * As a final note --- setting the score entry to getpid() is always safe, - * since when the parent is writing an entry, it's only noting SERVER_DEAD - * anyway. - */ - -void sync_scoreboard_image () -{ -#ifdef SCOREBOARD_FILE - lseek (scoreboard_fd, 0L, 0); - force_read (scoreboard_fd, (char*)scoreboard_image, - sizeof(*scoreboard_image)); -#endif -} - -int exists_scoreboard_image () -{ - return (scoreboard_image ? 1 : 0); -} - -int update_child_status (int child_num, int status, request_rec *r) -{ - int old_status; - short_score new_score_rec; - - if (child_num < 0) - return -1; - - sync_scoreboard_image(); - new_score_rec = scoreboard_image->servers[child_num]; - new_score_rec.pid = getpid(); - old_status = new_score_rec.status; - new_score_rec.status = status; - -#if defined(STATUS) - new_score_rec.last_used=time(NULL); - if (status == SERVER_READY || status == SERVER_DEAD) { - /* - * Reset individual counters - */ - if (status == SERVER_DEAD) { - new_score_rec.my_access_count = 0L; - new_score_rec.my_bytes_served = 0L; - } - new_score_rec.conn_count = (unsigned short)0; - new_score_rec.conn_bytes = (unsigned long)0; - } - if (r) { - int slot_size; - conn_rec *c = r->connection; - slot_size = sizeof(new_score_rec.client) - 1; - strncpy(new_score_rec.client, get_remote_host(c, r->per_dir_config, - REMOTE_NOLOOKUP), slot_size); - new_score_rec.client[slot_size] = '\0'; - slot_size = sizeof(new_score_rec.request) - 1; - strncpy(new_score_rec.request, (r->the_request ? r->the_request : - "NULL"), slot_size); - new_score_rec.request[slot_size] = '\0'; - slot_size = sizeof(new_score_rec.vhost) - 1; - strncpy(new_score_rec.vhost,r->server->server_hostname, slot_size); - new_score_rec.vhost[slot_size] = '\0'; - } -#endif - -#ifndef SCOREBOARD_FILE - memcpy(&scoreboard_image->servers[child_num], &new_score_rec, sizeof new_score_rec); -#else - lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0); - force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score)); -#endif - - return old_status; -} - -void update_scoreboard_global() - { -#ifdef SCOREBOARD_FILE - lseek(scoreboard_fd, - (char *)&scoreboard_image->global-(char *)scoreboard_image,0); - force_write(scoreboard_fd,(char *)&scoreboard_image->global, - sizeof scoreboard_image->global); -#endif - } - -int get_child_status (int child_num) -{ - if (child_num<0 || child_num>=HARD_SERVER_LIMIT) - return -1; - else - return scoreboard_image->servers[child_num].status; -} - -int count_busy_servers () -{ - int i; - int res = 0; - - for (i = 0; i < HARD_SERVER_LIMIT; ++i) - if (scoreboard_image->servers[i].status == SERVER_BUSY_READ || - scoreboard_image->servers[i].status == SERVER_BUSY_WRITE || - scoreboard_image->servers[i].status == SERVER_BUSY_KEEPALIVE || - scoreboard_image->servers[i].status == SERVER_BUSY_LOG || - scoreboard_image->servers[i].status == SERVER_BUSY_DNS) - ++res; - return res; -} - -int count_live_servers() - { - int i; - int res = 0; - - for (i = 0; i < HARD_SERVER_LIMIT; ++i) - if (scoreboard_image->servers[i].status != SERVER_DEAD) - ++res; - return res; - } - -short_score get_scoreboard_info(int i) -{ - return (scoreboard_image->servers[i]); -} - -#if defined(STATUS) -static void increment_counts (int child_num, request_rec *r) -{ - long int bs=0; - short_score new_score_rec; - - sync_scoreboard_image(); - new_score_rec = scoreboard_image->servers[child_num]; - if (r->sent_bodyct) - bgetopt(r->connection->client, BO_BYTECT, &bs); - - new_score_rec.access_count ++; - new_score_rec.my_access_count ++; - new_score_rec.conn_count ++; - new_score_rec.bytes_served += (unsigned long)bs; - new_score_rec.my_bytes_served += (unsigned long)bs; - new_score_rec.conn_bytes += (unsigned long)bs; - - times(&new_score_rec.times); - - -#ifndef SCOREBOARD_FILE - memcpy(&scoreboard_image->servers[child_num], &new_score_rec, sizeof(short_score)); -#else - lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0); - force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score)); -#endif -} -#endif - -int count_idle_servers () -{ - int i; - int res = 0; - - for (i = 0; i < HARD_SERVER_LIMIT; ++i) - if (scoreboard_image->servers[i].status == SERVER_READY) - ++res; - - return res; -} - -int find_free_child_num () -{ - int i; - - for (i = 0; i < HARD_SERVER_LIMIT; ++i) - if (scoreboard_image->servers[i].status == SERVER_DEAD) - return i; - - return -1; -} - -int find_child_by_pid (int pid) -{ - int i; - - for (i = 0; i < HARD_SERVER_LIMIT; ++i) - if (scoreboard_image->servers[i].pid == pid) - return i; - - return -1; -} - -void reclaim_child_processes () -{ - int i, status; - int my_pid = getpid(); - - sync_scoreboard_image(); - for (i = 0; i < HARD_SERVER_LIMIT; ++i) { - int pid = scoreboard_image->servers[i].pid; - - if (pid != my_pid && pid != 0) { - int waitret = 0, - tries = 1; - - while (waitret == 0 && tries <= 4) { - long int waittime = 4096; /* in usecs */ - struct timeval tv; - - /* don't want to hold up progress any more than - * necessary, so keep checking to see if the child - * has exited with an exponential backoff. - * Currently set for a maximum wait of a bit over - * four seconds. - */ - while (((waitret = waitpid(pid, &status, WNOHANG)) == 0) && - waittime < 3000000) { - tv.tv_sec = waittime / 1000000; - tv.tv_usec = waittime % 1000000; - waittime = waittime * 2; - select(0, NULL, NULL, NULL, &tv); - } - if (waitret == 0) { - switch (tries) { - case 1: - /* perhaps it missed the SIGHUP, lets try again */ - log_printf(server_conf, "child process %d did not exit, sending another SIGHUP", pid); - kill(pid, SIGHUP); - break; - case 2: - /* ok, now it's being annoying */ - log_printf(server_conf, "child process %d still did not exit, sending a SIGTERM", pid); - kill(pid, SIGTERM); - break; - case 3: - /* die child scum */ - log_printf(server_conf, "child process %d still did not exit, sending a SIGKILL", pid); - kill(pid, SIGKILL); - break; - case 4: - /* gave it our best shot, but alas... If this really - * is a child we are trying to kill and it really hasn't - * exited, we will likely fail to bind to the port - * after the restart. - */ - log_printf(server_conf, "could not make child process %d exit, attempting to continue anyway", pid); - break; - } - } - tries++; - } - } - } -} - -#if defined(BROKEN_WAIT) || defined(NEED_WAITPID) -/* -Some systems appear to fail to deliver dead children to wait() at times. -This sorts them out. In fact, this may have been caused by a race condition -in wait_or_timeout(). But this routine is still useful for systems with no -waitpid(). -*/ -int reap_children () -{ - int status, n; - int ret = 0; - - for (n = 0; n < HARD_SERVER_LIMIT; ++n) { - if (scoreboard_image->servers[n].status != SERVER_DEAD - && waitpid (scoreboard_image->servers[n].pid, &status, WNOHANG) - == -1 - && errno == ECHILD) { - sync_scoreboard_image (); - update_child_status (n, SERVER_DEAD, NULL); - ret = 1; - } - } - return ret; -} -#endif - -/* Finally, this routine is used by the caretaker process to wait for - * a while... - */ - -static int wait_or_timeout () -{ -#ifndef NEED_WAITPID - int ret; - - ret = waitpid (-1, NULL, WNOHANG); - if (ret == -1 && errno == EINTR) { - return -1; - } - if (ret <= 0) { - sleep (1); - return -1; - } - return ret; -#else - if (!reap_children ()) { - sleep(1); - } - return -1; -#endif -} - - -void sig_term() { - log_error("httpd: caught SIGTERM, shutting down", server_conf); - cleanup_scoreboard(); - ap_killpg (pgrp, SIGKILL); - close(sd); - exit(1); -} - -void bus_error(void) { - char emsg[256]; - - ap_snprintf - ( - emsg, - sizeof(emsg) - 1, - "httpd: caught SIGBUS, attempting to dump core in %s", - server_root - ); - log_error(emsg, server_conf); - chdir(server_root); - abort(); - exit(1); -} - -void seg_fault() { - char emsg[256]; - - ap_snprintf - ( - emsg, - sizeof(emsg) - 1, - "httpd: caught SIGSEGV, attempting to dump core in %s", - server_root - ); - log_error(emsg, server_conf); - chdir(server_root); - abort(); - exit(1); -} - -void just_die() /* SIGHUP to child process??? */ -{ - exit (0); -} - -static int deferred_die; - -static void deferred_die_handler () -{ - deferred_die = 1; -} - -/* volatile just in case */ -static volatile int restart_pending; -static volatile int is_graceful; -static volatile int generation; - -static void restart (int sig) -{ - is_graceful = (sig == SIGUSR1); - restart_pending = 1; -} - - -void set_signals() -{ -#ifndef NO_USE_SIGACTION - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - if (!one_process) { - sa.sa_handler = (void (*)())seg_fault; - if (sigaction (SIGSEGV, &sa, NULL) < 0) - log_unixerr ("sigaction(SIGSEGV)", NULL, NULL, server_conf); - sa.sa_handler = (void (*)())bus_error; - if (sigaction (SIGBUS, &sa, NULL) < 0) - log_unixerr ("sigaction(SIGBUS)", NULL, NULL, server_conf); - } - sa.sa_handler = (void (*)())sig_term; - if (sigaction (SIGTERM, &sa, NULL) < 0) - log_unixerr ("sigaction(SIGTERM)", NULL, NULL, server_conf); - - /* wait_or_timeout uses sleep() which could deliver a SIGALRM just as we're - * trying to process the restart requests. That's not good. restart - * cleans out the SIGALRM handler, but this totally avoids the race - * condition between when the restart request is made and when the handler - * is invoked. - * - * We also don't want to ignore HUPs and USR1 while we're busy processing - * one. - */ - sigaddset (&sa.sa_mask, SIGALRM); - sigaddset (&sa.sa_mask, SIGHUP); - sigaddset (&sa.sa_mask, SIGUSR1); - sa.sa_handler = (void (*)())restart; - if (sigaction (SIGHUP, &sa, NULL) < 0) - log_unixerr ("sigaction(SIGHUP)", NULL, NULL, server_conf); - if (sigaction (SIGUSR1, &sa, NULL) < 0) - log_unixerr ("sigaction(SIGUSR1)", NULL, NULL, server_conf); -#else - if(!one_process) { - signal (SIGSEGV, (void (*)())seg_fault); - signal (SIGBUS, (void (*)())bus_error); - } - - signal (SIGTERM, (void (*)())sig_term); - signal (SIGHUP, (void (*)())restart); - signal (SIGUSR1, (void (*)())restart); -#endif -} - - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -void detach() -{ - int x; - - chdir("/"); -#ifndef MPE -/* Don't detach for MPE because child processes can't survive the death of - the parent. */ - if((x = fork()) > 0) - exit(0); - else if(x == -1) { - perror("fork"); - fprintf(stderr,"httpd: unable to fork new process\n"); - exit(1); - } -#endif -#ifndef NO_SETSID - if((pgrp=setsid()) == -1) { - perror("setsid"); - fprintf(stderr,"httpd: setsid failed\n"); - exit(1); - } -#elif defined(NEXT) - if(setpgrp(0,getpid()) == -1 || (pgrp = getpgrp(0)) == -1) { - perror("setpgrp"); - fprintf(stderr,"httpd: setpgrp or getpgrp failed\n"); - exit(1); - } -#elif defined(__EMX__) - /* OS/2 doesn't support process group IDs */ - pgrp=getpid(); -#elif defined(MPE) - /* MPE uses negative pid for process group */ - pgrp=-getpid(); -#else - if((pgrp=setpgrp(getpid(),0)) == -1) { - perror("setpgrp"); - fprintf(stderr,"httpd: setpgrp failed\n"); - exit(1); - } -#endif -} - -/* Reset group privileges, after rereading the config files - * (our uid may have changed, and if so, we want the new perms). - * - * Don't reset the uid yet --- we do that only in the child process, - * so as not to lose any root privs. But we can set the group stuff - * now, once, as opposed to once per each new child. - * - * Note that we use the username as set in the config files, rather than - * the lookup of to uid --- the same uid may have multiple passwd entries, - * with different sets of groups for each. - */ - -static void set_group_privs() -{ - if(!geteuid()) { - char *name; - - /* Get username if passed as a uid */ - - if (user_name[0] == '#') { - struct passwd* ent; - uid_t uid=atoi(&user_name[1]); - - if ((ent = getpwuid(uid)) == NULL) { - log_unixerr("getpwuid",NULL,"couldn't determine user name from uid", server_conf); - exit(1); - } - - name = ent->pw_name; - } else name = user_name; - -#ifndef __EMX__ - /* OS/2 dosen't support groups. */ - - /* Reset `groups' attributes. */ - - if (initgroups(name, group_id) == -1) { - log_unixerr("initgroups", NULL, "unable to set groups", server_conf); - exit (1); - } -#ifdef MULTIPLE_GROUPS - if (getgroups(NGROUPS_MAX, group_id_list) == -1) { - log_unixerr("getgroups", NULL, "unable to get group list", server_conf); - exit (1); - } -#endif - if (setgid(group_id) == -1) { - log_unixerr("setgid", NULL, "unable to set group id", server_conf); - exit (1); - } -#endif - } -} - -/* check to see if we have the 'suexec' setuid wrapper installed */ -int init_suexec () -{ - struct stat wrapper; - - if ((stat(SUEXEC_BIN, &wrapper)) != 0) - return (suexec_enabled); - - if ((wrapper.st_mode & S_ISUID) && wrapper.st_uid == 0) { - suexec_enabled = 1; - fprintf(stderr, "Configuring Apache for use with suexec wrapper.\n"); - } - - return (suexec_enabled); -} - -/***************************************************************** - * Connection structures and accounting... - * Should these be global? Only to this file, at least... - */ - -pool *pconf; /* Pool for config stuff */ -pool *ptrans; /* Pool for per-transaction stuff */ - -static server_rec *find_virtual_server (struct in_addr server_ip, - unsigned port, server_rec *server) -{ - server_rec *virt; - server_addr_rec *sar; - server_rec *def; - - def = server; - for (virt = server->next; virt; virt = virt->next) { - for (sar = virt->addrs; sar; sar = sar->next) { - if ((virt->is_virtual == 1) && /* VirtualHost */ - (sar->host_addr.s_addr == htonl(INADDR_ANY) || - sar->host_addr.s_addr == server_ip.s_addr) && - (sar->host_port == 0 || sar->host_port == port)) { - return virt; - } else if ( sar->host_addr.s_addr == DEFAULT_VHOST_ADDR - && (sar->host_port == 0 || sar->host_port == port)) { - /* this is so that you can build a server that is the - "default" for any interface which isn't explicitly - specified. So that you can implement "deny anything - which isn't expressly permitted" -djg */ - def = virt; - } - } - } - - return def; -} - -void default_server_hostnames(server_rec *s) -{ - struct hostent *h; - struct in_addr *main_addr; - int num_addr; - char *def_hostname; - int n; - server_addr_rec *sar; - int has_default_vhost_addr; - unsigned mainport = s->port; - int from_local=0; - - /* Main host first */ - - if (!s->server_hostname) { - s->server_hostname = get_local_host(pconf); - from_local = 1; - } - - def_hostname = s->server_hostname; - h = gethostbyname(def_hostname); - if( h == NULL ) { - fprintf(stderr,"httpd: cannot determine the IP address of "); - if (from_local) { - fprintf(stderr,"the local host (%s). Use ServerName to set it manually.\n", - s->server_hostname ? s->server_hostname : "<NULL>"); - } else { - fprintf(stderr,"the specified ServerName (%s).\n", - s->server_hostname ? s->server_hostname : "<NULL>"); - }; - exit(1); - } - /* we need to use gethostbyaddr below... and since it shares a static - area with gethostbyname it'd clobber the value we just got. So - we need to make a copy. -djg */ - for (num_addr = 0; h->h_addr_list[num_addr] != NULL; num_addr++) { - /* nop */ - } - main_addr = palloc( pconf, sizeof( *main_addr ) * num_addr ); - for (n = 0; n < num_addr; n++) { - main_addr[n] = *(struct in_addr *)h->h_addr_list[n]; - } - - /* Then virtual hosts */ - - for (s = s->next; s; s = s->next) { - /* Check to see if we might be a HTTP/1.1 virtual host - same IP */ - has_default_vhost_addr = 0; - for (n = 0; n < num_addr; n++) { - for(sar = s->addrs; sar; sar = sar->next) { - if (sar->host_addr.s_addr == main_addr[n].s_addr && - s->port == mainport) - s->is_virtual = 2; - if( sar->host_addr.s_addr == DEFAULT_VHOST_ADDR ) { - has_default_vhost_addr = 1; - } - } - } - - /* FIXME: some of this decision doesn't make a lot of sense in - the presence of multiple addresses on the <VirtualHost> - directive. It should issue warnings here perhaps. -djg */ - if (!s->server_hostname) { - if (s->is_virtual == 2) { - if (s->addrs) { - s->server_hostname = s->addrs->virthost; - } else { - /* what else can we do? at this point this vhost has - no configured name, probably because they used - DNS in the VirtualHost statement. It's disabled - anyhow by the host matching code. -djg */ - s->server_hostname = "bogus_host_without_forward_dns"; - } - } else if (has_default_vhost_addr) { - s->server_hostname = def_hostname; - } else { - if (s->addrs - && (h = gethostbyaddr ((char *)&(s->addrs->host_addr), - sizeof (struct in_addr), AF_INET))) { - s->server_hostname = pstrdup (pconf, (char *)h->h_name); - } else { - /* again, what can we do? They didn't specify a - ServerName, and their DNS isn't working. -djg */ - if (s->addrs) { - fprintf(stderr, "Failed to resolve server name " - "for %s (check DNS)\n", - inet_ntoa(s->addrs->host_addr)); - } - s->server_hostname = "bogus_host_without_reverse_dns"; - } - } - } - } -} - -conn_rec *new_connection (pool *p, server_rec *server, BUFF *inout, - const struct sockaddr_in *remaddr, - const struct sockaddr_in *saddr, - int child_num) -{ - conn_rec *conn = (conn_rec *)pcalloc (p, sizeof(conn_rec)); - - /* Got a connection structure, so initialize what fields we can - * (the rest are zeroed out by pcalloc). - */ - - conn->child_num = child_num; - - conn->pool = p; - conn->local_addr = *saddr; - conn->server = find_virtual_server(saddr->sin_addr, ntohs(saddr->sin_port), - server); - conn->base_server = conn->server; - conn->client = inout; - - conn->remote_addr = *remaddr; - conn->remote_ip = pstrdup (conn->pool, - inet_ntoa(conn->remote_addr.sin_addr)); - - return conn; -} - -#if defined(TCP_NODELAY) && !defined(MPE) -static void sock_disable_nagle (int s) -{ - /* The Nagle algorithm says that we should delay sending partial - * packets in hopes of getting more data. We don't want to do - * this; we are not telnet. There are bad interactions between - * persistent connections and Nagle's algorithm that have very severe - * performance penalties. (Failing to disable Nagle is not much of a - * problem with simple HTTP.) - * - * In spite of these problems, failure here is not a shooting offense. - */ - int just_say_no = 1; - - if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&just_say_no, - sizeof(int)) < 0) { - log_unixerr("setsockopt", "(TCP_NODELAY)", NULL, server_conf); - } -} -#else -#define sock_disable_nagle(s) /* NOOP */ -#endif - -/***************************************************************** - * Child process main loop. - * The following vars are static to avoid getting clobbered by longjmp(); - * they are really private to child_main. - */ - -static int srv; -static int csd; -static int dupped_csd; -static int requests_this_child; -static int child_num; -static fd_set main_fds; - -void child_main(int child_num_arg) -{ -#if defined(UW) - size_t clen; -#else - int clen; -#endif - struct sockaddr sa_server; - struct sockaddr sa_client; - - csd = -1; - dupped_csd = -1; - child_num = child_num_arg; - requests_this_child = 0; - - reopen_scoreboard(pconf); - (void)update_child_status(child_num, SERVER_READY, (request_rec*)NULL); - -#ifdef MPE - /* Only try to switch if we're running as MANAGER.SYS */ - if (geteuid() == 1 && user_id > 1) { - GETPRIVMODE(); - if (setuid(user_id) == -1) { - GETUSERMODE(); -#else - /* Only try to switch if we're running as root */ - if (!geteuid() && setuid(user_id) == -1) { -#endif - log_unixerr("setuid", NULL, "unable to change uid", server_conf); - exit (1); - } -#ifdef MPE - GETUSERMODE(); - } -#endif - - /* - * Setup the jump buffers so that we can return here after - * a signal or a timeout (yeah, I know, same thing). - */ - ap_setjmp (jmpbuffer); -#ifndef __EMX__ -#ifdef SIGURG - signal(SIGURG, timeout); -#endif -#endif - - while (1) { - int errsave; - BUFF *conn_io; - request_rec *r; - - /* Prepare to receive a SIGUSR1 due to graceful restart so that - * we can exit cleanly. Since we're between connections right - * now it's the right time to exit, but we might be blocked in a - * system call when the graceful restart request is made. */ - signal (SIGUSR1, (void (*)())just_die); - - /* - * (Re)initialize this child to a pre-connection state. - */ - - alarm(0); /* Cancel any outstanding alarms. */ - timeout_req = NULL; /* No request in progress */ - current_conn = NULL; - signal(SIGPIPE, timeout); - - clear_pool (ptrans); - - sync_scoreboard_image(); - if (scoreboard_image->global.exit_generation >= generation) - exit(0); - - if ((count_idle_servers() >= daemons_max_free) - || (max_requests_per_child > 0 - && ++requests_this_child >= max_requests_per_child)) - { - exit(0); - } - - (void)update_child_status(child_num, SERVER_READY, (request_rec*)NULL); - - if (listeners == NULL) { - FD_ZERO(&listenfds); - FD_SET(sd, &listenfds); - listenmaxfd = sd; - } - - /* - * Wait for an acceptable connection to arrive. - */ - - accept_mutex_on(); /* Lock around "accept", if necessary */ - - for (;;) { - memcpy(&main_fds, &listenfds, sizeof(fd_set)); -#ifdef SELECT_NEEDS_CAST - srv = select(listenmaxfd+1, (int*)&main_fds, NULL, NULL, NULL); -#else - srv = select(listenmaxfd+1, &main_fds, NULL, NULL, NULL); -#endif - errsave = errno; - - sync_scoreboard_image(); - if (scoreboard_image->global.exit_generation >= generation) - exit(0); - - errno = errsave; - if (srv < 0 && errno != EINTR) { - /* Single Unix documents select as returning errnos - * EBADF, EINTR, and EINVAL... and in none of those - * cases does it make sense to continue. In fact - * on Linux 2.0.x we seem to end up with EFAULT - * occasionally, and we'd loop forever due to it. - */ - log_unixerr("select", "(listen)", NULL, server_conf); - exit(1); - } - - if (srv <= 0) - continue; - - if (listeners != NULL) { - for (sd = listenmaxfd; sd >= 0; sd--) - if (FD_ISSET(sd, &main_fds)) break; - if (sd < 0) - continue; - } - - /* if we accept() something we don't want to die, so we have to - * defer the exit - */ - deferred_die = 0; - signal (SIGUSR1, (void (*)())deferred_die_handler); - for (;;) { - clen = sizeof(sa_client); - csd = accept(sd, &sa_client, &clen); - if (csd >= 0 || errno != EINTR) break; - if (deferred_die) { - /* we didn't get a socket, and we were told to die */ - exit (0); - } - } - - if (csd >= 0) - break; /* We have a socket ready for reading */ - else { - /* Our old behaviour here was to continue after accept() - * errors. But this leads us into lots of troubles - * because most of the errors are quite fatal. For - * example, EMFILE can be caused by slow descriptor - * leaks (say in a 3rd party module, or libc). It's - * foolish for us to continue after an EMFILE. We also - * seem to tickle kernel bugs on some platforms which - * lead to never-ending loops here. So it seems best - * to just exit in most cases. - */ - switch (errno) { -#ifdef EPROTO - /* EPROTO on certain older kernels really means - * ECONNABORTED, so we need to ignore it for them. - * See discussion in new-httpd archives nh.9701 - * search for EPROTO. - * - * Also see nh.9603, search for EPROTO: - * There is potentially a bug in Solaris 2.x x<6, - * and other boxes that implement tcp sockets in - * userland (i.e. on top of STREAMS). On these - * systems, EPROTO can actually result in a fatal - * loop. See PR#981 for example. It's hard to - * handle both uses of EPROTO. - */ - case EPROTO: -#endif -#ifdef ECONNABORTED - case ECONNABORTED: -#endif - /* Linux generates the rest of these, other tcp - * stacks (i.e. bsd) tend to hide them behind - * getsockopt() interfaces. They occur when - * the net goes sour or the client disconnects - * after the three-way handshake has been done - * in the kernel but before userland has picked - * up the socket. - */ -#ifdef ECONNRESET - case ECONNRESET: -#endif -#ifdef ETIMEDOUT - case ETIMEDOUT: -#endif -#ifdef EHOSTUNREACH - case EHOSTUNREACH: -#endif -#ifdef ENETUNREACH - case ENETUNREACH: -#endif - break; - - default: - log_unixerr("accept", "(client socket)", NULL, server_conf); - exit(1); - } - } - - /* go around again, safe to die */ - signal (SIGUSR1, (void (*)())just_die); - if (deferred_die) { - /* ok maybe not, see ya later */ - exit (0); - } - } - - accept_mutex_off(); /* unlock after "accept" */ - - /* We've got a socket, let's at least process one request off the - * socket before we accept a graceful restart request. - */ - signal (SIGUSR1, SIG_IGN); - - note_cleanups_for_fd(ptrans,csd); - - /* - * We now have a connection, so set it up with the appropriate - * socket options, file descriptors, and read/write buffers. - */ - - clen = sizeof(sa_server); - if (getsockname(csd, &sa_server, &clen) < 0) { - log_unixerr("getsockname", NULL, NULL, server_conf); - continue; - } - - sock_disable_nagle(csd); - - (void)update_child_status(child_num, SERVER_BUSY_READ, - (request_rec*)NULL); - - conn_io = bcreate(ptrans, B_RDWR); - dupped_csd = csd; -#if defined(NEED_DUPPED_CSD) - if ((dupped_csd = dup(csd)) < 0) { - log_unixerr("dup", NULL, "couldn't duplicate csd", server_conf); - dupped_csd = csd; /* Oh well... */ - } - note_cleanups_for_fd(ptrans,dupped_csd); -#endif - bpushfd(conn_io, csd, dupped_csd); - - current_conn = new_connection (ptrans, server_conf, conn_io, - (struct sockaddr_in *)&sa_client, - (struct sockaddr_in *)&sa_server, - child_num); - - /* - * Read and process each request found on our connection - * until no requests are left or we decide to close. - */ - - while ((r = read_request(current_conn)) != NULL) { - - /* ok we've read the request... it's a little too late - * to do a graceful restart, so ignore them for now. - */ - signal (SIGUSR1, SIG_IGN); - - (void)update_child_status(child_num, SERVER_BUSY_WRITE, r); - - process_request(r); -#if defined(STATUS) - increment_counts(child_num, r); -#endif - if (!current_conn->keepalive || current_conn->aborted) - break; - - destroy_pool(r->pool); - (void)update_child_status(child_num, SERVER_BUSY_KEEPALIVE, - (request_rec*)NULL); - - sync_scoreboard_image(); - if (scoreboard_image->global.exit_generation >= generation) { - bclose(conn_io); - exit(0); - } - - /* In case we get a graceful restart while we're blocked - * waiting for the request. - * - * XXX: This isn't perfect, we might actually read the - * request and then just die without saying anything to - * the client. This can be fixed by using deferred_die - * but you have to teach buff.c about it so that it can handle - * the EINTR properly. - * - * In practice though browsers (have to) expect keepalive - * connections to close before receiving a response because - * of network latencies and server timeouts. - */ - signal (SIGUSR1, (void (*)())just_die); - } - - /* - * Close the connection, being careful to send out whatever is still - * in our buffers. If possible, try to avoid a hard close until the - * client has ACKed our FIN and/or has stopped sending us data. - */ - -#ifdef NO_LINGCLOSE - bclose(conn_io); /* just close it */ -#else - if (r && r->connection - && !r->connection->aborted - && r->connection->client - && (r->connection->client->fd >= 0)) { - - lingering_close(r); - } - else { - bsetflag(conn_io, B_EOUT, 1); - bclose(conn_io); - } -#endif - } -} - -int make_child(server_rec *server_conf, int child_num) -{ - int pid; - - if (one_process) { - signal (SIGHUP, (void (*)())just_die); - signal (SIGTERM, (void (*)())just_die); - child_main (child_num); - } - - Explain1 ("Starting new child in slot %d", child_num); - (void)update_child_status (child_num, SERVER_STARTING, (request_rec *)NULL); - - if ((pid = fork()) == -1) { - log_unixerr("fork", NULL, "Unable to fork new process", server_conf); - - /* fork didn't succeed. Fix the scoreboard or else - * it will say SERVER_STARTING forever and ever - */ - (void)update_child_status (child_num, SERVER_DEAD, (request_rec*)NULL); - - /* In case system resources are maxxed out, we don't want - Apache running away with the CPU trying to fork over and - over and over again. */ - sleep(10); - - return -1; - } - - if (!pid) { - /* Disable the restart signal handlers and enable the just_die stuff. - * Note that since restart() just notes that a restart has been - * requested there's no race condition here. - */ - signal (SIGHUP, (void (*)())just_die); - signal (SIGUSR1, (void (*)())just_die); - signal (SIGTERM, (void (*)())just_die); - child_main (child_num); - } - - /* If the parent proceeds with a restart before the child has written - * their pid into the scoreboard we'll end up "forgetting" about the - * child. So we write the child pid into the scoreboard now. (This - * is safe, because the child is going to be writing the same value - * to the same word.) - * XXX: this needs to be sync'd to disk in the non shared memory stuff - */ - scoreboard_image->servers[child_num].pid = pid; - - return 0; -} - -static int make_sock(pool *pconf, const struct sockaddr_in *server) -{ - int s; - int one = 1; - - if ((s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) { - log_unixerr("socket", NULL, "Failed to get a socket, exiting child", - server_conf); - exit(1); - } - - /* Solaris (probably versions 2.4, 2.5, and 2.5.1 with various levels - * of tcp patches) has some really weird bugs where if you dup the - * socket now it breaks things across SIGHUP restarts. It'll either - * be unable to bind, or it won't respond. - */ -#ifndef SOLARIS2 - s = ap_slack(s, AP_SLACK_HIGH); - - note_cleanups_for_fd(pconf, s); /* arrange to close on exec or restart */ -#endif - -#ifndef MPE -/* MPE does not support SO_REUSEADDR and SO_KEEPALIVE */ - if (setsockopt(s, SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(int)) < 0) { - log_unixerr("setsockopt", "(SO_REUSEADDR)", NULL, server_conf); - exit(1); - } - one = 1; - if (setsockopt(s, SOL_SOCKET,SO_KEEPALIVE,(char *)&one,sizeof(int)) < 0) { - log_unixerr("setsockopt", "(SO_KEEPALIVE)", NULL, server_conf); - exit(1); - } -#endif - - sock_disable_nagle(s); - sock_enable_linger(s); - - /* - * To send data over high bandwidth-delay connections at full - * speed we must force the TCP window to open wide enough to keep the - * pipe full. The default window size on many systems - * is only 4kB. Cross-country WAN connections of 100ms - * at 1Mb/s are not impossible for well connected sites. - * If we assume 100ms cross-country latency, - * a 4kB buffer limits throughput to 40kB/s. - * - * To avoid this problem I've added the SendBufferSize directive - * to allow the web master to configure send buffer size. - * - * The trade-off of larger buffers is that more kernel memory - * is consumed. YMMV, know your customers and your network! - * - * -John Heidemann <johnh@isi.edu> 25-Oct-96 - * - * If no size is specified, use the kernel default. - */ - if (server_conf->send_buffer_size) { - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, - (char *)&server_conf->send_buffer_size, sizeof(int)) < 0) { - log_unixerr("setsockopt", "(SO_SNDBUF)", - "Failed to set SendBufferSize, using default", - server_conf); - /* not a fatal error */ - } - } - -#ifdef MPE -/* MPE requires CAP=PM and GETPRIVMODE to bind to ports less than 1024 */ - if (ntohs(server->sin_port) < 1024) GETPRIVMODE(); -#endif - if(bind(s, (struct sockaddr *)server,sizeof(struct sockaddr_in)) == -1) - { - perror("bind"); -#ifdef MPE - if (ntohs(server->sin_port) < 1024) GETUSERMODE(); -#endif - if (server->sin_addr.s_addr != htonl(INADDR_ANY)) - fprintf(stderr,"httpd: could not bind to address %s port %d\n", - inet_ntoa(server->sin_addr), ntohs(server->sin_port)); - else - fprintf(stderr,"httpd: could not bind to port %d\n", - ntohs(server->sin_port)); - exit(1); - } -#ifdef MPE - if (ntohs(server->sin_port) < 1024) GETUSERMODE(); -#endif - listen(s, 512); - -#ifdef SOLARIS2 - s = ap_slack(s, AP_SLACK_HIGH); - - note_cleanups_for_fd(pconf, s); /* arrange to close on exec or restart */ -#endif - return s; -} - -static listen_rec *old_listeners; - -static void copy_listeners(pool *p) - { - listen_rec *lr; - - assert(old_listeners == NULL); - for(lr=listeners ; lr ; lr=lr->next) - { - listen_rec *nr=malloc(sizeof *nr); - if (nr == NULL) { - fprintf (stderr, "Ouch! malloc failed in copy_listeners()\n"); - exit (1); - } - *nr=*lr; - kill_cleanups_for_fd(p,nr->fd); - nr->next=old_listeners; - assert(!nr->used); - old_listeners=nr; - } - } - -static int find_listener(listen_rec *lr) - { - listen_rec *or; - - for(or=old_listeners ; or ; or=or->next) - if(!memcmp(&or->local_addr,&lr->local_addr,sizeof or->local_addr)) - { - or->used=1; - return or->fd; - } - return -1; - } - -static void close_unused_listeners() - { - listen_rec *or,*next; - - for(or=old_listeners ; or ; or=next) - { - next=or->next; - if(!or->used) - close(or->fd); - free(or); - } - old_listeners=NULL; - } - -/***************************************************************** - * Executive routines. - */ - -void standalone_main(int argc, char **argv) -{ - struct sockaddr_in sa_server; - int saved_sd; - int remaining_children_to_start; - - standalone = 1; - sd = listenmaxfd = -1; - - is_graceful = 0; - ++generation; - - if (!one_process) detach (); - - do { - copy_listeners(pconf); - saved_sd = sd; - if (!is_graceful) { - restart_time = time(NULL); - } -#ifdef SCOREBOARD_FILE - else { - kill_cleanups_for_fd (pconf, scoreboard_fd); - } -#endif - clear_pool (pconf); - ptrans = make_sub_pool (pconf); - - server_conf = read_config (pconf, ptrans, server_confname); - - if (listeners == NULL) { - if (!is_graceful) { - memset ((char *)&sa_server, 0, sizeof (sa_server)); - sa_server.sin_family = AF_INET; - sa_server.sin_addr = bind_address; - sa_server.sin_port = htons (server_conf->port); - sd = make_sock (pconf, &sa_server); - } - else { - sd = saved_sd; - note_cleanups_for_fd(pconf, sd); - } - } - else { - listen_rec *lr; - int fd; - - listenmaxfd = -1; - FD_ZERO (&listenfds); - for (lr = listeners; lr != NULL; lr = lr->next) - { - fd = find_listener (lr); - if (fd < 0) { - fd = make_sock (pconf, &lr->local_addr); - } - FD_SET (fd, &listenfds); - if (fd > listenmaxfd) listenmaxfd = fd; - lr->fd = fd; - } - close_unused_listeners (); - sd = -1; - } - - init_modules (pconf, server_conf); - open_logs (server_conf, pconf); - set_group_privs (); - accept_mutex_init (pconf); - if (!is_graceful) { - reinit_scoreboard(pconf); - } -#ifdef SCOREBOARD_FILE - else { - scoreboard_fname = server_root_relative (pconf, scoreboard_fname); - note_cleanups_for_fd (pconf, scoreboard_fd); - } -#endif - - default_server_hostnames (server_conf); - - set_signals (); - log_pid (pconf, pid_fname); - - if (daemons_max_free < daemons_min_free + 1) /* Don't thrash... */ - daemons_max_free = daemons_min_free + 1; - - /* If we're doing a graceful_restart then we're going to see a lot - * of children exiting immediately when we get into the main loop - * below (because we just sent them SIGUSR1). This happens pretty - * rapidly... and for each one that exits we'll start a new one until - * we reach at least daemons_min_free. But we may be permitted to - * start more than that, so we'll just keep track of how many we're - * supposed to start up without the 1 second penalty between each fork. - */ - remaining_children_to_start = daemons_to_start; - if( remaining_children_to_start > daemons_limit ) { - remaining_children_to_start = daemons_limit; - } - if (!is_graceful) { - while (remaining_children_to_start) { - --remaining_children_to_start; - make_child (server_conf, remaining_children_to_start); - } - } - - log_error ("Server configured -- resuming normal operations", - server_conf); - restart_pending = 0; - - while (!restart_pending) { - int child_slot; - int pid = wait_or_timeout (); - - /* XXX: if it takes longer than 1 second for all our children - * to start up and get into IDLE state then we may spawn an - * extra child - */ - if (pid >= 0) { - /* Child died... note that it's gone in the scoreboard. */ - sync_scoreboard_image (); - child_slot = find_child_by_pid (pid); - Explain2 ("Reaping child %d slot %d", pid, child_slot); - if (child_slot >= 0) { - (void)update_child_status (child_slot, SERVER_DEAD, - (request_rec *)NULL); - } else if (is_graceful) { - /* Great, we've probably just lost a slot in the - * scoreboard. Somehow we don't know about this - * child. - */ - log_printf (server_conf, - "long lost child came home! (pid %d)", pid ); - } - } else if (remaining_children_to_start) { - /* we hit a 1 second timeout in which none of the previous - * generation of children needed to be reaped... so assume - * they're all done, and pick up the slack if any is left. - */ - while (remaining_children_to_start > 0) { - child_slot = find_free_child_num (); - if (child_slot < 0 || child_slot >= daemons_limit) { - remaining_children_to_start = 0; - break; - } - if (make_child (server_conf, child_slot) < 0) { - remaining_children_to_start = 0; - break; - } - --remaining_children_to_start; - } - /* In any event we really shouldn't do the code below because - * few of the servers we just started are in the IDLE state - * yet, so we'd mistakenly create an extra server. - */ - continue; - } - - sync_scoreboard_image (); - if ((remaining_children_to_start - || (count_idle_servers () < daemons_min_free)) - && (child_slot = find_free_child_num ()) >= 0 - && child_slot < daemons_limit) { - make_child (server_conf, child_slot); - } - if (remaining_children_to_start) { - --remaining_children_to_start; - } - } - - /* we've been told to restart */ - signal (SIGHUP, SIG_IGN); - signal (SIGUSR1, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - exit (0); - } - - if (is_graceful) { -#ifndef SCOREBOARD_FILE - int i; -#endif - - /* USE WITH CAUTION: Graceful restarts are not known to work - * in various configurations on the architectures we support. */ - scoreboard_image->global.exit_generation = generation; - update_scoreboard_global (); - - log_error ("SIGUSR1 received. Doing graceful restart",server_conf); - kill_cleanups_for_fd (pconf, sd); - /* kill off the idle ones */ - if (ap_killpg(pgrp, SIGUSR1) < 0) { - log_unixerr ("killpg SIGUSR1", NULL, NULL, server_conf); - } -#ifndef SCOREBOARD_FILE - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. But we can't really - * do it if we're in a SCOREBOARD_FILE because it'll cause - * corruption too easily. - */ - sync_scoreboard_image(); - for (i = 0; i < daemons_limit; ++i ) { - if (scoreboard_image->servers[i].status != SERVER_DEAD) { - scoreboard_image->servers[i].status = SERVER_GRACEFUL; - } - } -#endif - } - else { - /* Kill 'em off */ - if (ap_killpg (pgrp, SIGHUP) < 0) { - log_unixerr ("killpg SIGHUP", NULL, NULL, server_conf); - } - reclaim_child_processes(); /* Not when just starting up */ - log_error ("SIGHUP received. Attempting to restart", server_conf); - } - ++generation; - - } while (restart_pending); - -} /* standalone_main */ - -extern char *optarg; -extern int optind; - -int -main(int argc, char *argv[]) -{ - int c; - -#ifdef AUX - (void)set42sig(); -#endif - -#ifdef SecureWare - if(set_auth_parameters(argc,argv) < 0) - perror("set_auth_parameters"); - if(getluid() < 0) - if(setluid(getuid()) < 0) - perror("setluid"); - if(setreuid(0, 0) < 0) - perror("setreuid"); -#endif - - init_alloc(); - pconf = permanent_pool; - ptrans = make_sub_pool(pconf); - - server_argv0 = argv[0]; - strncpy (server_root, HTTPD_ROOT, sizeof(server_root)-1); - server_root[sizeof(server_root)-1] = '\0'; - strncpy (server_confname, SERVER_CONFIG_FILE, sizeof(server_root)-1); - server_confname[sizeof(server_confname)-1] = '\0'; - - while((c = getopt(argc,argv,"Xd:f:vhl")) != -1) { - switch(c) { - case 'd': - strncpy (server_root, optarg, sizeof(server_root)-1); - server_root[sizeof(server_root)-1] = '\0'; - break; - case 'f': - strncpy (server_confname, optarg, sizeof(server_confname)-1); - server_confname[sizeof(server_confname)-1] = '\0'; - break; - case 'v': - printf("Server version %s.\n",SERVER_VERSION); - exit(0); - case 'h': - show_directives(); - exit(0); - case 'l': - show_modules(); - exit(0); - case 'X': - ++one_process; /* Weird debugging mode. */ - break; - case '?': - usage(argv[0]); - } - } - -#ifdef __EMX__ - printf("%s \n",SERVER_VERSION); - printf("OS/2 port by Garey Smiley <garey@slink.com> \n"); -#endif - - setup_prelinked_modules(); - - suexec_enabled = init_suexec(); - server_conf = read_config (pconf, ptrans, server_confname); - init_modules (pconf, server_conf); - - if(standalone) { - clear_pool (pconf); /* standalone_main rereads... */ - standalone_main(argc, argv); - } - else { - conn_rec *conn; - request_rec *r; - struct sockaddr sa_server, sa_client; - BUFF *cio; - - open_logs(server_conf, pconf); - set_group_privs(); - default_server_hostnames (server_conf); - -#ifdef MPE - /* Only try to switch if we're running as MANAGER.SYS */ - if (geteuid() == 1 && user_id > 1) { - GETPRIVMODE(); - if (setuid(user_id) == -1) { - GETUSERMODE(); -#else - /* Only try to switch if we're running as root */ - if(!geteuid() && setuid(user_id) == -1) { -#endif - log_unixerr("setuid", NULL, "unable to change uid", server_conf); - exit (1); - } -#ifdef MPE - GETUSERMODE(); - } -#endif - if (ap_setjmp (jmpbuffer)) { - exit (0); - } - - c = sizeof(sa_client); - if ((getpeername(fileno(stdin), &sa_client, &c)) < 0) - { -/* get peername will fail if the input isn't a socket */ - perror("getpeername"); - memset(&sa_client, '\0', sizeof(sa_client)); - } - - c = sizeof(sa_server); - if(getsockname(fileno(stdin), &sa_server, &c) < 0) { - perror("getsockname"); - fprintf(stderr, "Error getting local address\n"); - exit(1); - } - server_conf->port =ntohs(((struct sockaddr_in *)&sa_server)->sin_port); - cio = bcreate(ptrans, B_RDWR); -#ifdef MPE -/* HP MPE 5.5 inetd only passes the incoming socket as stdin (fd 0), whereas - HPUX inetd passes the incoming socket as stdin (fd 0) and stdout (fd 1). - Go figure. SR 5003355016 has been submitted to request that the existing - functionality be documented, and then to enhance the functionality to be - like HPUX. */ - - cio->fd = fileno(stdin); -#else - cio->fd = fileno(stdout); -#endif - cio->fd_in = fileno(stdin); - conn = new_connection (ptrans, server_conf, cio, - (struct sockaddr_in *)&sa_client, - (struct sockaddr_in *)&sa_server,-1); - r = read_request (conn); - if (r) process_request (r); /* else premature EOF (ignore) */ - - while (r && conn->keepalive && !conn->aborted) { - destroy_pool(r->pool); - r = read_request (conn); - if (r) process_request (r); - } - - bclose(cio); - } - exit (0); -} - -#ifdef __EMX__ -#ifdef HAVE_MMAP -/* The next two routines are used to access shared memory under OS/2. */ -/* This requires EMX v09c to be installed. */ - -caddr_t create_shared_heap (const char *name, size_t size) -{ - ULONG rc; - void *mem; - Heap_t h; - - rc = DosAllocSharedMem (&mem, name, size, - PAG_COMMIT | PAG_READ | PAG_WRITE); - if (rc != 0) - return NULL; - h = _ucreate (mem, size, !_BLOCK_CLEAN, _HEAP_REGULAR | _HEAP_SHARED, - NULL, NULL); - if (h == NULL) - DosFreeMem (mem); - return (caddr_t)h; -} - -caddr_t get_shared_heap (const char *Name) -{ - - PVOID BaseAddress; /* Pointer to the base address of - the shared memory object */ - ULONG AttributeFlags; /* Flags describing characteristics - of the shared memory object */ - APIRET rc; /* Return code */ - - /* Request read and write access to */ - /* the shared memory object */ - AttributeFlags = PAG_WRITE | PAG_READ; - - rc = DosGetNamedSharedMem(&BaseAddress, Name, AttributeFlags); - - if(rc != 0) { - printf("DosGetNamedSharedMem error: return code = %ld", rc); - return 0; - } - - return BaseAddress; -} -#endif -#endif - diff --git a/usr.sbin/httpd/src/http_main.h b/usr.sbin/httpd/src/http_main.h deleted file mode 100644 index 7d3c2f5a789..00000000000 --- a/usr.sbin/httpd/src/http_main.h +++ /dev/null @@ -1,99 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * Routines in http_main.c which other code --- in particular modules --- - * may want to call. Right now, that's limited to timeout handling. - * There are two functions which modules can call to trigger a timeout - * (with the per-virtual-server timeout duration); these are hard_timeout - * and soft_timeout. - * - * The difference between the two is what happens when the timeout - * expires (or earlier than that, if the client connection aborts) --- - * a soft_timeout just puts the connection to the client in an - * "aborted" state, which will cause http_protocol.c to stop trying to - * talk to the client, but otherwise allows the code to continue normally. - * hard_timeout(), by contrast, logs the request, and then aborts it - * completely --- longjmp()ing out to the accept() loop in http_main. - * Any resources tied into the request's resource pool will be cleaned up; - * everything that isn't will leak. - * - * soft_timeout() is recommended as a general rule, because it gives your - * code a chance to clean up. However, hard_timeout() may be the most - * convenient way of dealing with timeouts waiting for some external - * resource other than the client, if you can live with the restrictions. - * - * (When a hard timeout is in scope, critical sections can be guarded - * with block_alarms() and unblock_alarms() --- these are declared in - * alloc.c because they are most often used in conjunction with - * routines to allocate something or other, to make sure that the - * cleanup does get registered before any alarm is allowed to happen - * which might require it to be cleaned up; they * are, however, - * implemented in http_main.c). - * - * kill_timeout() will disarm either variety of timeout. - * - * reset_timeout() resets the timeout in progress. - */ - -void hard_timeout (char *, request_rec *); -void keepalive_timeout (char *, request_rec *); -void soft_timeout (char *, request_rec *); -void kill_timeout (request_rec *); -void reset_timeout (request_rec *); - -void sync_scoreboard_image (); -int update_child_status (int child_num, int status, request_rec *r); -int get_child_status (int child_num); -int count_busy_servers (); -int count_idle_servers (); - diff --git a/usr.sbin/httpd/src/http_protocol.c b/usr.sbin/httpd/src/http_protocol.c deleted file mode 100644 index f34097260c1..00000000000 --- a/usr.sbin/httpd/src/http_protocol.c +++ /dev/null @@ -1,2047 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_protocol.c --- routines which directly communicate with the client. - * - * Code originally by Rob McCool; much redone by Robert S. Thau - * and the Apache Group. - */ - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_log.h" /* For errors detected in basic auth - * common support code... - */ -#include "util_date.h" /* For parseHTTPdate and BAD_DATE */ -#include <stdarg.h> - -#define SET_BYTES_SENT(r) \ - do { if (r->sent_bodyct) \ - bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \ - } while (0) - - -static int parse_byterange (char *range, long clength, long *start, long *end) -{ - char *dash = strchr(range, '-'); - - if (!dash) - return 0; - - if ((dash == range)) { - /* In the form "-5" */ - *start = clength - atol(dash + 1); - *end = clength - 1; - } - else { - *dash = '\0'; - dash++; - *start = atol(range); - if (*dash) - *end = atol(dash); - else /* "5-" */ - *end = clength -1; - } - - if (*start > *end) - return 0; - - if (*end >= clength) - *end = clength - 1; - - return 1; -} - -static int internal_byterange(int, long*, request_rec*, char**, long*, long*); - -int set_byterange (request_rec *r) -{ - char *range, *if_range, *match; - char ts[MAX_STRING_LEN]; - long range_start, range_end; - - if (!r->clength || r->assbackwards) return 0; - - /* Check for Range request-header (HTTP/1.1) or Request-Range for - * backwards-compatibility with second-draft Luotonen/Franks - * byte-ranges (e.g. Netscape Navigator 2-3). - * - * We support this form, with Request-Range, and (farther down) we - * send multipart/x-byteranges instead of multipart/byteranges for - * Request-Range based requests to work around a bug in Netscape - * Navigator 2-3 and MSIE 3. - */ - - if (!(range = table_get(r->headers_in, "Range"))) - range = table_get(r->headers_in, "Request-Range"); - - if (!range || strncasecmp(range, "bytes=", 6)) { - table_set (r->headers_out, "Accept-Ranges", "bytes"); - return 0; - } - - /* Check the If-Range header for Etag or Date */ - - if ((if_range = table_get(r->headers_in, "If-Range"))) { - if (if_range[0] == '"') { - if (!(match = table_get(r->headers_out, "Etag")) || - (strcasecmp(if_range, match) != 0)) - return 0; - } - else if (!(match = table_get(r->headers_out, "Last-Modified")) || - (strcasecmp(if_range, match) != 0)) - return 0; - } - - if (!strchr(range, ',')) { - /* A single range */ - if (!parse_byterange(pstrdup(r->pool, range + 6), r->clength, - &range_start, &range_end)) - return 0; - - r->byterange = 1; - - ap_snprintf(ts, sizeof(ts), "bytes %ld-%ld/%ld", - range_start, range_end, r->clength); - table_set(r->headers_out, "Content-Range", ts); - ap_snprintf(ts, sizeof(ts), "%ld", range_end - range_start + 1); - table_set(r->headers_out, "Content-Length", ts); - } - else { - /* a multiple range */ - char boundary[33]; /* Long enough */ - char *r_range = pstrdup(r->pool, range + 6); - long tlength = 0; - - r->byterange = 2; - ap_snprintf(boundary, sizeof(boundary), "%lx%lx", - r->request_time, (long)getpid()); - r->boundary = pstrdup(r->pool, boundary); - while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL)); - ap_snprintf(ts, sizeof(ts), "%ld", tlength); - table_set(r->headers_out, "Content-Length", ts); - } - - r->status = PARTIAL_CONTENT; - r->range = range + 6; - - return 1; -} - -int each_byterange (request_rec *r, long *offset, long *length) -{ - return internal_byterange(1, NULL, r, &r->range, offset, length); -} - -/* If this function is called with realreq=1, it will spit out - * the correct headers for a byterange chunk, and set offset and - * length to the positions they should be. - * - * If it is called with realreq=0, it will add to tlength the length - * it *would* have used with realreq=1. - * - * Either case will return 1 if it should be called again, and 0 - * when done. - * - */ - -static int internal_byterange(int realreq, long *tlength, request_rec *r, - char **r_range, long *offset, long *length) -{ - long range_start, range_end; - char *range; - - if (!**r_range) { - if (r->byterange > 1) { - if (realreq) - rvputs(r, "\015\012--", r->boundary, "--\015\012", NULL); - else - *tlength += 4 + strlen(r->boundary) + 4; - } - return 0; - } - - range = getword_nc(r->pool, r_range, ','); - if (!parse_byterange(range, r->clength, &range_start, &range_end)) - /* Skip this one */ - return internal_byterange(realreq, tlength, r, r_range, offset, - length); - - if (r->byterange > 1) { - char *ct = r->content_type ? r->content_type : default_type(r); - char ts[MAX_STRING_LEN]; - - ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end, r->clength); - if (realreq) - rvputs(r, "\015\012--", r->boundary, "\015\012Content-type: ", - ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012", - NULL); - else - *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 + - strlen(ts) + 4; - } - - if (realreq) { - *offset = range_start; - *length = range_end - range_start + 1; - } - else { - *tlength += range_end - range_start + 1; - } - return 1; -} - -int set_content_length (request_rec *r, long clength) -{ - char ts[MAX_STRING_LEN]; - - r->clength = clength; - - ap_snprintf (ts, sizeof(ts), "%ld", clength); - table_set (r->headers_out, "Content-Length", ts); - - return 0; -} - -int set_keepalive(request_rec *r) -{ - int ka_sent = 0; - int wimpy = find_token(r->pool, - table_get(r->headers_out, "Connection"), "close"); - char *conn = table_get(r->headers_in, "Connection"); - - /* The following convoluted conditional determines whether or not - * the current connection should remain persistent after this response - * (a.k.a. HTTP Keep-Alive) and whether or not the output message - * body should use the HTTP/1.1 chunked transfer-coding. In English, - * - * IF we have not marked this connection as errored; - * and the response body has a defined length due to the status code - * being 304 or 204, the request method being HEAD, already - * having defined Content-Length or Transfer-Encoding: chunked, or - * the request version being HTTP/1.1 and thus capable of being set - * as chunked [we know the (r->chunked = 1) side-effect is ugly]; - * and the server configuration enables keep-alive; - * and the server configuration has a reasonable inter-request timeout; - * and there is no maximum # requests or the max hasn't been reached; - * and the response status does not require a close; - * and the response generator has not already indicated close; - * and the client did not request non-persistence (Connection: close); - * and we haven't been configured to ignore the buggy twit - * or they're a buggy twit coming through a HTTP/1.1 proxy - * and the client is requesting an HTTP/1.0-style keep-alive - * or the client claims to be HTTP/1.1 compliant (perhaps a proxy); - * THEN we can be persistent, which requires more headers be output. - * - * Note that the condition evaluation order is extremely important. - */ - if ((r->connection->keepalive != -1) && - ((r->status == HTTP_NOT_MODIFIED) || - (r->status == HTTP_NO_CONTENT) || - r->header_only || - table_get(r->headers_out, "Content-Length") || - find_last_token(r->pool, - table_get(r->headers_out, "Transfer-Encoding"), - "chunked") || - ((r->proto_num >= 1001) && (r->chunked = 1))) && - r->server->keep_alive && - (r->server->keep_alive_timeout > 0) && - ((r->server->keep_alive_max == 0) || - (r->server->keep_alive_max > r->connection->keepalives)) && - !status_drops_connection(r->status) && - !wimpy && - !find_token(r->pool, conn, "close") && - (!table_get(r->subprocess_env, "nokeepalive") || - table_get(r->headers_in, "Via")) && - ((ka_sent = find_token(r->pool, conn, "keep-alive")) || - (r->proto_num >= 1001)) - ) { - char header[256]; - int left = r->server->keep_alive_max - r->connection->keepalives; - - r->connection->keepalive = 1; - r->connection->keepalives++; - - /* If they sent a Keep-Alive token, send one back */ - if (ka_sent) { - if (r->server->keep_alive_max) - ap_snprintf(header, sizeof(header), "timeout=%d, max=%d", - r->server->keep_alive_timeout, left); - else - ap_snprintf(header, sizeof(header), "timeout=%d", - r->server->keep_alive_timeout); - table_set(r->headers_out, "Keep-Alive", header); - table_merge(r->headers_out, "Connection", "Keep-Alive"); - } - - return 1; - } - - /* Otherwise, we need to indicate that we will be closing this - * connection immediately after the current response. - * - * We only really need to send "close" to HTTP/1.1 clients, but we - * always send it anyway, because a broken proxy may identify itself - * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag - * to a HTTP/1.1 client. Better safe than sorry. - */ - if (!wimpy) - table_merge(r->headers_out, "Connection", "close"); - - r->connection->keepalive = 0; - - return 0; -} - -int set_last_modified(request_rec *r, time_t mtime) -{ - char *etag, weak_etag[MAX_STRING_LEN]; - char *if_match, *if_modified_since, *if_unmodified, *if_nonematch; - time_t now = time(NULL); - - if (now < 0) - now = r->request_time; - - table_set(r->headers_out, "Last-Modified", - gm_timestr_822(r->pool, (mtime > now) ? now : mtime)); - - /* Make an ETag header out of various pieces of information. We use - * the last-modified date and, if we have a real file, the - * length and inode number - note that this doesn't have to match - * the content-length (i.e. includes), it just has to be unique - * for the file. - * - * If the request was made within a second of the last-modified date, - * we send a weak tag instead of a strong one, since it could - * be modified again later in the second, and the validation - * would be incorrect. - */ - - if (r->finfo.st_mode != 0) - ap_snprintf(weak_etag, sizeof(weak_etag), "W/\"%lx-%lx-%lx\"", - (unsigned long)r->finfo.st_ino, - (unsigned long)r->finfo.st_size, (unsigned long)mtime); - else - ap_snprintf(weak_etag, sizeof(weak_etag), "W/\"%lx\"", - (unsigned long)mtime); - - etag = weak_etag + ((r->request_time - mtime > 1) ? 2 : 0); - table_set(r->headers_out, "ETag", etag); - - /* Check for conditional requests --- note that we only want to do - * this if we are successful so far and we are not processing a - * subrequest or an ErrorDocument. - * - * The order of the checks is important, since etag checks are supposed - * to be more accurate than checks relative to the modification time. - */ - - if (!is_HTTP_SUCCESS(r->status) || r->no_local_copy) - return OK; - - /* If an If-Match request-header field was given and - * if our ETag does not match any of the entity tags in that field - * and the field value is not "*" (meaning match anything), then - * respond with a status of 412 (Precondition Failed). - */ - - if ((if_match = table_get(r->headers_in, "If-Match")) != NULL) { - if ((if_match[0] != '*') && !find_token(r->pool, if_match, etag)) - return HTTP_PRECONDITION_FAILED; - } - - /* Else if a valid If-Unmodified-Since request-header field was given - * and the requested resource has been modified since the time - * specified in this field, then the server MUST - * respond with a status of 412 (Precondition Failed). - */ - - else if ((if_unmodified = table_get(r->headers_in, "If-Unmodified-Since")) - != NULL) { - time_t ius = parseHTTPdate(if_unmodified); - - if ((ius != BAD_DATE) && (mtime > ius)) - return HTTP_PRECONDITION_FAILED; - } - - /* If an If-None-Match request-header field was given and - * if our ETag matches any of the entity tags in that field or - * if the field value is "*" (meaning match anything), then - * if the request method was GET or HEAD, the server SHOULD - * respond with a 304 (Not Modified) response. - * For all other request methods, the server MUST - * respond with a status of 412 (Precondition Failed). - */ - - if ((if_nonematch = table_get(r->headers_in, "If-None-Match")) != NULL) { - if ((if_nonematch[0] == '*') || find_token(r->pool,if_nonematch,etag)) - return (r->method_number == M_GET) ? HTTP_NOT_MODIFIED - : HTTP_PRECONDITION_FAILED; - } - - /* Else if a valid If-Modified-Since request-header field was given - * and it is a GET or HEAD request - * and the requested resource has not been modified since the time - * specified in this field, then the server MUST - * respond with a status of 304 (Not Modified). - * A date later than the server's current request time is invalid. - */ - - else if ((r->method_number == M_GET) && ((if_modified_since = - table_get(r->headers_in, "If-Modified-Since")) != NULL)) { - time_t ims = parseHTTPdate(if_modified_since); - - if ((ims >= mtime) && (ims <= r->request_time)) - return HTTP_NOT_MODIFIED; - } - - return OK; -} - -/* Get a line of protocol input, including any continuation lines - * caused by MIME folding (or broken clients) if fold != 0, and place it - * in the buffer s, of size n bytes, without the ending newline. - * - * Returns -1 on error, or the length of s. - * - * Note: Because bgets uses 1 char for newline and 1 char for NUL, - * the most we can get is (n - 2) actual characters if it - * was ended by a newline, or (n - 1) characters if the line - * length exceeded (n - 1). So, if the result == (n - 1), - * then the actual input line exceeded the buffer length, - * and it would be a good idea for the caller to puke 400 or 414. - */ -static int getline(char *s, int n, BUFF *in, int fold) -{ - char *pos, next; - int retval; - int total = 0; - - pos = s; - - do { - retval = bgets(pos, n, in); /* retval == -1 if error, 0 if EOF */ - - if (retval <= 0) - return ((retval < 0) && (total == 0)) ? -1 : total; - - /* retval is the number of characters read, not including NUL */ - - n -= retval; /* Keep track of how much of s is full */ - pos += (retval-1); /* and where s ends */ - total += retval; /* and how long s has become */ - - if (*pos == '\n') { /* Did we get a full line of input? */ - *pos = '\0'; - --total; ++n; - } - else return total; /* if not, input line exceeded buffer size */ - - /* Continue appending if line folding is desired and - * the last line was not empty and we have room in the buffer and - * the next line begins with a continuation character. - */ - } while (fold && (retval != 1) && (n > 1) && - (blookc(&next, in) == 1) && - ((next == ' ') || (next == '\t'))); - - return total; -} - -void parse_uri (request_rec *r, const char *uri) -{ - const char *s; - -#ifdef __EMX__ - /* Variable for OS/2 fix below. */ - int loop; -#endif - -/* A proxy request contains a ':' early on, but not as first character */ - for (s=uri; s != '\0'; s++) - if (!isalnum(*s) && *s != '+' && *s != '-' && *s != '.') break; - - if (*s == ':' && s != uri) - { - r->proxyreq = 1; - r->uri = pstrdup(r->pool, uri); - r->args = NULL; - } - else if (r->method && !strcmp(r->method, "TRACE")) { - r->proxyreq = 0; - r->uri = pstrdup(r->pool, uri); - r->args = NULL; - } - else { - r->proxyreq = 0; - r->uri = getword (r->pool, &uri, '?'); - -#ifdef __EMX__ - /* Handle path translations for OS/2 and plug security hole. */ - /* This will prevent "http://www.wherever.com/..\..\/" from - returning a directory for the root drive. */ - for (loop = 0; loop <= strlen(r->uri); ++loop) { - if (r->uri[loop] == '\\') - r->uri[loop] = '/'; - }; - - /* Fix OS/2 HPFS filename case problem. */ - r->uri = strlwr(r->uri); -#endif - - if (*uri) r->args= pstrdup(r->pool, uri); - else r->args = NULL; - } -} - -const char *check_fulluri (request_rec *r, const char *uri) -{ - char *name, *host; - int i; - unsigned port; - server_addr_rec * sar; - - /* This routine parses full URLs, if they match the server */ - if (strncasecmp(uri, "http://", 7)) return uri; - name = pstrdup(r->pool, uri + 7); - - /* Find the hostname, assuming a valid request */ - i = ind(name, '/'); - name[i] = '\0'; - - /* Find the port */ - host = getword_nc(r->pool, &name, ':'); - if (*name) port = atoi(name); - else port = 80; - - /* Make sure ports patch */ - if (port != r->server->port) { - for (sar = r->server->addrs; sar; sar = sar->next) { - if( (sar->host_port == 0) || (port == sar->host_port) ) - break; - } - if (!sar) return uri; - } - - /* Save it for later use */ - r->hostname = pstrdup(r->pool, host); - r->hostlen = 7 + i; - - /* The easy cases first */ - if (!strcasecmp(host, r->server->server_hostname)) { - return (uri + r->hostlen); - } - else if (!strcmp(host, inet_ntoa(r->connection->local_addr.sin_addr))) { - return (uri + r->hostlen); - } - - /* Now things get a bit trickier - check the IP address(es) of the host */ - /* they gave, see if it matches ours. */ - else { - struct hostent *hp; - int n; - - if ((hp = gethostbyname(host))) { - for (n = 0; hp->h_addr_list[n] != NULL; n++) { - if (r->connection->local_addr.sin_addr.s_addr == - (((struct in_addr *)(hp->h_addr_list[n]))->s_addr)) { - return (uri + r->hostlen); - } - } - } - } - - return uri; -} - -int read_request_line (request_rec *r) -{ - char l[HUGE_STRING_LEN]; - const char *ll = l, *uri; - conn_rec *conn = r->connection; - int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol*/ - int len; - - /* Read past empty lines until we get a real request line, - * a read error, the connection closes (EOF), or we timeout. - * - * We skip empty lines because browsers have to tack a CRLF on to the end - * of POSTs to support old CERN webservers. But note that we may not - * have flushed any previous response completely to the client yet. - * We delay the flush as long as possible so that we can improve - * performance for clients that are pipelining requests. If a request - * is pipelined then we won't block during the (implicit) read() below. - * If the requests aren't pipelined, then the client is still waiting - * for the final buffer flush from us, and we will block in the implicit - * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will - * have to block during a read. - */ - bsetflag( conn->client, B_SAFEREAD, 1 ); - while ((len = getline(l, HUGE_STRING_LEN, conn->client, 0)) <= 0) { - if ((len < 0) || bgetflag(conn->client, B_EOF)) { - bsetflag( conn->client, B_SAFEREAD, 0 ); - return 0; - } - } - /* we've probably got something to do, ignore graceful restart requests */ - signal (SIGUSR1, SIG_IGN); - bsetflag( conn->client, B_SAFEREAD, 0 ); - if (len == (HUGE_STRING_LEN - 1)) { - log_printf(r->server, "request failed for %s, reason: URI too long", - get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME)); - r->status = HTTP_REQUEST_URI_TOO_LARGE; - return 0; - } - - r->request_time = time(NULL); - r->the_request = pstrdup (r->pool, l); - r->method = getword_white(r->pool, &ll); - uri = getword_white(r->pool, &ll); - uri = check_fulluri(r, uri); - parse_uri (r, uri); - - r->assbackwards = (ll[0] == '\0'); - r->protocol = pstrdup (r->pool, ll[0] ? ll : "HTTP/0.9"); - sscanf(r->protocol, "HTTP/%d.%d", &major, &minor); - r->proto_num = 1000*major + minor; - - return 1; -} - -void get_mime_headers (request_rec *r) -{ - conn_rec *c = r->connection; - int len; - char *value; - char field[MAX_STRING_LEN]; - - /* Read header lines until we get the empty separator line, - * a read error, the connection closes (EOF), or we timeout. - * Should we also check for overflow (len == MAX_STRING_LEN-1)? - */ - while ((len = getline(field, MAX_STRING_LEN, c->client, 1)) > 0) { - - if (!(value = strchr(field,':'))) /* Find the colon separator */ - continue; /* or should puke 400 here */ - - *value = '\0'; - ++value; - while (isspace(*value)) ++value; /* Skip to start of value */ - - table_merge(r->headers_in, field, value); - } -} - -#define ADDR_MATCHES(addr1,addr2) \ - (addr1.s_addr == addr2.s_addr) || (addr1.s_addr == htonl(INADDR_ANY)) \ - || (addr1.s_addr == DEFAULT_VHOST_ADDR) - -static void check_hostalias (request_rec *r) -{ - const char *hostname=r->hostname; - char *host = getword(r->pool, &hostname, ':'); /* Get rid of port */ - unsigned port = (*hostname) ? atoi(hostname) : 80; - server_rec *s = r->server; - server_addr_rec * sar; - int l; - -/* make sure the client can't spoof the port; - * have to check all possiblities to see if the server - * should be listening. */ - if (port != r->server->port) { - for (sar = s->addrs; sar; sar = sar->next) { - if ( (port == sar->host_port) || (sar->host_port == 0) ) - break; - } - if (!sar) return; - } - - l = strlen(host)-1; - if ((host[l]) == '.') { - host[l] = '\0'; - } - - r->hostname = host; - - for (s = r->server->next; s; s = s->next) { - const char *names; - server_addr_rec *sar; - - if (s->addrs == NULL) { - /* this server has been disabled because of DNS screwups during - configuration */ - continue; - } -/* ok, now there are several possibilities, and we're matching the - * hostname, the port, and r->connection->local_addr. The last is - * required so as to only respond on an address to which this vhost - * should actually be listening. - * - * Either we can match s->server_name and s->port while matching - * against the ip address in a record in the s->addrs list *or* we - * can match s->server_name and a complete record in the s->addrs - * list *or* we can match the virtual host name and the address and - * the port of a record in the s->addrs list. - */ - if (!strcasecmp(host,s->server_hostname)) { /* ServerName matches hostname */ - if (port == s->port) { /* possibly configured by Port */ - for (sar = s->addrs; sar; sar = sar->next) { - if (ADDR_MATCHES(sar->host_addr,r->connection->local_addr.sin_addr)) - break; /* SN matches, Port matches, and one IP addr matches */ - } - } else { /* check to see if an addr matches */ - for (sar = s->addrs; sar; sar = sar->next) { - if (((port == sar->host_port) || (sar->host_port == 0)) - && (ADDR_MATCHES(sar->host_addr, - r->connection->local_addr.sin_addr))) - break; /* SN matches, and a addr matches IP & port */ - } - } - if (sar) { /* we got a match */ - r->server = r->connection->server = s; - if (r->hostlen && !strncasecmp(r->uri, "http://", 7)) { - r->uri += r->hostlen; - parse_uri(r, r->uri); - /* we still might want to do something below (ie. set r->proxyreq) */ - } - } - } /* ServerName doesn't match */ - - /* now s->addrs list, include the names, from the VirtualHost directive */ - for (sar = s->addrs; sar; sar = sar->next) { - if (((sar->host_port==0) || (port==sar->host_port)) - && (ADDR_MATCHES(sar->host_addr,r->connection->local_addr.sin_addr)) - && !strcasecmp(host,sar->virthost)) { - /* ok, an element in the addrs list matched all three items */ - r->server = r->connection->server = s; - if (r->hostlen && !strncasecmp(r->uri, "http://", 7)) { - r->uri += r->hostlen; - r->proxyreq = 0; - } - } - } - - /* search all the aliases from ServerAlias directive - * ServerAlias acts like a wildcard, so as to help deal with the - * transition when the DNS for a given host changes. - */ - names = s->names; - if (names) { - while (*names) { - char *name = getword_conf (r->pool, &names); - - if ((is_matchexp(name) && !strcasecmp_match(host, name)) || - (!strcasecmp(host, name))) { - r->server = r->connection->server = s; - if (r->hostlen && !strncasecmp(r->uri, "http://", 7)) { - r->uri += r->hostlen; - r->proxyreq = 0; - } - } - } - } - } -} - -void check_serverpath (request_rec *r) -{ - server_rec *s; - server_addr_rec * sar = NULL; - int port = r->connection->local_addr.sin_port; - - /* This is in conjunction with the ServerPath code in - * http_core, so we get the right host attached to a non- - * Host-sending request. - */ - - for (s = r->server->next; s; s = s->next) { - /* we should check to make sure that this server should be listening - * at all. - * - * this code is duplicated in check_hostalias, but only one of these - * two functions runs for a given request. - */ - if (!s->addrs) continue; - - if( (port == s->port) ) { - for(sar = s->addrs; sar; sar = sar->next) { - if(ADDR_MATCHES(sar->host_addr, r->connection->local_addr.sin_addr)) - break; - } - } - else { - for(sar = s->addrs; sar; sar = sar->next) { - if( ( (port == sar->host_port) || (sar->host_port == 0) ) - && ( ADDR_MATCHES(sar->host_addr, - r->connection->local_addr.sin_addr) ) ) - break; - } - } - - if (!sar) continue; /* no match */ - - if (s->path && !strncmp(r->uri, s->path, s->pathlen) - && (s->path[s->pathlen - 1] == '/' - || r->uri[s->pathlen] == '/' - || r->uri[s->pathlen] == '\0')) - r->server = r->connection->server = s; - } -} - -request_rec *read_request (conn_rec *conn) -{ - request_rec *r = (request_rec *)pcalloc (conn->pool, sizeof(request_rec)); - - r->connection = conn; - conn->server = conn->base_server; - r->server = conn->server; - r->pool = make_sub_pool(conn->pool); - - conn->keptalive = conn->keepalive; - conn->keepalive = 0; - - conn->user = NULL; - conn->auth_type = NULL; - - r->headers_in = make_table (r->pool, 50); - r->subprocess_env = make_table (r->pool, 50); - r->headers_out = make_table (r->pool, 5); - r->err_headers_out = make_table (r->pool, 5); - r->notes = make_table (r->pool, 5); - - r->request_config = create_request_config (r->pool); - r->per_dir_config = r->server->lookup_defaults; /* For now. */ - - r->sent_bodyct = 0; /* bytect isn't for body */ - - r->read_length = 0; - r->read_body = REQUEST_NO_BODY; - - r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */ - - /* Get the request... */ - - keepalive_timeout("read request line", r); - if (!read_request_line (r)) { - kill_timeout(r); - return NULL; - } - if (!r->assbackwards) { - hard_timeout("read request headers", r); - get_mime_headers (r); - } - kill_timeout(r); - - r->status = HTTP_OK; /* Until further notice. */ - - /* handle Host header here, to get virtual server */ - - if (r->hostname || (r->hostname = table_get(r->headers_in, "Host"))) - check_hostalias(r); - else - check_serverpath(r); - - /* we may have switched to another server */ - r->per_dir_config = r->server->lookup_defaults; - - conn->keptalive = 0; /* We now have a request to play with */ - - if(!strcmp(r->method, "HEAD")) { - r->header_only=1; - r->method_number = M_GET; - } - else if(!strcmp(r->method, "GET")) - r->method_number = M_GET; - else if(!strcmp(r->method,"POST")) - r->method_number = M_POST; - else if(!strcmp(r->method,"PUT")) - r->method_number = M_PUT; - else if(!strcmp(r->method,"DELETE")) - r->method_number = M_DELETE; - else if(!strcmp(r->method,"CONNECT")) - r->method_number = M_CONNECT; - else if(!strcmp(r->method,"OPTIONS")) - r->method_number = M_OPTIONS; - else if(!strcmp(r->method,"TRACE")) - r->method_number = M_TRACE; - else - r->method_number = M_INVALID; /* Will eventually croak. */ - - return r; -} - -/* - * A couple of other functions which initialize some of the fields of - * a request structure, as appropriate for adjuncts of one kind or another - * to a request in progress. Best here, rather than elsewhere, since - * *someone* has to set the protocol-specific fields... - */ - -void set_sub_req_protocol (request_rec *rnew, const request_rec *r) -{ - rnew->the_request = r->the_request; /* Keep original request-line */ - - rnew->assbackwards = 1; /* Don't send headers from this. */ - rnew->no_local_copy = 1; /* Don't try to send USE_LOCAL_COPY for a - * fragment. - */ - rnew->method = "GET"; rnew->method_number = M_GET; - rnew->protocol = "INCLUDED"; - - rnew->status = HTTP_OK; - - rnew->headers_in = r->headers_in; - rnew->subprocess_env = copy_table (rnew->pool, r->subprocess_env); - rnew->headers_out = make_table (rnew->pool, 5); - rnew->err_headers_out = make_table (rnew->pool, 5); - rnew->notes = make_table (rnew->pool, 5); - - rnew->read_length = r->read_length; - rnew->read_body = REQUEST_NO_BODY; - - rnew->main = (request_rec *)r; -} - -void finalize_sub_req_protocol (request_rec *sub) -{ - SET_BYTES_SENT (sub->main); -} - -/* Support for the Basic authentication protocol, and a bit for Digest. - */ - -void note_auth_failure(request_rec *r) -{ - if (!strcasecmp(auth_type(r), "Basic")) - note_basic_auth_failure(r); - else if(!strcasecmp(auth_type(r), "Digest")) - note_digest_auth_failure(r); -} - -void note_basic_auth_failure(request_rec *r) -{ - if (strcasecmp(auth_type(r), "Basic")) - note_auth_failure(r); - else - table_set (r->err_headers_out, "WWW-Authenticate", - pstrcat(r->pool, "Basic realm=\"", auth_name(r), "\"", NULL)); -} - -void note_digest_auth_failure(request_rec *r) -{ - char nonce[256]; - - ap_snprintf(nonce, sizeof(nonce), "%lu", r->request_time); - table_set (r->err_headers_out, "WWW-Authenticate", - pstrcat(r->pool, "Digest realm=\"", auth_name(r), - "\", nonce=\"", nonce, "\"", NULL)); -} - -int get_basic_auth_pw (request_rec *r, char **pw) -{ - const char *auth_line = table_get (r->headers_in, "Authorization"); - char *t; - - if(!(t = auth_type(r)) || strcasecmp(t, "Basic")) - return DECLINED; - - if (!auth_name (r)) { - log_reason ("need AuthName", r->uri, r); - return SERVER_ERROR; - } - - if(!auth_line) { - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - - if (strcasecmp(getword (r->pool, &auth_line, ' '), "Basic")) { - /* Client tried to authenticate using wrong auth scheme */ - log_reason ("client used wrong authentication scheme", r->uri, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - - t = uudecode (r->pool, auth_line); - r->connection->user = getword_nulls_nc (r->connection->pool, &t, ':'); - r->connection->auth_type = "Basic"; - - *pw = t; - - return OK; -} - -/* New Apache routine to map status codes into array indicies - * e.g. 100 -> 0, 101 -> 1, 200 -> 2 ... - * The number of status lines must equal the value of RESPONSE_CODES (httpd.h) - * and must be listed in order. - */ - -static char *status_lines[] = { - "100 Continue", - "101 Switching Protocols", -#define LEVEL_200 2 - "200 OK", - "201 Created", - "202 Accepted", - "203 Non-Authoritative Information", - "204 No Content", - "205 Reset Content", - "206 Partial Content", -#define LEVEL_300 9 - "300 Multiple Choices", - "301 Moved Permanently", - "302 Moved Temporarily", - "303 See Other", - "304 Not Modified", - "305 Use Proxy", -#define LEVEL_400 15 - "400 Bad Request", - "401 Authorization Required", - "402 Payment Required", - "403 Forbidden", - "404 File Not Found", - "405 Method Not Allowed", - "406 Not Acceptable", - "407 Proxy Authentication Required", - "408 Request Time-out", - "409 Conflict", - "410 Gone", - "411 Length Required", - "412 Precondition Failed", - "413 Request Entity Too Large", - "414 Request-URI Too Large", - "415 Unsupported Media Type", -#define LEVEL_500 31 - "500 Internal Server Error", - "501 Method Not Implemented", - "502 Bad Gateway", - "503 Service Temporarily Unavailable", - "504 Gateway Time-out", - "505 HTTP Version Not Supported", - "506 Variant Also Varies" -}; - -/* The index is found by its offset from the x00 code of each level. - * Although this is fast, it will need to be replaced if some nutcase - * decides to define a high-numbered code before the lower numbers. - * If that sad event occurs, replace the code below with a linear search - * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1]; - */ - -int index_of_response(int status) -{ - static int shortcut[6] = { 0, LEVEL_200, LEVEL_300, LEVEL_400, - LEVEL_500, RESPONSE_CODES }; - int i, pos; - - if (status < 100) /* Below 100 is illegal for HTTP status */ - return LEVEL_500; - - for (i = 0; i < 5; i++) { - status -= 100; - if (status < 100) { - pos = (status + shortcut[i]); - if (pos < shortcut[i+1]) - return pos; - else - return LEVEL_500; /* status unknown (falls in gap) */ - } - } - return LEVEL_500; /* 600 or above is also illegal */ -} - -/* Send a single HTTP header field to the client. Note that this function - * is used in calls to table_do(), so their interfaces are co-dependent. - * In other words, don't change this one without checking table_do in alloc.c. - * It returns true unless there was a write error of some kind. - */ -int send_header_field (request_rec *r, const char *fieldname, - const char *fieldval) -{ - return (0 < bvputs(r->connection->client, - fieldname, ": ", fieldval, "\015\012", NULL)); -} - -void basic_http_header (request_rec *r) -{ - char *protocol; - - if (r->assbackwards) return; - - if (!r->status_line) - r->status_line = status_lines[index_of_response(r->status)]; - - /* mod_proxy is only HTTP/1.0, so avoid sending HTTP/1.1 error response; - * kluge around broken browsers when indicated by force-response-1.0 - */ - if (r->proxyreq - || (r->proto_num == 1000 - && table_get(r->subprocess_env,"force-response-1.0"))) { - - protocol = "HTTP/1.0"; - r->connection->keepalive = -1; - } - else - protocol = SERVER_PROTOCOL; - - /* Output the HTTP/1.x Status-Line and the Date and Server fields */ - - bvputs(r->connection->client, - protocol, " ", r->status_line, "\015\012", NULL); - - send_header_field(r, "Date", gm_timestr_822(r->pool, r->request_time)); - send_header_field(r, "Server", SERVER_VERSION); - - table_unset(r->headers_out, "Date"); /* Avoid bogosity */ - table_unset(r->headers_out, "Server"); -} - -/* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2 - * have a header parsing bug. If the terminating \r\n occur starting - * at the 256th or 257th byte of output then it will not properly parse - * the headers. Curiously it doesn't exhibit this problem at 512, 513. - * We are guessing that this is because their initial read of a new request - * uses a 256 byte buffer, and subsequent reads use a larger buffer. - * So the problem might exist at different offsets as well. - * - * This should also work on keepalive connections assuming they use the - * same small buffer for the first read of each new request. - * - * At any rate, we check the bytes written so far and, if we are about to - * tickle the bug, we instead insert a bogus padding header. Since the bug - * manifests as a broken image in Navigator, users blame the server. :( - * It is more expensive to check the User-Agent than it is to just add the - * bytes, so we haven't used the BrowserMatch feature here. - */ -static void terminate_header (BUFF *client) -{ - long int bs; - - bgetopt(client, BO_BYTECT, &bs); - if (bs >= 255 && bs <= 257) - bputs("X-Pad: avoid browser bug\015\012", client); - - bputs("\015\012", client); /* Send the terminating empty line */ -} - -/* Build the Allow field-value from the request handler method mask. - * Note that we always allow TRACE, since it is handled below. - */ -static char *make_allow(request_rec *r) -{ - return 2 + pstrcat(r->pool, - (r->allowed & (1 << M_GET)) ? ", GET, HEAD" : "", - (r->allowed & (1 << M_POST)) ? ", POST" : "", - (r->allowed & (1 << M_PUT)) ? ", PUT" : "", - (r->allowed & (1 << M_DELETE)) ? ", DELETE" : "", - (r->allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "", - ", TRACE", - NULL); -} - -int send_http_trace (request_rec *r) -{ - int rv; - - /* Get the original request */ - while (r->prev) r = r->prev; - - if ((rv = setup_client_block(r, REQUEST_NO_BODY))) - return rv; - - hard_timeout("send TRACE", r); - - r->content_type = "message/http"; - send_http_header(r); - - /* Now we recreate the request, and echo it back */ - - rvputs( r, r->the_request, "\015\012", NULL ); - - table_do((int (*)(void *, const char *, const char *))send_header_field, - (void *)r, r->headers_in, NULL); - bputs("\015\012", r->connection->client); - - kill_timeout(r); - return OK; -} - -int send_http_options(request_rec *r) -{ - const long int zero = 0L; - - if (r->assbackwards) return DECLINED; - - hard_timeout("send OPTIONS", r); - - basic_http_header(r); - - table_set(r->headers_out, "Content-Length", "0"); - table_set(r->headers_out, "Allow", make_allow(r)); - set_keepalive(r); - - table_do((int (*)(void *, const char *, const char *))send_header_field, - (void *)r, r->headers_out, NULL); - - terminate_header(r->connection->client); - - kill_timeout(r); - bsetopt(r->connection->client, BO_BYTECT, &zero); - - return OK; -} - -/* - * Here we try to be compatible with clients that want multipart/x-byteranges - * instead of multipart/byteranges (also see above), as per HTTP/1.1. We - * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication - * that the browser supports an older protocol. We also check User-Agent - * for Microsoft Internet Explorer 3, which needs this as well. - */ - -static int use_range_x(request_rec *r) { - char *ua; - return (table_get(r->headers_in, "Request-Range") || - ((ua = table_get(r->headers_in, "User-Agent")) - && strstr(ua, "MSIE 3"))); -} - -void send_http_header(request_rec *r) -{ - int i; - const long int zero = 0L; - - if (r->assbackwards) { - if(!r->main) - bsetopt(r->connection->client, BO_BYTECT, &zero); - r->sent_bodyct = 1; - return; - } - - /* Now that we are ready to send a response, we need to combine the two - * header field tables into a single table. If we don't do this, our - * later attempts to set or unset a given fieldname might be bypassed. - */ - if (!is_empty_table(r->err_headers_out)) - r->headers_out = overlay_tables(r->pool, r->err_headers_out, - r->headers_out); - - hard_timeout("send headers", r); - - basic_http_header(r); - - set_keepalive(r); - - if (r->chunked) { - table_merge(r->headers_out, "Transfer-Encoding", "chunked"); - table_unset(r->headers_out, "Content-Length"); - } - - if (r->byterange > 1) - table_set(r->headers_out, "Content-Type", - pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", - "byteranges; boundary=", r->boundary, NULL)); - else if (r->content_type) - table_set(r->headers_out, "Content-Type", r->content_type); - else - table_set(r->headers_out, "Content-Type", default_type(r)); - - if (r->content_encoding) - table_set(r->headers_out, "Content-Encoding", r->content_encoding); - - if (r->content_languages && r->content_languages->nelts) { - for (i = 0; i < r->content_languages->nelts; ++i) { - table_merge(r->headers_out, "Content-Language", - ((char**)(r->content_languages->elts))[i]); - } - } - else if (r->content_language) - table_set(r->headers_out, "Content-Language", r->content_language); - - /* Control cachability for non-cachable responses if not already set - * by some other part of the server configuration. - */ - if (r->no_cache && !table_get(r->headers_out, "Expires")) - table_add(r->headers_out, "Expires", - gm_timestr_822(r->pool, r->request_time)); - - /* Send the entire table of header fields, terminated by an empty line. */ - - table_do((int (*)(void *, const char *, const char *))send_header_field, - (void *)r, r->headers_out, NULL); - - terminate_header(r->connection->client); - - kill_timeout(r); - - bsetopt(r->connection->client, BO_BYTECT, &zero); - r->sent_bodyct = 1; /* Whatever follows is real body stuff... */ - - /* Set buffer flags for the body */ - if (r->chunked) bsetflag(r->connection->client, B_CHUNK, 1); -} - -void finalize_request_protocol (request_rec *r) -{ - /* Turn off chunked encoding */ - - if (r->chunked && !r->connection->aborted) { - soft_timeout("send ending chunk", r); - bsetflag(r->connection->client, B_CHUNK, 0); - bputs("0\015\012", r->connection->client); - /* If we had footer "headers", we'd send them now */ - bputs("\015\012", r->connection->client); - kill_timeout(r); - } -} - -/* Here we deal with getting the request message body from the client. - * Whether or not the request contains a body is signaled by the presence - * of a non-zero Content-Length or by a Transfer-Encoding: chunked. - * - * Note that this is more complicated than it was in Apache 1.1 and prior - * versions, because chunked support means that the module does less. - * - * The proper procedure is this: - * - * 1. Call setup_client_block() near the beginning of the request - * handler. This will set up all the necessary properties, and will - * return either OK, or an error code. If the latter, the module should - * return that error code. The second parameter selects the policy to - * apply if the request message indicates a body, and how a chunked - * transfer-coding should be interpreted. Choose one of - * - * REQUEST_NO_BODY Send 413 error if message has any body - * REQUEST_CHUNKED_ERROR Send 411 error if body without Content-Length - * REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me. - * REQUEST_CHUNKED_PASS Pass the chunks to me without removal. - * - * In order to use the last two options, the caller MUST provide a buffer - * large enough to hold a chunk-size line, including any extensions. - * - * 2. When you are ready to read a body (if any), call should_client_block(). - * This will tell the module whether or not to read input. If it is 0, - * the module should assume that there is no message body to read. - * This step also sends a 100 Continue response to HTTP/1.1 clients, - * so should not be called until the module is *definitely* ready to - * read content. (otherwise, the point of the 100 response is defeated). - * Never call this function more than once. - * - * 3. Finally, call get_client_block in a loop. Pass it a buffer and its size. - * It will put data into the buffer (not necessarily a full buffer), and - * return the length of the input block. When it is done reading, it will - * return 0 if EOF, or -1 if there was an error. - * If an error occurs on input, we force an end to keepalive. - */ - -int setup_client_block (request_rec *r, int read_policy) -{ - char *tenc = table_get(r->headers_in, "Transfer-Encoding"); - char *lenp = table_get(r->headers_in, "Content-Length"); - - r->read_body = read_policy; - r->read_chunked = 0; - r->remaining = 0; - - if (tenc) { - if (strcasecmp(tenc, "chunked")) { - log_printf(r->server, "Unknown Transfer-Encoding %s", tenc); - return HTTP_BAD_REQUEST; - } - if (r->read_body == REQUEST_CHUNKED_ERROR) { - log_reason("chunked Transfer-Encoding forbidden", r->uri, r); - return (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED; - } - - r->read_chunked = 1; - } - else if (lenp) { - char *pos = lenp; - - while (isdigit(*pos) || isspace(*pos)) ++pos; - if (*pos != '\0') { - log_printf(r->server, "Invalid Content-Length %s", lenp); - return HTTP_BAD_REQUEST; - } - - r->remaining = atol(lenp); - } - - if ((r->read_body == REQUEST_NO_BODY) && - (r->read_chunked || (r->remaining > 0))) { - log_printf(r->server, "%s with body is not allowed for %s", - r->method, r->uri); - return HTTP_REQUEST_ENTITY_TOO_LARGE; - } - - return OK; -} - -int should_client_block (request_rec *r) -{ - /* First check if we have already read the request body */ - - if (r->read_length || (!r->read_chunked && (r->remaining <= 0))) - return 0; - - if (!r->read_chunked && (r->remaining <= 0)) - return 0; - - if (r->proto_num >= 1001) { /* sending 100 Continue interim response */ - bvputs(r->connection->client, - SERVER_PROTOCOL, " ", status_lines[0], "\015\012\015\012", NULL); - bflush(r->connection->client); - } - - return 1; -} - -static long get_chunk_size (char *b) -{ - long chunksize = 0; - - while (isxdigit(*b)) { - int xvalue = 0; - - if (*b >= '0' && *b <= '9') xvalue = *b - '0'; - else if (*b >= 'A' && *b <= 'F') xvalue = *b - 'A' + 0xa; - else if (*b >= 'a' && *b <= 'f') xvalue = *b - 'a' + 0xa; - - chunksize = (chunksize << 4) | xvalue; - ++b; - } - - return chunksize; -} - -/* get_client_block is called in a loop to get the request message body. - * This is quite simple if the client includes a content-length - * (the normal case), but gets messy if the body is chunked. Note that - * r->remaining is used to maintain state across calls and that - * r->read_length is the total number of bytes given to the caller - * across all invocations. It is messy because we have to be careful not - * to read past the data provided by the client, since these reads block. - * Returns 0 on End-of-body, -1 on error or premature chunk end. - * - * Reading the chunked encoding requires a buffer size large enough to - * hold a chunk-size line, including any extensions. For now, we'll leave - * that to the caller, at least until we can come up with a better solution. - */ -long get_client_block (request_rec *r, char *buffer, int bufsiz) -{ - int c; - long len_read, len_to_read; - long chunk_start = 0; - - if (!r->read_chunked) { /* Content-length read */ - len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining; - len_read = bread(r->connection->client, buffer, len_to_read); - if (len_read <= 0) { - if (len_read < 0) r->connection->keepalive = -1; - return len_read; - } - r->read_length += len_read; - r->remaining -= len_read; - return len_read; - } - - /* Handle chunked reading - * Note: we are careful to shorten the input bufsiz so that there - * will always be enough space for us to add a CRLF (if necessary). - */ - if (r->read_body == REQUEST_CHUNKED_PASS) - bufsiz -= 2; - if (bufsiz <= 0) - return -1; /* Cannot read chunked with a small buffer */ - - if (r->remaining == 0) { /* Start of new chunk */ - - chunk_start = getline(buffer, bufsiz, r->connection->client, 0); - if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1)) - || !isxdigit(*buffer)) { - r->connection->keepalive = -1; - return -1; - } - - len_to_read = get_chunk_size(buffer); - - if (len_to_read == 0) { /* Last chunk indicated, get footers */ - if (r->read_body == REQUEST_CHUNKED_DECHUNK) { - get_mime_headers(r); - ap_snprintf(buffer, bufsiz, "%ld", r->read_length); - table_unset(r->headers_in, "Transfer-Encoding"); - table_set(r->headers_in, "Content-Length", buffer); - return 0; - } - r->remaining = -1; /* Indicate footers in-progress */ - } - else { - r->remaining = len_to_read; - } - if (r->read_body == REQUEST_CHUNKED_PASS) { - buffer[chunk_start++] = CR; /* Restore chunk-size line end */ - buffer[chunk_start++] = LF; - buffer += chunk_start; /* and pass line on to caller */ - bufsiz -= chunk_start; - } else { - /* REQUEST_CHUNKED_DECHUNK -- do not include the length of - * the header in the return value */ - chunk_start = 0; - } - } - /* When REQUEST_CHUNKED_PASS, we are */ - if (r->remaining == -1) { /* reading footers until empty line */ - len_read = chunk_start; - - while ((bufsiz > 1) && ((len_read = - getline(buffer, bufsiz, r->connection->client, 1)) > 0)) { - - if (len_read != (bufsiz - 1)) { - buffer[len_read++] = CR; /* Restore footer line end */ - buffer[len_read++] = LF; - } - chunk_start += len_read; - buffer += len_read; - bufsiz -= len_read; - } - if (len_read < 0) { - r->connection->keepalive = -1; - return -1; - } - - if (len_read == 0) { /* Indicates an empty line */ - buffer[0] = CR; - buffer[1] = LF; - chunk_start += 2; - r->remaining = -2; - } - r->read_length += chunk_start; - return chunk_start; - } - /* When REQUEST_CHUNKED_PASS, we */ - if (r->remaining == -2) { /* finished footers when last called */ - r->remaining = 0; /* so now we must signal EOF */ - return 0; - } - - /* Otherwise, we are in the midst of reading a chunk of data */ - - len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining; - - len_read = bread(r->connection->client, buffer, len_to_read); - if (len_read <= 0) { - r->connection->keepalive = -1; - return -1; - } - - r->remaining -= len_read; - - if (r->remaining == 0) { /* End of chunk, get trailing CRLF */ - if ((c = bgetc(r->connection->client)) == CR) { - c = bgetc(r->connection->client); - } - if (c != LF) { - r->connection->keepalive = -1; - return -1; - } - if (r->read_body == REQUEST_CHUNKED_PASS) { - buffer[len_read++] = CR; - buffer[len_read++] = LF; - } - } - r->read_length += (chunk_start + len_read); - - return (chunk_start + len_read); -} - -/* In HTTP/1.1, any method can have a body. However, most GET handlers - * wouldn't know what to do with a request body if they received one. - * This helper routine tests for and reads any message body in the request, - * simply discarding whatever it receives. We need to do this because - * failing to read the request body would cause it to be interpreted - * as the next request on a persistent connection. - * - * Since we return an error status if the request is malformed, this - * routine should be called at the beginning of a no-body handler, e.g., - * - * if ((retval = discard_request_body(r)) != OK) - * return retval; - */ -int discard_request_body(request_rec *r) -{ - int rv; - - if ((rv = setup_client_block(r, REQUEST_CHUNKED_PASS))) - return rv; - - if (should_client_block(r)) { - char dumpbuf[HUGE_STRING_LEN]; - - hard_timeout("reading request body", r); - while ((rv = get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0) - continue; - kill_timeout(r); - - if (rv < 0) - return HTTP_BAD_REQUEST; - } - return OK; -} - -/* - * Send the body of a response to the client. - */ -long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); } - -long send_fd_length(FILE *f, request_rec *r, long length) -{ - char buf[IOBUFSIZE]; - long total_bytes_sent = 0; - register int n, w, o, len; - - if (length == 0) return 0; - - soft_timeout("send body", r); - - while (!r->connection->aborted) { - if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length) - len = length - total_bytes_sent; - else len = IOBUFSIZE; - - while ((n= fread(buf, sizeof(char), len, f)) < 1 - && ferror(f) && errno == EINTR && !r->connection->aborted) - continue; - - if (n < 1) { - break; - } - o=0; - - while (n && !r->connection->aborted) { - w = bwrite(r->connection->client, &buf[o], n); - if (w > 0) { - reset_timeout(r); /* reset timeout after successful write */ - total_bytes_sent += w; - n-=w; - o+=w; - } - else if (w < 0) { - if (r->connection->aborted) - break; - else if (errno == EAGAIN) - continue; - else { - log_unixerr("send body lost connection to", - get_remote_host(r->connection, - r->per_dir_config, REMOTE_NAME), - NULL, r->server); - bsetflag(r->connection->client, B_EOUT, 1); - r->connection->aborted = 1; - break; - } - } - } - } - - kill_timeout(r); - SET_BYTES_SENT(r); - return total_bytes_sent; -} - -int rputc (int c, request_rec *r) -{ - if (r->connection->aborted) return EOF; - bputc(c, r->connection->client); - SET_BYTES_SENT(r); - return c; -} - -int rputs(const char *str, request_rec *r) -{ - if (r->connection->aborted) return EOF; - SET_BYTES_SENT(r); - return bputs(str, r->connection->client); -} - -int rwrite(const void *buf, int nbyte, request_rec *r) -{ - int n; - if (r->connection->aborted) return EOF; - n=bwrite(r->connection->client, buf, nbyte); - SET_BYTES_SENT(r); - return n; -} - -int rprintf(request_rec *r,const char *fmt,...) -{ - va_list vlist; - int n; - - if(r->connection->aborted) return EOF; - va_start(vlist,fmt); - n=vbprintf(r->connection->client,fmt,vlist); - va_end(vlist); - SET_BYTES_SENT(r); - return n; -} - -int rvputs(request_rec *r, ...) -{ - va_list args; - int i, j, k; - const char *x; - BUFF *fb=r->connection->client; - - if (r->connection->aborted) return EOF; - - va_start (args, r); - for (k=0;;) - { - x = va_arg(args, const char *); - if (x == NULL) break; - j = strlen(x); - i = bwrite(fb, x, j); - if (i != j) - { - va_end(args); - return -1; - } - k += i; - } - va_end(args); - - SET_BYTES_SENT(r); - return k; -} - -int rflush (request_rec *r) { - return bflush(r->connection->client); -} - -/* We should have named this send_canned_response, since it is used for any - * response that can be generated by the server from the request record. - * This includes all 204 (no content), 3xx (redirect), 4xx (client error), - * and 5xx (server error) messages that have not been redirected to another - * handler via the ErrorDocument feature. - */ -void send_error_response (request_rec *r, int recursive_error) -{ - BUFF *fd = r->connection->client; - int status = r->status; - int idx = index_of_response (status); - char *custom_response; - char *location = pstrdup(r->pool, table_get(r->headers_out, "Location")); - - /* We need to special-case the handling of 204 and 304 responses, - * since they have specific HTTP requirements and do not include a - * message body. Note that being assbackwards here is not an option. - */ - if (status == HTTP_NOT_MODIFIED) { - if (!is_empty_table(r->err_headers_out)) - r->headers_out = overlay_tables(r->pool, r->err_headers_out, - r->headers_out); - hard_timeout("send 304", r); - - basic_http_header(r); - set_keepalive(r); - - table_do((int (*)(void *, const char *, const char *))send_header_field, - (void *)r, r->headers_out, - "Connection", - "Keep-Alive", - "ETag", - "Content-Location", - "Expires", - "Cache-Control", - "Vary", - "Warning", - "WWW-Authenticate", - NULL); - - terminate_header(r->connection->client); - - kill_timeout(r); - return; - } - - if (status == HTTP_NO_CONTENT) { - send_http_header(r); - finalize_request_protocol(r); - return; - } - - if (!r->assbackwards) { - table *tmp = r->headers_out; - - /* For all HTTP/1.x responses for which we generate the message, - * we need to avoid inheriting the "normal status" header fields - * that may have been set by the request handler before the - * error or redirect, except for Location on external redirects. - */ - r->headers_out = r->err_headers_out; - r->err_headers_out = tmp; - clear_table(r->err_headers_out); - - if (location && *location - && (is_HTTP_REDIRECT(status) || status == HTTP_CREATED)) - table_set(r->headers_out, "Location", location); - - r->content_language = NULL; - r->content_languages = NULL; - r->content_encoding = NULL; - r->clength = 0; - r->content_type = "text/html"; - - if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED)) - table_set(r->headers_out, "Allow", make_allow(r)); - - send_http_header(r); - - if (r->header_only) { - finalize_request_protocol(r); - return; - } - } - - hard_timeout("send error body", r); - - if ((custom_response = response_code_string (r, idx))) { - /* - * We have a custom response output. This should only be - * a text-string to write back. But if the ErrorDocument - * was a local redirect and the requested resource failed - * for any reason, the custom_response will still hold the - * redirect URL. We don't really want to output this URL - * as a text message, so first check the custom response - * string to ensure that it is a text-string (using the - * same test used in die(), i.e. does it start with a - * "). If it doesn't, we've got a recursive error, so find - * the original error and output that as well. - */ - if (custom_response[0] == '\"') { - bputs(custom_response+1, fd); - kill_timeout(r); - finalize_request_protocol(r); - return; - } - /* Redirect failed, so get back the original error - */ - while (r->prev && (r->prev->status != HTTP_OK)) - r = r->prev; - } - { - char *title = status_lines[idx]; - /* folks decided they didn't want the error code in the H1 text */ - - char *h1 = 4 + status_lines[idx]; - - bvputs - ( - fd, - "<HTML><HEAD>\n<TITLE>", - title, - "</TITLE>\n</HEAD><BODY>\n<H1>", - h1, - "</H1>\n", - NULL - ); - - switch (status) { - case REDIRECT: - case MOVED: - bvputs(fd, "The document has moved <A HREF=\"", - escape_html(r->pool, location), "\">here</A>.<P>\n", NULL); - break; - case HTTP_SEE_OTHER: - bvputs(fd, "The answer to your request is located <A HREF=\"", - escape_html(r->pool, location), "\">here</A>.<P>\n", NULL); - break; - case HTTP_USE_PROXY: - bvputs(fd, "This resource is only accessible through the proxy\n", - escape_html(r->pool, location), "<BR>\nYou will need to ", - "configure your client to use that proxy.<P>\n", NULL); - break; - case AUTH_REQUIRED: - bputs("This server could not verify that you\n", fd); - bputs("are authorized to access the document you\n", fd); - bputs("requested. Either you supplied the wrong\n", fd); - bputs("credentials (e.g., bad password), or your\n", fd); - bputs("browser doesn't understand how to supply\n", fd); - bputs("the credentials required.<P>\n", fd); - break; - case BAD_REQUEST: - bputs("Your browser sent a request that\n", fd); - bputs("this server could not understand.<P>\n", fd); - break; - case FORBIDDEN: - bvputs(fd, "You don't have permission to access ", - escape_html(r->pool, r->uri), "\non this server.<P>\n", - NULL); - break; - case NOT_FOUND: - bvputs(fd, "The requested URL ", escape_html(r->pool, r->uri), - " was not found on this server.<P>\n", NULL); - break; - case METHOD_NOT_ALLOWED: - bvputs(fd, "The requested method ", r->method, " is not allowed " - "for the URL ", escape_html(r->pool, r->uri), - ".<P>\n", NULL); - break; - case NOT_ACCEPTABLE: - bvputs(fd, - "An appropriate representation of the requested resource ", - escape_html(r->pool, r->uri), - " could not be found on this server.<P>\n", NULL); - /* fall through */ - case MULTIPLE_CHOICES: - { - char *list; - if ((list = table_get (r->notes, "variant-list"))) - bputs(list, fd); - } - break; - case LENGTH_REQUIRED: - bvputs(fd, "A request of the requested method ", r->method, - " requires a valid Content-length.<P>\n", NULL); - break; - case PRECONDITION_FAILED: - bvputs(fd, "The precondition on the request for the URL ", - escape_html(r->pool, r->uri), " evaluated to false.<P>\n", - NULL); - break; - case NOT_IMPLEMENTED: - bvputs(fd, escape_html(r->pool, r->method), " to ", - escape_html(r->pool, r->uri), " not supported.<P>\n", NULL); - break; - case BAD_GATEWAY: - bputs("The proxy server received an invalid\015\012", fd); - bputs("response from an upstream server.<P>\015\012", fd); - break; - case VARIANT_ALSO_VARIES: - bvputs(fd, "A variant for the requested entity ", - escape_html(r->pool, r->uri), " is itself a ", - "transparently negotiable resource.<P>\n", NULL); - break; - case HTTP_REQUEST_TIME_OUT: - bputs("I'm tired of waiting for your request.\n", fd); - break; - case HTTP_GONE: - bvputs(fd, "The requested resource<BR>", - escape_html(r->pool, r->uri), - "<BR>\nis no longer available on this server ", - "and there is no forwarding address.\n", - "Please remove all references to this resource.\n", NULL); - break; - case HTTP_REQUEST_ENTITY_TOO_LARGE: - bvputs(fd, "The requested resource<BR>", - escape_html(r->pool, r->uri), "<BR>\n", - "does not allow request data with ", r->method, - " requests, or the amount of data provided in\n", - "the request exceeds the capacity limit.\n", NULL); - break; - case HTTP_REQUEST_URI_TOO_LARGE: - bputs("The requested URL's length exceeds the capacity\n", fd); - bputs("limit for this server.\n", fd); - break; - case HTTP_UNSUPPORTED_MEDIA_TYPE: - bputs("The supplied request data is not in a format\n", fd); - bputs("acceptable for processing by this resource.\n", fd); - break; - case HTTP_SERVICE_UNAVAILABLE: - bputs("The server is temporarily unable to service your\n", fd); - bputs("request due to maintenance downtime or capacity\n", fd); - bputs("problems. Please try again later.\n", fd); - break; - case HTTP_GATEWAY_TIME_OUT: - bputs("The proxy server did not receive a timely response\n", fd); - bputs("from the upstream server.<P>\n", fd); - break; - default: /* HTTP_INTERNAL_SERVER_ERROR */ - bputs("The server encountered an internal error or\n", fd); - bputs("misconfiguration and was unable to complete\n", fd); - bputs("your request.<P>\n", fd); - bputs("Please contact the server administrator,\n ", fd); - bputs(escape_html(r->pool, r->server->server_admin), fd); - bputs(" and inform them of the time the error occurred,\n", fd); - bputs("and anything you might have done that may have\n", fd); - bputs("caused the error.<P>\n", fd); - break; - } - - if (recursive_error) { - bvputs(fd, "<P>Additionally, a ", - status_lines[index_of_response(recursive_error)], - "\nerror was encountered while trying to use an " - "ErrorDocument to handle the request.\n", NULL); - } - bputs("</BODY></HTML>\n", fd); - } - kill_timeout(r); - finalize_request_protocol(r); -} - -/* Finally, this... it's here to support nph- scripts - * Now what ever are we going to do about them when HTTP-NG packetization - * comes along? - */ - -void client_to_stdout (conn_rec *c) -{ - bflush(c->client); - dup2(c->client->fd, STDOUT_FILENO); -} diff --git a/usr.sbin/httpd/src/http_protocol.h b/usr.sbin/httpd/src/http_protocol.h deleted file mode 100644 index db608c253e9..00000000000 --- a/usr.sbin/httpd/src/http_protocol.h +++ /dev/null @@ -1,191 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * Prototypes for routines which either talk directly back to the user, - * or control the ones that eventually do. - */ - -/* Read a request and fill in the fields. */ - -request_rec *read_request (conn_rec *c); - -/* Send a single HTTP header field */ - -int send_header_field (request_rec *r, const char *fieldname, - const char *fieldval); - -/* Send the Status-Line and header fields for HTTP response */ - -void send_http_header (request_rec *l); - -/* Send the response to special method requests */ - -int send_http_trace (request_rec *r); -int send_http_options (request_rec *r); - -/* Finish up stuff after a request */ - -void finalize_request_protocol (request_rec *r); - -/* Send error back to client... last arg indicates error status in case - * we get an error in the process of trying to deal with an ErrorDocument - * to handle some other error. In that case, we print the default report - * for the first thing that went wrong, and more briefly report on the - * problem with the ErrorDocument. - */ - -void send_error_response (request_rec *r, int recursive_error); - -/* Set last modified header line from the lastmod date of the associated file. - * Also, set content length. - * - * May return an error status, typically USE_LOCAL_COPY (that when the - * permit_cache argument is set to one). - */ - -int set_content_length (request_rec *r, long length); -int set_keepalive (request_rec *r); -int set_last_modified (request_rec *r, time_t mtime); - -/* Other ways to send stuff at the client. All of these keep track - * of bytes_sent automatically. This indirection is intended to make - * it a little more painless to slide things like HTTP-NG packetization - * underneath the main body of the code later. In the meantime, it lets - * us centralize a bit of accounting (bytes_sent). - * - * These also return the number of bytes written by the call. - * They should only be called with a timeout registered, for obvious reaasons. - * (Ditto the send_header stuff). - */ - -long send_fd(FILE *f, request_rec *r); -long send_fd_length(FILE *f, request_rec *r, long length); - -/* Hmmm... could macrofy these for now, and maybe forever, though the - * definitions of the macros would get a whole lot hairier. - */ - -int rputc (int c, request_rec *r); -int rputs(const char *str, request_rec *r); -int rwrite(const void *buf, int nbyte, request_rec *r); -int rvputs(request_rec *r, ...); -int rprintf(request_rec *r,const char *fmt,...); -int rflush(request_rec *r); - -/* - * Index used in custom_responses array for a specific error code - * (only use outside protocol.c is in getting them configured). - */ - -int index_of_response (int status); - -/* Reading a block of data from the client connection (e.g., POST arg) */ - -int setup_client_block (request_rec *r, int read_policy); -int should_client_block (request_rec *r); -long get_client_block (request_rec *r, char *buffer, int bufsiz); -int discard_request_body (request_rec *r); - -/* Sending a byterange */ - -int set_byterange (request_rec *r); -int each_byterange (request_rec *r, long *offset, long *length); - -/* Finally, this charming little number is here to encapsulate the - * degree to which nph- scripts completely escape from any discipline - * the protocol code might care to impose (this as opposed to other - * scripts, which *partially* escape to the extent that they may try - * to explicitly set the status line). - */ - -void client_to_stdout (conn_rec *c); - - -/* Support for the Basic authentication protocol. Note that there's - * nothing that prevents these from being in mod_auth.c, except that other - * modules which wanted to provide their own variants on finding users and - * passwords for Basic auth (a fairly common request) would then require - * mod_auth to be loaded or they wouldn't work. - * - * get_basic_auth_pw returns 0 (OK) if it set the 'pw' argument (and assured - * a correct value in r->connection->user); otherwise it returns an error - * code, either SERVER_ERROR if things are really confused, AUTH_REQUIRED - * if no authentication at all seemed to be in use, or DECLINED if there - * was authentication but it wasn't Basic (in which case, the caller should - * presumably decline as well). - * - * note_basic_auth_failure arranges for the right stuff to be scribbled on - * the HTTP return so that the client knows how to authenticate itself the - * next time. As does note_digest_auth_failure for Digest auth. - * - * note_auth_failure does the same thing, but will call the correct one - * based on the authentication type in use. - * - */ - -void note_auth_failure(request_rec *r); -void note_basic_auth_failure(request_rec *r); -void note_digest_auth_failure(request_rec *r); -int get_basic_auth_pw (request_rec *r, char **pw); - -/* - * Setting up the protocol fields for subsidiary requests... - * Also, a wrapup function to keep the internal accounting straight. - */ - -void set_sub_req_protocol (request_rec *rnew, const request_rec *r); -void finalize_sub_req_protocol (request_rec *sub_r); - -/* This is also useful for putting sub_reqs and internal_redirects together */ - -void parse_uri (request_rec *r, const char *uri); diff --git a/usr.sbin/httpd/src/http_request.c b/usr.sbin/httpd/src/http_request.c deleted file mode 100644 index 0ffa6ee6386..00000000000 --- a/usr.sbin/httpd/src/http_request.c +++ /dev/null @@ -1,1152 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_request.c: functions to get and process requests - * - * Rob McCool 3/21/93 - * - * Thoroughly revamped by rst for Apache. NB this file reads - * best from the bottom up. - * - */ - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "scoreboard.h" - -/***************************************************************** - * - * Getting and checking directory configuration. Also checks the - * FollowSymlinks and FollowSymOwner stuff, since this is really the - * only place that can happen (barring a new mid_dir_walk callout). - * - * We can't do it as an access_checker module function which gets - * called with the final per_dir_config, since we could have a directory - * with FollowSymLinks disabled, which contains a symlink to another - * with a .htaccess file which turns FollowSymLinks back on --- and - * access in such a case must be denied. So, whatever it is that - * checks FollowSymLinks needs to know the state of the options as - * they change, all the way down. - */ - - -/* - * We don't want people able to serve up pipes, or unix sockets, or other - * scary things. Note that symlink tests are performed later. - */ -static int check_safe_file(request_rec *r) -{ - if (r->finfo.st_mode == 0 /* doesn't exist */ - || S_ISDIR (r->finfo.st_mode) - || S_ISREG (r->finfo.st_mode) - || S_ISLNK (r->finfo.st_mode)) { - return OK; - } - log_reason("object is not a file, directory or symlink", r->filename, r); - return HTTP_FORBIDDEN; -} - - -int check_symlinks (char *d, int opts) -{ - struct stat lfi, fi; - char *lastp; - int res; - -#ifdef __EMX__ - /* OS/2 dosen't have symlinks */ - return OK; -#else - - if (opts & OPT_SYM_LINKS) return OK; - - /* Strip trailing '/', if any, off what we're checking; trailing - * slashes make some systems follow symlinks to directories even in - * lstat(). After we've done the lstat, put it back. Also, don't - * bother checking '/' at all... - * - * Note that we don't have to worry about multiple slashes here - * because of no2slash() below... - */ - - lastp = d + strlen(d) - 1; - if (lastp == d) return OK; /* Root directory, '/' */ - - if (*lastp == '/') *lastp = '\0'; - else lastp = NULL; - - res = lstat (d, &lfi); - - if (lastp) *lastp = '/'; - - /* Note that we don't reject accesses to nonexistent files (multiviews - * or the like may cons up a way to run the transaction anyway)... - */ - - if (!(res >= 0) || !S_ISLNK(lfi.st_mode)) return OK; - - /* OK, it's a symlink. May still be OK with OPT_SYM_OWNER */ - - if (!(opts & OPT_SYM_OWNER)) return HTTP_FORBIDDEN; - - if (stat (d, &fi) < 0) return HTTP_FORBIDDEN; - - return (fi.st_uid == lfi.st_uid) ? OK : HTTP_FORBIDDEN; - -#endif -} - -/* Dealing with the file system to get PATH_INFO - */ - -int get_path_info(request_rec *r) -{ - char *cp; - char *path = r->filename; - char *end = &path[strlen(path)]; - char *last_cp = NULL; - int rv; - - /* Advance over trailing slashes ... NOT part of filename */ - - for (cp = end; cp > path && cp[-1] == '/'; --cp) - continue; - - while (cp > path) { - - /* See if the pathname ending here exists... */ - - *cp = '\0'; - - errno = 0; - rv = stat(path, &r->finfo); - - if (cp != end) *cp = '/'; - - if (!rv) { - - /* Aha! Found something. If it was a directory, we will - * search contents of that directory for a multi_match, so - * the PATH_INFO argument starts with the component after that. - */ - - if (S_ISDIR(r->finfo.st_mode) && last_cp) { - r->finfo.st_mode = 0; /* No such file... */ - cp = last_cp; - } - - r->path_info = pstrdup (r->pool, cp); - *cp = '\0'; - return OK; - } -#if defined(ENOENT) && defined(ENOTDIR) - else if (errno == ENOENT || errno == ENOTDIR) { -#else -#error ENOENT || ENOTDIR not defined -- check the comment below this line in the source for details - /* - * If ENOENT || ENOTDIR is not defined in one of the your OS's - * include files, Apache does not know how to check to see why - * the stat() of the index file failed; there are cases where - * it can fail even though the file exists. This means - * that it is possible for someone to get a directory - * listing of a directory even though there is an index - * (eg. index.html) file in it. If you do not have a - * problem with this, delete the above #error line and - * start the compile again. If you need to do this, please - * submit a bug report from http://www.apache.org/bug_report.html - * letting us know that you needed to do this. Please be - * sure to include the operating system you are using. - */ - - else { -#endif - last_cp = cp; - - while (--cp > path && *cp != '/') - continue; - - while (cp > path && cp[-1] == '/') - --cp; - } -#if defined(ENOENT) && defined(ENOTDIR) - else { -#if defined(EACCES) - if (errno != EACCES) -#endif - log_printf(r->server, - "access to %s failed for %s, reason: stat: %s (errno = %d)", - r->uri, get_remote_host(r->connection, r->per_dir_config, - REMOTE_NAME), strerror(errno), errno); - - return HTTP_FORBIDDEN; - } -#endif /* ENOENT && ENOTDIR */ - } - return OK; -} - -int directory_walk (request_rec *r) -{ - core_server_config *sconf = get_module_config (r->server->module_config, - &core_module); - array_header *sec_array = copy_array (r->pool, sconf->sec); - void *per_dir_defaults = r->server->lookup_defaults; - - core_dir_config **sec = (core_dir_config **)sec_array->elts; - int num_sec = sec_array->nelts; - char *test_filename = pstrdup (r->pool, r->filename); - - int num_dirs, res; - int i; - - /* Are we dealing with a file? If not, we can (hopefuly) safely assume - * we have a handler that doesn't require one, but for safety's sake, - * and so we have something find_types() can get something out of, - * fake one. But don't run through the directory entries. - */ - - if (test_filename == NULL) { - r->filename = pstrdup(r->pool, r->uri); - r->finfo.st_mode = 0; /* Not really a file... */ - r->per_dir_config = per_dir_defaults; - - return OK; - } - - /* Go down the directory hierarchy. Where we have to check for symlinks, - * do so. Where a .htaccess file has permission to override anything, - * try to find one. If either of these things fails, we could poke - * around, see why, and adjust the lookup_rec accordingly --- this might - * save us a call to get_path_info (with the attendant stat()s); however, - * for the moment, that's not worth the trouble. - */ - -#ifdef __EMX__ - /* Add OS/2 drive name support */ - if ((test_filename[0] != '/') && (test_filename[1] != ':')) -#else - if (test_filename[0] != '/') -#endif - { -/* fake filenames only match Directory sections */ - void *this_conf, *entry_config; - core_dir_config *entry_core; - char *entry_dir; - int j; - - for (j = 0; j < num_sec; ++j) { - - entry_config = sec[j]; - if (!entry_config) continue; - - entry_core =(core_dir_config *) - get_module_config(entry_config, &core_module); - entry_dir = entry_core->d; - - this_conf = NULL; - if (entry_core->r) { - if (!regexec(entry_core->r, test_filename, 0, NULL, 0)) - this_conf = entry_config; - } - else if (entry_core->d_is_matchexp) { - if (!strcmp_match(test_filename, entry_dir)) - this_conf = entry_config; - } - else if (!strncmp (test_filename, entry_dir, strlen(entry_dir))) - this_conf = entry_config; - - if (this_conf) - per_dir_defaults = merge_per_dir_configs (r->pool, - per_dir_defaults, this_conf); - } - - r->per_dir_config = per_dir_defaults; - - return OK; - } - - no2slash (test_filename); - num_dirs = count_dirs(test_filename); - - res = get_path_info (r); - if (res != OK) { - return res; - } - - if ((res = check_safe_file(r))) { - return res; - } - - if (test_filename[strlen(test_filename)-1] == '/') - --num_dirs; - - if (S_ISDIR (r->finfo.st_mode)) { - ++num_dirs; - } - - for (i = 1; i <= num_dirs; ++i) { - core_dir_config *core_dir = - (core_dir_config *)get_module_config(per_dir_defaults, &core_module); - int overrides_here; - void *this_conf, *htaccess_conf = NULL; - char *this_dir = make_dirstr (r->pool, test_filename, i); - int j; - - /* Do symlink checks first, because they are done with the - * permissions appropriate to the *parent* directory... - */ - - if ((res = check_symlinks (this_dir, core_dir->opts))) - { - log_reason("Symbolic link not allowed", this_dir, r); - return res; - } - - /* Begin *this* level by looking for matching <Directory> sections from - * access.conf. - */ - - for (j = 0; j < num_sec; ++j) { - void *entry_config = sec[j]; - core_dir_config *entry_core; - char *entry_dir; - - if (!entry_config) continue; - - entry_core = - (core_dir_config *)get_module_config(entry_config, &core_module); - entry_dir = entry_core->d; - - this_conf = NULL; - if (entry_core->r) { - if (!regexec(entry_core->r, this_dir, 0, NULL, - (j == num_sec) ? 0 : REG_NOTEOL)) { - /* Don't try this wildcard again --- if it ends in '*' - * it'll match again, and subdirectories won't be able to - * override it... - */ - sec[j] = NULL; - this_conf = entry_config; - } - } - else if (entry_core->d_is_matchexp && - !strcmp_match(this_dir, entry_dir)) { - sec[j] = NULL; - this_conf = entry_config; - } - else if (!strcmp (this_dir, entry_dir)) - this_conf = entry_config; - - if (this_conf) { - per_dir_defaults = - merge_per_dir_configs (r->pool, per_dir_defaults, this_conf); - core_dir =(core_dir_config *)get_module_config(per_dir_defaults, - &core_module); - } - - } - - overrides_here = core_dir->override; - - /* If .htaccess files are enabled, check for one. - */ - - if (overrides_here) { - char *config_name = make_full_path(r->pool, this_dir, - sconf->access_name); - res = parse_htaccess (&htaccess_conf, r, overrides_here, - this_dir, config_name); - if (res) return res; - } - - if (htaccess_conf) - per_dir_defaults = - merge_per_dir_configs (r->pool, per_dir_defaults, - htaccess_conf); - - } - - r->per_dir_config = per_dir_defaults; - - /* Symlink permissions are determined by the parent. If the request is for - * a directory then applying the symlink test here would use the - * permissions of the directory as opposed to its parent. Consider a - * symlink pointing to a dir with a .htaccess disallowing symlinks. If you - * access /symlink (or /symlink/) you would get a 403 without this S_ISDIR - * test. But if you accessed /symlink/index.html, for example, you would - * *not* get the 403. - */ - if (!S_ISDIR (r->finfo.st_mode) - && (res = check_symlinks (r->filename, allow_options(r)))) { - log_reason("Symbolic link not allowed", r->filename, r); - return res; - } - - return OK; /* Can only "fail" if access denied - * by the symlink goop. - */ -} - -int location_walk (request_rec *r) -{ - core_server_config *sconf = get_module_config (r->server->module_config, - &core_module); - array_header *url_array = copy_array (r->pool, sconf->sec_url); - void *per_dir_defaults = r->per_dir_config; - - core_dir_config **url = (core_dir_config **)url_array->elts; - int len, num_url = url_array->nelts; - char *test_location = pstrdup (r->pool, r->uri); - - /* Collapse multiple slashes, if it's a path URL (we don't want to - * do anything to <Location http://...> or such). - */ - if (test_location[0] == '/') - no2slash (test_location); - - /* Go through the location entries, and check for matches. */ - - if (num_url) { - void *this_conf, *entry_config; - core_dir_config *entry_core; - char *entry_url; - int j; - -/* - * we apply the directive sections in some order; should really try them - * with the most general first. - */ - for (j = 0; j < num_url; ++j) { - - entry_config = url[j]; - if (!entry_config) continue; - - entry_core =(core_dir_config *) - get_module_config(entry_config, &core_module); - entry_url = entry_core->d; - - len = strlen(entry_url); - - this_conf = NULL; - - if (entry_core->r) { - if (!regexec(entry_core->r, test_location, 0, NULL, 0)) - this_conf = entry_config; - } - else if( entry_core->d_is_matchexp ) { - if (!strcmp_match(test_location, entry_url)) - this_conf = entry_config; - } - else if (!strncmp (test_location, entry_url, len) && - (entry_url[len - 1] == '/' || - test_location[len] == '/' || test_location[len] == '\0')) - this_conf = entry_config; - - if (this_conf) - per_dir_defaults = merge_per_dir_configs (r->pool, - per_dir_defaults, this_conf); - } - - r->per_dir_config = per_dir_defaults; - } - - return OK; -} - -int file_walk (request_rec *r) -{ - core_dir_config *conf = get_module_config(r->per_dir_config, &core_module); - array_header *file_array = copy_array (r->pool, conf->sec); - void *per_dir_defaults = r->per_dir_config; - - core_dir_config **file = (core_dir_config **)file_array->elts; - int len, num_files = file_array->nelts; - char *test_file = pstrdup (r->pool, r->filename); - - /* Collapse multiple slashes */ - no2slash (test_file); - - /* Go through the file entries, and check for matches. */ - - if (num_files) { - void *this_conf, *entry_config; - core_dir_config *entry_core; - char *entry_file; - int j; - -/* - * we apply the directive sections in some order; should really try them - * with the most general first. - */ - for (j = 0; j < num_files; ++j) { - - entry_config = file[j]; - if (!entry_config) continue; - - entry_core =(core_dir_config *) - get_module_config(entry_config, &core_module); - entry_file = entry_core->d; - - len = strlen(entry_file); - - this_conf = NULL; - - if (entry_core->r) { - if (!regexec(entry_core->r, test_file, 0, NULL, 0)) - this_conf = entry_config; - } - else if ( entry_core->d_is_matchexp ) { - if (!strcmp_match(test_file, entry_file)) - this_conf = entry_config; - } - else if (!strncmp (test_file, entry_file, len) && - (entry_file[len - 1] == '/' || - test_file[len] == '/' || test_file[len] == '\0')) - this_conf = entry_config; - - if (this_conf) - per_dir_defaults = merge_per_dir_configs (r->pool, - per_dir_defaults, this_conf); - } - - r->per_dir_config = per_dir_defaults; - } - - return OK; -} - -/***************************************************************** - * - * The sub_request mechanism. - * - * Fns to look up a relative URI from, e.g., a map file or SSI document. - * These do all access checks, etc., but don't actually run the transaction - * ... use run_sub_req below for that. Also, be sure to use destroy_sub_req - * as appropriate if you're likely to be creating more than a few of these. - * (An early Apache version didn't destroy the sub_reqs used in directory - * indexing. The result, when indexing a directory with 800-odd files in - * it, was massively excessive storage allocation). - * - * Note more manipulation of protocol-specific vars in the request - * structure... - */ - -request_rec *make_sub_request (const request_rec *r) -{ - pool *rrp = make_sub_pool (r->pool); - request_rec *rr = pcalloc (rrp, sizeof (request_rec)); - - rr->pool = rrp; - return rr; -} - - -request_rec *sub_req_lookup_uri (const char *new_file, const request_rec *r) -{ - request_rec *rnew; - int res; - char *udir; - - rnew = make_sub_request (r); - rnew->request_time = r->request_time; - rnew->connection = r->connection; - rnew->server = r->server; - rnew->request_config = create_request_config (rnew->pool); - rnew->htaccess = r->htaccess; /* copy htaccess cache */ - rnew->per_dir_config=r->server->lookup_defaults; - set_sub_req_protocol (rnew, r); - - if (new_file[0] == '/') - parse_uri(rnew, new_file); - else - { - udir = make_dirstr (rnew->pool, r->uri, count_dirs (r->uri)); - udir = escape_uri(rnew->pool, udir); /* re-escape it */ - parse_uri (rnew, make_full_path (rnew->pool, udir, new_file)); - } - - res = unescape_url (rnew->uri); - if (res) - { - rnew->status = res; - return rnew; - } - - getparents (rnew->uri); - - if ((res = location_walk (rnew))) { - rnew->status=res; - return rnew; - } - - res = translate_name(rnew); - if (res) - { - rnew->status = res; - return rnew; - } - - /* We could be clever at this point, and avoid calling directory_walk, etc. - * However, we'd need to test that the old and new filenames contain the - * same directory components, so it would require duplicating the start - * of translate_name. - * Instead we rely on the cache of .htaccess results. - */ - /* NB: directory_walk() clears the per_dir_config, so we don't inherit from - location_walk() above */ - - if ((res = directory_walk (rnew)) - || (res = file_walk (rnew)) - || (res = location_walk (rnew)) - || ((satisfies(rnew)==SATISFY_ALL || satisfies(rnew)==SATISFY_NOSPEC)? - ((res = check_access (rnew)) - || (some_auth_required (rnew) && - ((res = check_user_id (rnew)) || (res = check_auth (rnew))))): - ((res = check_access (rnew)) - && (!some_auth_required (rnew) || - ((res = check_user_id (rnew)) || (res = check_auth (rnew))))) - ) - || (res = find_types (rnew)) - || (res = run_fixups (rnew)) - ) - { - rnew->status = res; - } - - return rnew; -} - -request_rec *sub_req_lookup_file (const char *new_file, const request_rec *r) -{ - request_rec *rnew; - int res; - char *fdir; - - rnew = make_sub_request (r); - rnew->request_time = r->request_time; - rnew->connection = r->connection; /* For now... */ - rnew->server = r->server; - rnew->request_config = create_request_config (rnew->pool); - rnew->htaccess = r->htaccess; /* copy htaccess cache */ - set_sub_req_protocol (rnew, r); - fdir = make_dirstr (rnew->pool, r->filename, count_dirs (r->filename)); - - /* Check for a special case... if there are no '/' characters in new_file - * at all, then we are looking at a relative lookup in the same directory. - * That means we won't have to redo directory_walk, and we may not - * even have to redo access checks. - */ - - if (strchr (new_file, '/') == NULL) { - char *udir = make_dirstr(rnew->pool, r->uri, count_dirs(r->uri)); - - rnew->uri = make_full_path (rnew->pool, udir, new_file); - rnew->filename = make_full_path (rnew->pool, fdir, new_file); - if (stat (rnew->filename, &rnew->finfo) < 0) { - rnew->finfo.st_mode = 0; - } - - if ((res = check_safe_file(rnew))) { - rnew->status = res; - return rnew; - } - - rnew->per_dir_config = r->per_dir_config; - - /* no matter what, if it's a subdirectory, we need to re-run - * directory_walk */ - if (S_ISDIR (rnew->finfo.st_mode)) { - res = directory_walk (rnew); - if (!res) { - res = file_walk (rnew); - } - } else { - if ((res = check_symlinks (rnew->filename, allow_options (rnew)))) { - log_reason ("Symbolic link not allowed", rnew->filename, rnew); - rnew->status = res; - return rnew; - } - /* do a file_walk, if it doesn't change the per_dir_config then - * we know that we don't have to redo all the access checks */ - if ((res = file_walk (rnew))) { - rnew->status = res; - return rnew; - } - if (rnew->per_dir_config == r->per_dir_config) { - if ((res = find_types (rnew)) || (res = run_fixups (rnew))) { - rnew->status = res; - } - return rnew; - } - } - } else { - /* XXX: this should be set properly like it is in the same-dir case - * but it's actually sometimes to impossible to do it... because the - * file may not have a uri associated with it -djg */ - rnew->uri = "INTERNALLY GENERATED file-relative req"; - rnew->filename = ((new_file[0] == '/') ? - pstrdup(rnew->pool,new_file) : - make_full_path (rnew->pool, fdir, new_file)); - rnew->per_dir_config = r->server->lookup_defaults; - res = directory_walk (rnew); - if (!res) { - res = file_walk (rnew); - } - } - - if (res - || ((satisfies(rnew)==SATISFY_ALL || satisfies(rnew)==SATISFY_NOSPEC)? - ((res = check_access (rnew)) - || (some_auth_required (rnew) && - ((res = check_user_id (rnew)) || (res = check_auth (rnew))))): - ((res = check_access (rnew)) - && (!some_auth_required (rnew) || - ((res = check_user_id (rnew)) || (res = check_auth (rnew))))) - ) - || (res = find_types (rnew)) - || (res = run_fixups (rnew)) - ) - { - rnew->status = res; - } - - return rnew; -} - -int run_sub_req (request_rec *r) -{ - int retval = invoke_handler (r); - finalize_sub_req_protocol (r); - return retval; -} - -void destroy_sub_req (request_rec *r) -{ - /* Reclaim the space */ - destroy_pool (r->pool); -} - -/***************************************************************** - * - * Mainline request processing... - */ - -void die(int type, request_rec *r) -{ - int error_index = index_of_response (type); - char *custom_response = response_code_string(r, error_index); - int recursive_error = 0; - - /* The following takes care of Apache redirects to custom response URLs - * Note that if we are already dealing with the response to some other - * error condition, we just report on the original error, and give up on - * any attempt to handle the other thing "intelligently"... - */ - - if (r->status != HTTP_OK) { - recursive_error = type; - - while (r->prev && (r->prev->status != HTTP_OK)) - r = r->prev; /* Get back to original error */ - - type = r->status; - custom_response = NULL; /* Do NOT retry the custom thing! */ - } - - r->status = type; - - /* - * If we want to keep the connection, be sure that the request body - * (if any) has been read. - */ - if ((r->status != HTTP_NOT_MODIFIED) && (r->status != HTTP_NO_CONTENT) - && !status_drops_connection(r->status) - && r->connection && (r->connection->keepalive != -1)) { - (void) discard_request_body(r); - } - - /* Two types of custom redirects --- plain text, and URLs. - * Plain text has a leading '"', so the URL code, here, is triggered - * on its absence - */ - - if (custom_response && custom_response[0] != '"') { - - if (is_url(custom_response)) { - /* The URL isn't local, so lets drop through the rest of - * this apache code, and continue with the usual REDIRECT - * handler. But note that the client will ultimately see - * the wrong status... - */ - r->status = REDIRECT; - table_set (r->headers_out, "Location", custom_response); - } else if ( custom_response[0] == '/') { - r->no_local_copy = 1; /* Do NOT send USE_LOCAL_COPY for - * error documents! - */ - /* This redirect needs to be a GET no matter what the original - * method was. - */ - table_set(r->subprocess_env, "REQUEST_METHOD", r->method); - r->method = pstrdup(r->pool, "GET"); - r->method_number = M_GET; - internal_redirect (custom_response, r); - return; - } else { - /* Dumb user has given us a bad url to redirect to - * --- fake up dying with a recursive server error... - */ - recursive_error = SERVER_ERROR; - log_reason("Invalid error redirection directive", custom_response, - r); - } - } - - send_error_response (r, recursive_error); -} - -static void decl_die (int status, char *phase, request_rec *r) -{ - if (status == DECLINED) { - log_reason (pstrcat (r->pool, - "configuration error: couldn't ", - phase, NULL), - r->uri, - r); - die (SERVER_ERROR, r); - } - else die (status, r); -} - -int some_auth_required (request_rec *r) -{ - /* Is there a require line configured for the type of *this* req? */ - - array_header *reqs_arr = requires (r); - require_line *reqs; - int i; - - if (!reqs_arr) return 0; - - reqs = (require_line *)reqs_arr->elts; - - for (i = 0; i < reqs_arr->nelts; ++i) - if (reqs[i].method_mask & (1 << r->method_number)) - return 1; - - return 0; -} - -void process_request_internal (request_rec *r) -{ - int access_status; - - /* Kludge to be reading the assbackwards field outside of protocol.c, - * but we've got to check for this sort of nonsense somewhere... - */ - - if (r->assbackwards && r->header_only) { - /* Client asked for headers only with HTTP/0.9, which doesn't - * send headers! Have to dink things even to make sure the - * error message comes through... - */ - log_reason ("client sent illegal HTTP/0.9 request", r->uri, r); - r->header_only = 0; - die (BAD_REQUEST, r); - return; - } - - if ((!r->hostname && (r->proto_num >= 1001)) || - ((r->proto_num == 1001) && !table_get(r->headers_in, "Host"))) { - /* Client sent us a HTTP/1.1 or later request without telling - * us the hostname, either with a full URL or a Host: header. - * We therefore need to (as per the 1.1 spec) send an error. - * As a special case, HTTP/1.1 mentions twice (S9, S14.23) - * that a request MUST contain a Host: header, and the server - * MUST respond with 400 if it doesn't. - */ - log_reason ("client sent HTTP/1.1 request without hostname (see RFC2068 sections 9 and 14.23)", - r->uri, r); - die (BAD_REQUEST, r); - return; - } - - if (!r->proxyreq) - { - /* We don't want TRACE to run through the normal handler set, - * we handle it specially. - */ - if (r->method_number == M_TRACE) { - if ((access_status = send_http_trace(r))) - die(access_status, r); - else - finalize_request_protocol(r); - return; - } - - access_status = unescape_url(r->uri); - if (access_status) - { - die(access_status, r); - return; - } - - getparents(r->uri); /* OK --- shrinking transformations... */ - } - - if ((access_status = location_walk (r))) { - die (access_status, r); - return; - } - - if ((access_status = translate_name (r))) { - decl_die (access_status, "translate", r); - return; - } - - if (r->proto_num > 1000 && table_get (r->subprocess_env, "downgrade-1.0")) { - r->proto_num = 1000; - } - - /* NB: directory_walk() clears the per_dir_config, so we don't inherit from - location_walk() above */ - - if ((access_status = directory_walk (r))) { - die (access_status, r); - return; - } - - if ((access_status = file_walk (r))) { - die (access_status, r); - return; - } - - if ((access_status = location_walk (r))) { - die (access_status, r); - return; - } - - if ((access_status = header_parse (r))) { - die (access_status, r); - return; - } - - switch (satisfies(r)) { - case SATISFY_ALL: case SATISFY_NOSPEC: - if ((access_status = check_access (r)) != 0) { - decl_die (access_status, "check access", r); - return; - } - if (some_auth_required (r)) { - if ((access_status = check_user_id (r)) != 0) { - decl_die (access_status, "check user. No user file?", r); - return; - } - if ((access_status = check_auth (r)) != 0) { - decl_die (access_status, "check access. No groups file?", r); - return; - } - } - break; - case SATISFY_ANY: - if ((access_status = check_access (r)) != 0) { - if (!some_auth_required (r)) { - decl_die (access_status, "check access", r); - return; - } - if ((access_status = check_user_id (r)) != 0) { - decl_die (access_status, "check user. No user file?", r); - return; - } - if ((access_status = check_auth (r)) != 0) { - decl_die (access_status, "check access. No groups file?", r); - return; - } - } - break; - } - - if ((access_status = find_types (r)) != 0) { - decl_die (access_status, "find types", r); - return; - } - - if ((access_status = run_fixups (r)) != 0) { - die (access_status, r); - return; - } - - if ((access_status = invoke_handler (r)) != 0) { - die (access_status, r); - return; - } - - /* Take care of little things that need to happen when we're done */ - finalize_request_protocol (r); -} - -void process_request (request_rec *r) -{ -#ifdef STATUS - int old_stat; -#endif /* STATUS */ - process_request_internal (r); -#ifdef STATUS - old_stat = update_child_status (r->connection->child_num, SERVER_BUSY_LOG, - r); -#endif /* STATUS */ - log_transaction (r); -#ifdef STATUS - (void)update_child_status (r->connection->child_num, old_stat, r); -#endif /* STATUS */ -} - -table *rename_original_env (pool *p, table *t) -{ - array_header *env_arr = table_elts (t); - table_entry *elts = (table_entry *)env_arr->elts; - table *new = make_table (p, env_arr->nelts); - int i; - - for (i = 0; i < env_arr->nelts; ++i) { - if (!elts[i].key) continue; - table_set (new, pstrcat (p, "REDIRECT_", elts[i].key, NULL), - elts[i].val); - } - - return new; -} - -request_rec *internal_internal_redirect (const char *new_uri, request_rec *r) -{ - request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec)); - char t[256]; /* Long enough... */ - - new->connection = r->connection; - new->server = r->server; - new->pool = r->pool; - - /* A whole lot of this really ought to be shared with protocol.c... - * another missing cleanup. It's particularly inappropriate to be - * setting header_only, etc., here. - */ - - parse_uri (new, new_uri); - new->request_config = create_request_config (r->pool); - new->per_dir_config = r->server->lookup_defaults; - - new->prev = r; - r->next = new; - - /* Inherit the rest of the protocol info... */ - - new->the_request = r->the_request; - - new->method = r->method; - new->method_number = r->method_number; - new->allowed = r->allowed; - - new->status = r->status; - new->assbackwards = r->assbackwards; - new->header_only = r->header_only; - new->protocol = r->protocol; - new->proto_num = r->proto_num; - new->hostname = r->hostname; - new->hostlen = r->hostlen; - new->request_time = r->request_time; - new->main = r->main; - - new->headers_in = r->headers_in; - new->headers_out = make_table (r->pool, 5); - new->err_headers_out = r->err_headers_out; - new->subprocess_env = rename_original_env (r->pool, r->subprocess_env); - new->notes = make_table (r->pool, 5); - new->htaccess = r->htaccess; /* copy .htaccess cache */ - - new->no_cache = r->no_cache; /* If we've already made up our minds - * about this, don't change 'em back! - */ - new->no_local_copy = r->no_local_copy; - - new->read_length = r->read_length; /* We can only read it once */ - - ap_snprintf (t, sizeof(t), "%d", r->status); - table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t)); - - return new; -} - -void internal_redirect (const char *new_uri, request_rec *r) -{ - request_rec *new = internal_internal_redirect(new_uri, r); - process_request_internal (new); -} - -/* This function is designed for things like actions or CGI scripts, when - * using AddHandler, and you want to preserve the content type across - * an internal redirect. - */ - -void internal_redirect_handler (const char *new_uri, request_rec *r) -{ - request_rec *new = internal_internal_redirect(new_uri, r); - if (r->handler) - new->content_type = r->content_type; - process_request_internal (new); -} diff --git a/usr.sbin/httpd/src/http_request.h b/usr.sbin/httpd/src/http_request.h deleted file mode 100644 index f20d494cad9..00000000000 --- a/usr.sbin/httpd/src/http_request.h +++ /dev/null @@ -1,92 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* http_request.c is the code which handles the main line of request - * processing, once a request has been read in (finding the right per- - * directory configuration, building it if necessary, and calling all - * the module dispatch functions in the right order). - * - * The pieces here which are public to the modules, allow them to learn - * how the server would handle some other file or URI, or perhaps even - * direct the server to serve that other file instead of the one the - * client requested directly. - * - * There are two ways to do that. The first is the sub_request mechanism, - * which handles looking up files and URIs as adjuncts to some other - * request (e.g., directory entries for multiviews and directory listings); - * the lookup functions stop short of actually running the request, but - * (e.g., for includes), a module may call for the request to be run - * by calling run_sub_req. The space allocated to create sub_reqs can be - * reclaimed by calling destroy_sub_req --- be sure to copy anything you care - * about which was allocated in its pool elsewhere before doing this. - */ - -request_rec *sub_req_lookup_uri (const char *new_file, const request_rec *r); -request_rec *sub_req_lookup_file (const char *new_file, const request_rec *r); -int run_sub_req (request_rec *r); -void destroy_sub_req (request_rec *r); - -/* - * Then there's the case that you want some other request to be served - * as the top-level request INSTEAD of what the client requested directly. - * If so, call this from a handler, and then immediately return OK. - */ - -void internal_redirect (const char *new_uri, request_rec *); -void internal_redirect_handler (const char *new_uri, request_rec *); -int some_auth_required (request_rec *r); - -#ifdef CORE_PRIVATE -/* Function called by main.c to handle first-level request */ -void process_request (request_rec *); -int default_handler (request_rec *); -#endif diff --git a/usr.sbin/httpd/src/httpd.h b/usr.sbin/httpd/src/httpd.h deleted file mode 100644 index 33bb73cd645..00000000000 --- a/usr.sbin/httpd/src/httpd.h +++ /dev/null @@ -1,766 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * httpd.h: header for simple (ha! not anymore) http daemon - */ - -/* Headers in which EVERYONE has an interest... */ - -#include "conf.h" -#include "alloc.h" -#include "buff.h" - -/* ----------------------------- config dir ------------------------------ */ - -/* Define this to be the default server home dir. Anything later in this - * file with a relative pathname will have this added. - */ -#ifndef HTTPD_ROOT -#ifdef __EMX__ -/* Set default for OS/2 file system */ -#define HTTPD_ROOT "/os2httpd" -#else -#define HTTPD_ROOT "/var/www" -#endif -#endif - -#ifndef DOCUMENT_LOCATION -/* Root of server */ -#ifdef __EMX__ -/* Set default for OS/2 file system */ -#define DOCUMENT_LOCATION "/os2httpd/docs" -#else -#define DOCUMENT_LOCATION "/var/www/htdocs" -#endif -#endif - -/* Max. number of dynamically loaded modules */ -#define DYNAMIC_MODULE_LIMIT 64 - -/* Default administrator's address */ -#define DEFAULT_ADMIN "[no address given]" - -/* - * --------- You shouldn't have to edit anything below this line ---------- - * - * Any modifications to any defaults not defined above should be done in the - * respective config. file. - * - */ - - -/* -------------- Port number for server running standalone --------------- */ - -#define DEFAULT_PORT 80 - -/* --------- Default user name and group name running standalone ---------- */ -/* --- These may be specified as numbers by placing a # before a number --- */ - -#ifndef DEFAULT_USER -#define DEFAULT_USER "#-1" -#endif -#ifndef DEFAULT_GROUP -#define DEFAULT_GROUP "#-1" -#endif - -/* The name of the log files */ -#ifndef DEFAULT_XFERLOG -#ifdef __EMX__ -/* Set default for OS/2 file system */ -#define DEFAULT_XFERLOG "logs/access.log" -#else -#define DEFAULT_XFERLOG "logs/access_log" -#endif -#endif /* DEFAULT_XFERLOG */ -#ifndef DEFAULT_ERRORLOG -#ifdef __EMX__ -/* Set default for OS/2 file system */ -#define DEFAULT_ERRORLOG "logs/error.log" -#else -#define DEFAULT_ERRORLOG "logs/error_log" -#endif -#endif /* DEFAULT_ERRORLOG */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG "logs/httpd.pid" -#endif -#ifndef DEFAULT_SCOREBOARD -#define DEFAULT_SCOREBOARD "logs/apache_runtime_status" -#endif -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE "logs/accept.lock" -#endif - -/* Define this to be what your HTML directory content files are called */ -#define DEFAULT_INDEX "index.html" - -/* Define this to 1 if you want fancy indexing, 0 otherwise */ -#define DEFAULT_INDEXING 0 - -/* Define this to be what type you'd like returned for files with unknown */ -/* suffixes */ -#define DEFAULT_TYPE "text/plain" - -/* Define this to be what your per-directory security files are called */ -#ifdef __EMX__ -/* Set default for OS/2 file system */ -#define DEFAULT_ACCESS_FNAME "htaccess" -#else -#define DEFAULT_ACCESS_FNAME ".htaccess" -#endif - -/* The name of the server config file */ -#ifndef SERVER_CONFIG_FILE -#define SERVER_CONFIG_FILE "conf/httpd.conf" -#endif - -#ifndef RESOURCE_CONFIG_FILE -/* The name of the document config file */ -#define RESOURCE_CONFIG_FILE "conf/srm.conf" -#endif - -#ifndef TYPES_CONFIG_FILE -/* The name of the MIME types file */ -#define TYPES_CONFIG_FILE "conf/mime.types" -#endif - -#ifndef ACCESS_CONFIG_FILE -/* The name of the access file */ -#define ACCESS_CONFIG_FILE "conf/access.conf" -#endif - -/* Whether we should enable rfc1413 identity checking */ -#define DEFAULT_RFC1413 0 -/* The default directory in user's home dir */ -#define DEFAULT_USER_DIR "public_html" - -/* The default path for CGI scripts if none is currently set */ -#ifndef DEFAULT_PATH -#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin" -#endif - -/* The path to the Bourne shell, for parsed docs */ -#ifndef SHELL_PATH -#ifdef __EMX__ -/* Set default for OS/2 file system */ -#define SHELL_PATH "CMD.EXE" -#else -#define SHELL_PATH "/bin/sh" -#endif -#endif - -/* The path to the suExec wrapper, can be overridden in Configuration */ -#ifndef SUEXEC_BIN -#define SUEXEC_BIN "/usr/local/etc/httpd/sbin/suexec" -#endif - -/* The default string lengths */ -#define MAX_STRING_LEN HUGE_STRING_LEN -#define HUGE_STRING_LEN 8192 - -/* The timeout for waiting for messages */ -#define DEFAULT_TIMEOUT 300 - -/* The timeout for waiting for keepalive timeout until next request */ -#define DEFAULT_KEEPALIVE_TIMEOUT 15 - -/* The number of requests to entertain per connection */ -#define DEFAULT_KEEPALIVE 100 - -/* The size of the server's internal read-write buffers */ -#define IOBUFSIZE 8192 - -/* Number of servers to spawn off by default --- also, if fewer than - * this free when the caretaker checks, it will spawn more. - */ -#define DEFAULT_START_DAEMON 5 - -/* Maximum number of *free* server processes --- more than this, and - * they will die off. - */ - -#define DEFAULT_MAX_FREE_DAEMON 10 - -/* Minimum --- fewer than this, and more will be created */ - -#define DEFAULT_MIN_FREE_DAEMON 5 - -/* Limit on the total --- clients will be locked out if more servers than - * this are needed. It is intended solely to keep the server from crashing - * when things get out of hand. - * - * We keep a hard maximum number of servers, for two reasons --- first off, - * in case something goes seriously wrong, we want to stop the fork bomb - * short of actually crashing the machine we're running on by filling some - * kernel table. Secondly, it keeps the size of the scoreboard file small - * enough that we can read the whole thing without worrying too much about - * the overhead. - */ -#ifndef HARD_SERVER_LIMIT -#define HARD_SERVER_LIMIT 256 -#endif - -/* Number of requests to try to handle in a single process. If <= 0, - * the children don't die off. That's the default here, since I'm still - * interested in finding and stanching leaks. - */ - -#define DEFAULT_MAX_REQUESTS_PER_CHILD 0 - -/* If you have altered Apache and wish to change the SERVER_VERSION - * identifier below, please keep to the HTTP specification. This states that - * the identification string should consist of product tokens with an optional - * slash and version designator. Sub-products which form a significant part - * of the application can be listed, separated by whitespace, by adding - * their product tokens to EXTRA_CFLAGS in the Configuration file like so. - * - * EXTRA_CFLAGS="-DSERVER_SUBVERSION="MrWidget/0.1-alpha" - * - * The tokens are listed in order of their significance for identifying the - * application. - * - * "Product tokens should be short and to the point -- use of them for - * advertizing or other non-essential information is explicitly forbidden." - * - * Example: "Apache/1.1.0 MrWidget/0.1-alpha" - */ - -#define SERVER_BASEVERSION "Apache/1.2.6" /* SEE COMMENTS ABOVE */ -#ifdef SERVER_SUBVERSION -#define SERVER_VERSION SERVER_BASEVERSION " " SERVER_SUBVERSION -#else -#define SERVER_VERSION SERVER_BASEVERSION -#endif - -/* Numeric release version identifier: major minor bugfix betaseq - * Always increases along the same track as the source branch. - */ -#define APACHE_RELEASE 1020600 - -#define SERVER_PROTOCOL "HTTP/1.1" -#define SERVER_SUPPORT "http://www.apache.org/" - -#define DECLINED -1 /* Module declines to handle */ -#define OK 0 /* Module has handled this stage. */ - - -/* ----------------------- HTTP Status Codes ------------------------- */ - -#define RESPONSE_CODES 38 - -#define HTTP_CONTINUE 100 -#define HTTP_SWITCHING_PROTOCOLS 101 -#define HTTP_OK 200 -#define HTTP_CREATED 201 -#define HTTP_ACCEPTED 202 -#define HTTP_NON_AUTHORITATIVE 203 -#define HTTP_NO_CONTENT 204 -#define HTTP_RESET_CONTENT 205 -#define HTTP_PARTIAL_CONTENT 206 -#define HTTP_MULTIPLE_CHOICES 300 -#define HTTP_MOVED_PERMANENTLY 301 -#define HTTP_MOVED_TEMPORARILY 302 -#define HTTP_SEE_OTHER 303 -#define HTTP_NOT_MODIFIED 304 -#define HTTP_USE_PROXY 305 -#define HTTP_BAD_REQUEST 400 -#define HTTP_UNAUTHORIZED 401 -#define HTTP_PAYMENT_REQUIRED 402 -#define HTTP_FORBIDDEN 403 -#define HTTP_NOT_FOUND 404 -#define HTTP_METHOD_NOT_ALLOWED 405 -#define HTTP_NOT_ACCEPTABLE 406 -#define HTTP_PROXY_AUTHENTICATION_REQUIRED 407 -#define HTTP_REQUEST_TIME_OUT 408 -#define HTTP_CONFLICT 409 -#define HTTP_GONE 410 -#define HTTP_LENGTH_REQUIRED 411 -#define HTTP_PRECONDITION_FAILED 412 -#define HTTP_REQUEST_ENTITY_TOO_LARGE 413 -#define HTTP_REQUEST_URI_TOO_LARGE 414 -#define HTTP_UNSUPPORTED_MEDIA_TYPE 415 -#define HTTP_INTERNAL_SERVER_ERROR 500 -#define HTTP_NOT_IMPLEMENTED 501 -#define HTTP_BAD_GATEWAY 502 -#define HTTP_SERVICE_UNAVAILABLE 503 -#define HTTP_GATEWAY_TIME_OUT 504 -#define HTTP_VERSION_NOT_SUPPORTED 505 -#define HTTP_VARIANT_ALSO_VARIES 506 - -#define DOCUMENT_FOLLOWS HTTP_OK -#define PARTIAL_CONTENT HTTP_PARTIAL_CONTENT -#define MULTIPLE_CHOICES HTTP_MULTIPLE_CHOICES -#define MOVED HTTP_MOVED_PERMANENTLY -#define REDIRECT HTTP_MOVED_TEMPORARILY -#define USE_LOCAL_COPY HTTP_NOT_MODIFIED -#define BAD_REQUEST HTTP_BAD_REQUEST -#define AUTH_REQUIRED HTTP_UNAUTHORIZED -#define FORBIDDEN HTTP_FORBIDDEN -#define NOT_FOUND HTTP_NOT_FOUND -#define METHOD_NOT_ALLOWED HTTP_METHOD_NOT_ALLOWED -#define NOT_ACCEPTABLE HTTP_NOT_ACCEPTABLE -#define LENGTH_REQUIRED HTTP_LENGTH_REQUIRED -#define PRECONDITION_FAILED HTTP_PRECONDITION_FAILED -#define SERVER_ERROR HTTP_INTERNAL_SERVER_ERROR -#define NOT_IMPLEMENTED HTTP_NOT_IMPLEMENTED -#define BAD_GATEWAY HTTP_BAD_GATEWAY -#define VARIANT_ALSO_VARIES HTTP_VARIANT_ALSO_VARIES - -#define is_HTTP_INFO(x) (((x) >= 100)&&((x) < 200)) -#define is_HTTP_SUCCESS(x) (((x) >= 200)&&((x) < 300)) -#define is_HTTP_REDIRECT(x) (((x) >= 300)&&((x) < 400)) -#define is_HTTP_ERROR(x) (((x) >= 400)&&((x) < 600)) -#define is_HTTP_CLIENT_ERROR(x) (((x) >= 400)&&((x) < 500)) -#define is_HTTP_SERVER_ERROR(x) (((x) >= 500)&&((x) < 600)) - -#define status_drops_connection(x) (((x) == HTTP_BAD_REQUEST) || \ - ((x) == HTTP_REQUEST_TIME_OUT) || \ - ((x) == HTTP_LENGTH_REQUIRED) || \ - ((x) == HTTP_REQUEST_ENTITY_TOO_LARGE) || \ - ((x) == HTTP_REQUEST_URI_TOO_LARGE) || \ - ((x) == HTTP_INTERNAL_SERVER_ERROR) || \ - ((x) == HTTP_SERVICE_UNAVAILABLE)) - - -#define METHODS 8 -#define M_GET 0 -#define M_PUT 1 -#define M_POST 2 -#define M_DELETE 3 -#define M_CONNECT 4 -#define M_OPTIONS 5 -#define M_TRACE 6 -#define M_INVALID 7 - -#define CGI_MAGIC_TYPE "application/x-httpd-cgi" -#define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html" -#define INCLUDES_MAGIC_TYPE3 "text/x-server-parsed-html3" -#define MAP_FILE_MAGIC_TYPE "application/x-type-map" -#define ASIS_MAGIC_TYPE "httpd/send-as-is" -#define DIR_MAGIC_TYPE "httpd/unix-directory" -#define STATUS_MAGIC_TYPE "application/x-httpd-status" - -/* Just in case your linefeed isn't the one the other end is expecting. */ -#define LF 10 -#define CR 13 - -/* Possible values for request_rec.read_body (set by handling module): - * REQUEST_NO_BODY Send 413 error if message has any body - * REQUEST_CHUNKED_ERROR Send 411 error if body without Content-Length - * REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me. - * REQUEST_CHUNKED_PASS Pass the chunks to me without removal. - */ -#define REQUEST_NO_BODY 0 -#define REQUEST_CHUNKED_ERROR 1 -#define REQUEST_CHUNKED_DECHUNK 2 -#define REQUEST_CHUNKED_PASS 3 - -/* Things which may vary per file-lookup WITHIN a request --- - * e.g., state of MIME config. Basically, the name of an object, info - * about the object, and any other info we may ahve which may need to - * change as we go poking around looking for it (e.g., overridden by - * .htaccess files). - * - * Note how the default state of almost all these things is properly - * zero, so that allocating it with pcalloc does the right thing without - * a whole lot of hairy initialization... so long as we are willing to - * make the (fairly) portable assumption that the bit pattern of a NULL - * pointer is, in fact, zero. - */ - -/* This represents the result of calling htaccess; these are cached for - * each request. - */ -struct htaccess_result -{ - char *dir; /* the directory to which this applies */ - int override; /* the overrides allowed for the .htaccess file */ - void *htaccess; /* the configuration directives */ -/* the next one, or NULL if no more; N.B. never change this */ - const struct htaccess_result *next; -}; - - -typedef struct conn_rec conn_rec; -typedef struct server_rec server_rec; -typedef struct request_rec request_rec; -typedef struct listen_rec listen_rec; - -struct request_rec { - - pool *pool; - conn_rec *connection; - server_rec *server; - - request_rec *next; /* If we wind up getting redirected, - * pointer to the request we redirected to. - */ - request_rec *prev; /* If this is an internal redirect, - * pointer to where we redirected *from*. - */ - - request_rec *main; /* If this is a sub_request (see request.h) - * pointer back to the main request. - */ - - /* Info about the request itself... we begin with stuff that only - * protocol.c should ever touch... - */ - - char *the_request; /* First line of request, so we can log it */ - int assbackwards; /* HTTP/0.9, "simple" request */ - int proxyreq; /* A proxy request */ - int header_only; /* HEAD request, as opposed to GET */ - char *protocol; /* Protocol, as given to us, or HTTP/0.9 */ - int proto_num; /* Number version of protocol; 1.1 = 1001 */ - char *hostname; /* Host, as set by full URI or Host: */ - int hostlen; /* Length of http://host:port in full URI */ - - time_t request_time; /* When the request started */ - - char *status_line; /* Status line, if set by script */ - int status; /* In any case */ - - /* Request method, two ways; also, protocol, etc.. Outside of protocol.c, - * look, but don't touch. - */ - - char *method; /* GET, HEAD, POST, etc. */ - int method_number; /* M_GET, M_POST, etc. */ - int allowed; /* Allowed methods - for 405, OPTIONS, etc */ - - int sent_bodyct; /* byte count in stream is for body */ - long bytes_sent; /* body byte count, for easy access */ - - /* HTTP/1.1 connection-level features */ - - int chunked; /* sending chunked transfer-coding */ - int byterange; /* number of byte ranges */ - char *boundary; /* multipart/byteranges boundary */ - char *range; /* The Range: header */ - long clength; /* The "real" content length */ - - long remaining; /* bytes left to read */ - long read_length; /* bytes that have been read */ - int read_body; /* how the request body should be read */ - int read_chunked; /* reading chunked transfer-coding */ - - /* MIME header environments, in and out. Also, an array containing - * environment variables to be passed to subprocesses, so people can - * write modules to add to that environment. - * - * The difference between headers_out and err_headers_out is that the - * latter are printed even on error, and persist across internal redirects - * (so the headers printed for ErrorDocument handlers will have them). - * - * The 'notes' table is for notes from one module to another, with no - * other set purpose in mind... - */ - - table *headers_in; - table *headers_out; - table *err_headers_out; - table *subprocess_env; - table *notes; - - char *content_type; /* Break these out --- we dispatch on 'em */ - char *handler; /* What we *really* dispatch on */ - - char *content_encoding; - char *content_language; /* for back-compat. only -- do not use */ - array_header *content_languages; /* array of (char*) */ - - int no_cache; - int no_local_copy; - - /* What object is being requested (either directly, or via include - * or content-negotiation mapping). - */ - - char *uri; /* complete URI for a proxy req, or - URL path for a non-proxy req */ - char *filename; - char *path_info; - char *args; /* QUERY_ARGS, if any */ - struct stat finfo; /* ST_MODE set to zero if no such file */ - - /* Various other config info which may change with .htaccess files - * These are config vectors, with one void* pointer for each module - * (the thing pointed to being the module's business). - */ - - void *per_dir_config; /* Options set in config files, etc. */ - void *request_config; /* Notes on *this* request */ - -/* - * a linked list of the configuration directives in the .htaccess files - * accessed by this request. - * N.B. always add to the head of the list, _never_ to the end. - * that way, a sub request's list can (temporarily) point to a parent's list - */ - const struct htaccess_result *htaccess; -}; - - -/* Things which are per connection - */ - -struct conn_rec { - - pool *pool; - server_rec *server; - server_rec *base_server; /* Physical vhost this conn come in on */ - - /* Information about the connection itself */ - - int child_num; /* The number of the child handling conn_rec */ - BUFF *client; /* Connetion to the guy */ - int aborted; /* Are we still talking? */ - - /* Who is the client? */ - - struct sockaddr_in local_addr; /* local address */ - struct sockaddr_in remote_addr;/* remote address */ - char *remote_ip; /* Client's IP address */ - char *remote_host; /* Client's DNS name, if known. - * NULL if DNS hasn't been checked, - * "" if it has and no address was found. - * N.B. Only access this though - * get_remote_host() */ - char *remote_logname; /* Only ever set if doing rfc1413 lookups. - * N.B. Only access this through - * get_remote_logname() */ - char *user; /* If an authentication check was made, - * this gets set to the user name. We assume - * that there's only one user per connection(!) - */ - char *auth_type; /* Ditto. */ - - int keepalive; /* Are we using HTTP Keep-Alive? */ - int keptalive; /* Did we use HTTP Keep-Alive? */ - int keepalives; /* How many times have we used it? */ -}; - -/* Per-vhost config... */ - -/* The address 255.255.255.255, when used as a virtualhost address, - * will become the "default" server when the ip doesn't match other vhosts. - */ -#define DEFAULT_VHOST_ADDR 0xfffffffful - -typedef struct server_addr_rec server_addr_rec; -struct server_addr_rec { - server_addr_rec *next; - struct in_addr host_addr; /* The bound address, for this server */ - unsigned short host_port; /* The bound port, for this server */ - char *virthost; /* The name given in <VirtualHost> */ -}; - - -struct server_rec { - - server_rec *next; - - /* Full locations of server config info */ - - char *srm_confname; - char *access_confname; - - /* Contact information */ - - char *server_admin; - char *server_hostname; - unsigned short port; /* for redirects, etc. */ - - /* Log files --- note that transfer log is now in the modules... */ - - char *error_fname; - FILE *error_log; - - /* Module-specific configuration for server, and defaults... */ - - int is_virtual; /* true if this is the virtual server */ - void *module_config; /* Config vector containing pointers to - * modules' per-server config structures. - */ - void *lookup_defaults; /* MIME type info, etc., before we start - * checking per-directory info. - */ - /* Transaction handling */ - - server_addr_rec *addrs; - int timeout; /* Timeout, in seconds, before we give up */ - int keep_alive_timeout; /* Seconds we'll wait for another request */ - int keep_alive_max; /* Maximum requests per connection */ - int keep_alive; /* Use persistent connections? */ - int send_buffer_size; /* size of TCP send buffer (in bytes) */ - - char *path; /* Pathname for ServerPath */ - int pathlen; /* Length of path */ - - char *names; /* Wildcarded names for ServerAlias servers */ - - uid_t server_uid; /* effective user id when calling exec wrapper */ - gid_t server_gid; /* effective group id when calling exec wrapper */ -}; - -/* These are more like real hosts than virtual hosts */ -struct listen_rec { - listen_rec *next; - struct sockaddr_in local_addr; /* local IP address and port */ - int fd; - int used; /* Only used during restart */ -/* more stuff here, like which protocol is bound to the port */ -}; - -/* Prototypes for utilities... util.c. - */ - -/* Time */ -extern const char month_snames[12][4]; - -struct tm *get_gmtoff(int *tz); -char *get_time(); -char *ht_time (pool *p, time_t t, const char *fmt, int gmt); -char *gm_timestr_822(pool *p, time_t t); - -/* String handling. The *_nc variants allow you to use non-const char **s as -arguments (unfortunately C won't automatically convert a char ** to a const -char **) */ - -char *getword(pool *p, const char **line, char stop); -char *getword_nc(pool *p, char **line, char stop); -char *getword_white(pool *p, const char **line); -char *getword_white_nc(pool *p, char **line); -char *getword_nulls (pool *p, const char **line, char stop); -char *getword_nulls_nc (pool *p, char **line, char stop); -char *getword_conf (pool *p, const char **line); -char *getword_conf_nc (pool *p, char **line); - -char *get_token (pool *p, char **accept_line, int accept_white); -int find_token (pool *p, const char *line, const char *tok); -int find_last_token (pool *p, const char *line, const char *tok); - -int is_url(const char *u); -extern int unescape_url(char *url); -void no2slash(char *name); -void getparents(char *name); -char *escape_path_segment(pool *p, const char *s); -char *os_escape_path(pool *p,const char *path,int partial); -#define escape_uri(ppool,path) os_escape_path(ppool,path,1) -extern char *escape_html(pool *p, const char *s); -char *construct_server(pool *p, const char *hostname, unsigned port); -char *construct_url (pool *p, const char *path, const server_rec *s); -char *escape_shell_cmd (pool *p, const char *s); - -int count_dirs(const char *path); -char *make_dirstr(pool *a, const char *s, int n); -char *make_full_path(pool *a, const char *dir, const char *f); - -int is_matchexp(const char *str); -int strcmp_match(const char *str, const char *exp); -int strcasecmp_match(const char *str, const char *exp); -char *uudecode (pool *, const char *); - -char *pregsub(pool *p, const char *input, const char *source, - size_t nmatch, regmatch_t pmatch[]); - -void str_tolower (char *); -int ind (const char *, char); /* Sigh... */ -int rind (const char *, char); - -int cfg_getline(char *s, int n, FILE *f); - -#ifdef NEED_STRERROR -char *strerror (int err); -#endif - -/* Misc system hackery */ - -uid_t uname2id(const char *name); -gid_t gname2id(const char *name); -int is_directory(const char *name); -int can_exec(const struct stat *); -void chdir_file(const char *file); - -char *get_local_host(pool *); -unsigned long get_virthost_addr (const char *hostname, unsigned short *port); - -extern time_t restart_time; - -/* - * Apache tries to keep all of its long term filehandles (such as log files, - * and sockets) above this number. This is to workaround problems in many - * third party libraries that are compiled with a small FD_SETSIZE. There - * should be no reason to lower this, because it's only advisory. If a file - * can't be allocated above this number then it will remain in the "slack" - * area. - * - * Only the low slack line is used by default. If HIGH_SLACK_LINE is defined - * then an attempt is also made to keep all non-FILE * files above the high - * slack line. This is to work around a Solaris C library limitation, where it - * uses an unsigned char to store the file descriptor. - */ -#ifndef LOW_SLACK_LINE -#define LOW_SLACK_LINE 15 -#endif -/* #define HIGH_SLACK_LINE 255 */ - -/* - * The ap_slack() function takes a fd, and tries to move it above the indicated - * line. It returns an fd which may or may not have moved above the line, and - * never fails. If the high line was requested and it fails it will also try - * the low line. - */ -int ap_slack (int fd, int line); -#define AP_SLACK_LOW 1 -#define AP_SLACK_HIGH 2 diff --git a/usr.sbin/httpd/src/md5.h b/usr.sbin/httpd/src/md5.h deleted file mode 100644 index a8ff86c4bd0..00000000000 --- a/usr.sbin/httpd/src/md5.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This is work is derived from material Copyright RSA Data Security, Inc. - * - * The RSA copyright statement and Licence for that original material is - * included below. This is followed by the Apache copyright statement and - * licence for the modifications made to that material. - */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - - -/* MD5.H - header file for MD5C.C */ - -/* UINT4 defines a four byte word */ -typedef unsigned int UINT4; - -/* 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; - -extern void MD5Init(MD5_CTX *context); -extern void MD5Update(MD5_CTX *context, const unsigned char *input, - unsigned int inputLen); -extern void MD5Final(unsigned char digest[16], MD5_CTX *context); diff --git a/usr.sbin/httpd/src/md5c.c b/usr.sbin/httpd/src/md5c.c deleted file mode 100644 index fd42bcb456e..00000000000 --- a/usr.sbin/httpd/src/md5c.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * This is work is derived from material Copyright RSA Data Security, Inc. - * - * The RSA copyright statement and Licence for that original material is - * included below. This is followed by the Apache copyright statement and - * licence for the modifications made to that material. - */ - -/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#include <string.h> - -#include "md5.h" - -/* Constants for MD5Transform routine. - */ - -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -static void MD5Transform(UINT4 state[4], const unsigned char block[64]); -static void Encode(unsigned char *output, const UINT4 *input, - unsigned int len); -static void Decode(UINT4 *output, const unsigned char *input, - unsigned int len); - -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, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. -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); \ - } - -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -void -MD5Init(MD5_CTX *context) -{ - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* MD5 block update operation. Continues an MD5 message-digest - operation, processing another message block, and updating the - context. - */ -void -MD5Update(MD5_CTX *context, const unsigned char *input, unsigned int inputLen) -{ - unsigned int i, index, partLen; - - /* Compute number of bytes mod 64 */ - 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; - - /* Transform as many times as possible. */ - if (inputLen >= partLen) - { - memcpy(&context->buffer[index], input, partLen); - MD5Transform(context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform(context->state, &input[i]); - - index = 0; - } - else - i = 0; - - /* Buffer remaining input */ - memcpy(&context->buffer[index], &input[i], inputLen-i); -} - -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - the message digest and zeroizing the context. - */ -void -MD5Final(unsigned char digest[16], MD5_CTX *context) -{ - unsigned char bits[8]; - unsigned int index, padLen; - - /* Save number of bits */ - Encode (bits, context->count, 8); - - /* Pad out to 56 mod 64. */ - index = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (index < 56) ? (56 - index) : (120 - index); - MD5Update(context, PADDING, padLen); - - /* Append length (before padding) */ - MD5Update(context, bits, 8); - - /* Store state in digest */ - Encode(digest, context->state, 16); - - /* Zeroize sensitive information. */ - memset(context, 0, sizeof (*context)); -} - -/* MD5 basic transformation. Transforms state based on block. */ -static void -MD5Transform(UINT4 state[4], const unsigned char block[64]) -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. */ - memset(x, 0, sizeof (x)); -} - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void -Encode(unsigned char *output, const UINT4 *input, unsigned int len) -{ - unsigned int i, j; - UINT4 k; - - for (i = 0, j = 0; j < len; i++, j += 4) - { - k = input[i]; - output[j] = (unsigned char)(k & 0xff); - output[j+1] = (unsigned char)((k >> 8) & 0xff); - output[j+2] = (unsigned char)((k >> 16) & 0xff); - output[j+3] = (unsigned char)((k >> 24) & 0xff); - } -} - -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. - */ -static void -Decode(UINT4 *output, const unsigned char *input, unsigned int len) -{ - 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); -} diff --git a/usr.sbin/httpd/src/mod_access.c b/usr.sbin/httpd/src/mod_access.c deleted file mode 100644 index eb352380123..00000000000 --- a/usr.sbin/httpd/src/mod_access.c +++ /dev/null @@ -1,283 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * Security options etc. - * - * Module derived from code originally written by Rob McCool - * - */ - -#include "httpd.h" -#include "http_core.h" -#include "http_config.h" -#include "http_log.h" -#include "http_request.h" - -typedef struct { - char *from; - int limited; -} allowdeny; - -/* things in the 'order' array */ -#define DENY_THEN_ALLOW 0 -#define ALLOW_THEN_DENY 1 -#define MUTUAL_FAILURE 2 - -typedef struct { - int order[METHODS]; - array_header *allows; - array_header *denys; -} access_dir_conf; - -module access_module; - -void *create_access_dir_config (pool *p, char *dummy) -{ - access_dir_conf *conf = - (access_dir_conf *)pcalloc(p, sizeof(access_dir_conf)); - int i; - - for (i = 0; i < METHODS; ++i) conf->order[i] = DENY_THEN_ALLOW; - conf->allows = make_array (p, 1, sizeof (allowdeny)); - conf->denys = make_array (p, 1, sizeof (allowdeny)); - - return (void *)conf; -} - -const char *order (cmd_parms *cmd, void *dv, char *arg) -{ - access_dir_conf *d = (access_dir_conf *)dv; - int i, order; - - if (!strcasecmp (arg, "allow,deny")) order = ALLOW_THEN_DENY; - else if (!strcasecmp (arg, "deny,allow")) order = DENY_THEN_ALLOW; - else if (!strcasecmp (arg, "mutual-failure")) order = MUTUAL_FAILURE; - else return "unknown order"; - - for (i = 0; i < METHODS; ++i) - if (cmd->limited & (1 << i)) - d->order[i] = order; - - return NULL; -} - -const char *allow_cmd (cmd_parms *cmd, void *dv, char *from, char *where) -{ - access_dir_conf *d = (access_dir_conf *)dv; - allowdeny *a; - - if (strcasecmp (from, "from")) - return "allow and deny must be followed by 'from'"; - - a = (allowdeny *)push_array (cmd->info ? d->allows : d->denys); - a->from = pstrdup (cmd->pool, where); - a->limited = cmd->limited; - return NULL; -} - -static char its_an_allow; - -command_rec access_cmds[] = { -{ "order", order, NULL, OR_LIMIT, TAKE1, - "'allow,deny', 'deny,allow', or 'mutual-failure'" }, -{ "allow", allow_cmd, &its_an_allow, OR_LIMIT, ITERATE2, - "'from' followed by hostnames or IP-address wildcards" }, -{ "deny", allow_cmd, NULL, OR_LIMIT, ITERATE2, - "'from' followed by hostnames or IP-address wildcards" }, -{NULL} -}; - -int in_domain(const char *domain, const char *what) { - int dl=strlen(domain); - int wl=strlen(what); - - if((wl-dl) >= 0) { - if (strcasecmp(domain,&what[wl-dl]) != 0) return 0; - - /* Make sure we matched an *entire* subdomain --- if the user - * said 'allow from good.com', we don't want people from nogood.com - * to be able to get in. - */ - - if (wl == dl) return 1; /* matched whole thing */ - else return (domain[0] == '.' || what[wl - dl - 1] == '.'); - } else - return 0; -} - -int in_ip(char *domain, char *what) { - - /* Check a similar screw case to the one checked above --- - * "allow from 204.26.2" shouldn't let in people from 204.26.23 - */ - - int l = strlen(domain); - if (strncmp(domain,what,l) != 0) return 0; - if (domain[l - 1] == '.') return 1; - return (what[l] == '\0' || what[l] == '.'); -} - -static int is_ip(const char *host) -{ - while ((*host == '.') || isdigit(*host)) - host++; - return (*host == '\0'); -} - -int find_allowdeny (request_rec *r, array_header *a, int method) -{ - allowdeny *ap = (allowdeny *)a->elts; - int mmask = (1 << method); - int i; - int gothost = 0; - const char *remotehost = NULL; - - for (i = 0; i < a->nelts; ++i) { - if (!(mmask & ap[i].limited)) - continue; - - if (!strncmp(ap[i].from,"env=",4) && table_get(r->subprocess_env,ap[i].from+4)) - return 1; - - if (ap[i].from && !strcmp(ap[i].from, "user-agents")) { - char * this_agent = table_get(r->headers_in, "User-Agent"); - int j; - - if (!this_agent) return 0; - - for (j = i+1; j < a->nelts; ++j) { - if (strstr(this_agent, ap[j].from)) return 1; - } - return 0; - } - - if (!strcmp (ap[i].from, "all")) - return 1; - - if (!gothost) { - remotehost = get_remote_host(r->connection, r->per_dir_config, - REMOTE_HOST); - - if ((remotehost == NULL) || is_ip(remotehost)) - gothost = 1; - else - gothost = 2; - } - - if ((gothost == 2) && in_domain(ap[i].from, remotehost)) - return 1; - - if (in_ip (ap[i].from, r->connection->remote_ip)) - return 1; - } - - return 0; -} - -int check_dir_access (request_rec *r) -{ - int method = r->method_number; - access_dir_conf *a = - (access_dir_conf *) - get_module_config (r->per_dir_config, &access_module); - int ret = OK; - - if (a->order[method] == ALLOW_THEN_DENY) { - ret = FORBIDDEN; - if (find_allowdeny (r, a->allows, method)) - ret = OK; - if (find_allowdeny (r, a->denys, method)) - ret = FORBIDDEN; - } else if (a->order[method] == DENY_THEN_ALLOW) { - if (find_allowdeny (r, a->denys, method)) - ret = FORBIDDEN; - if (find_allowdeny (r, a->allows, method)) - ret = OK; - } - else { - if (find_allowdeny(r, a->allows, method) - && !find_allowdeny(r, a->denys, method)) - ret = OK; - else - ret = FORBIDDEN; - } - - if (ret == FORBIDDEN && ( - satisfies(r) != SATISFY_ANY || !some_auth_required(r) - )) { - log_reason ("Client denied by server configuration", r->filename, r); - } - - return ret; -} - - - -module access_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_access_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - access_cmds, - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - check_dir_access, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_actions.c b/usr.sbin/httpd/src/mod_actions.c deleted file mode 100644 index 570147069ed..00000000000 --- a/usr.sbin/httpd/src/mod_actions.c +++ /dev/null @@ -1,219 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_actions.c: executes scripts based on MIME type - * - * by Alexei Kosut; based on mod_cgi.c, mod_mime.c and mod_includes.c, - * adapted by rst from original NCSA code by Rob McCool - * - * Usage instructions: - * - * Action mime/type /cgi-bin/script - * - * will activate /cgi-bin/script when a file of content type mime/type is - * requested. It sends the URL and file path of the requested document using - * the standard CGI PATH_INFO and PATH_TRANSLATED environment variables. - * - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_log.h" -#include "util_script.h" - -typedef struct { - table *action_types; /* Added with Action... */ - char *get; /* Added with Script GET */ - char *post; /* Added with Script POST */ - char *put; /* Added with Script PUT */ - char *delete; /* Added with Script DELETE */ -} action_dir_config; - -module action_module; - -void *create_action_dir_config (pool *p, char *dummy) -{ - action_dir_config *new = - (action_dir_config *) palloc (p, sizeof(action_dir_config)); - - new->action_types = make_table (p, 4); - new->get = NULL; - new->post = NULL; - new->put = NULL; - new->delete = NULL; - - return new; -} - -void *merge_action_dir_configs (pool *p, void *basev, void *addv) -{ - action_dir_config *base = (action_dir_config *)basev; - action_dir_config *add = (action_dir_config *)addv; - action_dir_config *new = - (action_dir_config *)palloc (p, sizeof(action_dir_config)); - - new->action_types = overlay_tables (p, add->action_types, - base->action_types); - - new->get = add->get ? add->get : base->get; - new->post = add->post ? add->post : base->post; - new->put = add->put ? add->put : base->put; - new->delete = add->delete ? add->delete : base->delete; - - return new; -} - -const char *add_action(cmd_parms *cmd, action_dir_config *m, char *type, - char *script) -{ - table_set (m->action_types, type, script); - return NULL; -} - -const char *set_script (cmd_parms *cmd, action_dir_config *m, char *method, - char *script) -{ - if (!strcmp(method, "GET")) - m->get = pstrdup(cmd->pool, script); - else if (!strcmp(method, "POST")) - m->post = pstrdup(cmd->pool, script); - else if (!strcmp(method, "PUT")) - m->put = pstrdup(cmd->pool, script); - else if (!strcmp(method, "DELETE")) - m->delete = pstrdup(cmd->pool, script); - else - return "Unknown method type for Script"; - - return NULL; -} - -command_rec action_cmds[] = { -{ "Action", add_action, NULL, OR_FILEINFO, TAKE2, - "a media type followed by a script name" }, -{ "Script", set_script, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, - "a method followed by a script name" }, -{ NULL } -}; - -int action_handler (request_rec *r) -{ - action_dir_config *conf = - (action_dir_config *)get_module_config(r->per_dir_config,&action_module); - char *t, *action = r->handler ? r->handler : r->content_type; - char *script = NULL; - - /* Set allowed stuff */ - if (conf->get) r->allowed |= (1 << M_GET); - if (conf->post) r->allowed |= (1 << M_POST); - if (conf->put) r->allowed |= (1 << M_PUT); - if (conf->delete) r->allowed |= (1 << M_DELETE); - - /* First, check for the method-handling scripts */ - if ((r->method_number == M_GET) && r->args && conf->get) - script = conf->get; - else if ((r->method_number == M_POST) && conf->post) - script = conf->post; - else if ((r->method_number == M_PUT) && conf->put) - script = conf->put; - else if ((r->method_number == M_DELETE) && conf->delete) - script = conf->delete; - - /* Check for looping, which can happen if the CGI script isn't */ - if (script && r->prev && r->prev->prev) - return DECLINED; - - /* Second, check for actions (which override the method scripts) */ - if ((t = table_get(conf->action_types, - action ? action : default_type(r)))) { - script = t; - if (r->finfo.st_mode == 0) { - log_reason("File does not exist", r->filename, r); - return NOT_FOUND; - } - } - - if (script == NULL) - return DECLINED; - - internal_redirect_handler(pstrcat(r->pool, script, escape_uri(r->pool, - r->uri), r->args ? "?" : NULL, r->args, NULL), r); - return OK; -} - -handler_rec action_handlers[] = { -{ "*/*", action_handler }, -{ NULL } -}; - -module action_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_action_dir_config, /* dir config creater */ - merge_action_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - action_cmds, /* command table */ - action_handlers, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_alias.c b/usr.sbin/httpd/src/mod_alias.c deleted file mode 100644 index 2d96fd713fd..00000000000 --- a/usr.sbin/httpd/src/mod_alias.c +++ /dev/null @@ -1,329 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_alias.c: Stuff for dealing with directory aliases - * - * Original by Rob McCool, rewritten in succession by David Robinson - * and rst. - * - */ - -#include "httpd.h" -#include "http_config.h" - -typedef struct { - char *real; - char *fake; - char *handler; - int redir_status; /* 301, 302, 303, 410, etc */ -} alias_entry; - -typedef struct { - array_header *aliases; - array_header *redirects; -} alias_server_conf; - -typedef struct { - array_header *redirects; -} alias_dir_conf; -module alias_module; - -void *create_alias_config (pool *p, server_rec *s) -{ - alias_server_conf *a = - (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf)); - - a->aliases = make_array (p, 20, sizeof(alias_entry)); - a->redirects = make_array (p, 20, sizeof(alias_entry)); - return a; -} - -void *create_alias_dir_config (pool *p, char *d) -{ - alias_dir_conf *a = - (alias_dir_conf *)pcalloc (p, sizeof(alias_dir_conf)); - a->redirects = make_array (p, 2, sizeof(alias_entry)); - return a; -} -void *merge_alias_config (pool *p, void *basev, void *overridesv) -{ - alias_server_conf *a = - (alias_server_conf *)pcalloc (p, sizeof(alias_server_conf)); - alias_server_conf *base = (alias_server_conf *)basev, - *overrides = (alias_server_conf *)overridesv; - - a->aliases = append_arrays (p, overrides->aliases, base->aliases); - a->redirects = append_arrays (p, overrides->redirects, base->redirects); - return a; -} - -void *merge_alias_dir_config (pool *p, void *basev, void *overridesv) -{ - alias_dir_conf *a = - (alias_dir_conf *)pcalloc (p, sizeof(alias_dir_conf)); - alias_dir_conf *base = (alias_dir_conf *)basev, - *overrides = (alias_dir_conf *)overridesv; - a->redirects = append_arrays (p, overrides->redirects, base->redirects); - return a; -} - -const char *add_alias(cmd_parms *cmd, void *dummy, char *f, char *r) -{ - server_rec *s = cmd->server; - alias_server_conf *conf = - (alias_server_conf *)get_module_config(s->module_config,&alias_module); - alias_entry *new = push_array (conf->aliases); - - /* XX r can NOT be relative to DocumentRoot here... compat bug. */ - - new->fake = f; new->real = r; new->handler = cmd->info; - return NULL; -} - -const char *add_redirect(cmd_parms *cmd, alias_dir_conf *dirconf, char *arg1, - char *arg2, char *arg3) -{ - alias_entry *new; - server_rec *s = cmd->server; - alias_server_conf *serverconf = - (alias_server_conf *)get_module_config(s->module_config,&alias_module); - int status = (int)cmd->info; - char *f = arg2; - char *url = arg3; - - if (!strcasecmp(arg1, "gone")) - status = HTTP_GONE; - else if (!strcasecmp(arg1, "permanent")) - status = HTTP_MOVED_PERMANENTLY; - else if (!strcasecmp(arg1, "temp")) - status = HTTP_MOVED_TEMPORARILY; - else if (!strcasecmp(arg1, "seeother")) - status = HTTP_SEE_OTHER; - else if (isdigit(*arg1)) - status = atoi(arg1); - else { - f = arg1; - url = arg2; - } - - if (is_HTTP_REDIRECT(status)) { - if (!url) return "URL to redirect to is missing"; - if (!is_url (url)) return "Redirect to non-URL"; - } - else { - if (url) return "Redirect URL not valid for this status"; - } - - if ( cmd->path ) - new = push_array (dirconf->redirects); - else - new = push_array (serverconf->redirects); - - new->fake = f; new->real = url; - new->redir_status = status; - return NULL; -} - -command_rec alias_cmds[] = { -{ "Alias", add_alias, NULL, RSRC_CONF, TAKE2, - "a fakename and a realname"}, -{ "ScriptAlias", add_alias, "cgi-script", RSRC_CONF, TAKE2, - "a fakename and a realname"}, -{ "Redirect", add_redirect, (void*)HTTP_MOVED_TEMPORARILY, - OR_FILEINFO, TAKE23, - "an optional status, then document to be redirected and destination URL" }, -{ "RedirectTemp", add_redirect, (void*)HTTP_MOVED_TEMPORARILY, - OR_FILEINFO, TAKE2, - "a document to be redirected, then the destination URL" }, -{ "RedirectPermanent", add_redirect, (void*)HTTP_MOVED_PERMANENTLY, - OR_FILEINFO, TAKE2, - "a document to be redirected, then the destination URL" }, -{ NULL } -}; - -int alias_matches (char *uri, char *alias_fakename) -{ - char *end_fakename = alias_fakename + strlen (alias_fakename); - char *aliasp = alias_fakename, *urip = uri; - - while (aliasp < end_fakename) { - if (*aliasp == '/') { - /* any number of '/' in the alias matches any number in - * the supplied URI, but there must be at least one... - */ - if (*urip != '/') return 0; - - while (*aliasp == '/') ++ aliasp; - while (*urip == '/') ++ urip; - } - else { - /* Other characters are compared literally */ - if (*urip++ != *aliasp++) return 0; - } - } - - /* Check last alias path component matched all the way */ - - if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/') - return 0; - - /* Return number of characters from URI which matched (may be - * greater than length of alias, since we may have matched - * doubled slashes) - */ - - return urip - uri; -} - -char *try_alias_list (request_rec *r, array_header *aliases, int doesc, int *status) -{ - alias_entry *entries = (alias_entry *)aliases->elts; - int i; - - for (i = 0; i < aliases->nelts; ++i) { - alias_entry *p = &entries[i]; - int l = alias_matches (r->uri, p->fake); - - if (l > 0) { - if (p->handler) { /* Set handler, and leave a note for mod_cgi */ - r->handler = pstrdup(r->pool, p->handler); - table_set (r->notes, "alias-forced-type", p->handler); - } - - *status = p->redir_status; - - if (doesc) { - char *escurl; - escurl = os_escape_path(r->pool, r->uri + l, 1); - - return pstrcat(r->pool, p->real, escurl, NULL); - } else - return pstrcat(r->pool, p->real, r->uri + l, NULL); - } - } - - return NULL; -} - -int translate_alias_redir(request_rec *r) -{ - void *sconf = r->server->module_config; - alias_server_conf *serverconf = - (alias_server_conf *)get_module_config(sconf, &alias_module); - char *ret; - int status; - -#ifdef __EMX__ - /* Add support for OS/2 drive names */ - if ((r->uri[0] != '/' && r->uri[0] != '\0') && r->uri[1] != ':') -#else - if (r->uri[0] != '/' && r->uri[0] != '\0') -#endif - return DECLINED; - - if ((ret = try_alias_list (r, serverconf->redirects, 1, &status)) != NULL) { - if (is_HTTP_REDIRECT(status)) { - /* include QUERY_STRING if any */ - if (r->args) { - ret = pstrcat (r->pool, ret, "?", r->args, NULL); - } - table_set (r->headers_out, "Location", ret); - } - return status; - } - - if ((ret = try_alias_list (r, serverconf->aliases, 0, &status)) != NULL) { - r->filename = ret; - return OK; - } - - return DECLINED; -} - -int fixup_redir(request_rec *r) -{ - void *dconf = r->per_dir_config; - alias_dir_conf *dirconf = - (alias_dir_conf *)get_module_config(dconf, &alias_module); - char *ret; - int status; - - /* It may have changed since last time, so try again */ - - if ((ret = try_alias_list (r, dirconf->redirects, 1, &status)) != NULL) { - if (is_HTTP_REDIRECT(status)) - table_set (r->headers_out, "Location", ret); - return status; - } - - return DECLINED; -} - -module alias_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_alias_dir_config, /* dir config creater */ - merge_alias_dir_config, /* dir merger --- default is to override */ - create_alias_config, /* server config */ - merge_alias_config, /* merge server configs */ - alias_cmds, /* command table */ - NULL, /* handlers */ - translate_alias_redir, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - fixup_redir, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_asis.c b/usr.sbin/httpd/src/mod_asis.c deleted file mode 100644 index 47bf206d137..00000000000 --- a/usr.sbin/httpd/src/mod_asis.c +++ /dev/null @@ -1,131 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_protocol.h" -#include "http_log.h" -#include "util_script.h" -#include "http_main.h" -#include "http_request.h" - -int asis_handler (request_rec *r) -{ - FILE *f; - char *location; - - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) return DECLINED; - if (r->finfo.st_mode == 0) { - log_reason("File does not exist", r->filename, r); - return NOT_FOUND; - } - - f = pfopen (r->pool, r->filename, "r"); - - if (f == NULL) { - log_reason("file permissions deny server access", r->filename, r); - return FORBIDDEN; - } - - scan_script_header (r, f); - location = table_get (r->headers_out, "Location"); - - if (location && location[0] == '/' && - ((r->status == HTTP_OK) || is_HTTP_REDIRECT(r->status))) { - - pfclose(r->pool, f); - - /* Internal redirect -- fake-up a pseudo-request */ - r->status = HTTP_OK; - - /* This redirect needs to be a GET no matter what the original - * method was. - */ - r->method = pstrdup(r->pool, "GET"); - r->method_number = M_GET; - - internal_redirect_handler (location, r); - return OK; - } - - send_http_header (r); - if (!r->header_only) send_fd (f, r); - - pfclose(r->pool, f); - return OK; -} - -handler_rec asis_handlers[] = { -{ ASIS_MAGIC_TYPE, asis_handler }, -{ "send-as-is", asis_handler }, -{ NULL } -}; - -module asis_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - NULL, /* command table */ - asis_handlers, /* handlers */ - NULL, /* translate_handler */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* pre-run fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_auth.c b/usr.sbin/httpd/src/mod_auth.c deleted file mode 100644 index acacaf07b2f..00000000000 --- a/usr.sbin/httpd/src/mod_auth.c +++ /dev/null @@ -1,298 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_auth: authentication - * - * Rob McCool - * - * Adapted to Apache by rst. - * - * dirkx - Added Authoritative control to allow passing on to lower - * modules if and only if the user-id is not known to this - * module. A known user with a faulty or absent password still - * causes an AuthRequired. The default is 'Authoritative', i.e. - * no control is passed along. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#if defined(HAVE_CRYPT_H) -#include <crypt.h> -#endif - -typedef struct auth_config_struct { - char *auth_pwfile; - char *auth_grpfile; - int auth_authoritative; -} auth_config_rec; - -void *create_auth_dir_config (pool *p, char *d) -{ - auth_config_rec *sec = - (auth_config_rec *) pcalloc (p, sizeof(auth_config_rec)); - sec->auth_pwfile = NULL; /* just to illustrate the default really */ - sec->auth_grpfile = NULL; /* unless you have a broken HP cc */ - sec->auth_authoritative = 1; /* keep the fortress secure by default */ - return sec; -} - -const char *set_auth_slot (cmd_parms *cmd, void *offset, char *f, char *t) -{ - if (t && strcmp(t, "standard")) - return pstrcat(cmd->pool, "Invalid auth file type: ", t, NULL); - - return set_string_slot(cmd, offset, f); -} - -command_rec auth_cmds[] = { -{ "AuthUserFile", set_auth_slot, - (void*)XtOffsetOf(auth_config_rec,auth_pwfile), OR_AUTHCFG, TAKE12, NULL }, -{ "AuthGroupFile", set_auth_slot, - (void*)XtOffsetOf(auth_config_rec,auth_grpfile), OR_AUTHCFG, TAKE12, NULL }, -{ "AuthAuthoritative", set_flag_slot, - (void*)XtOffsetOf(auth_config_rec,auth_authoritative), - OR_AUTHCFG, FLAG, - "Set to 'no' to allow access control to be passed along to lower modules if the UserID is not known to this module" }, -{ NULL } -}; - -module auth_module; - -char *get_pw(request_rec *r, char *user, char *auth_pwfile) -{ - FILE *f; - char l[MAX_STRING_LEN]; - const char *rpw, *w; - - if(!(f=pfopen(r->pool, auth_pwfile, "r"))) { - log_reason ("Could not open password file", auth_pwfile, r); - return NULL; - } - while(!(cfg_getline(l,MAX_STRING_LEN,f))) { - if((l[0] == '#') || (!l[0])) continue; - rpw = l; - w = getword(r->pool, &rpw, ':'); - - if(!strcmp(user,w)) { - pfclose(r->pool, f); - return pstrdup (r->pool, rpw); - } - } - pfclose(r->pool, f); - return NULL; -} - -table *groups_for_user (pool *p, char *user, char *grpfile) { - FILE *f; - table *grps = make_table (p, 15); - pool *sp; - char l[MAX_STRING_LEN]; - const char *group_name, *ll, *w; - - if(!(f=pfopen(p, grpfile, "r"))) - return NULL; - - sp = make_sub_pool (p); - - while(!(cfg_getline(l,MAX_STRING_LEN,f))) { - if((l[0] == '#') || (!l[0])) continue; - ll = l; - clear_pool (sp); - - group_name = getword(sp, &ll, ':'); - - while(ll[0]) { - w = getword_conf (sp, &ll); - if(!strcmp(w,user)) { - table_set (grps, group_name, "in"); - break; - } - } - } - pfclose(p, f); - destroy_pool (sp); - return grps; -} - -/* These functions return 0 if client is OK, and proper error status - * if not... either AUTH_REQUIRED, if we made a check, and it failed, or - * SERVER_ERROR, if things are so totally confused that we couldn't - * figure out how to tell if the client is authorized or not. - * - * If they return DECLINED, and all other modules also decline, that's - * treated by the server core as a configuration error, logged and - * reported as such. - */ - -/* Determine user ID, and check if it really is that user, for HTTP - * basic authentication... - */ - -int authenticate_basic_user (request_rec *r) -{ - auth_config_rec *sec = - (auth_config_rec *)get_module_config (r->per_dir_config, &auth_module); - conn_rec *c = r->connection; - char *sent_pw, *real_pw; - char errstr[MAX_STRING_LEN]; - int res; - - if ((res = get_basic_auth_pw (r, &sent_pw))) return res; - - if(!sec->auth_pwfile) - return DECLINED; - - if (!(real_pw = get_pw(r, c->user, sec->auth_pwfile))) { - if (!(sec->auth_authoritative)) - return DECLINED; - ap_snprintf(errstr, sizeof(errstr), "user %s not found",c->user); - log_reason (errstr, r->uri, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - /* anyone know where the prototype for crypt is? */ - if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) { - ap_snprintf(errstr, sizeof(errstr), "user %s: password mismatch",c->user); - log_reason (errstr, r->uri, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - return OK; -} - -/* Checking ID */ - -int check_user_access (request_rec *r) { - auth_config_rec *sec = - (auth_config_rec *)get_module_config (r->per_dir_config, &auth_module); - char *user = r->connection->user; - int m = r->method_number; - int method_restricted = 0; - register int x; - const char *t, *w; - table *grpstatus; - array_header *reqs_arr = requires (r); - require_line *reqs; - - /* BUG FIX: tadc, 11-Nov-1995. If there is no "requires" directive, - * then any user will do. - */ - if (!reqs_arr) - return (OK); - reqs = (require_line *)reqs_arr->elts; - - if(sec->auth_grpfile) - grpstatus = groups_for_user (r->pool, user, sec->auth_grpfile); - else - grpstatus = NULL; - - for(x=0; x < reqs_arr->nelts; x++) { - - if (! (reqs[x].method_mask & (1 << m))) continue; - - method_restricted = 1; - - t = reqs[x].requirement; - w = getword(r->pool, &t, ' '); - if(!strcmp(w,"valid-user")) - return OK; - if(!strcmp(w,"user")) { - while(t[0]) { - w = getword_conf (r->pool, &t); - if(!strcmp(user,w)) - return OK; - } - } - else if(!strcmp(w,"group")) { - if(!grpstatus) - return DECLINED; /* DBM group? Something else? */ - - while(t[0]) { - w = getword_conf(r->pool, &t); - if(table_get (grpstatus, w)) - return OK; - } - } - } - - if (!method_restricted) - return OK; - - if (!(sec -> auth_authoritative)) - return DECLINED; - - note_basic_auth_failure (r); - return AUTH_REQUIRED; -} - -module auth_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_auth_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - auth_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - authenticate_basic_user, /* check_user_id */ - check_user_access, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_auth_anon.c b/usr.sbin/httpd/src/mod_auth_anon.c deleted file mode 100644 index 2bb90b4d823..00000000000 --- a/usr.sbin/httpd/src/mod_auth_anon.c +++ /dev/null @@ -1,299 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_auth: authentication - * - * Rob McCool & Brian Behlendorf. - * - * Adapted to Apache by rst. - * - * Version 0.5 May 1996 - * - * Modified by Dirk.vanGulik@jrc.it to - * - * Adapted to allow anonymous logins, just like with Anon-FTP, when - * one gives the magic user name 'anonymous' and ones email address - * as the password. - * - * Just add the following tokes to your <directory> setup: - * - * Anonymous magic-user-id [magic-user-id]... - * - * Anonymous_MustGiveEmail [ on | off ] default = off - * Anonymous_LogEmail [ on | off ] default = on - * Anonymous_VerifyEmail [ on | off ] default = off - * Anonymous_NoUserId [ on | off ] default = off - * Anonymous_Authoritative [ on | off ] default = off - * - * The magic user id is something like 'anonymous', it is NOT case sensitive. - * - * The MustGiveEmail flag can be used to force users to enter something - * in the password field (like an email address). Default is off. - * - * Furthermore the 'NoUserID' flag can be set to allow completely empty - * usernames in as well; this can be is convenient as a single return - * in broken GUIs like W95 is often given by the user. The Default is off. - * - * Dirk.vanGulik@jrc.it; http://ewse.ceo.org; http://me-www.jrc.it/~dirkx - * - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" - -typedef struct auth_anon { - char *password; - struct auth_anon * next; - } auth_anon; - -typedef struct { - - auth_anon *auth_anon_passwords; - int auth_anon_nouserid; - int auth_anon_logemail; - int auth_anon_verifyemail; - int auth_anon_mustemail; - int auth_anon_authoritative; - -} anon_auth_config_rec; - -void *create_anon_auth_dir_config (pool *p, char *d) -{ - anon_auth_config_rec * sec = (anon_auth_config_rec *) - pcalloc (p, sizeof(anon_auth_config_rec)); - - if (!sec) return NULL; /* no memory... */ - - /* just to illustrate the defaults really. */ - sec -> auth_anon_passwords =NULL; - - sec -> auth_anon_nouserid =0; - sec -> auth_anon_logemail =1; - sec -> auth_anon_verifyemail =0; - sec -> auth_anon_mustemail =1; - sec -> auth_anon_authoritative =0; - return sec; -} - -const char *anon_set_passwd_flag (cmd_parms *cmd, - anon_auth_config_rec *sec, int arg) { - sec->auth_anon_mustemail=arg; - return NULL; -} - -const char *anon_set_userid_flag (cmd_parms *cmd, - anon_auth_config_rec *sec, int arg) { - sec->auth_anon_nouserid=arg; - return NULL; -} -const char *anon_set_logemail_flag (cmd_parms *cmd, - anon_auth_config_rec *sec, int arg) { - sec->auth_anon_logemail=arg; - return NULL; -} -const char *anon_set_verifyemail_flag (cmd_parms *cmd, - anon_auth_config_rec *sec, int arg) { - sec->auth_anon_verifyemail=arg; - return NULL; -} -const char *anon_set_authoritative_flag (cmd_parms *cmd, - anon_auth_config_rec *sec, int arg) { - sec->auth_anon_authoritative=arg; - return NULL; -} - -const char *anon_set_string_slots (cmd_parms *cmd, - anon_auth_config_rec *sec, char *arg) { - - auth_anon * first; - - if (!(*arg)) - return "Anonymous string cannot be empty, use Anonymous_NoUserId instead"; - - /* squeeze in a record */ - first = sec->auth_anon_passwords; - - if ( - (!(sec->auth_anon_passwords=(auth_anon *) palloc(cmd -> pool, sizeof(auth_anon)))) || - (!(sec->auth_anon_passwords->password = pstrdup(cmd -> pool, arg))) - ) return "Failed to claim memory for an anonymous password..."; - - /* and repair the next */ - sec->auth_anon_passwords->next = first; - - return NULL; -} - -command_rec anon_auth_cmds[] = { -{ "Anonymous", anon_set_string_slots, - NULL,OR_AUTHCFG, ITERATE, NULL }, -{ "Anonymous_MustGiveEmail", anon_set_passwd_flag, NULL, OR_AUTHCFG, FLAG, - "Limited to 'on' or 'off'" }, -{ "Anonymous_NoUserId", anon_set_userid_flag, NULL, OR_AUTHCFG, FLAG, - "Limited to 'on' or 'off'" }, -{ "Anonymous_VerifyEmail", anon_set_verifyemail_flag, NULL, OR_AUTHCFG, FLAG, - "Limited to 'on' or 'off'" }, -{ "Anonymous_LogEmail", anon_set_logemail_flag, NULL, OR_AUTHCFG, FLAG, - "Limited to 'on' or 'off'" }, -{ "Anonymous_Authoritative", anon_set_authoritative_flag, NULL, OR_AUTHCFG, FLAG, - "Limited to 'on' or 'off'" }, - -{ NULL } -}; - -module anon_auth_module; - -int anon_authenticate_basic_user (request_rec *r) -{ - anon_auth_config_rec *sec = - (anon_auth_config_rec *)get_module_config (r->per_dir_config, - &anon_auth_module); - conn_rec *c = r->connection; - char *send_pw; - char errstr[MAX_STRING_LEN]; - int res=DECLINED; - - - if ((res=get_basic_auth_pw (r,&send_pw))) - return res; - - /* Ignore if we are not configured */ - if (!sec->auth_anon_passwords) return DECLINED; - - /* Do we allow an empty userID and/or is it the magic one - */ - - if ( (!(c->user[0])) && (sec->auth_anon_nouserid) ) { - res=OK; - } else { - auth_anon *p=sec->auth_anon_passwords; - res=DECLINED; - while ((res == DECLINED) && (p !=NULL)) { - if (!(strcasecmp(c->user,p->password))) - res=OK; - p=p->next; - } - } - if ( - /* username is OK */ - (res == OK) && - /* password been filled out ? */ - ( (!sec->auth_anon_mustemail) || strlen(send_pw) ) && - /* does the password look like an email address ? */ - ( (!sec->auth_anon_verifyemail) || - ((strpbrk("@",send_pw) != NULL) - && - (strpbrk(".",send_pw) != NULL)) - ) - ) { - if (sec->auth_anon_logemail && r->prev == NULL && r->main == NULL) { - ap_snprintf(errstr, sizeof(errstr), "Anonymous: Passwd <%s> Accepted", - send_pw ? send_pw : "\'none\'"); - log_error (errstr, r->server ); - } - return OK; - } else { - if (sec->auth_anon_authoritative) { - ap_snprintf(errstr, sizeof(errstr), - "Anonymous: Authoritative, Passwd <%s> not accepted", - send_pw ? send_pw : "\'none\'"); - log_error(errstr,r->server); - return AUTH_REQUIRED; - } - /* Drop out the bottom to return DECLINED */ - } - - - return DECLINED; -} - -int check_anon_access (request_rec *r) { - -#ifdef NOTYET - conn_rec *c = r->connection; - anon_auth_config_rec *sec = - (anon_auth_config_rec *)get_module_config (r->per_dir_config, - &anon_auth_module); - - if (!sec->auth_anon) return DECLINED; - - if ( strcasecmp(r->connection->user,sec->auth_anon )) - return DECLINED; - - return OK; -#endif - return DECLINED; -} - - -module anon_auth_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_anon_auth_dir_config, /* dir config creater */ - NULL, /* dir merger ensure strictness */ - NULL, /* server config */ - NULL, /* merge server config */ - anon_auth_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - anon_authenticate_basic_user,/* check_user_id */ - check_anon_access, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_auth_db.c b/usr.sbin/httpd/src/mod_auth_db.c deleted file mode 100644 index 76d21d7ea6c..00000000000 --- a/usr.sbin/httpd/src/mod_auth_db.c +++ /dev/null @@ -1,303 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_auth_db: authentication - * - * Original work by Rob McCool & Brian Behlendorf. - * - * Adapted to Apache by rst (mod_auth_dbm) - * - * Adapted for Berkeley DB by Andrew Cohen - * - * mod_auth_db was based on mod_auth_dbm. - * - * Warning, this is not a drop in replacement for mod_auth_dbm, - * for people wanting to switch from dbm to Berkeley DB. - * It requires the use of AuthDBUserFile and AuthDBGroupFile - * instead of AuthDBMUserFile AuthDBMGroupFile - * - * Also, in the configuration file you need to specify - * db_auth_module rather than dbm_auth_module - * - * On some BSD systems (e.g. FreeBSD and NetBSD) dbm is automatically - * mapped to Berkeley DB. You can use either mod_auth_dbm or - * mod_auth_db. The latter makes it more obvious that it's Berkeley. - * - * dirkx - Added Authoritative control to allow passing on to lower - * modules if and only if the user-id is not known to this - * module. A known user with a faulty or absent password still - * causes an AuthRequired. The default is 'Authoritative', i.e. - * no control is passed along. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#include <db.h> - -typedef struct { - - char *auth_dbpwfile; - char *auth_dbgrpfile; - int auth_dbauthoritative; -} db_auth_config_rec; - -void *create_db_auth_dir_config (pool *p, char *d) -{ - db_auth_config_rec *sec - = (db_auth_config_rec *)pcalloc (p, sizeof(db_auth_config_rec)); - sec->auth_dbpwfile = NULL; - sec->auth_dbgrpfile = NULL; - sec->auth_dbauthoritative=1; /* fortress is secure by default */ - return sec; -} - -const char *set_db_slot (cmd_parms *cmd, void *offset, char *f, char *t) -{ - if (!t || strcmp(t, "db")) - return DECLINE_CMD; - - return set_string_slot(cmd, offset, f); -} - -command_rec db_auth_cmds[] = { -{ "AuthDBUserFile", set_string_slot, - (void*)XtOffsetOf(db_auth_config_rec, auth_dbpwfile), - OR_AUTHCFG, TAKE1, NULL }, -{ "AuthDBGroupFile", set_string_slot, - (void*)XtOffsetOf(db_auth_config_rec, auth_dbgrpfile), - OR_AUTHCFG, TAKE1, NULL }, -{ "AuthUserFile", set_db_slot, - (void*)XtOffsetOf(db_auth_config_rec, auth_dbpwfile), - OR_AUTHCFG, TAKE12, NULL }, -{ "AuthGroupFile", set_db_slot, - (void*)XtOffsetOf(db_auth_config_rec, auth_dbgrpfile), - OR_AUTHCFG, TAKE12, NULL }, -{ "AuthDBAuthoritative", set_flag_slot, - (void*)XtOffsetOf(db_auth_config_rec, auth_dbauthoritative), - OR_AUTHCFG, FLAG, - "Set to 'no' to allow access control to be passed along to lower modules if the userID is not known to this module" }, -{ NULL } -}; - -module db_auth_module; - -char *get_db_pw(request_rec *r, char *user, const char *auth_dbpwfile) { - DB *f; - DBT d, q; - char *pw = NULL; - - q.data = user; - q.size = strlen(q.data); - - if(!(f=dbopen(auth_dbpwfile,O_RDONLY,0664,DB_HASH,NULL))) { - log_reason ("could not open db auth file", (char *) auth_dbpwfile, r); - return NULL; - } - - if (!((f->get)(f,&q,&d,0))) { - pw = palloc (r->pool, d.size + 1); - strncpy(pw,d.data,d.size); - pw[d.size] = '\0'; /* Terminate the string */ - } - - (f->close)(f); - return pw; -} - -/* We do something strange with the group file. If the group file - * contains any : we assume the format is - * key=username value=":"groupname [":"anything here is ignored] - * otherwise we now (0.8.14+) assume that the format is - * key=username value=groupname - * The first allows the password and group files to be the same - * physical DB file; key=username value=password":"groupname[":"anything] - * - * mark@telescope.org, 22Sep95 - */ - -char *get_db_grp(request_rec *r, char *user, const char *auth_dbgrpfile) { - char *grp_data = get_db_pw (r, user, auth_dbgrpfile); - char *grp_colon; char *grp_colon2; - - if (grp_data == NULL) return NULL; - - if ((grp_colon = strchr(grp_data, ':'))!=NULL) { - grp_colon2 = strchr(++grp_colon, ':'); - if (grp_colon2) *grp_colon2='\0'; - return grp_colon; - } - return grp_data; -} - -int db_authenticate_basic_user (request_rec *r) -{ - db_auth_config_rec *sec = - (db_auth_config_rec *)get_module_config (r->per_dir_config, - &db_auth_module); - conn_rec *c = r->connection; - char *sent_pw, *real_pw, *colon_pw; - char errstr[MAX_STRING_LEN]; - int res; - - if ((res = get_basic_auth_pw (r, &sent_pw))) - return res; - - if(!sec->auth_dbpwfile) - return DECLINED; - - if(!(real_pw = get_db_pw(r, c->user, sec->auth_dbpwfile))) { - if (!(sec -> auth_dbauthoritative)) - return DECLINED; - ap_snprintf(errstr, sizeof(errstr), "DB user %s not found", c->user); - log_reason (errstr, r->filename, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - /* Password is up to first : if exists */ - colon_pw = strchr(real_pw,':'); - if (colon_pw) *colon_pw='\0'; - /* anyone know where the prototype for crypt is? */ - if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) { - ap_snprintf(errstr, sizeof(errstr), - "user %s: password mismatch",c->user); - log_reason (errstr, r->uri, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - return OK; -} - -/* Checking ID */ - -int db_check_auth(request_rec *r) { - db_auth_config_rec *sec = - (db_auth_config_rec *)get_module_config (r->per_dir_config, - &db_auth_module); - char *user = r->connection->user; - int m = r->method_number; - char errstr[MAX_STRING_LEN]; - - array_header *reqs_arr = requires (r); - require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL; - - register int x; - const char *t; - char *w; - - if (!sec->auth_dbgrpfile) return DECLINED; - if (!reqs_arr) return DECLINED; - - for(x=0; x < reqs_arr->nelts; x++) { - - if (! (reqs[x].method_mask & (1 << m))) continue; - - t = reqs[x].requirement; - w = getword(r->pool, &t, ' '); - - if(!strcmp(w,"group") && sec->auth_dbgrpfile) { - const char *orig_groups,*groups; - char *v; - - if (!(groups = get_db_grp(r, user, sec->auth_dbgrpfile))) { - if (!(sec->auth_dbauthoritative)) - return DECLINED; - ap_snprintf(errstr, sizeof(errstr), - "user %s not in DB group file %s", - user, sec->auth_dbgrpfile); - log_reason (errstr, r->filename, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - orig_groups = groups; - while(t[0]) { - w = getword(r->pool, &t, ' '); - groups = orig_groups; - while(groups[0]) { - v = getword(r->pool, &groups,','); - if(!strcmp(v,w)) - return OK; - } - } - ap_snprintf(errstr, sizeof(errstr), - "user %s not in right group",user); - log_reason (errstr, r->filename, r); - note_basic_auth_failure(r); - return AUTH_REQUIRED; - } - } - - return DECLINED; -} - - -module db_auth_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_db_auth_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - db_auth_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - db_authenticate_basic_user, /* check_user_id */ - db_check_auth, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_auth_dbm.c b/usr.sbin/httpd/src/mod_auth_dbm.c deleted file mode 100644 index d383264e9f6..00000000000 --- a/usr.sbin/httpd/src/mod_auth_dbm.c +++ /dev/null @@ -1,291 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_auth: authentication - * - * Rob McCool & Brian Behlendorf. - * - * Adapted to Apache by rst. - * - * dirkx - Added Authoritative control to allow passing on to lower - * modules if and only if the user-id is not known to this - * module. A known user with a faulty or absent password still - * causes an AuthRequired. The default is 'Authoritative', i.e. - * no control is passed along. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#include <ndbm.h> - -typedef struct { - - char *auth_dbmpwfile; - char *auth_dbmgrpfile; - int auth_dbmauthoritative; - -} dbm_auth_config_rec; - -void *create_dbm_auth_dir_config (pool *p, char *d) -{ - dbm_auth_config_rec *sec - = (dbm_auth_config_rec *)pcalloc (p, sizeof(dbm_auth_config_rec)); - - sec->auth_dbmpwfile = NULL; - sec->auth_dbmgrpfile = NULL; - sec->auth_dbmauthoritative = 1; /* fortress is secure by default */ - - return sec; -} - -const char *set_dbm_slot (cmd_parms *cmd, void *offset, char *f, char *t) -{ - if (!t || strcmp(t, "dbm")) - return DECLINE_CMD; - - return set_string_slot(cmd, offset, f); -} - -command_rec dbm_auth_cmds[] = { -{ "AuthDBMUserFile", set_string_slot, - (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile), - OR_AUTHCFG, TAKE1, NULL }, -{ "AuthDBMGroupFile", set_string_slot, - (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile), - OR_AUTHCFG, TAKE1, NULL }, -{ "AuthUserFile", set_dbm_slot, - (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmpwfile), - OR_AUTHCFG, TAKE12, NULL }, -{ "AuthGroupFile", set_dbm_slot, - (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmgrpfile), - OR_AUTHCFG, TAKE12, NULL }, -{ "AuthDBMAuthoritative", set_flag_slot, - (void*)XtOffsetOf(dbm_auth_config_rec, auth_dbmauthoritative), - OR_AUTHCFG, FLAG, "Set to 'no' to allow access control to be passed along to lower modules, if the UserID is not known in this module" }, -{ NULL } -}; - -module dbm_auth_module; - -char *get_dbm_pw(request_rec *r, char *user, char *auth_dbmpwfile) { - DBM *f; - datum d, q; - char *pw = NULL; - - q.dptr = user; - q.dsize = strlen(q.dptr); - - if(!(f=dbm_open(auth_dbmpwfile,O_RDONLY,0664))) { - log_reason ("could not open dbm auth file", auth_dbmpwfile, r); - return NULL; - } - - d = dbm_fetch(f, q); - - if (d.dptr) { - pw = palloc (r->pool, d.dsize + 1); - strncpy(pw,d.dptr,d.dsize); - pw[d.dsize] = '\0'; /* Terminate the string */ - } - - dbm_close(f); - return pw; -} - -/* We do something strange with the group file. If the group file - * contains any : we assume the format is - * key=username value=":"groupname [":"anything here is ignored] - * otherwise we now (0.8.14+) assume that the format is - * key=username value=groupname - * The first allows the password and group files to be the same - * physical DBM file; key=username value=password":"groupname[":"anything] - * - * mark@telescope.org, 22Sep95 - */ - -char *get_dbm_grp(request_rec *r, char *user, char *auth_dbmgrpfile) { - char *grp_data = get_dbm_pw (r, user, auth_dbmgrpfile); - char *grp_colon; char *grp_colon2; - - if (grp_data == NULL) return NULL; - - if ((grp_colon = strchr(grp_data, ':'))!=NULL) { - grp_colon2 = strchr(++grp_colon, ':'); - if (grp_colon2) *grp_colon2='\0'; - return grp_colon; - } - return grp_data; -} - -int dbm_authenticate_basic_user (request_rec *r) -{ - dbm_auth_config_rec *sec = - (dbm_auth_config_rec *)get_module_config (r->per_dir_config, - &dbm_auth_module); - conn_rec *c = r->connection; - char *sent_pw, *real_pw, *colon_pw; - char errstr[MAX_STRING_LEN]; - int res; - - if ((res = get_basic_auth_pw (r, &sent_pw))) - return res; - - if(!sec->auth_dbmpwfile) - return DECLINED; - - if(!(real_pw = get_dbm_pw(r, c->user, sec->auth_dbmpwfile))) { - if (!(sec->auth_dbmauthoritative)) - return DECLINED; - ap_snprintf(errstr, sizeof(errstr), "DBM user %s not found", c->user); - log_reason (errstr, r->filename, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - /* Password is up to first : if exists */ - colon_pw = strchr(real_pw,':'); - if (colon_pw) *colon_pw='\0'; - /* anyone know where the prototype for crypt is? */ - if(strcmp(real_pw,(char *)crypt(sent_pw,real_pw))) { - ap_snprintf(errstr, sizeof(errstr), - "user %s: password mismatch",c->user); - log_reason (errstr, r->uri, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - return OK; -} - -/* Checking ID */ - -int dbm_check_auth(request_rec *r) { - dbm_auth_config_rec *sec = - (dbm_auth_config_rec *)get_module_config (r->per_dir_config, - &dbm_auth_module); - char *user = r->connection->user; - int m = r->method_number; - char errstr[MAX_STRING_LEN]; - - array_header *reqs_arr = requires (r); - require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL; - - register int x; - const char *t; - char *w; - - if (!sec->auth_dbmgrpfile) return DECLINED; - if (!reqs_arr) return DECLINED; - - for(x=0; x < reqs_arr->nelts; x++) { - - if (! (reqs[x].method_mask & (1 << m))) continue; - - t = reqs[x].requirement; - w = getword(r->pool, &t, ' '); - - if(!strcmp(w,"group") && sec->auth_dbmgrpfile) { - const char *orig_groups,*groups; - char *v; - - if (!(groups = get_dbm_grp(r, user, sec->auth_dbmgrpfile))) { - if (!(sec->auth_dbmauthoritative)) - return DECLINED; - ap_snprintf(errstr, sizeof(errstr), - "user %s not in DBM group file %s", - user, sec->auth_dbmgrpfile); - log_reason (errstr, r->filename, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - orig_groups = groups; - while(t[0]) { - w = getword(r->pool, &t, ' '); - groups = orig_groups; - while(groups[0]) { - v = getword(r->pool, &groups,','); - if(!strcmp(v,w)) - return OK; - } - } - ap_snprintf(errstr, sizeof(errstr), - "user %s not in right group",user); - log_reason (errstr, r->filename, r); - note_basic_auth_failure(r); - return AUTH_REQUIRED; - } - } - - return DECLINED; -} - - -module dbm_auth_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_dbm_auth_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - dbm_auth_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - dbm_authenticate_basic_user, /* check_user_id */ - dbm_check_auth, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_auth_msql.c b/usr.sbin/httpd/src/mod_auth_msql.c deleted file mode 100644 index dc8064276e8..00000000000 --- a/usr.sbin/httpd/src/mod_auth_msql.c +++ /dev/null @@ -1,996 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_auth_msql: authentication - * - * Rob McCool & Brian Behlendorf. - * - * Adapted to Apache by rst. - * - * Addapted for use with the mSQL database - * (see ftp:/ftp.bond.edu.au/pub/Minerva/mSQL) - * - * Version 1.0 May 1996 - Blame: Dirk.vanGulik@jrc.it. - * - * A (sometimes more up to date) version of the documentation - * can be found at the http://www.apache.org site or at - * http://me-www.jrc.it/~dirkx/mod_auth_msql.html. - * - * Outline: - * - * This module allows access control using the public domain - * mSQL database; a fast but limted SQL engine which can be - * contacted over an internal unix domain protocol as well as - * over normal inter-machine tcp/ip socket communication. - * - * An example table could be: - * - * create table user_records ( - * User_id char(32) primary key, - * Cpasswd char(32), - * [ Xgroup char(32) ] - * ) \g - * - * The user_id can be as long as desired; however some of the - * popular web browsers truncate, or stop the user from entering - * names longer than 32 characters. Furthermore the 'crypt' function - * on your platform might impose further limits. Also use of - * the 'require users uid [uid..]' directive in the access.conf file, - * where the user ids are separated by spaces can possibly prohibit the - * use of spaces in your user-names. Also, not the MAX_FIELD_LEN define - * somewhere below. - * - * To use the above, the following example could be in your access.conf - * file. Also there is a more elaborate description afther this example. - * - * <directory /web/docs/private> - * - * Auth_MSQLhost localhost - * or - * Auth_MSQLhost datab.machine.your.org - * - * If this directive is ommited, or set to - * localhost, the machine on which apache - * runs is assumed, and the faster /dev/msql - * communication channel will be used. Otherwise - * it is the machine to contact by tcp/ip. - * - * Auth_MSQLdatabase www - * - * The name of the database on the above machine, - * which contains *both* the tables for group and - * for user/passwords. Currently it is not possible - * to have these split over two databases. Make - * sure that the msql.acl (access control file) of - * mSQL does indeed allow the effective uid of the - * web server read access to this database. Check the - * httpd.conf file for this uid. - * - * Auth_MSQLpwd_table user_records - * - * Here the table which contain the uid/password combination - * is specified. - * - * Auth_MSQLuid_field User_id - * Auth_MSQLpwd_field Cpasswd - * - * These two directive specify the field names in the 'user_record' - * table. If this module is compiled with the BACKWARD_VITEK - * compatibility switch, the defaults 'user' and 'password' are - * assumed if you do not specify them. Currently the user_id field - * *MUST* be a primary key or one must ensure that each user only - * occurs *once* in the table. If a UID occurs twice access is - * denied by default. - * - * Auth_MSQLgrp_table user_records - * Auth_MSQLgrp_field Xgroup - * - * Optionaly one can also specify a table which contains the - * user/group combinations. This can be the same table which - * also contains the username/password combinations. However - * if a user belongs to two or more groups, one will have to - * use a differt table with multiple entries. - * - * Auth_MSQL_nopasswd off - * Auth_MSQL_Authoritative on - * Auth_MSQL_EncryptedPasswords on - * - * These three optional fields (all set to the sensible defaults, - * so you really do not have to enter them) are described in more - * detail below. If you choose to set these to any other values than - * the above be very sure you understand the security implications and - * do verify that apache does what you exect it to do. - * - * AuthName example mSQL realm - * AuthType basic - * - * Normal apache/ncsa tokens for access control - * - * <limit get post head> - * order deny,allow - * allow from all - * - * require valid-user - * 'valid-user'; allow in any user which has a valid uid/passwd - * pair in the above pwd_table. - * or - * require user smith jones - * Limit access to users who have a valid uid/passwd pair in the - * above pwd_table AND whose uid is 'smith' or 'jones'. Do note that - * the uid's are separated by 'spaces' for historic (ncsa) reasons. - * So allowing uids with spaces might cause problems. - * - * require group has_paid - * Optionally also ensure that the uid has the value 'has_paid' in the group - * field in the group table. - * </limit> - * </directory> - * - * End of the example - * - * - full description of all tokens: - - * - * Directives: - * - * Auth_MSQLhost Hostname of the machine running - * the mSQL demon. The effective uid - * of the server should be allowed - * access. If not given, or if it is - * the magic name 'localhost', it is - * passed to the mSQL libary as a null - * pointer. This effectively forces it - * to use /dev/msql rather than the - * (slower) socket communication. - * - * Auth_MSQLdatabase Name of the database in which the following - * table(s) are contained. - * - * Auth_MSQLpwd_table Contains at least the fields with the - * username and the (encrypted) password. Each - * uid should only occur once in this table and - * for performance reasons should be a primary key. - * Normally this table is compulsory, but it is - * possible to use a fall-through to other methods - * and use the mSQL module for group control only; - * see the Authoritative directive below. - * - * Auth_MSQLgrp_table Contains at least the fields with the - * username and the groupname. A user which - * is in multiple groups has therefore - * multiple entries; this might be some per- - * formance problems associated with this; and one - * might consider to have separate tables for each - * group (rather than all groups in one table) if - * your directory structure allows for it. - * One only needs to specify this table when doing - * group control. - * - * Auth_MSQLuid_field Name of the field containing the username - * Auth_MSQLpwd_field Fieldname for the passwords - * Auth_MSQLgrp_field Fieldname for the groupname - * - * Only the fields used need to be specified. When this - * module is compiled with the BACKWARD_VITEK option the - * uid and pwd field names default to 'user' and 'password'. - * - * - * Auth_MSQL_nopasswd <on|off> - * skip password comparison if passwd field is - * empty; i.e. allow 'any' password. This is off - * by default; thus to ensure that an empty field - * in the mSQL table does not allow people in by - * default with a random password. - * - * Auth_MSQL_Authoritative <on|off> - * default is 'on'. When set on, there is no - * fall through to other authorization methods. So if a - * user is not in the mSQL dbase table (and perhaps - * not in the right group) or has the password wrong, then - * he or she is denied access. When this directive is set to - * 'off' control is passed on to any other authorization - * modules, such as the basic auth module wih the htpasswd - * file and or the unix-(g)dbm modules. - * The default is 'ON' to avoid nasty 'fall-through' sur- - * prizes. Do be sure you know what you decide to switch - * it off. - * - * Auth_MSQL_EncryptedPasswords <on|off> - * default is on. When set on, the values in the - * pwd_field are assumed to be crypted using *your* - * machines 'crypt' function; and the incoming password - * is 'crypt'ed before comparison. When this function is - * off, the comparison is done directly with the plaintext - * entered password. (Yes; http-basic-auth does send the - * password as plaintext over the wire :-( ). The default - * is a sensible 'on', and I personally thing that it is - * a *very-bad-idea* to change this. However a multi - * vendor or international environment (which sometimes - * leads to different crypts functions) might force you to. - * - * Dirk.vanGulik@jrc.it; http://ewse.ceo.org; http://me-www.jrc.it/~dirkx - * 23 Nov 1995, 24 Feb 1996, 16 May 1996. - * - * Version 0.0 First release - * 0.1 Update to apache 1.00 - * 0.2 added lines which got missing god knows when - * and which did the valid-user authentification - * no good at all ! - * 0.3 Added 'Auth_MSQL_nopasswd' option - * 0.4 Cleaned out the error messages mess. - * 0.6 Inconsistency with gid/grp in comment/token/source - * Make sure you really use 'Auth_MSQLgrp_field' as - * indicated above. - * 0.7 *host to host fixed. Credits go to Rob Stout, - * <stout@lava.et.tudelft.nl> for spotting this one. - * 0.8 Authoritative directive added. See above. - * 0.9 palloc return code check(s), should be backward compatible with - * 1.11 version of Vivek Khera <khera@kciLink.com> msql module, - * fixed broken err msg in group control, changed command table - * messages to make more sense when displayed in that new module - * management tool. Added EncryptedPassword on/off functionality. - * msqlClose() statements added upon error. Support for persistent - * connections with the mSQL database (riscy). Escaping of ' and \. - * Replaced some MAX_STRING_LEN claims. - * 1.0 removed some error check as they where already done elsehwere - * NumFields -> NumRows (Thanks Vitek). More stack memory. - * 1.1 no logging of empty password strings. - * 1.2 Problem with the Backward vitek which cause it to check - * even if msql_auth was not configured; Also more carefull - * with the authoritative stuff; caught by thomas@marvin.calvacom.fr. - * 1.3 Even more changes to get it right; that BACKWARD thing was a bad - * idea. - */ - - -#define ONLY_ONCE 1 -/* - * If the mSQL table containing the uid/passwd combination does - * not have the uid field as a primary key, it is possible for the - * uid to occur more than once in the table with possibly different - * passwords. When this module is compiled with the ONLY_ONCE directive - * set, access is denied if the uid occures more than once in the - * uid/passwd table. If you choose not to set it, the software takes - * the first pair returned and ignores any further pairs. The SQL - * statement used for this is - * - * "select password form pwd_table where user='uid'" - * - * this might lead to unpredictable results. For this reason as well - * as for performance reasons you are strongly adviced to make the - * uid field a primary key. Use at your own peril :-) - */ - -#undef KEEP_MSQL_CONNECTION_OPEN -/* - * Normally the (tcp/ip) connection with the database is opened and - * closed for each SQL query. When the httpd-server and the database - * are on the same machine, and /dev/msql is used this does not - * cause a serious overhead. However when your platform does not - * support this (see the mSQL documentation) or when the web server - * and the database are on different machines the overhead can be - * considerable. When the above is set defined the server leaves the - * connection open; i.e. no call to msqlClose(). If an error occures - * an attempt is made to re-open the connection for the next http-rq. - * - * This has a number of very serious drawbacks - * - It costs 2 already rare filedescriptors for each child. - * - It costs msql-connections, typically one per child. The (compiled in) - * number of connections mSQL can handle is low, typically 6 or 12. - * which might prohibit access to the mSQL database for later - * processes. - * - when a child dies, it might not free that connection properly - * or quick enough. - * - When errors start to occur, connection/file-descr resources might - * become exausted very quickly. - * - * In short; use this at your own peril and only in a highly controled and - * monitored environment - */ - -#define BACKWARD_VITEK -#define VITEX_uid_name "user" -#define VITEX_gid_name "passwd" -/* A second mSQL auth module for apache has also been developed by - * Vivek Khera <khera@kciLink.com> and was subsequently distributed - * with some early versions of Apache. It can be optained from - * ftp://ftp.kcilink.com/pub/mod_auth_msql.c*. Older 'vitek' versions had - * the field/table names compiled in; newer versions, v.1.11 have - * more access.conf configuration options; however these where - * choosen not to be in line the 'ewse' version of this module. Also, - * the 'vitek' module does not give group control or 'empty' password - * control. - * - * To get things slightly more in line this version (0.9) should - * be backward compatible with the vitek module by: - * - * - adding support for the EncryptedPassword on/off functionality - * - * - adding support for the different spelling fo the 4 configuration - * tokens for user-table-name, user/password-field-name and dbase-name. - * - * - setting some field names to a default which used to be hard - * coded in in older vitek modules. - * - * If this troubles you; remove the 'BACKWARD_VITEX' define. - */ - -/* get some sensible values; rather than that big MAX_STRING_LEN, - */ - -/* Max field value length limit; well above the limit of some browsers :-) - */ -#define MAX_FIELD_LEN (64) -/* the next two values can be pulled from msql_priv.c, which is *NOT* copied to your - * /usr/local/include as part of the normal install procedure which comes with - * mSQL. - */ -#define MSQL_FIELD_NAME_LEN (19) -#define MSQL_TABLE_NAME_LEN (19) -/* We only do the following two queries: - * - * - for the user/passwd combination - * select PWDFIELD from PWDTABEL where USERFIELD='UID' - * - * - optionally for the user/group combination: - * select GROUPFIELD from GROUPTABLE where USERFIELD='UID' and GROUPFIELD='GID' - * - * This leads to the following limits: (we are ignoring escaping a wee bit bit here - * assuming not more than 24 escapes.) - */ - -#define MAX_QUERY_LEN (32+24+MAX_FIELD_LEN*2+3*MSQL_FIELD_NAME_LEN+1*MSQL_TABLE_NAME_LEN) - - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#include <msql.h> -#ifdef HAVE_CRYPT_H -#include <crypt.h> -#endif - -typedef struct { - - char *auth_msql_host; - char *auth_msql_database; - - char *auth_msql_pwd_table; - char *auth_msql_grp_table; - - char *auth_msql_pwd_field; - char *auth_msql_uname_field; - char *auth_msql_grp_field; - - int auth_msql_nopasswd; - int auth_msql_authoritative; - int auth_msql_encrypted; - -} msql_auth_config_rec; - -void *create_msql_auth_dir_config (pool *p, char *d) -{ - msql_auth_config_rec * sec= (msql_auth_config_rec *) pcalloc (p, sizeof(msql_auth_config_rec)); - - sec->auth_msql_host = NULL; /* just to enforce the default 'localhost' behaviour */ - - /* just in case, to be nice... */ - sec->auth_msql_database = NULL; - sec->auth_msql_pwd_table = NULL; - sec->auth_msql_grp_table = NULL; - sec->auth_msql_pwd_field = NULL; - sec->auth_msql_uname_field = NULL; - sec->auth_msql_grp_field = NULL; - - - sec->auth_msql_authoritative = 1; /* set some defaults, just in case... */ - sec->auth_msql_encrypted = 1; - sec->auth_msql_nopasswd = 0; - -#ifdef BACKWARD_VITEK - /* these are for backward compatibility with the Vivek - * msql module, as it used to have compile-time defaults. - */ - sec->auth_msql_uname_field = VITEX_uid_name; - sec->auth_msql_pwd_field = VITEX_gid_name; -#endif - - return sec; -} - -const char *set_passwd_flag (cmd_parms *cmd, msql_auth_config_rec *sec, int arg) { - sec->auth_msql_nopasswd=arg; - return NULL; -} - -const char *set_authoritative_flag (cmd_parms *cmd, msql_auth_config_rec *sec, int arg) { - sec->auth_msql_authoritative=arg; - return NULL; -} - -const char *set_crypted_password_flag (cmd_parms *cmd, msql_auth_config_rec *sec , int arg) { - sec->auth_msql_encrypted = arg; - return NULL; -} - -const char *msql_set_string_slot (cmd_parms *cmd, char *struct_ptr, char *arg) { - int offset = (int)cmd->info; - *(char **)(struct_ptr + offset) = pstrdup (cmd->pool, arg); - return NULL; -} - - -command_rec msql_auth_cmds[] = { -{ "Auth_MSQLhost", msql_set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_host), - OR_AUTHCFG, TAKE1, "Host on which the mSQL database engine resides (defaults to localhost)" }, - -{ "Auth_MSQLdatabase", msql_set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_database), - OR_AUTHCFG, TAKE1, "Name of the mSQL database which contains the password (and possibly the group) tables. " }, - -{ "Auth_MSQLpwd_table", msql_set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_table), - OR_AUTHCFG, TAKE1, "Name of the mSQL table containing the password/user-name combination" }, - -{ "Auth_MSQLgrp_table", msql_set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_table), - OR_AUTHCFG, TAKE1, "Name of the mSQL table containing the group-name/user-name combination; can be the same as the password-table." }, - -{ "Auth_MSQLpwd_field", msql_set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_field), - OR_AUTHCFG, TAKE1, "The name of the field in the mSQL password table" }, - -{ "Auth_MSQLuid_field", msql_set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_uname_field), - OR_AUTHCFG, TAKE1, "The name of the user-name field in the mSQL password (and possibly group) table(s)." }, - -{ "Auth_MSQLgrp_field", msql_set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_field), - OR_AUTHCFG, TAKE1, - "The name of the group field in the mSQL group table; must be set if you want to use groups." }, - -{ "Auth_MSQL_nopasswd", set_passwd_flag, NULL, OR_AUTHCFG, FLAG, - "Enable (on) or disable (off) empty password strings; in which case any user password is accepted." }, - -{ "Auth_MSQL_Authoritative", set_authoritative_flag, NULL, OR_AUTHCFG, FLAG, - "When 'on' the mSQL database is taken to be authoritative and access control is not passed along to other db or access modules." }, - -{ "Auth_MSQL_EncryptedPasswords", set_crypted_password_flag, NULL, OR_AUTHCFG, FLAG, - "When 'on' the password in the password table are taken to be crypt()ed using your machines crypt() function." }, - -#ifdef BACKWARD_VITEK -/* These 'altenative' tokens should ensure backward compatibility - * with viteks mSQL module. The only difference is the spelling. - * Note that these tokens do not allow group configuration. - */ -{ "AuthMSQLHost", set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_host), - OR_AUTHCFG, TAKE1, "mSQL server hostname" }, -{ "AuthMSQLDB", set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_database), - OR_AUTHCFG, TAKE1, "mSQL database name" }, -{ "AuthMSQLUserTable", set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_table), - OR_AUTHCFG, TAKE1, "mSQL user table name" }, -{ "AuthMSQLGroupTable", set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_table), - OR_AUTHCFG, TAKE1, "mSQL group table name" }, -{ "AuthMSQLNameField", set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_uname_field), - OR_AUTHCFG, TAKE1, "mSQL User ID field name within table" }, -{ "AuthMSQLGroupField", set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_grp_field), - OR_AUTHCFG, TAKE1, "mSQL Group field name within table" }, -{ "AuthMSQLPasswordField", set_string_slot, - (void*)XtOffsetOf(msql_auth_config_rec, auth_msql_pwd_field), - OR_AUTHCFG, TAKE1, "mSQL Password field name within table" }, -{ "AuthMSQLCryptedPasswords", set_crypted_password_flag, NULL, - OR_AUTHCFG, FLAG, "mSQL passwords are stored encrypted if On" }, - -#endif - -{ NULL } -}; - -module msql_auth_module; - -/* boring little routine which escapes the ' and \ in the - * SQL query. See the mSQL FAQ for more information :-) on - * this very popular subject in the msql-mailing list. - */ -char *msql_escape(char *out, char *in, char *msql_errstr) { - - register int i=0,j=0; - - do { - /* do we need to escape */ - if ( (in[i] == '\'') || (in[i] == '\\')) { - - /* does this fit ? */ - if (j >= (MAX_FIELD_LEN-1)) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "Could not escape '%s', longer than %d",in,MAX_FIELD_LEN); - return NULL; - }; - - out[j++] = '\\'; /* insert that escaping slash for good measure */ - }; - - /* Do things still fit ? */ - if (j >= MAX_FIELD_LEN) return NULL; - - } while ( ( out[j++] = in[i++]) != '\0' ); - - return out; -} - -/* get the password for uname=user, and copy it - * into r. Assume that user is a string and stored - * as such in the mSQL database - */ -char *do_msql_query(request_rec *r, char *query, msql_auth_config_rec *sec, int once , char *msql_errstr) { - - static int sock=-1; - int hit; - m_result *results; - m_row currow; - - char *result=NULL; - char *host=sec->auth_msql_host; - -#ifndef KEEP_MSQL_CONNECTION_OPEN - sock=-1; -#endif - - /* force fast access over /dev/msql */ - - if ((host) && (!(strcasecmp(host,"localhost")))) - host=NULL; - - /* (re) open if nessecary - */ - if (sock==-1) if ((sock=msqlConnect(host)) == -1) { - ap_snprintf (msql_errstr, MAX_STRING_LEN, - "mSQL: Could not connect to Msql DB %s (%s)", - (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"), - msqlErrMsg); - return NULL; - } - - /* we always do this, as it avoids book-keeping - * and is quite cheap anyway - */ - if (msqlSelectDB(sock,sec->auth_msql_database) == -1 ) { - ap_snprintf (msql_errstr, MAX_STRING_LEN, - "mSQL: Could not select Msql Table \'%s\' on host \'%s\'(%s)", - (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"), - (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"), - msqlErrMsg); - msqlClose(sock); - sock=-1; - return NULL; - } - - if (msqlQuery(sock,query) == -1 ) { - ap_snprintf (msql_errstr, MAX_STRING_LEN, - "mSQL: Could not Query database '%s' on host '%s' (%s) with query [%s]", - (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"), - (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"), - msqlErrMsg, - ( query ? query : "\'unset!\'") ); - msqlClose(sock); - sock=-1; - return NULL; - } - - if (!(results=msqlStoreResult())) { - ap_snprintf (msql_errstr, MAX_STRING_LEN, - "mSQL: Could not get the results from mSQL database \'%s\' on \'%s\' (%s) with query [%s]", - (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"), - (sec->auth_msql_host ? sec->auth_msql_host : "\'unset, assuming localhost!\'"), - msqlErrMsg, - ( query ? query : "\'unset!\'") ); - msqlClose(sock); - sock=-1; - return NULL; - }; - - hit=msqlNumRows(results); - - if (( once ) && ( hit >1 )) { - /* complain if there are to many - * matches. - */ - ap_snprintf (msql_errstr, MAX_STRING_LEN, - "mSQL: More than %d matches (%d) whith query [%s]", - once,hit,( query ? query : "\'unset!\'") ); - } else - /* if we have a it, try to get it - */ - if ( hit ) { - if ( (currow=msqlFetchRow(results)) != NULL) { - /* copy the first matching field value */ - if (!(result=palloc(r->pool,strlen(currow[0])+1))) { - ap_snprintf (msql_errstr, MAX_STRING_LEN, - "mSQL: Could not get memory for mSQL %s (%s) with [%s]", - (sec->auth_msql_database ? sec->auth_msql_database : "\'unset!\'"), - msqlErrMsg, - ( query ? query : "\'unset!\'") ); - /* do not return right away, to ensure Free/Close. - */ - } else { - strcpy(result,currow[0]); - }; - } - }; - - /* ignore errors, functions are voids anyway. */ - msqlFreeResult(results); - -#ifndef KEEP_MSQL_CONNECTION_OPEN - /* close the connection, unless explicitly told not to. Do note that - * we do not have a decent closing option of child termination due - * the lack of hooks in the API (or my understanding thereof) - */ - msqlClose(sock); - sock=-1; -#endif - - return result; -} - -char *get_msql_pw(request_rec *r, char *user, msql_auth_config_rec *sec ,char *msql_errstr) { - char query[MAX_QUERY_LEN]; - char esc_user[MAX_FIELD_LEN]; - - /* do we have enough information to build a query */ - if ( - (!sec->auth_msql_pwd_table) || - (!sec->auth_msql_pwd_field) || - (!sec->auth_msql_uname_field) - ) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "mSQL: Missing parameters for password lookup: %s%s%s", - (sec->auth_msql_pwd_table ? "" : "Password table "), - (sec->auth_msql_pwd_field ? "" : "Password field name "), - (sec->auth_msql_uname_field ? "" : "UserID field name ") - ); - return NULL; - }; - - if (!(msql_escape(esc_user, user, msql_errstr))) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "mSQL: Could not cope/escape the '%s' user_id value; ",user); - return NULL; - }; - ap_snprintf(query, sizeof(query), - "select %s from %s where %s='%s'", - sec->auth_msql_pwd_field, - sec->auth_msql_pwd_table, - sec->auth_msql_uname_field, - esc_user - ); - - return do_msql_query(r,query,sec,ONLY_ONCE,msql_errstr); -} - -char *get_msql_grp(request_rec *r, char *group,char *user, msql_auth_config_rec *sec, char *msql_errstr) { - char query[MAX_QUERY_LEN]; - - char esc_user[MAX_FIELD_LEN]; - char esc_group[MAX_FIELD_LEN]; - - /* do we have enough information to build a query */ - if ( - (!sec->auth_msql_grp_table) || - (!sec->auth_msql_grp_field) || - (!sec->auth_msql_uname_field) - ) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "mSQL: Missing parameters for group lookup: %s%s%s", - (sec->auth_msql_grp_table ? "" : "Group table "), - (sec->auth_msql_grp_field ? "" : "GroupID field name "), - (sec->auth_msql_uname_field ? "" : "UserID field name ") - ); - return NULL; - }; - - if (!(msql_escape(esc_user, user,msql_errstr))) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "mSQL: Could not cope/escape the '%s' user_id value",user); - - return NULL; - }; - if (!(msql_escape(esc_group, group,msql_errstr))) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "mSQL: Could not cope/escape the '%s' group_id value",group); - - return NULL; - }; - - ap_snprintf(query, sizeof(query), - "select %s from %s where %s='%s' and %s='%s'", - sec->auth_msql_grp_field, - sec->auth_msql_grp_table, - sec->auth_msql_uname_field,esc_user, - sec->auth_msql_grp_field, esc_group - ); - - return do_msql_query(r,query,sec,0,msql_errstr); -} - - -int msql_authenticate_basic_user (request_rec *r) -{ - msql_auth_config_rec *sec = - (msql_auth_config_rec *)get_module_config (r->per_dir_config, - &msql_auth_module); - char msql_errstr[MAX_STRING_LEN]; - /* msql_errstr must be MAX_STRING_LEN in size unless you - * change size in ap_snprintf() calls - */ - conn_rec *c = r->connection; - char *sent_pw, *real_pw; - int res; - msql_errstr[0]='\0'; - - if ((res = get_basic_auth_pw (r, &sent_pw))) - return res; - - /* if mSQL *password* checking is configured in any way, i.e. then - * handle it, if not decline and leave it to the next in line.. - * We do not check on dbase, group, userid or host name, as it is - * perfectly possible to only do group control with mSQL and leave - * user control to the next (dbm) guy in line. - * We no longer check on the user field name; to avoid problems - * with Backward VITEK. - */ - if (!sec->auth_msql_pwd_table) return DECLINED; - - if(!(real_pw = get_msql_pw(r, c->user, sec,msql_errstr ))) { - if ( msql_errstr[0] ) { - res = SERVER_ERROR; - } else { - if (sec->auth_msql_authoritative) { - /* insist that the user is in the database - */ - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "mSQL: Password for user %s not found", c->user); - note_basic_auth_failure (r); - res = AUTH_REQUIRED; - } else { - /* pass control on to the next authorization module. - */ - return DECLINED; - }; /* if authoritative */ - }; /* if no error */ - log_reason (msql_errstr, r->filename, r); - return res; - } - - /* allow no password, if the flag is set and the password - * is empty. But be sure to log this. - */ - - if ((sec->auth_msql_nopasswd) && (!strlen(real_pw))) { -/* - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "mSQL: user %s: Empty/'any' password accepted",c->user); - log_reason (msql_errstr, r->uri, r); - */ - return OK; - }; - - /* if the flag is off however, keep that kind of stuff at - * an arms length. - */ - if ((!strlen(real_pw)) || (!strlen(sent_pw))) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "mSQL: user %s: Empty Password(s) Rejected",c->user); - log_reason (msql_errstr, r->uri, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - }; - - if(sec->auth_msql_encrypted) { - /* anyone know where the prototype for crypt is? - * - * PLEASE NOTE: - * The crypt function (at least under FreeBSD 2.0.5) returns - * a ptr to a *static* array (max 120 chars) and does *not* - * modify the string pointed at by sent_pw ! - */ - sent_pw=(char *)crypt(sent_pw,real_pw); - }; - - if (strcmp(real_pw,sent_pw)) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, - "mSQL user %s: password mismatch",c->user); - log_reason (msql_errstr, r->uri, r); - note_basic_auth_failure (r); - return AUTH_REQUIRED; - } - return OK; -} - -/* Checking ID */ - -int msql_check_auth (request_rec *r) { - int user_result=DECLINED,group_result=DECLINED; - - msql_auth_config_rec *sec = - (msql_auth_config_rec *)get_module_config (r->per_dir_config, - &msql_auth_module); - char msql_errstr[MAX_STRING_LEN]; - /* msql_errstr must be MAX_STRING_LEN in size unless you - * change size in ap_snprintf() calls - */ - char *user = r->connection->user; - int m = r->method_number; - array_header *reqs_arr = requires (r); - require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL; - - register int x; - const char *t, *w; - msql_errstr[0]='\0'; - - /* If we are not configured, ignore */ - if (!sec->auth_msql_pwd_table) return DECLINED; - - if (!reqs_arr) { - if (sec->auth_msql_authoritative) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, "user %s denied, no access rules specified (MSQL-Authoritative) ",user); - log_reason (msql_errstr, r->uri, r); - note_basic_auth_failure(r); - return AUTH_REQUIRED; - }; - return DECLINED; - }; - - for(x=0; (x < reqs_arr->nelts) ; x++) { - - if (! (reqs[x].method_mask & (1 << m))) continue; - - t = reqs[x].requirement; - w = getword(r->pool, &t, ' '); - - if ((user_result != OK) && (!strcmp(w,"user"))) { - user_result=AUTH_REQUIRED; - while(t[0]) { - w = getword_conf (r->pool, &t); - if (!strcmp(user,w)) { - user_result= OK; - break; - }; - } - if ((sec->auth_msql_authoritative) && ( user_result != OK)) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, "User %s not found (MSQL-Auhtorative)",user); - log_reason (msql_errstr, r->uri, r); - note_basic_auth_failure(r); - return AUTH_REQUIRED; - }; - } - - if ( (group_result != OK) && - (!strcmp(w,"group")) && - (sec->auth_msql_grp_table) && - (sec->auth_msql_grp_field) - ) { - /* look up the membership for each of the groups in the table - */ - group_result=AUTH_REQUIRED; - while ( (t[0]) && (group_result != OK) && (!msql_errstr[0]) ) { - if (get_msql_grp(r,getword(r->pool, &t, ' '),user,sec,msql_errstr)) { - group_result= OK; - break; - }; - }; - - if (msql_errstr[0]) { - log_reason (msql_errstr, r->filename, r); - return SERVER_ERROR; - }; - - if ( (sec->auth_msql_authoritative) && (group_result != OK) ) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, "user %s not in right groups (MSQL-Authoritative) ",user); - log_reason (msql_errstr, r->uri, r); - note_basic_auth_failure(r); - return AUTH_REQUIRED; - }; - }; - - if(!strcmp(w,"valid-user")) { - user_result= OK; - }; - } - - /* Get serious if we are authoritative, previous - * returns are only if msql yielded a correct result. - * This really is not needed. - */ - if (((group_result == AUTH_REQUIRED) || (user_result == AUTH_REQUIRED)) && (sec->auth_msql_authoritative) ) { - ap_snprintf(msql_errstr, MAX_STRING_LEN, "mSQL-Authoritative: Access denied on %s %s rule(s) ", - (group_result == AUTH_REQUIRED) ? "USER" : "", - (user_result == AUTH_REQUIRED) ? "GROUP" : "" - ); - log_reason (msql_errstr, r->uri, r); - return AUTH_REQUIRED; - }; - - if ( (user_result == OK) || (group_result == OK)) - return OK; - - return DECLINED; -} - - -module msql_auth_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_msql_auth_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - msql_auth_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - msql_authenticate_basic_user,/* check_user_id */ - msql_check_auth, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* pre-run fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_browser.c b/usr.sbin/httpd/src/mod_browser.c deleted file mode 100644 index 3779cdec087..00000000000 --- a/usr.sbin/httpd/src/mod_browser.c +++ /dev/null @@ -1,189 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_browser.c - * Set environment variables based on browser support. - * - * Alexei Kosut <akosut@organic.com> - */ - -#include "httpd.h" -#include "http_config.h" - -typedef struct { - char *name; - regex_t *preg; - table *features; -} browser_entry; - -typedef struct { - array_header *browsers; -} browser_server_config_rec; - -module browser_module; - -void *create_browser_config (pool *p, server_rec *dummy) -{ - browser_server_config_rec *new = - (browser_server_config_rec *) palloc (p, sizeof(browser_server_config_rec)); - - new->browsers = make_array (p, 20, sizeof(browser_entry)); - return (void *)new; -} - -void *merge_browser_config (pool *p, void *basev, void *overridesv) -{ - browser_server_config_rec *a = - pcalloc(p, sizeof(browser_server_config_rec)); - browser_server_config_rec *base = basev, *overrides = overridesv; - - a->browsers = append_arrays(p, base->browsers, overrides->browsers); - return a; -} - -const char *add_browser(cmd_parms *cmd, void *dummy, char *name, - const char *feature) -{ - browser_server_config_rec *sconf = - get_module_config (cmd->server->module_config, &browser_module); - browser_entry *new, *entries = (browser_entry *)sconf->browsers->elts; - char *var; - int i, cflags = (int)cmd->info; - - /* First, try to merge into an existing entry */ - - for (i = 0; i < sconf->browsers->nelts; ++i) { - browser_entry *b = &entries[i]; - if (!strcmp(b->name, name)) { - var = getword(cmd->pool, &feature, '='); - if (*feature) table_set(b->features, var, feature); - else if (*var == '!') table_set(b->features, var + 1, "!"); - else table_set(b->features, var, "1"); - return NULL; - } - } - - /* If none was found, create a new entry */ - - new = push_array(sconf->browsers); - new->name = name; - new->preg = pregcomp (cmd->pool, name, REG_EXTENDED|REG_NOSUB|cflags); - if (new->preg == NULL) { - return "Browser regex could not be compiled."; - } - new->features = make_table(cmd->pool, 5); - - var = getword(cmd->pool, &feature, '='); - if (*feature) table_set(new->features, var, feature); - else if (*var == '!') table_set(new->features, var + 1, "!"); - else table_set(new->features, var, "1"); - - return NULL; -} - -command_rec browser_module_cmds[] = { -{ "BrowserMatch", add_browser, (void*)0, - RSRC_CONF, ITERATE2, "A browser regex and a list of variables." }, -{ "BrowserMatchNoCase", add_browser, (void*)REG_ICASE, - RSRC_CONF, ITERATE2, "a browser regex and a list of variables." }, -{ NULL }, -}; - -static int browser_match(request_rec *r) -{ - server_rec *s = r->server; - browser_server_config_rec *sconf = get_module_config (s->module_config, - &browser_module); - browser_entry *entries = (browser_entry *)sconf->browsers->elts; - table_entry *elts; - char *ua = table_get(r->headers_in, "User-Agent"); - int i, j; - - if (!ua) return DECLINED; - - for (i = 0; i < sconf->browsers->nelts; ++i) { - browser_entry *b = &entries[i]; - - if (!regexec(b->preg, ua, 0, NULL, 0)) { - elts = (table_entry *)b->features->elts; - - for (j = 0; j < b->features->nelts; ++j) { - if (!strcmp(elts[j].val, "!")) - table_unset(r->subprocess_env, elts[j].key); - else - table_set(r->subprocess_env, elts[j].key, elts[j].val); - } - } - } - - return DECLINED; -} - -module browser_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - create_browser_config, /* server config */ - merge_browser_config, /* merge server configs */ - browser_module_cmds, /* command table */ - NULL, /* handlers */ - browser_match, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_cern_meta.c b/usr.sbin/httpd/src/mod_cern_meta.c deleted file mode 100644 index d05677c8c25..00000000000 --- a/usr.sbin/httpd/src/mod_cern_meta.c +++ /dev/null @@ -1,325 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_cern_meta.c - * version 0.0.5 - * status beta - * - * Andrew Wilson <Andrew.Wilson@cm.cf.ac.uk> 25.Jan.96 - * - * Emulate the CERN HTTPD Meta file semantics. Meta files are HTTP - * headers that can be output in addition to the normal range of - * headers for each file accessed. They appear rather like the Apache - * .asis files, and are able to provide a crude way of influencing - * the Expires: header, as well as providing other curiosities. - * There are many ways to manage meta information, this one was - * chosen because there is already a large number of CERN users - * who can exploit this module. It should be noted that there are probably - * more sensitive ways of managing the Expires: header specifically. - * - * The module obeys the following directives, which can only appear - * in the server's .conf files and not in any .htaccess file. - * - * MetaDir <directory name> - * - * specifies the name of the directory in which Apache can find - * meta information files. The directory is usually a 'hidden' - * subdirectory of the directory that contains the file being - * accessed. eg: - * - * # .meta files are in the *same* directory as the - * # file being accessed - * MetaDir . - * - * the default is to look in a '.web' subdirectory. This is the - * same as for CERN 3.+ webservers and behaviour is the same as - * for the directive: - * - * MetaDir .web - * - * MetaSuffix <meta file suffix> - * - * specifies the file name suffix for the file containing the - * meta information. eg: - * - * # our meta files are suffixed with '.cern_meta' - * MetaSuffix .cern_meta - * - * the default is to look for files with the suffix '.meta'. This - * behaviour is the same as for the directive: - * - * MetaSuffix .meta - * - * When accessing the file - * - * DOCUMENT_ROOT/somedir/index.html - * - * this module will look for the file - * - * DOCUMENT_ROOT/somedir/.web/index.html.meta - * - * and will use its contents to generate additional MIME header - * information. - * - * For more information on the CERN Meta file semantics see: - * - * http://www.w3.org/hypertext/WWW/Daemon/User/Config/General.html#MetaDir - * - * Change-log: - * 29.Jan.96 pfopen/pfclose instead of fopen/fclose - * DECLINE when real file not found, we may be checking each - * of the index.html/index.shtml/index.htm variants and don't - * need to report missing ones as spurious errors. - * 31.Jan.96 log_error reports about a malformed .meta file, rather - * than a script error. - * - */ - -#include "httpd.h" -#include "http_config.h" -#include <sys/types.h> -#include <sys/stat.h> -#include "util_script.h" -#include "http_log.h" -#include "http_request.h" - -#define DEFAULT_METADIR ".web" -#define DEFAULT_METASUFFIX ".meta" - -module cern_meta_module; - -typedef struct { - char *metadir; - char *metasuffix; -} cern_meta_config; - -void *create_cern_meta_config (pool *p, server_rec *dummy) -{ - cern_meta_config *new = - (cern_meta_config *) palloc (p, sizeof(cern_meta_config)); - - new->metadir = DEFAULT_METADIR; - new->metasuffix = DEFAULT_METASUFFIX; - - return new; -} - -const char *set_metadir (cmd_parms *parms, void *dummy, char *arg) -{ - cern_meta_config *cmc ; - - cmc = get_module_config (parms->server->module_config, - &cern_meta_module); - cmc->metadir = arg; - return NULL; -} - -const char *set_metasuffix (cmd_parms *parms, void *dummy, char *arg) -{ - cern_meta_config *cmc ; - - cmc = get_module_config (parms->server->module_config, - &cern_meta_module); - cmc->metasuffix = arg; - return NULL; -} - -command_rec cern_meta_cmds[] = { -{ "MetaDir", set_metadir, NULL, RSRC_CONF, TAKE1, - "the name of the directory containing meta files"}, -{ "MetaSuffix", set_metasuffix, NULL, RSRC_CONF, TAKE1, - "the filename suffix for meta files"}, -{ NULL } -}; - -int scan_meta_file(request_rec *r, FILE *f) -{ - char w[MAX_STRING_LEN]; - char *l; - int p; - - while( fgets(w, MAX_STRING_LEN-1, f) != NULL ) { - - /* Delete terminal (CR?)LF */ - - p = strlen(w); - if (p > 0 && w[p-1] == '\n') - { - if (p > 1 && w[p-2] == '\015') w[p-2] = '\0'; - else w[p-1] = '\0'; - } - - if(w[0] == '\0') { - return OK; - } - - /* if we see a bogus header don't ignore it. Shout and scream */ - - if(!(l = strchr(w,':'))) { - log_reason ("malformed header in meta file", r->filename, r); - return SERVER_ERROR; - } - - *l++ = '\0'; - while (*l && isspace (*l)) ++l; - - if(!strcasecmp(w,"Content-type")) { - - /* Nuke trailing whitespace */ - - char *endp = l + strlen(l) - 1; - while (endp > l && isspace(*endp)) *endp-- = '\0'; - - r->content_type = pstrdup (r->pool, l); - } - else if(!strcasecmp(w,"Status")) { - sscanf(l, "%d", &r->status); - r->status_line = pstrdup(r->pool, l); - } - else { - table_set (r->headers_out, w, l); - } - } - return OK; -} - -int add_cern_meta_data(request_rec *r) -{ - char *metafilename; - char *last_slash; - char *real_file; - char *scrap_book; - FILE *f; - cern_meta_config *cmc ; - int rv; - request_rec *rr; - - cmc = get_module_config (r->server->module_config, - &cern_meta_module); - - /* if ./.web/$1.meta exists then output 'asis' */ - - if (r->finfo.st_mode == 0) { - return DECLINED; - }; - - /* does uri end in a trailing slash? */ - if ( r->uri[strlen(r->uri) - 1] == '/' ) { - return DECLINED; - }; - - /* what directory is this file in? */ - scrap_book = pstrdup( r->pool, r->filename ); - /* skip leading slash, recovered in later processing */ - scrap_book++; - last_slash = strrchr( scrap_book, '/' ); - if ( last_slash != NULL ) { - /* skip over last slash */ - real_file = last_slash; - real_file++; - *last_slash = '\0'; - } else { - /* no last slash, buh?! */ - log_reason("internal error in mod_cern_meta", r->filename, r); - /* should really barf, but hey, let's be friends... */ - return DECLINED; - }; - - metafilename = pstrcat(r->pool, "/", scrap_book, "/", cmc->metadir, "/", real_file, cmc->metasuffix, NULL); - - /* XXX: it sucks to require this subrequest to complete, because this - * means people must leave their meta files accessible to the world. - * A better solution might be a "safe open" feature of pfopen to avoid - * pipes, symlinks, and crap like that. - */ - rr = sub_req_lookup_file (metafilename, r); - if (rr->status != HTTP_OK) { - destroy_sub_req (rr); - return DECLINED; - } - destroy_sub_req (rr); - - f = pfopen (r->pool, metafilename, "r"); - if (f == NULL) { - if (errno == ENOENT) { - return DECLINED; - } - log_reason("meta file permissions deny server access", metafilename, r); - return FORBIDDEN; - }; - - /* read the headers in */ - rv = scan_meta_file(r, f); - pfclose( r->pool, f ); - - return rv; -} - -module cern_meta_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - create_cern_meta_config, /* server config */ - NULL, /* merge server configs */ - cern_meta_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - add_cern_meta_data, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_cgi.c b/usr.sbin/httpd/src/mod_cgi.c deleted file mode 100644 index 6931d128878..00000000000 --- a/usr.sbin/httpd/src/mod_cgi.c +++ /dev/null @@ -1,575 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_script: keeps all script-related ramblings together. - * - * Compliant to CGI/1.1 spec - * - * Adapted by rst from original NCSA code by Rob McCool - * - * Apache adds some new env vars; REDIRECT_URL and REDIRECT_QUERY_STRING for - * custom error responses, and DOCUMENT_ROOT because we found it useful. - * It also adds SERVER_ADMIN - useful for scripts to know who to mail when - * they fail. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_log.h" -#include "util_script.h" -#include "http_conf_globals.h" - -module cgi_module; - -/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI - * in ScriptAliased directories, which means we need to know if this - * request came through ScriptAlias or not... so the Alias module - * leaves a note for us. - */ - -int is_scriptaliased (request_rec *r) -{ - char *t = table_get (r->notes, "alias-forced-type"); - return t && (!strcasecmp (t, "cgi-script")); -} - -/* Configuration stuff */ - -#define DEFAULT_LOGBYTES 10385760 -#define DEFAULT_BUFBYTES 1024 - -typedef struct { - char *logname; - long logbytes; - int bufbytes; -} cgi_server_conf; - -void *create_cgi_config (pool *p, server_rec *s) -{ - cgi_server_conf *c = - (cgi_server_conf *)pcalloc (p, sizeof(cgi_server_conf)); - - c->logname = NULL; - c->logbytes = DEFAULT_LOGBYTES; - c->bufbytes = DEFAULT_BUFBYTES; - - return c; -} - -void *merge_cgi_config (pool *p, void *basev, void *overridesv) -{ - cgi_server_conf *base = (cgi_server_conf *)basev, - *overrides = (cgi_server_conf *)overridesv; - - return overrides->logname ? overrides : base; -} - -const char *set_scriptlog (cmd_parms *cmd, void *dummy, char *arg) { - server_rec *s = cmd->server; - cgi_server_conf *conf = - (cgi_server_conf *)get_module_config(s->module_config, &cgi_module); - - conf->logname = arg; - return NULL; -} - -const char *set_scriptlog_length (cmd_parms *cmd, void *dummy, char *arg) { - server_rec *s = cmd->server; - cgi_server_conf *conf = - (cgi_server_conf *)get_module_config(s->module_config, &cgi_module); - - conf->logbytes = atol (arg); - return NULL; -} - -const char *set_scriptlog_buffer (cmd_parms *cmd, void *dummy, char *arg) { - server_rec *s = cmd->server; - cgi_server_conf *conf = - (cgi_server_conf *)get_module_config(s->module_config, &cgi_module); - - conf->bufbytes = atoi (arg); - return NULL; -} - -command_rec cgi_cmds[] = { -{ "ScriptLog", set_scriptlog, NULL, RSRC_CONF, TAKE1, - "the name of a log for script debugging info"}, -{ "ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF, TAKE1, - "the maximum length (in bytes) of the script debug log"}, -{ "ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, TAKE1, - "the maximum size (in bytes) to record of a POST request"}, -{ NULL} -}; - -static int log_scripterror(request_rec *r, cgi_server_conf *conf, int ret, - char *error) -{ - FILE *f; - - log_reason(error, r->filename, r); - - if (!conf->logname || - ((stat(server_root_relative(r->pool, conf->logname), &r->finfo) == 0) - && (r->finfo.st_size > conf->logbytes)) || - ((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname), - "a")) == NULL)) { - return ret; - } - - /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ - fprintf(f, "%%%% [%s] %s %s%s%s %s\n", get_time(), r->method, r->uri, - r->args ? "?" : "", r->args ? r->args : "", r->protocol); - /* "%% 500 /usr/local/etc/httpd/cgi-bin */ - fprintf(f, "%%%% %d %s\n", ret, r->filename); - - fprintf(f, "%%error\n%s\n", error); - - pfclose(r->pool, f); - return ret; -} - -static int log_script(request_rec *r, cgi_server_conf *conf, int ret, - char *dbuf, char *sbuf, FILE *script_in, FILE *script_err) -{ - table *hdrs_arr = r->headers_in; - table_entry *hdrs = (table_entry *)hdrs_arr->elts; - char argsbuffer[HUGE_STRING_LEN]; - FILE *f; - int i; - - if (!conf->logname || - ((stat(server_root_relative(r->pool, conf->logname), &r->finfo) == 0) - && (r->finfo.st_size > conf->logbytes)) || - ((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname), - "a")) == NULL)) { - /* Soak up script output */ - while (fgets(argsbuffer, MAX_STRING_LEN-1, script_in) != NULL) - continue; - while (fgets(argsbuffer, MAX_STRING_LEN-1, script_err) != NULL) - continue; - return ret; - } - - /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ - fprintf(f, "%%%% [%s] %s %s%s%s %s\n", get_time(), r->method, r->uri, - r->args ? "?" : "", r->args ? r->args : "", r->protocol); - /* "%% 500 /usr/local/etc/httpd/cgi-bin */ - fprintf(f, "%%%% %d %s\n", ret, r->filename); - - fputs("%request\n", f); - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (!hdrs[i].key) continue; - fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); - } - if ((r->method_number == M_POST || r->method_number == M_PUT) - && dbuf && *dbuf) { - fprintf(f, "\n%s\n", dbuf); - } - - fputs("%response\n", f); - hdrs_arr = r->err_headers_out; - hdrs = (table_entry *)hdrs_arr->elts; - - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (!hdrs[i].key) continue; - fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); - } - - if (sbuf && *sbuf) - fprintf(f, "%s\n", sbuf); - - *argsbuffer = '\0'; - fgets(argsbuffer, HUGE_STRING_LEN-1, script_in); - if (*argsbuffer) { - fputs("%stdout\n", f); - fputs(argsbuffer, f); - while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) - fputs(argsbuffer, f); - fputs("\n", f); - } - - *argsbuffer = '\0'; - fgets(argsbuffer, HUGE_STRING_LEN-1, script_err); - if (*argsbuffer) { - fputs("%stderr\n", f); - fputs(argsbuffer, f); - while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err) != NULL) - fputs(argsbuffer, f); - fputs("\n", f); - } - - pfclose(r->main ? r->main->pool : r->pool, script_in); - pfclose(r->main ? r->main->pool : r->pool, script_err); - - pfclose(r->pool, f); - return ret; -} - -/**************************************************************** - * - * Actual CGI handling... - */ - - -struct cgi_child_stuff { - request_rec *r; - int nph; - int debug; - char *argv0; -}; - -void cgi_child (void *child_stuff) -{ - struct cgi_child_stuff *cld = (struct cgi_child_stuff *)child_stuff; - request_rec *r = cld->r; - char *argv0 = cld->argv0; - int nph = cld->nph; - -#ifdef DEBUG_CGI -#ifdef __EMX__ - /* Under OS/2 need to use device con. */ - FILE *dbg = fopen ("con", "w"); -#else - FILE *dbg = fopen ("/dev/tty", "w"); -#endif - int i; -#endif - - char **env; - char err_string[HUGE_STRING_LEN]; - -#ifdef DEBUG_CGI - fprintf (dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n", - r->filename, nph ? "NPH " : "", argv0); -#endif - - add_cgi_vars (r); - env = create_environment (r->pool, r->subprocess_env); - -#ifdef DEBUG_CGI - fprintf (dbg, "Environment: \n"); - for (i = 0; env[i]; ++i) fprintf (dbg, "'%s'\n", env[i]); -#endif - - chdir_file (r->filename); - if (!cld->debug) - error_log2stderr (r->server); - -#ifndef __EMX__ - if (nph) client_to_stdout (r->connection); -#endif - - /* Transumute outselves into the script. - * NB only ISINDEX scripts get decoded arguments. - */ - - cleanup_for_exec(); - - call_exec(r, argv0, env, 0); - - /* Uh oh. Still here. Where's the kaboom? There was supposed to be an - * EARTH-shattering kaboom! - * - * Oh, well. Muddle through as best we can... - * - * (NB we can't use log_error, or anything like that, because we - * just closed the file descriptor which r->server->error_log - * was tied to in cleanup_for_exec(). It's only available on stderr - * now, so that's what we use). - */ - - ap_snprintf(err_string, sizeof(err_string), - "exec of %s failed, reason: %s (errno = %d)\n", - r->filename, strerror(errno), errno); - write(2, err_string, strlen(err_string)); - exit(0); -} - -int cgi_handler (request_rec *r) -{ - int retval, nph, dbpos = 0; - char *argv0, *dbuf = NULL; - FILE *script_out, *script_in, *script_err; - char argsbuffer[HUGE_STRING_LEN]; - int is_included = !strcmp (r->protocol, "INCLUDED"); - void *sconf = r->server->module_config; - cgi_server_conf *conf = - (cgi_server_conf *)get_module_config(sconf, &cgi_module); - - struct cgi_child_stuff cld; - pid_t child_pid; - - if (r->method_number == M_OPTIONS) { - /* 99 out of 100 CGI scripts, this is all they support */ - r->allowed |= (1 << M_GET); - r->allowed |= (1 << M_POST); - return DECLINED; - } - - if((argv0 = strrchr(r->filename,'/')) != NULL) - argv0++; - else argv0 = r->filename; - - nph = !(strncmp(argv0,"nph-",4)); - - if (!(allow_options (r) & OPT_EXECCGI) && !is_scriptaliased (r)) - return log_scripterror(r, conf, FORBIDDEN, - "Options ExecCGI is off in this directory"); - if (nph && is_included) - return log_scripterror(r, conf, FORBIDDEN, - "attempt to include NPH CGI script"); - - if (S_ISDIR(r->finfo.st_mode)) - return log_scripterror(r, conf, FORBIDDEN, - "attempt to invoke directory as script"); -#ifdef __EMX__ - /* Allow for cgi files without the .EXE extension on them under OS/2 */ - if (r->finfo.st_mode == 0) { - struct stat statbuf; - - r->filename = pstrcat (r->pool, r->filename, ".EXE", NULL); - - if ((stat(r->filename, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode))) { - return log_scripterror(r, conf, NOT_FOUND, - "script not found or unable to stat"); - } - } -#else - if (r->finfo.st_mode == 0) - return log_scripterror(r, conf, NOT_FOUND, - "script not found or unable to stat"); -#endif - if (!suexec_enabled) { - if (!can_exec(&r->finfo)) - return log_scripterror(r, conf, FORBIDDEN, - "file permissions deny server execution"); - } - - if ((retval = setup_client_block(r, REQUEST_CHUNKED_ERROR))) - return retval; - - add_common_vars (r); - cld.argv0 = argv0; cld.r = r; cld.nph = nph; - cld.debug = conf->logname ? 1 : 0; - - if (!(child_pid = - /* - * we spawn out of r->main if it's there so that we can avoid - * waiting for free_proc_chain to cleanup in the middle of an - * SSI request -djg - */ - spawn_child_err (r->main ? r->main->pool : r->pool, cgi_child, - (void *)&cld, - nph ? just_wait : kill_after_timeout, -#ifdef __EMX__ - &script_out, &script_in, &script_err))) { -#else - &script_out, nph ? NULL : &script_in, - &script_err))) { -#endif - log_reason ("couldn't spawn child process", r->filename, r); - return SERVER_ERROR; - } - - /* Transfer any put/post args, CERN style... - * Note that if a buggy script fails to read everything we throw - * at it, or a buggy client sends too much, we get a SIGPIPE, so - * we have to ignore SIGPIPE while doing this. CERN does the same - * (and in fact, they pretty nearly guarantee themselves a SIGPIPE - * on every invocation by chasing the real client data with a - * spurious newline). - */ - - if (should_client_block(r)) { - void (*handler)(); - int dbsize, len_read; - - if (conf->logname) { - dbuf = pcalloc(r->pool, conf->bufbytes+1); - dbpos = 0; - } - - hard_timeout ("copy script args", r); - handler = signal (SIGPIPE, SIG_IGN); - - while ((len_read = - get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0) - { - if (conf->logname) { - if ((dbpos + len_read) > conf->bufbytes) { - dbsize = conf->bufbytes - dbpos; - } - else { - dbsize = len_read; - } - memcpy(dbuf + dbpos, argsbuffer, dbsize); - dbpos += dbsize; - } - reset_timeout(r); - if (fwrite(argsbuffer, sizeof(char), len_read, script_out) - < (size_t)len_read) { - /* silly script stopped reading, soak up remaining message */ - while (get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0) - ; /* dump it */ - break; - } - } - - fflush (script_out); - signal (SIGPIPE, handler); - - kill_timeout (r); - } - - pfclose (r->main ? r->main->pool : r->pool, script_out); - - /* Handle script return... */ - if (script_in && !nph) { - char *location, sbuf[MAX_STRING_LEN]; - int ret; - - if ((ret = scan_script_header_err(r, script_in, sbuf))) - return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err); - - location = table_get (r->headers_out, "Location"); - - if (location && location[0] == '/' && r->status == 200) { - - /* Soak up all the script output */ - hard_timeout ("read from script", r); - while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_in) - > 0) - continue; - while (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err) - > 0) - continue; - kill_timeout (r); - - - /* This redirect needs to be a GET no matter what the original - * method was. - */ - r->method = pstrdup(r->pool, "GET"); - r->method_number = M_GET; - - /* We already read the message body (if any), so don't allow - * the redirected request to think it has one. We can ignore - * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. - */ - table_unset(r->headers_in, "Content-Length"); - - internal_redirect_handler (location, r); - return OK; - } - else if (location && r->status == 200) { - /* XX Note that if a script wants to produce its own Redirect - * body, it now has to explicitly *say* "Status: 302" - */ - return REDIRECT; - } - - send_http_header(r); - if (!r->header_only) - send_fd(script_in, r); - pfclose (r->main ? r->main->pool : r->pool, script_in); - - /* Soak up stderr */ - soft_timeout("soaking script stderr", r); - while (!r->connection->aborted && - (fread(argsbuffer, sizeof(char), HUGE_STRING_LEN, script_err) > 0)) - continue; - kill_timeout(r); - pfclose (r->main ? r->main->pool : r->pool, script_err); - } - - if (nph) { -#ifdef __EMX__ - while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) { - bputs(argsbuffer, r->connection->client); - } -#else - waitpid(child_pid, (int*)0, 0); -#endif - } - - return OK; /* NOT r->status, even if it has changed. */ -} - -handler_rec cgi_handlers[] = { -{ CGI_MAGIC_TYPE, cgi_handler }, -{ "cgi-script", cgi_handler }, -{ NULL } -}; - -module cgi_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - create_cgi_config, /* server config */ - merge_cgi_config, /* merge server config */ - cgi_cmds, /* command table */ - cgi_handlers, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_digest.c b/usr.sbin/httpd/src/mod_digest.c deleted file mode 100644 index 814f416d3e2..00000000000 --- a/usr.sbin/httpd/src/mod_digest.c +++ /dev/null @@ -1,363 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_digest: MD5 digest authentication - * - * by Alexei Kosut <akosut@nueva.pvt.k12.ca.us> - * based on mod_auth, by Rob McCool and Robert S. Thau - * - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_protocol.h" -#include "util_md5.h" - -typedef struct digest_config_struct { - char *pwfile; -} digest_config_rec; - -typedef struct digest_header_struct { - char *username; - char *realm; - char *nonce; - char *requested_uri; - char *digest; -} digest_header_rec; - -void *create_digest_dir_config (pool *p, char *d) -{ - return pcalloc (p, sizeof(digest_config_rec)); -} - -const char *set_digest_slot (cmd_parms *cmd, void *offset, char *f, char *t) -{ - if (t && strcmp(t, "standard")) - return pstrcat(cmd->pool, "Invalid auth file type: ", t, NULL); - - return set_string_slot(cmd, offset, f); -} - -command_rec digest_cmds[] = { -{ "AuthDigestFile", set_digest_slot, - (void*)XtOffsetOf(digest_config_rec,pwfile), OR_AUTHCFG, TAKE12, NULL }, -{ NULL } -}; - -module digest_module; - -char *get_hash(request_rec *r, char *user, char *auth_pwfile) -{ - FILE *f; - char l[MAX_STRING_LEN]; - const char *rpw; - char *w, *x; - - if(!(f=pfopen(r->pool, auth_pwfile, "r"))) { - log_reason ("Could not open password file", auth_pwfile, r); - return NULL; - } - while(!(cfg_getline(l,MAX_STRING_LEN,f))) { - if((l[0] == '#') || (!l[0])) continue; - rpw = l; - w = getword(r->pool, &rpw, ':'); - x = getword(r->pool, &rpw, ':'); - - if(x && w && !strcmp(user,w) && !strcmp(auth_name(r), x)) { - pfclose(r->pool, f); - return pstrdup (r->pool, rpw); - } - } - pfclose(r->pool, f); - return NULL; -} - -/* Parse the Authorization header, if it exists */ - -int get_digest_rec(request_rec *r, digest_header_rec *response) { - const char *auth_line = table_get(r->headers_in, "Authorization"); - int l; - int s = 0, vk = 0, vv = 0; - char *t, *key, *value; - - if (!(t = auth_type(r)) || strcasecmp(t, "Digest")) - return DECLINED; - - if (!auth_name (r)) { - log_reason ("need AuthName", r->uri, r); - return SERVER_ERROR; - } - - if (!auth_line) { - note_digest_auth_failure (r); - return AUTH_REQUIRED; - } - - if (strcasecmp(getword (r->pool, &auth_line, ' '), "Digest")) { - /* Client tried to authenticate using wrong auth scheme */ - log_reason ("client used wrong authentication scheme", r->uri, r); - note_digest_auth_failure (r); - return AUTH_REQUIRED; - } - - l = strlen(auth_line); - - key=palloc(r->pool,l); - value=palloc(r->pool,l); - - /* There's probably a better way to do this, but for the time being... */ - -#define D_KEY 0 -#define D_VALUE 1 -#define D_STRING 2 -#define D_EXIT -1 - - while (s != D_EXIT) { - switch (s) { - case D_STRING: - if (auth_line[0] == '\"') { - s = D_VALUE; - } - else { - value[vv] = auth_line[0]; - vv++; - } - auth_line++; - break; - - case D_VALUE: - if (isalnum(auth_line[0])) { - value[vv] = auth_line[0]; - vv++; - } - else if (auth_line[0] == '\"') { - s = D_STRING; - } - else { - value[vv] = '\0'; - - if (!strcasecmp(key, "username")) - response->username = pstrdup(r->pool, value); - else if (!strcasecmp(key, "realm")) - response->realm = pstrdup(r->pool, value); - else if (!strcasecmp(key, "nonce")) - response->nonce = pstrdup(r->pool, value); - else if (!strcasecmp(key, "uri")) - response->requested_uri = pstrdup(r->pool, value); - else if (!strcasecmp(key, "response")) - response->digest = pstrdup(r->pool, value); - - vv = 0; - s = D_KEY; - } - auth_line++; - break; - - case D_KEY: - if (isalnum(auth_line[0])) { - key[vk] = auth_line[0]; - vk++; - } - else if (auth_line[0] == '=') { - key[vk] = '\0'; - vk = 0; - s = D_VALUE; - } - auth_line++; - break; - } - - if (auth_line[-1] == '\0') - s = D_EXIT; - } - - if (!response->username || !response->realm || !response->nonce || - !response->requested_uri || !response->digest) { - note_digest_auth_failure (r); - return AUTH_REQUIRED; - } - - r->connection->user = response->username; - r->connection->auth_type = "Digest"; - - return OK; -} - -/* The actual MD5 code... whee */ - -char *find_digest(request_rec *r, digest_header_rec *h, char *a1) { - return md5(r->pool, - (unsigned char *)pstrcat(r->pool, a1, ":", h->nonce, ":", - md5(r->pool, - (unsigned char *)pstrcat(r->pool,r->method,":", - h->requested_uri,NULL)), - NULL)); -} - -/* These functions return 0 if client is OK, and proper error status - * if not... either AUTH_REQUIRED, if we made a check, and it failed, or - * SERVER_ERROR, if things are so totally confused that we couldn't - * figure out how to tell if the client is authorized or not. - * - * If they return DECLINED, and all other modules also decline, that's - * treated by the server core as a configuration error, logged and - * reported as such. - */ - -/* Determine user ID, and check if it really is that user, for HTTP - * basic authentication... - */ - -int authenticate_digest_user (request_rec *r) -{ - digest_config_rec *sec = - (digest_config_rec *)get_module_config (r->per_dir_config, - &digest_module); - digest_header_rec *response = pcalloc (r->pool, sizeof(digest_header_rec)); - conn_rec *c = r->connection; - char *a1; - char errstr[MAX_STRING_LEN]; - int res; - - if ((res = get_digest_rec (r, response))) return res; - - if(!sec->pwfile) - return DECLINED; - - if (!(a1 = get_hash(r, c->user, sec->pwfile))) { - ap_snprintf(errstr, sizeof(errstr), "user %s not found",c->user); - log_reason (errstr, r->uri, r); - note_digest_auth_failure (r); - return AUTH_REQUIRED; - } - /* anyone know where the prototype for crypt is? */ - if(strcmp(response->digest, find_digest(r, response, a1))) { - ap_snprintf(errstr, sizeof(errstr), "user %s: password mismatch",c->user); - log_reason (errstr, r->uri, r); - note_digest_auth_failure (r); - return AUTH_REQUIRED; - } - return OK; -} - -/* Checking ID */ - -int digest_check_auth (request_rec *r) { - char *user = r->connection->user; - int m = r->method_number; - int method_restricted = 0; - register int x; - const char *t; - char *w; - array_header *reqs_arr; - require_line *reqs; - - if (!(t = auth_type(r)) || strcasecmp(t, "Digest")) - return DECLINED; - - reqs_arr = requires (r); - /* If there is no "requires" directive, - * then any user will do. - */ - if (!reqs_arr) - return OK; - reqs = (require_line *)reqs_arr->elts; - - for(x=0; x < reqs_arr->nelts; x++) { - - if (! (reqs[x].method_mask & (1 << m))) continue; - - method_restricted = 1; - - t = reqs[x].requirement; - w = getword(r->pool, &t, ' '); - if(!strcmp(w,"valid-user")) - return OK; - else if(!strcmp(w,"user")) { - while(t[0]) { - w = getword_conf (r->pool, &t); - if(!strcmp(user,w)) - return OK; - } - } - else - return DECLINED; - } - - if (!method_restricted) - return OK; - - note_digest_auth_failure(r); - return AUTH_REQUIRED; -} - -module digest_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_digest_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - digest_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - authenticate_digest_user, /* check_user_id */ - digest_check_auth, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_dir.c b/usr.sbin/httpd/src/mod_dir.c deleted file mode 100644 index 435b5d3378f..00000000000 --- a/usr.sbin/httpd/src/mod_dir.c +++ /dev/null @@ -1,911 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_dir.c: Handles the on-the-fly html index generation - * - * Rob McCool - * 3/23/93 - * - * Adapted to Apache by rst. - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_request.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "util_script.h" - -module dir_module; - -/**************************************************************** - * - * Handling configuration directives... - */ - -#define FANCY_INDEXING 1 /* Indexing options */ -#define ICONS_ARE_LINKS 2 -#define SCAN_HTML_TITLES 4 -#define SUPPRESS_LAST_MOD 8 -#define SUPPRESS_SIZE 16 -#define SUPPRESS_DESC 32 - -struct item { - char *type; - char *apply_to; - char *apply_path; - char *data; -}; - -typedef struct dir_config_struct { - - char *default_icon; - char *index_names; - - array_header *icon_list, *alt_list, *desc_list, *ign_list; - array_header *hdr_list, *rdme_list, *opts_list; - -} dir_config_rec; - -char c_by_encoding, c_by_type, c_by_path; - -#define BY_ENCODING &c_by_encoding -#define BY_TYPE &c_by_type -#define BY_PATH &c_by_path - -void push_item(array_header *arr, char *type, char *to, char *path, char *data) -{ - struct item *p = (struct item *)push_array(arr); - - if (!to) to = ""; - if (!path) path = ""; - - p->type = type; - p->data = data ? pstrdup(arr->pool, data): NULL; - p->apply_path = pstrcat(arr->pool, path, "*", NULL); - - if((type == BY_PATH) && (!is_matchexp(to))) - p->apply_to = pstrcat (arr->pool, "*", to, NULL); - else if (to) - p->apply_to = pstrdup (arr->pool, to); - else - p->apply_to = NULL; -} - -const char *add_alt(cmd_parms *cmd, void *d, char *alt, char *to) -{ - if (cmd->info == BY_PATH) - if(!strcmp(to,"**DIRECTORY**")) - to = "^^DIRECTORY^^"; - - push_item(((dir_config_rec *)d)->alt_list, cmd->info, to, cmd->path, alt); - return NULL; -} - -const char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to) -{ - char *iconbak = pstrdup (cmd->pool, icon); - - if(icon[0] == '(') { - char *alt = getword_nc (cmd->pool, &iconbak, ','); - iconbak[strlen(iconbak) - 1] = '\0'; /* Lose closing paren */ - add_alt(cmd, d, &alt[1], to); - } - if(cmd->info == BY_PATH) - if(!strcmp(to,"**DIRECTORY**")) - to = "^^DIRECTORY^^"; - - push_item(((dir_config_rec *)d)->icon_list, cmd->info, to, cmd->path, - iconbak); - return NULL; -} - -const char *add_desc(cmd_parms *cmd, void *d, char *desc, char *to) -{ - push_item(((dir_config_rec *)d)->desc_list, cmd->info, to, cmd->path,desc); - return NULL; -} - -const char *add_ignore(cmd_parms *cmd, void *d, char *ext) { - push_item(((dir_config_rec *)d)->ign_list, 0, ext, cmd->path, NULL); - return NULL; -} - -const char *add_header(cmd_parms *cmd, void *d, char *name) { - if (strchr (name, '/')) { - return "HeaderName cannot contain a /"; - } - push_item(((dir_config_rec *)d)->hdr_list, 0, NULL, cmd->path, name); - return NULL; -} - -const char *add_readme(cmd_parms *cmd, void *d, char *name) { - if (strchr (name, '/')) { - return "ReadmeName cannot contain a /"; - } - push_item(((dir_config_rec *)d)->rdme_list, 0, NULL, cmd->path, name); - return NULL; -} - - -const char *add_opts_int(cmd_parms *cmd, void *d, int opts) { - push_item(((dir_config_rec *)d)->opts_list, (char*)opts, NULL, - cmd->path, NULL); - return NULL; -} - -const char *fancy_indexing (cmd_parms *cmd, void *d, int arg) -{ - return add_opts_int (cmd, d, arg? FANCY_INDEXING : 0); -} - -const char *add_opts(cmd_parms *cmd, void *d, const char *optstr) { - char *w; - int opts = 0; - - while(optstr[0]) { - w = getword_conf(cmd->pool, &optstr); - if(!strcasecmp(w,"FancyIndexing")) - opts |= FANCY_INDEXING; - else if(!strcasecmp(w,"IconsAreLinks")) - opts |= ICONS_ARE_LINKS; - else if(!strcasecmp(w,"ScanHTMLTitles")) - opts |= SCAN_HTML_TITLES; - else if(!strcasecmp(w,"SuppressLastModified")) - opts |= SUPPRESS_LAST_MOD; - else if(!strcasecmp(w,"SuppressSize")) - opts |= SUPPRESS_SIZE; - else if(!strcasecmp(w,"SuppressDescription")) - opts |= SUPPRESS_DESC; - else if(!strcasecmp(w,"None")) - opts = 0; - else - return "Invalid directory indexing option"; - } - return add_opts_int(cmd, d, opts); -} - -#define DIR_CMD_PERMS OR_INDEXES - -command_rec dir_cmds[] = { -{ "AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2, - "an icon URL followed by one or more filenames" }, -{ "AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2, - "an icon URL followed by one or more MIME types" }, -{ "AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, ITERATE2, - "an icon URL followed by one or more content encodings" }, -{ "AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, ITERATE2, - "alternate descriptive text followed by one or more filenames" }, -{ "AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, ITERATE2, - "alternate descriptive text followed by one or more MIME types" }, -{ "AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, ITERATE2, - "alternate descriptive text followed by one or more content encodings" }, -{ "IndexOptions", add_opts, NULL, DIR_CMD_PERMS, RAW_ARGS, - "one or more index options" }, -{ "IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, ITERATE, - "one or more file extensions" }, -{ "AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, ITERATE2, - "Descriptive text followed by one or more filenames" }, -{ "HeaderName", add_header, NULL, DIR_CMD_PERMS, TAKE1, "a filename" }, -{ "ReadmeName", add_readme, NULL, DIR_CMD_PERMS, TAKE1, "a filename" }, -{ "FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, FLAG, NULL }, -{ "DefaultIcon", set_string_slot, - (void*)XtOffsetOf(dir_config_rec, default_icon), - DIR_CMD_PERMS, TAKE1, "an icon URL"}, -{ "DirectoryIndex", set_string_slot, - (void*)XtOffsetOf(dir_config_rec, index_names), - DIR_CMD_PERMS, RAW_ARGS, NULL }, -{ NULL } -}; - -void *create_dir_config (pool *p, char *dummy) -{ - dir_config_rec *new = - (dir_config_rec *) pcalloc (p, sizeof(dir_config_rec)); - - new->index_names = NULL; - new->icon_list = make_array (p, 4, sizeof (struct item)); - new->alt_list = make_array (p, 4, sizeof (struct item)); - new->desc_list = make_array (p, 4, sizeof (struct item)); - new->ign_list = make_array (p, 4, sizeof (struct item)); - new->hdr_list = make_array (p, 4, sizeof (struct item)); - new->rdme_list = make_array (p, 4, sizeof (struct item)); - new->opts_list = make_array (p, 4, sizeof (struct item)); - - return (void *)new; -} - -void *merge_dir_configs (pool *p, void *basev, void *addv) -{ - dir_config_rec *new=(dir_config_rec*)pcalloc (p, sizeof(dir_config_rec)); - dir_config_rec *base = (dir_config_rec *)basev; - dir_config_rec *add = (dir_config_rec *)addv; - - new->default_icon = add->default_icon?add->default_icon:base->default_icon; - new->index_names = add->index_names? add->index_names: base->index_names; - - new->alt_list = append_arrays (p, add->alt_list, base->alt_list); - new->ign_list = append_arrays (p, add->ign_list, base->ign_list); - new->hdr_list = append_arrays (p, add->hdr_list, base->hdr_list); - new->desc_list = append_arrays (p, add->desc_list, base->desc_list); - new->icon_list = append_arrays (p, add->icon_list, base->icon_list); - new->rdme_list = append_arrays (p, add->rdme_list, base->rdme_list); - new->opts_list = append_arrays (p, add->opts_list, base->opts_list); - - return new; -} - -/**************************************************************** - * - * Looking things up in config entries... - */ - -/* Structure used to hold entries when we're actually building an index */ - -struct ent { - char *name; - char *icon; - char *alt; - char *desc; - size_t size; - time_t lm; - struct ent *next; -}; - -char *find_item(request_rec *r, array_header *list, int path_only) { - char *content_type = r->content_type; - char *content_encoding = r->content_encoding; - char *path = r->filename; - - struct item *items = (struct item *)list->elts; - int i; - - for (i = 0; i < list->nelts; ++i) { - struct item *p = &items[i]; - - /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */ - if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) { - if(!*(p->apply_to)) - return p->data; - else if(p->type == BY_PATH || path[0] == '^') { - if(!strcmp_match(path,p->apply_to)) - return p->data; - } else if(!path_only) { - if(!content_encoding) { - if(p->type == BY_TYPE) { - if(content_type && !strcmp_match(content_type,p->apply_to)) - return p->data; - } - } else { - if(p->type == BY_ENCODING) { - if(!strcmp_match(content_encoding,p->apply_to)) - return p->data; - } - } - } - } - } - return NULL; -} - -#define find_icon(d,p,t) find_item(p,d->icon_list,t) -#define find_alt(d,p,t) find_item(p,d->alt_list,t) -#define find_desc(d,p) find_item(p,d->desc_list,0) -#define find_header(d,p) find_item(p,d->hdr_list,0) -#define find_readme(d,p) find_item(p,d->rdme_list,0) - -char *find_default_icon (dir_config_rec *d, char *bogus_name) -{ - request_rec r; - - /* Bleah. I tried to clean up find_item, and it lead to this bit - * of ugliness. Note that the fields initialized are precisely - * those that find_item looks at... - */ - - r.filename = bogus_name; - r.content_type = r.content_encoding = NULL; - - return find_item (&r, d->icon_list, 1); -} - -int ignore_entry(dir_config_rec *d, char *path) { - array_header *list = d->ign_list; - struct item *items = (struct item *)list->elts; - char *tt; - int i; - - if((tt=strrchr(path,'/')) == NULL) - tt=path; - else { - tt++; - } - - for (i = 0; i < list->nelts; ++i) { - struct item *p = &items[i]; - char *ap; - - if((ap=strrchr(p->apply_to,'/')) == NULL) - ap=p->apply_to; - else - ap++; - - if(!strcmp_match(path,p->apply_path) && !strcmp_match(tt,ap)) - return 1; - } - return 0; -} - -int find_opts(dir_config_rec *d, request_rec *r) { - char *path = r->filename; - array_header *list = d->opts_list; - struct item *items = (struct item *)list->elts; - int i; - - for (i = 0; i < list->nelts; ++i) { - struct item *p = &items[i]; - - if(!strcmp_match(path,p->apply_path)) - return (int)p->type; - } - return 0; -} - -/***************************************************************** - * - * Actually generating output - */ - - -int insert_readme(char *name, char *readme_fname, int rule, request_rec *r) { - char *fn; - FILE *f; - struct stat finfo; - int plaintext=0; - request_rec *rr; - - /* XXX: this is a load of crap, it needs to do a full sub_req_lookup_uri */ - fn = make_full_path(r->pool, name, readme_fname); - fn = pstrcat(r->pool, fn, ".html", NULL); - if(stat(fn,&finfo) == -1) { - /* A brief fake multiviews search for README.html */ - fn[strlen(fn)-5] = '\0'; - if(stat(fn,&finfo) == -1) - return 0; - plaintext=1; - if(rule) rputs("<HR>\n", r); - rputs("<PRE>\n", r); - } - else if (rule) rputs("<HR>\n", r); - /* XXX: when the above is rewritten properly, this necessary security - * check will be redundant. -djg */ - rr = sub_req_lookup_file (fn, r); - if (rr->status != HTTP_OK) { - destroy_sub_req (rr); - return 0; - } - destroy_sub_req (rr); - if(!(f = pfopen(r->pool,fn,"r"))) - return 0; - if (!plaintext) - send_fd(f, r); - else - { - char buf[IOBUFSIZE+1]; - int i, n, c, ch; - while (!feof(f)) - { - do n = fread(buf, sizeof(char), IOBUFSIZE, f); - while (n == -1 && ferror(f) && errno == EINTR); - if (n == -1 || n == 0) break; - buf[n] = '\0'; - c = 0; - while (c < n) - { - for (i=c; i < n; i++) - if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') break; - ch = buf[i]; - buf[i] = '\0'; - rputs(&buf[c], r); - if (ch == '<') rputs("<", r); - else if (ch == '>') rputs(">", r); - else if (ch == '&') rputs("&", r); - c = i + 1; - } - } - } - pfclose(r->pool, f); - if(plaintext) - rputs("</PRE>\n", r); - return 1; -} - - -char *find_title(request_rec *r) { - char titlebuf[MAX_STRING_LEN], *find = "<TITLE>"; - FILE *thefile = NULL; - int x,y,n,p; - - if (r->status != HTTP_OK) { - return NULL; - } - if (r->content_type && !strcasecmp(r->content_type,"text/html") && !r->content_encoding) { - if(!(thefile = pfopen(r->pool, r->filename,"r"))) - return NULL; - n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile); - titlebuf[n] = '\0'; - for(x=0,p=0;titlebuf[x];x++) { - if(toupper(titlebuf[x]) == find[p]) { - if(!find[++p]) { - if((p = ind(&titlebuf[++x],'<')) != -1) - titlebuf[x+p] = '\0'; - /* Scan for line breaks for Tanmoy's secretary */ - for(y=x;titlebuf[y];y++) - if((titlebuf[y] == CR) || (titlebuf[y] == LF)) - titlebuf[y] = ' '; - pfclose (r->pool, thefile); - return pstrdup(r->pool, &titlebuf[x]); - } - } else p=0; - } - pfclose(r->pool, thefile); - } - return NULL; -} - -struct ent *make_dir_entry(char *name, int dir_opts, - dir_config_rec *d, request_rec *r) -{ - struct ent *p; - - if((name[0] == '.') && (!name[1])) - return(NULL); - - if (ignore_entry(d, make_full_path (r->pool, r->filename, name))) - return(NULL); - - p=(struct ent *)pcalloc(r->pool, sizeof(struct ent)); - p->name = pstrdup (r->pool, name); - p->size = -1; - p->icon = NULL; - p->alt = NULL; - p->desc = NULL; - p->lm = -1; - - if(dir_opts & FANCY_INDEXING) { - request_rec *rr = sub_req_lookup_file (name, r); - - if (rr->finfo.st_mode != 0) { - p->lm = rr->finfo.st_mtime; - if(S_ISDIR(rr->finfo.st_mode)) { - if(!(p->icon = find_icon(d,rr,1))) - p->icon = find_default_icon(d,"^^DIRECTORY^^"); - if(!(p->alt = find_alt(d,rr,1))) - p->alt = "DIR"; - p->size = -1; - p->name = pstrcat (r->pool, name, "/", NULL); - } - else { - p->icon = find_icon(d, rr, 0); - p->alt = find_alt(d, rr, 0); - p->size = rr->finfo.st_size; - } - } - - p->desc = find_desc(d, rr); - - if((!p->desc) && (dir_opts & SCAN_HTML_TITLES)) - p->desc = pstrdup (r->pool, find_title(rr)); - - destroy_sub_req (rr); - } - return(p); -} - -char *terminate_description(dir_config_rec *d, char *desc, int dir_opts) { - int maxsize = 23; - register int x; - - if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17; - if(dir_opts & SUPPRESS_SIZE) maxsize += 7; - - for(x=0;desc[x] && maxsize;x++) { - if(desc[x] == '<') { - while(desc[x] != '>') { - if(!desc[x]) { - maxsize = 0; - break; - } - ++x; - } - } - else --maxsize; - } - if(!maxsize) { - desc[x-1] = '>'; /* Grump. */ - desc[x] = '\0'; /* Double Grump! */ - } - return desc; -} - -void output_directories(struct ent **ar, int n, - dir_config_rec *d, request_rec *r, int dir_opts) -{ - int x, len; - char *name = r->uri; - char *tp; - pool *scratch = make_sub_pool (r->pool); - - if(name[0] == '\0') name = "/"; - - if(dir_opts & FANCY_INDEXING) { - rputs("<PRE>", r); - if((tp = find_default_icon(d,"^^BLANKICON^^"))) - rvputs(r, "<IMG SRC=\"", escape_html(scratch, tp), - "\" ALT=\" \"> ", NULL); - rputs("Name ", r); - if(!(dir_opts & SUPPRESS_LAST_MOD)) - rputs("Last modified ", r); - if(!(dir_opts & SUPPRESS_SIZE)) - rputs("Size ", r); - if(!(dir_opts & SUPPRESS_DESC)) - rputs("Description", r); - rputs("\n<HR>\n", r); - } - else { - rputs("<UL>", r); - } - - for(x=0;x<n;x++) { - char *anchor = NULL, *t = NULL, *t2 = NULL; - - clear_pool (scratch); - - if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) { - char *t = make_full_path (scratch, name, "../"); - getparents(t); - if(t[0] == '\0') t = "/"; - anchor = pstrcat (scratch, "<A HREF=\"", - escape_html(scratch, os_escape_path(scratch, t, 0)), - "\">", NULL); - t2 = "Parent Directory</A> "; - } - else { - t = ar[x]->name; - len = strlen(t); - if(len > 23) { - t2 = pstrdup(scratch, t); - t2[21] = '.'; - t2[22] = '.'; - t2[23] = '\0'; - t2 = escape_html(scratch, t2); - t2 = pstrcat(scratch, t2, "</A>", NULL); - } else - { - char buff[24]=" "; - t2 = escape_html(scratch, t); - buff[23-len] = '\0'; - t2 = pstrcat(scratch, t2, "</A>", buff, NULL); - } - anchor = pstrcat (scratch, "<A HREF=\"", - escape_html(scratch, os_escape_path(scratch, t, 0)), - "\">", NULL); - } - - if(dir_opts & FANCY_INDEXING) { - if(dir_opts & ICONS_ARE_LINKS) - rputs(anchor, r); - if((ar[x]->icon) || d->default_icon) { - rvputs(r, "<IMG SRC=\"", - escape_html(scratch, ar[x]->icon ? - ar[x]->icon : d->default_icon), - "\" ALT=\"[", (ar[x]->alt ? ar[x]->alt : " "), - "]\">", NULL); - } - if(dir_opts & ICONS_ARE_LINKS) - rputs("</A>", r); - - rvputs(r," ", anchor, t2, NULL); - if(!(dir_opts & SUPPRESS_LAST_MOD)) { - if(ar[x]->lm != -1) { - char time[MAX_STRING_LEN]; - struct tm *ts = localtime(&ar[x]->lm); - strftime(time,MAX_STRING_LEN,"%d-%b-%y %H:%M ",ts); - rputs(time, r); - } - else { - rputs(" ", r); - } - } - if(!(dir_opts & SUPPRESS_SIZE)) { - send_size(ar[x]->size,r); - rputs(" ", r); - } - if(!(dir_opts & SUPPRESS_DESC)) { - if(ar[x]->desc) { - rputs(terminate_description(d, ar[x]->desc, dir_opts), r); - } - } - } - else - rvputs(r, "<LI> ", anchor," ", t2, NULL); - rputc('\n', r); - } - if(dir_opts & FANCY_INDEXING) { - rputs("</PRE>", r); - } - else { - rputs("</UL>", r); - } -} - - -int dsortf(struct ent **s1,struct ent **s2) -{ - return(strcmp((*s1)->name,(*s2)->name)); -} - - -int index_directory(request_rec *r, dir_config_rec *dir_conf) -{ - char *title_name = escape_html(r->pool, r->uri); - char *title_endp; - char *name = r->filename; - - DIR *d; - struct DIR_TYPE *dstruct; - int num_ent=0,x; - struct ent *head,*p; - struct ent **ar = NULL; - char *tmp; - int dir_opts = find_opts(dir_conf, r); - - if(!(d=opendir(name))) { - log_reason ("Can't open directory for index", r->filename, r); - return HTTP_FORBIDDEN; - } - - r->content_type = "text/html"; - - send_http_header(r); - - if (r->header_only) { - closedir (d); - return 0; - } - hard_timeout("send directory", r); - - /* Spew HTML preamble */ - - title_endp = title_name + strlen(title_name) - 1; - - while (title_endp > title_name && *title_endp == '/') - *title_endp-- = '\0'; - - rvputs - ( - r, - "<HTML><HEAD>\n<TITLE>Index of ", - title_name, - "</TITLE>\n</HEAD><BODY>\n", - NULL - ); - - if((!(tmp = find_header(dir_conf,r))) || (!(insert_readme(name,tmp,0,r)))) - rvputs(r, "<H1>Index of ", title_name, "</H1>\n", NULL); - - /* - * Since we don't know how many dir. entries there are, put them into a - * linked list and then arrayificate them so qsort can use them. - */ - head=NULL; - while((dstruct=readdir(d))) { - if((p = make_dir_entry(dstruct->d_name, dir_opts, dir_conf, r))) { - p->next=head; - head=p; - num_ent++; - } - } - if (num_ent > 0) { - ar=(struct ent **) palloc(r->pool, num_ent*sizeof(struct ent *)); - p=head; - x=0; - while(p) { - ar[x++]=p; - p = p->next; - } - - qsort((void *)ar,num_ent,sizeof(struct ent *), -#ifdef ULTRIX_BRAIN_DEATH - (int (*))dsortf); -#else - (int (*)(const void *,const void *))dsortf); -#endif - } - output_directories(ar, num_ent, dir_conf, r, dir_opts); - closedir(d); - - if (dir_opts & FANCY_INDEXING) - if((tmp = find_readme(dir_conf, r))) - insert_readme(name,tmp,1,r); - else { - rputs("</UL>", r); - } - - rputs ("</BODY></HTML>\n", r); - - kill_timeout(r); - return 0; -} - -/* The formal handler... */ - -int handle_dir (request_rec *r) -{ - dir_config_rec *d = - (dir_config_rec *)get_module_config (r->per_dir_config, &dir_module); - const char *names_ptr = d->index_names ? d->index_names : DEFAULT_INDEX; - int allow_opts = allow_options (r); - int error_notfound = 0; - - if (r->uri[0] == '\0' || r->uri[strlen(r->uri)-1] != '/') { - char* ifile; - if (r->args != NULL) - ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri), - "/", "?", r->args, NULL); - else - ifile = pstrcat (r->pool, escape_uri(r->pool, r->uri), - "/", NULL); - - table_set (r->headers_out, "Location", - construct_url(r->pool, ifile, r->server)); - return HTTP_MOVED_PERMANENTLY; - } - - /* KLUDGE --- make the sub_req lookups happen in the right directory. - * Fixing this in the sub_req_lookup functions themselves is difficult, - * and would probably break virtual includes... - */ - - r->filename = pstrcat (r->pool, r->filename, "/", NULL); - - while (*names_ptr) { - - char *name_ptr = getword_conf (r->pool, &names_ptr); - request_rec *rr = sub_req_lookup_uri (name_ptr, r); - - if (rr->status == HTTP_OK && rr->finfo.st_mode != 0) { - char* new_uri = escape_uri(r->pool, rr->uri); - - if (rr->args != NULL) - new_uri = pstrcat(r->pool, new_uri, "?", rr->args, NULL); - else if (r->args != NULL) - new_uri = pstrcat(r->pool, new_uri, "?", r->args, NULL); - - destroy_sub_req (rr); - internal_redirect (new_uri, r); - return OK; - } - - /* If the request returned a redirect, propagate it to the client */ - - if (is_HTTP_REDIRECT(rr->status) || - (rr->status == HTTP_NOT_ACCEPTABLE && *names_ptr == '\0')) { - - error_notfound = rr->status; - r->notes = overlay_tables(r->pool, r->notes, rr->notes); - r->headers_out = overlay_tables(r->pool, r->headers_out, - rr->headers_out); - r->err_headers_out = overlay_tables(r->pool, r->err_headers_out, - rr->err_headers_out); - destroy_sub_req(rr); - return error_notfound; - } - - /* If the request returned something other than 404 (or 200), - * it means the module encountered some sort of problem. To be - * secure, we should return the error, rather than create - * along a (possibly unsafe) directory index. - * - * So we store the error, and if none of the listed files - * exist, we return the last error response we got, instead - * of a directory listing. - */ - if (rr->status && rr->status != HTTP_NOT_FOUND && rr->status != HTTP_OK) - error_notfound = rr->status; - - destroy_sub_req (rr); - } - - if (error_notfound) - return error_notfound; - - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) return NOT_IMPLEMENTED; - - /* OK, nothing easy. Trot out the heavy artillery... */ - - if (allow_opts & OPT_INDEXES) - return index_directory (r, d); - else { - log_reason ("Directory index forbidden by rule", r->filename, r); - return HTTP_FORBIDDEN; - } -} - - -handler_rec dir_handlers[] = { -{ DIR_MAGIC_TYPE, handle_dir }, -{ NULL } -}; - -module dir_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_dir_config, /* dir config creater */ - merge_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - dir_cmds, /* command table */ - dir_handlers, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_dld.c b/usr.sbin/httpd/src/mod_dld.c deleted file mode 100644 index ac6ff33a7ad..00000000000 --- a/usr.sbin/httpd/src/mod_dld.c +++ /dev/null @@ -1,190 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * A first stab at dynamic loading, using the GNU dld library - * (or at least, an embarassingly old version of it...). - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_conf_globals.h" /* server_argv0. Sigh... */ -#include <dld.h> - -/* - * The hard part of implementing LoadModule is deciding what to do about - * rereading the config files. This proof-of-concept implementation takes the - * cheap way out: we only actually load the modules the first time through. - */ - -static int been_there_done_that = 0; /* Loaded the modules yet? */ -static int have_symbol_table = 0; - -char *insure_dld_sane() -{ - int errcode; - char *bin_name; - - if (have_symbol_table) return NULL; - - bin_name = dld_find_executable (server_argv0); - - if ((errcode = dld_init (bin_name))) { - dld_perror (server_argv0); - return "Cannot find server binary (needed for dynamic linking)."; - } - - have_symbol_table = 1; - return NULL; -} - -char *link_file (pool *p, char *filename) -{ - int errcode; - - filename = server_root_relative (p, filename); - if ((errcode = dld_link (filename))) { - dld_perror (server_argv0); - return pstrcat (p, "Cannot load ", filename, " into server", NULL); - } - return NULL; -} - -char *load_module (cmd_parms *cmd, void *dummy, char *modname, char *filename) -{ - char *errname; - module *modp; - - if (been_there_done_that) return NULL; - - if ((errname = insure_dld_sane())) return errname; - if ((errname = link_file (cmd->pool, filename))) return errname; - if (!(modp = (module *)dld_get_symbol (modname))) { - return pstrcat (cmd->pool, "Can't find module ", modname, - " in file ", filename, NULL); - } - - add_module (modp); - - /* Alethea Patch (rws,djw2) - need to run configuration functions - in new modules */ - - if (modp->create_server_config) - ((void**)cmd->server->module_config)[modp->module_index]= - (*modp->create_server_config)(cmd->pool, cmd->server); - - if (modp->create_dir_config) - ((void**)cmd->server->lookup_defaults)[modp->module_index]= - (*modp->create_dir_config)(cmd->pool, NULL); - - - return NULL; -} - -char *load_file (cmd_parms *cmd, void *dummy, char *filename) -{ - char *errname; - - if (been_there_done_that) return NULL; - - if ((errname = insure_dld_sane())) return errname; - if ((errname = link_file (cmd->pool, filename))) return errname; - return NULL; -} - -void check_loaded_modules (server_rec *dummy, pool *p) -{ - if (been_there_done_that) return; - - if (dld_undefined_sym_count > 0) { - /* Screwup. Do the best we can to inform the user, and exit */ - char **bad_syms = dld_list_undefined_sym(); - int i; - - fprintf(stderr, "Dynamic linking error --- symbols left undefined.\n"); - fprintf(stderr, "(It may help to relink libraries).\n"); - fprintf(stderr, "Undefined symbols follow:\n"); - - for (i = 0; i < dld_undefined_sym_count; ++i) - fprintf (stderr, "%s\n", bad_syms[i]); - - exit (1); - } - - been_there_done_that = 1; -} - -command_rec dld_cmds[] = { -{ "LoadModule", load_module, NULL, RSRC_CONF, TAKE2, - "a module name, and the name of a file to load it from"}, -{ "LoadFile", load_file, NULL, RSRC_CONF, ITERATE, - "files or libraries to link into the server at runtime"}, -{ NULL } -}; - -module dld_module = { - STANDARD_MODULE_STUFF, - check_loaded_modules, /* initializer */ - NULL, /* create per-dir config */ - NULL, /* merge per-dir config */ - NULL, /* server config */ - NULL, /* merge server config */ - dld_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_env.c b/usr.sbin/httpd/src/mod_env.c deleted file mode 100644 index 8ae697038da..00000000000 --- a/usr.sbin/httpd/src/mod_env.c +++ /dev/null @@ -1,261 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_env.c - * version 0.0.5 - * status beta - * Pass environment variables to CGI/SSI scripts. - * - * Andrew Wilson <Andrew.Wilson@cm.cf.ac.uk> 06.Dec.95 - * - * Change log: - * 08.Dec.95 Now allows PassEnv directive to appear more than once in - * conf files. - * 10.Dec.95 optimisation. getenv() only called at startup and used - * to build a fast-to-access table. table used to build - * per-server environment for each request. - * robustness. better able to handle errors in configuration - * files: - * 1) PassEnv directive present, but no environment variable listed - * 2) PassEnv FOO present, but $FOO not present in environment - * 3) no PassEnv directive present - * 23.Dec.95 Now allows SetEnv directive with same semantics as 'sh' setenv: - * SetEnv Var sets Var to the empty string - * SetEnv Var Val sets Var to the value Val - * Values containing whitespace should be quoted, eg: - * SetEnv Var "this is some text" - * Environment variables take their value from the last instance - * of PassEnv / SetEnv to be reached in the configuration file. - * For example, the sequence: - * PassEnv FOO - * SetEnv FOO override - * Causes FOO to take the value 'override'. - * 23.Feb.96 Added UnsetEnv directive to allow environment variables - * to be removed. - * Virtual hosts now 'inherit' parent server environment which - * they're able to overwrite with their own directives or - * selectively ignore with UnsetEnv. - * *** IMPORTANT - the way that virtual hosts inherit their *** - * *** environment variables from the default server's *** - * *** configuration has changed. You should test your *** - * *** configuration carefully before accepting this *** - * *** version of the module in a live webserver which used *** - * *** older versions of the module. *** - */ - -#include "httpd.h" -#include "http_config.h" - -typedef struct { - table *vars; - char *unsetenv; - int vars_present; -} env_server_config_rec; - -module env_module; - -void *create_env_server_config (pool *p, server_rec *dummy) -{ - env_server_config_rec *new = - (env_server_config_rec *) palloc (p, sizeof(env_server_config_rec)); - new->vars = make_table (p, 50); - new->unsetenv = ""; - new->vars_present = 0; - return (void *) new; -} - -void *merge_env_server_configs (pool *p, void *basev, void *addv) -{ - env_server_config_rec *base = (env_server_config_rec *)basev; - env_server_config_rec *add = (env_server_config_rec *)addv; - env_server_config_rec *new = - (env_server_config_rec *)palloc (p, sizeof(env_server_config_rec)); - - table *new_table; - table_entry *elts; - - int i; - const char *uenv, *unset; - - /* - * new_table = copy_table( p, base->vars ); - * foreach $element ( @add->vars ) { - * table_set( new_table, $element.key, $element.val ); - * }; - * foreach $unsetenv ( @UNSETENV ) { - * table_unset( new_table, $unsetenv ); - * } - */ - - new_table = copy_table( p, base->vars ); - - elts = (table_entry *) add->vars->elts; - - for ( i = 0; i < add->vars->nelts; ++i ) { - table_set( new_table, elts[i].key, elts[i].val ); - } - - unset = add->unsetenv; - uenv = getword_conf( p, &unset ); - while ( uenv[0] != '\0' ) { - table_unset( new_table, uenv ); - uenv = getword_conf( p, &unset ); - } - - new->vars = new_table; - - new->vars_present = base->vars_present || add->vars_present; - - return new; -} - -const char *add_env_module_vars_passed (cmd_parms *cmd, char *struct_ptr, - const char *arg) -{ - env_server_config_rec *sconf = - get_module_config (cmd->server->module_config, &env_module); - table *vars = sconf->vars; - char *env_var; - char *name_ptr; - - while (*arg) { - name_ptr = getword_conf (cmd->pool, &arg); - env_var = getenv(name_ptr); - if ( env_var != NULL ) { - sconf->vars_present = 1; - table_set (vars, name_ptr, env_var); - } - } - return NULL; -} - -const char *add_env_module_vars_set (cmd_parms *cmd, char *struct_ptr, - const char *arg) -{ - env_server_config_rec *sconf = - get_module_config (cmd->server->module_config, &env_module); - table *vars = sconf->vars; - char *name, *value; - - name = getword_conf( cmd->pool, &arg ); - value = getword_conf( cmd->pool, &arg ); - - /* name is mandatory, value is optional. no value means - * set the variable to an empty string - */ - - - if ( (*name == '\0') || (*arg != '\0')) { - return "SetEnv takes one or two arguments. An environment variable name and an optional value to pass to CGI." ; - } - - sconf->vars_present = 1; - table_set (vars, name, value); - - return NULL; -} - -const char *add_env_module_vars_unset (cmd_parms *cmd, char *struct_ptr, - char *arg) -{ - env_server_config_rec *sconf = - get_module_config (cmd->server->module_config, &env_module); - sconf->unsetenv = sconf->unsetenv ? - pstrcat( cmd->pool, sconf->unsetenv, " ", arg, NULL ) : - pstrdup( cmd->pool, arg ); - return NULL; -} - -command_rec env_module_cmds[] = { -{ "PassEnv", add_env_module_vars_passed, NULL, - RSRC_CONF, RAW_ARGS, "a list of environment variables to pass to CGI." }, -{ "SetEnv", add_env_module_vars_set, NULL, - RSRC_CONF, RAW_ARGS, "an environment variable name and a value to pass to CGI." }, -{ "UnsetEnv", add_env_module_vars_unset, NULL, - RSRC_CONF, RAW_ARGS, "a list of variables to remove from the CGI environment." }, -{ NULL }, -}; - -int fixup_env_module(request_rec *r) -{ - table *e = r->subprocess_env; - server_rec *s = r->server; - env_server_config_rec *sconf = get_module_config (s->module_config, - &env_module); - table *vars = sconf->vars; - - if ( !sconf->vars_present ) return DECLINED; - - r->subprocess_env = overlay_tables( r->pool, e, vars ); - - return OK; -} - -module env_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - create_env_server_config, /* server config */ - merge_env_server_configs, /* merge server configs */ - env_module_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - fixup_env_module, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_expires.c b/usr.sbin/httpd/src/mod_expires.c deleted file mode 100644 index 226726a0a93..00000000000 --- a/usr.sbin/httpd/src/mod_expires.c +++ /dev/null @@ -1,477 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_expires.c - * version 0.0.11 - * status beta - * - * Andrew Wilson <Andrew.Wilson@cm.cf.ac.uk> 26.Jan.96 - * - * This module allows you to control the form of the Expires: header - * that Apache issues for each access. Directives can appear in - * configuration files or in .htaccess files so expiry semantics can - * be defined on a per-directory basis. - * - * DIRECTIVE SYNTAX - * - * Valid directives are: - * - * ExpiresActive on | off - * ExpiresDefault <code><seconds> - * ExpiresByType type/encoding <code><seconds> - * - * Valid values for <code> are: - * - * 'M' expires header shows file modification date + <seconds> - * 'A' expires header shows access time + <seconds> - * - * [I'm not sure which of these is best under different - * circumstances, I guess it's for other people to explore. - * The effects may be indistinguishable for a number of cases] - * - * <seconds> should be an integer value [acceptable to atoi()] - * - * There is NO space between the <code> and <seconds>. - * - * For example, a directory which contains information which changes - * frequently might contain: - * - * # reports generated by cron every hour. don't let caches - * # hold onto stale information - * ExpiresDefault M3600 - * - * Another example, our html pages can change all the time, the gifs - * tend not to change often: - * - * # pages are hot (1 week), images are cold (1 month) - * ExpiresByType text/html A604800 - * ExpiresByType image/gif A2592000 - * - * Expires can be turned on for all URLs on the server by placing the - * following directive in a conf file: - * - * ExpiresActive on - * - * ExpiresActive can also appear in .htaccess files, enabling the - * behaviour to be turned on or off for each chosen directory. - * - * # turn off Expires behaviour in this directory - * # and subdirectories - * ExpiresActive off - * - * Directives defined for a directory are valid in subdirectories - * unless explicitly overridden by new directives in the subdirectory - * .htaccess files. - * - * ALTERNATIVE DIRECTIVE SYNTAX - * - * Directives can also be defined in a more readable syntax of the form: - * - * ExpiresDefault "<base> [plus] {<num> <type>}*" - * ExpiresByType type/encoding "<base> [plus] {<num> <type>}*" - * - * where <base> is one of: - * access - * now equivalent to 'access' - * modification - * - * where the 'plus' keyword is optional - * - * where <num> should be an integer value [acceptable to atoi()] - * - * where <type> is one of: - * years - * months - * weeks - * days - * hours - * minutes - * seconds - * - * For example, any of the following directives can be used to make - * documents expire 1 month after being accessed, by default: - * - * ExpiresDefault "access plus 1 month" - * ExpiresDefault "access plus 4 weeks" - * ExpiresDefault "access plus 30 days" - * - * The expiry time can be fine-tuned by adding several '<num> <type>' - * clauses: - * - * ExpiresByType text/html "access plus 1 month 15 days 2 hours" - * ExpiresByType image/gif "modification plus 5 hours 3 minutes" - * - * --- - * - * Change-log: - * 29.Jan.96 Hardened the add_* functions. Server will now bail out - * if bad directives are given in the conf files. - * 02.Feb.96 Returns DECLINED if not 'ExpiresActive on', giving other - * expires-aware modules a chance to play with the same - * directives. [Michael Rutman] - * 03.Feb.96 Call tzset() before localtime(). Trying to get the module - * to work properly in non GMT timezones. - * 12.Feb.96 Modified directive syntax to allow more readable commands: - * ExpiresDefault "now plus 10 days 20 seconds" - * ExpiresDefault "access plus 30 days" - * ExpiresDefault "modification plus 1 year 10 months 30 days" - * 13.Feb.96 Fix call to table_get() with NULL 2nd parameter [Rob Hartill] - * 19.Feb.96 Call gm_timestr_822() to get time formatted correctly, can't - * rely on presence of HTTP_TIME_FORMAT in Apache 1.1+. - * 21.Feb.96 This version (0.0.9) reverses assumptions made in 0.0.8 - * about star/star handlers. Reverting to 0.0.7 behaviour. - * 08.Jun.96 allows ExpiresDefault to be used with responses that use - * the DefaultType by not DECLINING, but instead skipping - * the table_get check and then looking for an ExpiresDefault. - * [Rob Hartill] - * 04.Nov.96 'const' definitions added. - * - * TODO - * add support for Cache-Control: max-age=20 from the HTTP/1.1 - * proposal (in this case, a ttl of 20 seconds) [ask roy] - * add per-file expiry and explicit expiry times - duplicates some - * of the mod_cern_meta.c functionality. eg: - * ExpiresExplicit index.html "modification plus 30 days" - * - * BUGS - * Hi, welcome to the internet. - */ - -#include <ctype.h> -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" - -typedef struct { - int active; - char *expiresdefault; - table *expiresbytype; -} expires_dir_config; - -/* from mod_dir, why is this alias used? - */ -#define DIR_CMD_PERMS OR_INDEXES - -#define ACTIVE_ON 1 -#define ACTIVE_OFF 0 -#define ACTIVE_DONTCARE 2 - -module expires_module; - -void *create_dir_expires_config (pool *p, char *dummy) -{ - expires_dir_config *new = - (expires_dir_config *) pcalloc (p, sizeof(expires_dir_config)); - new->active = ACTIVE_DONTCARE; - new->expiresdefault = ""; - new->expiresbytype = make_table(p, 4); - return (void *)new; -} - -const char *set_expiresactive (cmd_parms *cmd, expires_dir_config *dir_config, int arg) -{ - /* if we're here at all it's because someone explicitly - * set the active flag - */ - dir_config->active = ACTIVE_ON; - if ( arg == 0 ) { - dir_config->active = ACTIVE_OFF; - }; - return NULL; -} - -/* check_code() parse 'code' and return NULL or an error response - * string. If we return NULL then real_code contains code converted - * to the cnnnn format. - */ -char *check_code( pool *pool, const char *code, char **real_code ) -{ - char *word; - char base = 'X'; - int modifier = 0; - int num = 0; - int factor = 0; - char foo[MAX_STRING_LEN]; - - /* 0.0.4 compatibility? - */ - if ( (code[0] == 'A') || (code[0] == 'M') ) { - *real_code = pstrdup( pool, code ); - return NULL; - }; - - /* <base> [plus] {<num> <type>}* - */ - - /* <base> - */ - word = getword_conf( pool, &code ); - if ( !strncasecmp( word, "now", 1 ) || - !strncasecmp( word, "access", 1 ) ) { - base = 'A'; - } else if ( !strncasecmp( word, "modification", 1 ) ) { - base = 'M'; - } else { - return pstrcat( pool, "bad expires code, unrecognised <base> '", - word, "'", NULL); - }; - - /* [plus] - */ - word = getword_conf( pool, &code ); - if ( !strncasecmp( word, "plus", 1 ) ) { - word = getword_conf( pool, &code ); - }; - - /* {<num> <type>}* - */ - while ( word[0] ) { - /* <num> - */ - if (isdigit(word[0])) { - num = atoi( word ); - } else { - return pstrcat( pool, "bad expires code, numeric value expected <num> '", - word, "'", NULL); - }; - - /* <type> - */ - word = getword_conf( pool, &code ); - if ( word[0] ) { - /* do nothing */ - } else { - return pstrcat( pool, "bad expires code, missing <type>", NULL); - }; - - factor = 0; - if ( !strncasecmp( word, "years", 1 ) ) { - factor = 60*60*24*365; - } else if ( !strncasecmp( word, "months", 2 ) ) { - factor = 60*60*24*30; - } else if ( !strncasecmp( word, "weeks", 1 ) ) { - factor = 60*60*24*7; - } else if ( !strncasecmp( word, "days", 1 ) ) { - factor = 60*60*24; - } else if ( !strncasecmp( word, "hours", 1 ) ) { - factor = 60*60; - } else if ( !strncasecmp( word, "minutes", 2 ) ) { - factor = 60; - } else if ( !strncasecmp( word, "seconds", 1 ) ) { - factor = 1; - } else { - return pstrcat( pool, "bad expires code, unrecognised <type>", - "'", word, "'", NULL); - }; - - modifier = modifier + factor * num; - - /* next <num> - */ - word = getword_conf( pool, &code ); - }; - - ap_snprintf(foo, sizeof(foo), "%c%d", base, modifier ); - *real_code = pstrdup( pool, foo ); - - return NULL; -} - -const char *set_expiresbytype(cmd_parms *cmd, expires_dir_config *dir_config, char *mime, char *code) -{ - char *response, *real_code; - - if ( (response = check_code( cmd->pool, code, &real_code )) == NULL ) { - table_set (dir_config->expiresbytype, mime, real_code); - return NULL; - }; - return pstrcat( cmd->pool, - "'ExpiresByType ", mime, " ", code, "': ", response, NULL ); -} - -const char *set_expiresdefault (cmd_parms *cmd, expires_dir_config *dir_config, char *code) -{ - char *response, *real_code; - - if ( (response = check_code( cmd->pool, code, &real_code )) == NULL ) { - dir_config->expiresdefault = pstrdup( cmd->pool, real_code ); - return NULL; - }; - return pstrcat( cmd->pool, - "'ExpiresDefault ", code, "': ", response, NULL ); -} - -command_rec expires_cmds[] = { -{ "ExpiresActive", set_expiresactive, NULL, DIR_CMD_PERMS, FLAG, NULL}, -{ "ExpiresBytype", set_expiresbytype, NULL, DIR_CMD_PERMS, TAKE2, - "a mime type followed by an expiry date code"}, -{ "ExpiresDefault", set_expiresdefault, NULL, DIR_CMD_PERMS, TAKE1, - "an expiry date code"}, -{ NULL } -}; - -void *merge_expires_dir_configs (pool *p, void *basev, void *addv) -{ - expires_dir_config *new= (expires_dir_config*)pcalloc (p, sizeof(expires_dir_config)); - expires_dir_config *base = (expires_dir_config *)basev; - expires_dir_config *add = (expires_dir_config *)addv; - - if ( add->active == ACTIVE_DONTCARE ) { - new->active = base->active; - } else { - new->active = add->active; - }; - - if ( add->expiresdefault != '\0' ) { - new->expiresdefault = add->expiresdefault; - }; - - new->expiresbytype = overlay_tables (p, add->expiresbytype, - base->expiresbytype); - return new; -} - -int add_expires(request_rec *r) -{ - expires_dir_config *conf = - (expires_dir_config *)get_module_config(r->per_dir_config, &expires_module); - char *code; - time_t base; - time_t additional; - time_t expires; - - if ( r->finfo.st_mode == 0 ) - return DECLINED; - - /* COMMA bites my ass... - */ - if ( conf == NULL ) { - log_reason ("internal error in expires_module; add_expires(), conf == NULL", r->filename, r); - return SERVER_ERROR; - }; - - if ( conf->active != ACTIVE_ON ) - return DECLINED; - - /* we perhaps could use the default_type(r) in its place but that - * may be 2nd guesing the desired configuration... calling table_get - * with a NULL key will SEGV us - * - * I still don't know *why* r->content_type would ever be NULL, this - * is possibly a result of fixups being called in many different - * places. Fixups is probably the wrong place to be doing all this - * work... Bah. - * - * Changed as of 08.Jun.96 don't DECLINE, look for an ExpiresDefault. - */ - if ( r->content_type == NULL ) - code = NULL; - else - code = (char *) table_get( conf->expiresbytype, r->content_type ); - - if ( code == NULL ) { - /* no expires defined for that type, is there a default? */ - code = conf->expiresdefault; - - if ( code[0] == '\0' ) - return OK; - }; - - /* we have our code */ - - switch (code[0]) { - case 'M': - base = r->finfo.st_mtime; - additional = atoi( &code[1] ); - break; - case 'A': - /* there's been some discussion and it's possible that - * 'access time' will be stored in request structure - */ - base = time( NULL ); - additional = atoi( &code[1] ); - break; - default: - /* expecting the add_* routines to be case-hardened this - * is just a reminder that module is beta - */ - log_reason ("internal error in expires_module; bad expires code", r->filename, r); - return SERVER_ERROR; - }; - - expires = base + additional; - tzset(); /* redundant? called implicitly by localtime, at least - * under FreeBSD - */ - table_set( r->headers_out, "Expires", gm_timestr_822( r->pool, expires )); - return OK; -} - -module expires_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_dir_expires_config, /* dir config creater */ - merge_expires_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server configs */ - expires_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - add_expires, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_headers.c b/usr.sbin/httpd/src/mod_headers.c deleted file mode 100644 index 3976be7ba8a..00000000000 --- a/usr.sbin/httpd/src/mod_headers.c +++ /dev/null @@ -1,253 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_headers.c: Add/append/remove HTTP response headers - * Written by Paul Sutton, paul@ukweb.com, 1 Oct 1996 - * - * New directive, Header, can be used to add/replace/remove HTTP headers. - * Valid in both per-server and per-dir configurations. - * - * Syntax is: - * - * Header action header value - * - * Where action is one of: - * set - set this header, replacing any old value - * add - add this header, possible resulting in two or more - * headers with the same name - * append - append this text onto any existing header of this same - * unset - remove this header - * - * Where action is unset, the third argument (value) should not be given. - * The header name can include the colon, or not. - * - * The Header directive can only be used where allowed by the FileInfo - * override. - * - * When the request is processed, the header directives are processed in - * this order: firstly, the main server, then the virtual server handling - * this request (if any), then any <Directory> sections (working downwards - * from the root dir), then an <Location> sections (working down from - * shortest URL component), the any <File> sections. This order is - * important if any 'set' or 'unset' actions are used. For example, - * the following two directives have different effect if applied in - * the reverse order: - * - * Header append Author "John P. Doe" - * Header unset Author - * - * Examples: - * - * To set the "Author" header, use - * Header add Author "John P. Doe" - * - * To remove a header: - * Header unset Author - * - */ - -#include "httpd.h" -#include "http_config.h" - -typedef enum { - hdr_add = 'a', /* add header (could mean multiple hdrs) */ - hdr_set = 's', /* set (replace old value) */ - hdr_append = 'm', /* append (merge into any old value) */ - hdr_unset = 'u' /* unset header */ -} hdr_actions; - -typedef struct { - hdr_actions action; - char *header; - char *value; -} header_entry; - -/* - * headers_conf is our per-module configuration. This is used as both - * a per-dir and per-server config - */ -typedef struct { - array_header *headers; -} headers_conf; - -module headers_module; - -void *create_headers_config (pool *p, server_rec *s) -{ - headers_conf *a = - (headers_conf *)pcalloc (p, sizeof(headers_conf)); - - a->headers = make_array (p, 2, sizeof(header_entry)); - return a; -} - -void *create_headers_dir_config (pool *p, char *d) -{ - return (headers_conf*)create_headers_config(p, NULL); -} - -void *merge_headers_config (pool *p, void *basev, void *overridesv) -{ - headers_conf *a = - (headers_conf *)pcalloc (p, sizeof(headers_conf)); - headers_conf *base = (headers_conf *)basev, - *overrides = (headers_conf *)overridesv; - - a->headers = append_arrays(p, base->headers, overrides->headers); - - return a; -} - - -const char *header_cmd(cmd_parms *cmd, headers_conf *dirconf, char *action, char *hdr, char *value) -{ - header_entry *new; - server_rec *s = cmd->server; - headers_conf *serverconf = - (headers_conf *)get_module_config(s->module_config,&headers_module); - char *colon; - - if ( cmd->path ) - { - new = (header_entry*)push_array(dirconf->headers); - } - else - { - new = (header_entry*)push_array(serverconf->headers); - } - - if (!strcasecmp(action, "set")) new->action = hdr_set; - else if (!strcasecmp(action, "add")) new->action = hdr_add; - else if (!strcasecmp(action, "append")) new->action = hdr_append; - else if (!strcasecmp(action, "unset")) new->action = hdr_unset; - else - return "first argument must be add, set, append or unset."; - - if (new->action == hdr_unset) { - if (value) return "Header unset takes two arguments"; - } - else if (!value) - return "Header requires three arguments"; - - if ((colon = strchr(hdr, ':'))) - *colon = '\0'; - - new->header = pstrdup(cmd->pool, hdr); - new->value = value ? pstrdup(cmd->pool, value) : NULL; - - return NULL; -} - -command_rec headers_cmds[] = { -{ "Header", header_cmd, NULL, OR_FILEINFO, TAKE23, - "an action, header and value"}, -{ NULL } -}; - -void do_headers_fixup(request_rec *r, array_header *headers) -{ - int i; - - for (i = 0; i < headers->nelts; ++i) { - header_entry *hdr = &((header_entry*)(headers->elts))[i]; - switch (hdr->action) { - case hdr_add: - table_add(r->headers_out, hdr->header, hdr->value); - break; - case hdr_append: - table_merge(r->headers_out, hdr->header, hdr->value); - break; - case hdr_set: - table_set(r->headers_out, hdr->header, hdr->value); - break; - case hdr_unset: - table_unset(r->headers_out, hdr->header); - break; - } - } - -} - -int fixup_headers(request_rec *r) -{ - void *sconf = r->server->module_config; - headers_conf *serverconf = - (headers_conf *)get_module_config(sconf, &headers_module); - void *dconf = r->per_dir_config; - headers_conf *dirconf = - (headers_conf *)get_module_config(dconf, &headers_module); - - do_headers_fixup(r, serverconf->headers); - do_headers_fixup(r, dirconf->headers); - - return DECLINED; -} - -module headers_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_headers_dir_config, /* dir config creater */ - merge_headers_config, /* dir merger --- default is to override */ - create_headers_config, /* server config */ - merge_headers_config, /* merge server configs */ - headers_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - fixup_headers, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_imap.c b/usr.sbin/httpd/src/mod_imap.c deleted file mode 100644 index 3282dfe71f3..00000000000 --- a/usr.sbin/httpd/src/mod_imap.c +++ /dev/null @@ -1,877 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * apache@apache.org. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * This imagemap module started as a port of the original imagemap.c - * written by Rob McCool (11/13/93 robm@ncsa.uiuc.edu). - * This version includes the mapping algorithms found in version 1.3 - * of imagemap.c. - * - * Contributors to this code include: - * - * Kevin Hughes, kevinh@pulua.hcc.hawaii.edu - * - * Eric Haines, erich@eye.com - * "macmartinized" polygon code copyright 1992 by Eric Haines, erich@eye.com - * - * Randy Terbush, randy@zyzzyva.com - * port to Apache module format, "base_uri" and support for relative URLs - * - * James H. Cloos, Jr., cloos@jhcloos.com - * Added point datatype, using code in NCSA's version 1.8 imagemap.c - * program, as distributed with version 1.4.1 of their server. - * The point code is originally added by Craig Milo Rogers, Rogers@ISI.Edu - * - * Nathan Kurz, nate@tripod.com - * Rewrite/reorganization. New handling of default, base and relative URLs. - * New Configuration directives: - * ImapMenu {none, formatted, semiformatted, unformatted} - * ImapDefault {error, nocontent, referer, menu, URL} - * ImapBase {map, referer, URL} - * Support for creating non-graphical menu added. (backwards compatible): - * Old: directive URL [x,y ...] - * New: directive URL "Menu text" [x,y ...] - * or: directive URL x,y ... "Menu text" - * Map format and menu concept courtesy Joshua Bell, jsbell@acs.ucalgary.ca. - * - * Mark Cox, mark@ukweb.com, Allow relative URLs even when no base specified - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_log.h" -#include "util_script.h" - -#define IMAP_MAGIC_TYPE "application/x-httpd-imap" -#define MAXVERTS 100 -#define X 0 -#define Y 1 - -#define IMAP_MENU_DEFAULT "formatted" -#define IMAP_DEFAULT_DEFAULT "nocontent" -#define IMAP_BASE_DEFAULT "map" - -#ifdef SUNOS4 -double strtod(); /* SunOS needed this */ -#endif - -module imap_module; - -typedef struct { - char *imap_menu; - char *imap_default; - char *imap_base; -} imap_conf_rec; - -static void *create_imap_dir_config(pool *p, char *dummy) -{ - imap_conf_rec *icr = - (imap_conf_rec *) palloc(p, sizeof(imap_conf_rec)); - - icr->imap_menu = NULL; - icr->imap_default = NULL; - icr->imap_base = NULL; - - return icr; -} - -static void *merge_imap_dir_configs(pool *p, void *basev, void *addv) -{ - imap_conf_rec *new = (imap_conf_rec *) pcalloc(p, sizeof(imap_conf_rec)); - imap_conf_rec *base = (imap_conf_rec *) basev; - imap_conf_rec *add = (imap_conf_rec *) addv; - - new->imap_menu = add->imap_menu ? add->imap_menu : base->imap_menu; - new->imap_default = add->imap_default ? add->imap_default : base->imap_default; - new->imap_base = add->imap_base ? add->imap_base : base->imap_base; - - return new; -} - - -static command_rec imap_cmds[] = -{ - {"ImapMenu", set_string_slot, - (void *) XtOffsetOf(imap_conf_rec, imap_menu), OR_INDEXES, TAKE1, - "the type of menu generated: none, formatted, semiformatted, unformatted"}, - {"ImapDefault", set_string_slot, - (void *) XtOffsetOf(imap_conf_rec, imap_default), OR_INDEXES, TAKE1, - "the action taken if no match: error, nocontent, referer, menu, URL"}, - {"ImapBase", set_string_slot, - (void *) XtOffsetOf(imap_conf_rec, imap_base), OR_INDEXES, TAKE1, - "the base for all URL's: map, referer, URL (or start of)"}, - {NULL} -}; - -static int pointinrect(const double point[2], double coords[MAXVERTS][2]) -{ - double max[2], min[2]; - if (coords[0][X] > coords[1][X]) { - max[0] = coords[0][X]; - min[0] = coords[1][X]; - } - else { - max[0] = coords[1][X]; - min[0] = coords[0][X]; - } - - if (coords[0][Y] > coords[1][Y]) { - max[1] = coords[0][Y]; - min[1] = coords[1][Y]; - } - else { - max[1] = coords[1][Y]; - min[1] = coords[0][Y]; - } - - return ((point[X] >= min[0] && point[X] <= max[0]) && - (point[Y] >= min[1] && point[Y] <= max[1])); -} - -static int pointincircle(const double point[2], double coords[MAXVERTS][2]) -{ - double radius1, radius2; - - radius1 = ((coords[0][Y] - coords[1][Y]) * (coords[0][Y] - coords[1][Y])) - + ((coords[0][X] - coords[1][X]) * (coords[0][X] - coords[1][X])); - - radius2 = ((coords[0][Y] - point[Y]) * (coords[0][Y] - point[Y])) - + ((coords[0][X] - point[X]) * (coords[0][X] - point[X])); - - return (radius2 <= radius1); -} - -static int pointinpoly(const double point[2], double pgon[MAXVERTS][2]) -{ - int i, numverts, inside_flag, xflag0; - int crossings; - double *p; - const double *stop; - double tx, ty, y; - - for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++); - - numverts = i; - crossings = 0; - - tx = point[X]; - ty = point[Y]; - y = pgon[numverts - 1][Y]; - - p = (double *) pgon + 1; - if ((y >= ty) != (*p >= ty)) { - - if ((xflag0 = (pgon[numverts - 1][X] >= tx)) == (*(double *) pgon >= tx)) { - if (xflag0) - crossings++; - } - else { - crossings += (pgon[numverts - 1][X] - (y - ty) * - (*(double *) pgon - pgon[numverts - 1][X]) / - (*p - y)) >= tx; - } - } - - stop = pgon[numverts]; - - for (y = *p, p += 2; p < stop; y = *p, p += 2) { - - if (y >= ty) { - - while ((p < stop) && (*p >= ty)) - p += 2; - - if (p >= stop) - break; - if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) { - - if (xflag0) - crossings++; - } - else { - crossings += (*(p - 3) - (*(p - 2) - ty) * - (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx; - } - } - else { - while ((p < stop) && (*p < ty)) - p += 2; - - if (p >= stop) - break; - - if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) { - if (xflag0) - crossings++; - } - else { - crossings += (*(p - 3) - (*(p - 2) - ty) * - (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx; - } - } - } - - inside_flag = crossings & 0x01; - return (inside_flag); -} - - -static int is_closer(const double point[2], double coords[MAXVERTS][2], - double *closest) -{ - double dist_squared = ((point[X] - coords[0][X]) * (point[X] - coords[0][X])) - + ((point[Y] - coords[0][Y]) * (point[Y] - coords[0][Y])); - - if (point[X] < 0 || point[Y] < 0) - return (0); /* don't mess around with negative coordinates */ - - if (*closest < 0 || dist_squared < *closest) { - *closest = dist_squared; - return (1); /* if this is the first point or is the closest yet - set 'closest' equal to this distance^2 */ - } - - return (0); /* if it's not the first or closest */ - -} - -static double get_x_coord(const char *args) -{ - char *endptr; /* we want it non-null */ - double x_coord = -1; /* -1 is returned if no coordinate is given */ - - if (args == NULL) - return (-1); /* in case we aren't passed anything */ - - while (*args && !isdigit(*args) && *args != ',') - args++; /* jump to the first digit, but not past a comma or end */ - - x_coord = strtod(args, &endptr); - - if (endptr > args) /* if a conversion was made */ - return (x_coord); - - return (-1); /* else if no conversion was made, or if no args was given */ -} - -static double get_y_coord(const char *args) -{ - char *endptr; /* we want it non-null */ - char *start_of_y = NULL; - double y_coord = -1; /* -1 is returned on error */ - - if (args == NULL) - return (-1); /* in case we aren't passed anything */ - - start_of_y = strchr(args, ','); /* the comma */ - - if (start_of_y) { - - start_of_y++; /* start looking at the character after the comma */ - - while (*start_of_y && !isdigit(*start_of_y)) - start_of_y++; /* jump to the first digit, but not past the end */ - - y_coord = strtod(start_of_y, &endptr); - - if (endptr > start_of_y) - return (y_coord); - } - - return (-1); /* if no conversion was made, or no comma was found in args */ -} - - -/* See if string has a "quoted part", and if so set *quoted_part to - * the first character of the quoted part, then hammer a \0 onto the - * trailing quote, and set *string to point at the first character - * past the second quote. - * - * Otherwise set *quoted_part to NULL, and leave *string alone. - */ -static void read_quoted(char **string, char **quoted_part) -{ - char *strp = *string; - - /* assume there's no quoted part */ - *quoted_part = NULL; - - while (isspace(*strp)) - strp++; /* go along string until non-whitespace */ - - if (*strp == '"') { /* if that character is a double quote */ - strp++; /* step over it */ - *quoted_part = strp; /* note where the quoted part begins */ - - while (*strp && *strp != '"') { - ++strp; /* skip the quoted portion */ - } - - *strp = '\0'; /* end the string with a NUL */ - - strp++; /* step over the last double quote */ - *string = strp; - } -} - -/* - * returns the mapped URL or NULL. - */ -static char *imap_url(request_rec *r, const char *base, const char *value) -{ -/* translates a value into a URL. */ - int slen, clen; - char *string_pos = NULL; - const char *string_pos_const = NULL; - char *directory = NULL; - char *referer = NULL; - char *my_base; - - if (!strcasecmp(value, "map") || !strcasecmp(value, "menu")) { - return construct_url(r->pool, r->uri, r->server); - } - - if (!strcasecmp(value, "nocontent") || !strcasecmp(value, "error")) { - return pstrdup(r->pool, value); /* these are handled elsewhere, so just copy them */ - } - - if (!strcasecmp(value, "referer")) { - referer = table_get(r->headers_in, "Referer"); - if (referer && *referer) { - return pstrdup(r->pool, referer); - } - else { - /* XXX: This used to do *value = '\0'; ... which is totally bogus - * because it hammers the passed in value, which can be a string constant, - * or part of a config, or whatever. Total garbage. This works around - * that without changing the rest of this code much - */ - value = ""; /* if 'referer' but no referring page, null the value */ - } - } - - string_pos_const = value; - while (isalpha(*string_pos_const)) - string_pos_const++; /* go along the URL from the map until a non-letter */ - if (*string_pos_const == ':') { - /* if letters and then a colon (like http:) */ - /* it's an absolute URL, so use it! */ - return pstrdup(r->pool, value); - } - - if (!base || !*base) { - if (value && *value) { - return pstrdup(r->pool, value); /* no base: use what is given */ - } - /* no base, no value: pick a simple default */ - return construct_url(r->pool, "/", r->server); - } - - /* must be a relative URL to be combined with base */ - if (strchr(base, '/') == NULL && (!strncmp(value, "../", 3) || !strcmp(value, ".."))) { - log_reason("invalid base directive in map file: %s", r->uri, r); - return NULL; - } - my_base = pstrdup(r->pool, base); - string_pos = my_base; - while (*string_pos) { - if (*string_pos == '/' && *(string_pos + 1) == '/') { - string_pos += 2; /* if there are two slashes, jump over them */ - continue; - } - if (*string_pos == '/') { /* the first single slash */ - if (value[0] == '/') { - *string_pos = '\0'; - } /* if the URL from the map starts from root, end the - base URL string at the first single slash */ - else { - directory = string_pos; /* save the start of the directory portion */ - - string_pos = strrchr(string_pos, '/'); /* now reuse string_pos */ - string_pos++; /* step over that last slash */ - *string_pos = '\0'; - } /* but if the map url is relative, leave the - slash on the base (if there is one) */ - break; - } - string_pos++; /* until we get to the end of my_base without finding - a slash by itself */ - } - - while (!strncmp(value, "../", 3) || !strcmp(value, "..")) { - - if (directory && (slen = strlen(directory))) { - - /* for each '..', knock a directory off the end - by ending the string right at the last slash. - But only consider the directory portion: don't eat - into the server name. And only try if a directory - portion was found */ - - clen = slen - 1; - - while ((slen - clen) == 1) { - - if ((string_pos = strrchr(directory, '/'))) - *string_pos = '\0'; - clen = strlen(directory); - if (clen == 0) - break; - } - - value += 2; /* jump over the '..' that we found in the value */ - } - else if (directory) { - log_reason("invalid directory name in map file: %s", r->uri, r); - return NULL; - } - - if (!strncmp(value, "/../", 4) || !strcmp(value, "/..")) - value++; /* step over the '/' if there are more '..' to do. - this way, we leave the starting '/' on value after - the last '..', but get rid of it otherwise */ - - } /* by this point, value does not start with '..' */ - - if (value && *value) { - return pstrcat(r->pool, my_base, value, NULL); - } - return my_base; -} - -static int imap_reply(request_rec *r, char *redirect) -{ - if (!strcasecmp(redirect, "error")) { - return SERVER_ERROR; /* they actually requested an error! */ - } - if (!strcasecmp(redirect, "nocontent")) { - return HTTP_NO_CONTENT; /* tell the client to keep the page it has */ - } - if (redirect && *redirect) { - table_set(r->headers_out, "Location", redirect); - return REDIRECT; /* must be a URL, so redirect to it */ - } - return SERVER_ERROR; -} - -static void menu_header(request_rec *r, char *menu) -{ - r->content_type = "text/html"; - send_http_header(r); - hard_timeout("send menu", r); /* killed in menu_footer */ - - rvputs(r, "<html><head>\n<title>Menu for ", r->uri, - "</title>\n</head><body>\n", NULL); - - if (!strcasecmp(menu, "formatted")) { - rvputs(r, "<h1>Menu for ", r->uri, "</h1>\n<hr>\n\n", NULL); - } - - return; -} - -static void menu_blank(request_rec *r, char *menu) -{ - if (!strcasecmp(menu, "formatted")) { - rputs("\n", r); - } - if (!strcasecmp(menu, "semiformatted")) { - rputs("<br>\n", r); - } - if (!strcasecmp(menu, "unformatted")) { - rputs("\n", r); - } - return; -} - -static void menu_comment(request_rec *r, char *menu, char *comment) -{ - if (!strcasecmp(menu, "formatted")) { - rputs("\n", r); /* print just a newline if 'formatted' */ - } - if (!strcasecmp(menu, "semiformatted") && *comment) { - rvputs(r, comment, "\n", NULL); - } - if (!strcasecmp(menu, "unformatted") && *comment) { - rvputs(r, comment, "\n", NULL); - } - return; /* comments are ignored in the 'formatted' form */ -} - -static void menu_default(request_rec *r, char *menu, char *href, char *text) -{ - if (!strcasecmp(href, "error") || !strcasecmp(href, "nocontent")) { - return; /* don't print such lines, these aren'te really href's */ - } - if (!strcasecmp(menu, "formatted")) { - rvputs(r, "<pre>(Default) <a href=\"", href, "\">", text, "</a></pre>\n", - NULL); - } - if (!strcasecmp(menu, "semiformatted")) { - rvputs(r, "<pre>(Default) <a href=\"", href, "\">", text, "</a></pre>\n", - NULL); - } - if (!strcasecmp(menu, "unformatted")) { - rvputs(r, "<a href=\"", href, "\">", text, "</a>", NULL); - } - return; -} - -static void menu_directive(request_rec *r, char *menu, char *href, char *text) -{ - if (!strcasecmp(href, "error") || !strcasecmp(href, "nocontent")) { - return; /* don't print such lines, as this isn't really an href */ - } - if (!strcasecmp(menu, "formatted")) { - rvputs(r, "<pre> <a href=\"", href, "\">", text, "</a></pre>\n", - NULL); - } - if (!strcasecmp(menu, "semiformatted")) { - rvputs(r, "<pre> <a href=\"", href, "\">", text, "</a></pre>\n", - NULL); - } - if (!strcasecmp(menu, "unformatted")) { - rvputs(r, "<a href=\"", href, "\">", text, "</a>", NULL); - } - return; -} - -static void menu_footer(request_rec *r) -{ - rputs("\n\n</body>\n</html>\n", r); /* finish the menu */ - kill_timeout(r); -} - -static int imap_handler(request_rec *r) -{ - char input[MAX_STRING_LEN]; - char *directive; - char *value; - char *href_text; - char *base; - char *redirect; - char *mapdflt; - char *closest = NULL; - double closest_yet = -1; - - double testpoint[2]; - double pointarray[MAXVERTS + 1][2]; - int vertex; - - char *string_pos; - int showmenu = 0; - - imap_conf_rec *icr = get_module_config(r->per_dir_config, &imap_module); - - char *imap_menu = icr->imap_menu ? icr->imap_menu : IMAP_MENU_DEFAULT; - char *imap_default = icr->imap_default - ? icr->imap_default : IMAP_DEFAULT_DEFAULT; - char *imap_base = icr->imap_base ? icr->imap_base : IMAP_BASE_DEFAULT; - - FILE *imap; - - if (r->method_number != M_GET) - return DECLINED; - - imap = pfopen(r->pool, r->filename, "r"); - - if (!imap) - return NOT_FOUND; - - base = imap_url(r, NULL, imap_base); /* set base according to default */ - if (!base) - return HTTP_INTERNAL_SERVER_ERROR; - mapdflt = imap_url(r, NULL, imap_default); /* and default to global default */ - if (!mapdflt) - return HTTP_INTERNAL_SERVER_ERROR; - - testpoint[X] = get_x_coord(r->args); - testpoint[Y] = get_y_coord(r->args); - - if ((testpoint[X] == -1 || testpoint[Y] == -1) || - (testpoint[X] == 0 && testpoint[Y] == 0)) { - /* if either is -1 or if both are zero (new Lynx) */ - /* we don't have valid coordinates */ - testpoint[X] = -1; - testpoint[Y] = -1; - if (strncasecmp(imap_menu, "none", 2)) - showmenu = 1; /* show the menu _unless_ ImapMenu is 'none' or 'no' */ - } - - if (showmenu) { /* send start of imagemap menu if we're going to */ - menu_header(r, imap_menu); - } - - while (!cfg_getline(input, sizeof(input), imap)) { - if (!input[0]) { - if (showmenu) { - menu_blank(r, imap_menu); - } - continue; - } - - if (input[0] == '#') { - if (showmenu) { - menu_comment(r, imap_menu, input + 1); - } - continue; - } /* blank lines and comments are ignored if we aren't printing a menu */ - - /* find the first two space delimited fields, recall that - * cfg_getline has removed leading/trailing whitespace and - * compressed the other whitespace down to one space a piece - * - * note that we're tokenizing as we go... if we were to use the - * getword() class of functions we would end up allocating extra - * memory for every line of the map file - */ - string_pos = input; - if (!*string_pos) /* need at least two fields */ - goto need_2_fields; - - directive = string_pos; - while (*string_pos && *string_pos != ' ') /* past directive */ - ++string_pos; - if (!*string_pos) /* need at least two fields */ - goto need_2_fields; - *string_pos++ = '\0'; - - if (!*string_pos) /* need at least two fields */ - goto need_2_fields; - value = string_pos; - while (*string_pos && *string_pos != ' ') /* past value */ - ++string_pos; - if (*string_pos == ' ') { - *string_pos++ = '\0'; - } - else { - /* end of input, don't advance past it */ - *string_pos = '\0'; - } - - if (!strncasecmp(directive, "base", 4)) { /* base, base_uri */ - base = imap_url(r, NULL, value); - if (!base) - goto menu_bail; - continue; /* base is never printed to a menu */ - } - - read_quoted(&string_pos, &href_text); - - if (!strcasecmp(directive, "default")) { /* default */ - mapdflt = imap_url(r, NULL, value); - if (!mapdflt) - goto menu_bail; - if (showmenu) { /* print the default if there's a menu */ - redirect = imap_url(r, base, mapdflt); - if (!redirect) - goto menu_bail; - menu_default(r, imap_menu, redirect, href_text ? href_text : mapdflt); - } - continue; - } - - vertex = 0; - while (vertex < MAXVERTS && - sscanf(string_pos, "%lf%*[, ]%lf", - &pointarray[vertex][X], &pointarray[vertex][Y]) == 2) { - /* Now skip what we just read... we can't use ANSIism %n */ - while (isspace(*string_pos)) /* past whitespace */ - string_pos++; - while (isdigit(*string_pos)) /* and the 1st number */ - string_pos++; - string_pos++; /* skip the ',' */ - while (isspace(*string_pos)) /* past any more whitespace */ - string_pos++; - while (isdigit(*string_pos)) /* 2nd number */ - string_pos++; - vertex++; - } /* so long as there are more vertices to read, and - we have room, read them in. We start where we left - off of the last sscanf, not at the beginning. */ - - pointarray[vertex][X] = -1; /* signals the end of vertices */ - - if (showmenu) { - if (!href_text) { - read_quoted(&string_pos, &href_text); /* href text could be here instead */ - } - redirect = imap_url(r, base, value); - if (!redirect) - goto menu_bail; - menu_directive(r, imap_menu, redirect, href_text ? href_text : value); - continue; - } - /* note that we don't make it past here if we are making a menu */ - - if (testpoint[X] == -1 || pointarray[0][X] == -1) - continue; /* don't try the following tests if testpoints - are invalid, or if there are no coordinates */ - - if (!strcasecmp(directive, "poly")) { /* poly */ - - if (pointinpoly(testpoint, pointarray)) { - pfclose(r->pool, imap); - redirect = imap_url(r, base, value); - if (!redirect) - return HTTP_INTERNAL_SERVER_ERROR; - return (imap_reply(r, redirect)); - } - continue; - } - - if (!strcasecmp(directive, "circle")) { /* circle */ - - if (pointincircle(testpoint, pointarray)) { - pfclose(r->pool, imap); - redirect = imap_url(r, base, value); - if (!redirect) - return HTTP_INTERNAL_SERVER_ERROR; - return (imap_reply(r, redirect)); - } - continue; - } - - if (!strcasecmp(directive, "rect")) { /* rect */ - - if (pointinrect(testpoint, pointarray)) { - pfclose(r->pool, imap); - redirect = imap_url(r, base, value); - if (!redirect) - return HTTP_INTERNAL_SERVER_ERROR; - return (imap_reply(r, redirect)); - } - continue; - } - - if (!strcasecmp(directive, "point")) { /* point */ - - if (is_closer(testpoint, pointarray, &closest_yet)) { - closest = pstrdup(r->pool, value); - } - - continue; - } /* move on to next line whether it's closest or not */ - - } /* nothing matched, so we get another line! */ - - pfclose(r->pool, imap); /* we are done with the map file, so close it */ - - if (showmenu) { - menu_footer(r); /* finish the menu and we are done */ - return OK; - } - - if (closest) { /* if a 'point' directive has been seen */ - redirect = imap_url(r, base, closest); - if (!redirect) - return HTTP_INTERNAL_SERVER_ERROR; - return (imap_reply(r, redirect)); - } - - if (mapdflt) { /* a default should be defined, even if only 'nocontent' */ - redirect = imap_url(r, base, mapdflt); - if (!redirect) - return HTTP_INTERNAL_SERVER_ERROR; - return (imap_reply(r, redirect)); - } - - return SERVER_ERROR; /* If we make it this far, we failed. They lose! */ - -need_2_fields: - log_reason("all map file lines require at least two fields", r->uri, r); - /* fall through */ -menu_bail: - pfclose(r->pool, imap); - if (showmenu) { - /* There's not much else we can do ... we've already sent the headers - * to the client. - */ - rputs("\n\n[an internal server error occured]\n", r); - menu_footer(r); - return OK; - } - return HTTP_INTERNAL_SERVER_ERROR; -} - - -static handler_rec imap_handlers[] = -{ - {IMAP_MAGIC_TYPE, imap_handler}, - {"imap-file", imap_handler}, - {NULL} -}; - -module imap_module = -{ - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_imap_dir_config, /* dir config creater */ - merge_imap_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - imap_cmds, /* command table */ - imap_handlers, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_include.c b/usr.sbin/httpd/src/mod_include.c deleted file mode 100644 index 2b53f24aaa1..00000000000 --- a/usr.sbin/httpd/src/mod_include.c +++ /dev/null @@ -1,2329 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * apache@apache.org. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_include.c: Handles the server-parsed HTML documents - * - * Original by Rob McCool; substantial fixups by David Robinson; - * incorporated into the Apache module framework by rst. - * - */ -/* - * sub key may be anything a Perl*Handler can be: - * subroutine name, package name (defaults to package::handler), - * Class->method call or anoymous sub {} - * - * Child <!--#perl sub="sub {print $$}" --> accessed - * <!--#perl sub="sub {print ++$Access::Cnt }" --> times. <br> - * - * <!--#perl arg="one" sub="mymod::includer" --> - * - * -Doug MacEachern - */ - -#ifdef USE_PERL_SSI -#include "config.h" -#ifdef USE_SFIO -#undef USE_SFIO -#define USE_STDIO -#endif -#include "modules/perl/mod_perl.h" -#else -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "util_script.h" -#endif - -#define STARTING_SEQUENCE "<!--#" -#define ENDING_SEQUENCE "-->" -#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]" -#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z" -#define SIZEFMT_BYTES 0 -#define SIZEFMT_KMG 1 - - -static void safe_copy(char *dest, const char *src, size_t max_len) -{ - strncpy(dest, src, max_len - 1); - dest[max_len - 1] = '\0'; -} - -/* ------------------------ Environment function -------------------------- */ - -static void add_include_vars(request_rec *r, char *timefmt) -{ - struct passwd *pw; - table *e = r->subprocess_env; - char *t; - time_t date = r->request_time; - - table_set(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0)); - table_set(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1)); - table_set(e, "LAST_MODIFIED", - ht_time(r->pool, r->finfo.st_mtime, timefmt, 0)); - table_set(e, "DOCUMENT_URI", r->uri); - table_set(e, "DOCUMENT_PATH_INFO", r->path_info); - pw = getpwuid(r->finfo.st_uid); - if (pw) { - table_set(e, "USER_NAME", pw->pw_name); - } - else { - char uid[16]; - ap_snprintf(uid, sizeof(uid), "user#%lu", - (unsigned long) r->finfo.st_uid); - table_set(e, "USER_NAME", uid); - } - - if ((t = strrchr(r->filename, '/'))) { - table_set(e, "DOCUMENT_NAME", ++t); - } - else { - table_set(e, "DOCUMENT_NAME", r->uri); - } - if (r->args) { - char *arg_copy = pstrdup(r->pool, r->args); - - unescape_url(arg_copy); - table_set(e, "QUERY_STRING_UNESCAPED", - escape_shell_cmd(r->pool, arg_copy)); - } -} - - - -/* --------------------------- Parser functions --------------------------- */ - -#define OUTBUFSIZE 4096 -/* PUT_CHAR and FLUSH_BUF currently only work within the scope of - * find_string(); they are hacks to avoid calling rputc for each and - * every character output. A common set of buffering calls for this - * type of output SHOULD be implemented. - */ -#define PUT_CHAR(c,r) \ - { \ - outbuf[outind++] = c; \ - if (outind == OUTBUFSIZE) { \ - FLUSH_BUF(r) \ - }; \ - } - -/* there SHOULD be some error checking on the return value of - * rwrite, however it is unclear what the API for rwrite returning - * errors is and little can really be done to help the error in - * any case. - */ -#define FLUSH_BUF(r) \ - { \ - rwrite(outbuf, outind, r); \ - outind = 0; \ - } - -/* - * f: file handle being read from - * c: character to read into - * ret: return value to use if input fails - * r: current request_rec - * - * This macro is redefined after find_string() for historical reasons - * to avoid too many code changes. This is one of the many things - * that should be fixed. - */ -#define GET_CHAR(f,c,ret,r) \ - { \ - int i = getc(f); \ - if (i == EOF) { /* either EOF or error -- needs error handling if latter */ \ - if (ferror(f)) { \ - fprintf(stderr, "encountered error in GET_CHAR macro, " \ - "mod_include.\n"); \ - } \ - FLUSH_BUF(r); \ - pfclose(r->pool, f); \ - return ret; \ - } \ - c = (char)i; \ - } - -static int find_string(FILE *in, const char *str, request_rec *r, int printing) -{ - int x, l = strlen(str), p; - char outbuf[OUTBUFSIZE]; - int outind = 0; - char c; - - p = 0; - while (1) { - GET_CHAR(in, c, 1, r); - if (c == str[p]) { - if ((++p) == l) { - FLUSH_BUF(r); - return 0; - } - } - else { - if (printing) { - for (x = 0; x < p; x++) { - PUT_CHAR(str[x], r); - } - PUT_CHAR(c, r); - } - p = 0; - } - } -} - -#undef FLUSH_BUF -#undef PUT_CHAR -#undef GET_CHAR -#define GET_CHAR(f,c,r,p) \ - { \ - int i = getc(f); \ - if (i == EOF) { /* either EOF or error -- needs error handling if latter */ \ - if (ferror(f)) { \ - fprintf(stderr, "encountered error in GET_CHAR macro, " \ - "mod_include.\n"); \ - } \ - pfclose(p, f); \ - return r; \ - } \ - c = (char)i; \ - } - -/* - * decodes a string containing html entities or numeric character references. - * 's' is overwritten with the decoded string. - * If 's' is syntatically incorrect, then the followed fixups will be made: - * unknown entities will be left undecoded; - * references to unused numeric characters will be deleted. - * In particular, � will not be decoded, but will be deleted. - * - * drtr - */ - -/* maximum length of any ISO-LATIN-1 HTML entity name. */ -#define MAXENTLEN (6) - -/* The following is a shrinking transformation, therefore safe. */ - -static void decodehtml(char *s) -{ - int val, i, j; - char *p = s; - const char *ents; - static const char * const entlist[MAXENTLEN + 1] = - { - NULL, /* 0 */ - NULL, /* 1 */ - "lt\074gt\076", /* 2 */ - "amp\046ETH\320eth\360", /* 3 */ - "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml\353\ -iuml\357ouml\366uuml\374yuml\377", /* 4 */ - "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc\333\ -THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352icirc\356ocirc\364\ -ucirc\373thorn\376", /* 5 */ - "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311\ -Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde\325Oslash\330\ -Ugrave\331Uacute\332Yacute\335agrave\340aacute\341atilde\343ccedil\347\ -egrave\350eacute\351igrave\354iacute\355ntilde\361ograve\362oacute\363\ -otilde\365oslash\370ugrave\371uacute\372yacute\375" /* 6 */ - }; - - for (; *s != '\0'; s++, p++) { - if (*s != '&') { - *p = *s; - continue; - } - /* find end of entity */ - for (i = 1; s[i] != ';' && s[i] != '\0'; i++) { - continue; - } - - if (s[i] == '\0') { /* treat as normal data */ - *p = *s; - continue; - } - - /* is it numeric ? */ - if (s[1] == '#') { - for (j = 2, val = 0; j < i && isdigit(s[j]); j++) { - val = val * 10 + s[j] - '0'; - } - s += i; - if (j < i || val <= 8 || (val >= 11 && val <= 31) || - (val >= 127 && val <= 160) || val >= 256) { - p--; /* no data to output */ - } - else { - *p = val; - } - } - else { - j = i - 1; - if (i - 1 > MAXENTLEN || entlist[i - 1] == NULL) { - /* wrong length */ - *p = '&'; - continue; /* skip it */ - } - for (ents = entlist[i - 1]; *ents != '\0'; ents += i) { - if (strncmp(s + 1, ents, i - 1) == 0) { - break; - } - } - - if (*ents == '\0') { - *p = '&'; /* unknown */ - } - else { - *p = ((const unsigned char *) ents)[i - 1]; - s += i; - } - } - } - - *p = '\0'; -} - -/* - * extract the next tag name and value. - * if there are no more tags, set the tag name to 'done' - * the tag value is html decoded if dodecode is non-zero - */ - -static char *get_tag(pool *p, FILE *in, char *tag, int tagbuf_len, int dodecode) -{ - char *t = tag, *tag_val, c, term; - - /* makes code below a little less cluttered */ - --tagbuf_len; - - do { /* skip whitespace */ - GET_CHAR(in, c, NULL, p); - } while (isspace(c)); - - /* tags can't start with - */ - if (c == '-') { - GET_CHAR(in, c, NULL, p); - if (c == '-') { - do { - GET_CHAR(in, c, NULL, p); - } while (isspace(c)); - if (c == '>') { - safe_copy(tag, "done", tagbuf_len); - return tag; - } - } - return NULL; /* failed */ - } - - /* find end of tag name */ - while (1) { - if (t - tag == tagbuf_len) { - *t = '\0'; - return NULL; - } - if (c == '=' || isspace(c)) { - break; - } - *(t++) = tolower(c); - GET_CHAR(in, c, NULL, p); - } - - *t++ = '\0'; - tag_val = t; - - while (isspace(c)) { - GET_CHAR(in, c, NULL, p); /* space before = */ - } - if (c != '=') { - ungetc(c, in); - return NULL; - } - - do { - GET_CHAR(in, c, NULL, p); /* space after = */ - } while (isspace(c)); - - /* we should allow a 'name' as a value */ - - if (c != '"' && c != '\'') { - return NULL; - } - term = c; - while (1) { - GET_CHAR(in, c, NULL, p); - if (t - tag == tagbuf_len) { - *t = '\0'; - return NULL; - } -/* Want to accept \" as a valid character within a string. */ - if (c == '\\') { - *(t++) = c; /* Add backslash */ - GET_CHAR(in, c, NULL, p); - if (c == term) { /* Only if */ - *(--t) = c; /* Replace backslash ONLY for terminator */ - } - } - else if (c == term) { - break; - } - *(t++) = c; - } - *t = '\0'; - if (dodecode) { - decodehtml(tag_val); - } - return pstrdup(p, tag_val); -} - -static int get_directive(FILE *in, char *dest, size_t len, pool *p) -{ - char *d = dest; - char c; - - /* make room for nul terminator */ - --len; - - /* skip initial whitespace */ - while (1) { - GET_CHAR(in, c, 1, p); - if (!isspace(c)) { - break; - } - } - /* now get directive */ - while (1) { - if (d - dest == len) { - return 1; - } - *d++ = tolower(c); - GET_CHAR(in, c, 1, p); - if (isspace(c)) { - break; - } - } - *d = '\0'; - return 0; -} - -/* - * Do variable substitution on strings - */ -static void parse_string(request_rec *r, const char *in, char *out, - size_t length, int leave_name) -{ - char ch; - char *next = out; - char *end_out; - - /* leave room for nul terminator */ - end_out = out + length - 1; - - while ((ch = *in++) != '\0') { - switch (ch) { - case '\\': - if (next == end_out) { - /* truncated */ - *next = '\0'; - return; - } - if (*in == '$') { - *next++ = *in++; - } - else { - *next++ = ch; - } - break; - case '$': - { - char var[MAX_STRING_LEN]; - const char *start_of_var_name; - const char *end_of_var_name; /* end of var name + 1 */ - const char *expansion; - const char *val; - size_t l; - - /* guess that the expansion won't happen */ - expansion = in - 1; - if (*in == '{') { - ++in; - start_of_var_name = in; - in = strchr(in, '}'); - if (in == NULL) { - log_printf(r->server, - "Missing '}' on variable \"%s\" in %s", - expansion, r->filename); - *next = '\0'; - return; - } - end_of_var_name = in; - ++in; - } - else { - start_of_var_name = in; - while (isalnum(*in) || *in == '_') { - ++in; - } - end_of_var_name = in; - } - /* what a pain, too bad there's no table_getn where you can - * pass a non-nul terminated string */ - l = end_of_var_name - start_of_var_name; - l = (l > sizeof(var) - 1) ? (sizeof(var) - 1) : l; - memcpy(var, start_of_var_name, l); - var[l] = '\0'; - - val = table_get(r->subprocess_env, var); - if (val) { - expansion = val; - l = strlen(expansion); - } - else if (leave_name) { - l = in - expansion; - } - else { - break; /* no expansion to be done */ - } - l = (l > end_out - next) ? (end_out - next) : l; - memcpy(next, expansion, l); - next += l; - break; - } - default: - if (next == end_out) { - /* truncated */ - *next = '\0'; - return; - } - *next++ = ch; - break; - } - } - *next = '\0'; - return; -} - -/* --------------------------- Action handlers ---------------------------- */ - -static int include_cgi(char *s, request_rec *r) -{ - request_rec *rr = sub_req_lookup_uri(s, r); - int rr_status; - - if (rr->status != HTTP_OK) { - return -1; - } - - /* No hardwired path info or query allowed */ - - if ((rr->path_info && rr->path_info[0]) || rr->args) { - return -1; - } - if (rr->finfo.st_mode == 0) { - return -1; - } - - /* Script gets parameters of the *document*, for back compatibility */ - - rr->path_info = r->path_info; /* hard to get right; see mod_cgi.c */ - rr->args = r->args; - - /* Force sub_req to be treated as a CGI request, even if ordinary - * typing rules would have called it something else. - */ - - rr->content_type = CGI_MAGIC_TYPE; - - /* Run it. */ - - rr_status = run_sub_req(rr); - if (is_HTTP_REDIRECT(rr_status)) { - char *location = table_get(rr->headers_out, "Location"); - location = escape_html(rr->pool, location); - rvputs(r, "<A HREF=\"", location, "\">", location, "</A>", NULL); - } - - destroy_sub_req(rr); - chdir_file(r->filename); - - return 0; -} - -/* ensure that path is relative, and does not contain ".." elements - * ensentially ensure that it does not match the regex: - * (^/|(^|/)\.\.(/|$)) - * XXX: this needs os abstraction... consider c:..\foo in win32 - */ -static int is_only_below(const char *path) -{ - if (path[0] == '/') { - return 0; - } - if (path[0] == '.' && path[1] == '.' - && (path[2] == '\0' || path[2] == '/')) { - return 0; - } - while (*path) { - if (*path == '/' && path[1] == '.' && path[2] == '.' - && (path[3] == '\0' || path[3] == '/')) { - return 0; - } - ++path; - } - return 1; -} - -static int handle_include(FILE *in, request_rec *r, const char *error, int noexec) -{ - char tag[MAX_STRING_LEN]; - char parsed_string[MAX_STRING_LEN]; - char *tag_val; - - while (1) { - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - return 1; - } - if (!strcmp(tag, "file") || !strcmp(tag, "virtual")) { - request_rec *rr = NULL; - char *error_fmt = NULL; - - parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - if (tag[0] == 'f') { - /* be safe; only files in this directory or below allowed */ - if (!is_only_below(parsed_string)) { - error_fmt = "unable to include file \"%s\" " - "in parsed file %s"; - } - else { - rr = sub_req_lookup_file(parsed_string, r); - } - } - else { - rr = sub_req_lookup_uri(parsed_string, r); - } - - if (!error_fmt && rr->status != HTTP_OK) { - error_fmt = "unable to include \"%s\" in parsed file %s"; - } - - if (!error_fmt && noexec && rr->content_type - && (strncmp(rr->content_type, "text/", 5))) { - error_fmt = "unable to include potential exec \"%s\" " - "in parsed file %s"; - } - if (error_fmt == NULL) { - request_rec *p; - - for (p = r; p != NULL; p = p->main) { - if (strcmp(p->filename, rr->filename) == 0) { - break; - } - } - if (p != NULL) { - error_fmt = "Recursive include of \"%s\" " - "in parsed file %s"; - } - } - - if (!error_fmt && run_sub_req(rr)) { - error_fmt = "unable to include \"%s\" in parsed file %s"; - } - chdir_file(r->filename); - - if (error_fmt) { - log_printf(r->server, error_fmt, tag_val, r->filename); - rputs(error, r); - } - - if (rr != NULL) { - destroy_sub_req(rr); - } - } - else if (!strcmp(tag, "done")) { - return 0; - } - else { - log_printf(r->server, - "unknown parameter \"%s\" to tag include in %s", - tag, r->filename); - rputs(error, r); - } - } -} - -typedef struct { - request_rec *r; - char *s; -} include_cmd_arg; - -static void include_cmd_child(void *arg) -{ - request_rec *r = ((include_cmd_arg *) arg)->r; - char *s = ((include_cmd_arg *) arg)->s; - table *env = r->subprocess_env; -#ifdef DEBUG_INCLUDE_CMD - FILE *dbg = fopen("/dev/tty", "w"); -#endif - char err_string[MAX_STRING_LEN]; - -#ifdef DEBUG_INCLUDE_CMD -#ifdef __EMX__ - /* under OS/2 /dev/tty is referenced as con */ - FILE *dbg = fopen("con", "w"); -#else - fprintf(dbg, "Attempting to include command '%s'\n", s); -#endif -#endif - - if (r->path_info && r->path_info[0] != '\0') { - request_rec *pa_req; - - table_set(env, "PATH_INFO", escape_shell_cmd(r->pool, r->path_info)); - - pa_req = sub_req_lookup_uri(escape_uri(r->pool, r->path_info), r); - if (pa_req->filename) { - table_set(env, "PATH_TRANSLATED", - pstrcat(r->pool, pa_req->filename, pa_req->path_info, - NULL)); - } - } - - if (r->args) { - char *arg_copy = pstrdup(r->pool, r->args); - - table_set(env, "QUERY_STRING", r->args); - unescape_url(arg_copy); - table_set(env, "QUERY_STRING_UNESCAPED", - escape_shell_cmd(r->pool, arg_copy)); - } - - error_log2stderr(r->server); - -#ifdef DEBUG_INCLUDE_CMD - fprintf(dbg, "Attempting to exec '%s'\n", s); -#endif - cleanup_for_exec(); - /* set shellcmd flag to pass arg to SHELL_PATH */ - call_exec(r, s, create_environment(r->pool, env), 1); - /* Oh, drat. We're still here. The log file descriptors are closed, - * so we have to whimper a complaint onto stderr... - */ - -#ifdef DEBUG_INCLUDE_CMD - fprintf(dbg, "Exec failed\n"); -#endif - ap_snprintf(err_string, sizeof(err_string), - "httpd: exec of %s failed, reason: %s (errno = %d)\n", - SHELL_PATH, strerror(errno), errno); - write(STDERR_FILENO, err_string, strlen(err_string)); - exit(0); -} - -static int include_cmd(char *s, request_rec *r) -{ - include_cmd_arg arg; - FILE *f; - - arg.r = r; - arg.s = s; - - if (!spawn_child(r->pool, include_cmd_child, &arg, - kill_after_timeout, NULL, &f)) { - return -1; - } - - send_fd(f, r); - pfclose(r->pool, f); /* will wait for zombie when - * r->pool is cleared - */ - return 0; -} - - -static int handle_exec(FILE *in, request_rec *r, const char *error) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - char *file = r->filename; - char parsed_string[MAX_STRING_LEN]; - - while (1) { - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - return 1; - } - if (!strcmp(tag, "cmd")) { - parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 1); - if (include_cmd(parsed_string, r) == -1) { - log_printf(r->server, - "execution failure for parameter \"%s\" " - "to tag exec in file %s", - tag, r->filename); - rputs(error, r); - } - /* just in case some stooge changed directories */ - chdir_file(r->filename); - } - else if (!strcmp(tag, "cgi")) { - parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - if (include_cgi(parsed_string, r) == -1) { - log_printf(r->server, - "invalid CGI ref \"%s\" in %s", tag_val, file); - rputs(error, r); - } - /* grumble groan */ - chdir_file(r->filename); - } - else if (!strcmp(tag, "done")) { - return 0; - } - else { - log_printf(r->server, - "unknown parameter \"%s\" to tag exec in %s", - tag, file); - rputs(error, r); - } - } - -} - -static int handle_echo(FILE *in, request_rec *r, const char *error) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - - while (1) { - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - return 1; - } - if (!strcmp(tag, "var")) { - char *val = table_get(r->subprocess_env, tag_val); - - if (val) { - rputs(val, r); - } - else { - rputs("(none)", r); - } - } - else if (!strcmp(tag, "done")) { - return 0; - } - else { - log_printf(r->server, - "unknown parameter \"%s\" to tag echo in %s", - tag, r->filename); - rputs(error, r); - } - } -} - -#ifdef USE_PERL_SSI -static int handle_perl(FILE *in, request_rec *r, const char *error) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - SV *sub = Nullsv; - AV *av = newAV(); - - if (!(allow_options(r) & OPT_INCLUDES)) { - log_printf(r->server, - "httpd: #perl SSI disallowed by IncludesNoExec in %s", - r->filename); - return DECLINED; - } - while (1) { - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - break; - } - if (strnEQ(tag, "sub", 3)) { - sub = newSVpv(tag_val, 0); - } - else if (strnEQ(tag, "arg", 3)) { - av_push(av, newSVpv(tag_val, 0)); - } - else if (strnEQ(tag, "done", 4)) { - break; - } - } - perl_stdout2client(r); - perl_call_handler(sub, r, av); - return OK; -} -#endif - -/* error and tf must point to a string with room for at - * least MAX_STRING_LEN characters - */ -static int handle_config(FILE *in, request_rec *r, char *error, char *tf, - int *sizefmt) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - char parsed_string[MAX_STRING_LEN]; - table *env = r->subprocess_env; - - while (1) { - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0))) { - return 1; - } - if (!strcmp(tag, "errmsg")) { - parse_string(r, tag_val, error, MAX_STRING_LEN, 0); - } - else if (!strcmp(tag, "timefmt")) { - time_t date = r->request_time; - - parse_string(r, tag_val, tf, MAX_STRING_LEN, 0); - table_set(env, "DATE_LOCAL", ht_time(r->pool, date, tf, 0)); - table_set(env, "DATE_GMT", ht_time(r->pool, date, tf, 1)); - table_set(env, "LAST_MODIFIED", - ht_time(r->pool, r->finfo.st_mtime, tf, 0)); - } - else if (!strcmp(tag, "sizefmt")) { - parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - decodehtml(parsed_string); - if (!strcmp(parsed_string, "bytes")) { - *sizefmt = SIZEFMT_BYTES; - } - else if (!strcmp(parsed_string, "abbrev")) { - *sizefmt = SIZEFMT_KMG; - } - } - else if (!strcmp(tag, "done")) { - return 0; - } - else { - log_printf(r->server, - "unknown parameter \"%s\" to tag config in %s", - tag, r->filename); - rputs(error, r); - } - } -} - - -static int find_file(request_rec *r, const char *directive, const char *tag, - char *tag_val, struct stat *finfo, const char *error) -{ - char *to_send; - - if (!strcmp(tag, "file")) { - getparents(tag_val); /* get rid of any nasties */ - to_send = make_full_path(r->pool, "./", tag_val); - if (stat(to_send, finfo) == -1) { - log_printf(r->server, - "unable to get information about \"%s\" " - "in parsed file %s", - to_send, r->filename); - rputs(error, r); - return -1; - } - return 0; - } - else if (!strcmp(tag, "virtual")) { - request_rec *rr = sub_req_lookup_uri(tag_val, r); - - if (rr->status == HTTP_OK && rr->finfo.st_mode != 0) { - memcpy((char *) finfo, (const char *) &rr->finfo, - sizeof(struct stat)); - destroy_sub_req(rr); - return 0; - } - else { - log_printf(r->server, - "unable to get information about \"%s\" " - "in parsed file %s", - tag_val, r->filename); - rputs(error, r); - destroy_sub_req(rr); - return -1; - } - } - else { - log_printf(r->server, - "unknown parameter \"%s\" to tag %s in %s", - tag, directive, r->filename); - rputs(error, r); - return -1; - } -} - - -static int handle_fsize(FILE *in, request_rec *r, const char *error, int sizefmt) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - struct stat finfo; - char parsed_string[MAX_STRING_LEN]; - - while (1) { - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - return 1; - } - else if (!strcmp(tag, "done")) { - return 0; - } - else { - parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - if (!find_file(r, "fsize", tag, parsed_string, &finfo, error)) { - if (sizefmt == SIZEFMT_KMG) { - send_size(finfo.st_size, r); - } - else { - int l, x; -#if defined(BSD) && BSD > 199305 - /* ap_snprintf can't handle %qd */ - sprintf(tag, "%qd", finfo.st_size); -#else - ap_snprintf(tag, sizeof(tag), "%ld", finfo.st_size); -#endif - l = strlen(tag); /* grrr */ - for (x = 0; x < l; x++) { - if (x && (!((l - x) % 3))) { - rputc(',', r); - } - rputc(tag[x], r); - } - } - } - } - } -} - -static int handle_flastmod(FILE *in, request_rec *r, const char *error, const char *tf) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - struct stat finfo; - char parsed_string[MAX_STRING_LEN]; - - while (1) { - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - return 1; - } - else if (!strcmp(tag, "done")) { - return 0; - } - else { - parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - if (!find_file(r, "flastmod", tag, parsed_string, &finfo, error)) { - rputs(ht_time(r->pool, finfo.st_mtime, tf, 0), r); - } - } - } -} - -static int re_check(request_rec *r, char *string, char *rexp) -{ - regex_t *compiled; - int regex_error; - - compiled = pregcomp(r->pool, rexp, REG_EXTENDED | REG_NOSUB); - if (compiled == NULL) { - log_printf(r->server, "unable to compile pattern \"%s\"", rexp); - return -1; - } - regex_error = regexec(compiled, string, 0, (regmatch_t *) NULL, 0); - pregfree(r->pool, compiled); - return (!regex_error); -} - -enum token_type { - token_string, - token_and, token_or, token_not, token_eq, token_ne, - token_rbrace, token_lbrace, token_group, - token_ge, token_le, token_gt, token_lt -}; -struct token { - enum token_type type; - char value[MAX_STRING_LEN]; -}; - -/* there is an implicit assumption here that string is at most MAX_STRING_LEN-1 - * characters long... - */ -static const char *get_ptoken(request_rec *r, const char *string, struct token *token) -{ - char ch; - int next = 0; - int qs = 0; - - /* Skip leading white space */ - if (string == (char *) NULL) { - return (char *) NULL; - } - while ((ch = *string++)) { - if (!isspace(ch)) { - break; - } - } - if (ch == '\0') { - return (char *) NULL; - } - - token->type = token_string; /* the default type */ - switch (ch) { - case '(': - token->type = token_lbrace; - return (string); - case ')': - token->type = token_rbrace; - return (string); - case '=': - token->type = token_eq; - return (string); - case '!': - if (*string == '=') { - token->type = token_ne; - return (string + 1); - } - else { - token->type = token_not; - return (string); - } - case '\'': - token->type = token_string; - qs = 1; - break; - case '|': - if (*string == '|') { - token->type = token_or; - return (string + 1); - } - break; - case '&': - if (*string == '&') { - token->type = token_and; - return (string + 1); - } - break; - case '>': - if (*string == '=') { - token->type = token_ge; - return (string + 1); - } - else { - token->type = token_gt; - return (string); - } - case '<': - if (*string == '=') { - token->type = token_le; - return (string + 1); - } - else { - token->type = token_lt; - return (string); - } - default: - token->type = token_string; - break; - } - /* We should only be here if we are in a string */ - if (!qs) { - token->value[next++] = ch; - } - - /* - * Yes I know that goto's are BAD. But, c doesn't allow me to - * exit a loop from a switch statement. Yes, I could use a flag, - * but that is (IMHO) even less readable/maintainable than the goto. - */ - /* - * I used the ++string throughout this section so that string - * ends up pointing to the next token and I can just return it - */ - for (ch = *string; ch != '\0'; ch = *++string) { - if (ch == '\\') { - if ((ch = *++string) == '\0') { - goto TOKEN_DONE; - } - token->value[next++] = ch; - continue; - } - if (!qs) { - if (isspace(ch)) { - goto TOKEN_DONE; - } - switch (ch) { - case '(': - goto TOKEN_DONE; - case ')': - goto TOKEN_DONE; - case '=': - goto TOKEN_DONE; - case '!': - goto TOKEN_DONE; - case '|': - if (*(string + 1) == '|') { - goto TOKEN_DONE; - } - break; - case '&': - if (*(string + 1) == '&') { - goto TOKEN_DONE; - } - break; - case '<': - goto TOKEN_DONE; - case '>': - goto TOKEN_DONE; - } - token->value[next++] = ch; - } - else { - if (ch == '\'') { - qs = 0; - ++string; - goto TOKEN_DONE; - } - token->value[next++] = ch; - } - } - TOKEN_DONE: - /* If qs is still set, I have an unmatched ' */ - if (qs) { - rputs("\nUnmatched '\n", r); - next = 0; - } - token->value[next] = '\0'; - return (string); -} - - -/* - * Hey I still know that goto's are BAD. I don't think that I've ever - * used two in the same project, let alone the same file before. But, - * I absolutely want to make sure that I clean up the memory in all - * cases. And, without rewriting this completely, the easiest way - * is to just branch to the return code which cleans it up. - */ -/* there is an implicit assumption here that expr is at most MAX_STRING_LEN-1 - * characters long... - */ -static int parse_expr(request_rec *r, const char *expr, const char *error) -{ - struct parse_node { - struct parse_node *left, *right, *parent; - struct token token; - int value, done; - } *root, *current, *new; - const char *parse; - char buffer[MAX_STRING_LEN]; - pool *expr_pool; - int retval = 0; - - if ((parse = expr) == (char *) NULL) { - return (0); - } - root = current = (struct parse_node *) NULL; - expr_pool = make_sub_pool(r->pool); - - /* Create Parse Tree */ - while (1) { - new = (struct parse_node *) palloc(expr_pool, - sizeof(struct parse_node)); - new->parent = new->left = new->right = (struct parse_node *) NULL; - new->done = 0; - if ((parse = get_ptoken(r, parse, &new->token)) == (char *) NULL) { - break; - } - switch (new->token.type) { - - case token_string: -#ifdef DEBUG_INCLUDE - rvputs(r, " Token: string (", new->token.value, ")\n", NULL); -#endif - if (current == (struct parse_node *) NULL) { - root = current = new; - break; - } - switch (current->token.type) { - case token_string: - if (current->token.value[0] != '\0') { - strncat(current->token.value, " ", - MAX_STRING_LEN - strlen(current->token.value) - 1); - } - strncat(current->token.value, new->token.value, - MAX_STRING_LEN - strlen(current->token.value) - 1); - current->token.value[sizeof(current->token.value) - 1] = '\0'; - break; - case token_eq: - case token_ne: - case token_and: - case token_or: - case token_lbrace: - case token_not: - case token_ge: - case token_gt: - case token_le: - case token_lt: - new->parent = current; - current = current->right = new; - break; - default: - log_printf(r->server, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - break; - - case token_and: - case token_or: -#ifdef DEBUG_INCLUDE - rputs(" Token: and/or\n", r); -#endif - if (current == (struct parse_node *) NULL) { - log_printf(r->server, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - /* Percolate upwards */ - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_string: - case token_group: - case token_not: - case token_eq: - case token_ne: - case token_and: - case token_or: - case token_ge: - case token_gt: - case token_le: - case token_lt: - current = current->parent; - continue; - case token_lbrace: - break; - default: - log_printf(r->server, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - break; - } - if (current == (struct parse_node *) NULL) { - new->left = root; - new->left->parent = new; - new->parent = (struct parse_node *) NULL; - root = new; - } - else { - new->left = current->right; - current->right = new; - new->parent = current; - } - current = new; - break; - - case token_not: -#ifdef DEBUG_INCLUDE - rputs(" Token: not\n", r); -#endif - if (current == (struct parse_node *) NULL) { - root = current = new; - break; - } - /* Percolate upwards */ - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_not: - case token_eq: - case token_ne: - case token_and: - case token_or: - case token_lbrace: - case token_ge: - case token_gt: - case token_le: - case token_lt: - break; - default: - log_printf(r->server, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - break; - } - if (current == (struct parse_node *) NULL) { - new->left = root; - new->left->parent = new; - new->parent = (struct parse_node *) NULL; - root = new; - } - else { - new->left = current->right; - current->right = new; - new->parent = current; - } - current = new; - break; - - case token_eq: - case token_ne: - case token_ge: - case token_gt: - case token_le: - case token_lt: -#ifdef DEBUG_INCLUDE - rputs(" Token: eq/ne/ge/gt/le/lt\n", r); -#endif - if (current == (struct parse_node *) NULL) { - log_printf(r->server, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - /* Percolate upwards */ - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_string: - case token_group: - current = current->parent; - continue; - case token_lbrace: - case token_and: - case token_or: - break; - case token_not: - case token_eq: - case token_ne: - case token_ge: - case token_gt: - case token_le: - case token_lt: - default: - log_printf(r->server, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - break; - } - if (current == (struct parse_node *) NULL) { - new->left = root; - new->left->parent = new; - new->parent = (struct parse_node *) NULL; - root = new; - } - else { - new->left = current->right; - current->right = new; - new->parent = current; - } - current = new; - break; - - case token_rbrace: -#ifdef DEBUG_INCLUDE - rputs(" Token: rbrace\n", r); -#endif - while (current != (struct parse_node *) NULL) { - if (current->token.type == token_lbrace) { - current->token.type = token_group; - break; - } - current = current->parent; - } - if (current == (struct parse_node *) NULL) { - log_printf(r->server, "Unmatched ')' in \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - break; - - case token_lbrace: -#ifdef DEBUG_INCLUDE - rputs(" Token: lbrace\n", r); -#endif - if (current == (struct parse_node *) NULL) { - root = current = new; - break; - } - /* Percolate upwards */ - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_not: - case token_eq: - case token_ne: - case token_and: - case token_or: - case token_lbrace: - case token_ge: - case token_gt: - case token_le: - case token_lt: - break; - case token_string: - case token_group: - default: - log_printf(r->server, - "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - break; - } - if (current == (struct parse_node *) NULL) { - new->left = root; - new->left->parent = new; - new->parent = (struct parse_node *) NULL; - root = new; - } - else { - new->left = current->right; - current->right = new; - new->parent = current; - } - current = new; - break; - default: - break; - } - } - - /* Evaluate Parse Tree */ - current = root; - while (current != (struct parse_node *) NULL) { - switch (current->token.type) { - case token_string: -#ifdef DEBUG_INCLUDE - rputs(" Evaluate string\n", r); -#endif - parse_string(r, current->token.value, buffer, sizeof(buffer), 0); - safe_copy(current->token.value, buffer, sizeof(current->token.value)); - current->value = (current->token.value[0] != '\0'); - current->done = 1; - current = current->parent; - break; - - case token_and: - case token_or: -#ifdef DEBUG_INCLUDE - rputs(" Evaluate and/or\n", r); -#endif - if (current->left == (struct parse_node *) NULL || - current->right == (struct parse_node *) NULL) { - log_printf(r->server, "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - if (!current->left->done) { - switch (current->left->token.type) { - case token_string: - parse_string(r, current->left->token.value, - buffer, sizeof(buffer), 0); - safe_copy(current->left->token.value, buffer, - sizeof(current->left->token.value)); - current->left->value = (current->left->token.value[0] != '\0'); - current->left->done = 1; - break; - default: - current = current->left; - continue; - } - } - if (!current->right->done) { - switch (current->right->token.type) { - case token_string: - parse_string(r, current->right->token.value, - buffer, sizeof(buffer), 0); - safe_copy(current->right->token.value, buffer, - sizeof(current->right->token.value)); - current->right->value = (current->right->token.value[0] != '\0'); - current->right->done = 1; - break; - default: - current = current->right; - continue; - } - } -#ifdef DEBUG_INCLUDE - rvputs(r, " Left: ", current->left->value ? "1" : "0", - "\n", NULL); - rvputs(r, " Right: ", current->right->value ? "1" : "0", - "\n", NULL); -#endif - if (current->token.type == token_and) { - current->value = current->left->value && current->right->value; - } - else { - current->value = current->left->value || current->right->value; - } -#ifdef DEBUG_INCLUDE - rvputs(r, " Returning ", current->value ? "1" : "0", - "\n", NULL); -#endif - current->done = 1; - current = current->parent; - break; - - case token_eq: - case token_ne: -#ifdef DEBUG_INCLUDE - rputs(" Evaluate eq/ne\n", r); -#endif - if ((current->left == (struct parse_node *) NULL) || - (current->right == (struct parse_node *) NULL) || - (current->left->token.type != token_string) || - (current->right->token.type != token_string)) { - log_printf(r->server, "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - parse_string(r, current->left->token.value, - buffer, sizeof(buffer), 0); - safe_copy(current->left->token.value, buffer, - sizeof(current->left->token.value)); - parse_string(r, current->right->token.value, - buffer, sizeof(buffer), 0); - safe_copy(current->right->token.value, buffer, - sizeof(current->right->token.value)); - if (current->right->token.value[0] == '/') { - int len; - len = strlen(current->right->token.value); - if (current->right->token.value[len - 1] == '/') { - current->right->token.value[len - 1] = '\0'; - } - else { - log_printf(r->server, "Invalid rexp \"%s\" in file %s", - current->right->token.value, r->filename); - rputs(error, r); - goto RETURN; - } -#ifdef DEBUG_INCLUDE - rvputs(r, " Re Compare (", current->left->token.value, - ") with /", ¤t->right->token.value[1], "/\n", NULL); -#endif - current->value = - re_check(r, current->left->token.value, - ¤t->right->token.value[1]); - } - else { -#ifdef DEBUG_INCLUDE - rvputs(r, " Compare (", current->left->token.value, - ") with (", current->right->token.value, ")\n", NULL); -#endif - current->value = - (strcmp(current->left->token.value, - current->right->token.value) == 0); - } - if (current->token.type == token_ne) { - current->value = !current->value; - } -#ifdef DEBUG_INCLUDE - rvputs(r, " Returning ", current->value ? "1" : "0", - "\n", NULL); -#endif - current->done = 1; - current = current->parent; - break; - case token_ge: - case token_gt: - case token_le: - case token_lt: -#ifdef DEBUG_INCLUDE - rputs(" Evaluate ge/gt/le/lt\n", r); -#endif - if ((current->left == (struct parse_node *) NULL) || - (current->right == (struct parse_node *) NULL) || - (current->left->token.type != token_string) || - (current->right->token.type != token_string)) { - log_printf(r->server, "Invalid expression \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - } - parse_string(r, current->left->token.value, - buffer, sizeof(buffer), 0); - safe_copy(current->left->token.value, buffer, - sizeof(current->left->token.value)); - parse_string(r, current->right->token.value, - buffer, sizeof(buffer), 0); - safe_copy(current->right->token.value, buffer, - sizeof(current->right->token.value)); -#ifdef DEBUG_INCLUDE - rvputs(r, " Compare (", current->left->token.value, - ") with (", current->right->token.value, ")\n", NULL); -#endif - current->value = - strcmp(current->left->token.value, - current->right->token.value); - if (current->token.type == token_ge) { - current->value = current->value >= 0; - } - else if (current->token.type == token_gt) { - current->value = current->value > 0; - } - else if (current->token.type == token_le) { - current->value = current->value <= 0; - } - else if (current->token.type == token_lt) { - current->value = current->value < 0; - } - else { - current->value = 0; /* Don't return -1 if unknown token */ - } -#ifdef DEBUG_INCLUDE - rvputs(r, " Returning ", current->value ? "1" : "0", - "\n", NULL); -#endif - current->done = 1; - current = current->parent; - break; - - case token_not: - if (current->right != (struct parse_node *) NULL) { - if (!current->right->done) { - current = current->right; - continue; - } - current->value = !current->right->value; - } - else { - current->value = 0; - } -#ifdef DEBUG_INCLUDE - rvputs(r, " Evaluate !: ", current->value ? "1" : "0", - "\n", NULL); -#endif - current->done = 1; - current = current->parent; - break; - - case token_group: - if (current->right != (struct parse_node *) NULL) { - if (!current->right->done) { - current = current->right; - continue; - } - current->value = current->right->value; - } - else { - current->value = 1; - } -#ifdef DEBUG_INCLUDE - rvputs(r, " Evaluate (): ", current->value ? "1" : "0", - "\n", NULL); -#endif - current->done = 1; - current = current->parent; - break; - - case token_lbrace: - log_printf(r->server, "Unmatched '(' in \"%s\" in file %s", - expr, r->filename); - rputs(error, r); - goto RETURN; - - case token_rbrace: - log_printf(r->server, "Unmatched ')' in \"%s\" in file %s\n", - expr, r->filename); - rputs(error, r); - goto RETURN; - - default: - log_printf(r->server, "bad token type"); - rputs(error, r); - goto RETURN; - } - } - - retval = (root == (struct parse_node *) NULL) ? 0 : root->value; - RETURN: - destroy_pool(expr_pool); - return (retval); -} - -static int handle_if(FILE *in, request_rec *r, const char *error, - int *conditional_status, int *printing) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - char *expr; - - expr = NULL; - while (1) { - tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0); - if (*tag == '\0') { - return 1; - } - else if (!strcmp(tag, "done")) { - if (expr == NULL) { - log_printf(r->server, "missing expr in if statement: %s", - r->filename); - rputs(error, r); - return 1; - } - *printing = *conditional_status = parse_expr(r, expr, error); -#ifdef DEBUG_INCLUDE - rvputs(r, "**** if conditional_status=\"", - *conditional_status ? "1" : "0", "\"\n", NULL); -#endif - return 0; - } - else if (!strcmp(tag, "expr")) { - expr = tag_val; -#ifdef DEBUG_INCLUDE - rvputs(r, "**** if expr=\"", expr, "\"\n", NULL); -#endif - } - else { - log_printf(r->server, "unknown parameter \"%s\" to tag if in %s", - tag, r->filename); - rputs(error, r); - } - } -} - -static int handle_elif(FILE *in, request_rec *r, const char *error, - int *conditional_status, int *printing) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - char *expr; - - expr = NULL; - while (1) { - tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0); - if (*tag == '\0') { - return 1; - } - else if (!strcmp(tag, "done")) { -#ifdef DEBUG_INCLUDE - rvputs(r, "**** elif conditional_status=\"", - *conditional_status ? "1" : "0", "\"\n", NULL); -#endif - if (*conditional_status) { - *printing = 0; - return (0); - } - if (expr == NULL) { - log_printf(r->server, "missing expr in elif statement: %s", - r->filename); - rputs(error, r); - return 1; - } - *printing = *conditional_status = parse_expr(r, expr, error); -#ifdef DEBUG_INCLUDE - rvputs(r, "**** elif conditional_status=\"", - *conditional_status ? "1" : "0", "\"\n", NULL); -#endif - return 0; - } - else if (!strcmp(tag, "expr")) { - expr = tag_val; -#ifdef DEBUG_INCLUDE - rvputs(r, "**** if expr=\"", expr, "\"\n", NULL); -#endif - } - else { - log_printf(r->server, "unknown parameter \"%s\" to tag if in %s", - tag, r->filename); - rputs(error, r); - } - } -} - -static int handle_else(FILE *in, request_rec *r, const char *error, - int *conditional_status, int *printing) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - return 1; - } - else if (!strcmp(tag, "done")) { -#ifdef DEBUG_INCLUDE - rvputs(r, "**** else conditional_status=\"", - *conditional_status ? "1" : "0", "\"\n", NULL); -#endif - *printing = !(*conditional_status); - *conditional_status = 1; - return 0; - } - else { - log_printf(r->server, "else directive does not take tags in %s", - r->filename); - if (*printing) { - rputs(error, r); - } - return -1; - } -} - -static int handle_endif(FILE *in, request_rec *r, const char *error, - int *conditional_status, int *printing) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - return 1; - } - else if (!strcmp(tag, "done")) { -#ifdef DEBUG_INCLUDE - rvputs(r, "**** endif conditional_status=\"", - *conditional_status ? "1" : "0", "\"\n", NULL); -#endif - *printing = 1; - *conditional_status = 1; - return 0; - } - else { - log_printf(r->server, "endif directive does not take tags in %s", - r->filename); - rputs(error, r); - return -1; - } -} - -static int handle_set(FILE *in, request_rec *r, const char *error) -{ - char tag[MAX_STRING_LEN]; - char parsed_string[MAX_STRING_LEN]; - char *tag_val; - char *var; - - var = (char *) NULL; - while (1) { - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - return 1; - } - else if (!strcmp(tag, "done")) { - return 0; - } - else if (!strcmp(tag, "var")) { - var = tag_val; - } - else if (!strcmp(tag, "value")) { - if (var == (char *) NULL) { - log_printf(r->server, - "variable must precede value in set directive in %s", - r->filename); - rputs(error, r); - return -1; - } - parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0); - table_set(r->subprocess_env, var, parsed_string); - } - else { - log_printf(r->server, "Invalid tag for set directive in %s", - r->filename); - rputs(error, r); - return -1; - } - } -} - -static int handle_printenv(FILE *in, request_rec *r, const char *error) -{ - char tag[MAX_STRING_LEN]; - char *tag_val; - table_entry *elts = (table_entry *) r->subprocess_env->elts; - int i; - - if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) { - return 1; - } - else if (!strcmp(tag, "done")) { - for (i = 0; i < r->subprocess_env->nelts; ++i) { - rvputs(r, elts[i].key, "=", elts[i].val, "\n", NULL); - } - return 0; - } - else { - log_printf(r->server, "printenv directive does not take tags in %s", - r->filename); - rputs(error, r); - return -1; - } -} - - - -/* -------------------------- The main function --------------------------- */ - -/* This is a stub which parses a file descriptor. */ - -static void send_parsed_content(FILE *f, request_rec *r) -{ - char directive[MAX_STRING_LEN], error[MAX_STRING_LEN]; - char timefmt[MAX_STRING_LEN]; - int noexec = allow_options(r) & OPT_INCNOEXEC; - int ret, sizefmt; - int if_nesting; - int printing; - int conditional_status; - - safe_copy(error, DEFAULT_ERROR_MSG, sizeof(error)); - safe_copy(timefmt, DEFAULT_TIME_FORMAT, sizeof(timefmt)); - sizefmt = SIZEFMT_KMG; - -/* Turn printing on */ - printing = conditional_status = 1; - if_nesting = 0; - - chdir_file(r->filename); - if (r->args) { /* add QUERY stuff to env cause it ain't yet */ - char *arg_copy = pstrdup(r->pool, r->args); - - table_set(r->subprocess_env, "QUERY_STRING", r->args); - unescape_url(arg_copy); - table_set(r->subprocess_env, "QUERY_STRING_UNESCAPED", - escape_shell_cmd(r->pool, arg_copy)); - } - - while (1) { - if (!find_string(f, STARTING_SEQUENCE, r, printing)) { - if (get_directive(f, directive, sizeof(directive), r->pool)) { - log_printf(r->server, - "mod_include: error reading directive in %s", - r->filename); - rputs(error, r); - return; - } - if (!strcmp(directive, "if")) { - if (!printing) { - if_nesting++; - } - else { - ret = handle_if(f, r, error, &conditional_status, - &printing); - if_nesting = 0; - } - continue; - } - else if (!strcmp(directive, "else")) { - if (!if_nesting) { - ret = handle_else(f, r, error, &conditional_status, - &printing); - } - continue; - } - else if (!strcmp(directive, "elif")) { - if (!if_nesting) { - ret = handle_elif(f, r, error, &conditional_status, - &printing); - } - continue; - } - else if (!strcmp(directive, "endif")) { - if (!if_nesting) { - ret = handle_endif(f, r, error, &conditional_status, - &printing); - } - else { - if_nesting--; - } - continue; - } - if (!printing) { - continue; - } - if (!strcmp(directive, "exec")) { - if (noexec) { - log_printf(r->server, - "httpd: exec used but not allowed in %s", - r->filename); - if (printing) { - rputs(error, r); - } - ret = find_string(f, ENDING_SEQUENCE, r, 0); - } - else { - ret = handle_exec(f, r, error); - } - } - else if (!strcmp(directive, "config")) { - ret = handle_config(f, r, error, timefmt, &sizefmt); - } - else if (!strcmp(directive, "set")) { - ret = handle_set(f, r, error); - } - else if (!strcmp(directive, "include")) { - ret = handle_include(f, r, error, noexec); - } - else if (!strcmp(directive, "echo")) { - ret = handle_echo(f, r, error); - } - else if (!strcmp(directive, "fsize")) { - ret = handle_fsize(f, r, error, sizefmt); - } - else if (!strcmp(directive, "flastmod")) { - ret = handle_flastmod(f, r, error, timefmt); - } - else if (!strcmp(directive, "printenv")) { - ret = handle_printenv(f, r, error); - } -#ifdef USE_PERL_SSI - else if (!strcmp(directive, "perl")) { - ret = handle_perl(f, r, error); - } -#endif - else { - log_printf(r->server, "httpd: unknown directive \"%s\" " - "in parsed doc %s", - directive, r->filename); - if (printing) { - rputs(error, r); - } - ret = find_string(f, ENDING_SEQUENCE, r, 0); - } - if (ret) { - log_printf(r->server, "httpd: premature EOF in parsed file %s", - r->filename); - return; - } - } - else { - return; - } - } -} - -/***************************************************************** - * - * XBITHACK. Sigh... NB it's configurable per-directory; the compile-time - * option only changes the default. - */ - -module includes_module; -enum xbithack { - xbithack_off, xbithack_on, xbithack_full -}; - -#ifdef XBITHACK -#define DEFAULT_XBITHACK xbithack_full -#else -#define DEFAULT_XBITHACK xbithack_off -#endif - -static void *create_includes_dir_config(pool *p, char *dummy) -{ - enum xbithack *result = (enum xbithack *) palloc(p, sizeof(enum xbithack)); - *result = DEFAULT_XBITHACK; - return result; -} - -static const char *set_xbithack(cmd_parms *cmd, void *xbp, char *arg) -{ - enum xbithack *state = (enum xbithack *) xbp; - - if (!strcasecmp(arg, "off")) { - *state = xbithack_off; - } - else if (!strcasecmp(arg, "on")) { - *state = xbithack_on; - } - else if (!strcasecmp(arg, "full")) { - *state = xbithack_full; - } - else { - return "XBitHack must be set to Off, On, or Full"; - } - - return NULL; -} - -static int send_parsed_file(request_rec *r) -{ - FILE *f; - enum xbithack *state = - (enum xbithack *) get_module_config(r->per_dir_config, &includes_module); - int errstatus; - - if (!(allow_options(r) & OPT_INCLUDES)) { - return DECLINED; - } - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) { - return DECLINED; - } - if (r->finfo.st_mode == 0) { - log_printf(r->server, "File does not exist: %s", - (r->path_info - ? pstrcat(r->pool, r->filename, r->path_info, NULL) - : r->filename)); - return HTTP_NOT_FOUND; - } - - if (!(f = pfopen(r->pool, r->filename, "r"))) { - log_printf(r->server, - "file permissions deny server access: %s", r->filename); - return HTTP_FORBIDDEN; - } - - if (*state == xbithack_full -#ifndef __EMX__ - /* OS/2 dosen't support Groups. */ - && (r->finfo.st_mode & S_IXGRP) -#endif - ) { - errstatus = set_last_modified (r, r->finfo.st_mtime); - table_unset(r->headers_out, "ETag"); - if (errstatus) { - return errstatus; - } - } - - send_http_header(r); - - if (r->header_only) { - pfclose(r->pool, f); - return OK; - } - - if (r->main) { - /* Kludge --- for nested includes, we want to keep the - * subprocess environment of the base document (for compatibility); - * that means torquing our own last_modified date as well so that - * the LAST_MODIFIED variable gets reset to the proper value if - * the nested document resets <!--#config timefmt--> - */ - r->subprocess_env = r->main->subprocess_env; - r->finfo.st_mtime = r->main->finfo.st_mtime; - } - else { - add_common_vars(r); - add_cgi_vars(r); - add_include_vars(r, DEFAULT_TIME_FORMAT); - } - hard_timeout("send SSI", r); - - send_parsed_content(f, r); - - kill_timeout(r); - return OK; -} - -static int send_shtml_file(request_rec *r) -{ - r->content_type = "text/html"; - return send_parsed_file(r); -} - -static int xbithack_handler(request_rec *r) -{ -#ifdef __EMX__ - /* OS/2 dosen't currently support the xbithack. This is being worked on. */ - return DECLINED; -#else - enum xbithack *state; - - if (!(r->finfo.st_mode & S_IXUSR)) { - return DECLINED; - } - - state = (enum xbithack *) get_module_config(r->per_dir_config, - &includes_module); - - if (*state == xbithack_off) { - return DECLINED; - } - return send_parsed_file(r); -#endif -} - -static command_rec includes_cmds[] = -{ - {"XBitHack", set_xbithack, NULL, OR_OPTIONS, TAKE1, "Off, On, or Full"}, - {NULL} -}; - -static handler_rec includes_handlers[] = -{ - {INCLUDES_MAGIC_TYPE, send_shtml_file}, - {INCLUDES_MAGIC_TYPE3, send_shtml_file}, - {"server-parsed", send_parsed_file}, - {"text/html", xbithack_handler}, - {NULL} -}; - -module includes_module = -{ - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_includes_dir_config, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - includes_cmds, /* command table */ - includes_handlers, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_info.c b/usr.sbin/httpd/src/mod_info.c deleted file mode 100644 index 9aedbec2cd5..00000000000 --- a/usr.sbin/httpd/src/mod_info.c +++ /dev/null @@ -1,455 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * Info Module. Display configuration information for the server and - * all included modules. - * - * <Location /server-info> - * SetHandler server-info - * </Location> - * - * GET /server-info - Returns full configuration page for server and all modules - * GET /server-info?server - Returns server configuration only - * GET /server-info?module_name - Returns configuration for a single module - * GET /server-info?list - Returns quick list of included modules - * - * Rasmus Lerdorf <rasmus@vex.net>, May 1996 - * - * 05.01.96 Initial Version - * - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_main.h" -#include "http_protocol.h" -#include "util_script.h" - -typedef struct mod_info_config_lines { - char *cmd; - char *line; - struct mod_info_config_lines *next; -} mod_info_config_lines; - -module info_module; -extern module *top_module; - -char *mod_info_html_cmd_string(char *string) { - char *s,*t; - static char ret[256]; /* What is the max size of a command? */ - char *end_ret; - - ret[0]='\0'; - s = string; - t=ret; - end_ret = t + sizeof(ret); - while((*s) && ((t-ret) < sizeof(ret))) { - if(*s=='<') { - strncpy(t,"<", end_ret - t); - t+=4; - } else if(*s=='>') { - strncpy(t,">", end_ret - t); - t+=4; - } else if(*s=='&') { - strncpy(t,"&", end_ret - t); - t+=5; - } else { - *t++=*s; - } - s++; - } - *t='\0'; - return(ret); -} - -mod_info_config_lines *mod_info_load_config(pool *p, char *filename, request_rec *r) { - char s[MAX_STRING_LEN]; - FILE *fp; - mod_info_config_lines *new, *ret=NULL, *prev=NULL; - char *t,*tt,o, *msg; - - fp = pfopen(p,filename,"r"); - if(!fp) { - msg = pstrcat - ( - r->pool, - "mod_info: couldn't open config file ", - filename, - NULL - ); - log_error (msg, r->server); - return NULL; - } - while(!cfg_getline(s,MAX_STRING_LEN,fp)) { - if(*s=='#') continue; /* skip comments */ - new = palloc(p,sizeof(struct mod_info_config_lines)); - new->next = NULL; - if(!ret) ret=new; - if(prev) prev->next=new; - t=strchr(s,' '); - tt=strchr(s,'\t'); - if(t && tt) t = (t<tt)?t:tt; - else if(tt) t=tt; - if(t) { - o=*t; - *t='\0'; - new->cmd = pstrdup(p,s); - new->line = pstrdup(p,t+1); - *t=o; - } else { - new->cmd = pstrdup(p,s); - new->line = NULL; - } - prev=new; - } - pfclose(p,fp); - return(ret); -} - -void mod_info_module_cmds(request_rec *r, mod_info_config_lines *cfg, command_rec *cmds,char *label) { - command_rec *cmd=cmds; - mod_info_config_lines *li=cfg,*li_st=NULL,*li_se=NULL,*block_start=NULL; - int lab=0, nest=0; - - while(li) { - if(!strncasecmp(li->cmd,"<directory",10) || - !strncasecmp(li->cmd,"<location",9) || - !strncasecmp(li->cmd,"<limit",6) || - !strncasecmp(li->cmd,"<files",6)) { - if(nest) li_se=li; - else li_st=li; - li=li->next; - nest++; - continue; - } else if(nest && (!strncasecmp(li->cmd,"</limit",7) || - !strncasecmp(li->cmd,"</location",10) || - !strncasecmp(li->cmd,"</directory",11) || - !strncasecmp(li->cmd,"</files",7))) { - if(block_start) { - if((nest==1 && block_start==li_st) || (nest==2 && block_start==li_se)) { - rputs("<dd><tt>",r); - if(nest==2) rputs(" ",r); - rputs(mod_info_html_cmd_string(li->cmd),r); - rputs(" ",r); - if(li->line) rputs(mod_info_html_cmd_string(li->line),r); - rputs("</tt>\n",r); - nest--; - if(!nest) { - block_start=NULL; - li_st=NULL; - } else { - block_start=li_st; - } - li_se=NULL; - } else { - nest--; - if(!nest) { - li_st=NULL; - } - li_se=NULL; - } - } else { - nest--; - if(!nest) { - li_st=NULL; - } - li_se=NULL; - } - li=li->next; - continue; - } - cmd = cmds; - while(cmd) { - if(cmd->name) { - if(!strcasecmp(cmd->name,li->cmd)) { - if(!lab) { - rputs("<dt><strong>",r); - rputs(label,r); - rputs("</strong>\n",r); - lab=1; - } - if(((nest && block_start==NULL) || (nest==2 && block_start==li_st)) - && (strncasecmp(li->cmd,"<directory",10) && - strncasecmp(li->cmd,"<location",9) && strncasecmp(li->cmd,"<limit",6) && - strncasecmp(li->cmd,"</limit",7) && strncasecmp(li->cmd,"</location",10) && - strncasecmp(li->cmd,"</directory",11) && - strncasecmp(li->cmd,"</files",7))) { - rputs("<dd><tt>",r); - rputs(mod_info_html_cmd_string(li_st->cmd),r); - rputs(" ",r); - if(li_st->line) rputs(mod_info_html_cmd_string(li_st->line),r); - rputs("</tt>\n",r); - block_start=li_st; - if(li_se) { - rputs("<dd><tt> ",r); - rputs(mod_info_html_cmd_string(li_se->cmd),r); - rputs(" ",r); - if(li_se->line) rputs(mod_info_html_cmd_string(li_se->line),r); - rputs("</tt>\n",r); - block_start=li_se; - } - } - rputs("<dd><tt>",r); - if(nest) rputs(" ",r); - if(nest==2) rputs(" ",r); - rputs(mod_info_html_cmd_string(li->cmd),r); - if(li->line) { - rputs(" <i>",r); - rputs(mod_info_html_cmd_string(li->line),r); - rputs("</i></tt>",r); - } - } - } else break; - cmd++; - } - li = li->next; - } -} - -int display_info(request_rec *r) { - module *modp = NULL; - char buf[512], *cfname; - command_rec *cmd=NULL; - handler_rec *hand=NULL; - server_rec *serv = r->server; - int comma=0; - mod_info_config_lines *mod_info_cfg_httpd=NULL; - mod_info_config_lines *mod_info_cfg_srm=NULL; - mod_info_config_lines *mod_info_cfg_access=NULL; - extern int standalone; - extern uid_t user_id; - extern char *user_name; - extern gid_t group_id; - extern int max_requests_per_child; - extern char *pid_fname; - extern char *scoreboard_fname; - extern int daemons_to_start; - extern int daemons_min_free; - extern int daemons_max_free; - extern int daemons_limit; - extern char server_root[MAX_STRING_LEN]; - extern char server_confname[MAX_STRING_LEN]; - - r->allowed |= (1 << M_GET); - if (r->method_number != M_GET) - return DECLINED; - - r->content_type = "text/html"; - send_http_header(r); - if(r->header_only) { - return 0; - } - hard_timeout("send server info", r); - - rputs("<html><head><title>Server Information</title></head>\n",r); - rputs("<body><h1 align=center>Apache Server Information</h1>\n",r); - if(!r->args || strcasecmp(r->args,"list")) { - cfname = server_root_relative (r->pool, server_confname); - mod_info_cfg_httpd = mod_info_load_config (r->pool, cfname, r); - cfname = server_root_relative (r->pool, serv->srm_confname); - mod_info_cfg_srm = mod_info_load_config(r->pool, cfname, r); - cfname = server_root_relative (r->pool, serv->access_confname); - mod_info_cfg_access = mod_info_load_config (r->pool, cfname, r); - if(!r->args) { - rputs("<tt><a href=\"#server\">Server Settings</a>, ",r); - for(modp = top_module; modp; modp = modp->next) { - ap_snprintf(buf, sizeof(buf), "<a href=\"#%s\">%s</a>",modp->name,modp->name); - rputs(buf, r); - if(modp->next) rputs(", ",r); - } - rputs("</tt><hr>",r); - - } - if(!r->args || !strcasecmp(r->args,"server")) { - ap_snprintf(buf, sizeof(buf), "<a name=\"server\"><strong>Server Version:</strong> <font size=+1><tt>%s</tt></a></font><br>\n",SERVER_VERSION); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>API Version:</strong> <tt>%d</tt><br>\n",MODULE_MAGIC_NUMBER); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>Run Mode:</strong> <tt>%s</tt><br>\n",standalone?"standalone":"inetd"); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>User/Group:</strong> <tt>%s(%d)/%d</tt><br>\n",user_name,(int)user_id,(int)group_id); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>Hostname/port:</strong> <tt>%s:%u</tt><br>\n",serv->server_hostname,serv->port); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>Daemons:</strong> <tt>start: %d min idle: %d max idle: %d max: %d</tt><br>\n",daemons_to_start,daemons_min_free,daemons_max_free,daemons_limit); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>Max Requests:</strong> <tt>per child: %d keep alive: %s max per connection: %d</tt><br>\n",max_requests_per_child,serv->keep_alive ? "on":"off", serv->keep_alive_max); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>Timeouts:</strong> <tt>connection: %d keep-alive: %d</tt><br>",serv->timeout,serv->keep_alive_timeout); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>Server Root:</strong> <tt>%s</tt><br>\n",server_root); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>Config File:</strong> <tt>%s</tt><br>\n",server_confname); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>PID File:</strong> <tt>%s</tt><br>\n",pid_fname); - rputs(buf,r); - ap_snprintf(buf, sizeof(buf), "<strong>Scoreboard File:</strong> <tt>%s</tt><br>\n",scoreboard_fname); - rputs(buf,r); - } - rputs("<hr><dl>",r); - for(modp = top_module; modp; modp = modp->next) { - if(!r->args || !strcasecmp(modp->name,r->args)) { - ap_snprintf(buf, sizeof(buf), "<dt><a name=\"%s\"><strong>Module Name:</strong> <font size=+1><tt>%s</tt></a></font>\n",modp->name,modp->name); - rputs(buf,r); - rputs("<dt><strong>Content-types affected:</strong>",r); - hand = modp->handlers; - if(hand) { - while(hand) { - if(hand->content_type) { - ap_snprintf(buf, sizeof(buf), " <tt>%s</tt>\n",hand->content_type); - rputs(buf,r); - } else break; - hand++; - if(hand && hand->content_type) rputs(",",r); - } - } else { - rputs("<tt> none</tt>",r); - } - rputs("<dt><strong>Module Groups:</strong> \n",r); - if(modp->translate_handler) { - rputs("<tt>Translate Handler</tt>\n",r); - comma=1; - } - if(modp->check_user_id) { - if(comma) rputs(", ",r); - rputs("<tt>User ID Checking</tt>\n",r); - comma=1; - } - if(modp->auth_checker) { - if(comma) rputs(", ",r); - rputs("<tt>Authentication Checking</tt>\n",r); - comma=1; - } - if(modp->access_checker) { - if(comma) rputs(", ",r); - rputs("<tt>Access Checking</tt>\n",r); - comma=1; - } - if(modp->type_checker) { - if(comma) rputs(", ",r); - rputs("<tt>Type Checking</tt>\n",r); - comma=1; - } - if(modp->fixer_upper) { - if(comma) rputs(", ",r); - rputs("<tt>Header Fixer</tt>\n",r); - comma=1; - } - if(modp->logger) { - if(comma) rputs(", ",r); - rputs("<tt>Logging</tt>\n",r); - comma=1; - } - if(!comma) rputs("<tt> none</tt>",r); - comma=0; - rputs("<dt><strong>Module Configuration Commands:</strong> ",r); - cmd = modp->cmds; - if(cmd) { - while(cmd) { - if(cmd->name) { - ap_snprintf(buf, sizeof(buf), "<dd><tt>%s - <i>",mod_info_html_cmd_string(cmd->name)); - rputs(buf,r); - if(cmd->errmsg) rputs(cmd->errmsg,r); - rputs("</i></tt>\n",r); - } else break; - cmd++; - } - rputs("<dt><strong>Current Configuration:</strong>\n",r); - mod_info_module_cmds(r,mod_info_cfg_httpd,modp->cmds,"httpd.conf"); - mod_info_module_cmds(r,mod_info_cfg_srm,modp->cmds,"srm.conf"); - mod_info_module_cmds(r,mod_info_cfg_access,modp->cmds,"access.conf"); - } else { - rputs("<tt> none</tt>\n",r); - } - rputs("<dt><hr>\n",r); - if(r->args) break; - } - } - if(!modp && r->args && strcasecmp(r->args,"server")) rputs("<b>No such module</b>\n",r); - } else { - for(modp = top_module; modp; modp = modp->next) { - rputs(modp->name,r); - if(modp->next) rputs("<br>",r); - } - } - rputs("</dl></body></html>\n",r); - /* Done, turn off timeout, close file and return */ - kill_timeout(r); - return 0; -} - -handler_rec info_handlers[] = { - { "server-info", display_info }, - { NULL } -}; - -module info_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - NULL, /* command table */ - info_handlers, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_log_agent.c b/usr.sbin/httpd/src/mod_log_agent.c deleted file mode 100644 index 234de33ab24..00000000000 --- a/usr.sbin/httpd/src/mod_log_agent.c +++ /dev/null @@ -1,198 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - - -#include "httpd.h" -#include "http_config.h" - -module agent_log_module; - -static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT ); -#ifdef __EMX__ -/* OS/2 dosen't support users and groups */ -static mode_t xfer_mode = ( S_IREAD | S_IWRITE ); -#else -static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); -#endif - -typedef struct { - char *fname; - int agent_fd; -} agent_log_state; - -void *make_agent_log_state (pool *p, server_rec *s) -{ - agent_log_state *cls = - (agent_log_state *)palloc (p, sizeof (agent_log_state)); - - cls->fname = ""; - cls->agent_fd = -1; - - - return (void *)cls; -} - -const char *set_agent_log (cmd_parms *parms, void *dummy, char *arg) -{ - agent_log_state *cls = get_module_config (parms->server->module_config, - &agent_log_module); - - cls->fname = arg; - return NULL; -} - -command_rec agent_log_cmds[] = { -{ "AgentLog", set_agent_log, NULL, RSRC_CONF, TAKE1, - "the filename of the agent log" }, -{ NULL } -}; - -void agent_log_child (void *cmd) -{ - /* Child process code for 'AgentLog "|..."'; - * may want a common framework for this, since I expect it will - * be common for other foo-loggers to want this sort of thing... - */ - - cleanup_for_exec(); - signal (SIGHUP, SIG_IGN); -#ifdef __EMX__ - /* For OS/2 we need to use a '/' */ - execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); -#else - execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); -#endif - perror ("exec"); - fprintf (stderr, "Exec of shell for logging failed!!!\n"); - exit (1); -} - -void open_agent_log (server_rec *s, pool *p) -{ - agent_log_state *cls = get_module_config (s->module_config, - &agent_log_module); - - char *fname = server_root_relative (p, cls->fname); - - if (cls->agent_fd > 0) return; /* virtual log shared w/main server */ - - if (*cls->fname == '|') { - FILE *dummy; - - if (!spawn_child (p, agent_log_child, (void *)(cls->fname+1), - kill_after_timeout, &dummy, NULL)) { - perror ("spawn_child"); - fprintf (stderr, "Couldn't fork child for AgentLog process\n"); - exit (1); - } - - cls->agent_fd = fileno (dummy); - } - else if(*cls->fname != '\0') { - if((cls->agent_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) { - perror("open"); - fprintf(stderr,"httpd: could not open agent log file %s.\n", fname); - exit(1); - } - } -} - -void init_agent_log (server_rec *s, pool *p) -{ - for (; s; s = s->next) open_agent_log (s, p); -} - -int agent_log_transaction(request_rec *orig) -{ - agent_log_state *cls = get_module_config (orig->server->module_config, - &agent_log_module); - - char str[HUGE_STRING_LEN]; - char *agent; - request_rec *r; - - if(cls->agent_fd <0) - return OK; - - for (r = orig; r->next; r = r->next) - continue; - if (*cls->fname == '\0') /* Don't log agent */ - return DECLINED; - - agent = table_get(orig->headers_in, "User-Agent"); - if(agent != NULL) - { - ap_snprintf(str, sizeof(str), "%s\n", agent); - write(cls->agent_fd, str, strlen(str)); - } - - return OK; -} - -module agent_log_module = { - STANDARD_MODULE_STUFF, - init_agent_log, /* initializer */ - NULL, /* create per-dir config */ - NULL, /* merge per-dir config */ - make_agent_log_state, /* server config */ - NULL, /* merge server config */ - agent_log_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - agent_log_transaction, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_log_config.c b/usr.sbin/httpd/src/mod_log_config.c deleted file mode 100644 index d383cd5f6bc..00000000000 --- a/usr.sbin/httpd/src/mod_log_config.c +++ /dev/null @@ -1,787 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * This is module implements the TransferLog directive (same as the - * common log module), and additional directives, LogFormat and CustomLog. - * - * - * Syntax: - * - * TransferLog fn Logs transfers to fn in standard log format, unless - * a custom format is set with LogFormat - * LogFormat format Set a log format from TransferLog files - * CustomLog fn format - * Log to file fn with format given by the format - * argument - * - * CookieLog fn For backwards compatability with old Cookie - * logging module - now deprecated. - * - * There can be any number of TransferLog and CustomLog - * commands. Each request will be logged to _ALL_ the - * named files, in the appropriate format. - * - * If no TransferLog or CustomLog directive appears in a VirtualHost, - * the request will be logged to the log file(s) defined outside - * the virtual host section. If a TransferLog or CustomLog directive - * appears in the VirtualHost section, the log files defined outside - * the VirtualHost will _not_ be used. This makes this module compatable - * with the CLF and config log modules, where the use of TransferLog - * inside the VirtualHost section overrides its use outside. - * - * Examples: - * - * TransferLog logs/access_log - * <VirtualHost> - * LogFormat "... custom format ..." - * TransferLog log/virtual_only - * CustomLog log/virtual_useragents "%t %{user-agent}i" - * </VirtualHost> - * - * This will log using CLF to access_log any requests handled by the - * main server, while any requests to the virtual host will be logged - * with the "... custom format..." to virtual_only _AND_ using - * the custom user-agent log to virtual_useragents. - * - * Note that the NCSA referer and user-agent logs are easily added with - * CustomLog: - * CustomLog logs/referer "%{referer}i -> %U" - * CustomLog logs/agent "%{user-agent}i" - * - * Except: no RefererIgnore functionality - * logs '-' if no Referer or User-Agent instead of nothing - * - * But using this method allows much easier modification of the - * log format, e.g. to log hosts along with UA: - * CustomLog logs/referer "%{referer}i %U %h" - * - * The argument to LogFormat and CustomLog is a string, which can include - * literal characters copied into the log files, and '%' directives as - * follows: - * - * %...b: bytes sent, excluding HTTP headers. - * %...{FOOBAR}e: The contents of the environment variable FOOBAR - * %...f: filename - * %...h: remote host - * %...{Foobar}i: The contents of Foobar: header line(s) in the request - * sent to the client. - * %...l: remote logname (from identd, if supplied) - * %...{Foobar}n: The contents of note "Foobar" from another module. - * %...{Foobar}o: The contents of Foobar: header line(s) in the reply. - * %...p: the port the request was served to - * %...P: the process ID of the child that serviced the request. - * %...r: first line of request - * %...s: status. For requests that got internally redirected, this - * is status of the *original* request --- %...>s for the last. - * %...t: time, in common log format time format - * %...{format}t: The time, in the form given by format, which should - * be in strftime(3) format. - * %...T: the time taken to serve the request, in seconds. - * %...u: remote user (from auth; may be bogus if return status (%s) is 401) - * %...U: the URL path requested. - * %...v: the name of the server (i.e. which virtual host?) - * - * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can - * indicate conditions for inclusion of the item (which will cause it - * to be replaced with '-' if the condition is not met). Note that - * there is no escaping performed on the strings from %r, %...i and - * %...o; some with long memories may remember that I thought this was - * a bad idea, once upon a time, and I'm still not comfortable with - * it, but it is difficult to see how to "do the right thing" with all - * of '%..i', unless we URL-escape everything and break with CLF. - * - * The forms of condition are a list of HTTP status codes, which may - * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs - * User-agent: on 400 errors and 501 errors (Bad Request, Not - * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all - * requests which did *not* return some sort of normal status. - * - * The default LogFormat reproduces CLF; see below. - * - * The way this is supposed to work with virtual hosts is as follows: - * a virtual host can have its own LogFormat, or its own TransferLog. - * If it doesn't have its own LogFormat, it inherits from the main - * server. If it doesn't have its own TransferLog, it writes to the - * same descriptor (meaning the same process for "| ..."). - * - * --- rst */ - -#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b" - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" /* For REMOTE_NAME */ - -module config_log_module; - -static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT ); -#ifdef __EMX__ -/* OS/2 dosen't support users and groups */ -static mode_t xfer_mode = ( S_IREAD | S_IWRITE ); -#else -static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); -#endif - -/* - * multi_log_state is our per-(virtual)-server configuration. We store - * an array of the logs we are going to use, each of type config_log_state. - * If a default log format is given by LogFormat, store in default_format - * (backward compat. with mod_log_config). We also store a pointer to - * the logs specified for the main server for virtual servers, so that - * if this vhost has now logs defined, we can use the main server's - * logs instead. - * - * So, for the main server, config_logs contains a list of the log files - * and server_config_logs in empty. For a vhost, server_config_logs - * points to the same array as config_logs in the main server, and - * config_logs points to the array of logs defined inside this vhost, - * which might be empty. - */ - -typedef struct { - array_header *default_format; - array_header *config_logs; - array_header *server_config_logs; -} multi_log_state; - -/* - * config_log_state holds the status of a single log file. fname cannot - * be NULL. format might be NULL, in which case the default_format from - * the multi_log_state should be used, or if that is NULL as well, use - * the CLF. log_fd is -1 before the log file is opened and set to a valid - * fd after it is opened. - */ - -typedef struct { - char *fname; - array_header *format; - int log_fd; -} config_log_state; - -/* - * Format items... - */ - -typedef char *(*item_key_func)(request_rec *, char *); - -typedef struct { - item_key_func func; - char *arg; - int condition_sense; - int want_orig; - array_header *conditions; -} log_format_item; - -char *format_integer(pool *p, int i) -{ - char dummy[40]; - ap_snprintf (dummy, sizeof(dummy), "%d", i); - return pstrdup (p, dummy); -} - -static char *pfmt(pool *p, int i) -{ - if (i <= 0) return "-"; - else return format_integer (p, i); -} - -char *constant_item (request_rec *dummy, char *stuff) { return stuff; } - -char *log_remote_host (request_rec *r, char *a) -{ return (char *)get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); } - -char *log_remote_logname(request_rec *r, char *a) -{return (char *)get_remote_logname(r);} - -char *log_remote_user (request_rec *r, char *a) { - char *rvalue = r->connection->user; - - if (rvalue == NULL) { - rvalue = "-"; - } else if (strlen (rvalue) == 0) { - rvalue = "\"\""; - } - return rvalue; -} - -char *log_request_line (request_rec *r, char *a) -{ return r->the_request; } - -char *log_request_file (request_rec *r, char *a) -{ return r->filename; } -char *log_request_uri (request_rec *r, char *a) -{ return r->uri; } -char *log_status (request_rec *r, char *a) -{ return pfmt(r->pool, r->status); } - -char *log_bytes_sent (request_rec *r, char *a) -{ - if (!r->sent_bodyct) return "-"; - else - { - long int bs; - char dummy[40]; - bgetopt(r->connection->client, BO_BYTECT, &bs); - ap_snprintf(dummy, sizeof(dummy), "%ld", bs); - return pstrdup(r->pool, dummy); - } -} - -char *log_header_in (request_rec *r, char *a) -{ return table_get (r->headers_in, a); } - -char *log_header_out (request_rec *r, char *a) -{ - char *cp = table_get (r->headers_out, a); - if (!strcasecmp(a, "Content-type") && r->content_type) - cp = r->content_type; - if (cp) return cp; - return table_get (r->err_headers_out, a); -} - -char *log_note (request_rec *r, char *a) -{ return table_get (r->notes, a); } -char *log_env_var (request_rec *r, char *a) -{ return table_get (r->subprocess_env, a); } - -char *log_request_time (request_rec *r, char *a) -{ - int timz; - struct tm *t; - char tstr[MAX_STRING_LEN]; - - t = get_gmtoff(&timz); - - if (a && *a) /* Custom format */ - strftime(tstr, MAX_STRING_LEN, a, t); - else { /* CLF format */ - char sign = (timz < 0 ? '-' : '+'); - - if(timz < 0) timz = -timz; - - strftime(tstr,MAX_STRING_LEN,"[%d/%b/%Y:%H:%M:%S ",t); - ap_snprintf (tstr + strlen(tstr), sizeof(tstr)-strlen(tstr), - "%c%.2d%.2d]", sign, timz/60, timz%60); - } - - return pstrdup (r->pool, tstr); -} - -char *log_request_duration (request_rec *r, char *a) { - char duration[22]; /* Long enough for 2^64 */ - - ap_snprintf(duration, sizeof(duration), "%ld", time(NULL) - r->request_time); - return pstrdup(r->pool, duration); -} - -char *log_virtual_host (request_rec *r, char *a) { - return pstrdup(r->pool, r->server->server_hostname); -} - -char *log_server_port (request_rec *r, char *a) { - char portnum[22]; - - ap_snprintf(portnum, sizeof(portnum), "%u", r->server->port); - return pstrdup(r->pool, portnum); -} - -char *log_child_pid (request_rec *r, char *a) { - char pidnum[22]; - ap_snprintf(pidnum, sizeof(pidnum), "%ld", (long)getpid()); - return pstrdup(r->pool, pidnum); -} -/***************************************************************** - * - * Parsing the log format string - */ - -struct log_item_list { - char ch; - item_key_func func; - int want_orig_default; -} log_item_keys[] = { - { 'h', log_remote_host, 0 }, - { 'l', log_remote_logname, 0 }, - { 'u', log_remote_user, 0 }, - { 't', log_request_time, 0 }, - { 'T', log_request_duration, 1 }, - { 'r', log_request_line, 1 }, - { 'f', log_request_file, 0 }, - { 'U', log_request_uri, 1 }, - { 's', log_status, 1 }, - { 'b', log_bytes_sent, 0 }, - { 'i', log_header_in, 0 }, - { 'o', log_header_out, 0 }, - { 'n', log_note, 0 }, - { 'e', log_env_var, 0 }, - { 'v', log_virtual_host, 0 }, - { 'p', log_server_port, 0 }, - { 'P', log_child_pid, 0 }, - { '\0' } -}; - -struct log_item_list *find_log_func (char k) -{ - int i; - - for (i = 0; log_item_keys[i].ch; ++i) - if (k == log_item_keys[i].ch) - return &log_item_keys[i]; - - return NULL; -} - -char *log_format_substring (pool *p, const char *start, const char *end) -{ - char *res = palloc (p, end - start + 1); - strncpy (res, start, end - start); - res[end - start] = '\0'; - return res; -} - -char *parse_log_misc_string (pool *p, log_format_item *it, const char **sa) -{ - const char *s = *sa; - - it->func = constant_item; - it->conditions = NULL; - - while (*s && *s != '%') ++s; - it->arg = log_format_substring (p, *sa, s); - *sa = s; - - return NULL; -} - -char *parse_log_item (pool *p, log_format_item *it, const char **sa) -{ - const char *s = *sa; - if (*s != '%') return parse_log_misc_string (p, it, sa); - - ++s; - it->condition_sense = 0; - it->conditions = NULL; - it->want_orig = -1; - it->arg = ""; /* For safety's sake... */ - - while (*s) { - int i; - struct log_item_list *l; - - switch (*s) { - case '!': - ++s; - it->condition_sense = !it->condition_sense; - break; - - case '<': - ++s; - it->want_orig = 1; - break; - - case '>': - ++s; - it->want_orig = 0; - break; - - case ',': - ++s; - break; - - case '{': - ++s; - it->arg = getword (p, &s, '}'); - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - i = *s - '0'; - while (isdigit (*++s)) i = i * 10 + (*s) - '0'; - if (!it->conditions) - it->conditions = make_array (p, 4, sizeof(int)); - *(int *)push_array(it->conditions) = i; - break; - - default: - l = find_log_func (*s++); - if (!l) { - char dummy[] = { '\0', '\0'}; - dummy[0] = s[-1]; - return pstrcat (p, "Unrecognized LogFormat directive %", - dummy, NULL); - } - it->func = l->func; - if (it->want_orig == -1) it->want_orig = l->want_orig_default; - *sa = s; - return NULL; - } - } - - return "Ran off end of LogFormat parsing args to some directive"; -} - -array_header *parse_log_string (pool *p, const char *s, const char **err) -{ - array_header *a = make_array (p, 30, sizeof (log_format_item)); - char *res; - - while (*s) { - if ((res = parse_log_item (p, (log_format_item *)push_array(a), &s))) { - *err = res; - return NULL; - } - } - - s = "\n"; - parse_log_item (p, (log_format_item *)push_array(a), &s); - return a; -} - -/***************************************************************** - * - * Actually logging. - */ - -char *process_item(request_rec *r, request_rec *orig, log_format_item *item) -{ - char *cp; - - /* First, see if we need to process this thing at all... */ - - if (item->conditions && item->conditions->nelts != 0) { - int i; - int *conds = (int *)item->conditions->elts; - int in_list = 0; - - for (i = 0; i < item->conditions->nelts; ++i) - if (r->status == conds[i]) { - in_list = 1; - break; - } - - if ((item->condition_sense && in_list) - || (!item->condition_sense && !in_list)) - { - return "-"; - } - } - - /* We do. Do it... */ - - cp = (*item->func)(item->want_orig ? orig : r, item->arg); - return cp ? cp : "-"; -} - -int config_log_transaction(request_rec *r, config_log_state *cls, - array_header *default_format) { - array_header *strsa; - log_format_item *items; - char *str, **strs, *s; - request_rec *orig; - int i; - int len = 0; - array_header *format; - - format = cls->format ? cls->format : default_format; - - strsa= make_array(r->pool, format->nelts,sizeof(char*)); - items = (log_format_item *)format->elts; - - orig = r; - while (orig->prev) orig = orig->prev; - while (r->next) r = r->next; - - for (i = 0; i < format->nelts; ++i) - *((char**)push_array (strsa)) = process_item (r, orig, &items[i]); - - strs = (char **)strsa->elts; - - for (i = 0; i < format->nelts; ++i) - len += strlen (strs[i]); - - str = palloc (r->pool, len + 1); - - for (i = 0, s = str; i < format->nelts; ++i) { - strcpy (s, strs[i]); - s += strlen (strs[i]); - } - - write(cls->log_fd, str, strlen(str)); - - return OK; -} - -int multi_log_transaction(request_rec *r) -{ - multi_log_state *mls = get_module_config (r->server->module_config, - &config_log_module); - config_log_state *clsarray; - int i; - - if (mls->config_logs->nelts) { - clsarray = (config_log_state *)mls->config_logs->elts; - for (i = 0; i < mls->config_logs->nelts; ++i) { - config_log_state *cls = &clsarray[i]; - - config_log_transaction(r, cls, mls->default_format); - } - } - else if (mls->server_config_logs) { - clsarray = (config_log_state *)mls->server_config_logs->elts; - for (i = 0; i < mls->server_config_logs->nelts; ++i) { - config_log_state *cls = &clsarray[i]; - - config_log_transaction(r, cls, mls->default_format); - } - } - - return OK; -} - -/***************************************************************** - * - * Module glue... - */ - -void *make_config_log_state (pool *p, server_rec *s) -{ - multi_log_state *mls = - (multi_log_state *)palloc(p, sizeof (multi_log_state)); - - mls->config_logs = - make_array(p, 5, sizeof (config_log_state)); - mls->default_format = NULL; - mls->server_config_logs = NULL; - - return mls; -} - -/* - * Use the merger to simply add a pointer from the vhost log state - * to the log of logs specified for the non-vhost configuration - */ - -void *merge_config_log_state (pool *p, void *basev, void *addv) -{ - multi_log_state *base = (multi_log_state *)basev; - multi_log_state *add = (multi_log_state *)addv; - - add->server_config_logs = base->config_logs; - if (!add->default_format) - add->default_format = base->default_format; - - return add; -} - -const char *log_format (cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err_string = NULL; - multi_log_state *mls = get_module_config (cmd->server->module_config, - &config_log_module); - - mls->default_format = parse_log_string (cmd->pool, arg, &err_string); - return err_string; -} - -const char *add_custom_log(cmd_parms *cmd, void *dummy, char *fn, char *fmt) -{ - const char *err_string = NULL; - multi_log_state *mls = get_module_config (cmd->server->module_config, - &config_log_module); - config_log_state *cls; - - cls = (config_log_state*)push_array(mls->config_logs); - cls->fname = fn; - if (!fmt) - cls->format = NULL; - else - cls->format = parse_log_string (cmd->pool, fmt, &err_string); - cls->log_fd = -1; - - return err_string; -} - -const char *set_transfer_log(cmd_parms *cmd, void *dummy, char *fn) -{ - return add_custom_log(cmd, dummy, fn, NULL); -} - -const char *set_cookie_log(cmd_parms *cmd, void *dummy, char *fn) -{ - return add_custom_log(cmd, dummy, fn, "%{Cookie}n \"%r\" %t"); -} - -command_rec config_log_cmds[] = { -{ "CustomLog", add_custom_log, NULL, RSRC_CONF, TAKE2, - "a file name and a custom log format string" }, -{ "TransferLog", set_transfer_log, NULL, RSRC_CONF, TAKE1, - "the filename of the access log" }, -{ "LogFormat", log_format, NULL, RSRC_CONF, TAKE1, - "a log format string (see docs)" }, -{ "CookieLog", set_cookie_log, NULL, RSRC_CONF, TAKE1, - "the filename of the cookie log" }, -{ NULL } -}; - -void config_log_child (void *cmd) -{ - /* Child process code for 'TransferLog "|..."'; - * may want a common framework for this, since I expect it will - * be common for other foo-loggers to want this sort of thing... - */ - - cleanup_for_exec(); - signal (SIGHUP, SIG_IGN); -#ifdef __EMX__ - /* For OS/2 we need to use a '/' */ - execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); -#else - execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); -#endif - perror ("exec"); - fprintf (stderr, "Exec of shell for logging failed!!!\n"); - exit (1); -} - -config_log_state *open_config_log (server_rec *s, pool *p, - config_log_state *cls, - array_header *default_format) { - if (cls->log_fd > 0) return cls; /* virtual config shared w/main server */ - - if (*cls->fname == '|') { - FILE *dummy; - - if (!spawn_child (p, config_log_child, (void *)(cls->fname+1), - kill_after_timeout, &dummy, NULL)) { - perror ("spawn_child"); - fprintf (stderr, "Couldn't fork child for TransferLog process\n"); - exit (1); - } - - cls->log_fd = fileno (dummy); - } - else { - char *fname = server_root_relative (p, cls->fname); - if((cls->log_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) { - perror("open"); - fprintf (stderr, - "httpd: could not open transfer log file %s.\n", fname); - exit(1); - } - } - - return cls; -} - -config_log_state *open_multi_logs (server_rec *s, pool *p) -{ - int i; - multi_log_state *mls = get_module_config(s->module_config, - &config_log_module); - config_log_state *clsarray; - const char *dummy; - - if (!mls->default_format) - mls->default_format = parse_log_string (p, DEFAULT_LOG_FORMAT, &dummy); - - if (mls->config_logs->nelts) { - clsarray = (config_log_state *)mls->config_logs->elts; - for (i = 0; i < mls->config_logs->nelts; ++i) { - config_log_state *cls = &clsarray[i]; - - cls = open_config_log(s, p, cls, mls->default_format); - } - } - else if (mls->server_config_logs) { - clsarray = (config_log_state *)mls->server_config_logs->elts; - for (i = 0; i < mls->server_config_logs->nelts; ++i) { - config_log_state *cls = &clsarray[i]; - - cls = open_config_log(s, p, cls, mls->default_format); - } - } - - return NULL; -} - -void init_config_log (server_rec *s, pool *p) -{ - /* First, do "physical" server, which gets default log fd and format - * for the virtual servers, if they don't override... - */ - - open_multi_logs (s, p); - - /* Then, virtual servers */ - - for (s = s->next; s; s = s->next) open_multi_logs (s, p); -} - -module config_log_module = { - STANDARD_MODULE_STUFF, - init_config_log, /* initializer */ - NULL, /* create per-dir config */ - NULL, /* merge per-dir config */ - make_config_log_state, /* server config */ - merge_config_log_state, /* merge server config */ - config_log_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - multi_log_transaction, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_log_referer.c b/usr.sbin/httpd/src/mod_log_referer.c deleted file mode 100644 index e494298944c..00000000000 --- a/usr.sbin/httpd/src/mod_log_referer.c +++ /dev/null @@ -1,235 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - - -#include "httpd.h" -#include "http_config.h" - -module referer_log_module; - -static int xfer_flags = ( O_WRONLY | O_APPEND | O_CREAT ); - -#ifdef __EMX__ -/* OS/2 lacks support for users and groups */ -static mode_t xfer_mode = ( S_IREAD | S_IWRITE ); -#else -static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); -#endif - -typedef struct { - char *fname; - int referer_fd; - array_header *referer_ignore_list; -} referer_log_state; - -void *make_referer_log_state (pool *p, server_rec *s) -{ - referer_log_state *cls = - (referer_log_state *)palloc (p, sizeof (referer_log_state)); - - cls->fname = ""; - cls->referer_fd = -1; - cls->referer_ignore_list = make_array(p, 1, sizeof(char *)); - return (void *)cls; -} - -const char *set_referer_log (cmd_parms *parms, void *dummy, char *arg) -{ - referer_log_state *cls = get_module_config (parms->server->module_config, - &referer_log_module); - - cls->fname = arg; - return NULL; -} - -const char *add_referer_ignore (cmd_parms *parms, void *dummy, char *arg) -{ - char **addme; - referer_log_state *cls = get_module_config (parms->server->module_config, - &referer_log_module); - - addme = push_array(cls->referer_ignore_list); - *addme = pstrdup(cls->referer_ignore_list->pool, arg); - return NULL; -} - -command_rec referer_log_cmds[] = { -{ "RefererLog", set_referer_log, NULL, RSRC_CONF, TAKE1, - "the filename of the referer log" }, -{ "RefererIgnore", add_referer_ignore, NULL, RSRC_CONF, ITERATE, - "referer hostnames to ignore" }, -{ NULL } -}; - -void referer_log_child (void *cmd) -{ - /* Child process code for 'RefererLog "|..."'; - * may want a common framework for this, since I expect it will - * be common for other foo-loggers to want this sort of thing... - */ - - cleanup_for_exec(); - signal (SIGHUP, SIG_IGN); -#ifdef __EMX__ - /* For OS/2 we need to use a '/' */ - execl (SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); -#else - execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); -#endif - perror ("execl"); - fprintf (stderr, "Exec of shell for logging failed!!!\n"); - exit (1); -} - -void open_referer_log (server_rec *s, pool *p) -{ - referer_log_state *cls = get_module_config (s->module_config, - &referer_log_module); - - char *fname = server_root_relative (p, cls->fname); - - if (cls->referer_fd > 0) return; /* virtual log shared w/main server */ - - if (*cls->fname == '|') { - FILE *dummy; - - if (!spawn_child (p, referer_log_child, (void *)(cls->fname+1), - kill_after_timeout, &dummy, NULL)) { - perror ("spawn_child"); - fprintf (stderr, "Couldn't fork child for RefererLog process\n"); - exit (1); - } - - cls->referer_fd = fileno (dummy); - } - else if(*cls->fname != '\0') { - if((cls->referer_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) { - perror("open"); - fprintf(stderr,"httpd: could not open referer log file %s.\n", fname); - exit(1); - } - } -} - -void init_referer_log (server_rec *s, pool *p) -{ - for (; s; s = s->next) open_referer_log (s, p); -} - -int referer_log_transaction(request_rec *orig) -{ - char **ptrptr, **ptrptr2; - referer_log_state *cls = get_module_config (orig->server->module_config, - &referer_log_module); - - char *str; - char *referer; - request_rec *r; - - if(cls->referer_fd <0) - return OK; - - for (r = orig; r->next; r = r->next) - continue; - if (*cls->fname == '\0') /* Don't log referer */ - return DECLINED; - - referer = table_get(orig->headers_in, "Referer"); - if(referer != NULL) - { - - - /* The following is an upsetting mess of pointers, I'm sorry - Anyone with the motiviation and/or the time should feel free - to make this cleaner... */ - - ptrptr2 = (char **) (cls->referer_ignore_list->elts + - (cls->referer_ignore_list->nelts * - cls->referer_ignore_list->elt_size)); - - /* Go through each element of the ignore list and compare it to the - referer_host. If we get a match, return without logging */ - - for(ptrptr = (char **) cls->referer_ignore_list->elts; - ptrptr < ptrptr2; - ptrptr = (char **)((char *)ptrptr + cls->referer_ignore_list->elt_size)) - { - if(strstr(referer, *ptrptr)) - return OK; - } - - - str = pstrcat(orig->pool, referer, " -> ", r->uri, "\n", NULL); - write(cls->referer_fd, str, strlen(str)); - } - - return OK; -} - -module referer_log_module = { - STANDARD_MODULE_STUFF, - init_referer_log, /* initializer */ - NULL, /* create per-dir config */ - NULL, /* merge per-dir config */ - make_referer_log_state, /* server config */ - NULL, /* merge server config */ - referer_log_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - referer_log_transaction, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_mime.c b/usr.sbin/httpd/src/mod_mime.c deleted file mode 100644 index dc84975e1ae..00000000000 --- a/usr.sbin/httpd/src/mod_mime.c +++ /dev/null @@ -1,324 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * http_mime.c: Sends/gets MIME headers for requests - * - * Rob McCool - * - */ - -#define MIME_PRIVATE - -#include "httpd.h" -#include "http_config.h" - -typedef struct { - table *forced_types; /* Additional AddTyped stuff */ - table *encoding_types; /* Added with AddEncoding... */ - table *language_types; /* Added with AddLanguage... */ - table *handlers; /* Added with AddHandler... */ - - char *type; /* Type forced with ForceType */ - char *handler; /* Handler forced with SetHandler */ -} mime_dir_config; - -module mime_module; - -void *create_mime_dir_config (pool *p, char *dummy) -{ - mime_dir_config *new = - (mime_dir_config *) palloc (p, sizeof(mime_dir_config)); - - new->forced_types = make_table (p, 4); - new->encoding_types = make_table (p, 4); - new->language_types = make_table (p, 4); - new->handlers = make_table (p, 4); - - new->type = NULL; - new->handler = NULL; - - return new; -} - -void *merge_mime_dir_configs (pool *p, void *basev, void *addv) -{ - mime_dir_config *base = (mime_dir_config *)basev; - mime_dir_config *add = (mime_dir_config *)addv; - mime_dir_config *new = - (mime_dir_config *)palloc (p, sizeof(mime_dir_config)); - - new->forced_types = overlay_tables (p, add->forced_types, - base->forced_types); - new->encoding_types = overlay_tables (p, add->encoding_types, - base->encoding_types); - new->language_types = overlay_tables (p, add->language_types, - base->language_types); - new->handlers = overlay_tables (p, add->handlers, - base->handlers); - - new->type = add->type ? add->type : base->type; - new->handler = add->handler ? add->handler : base->handler; - - return new; -} - -const char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext) -{ - if (*ext == '.') ++ext; - table_set (m->forced_types, ext, ct); - return NULL; -} - -const char *add_encoding(cmd_parms *cmd, mime_dir_config *m, char *enc, - char *ext) -{ - if (*ext == '.') ++ext; - table_set (m->encoding_types, ext, enc); - return NULL; -} - -const char *add_language(cmd_parms *cmd, mime_dir_config *m, char *lang, - char *ext) -{ - if (*ext == '.') ++ext; - table_set (m->language_types, ext, lang); - return NULL; -} - -const char *add_handler(cmd_parms *cmd, mime_dir_config *m, char *hdlr, - char *ext) -{ - if (*ext == '.') ++ext; - table_set (m->handlers, ext, hdlr); - return NULL; -} - -/* The sole bit of server configuration that the MIME module has is - * the name of its config file, so... - */ - -const char *set_types_config (cmd_parms *cmd, void *dummy, char *arg) -{ - set_module_config (cmd->server->module_config, &mime_module, - pstrdup (cmd->pool, arg)); - return NULL; -} - -command_rec mime_cmds[] = { -{ "AddType", add_type, NULL, OR_FILEINFO, ITERATE2, - "a mime type followed by one or more file extensions" }, -{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, ITERATE2, - "an encoding (e.g., gzip), followed by one or more file extensions" }, -{ "AddLanguage", add_language, NULL, OR_FILEINFO, ITERATE2, - "a language (e.g., fr), followed by one or more file extensions" }, -{ "AddHandler", add_handler, NULL, OR_FILEINFO, ITERATE2, - "a handler name followed by one or more file extensions" }, -{ "ForceType", set_string_slot, (void*)XtOffsetOf(mime_dir_config, type), - OR_FILEINFO, TAKE1, "a media type" }, -{ "SetHandler", set_string_slot, (void*)XtOffsetOf(mime_dir_config, handler), - OR_FILEINFO, TAKE1, "a handler name" }, -{ "TypesConfig", set_types_config, NULL, RSRC_CONF, TAKE1, - "the MIME types config file" }, -{ NULL } -}; - -/* Hash table --- only one of these per daemon; virtual hosts can - * get private versions through AddType... - */ - -#define MIME_HASHSIZE 27 -#define hash(i) (isalpha(i) ? (tolower(i)) - 'a' : 26) - -static table *hash_buckets[MIME_HASHSIZE]; - -void init_mime (server_rec *s, pool *p) -{ - FILE *f; - char l[MAX_STRING_LEN]; - int x; - char *types_confname = get_module_config (s->module_config, &mime_module); - - if (!types_confname) types_confname = TYPES_CONFIG_FILE; - - types_confname = server_root_relative (p, types_confname); - - if(!(f = fopen(types_confname,"r"))) { - perror("fopen"); - fprintf(stderr,"httpd: could not open mime types file %s\n", - types_confname); - exit(1); - } - - for(x=0;x<27;x++) - hash_buckets[x] = make_table (p, 10); - - while(!(cfg_getline(l,MAX_STRING_LEN,f))) { - const char *ll = l, *ct; - - if(l[0] == '#') continue; - ct = getword_conf (p, &ll); - - while(ll[0]) { - char *ext = getword_conf (p, &ll); - str_tolower (ext); /* ??? */ - table_set (hash_buckets[hash(ext[0])], ext, ct); - } - } - fclose(f); -} - -int find_ct(request_rec *r) -{ - const char *fn = strrchr(r->filename, '/'); - mime_dir_config *conf = - (mime_dir_config *)get_module_config(r->per_dir_config, &mime_module); - char *ext, *type, *orighandler = r->handler; - - if (S_ISDIR(r->finfo.st_mode)) { - r->content_type = DIR_MAGIC_TYPE; - return OK; - } - - /* TM -- FIXME - * - * if r->filename does not contain a '/', the following passes a null - * pointer to getword, causing a SEGV .. - */ - - if(fn == NULL) fn = r->filename; - - /* Parse filename extensions, which can be in any order */ - while ((ext = getword(r->pool, &fn, '.')) && *ext) { - int found = 0; - - /* Check for Content-Type */ - if ((type = table_get (conf->forced_types, ext)) - || (type = table_get (hash_buckets[hash(*ext)], ext))) { - r->content_type = type; - found = 1; - } - - /* Check for Content-Language */ - if ((type = table_get (conf->language_types, ext))) { - char **new; - - r->content_language = type; /* back compat. only */ - if (!r->content_languages) - r->content_languages = make_array (r->pool, 2, sizeof(char*)); - new = (char **)push_array (r->content_languages); - *new = type; - found = 1; - } - - /* Check for Content-Encoding */ - if ((type = table_get (conf->encoding_types, ext))) { - if (!r->content_encoding) - r->content_encoding = type; - else - r->content_encoding = pstrcat(r->pool, r->content_encoding, - ", ", type, NULL); - found = 1; - } - - /* Check for a special handler, but not for proxy request */ - if ((type = table_get (conf->handlers, ext)) && !r->proxyreq) { - r->handler = type; - found = 1; - } - - /* This is to deal with cases such as foo.gif.bak, which we want - * to not have a type. So if we find an unknown extension, we - * zap the type/language/encoding and reset the handler - */ - - if (!found) { - r->content_type = NULL; - r->content_language = NULL; - r->content_languages = NULL; - r->content_encoding = NULL; - r->handler = orighandler; - } - - } - - /* Check for overrides with ForceType/SetHandler */ - - if (conf->type && strcmp(conf->type, "none")) - r->content_type = pstrdup(r->pool, conf->type); - if (conf->handler && strcmp(conf->handler, "none")) - r->handler = pstrdup(r->pool, conf->handler); - - if (!r->content_type) return DECLINED; - - return OK; -} - - -module mime_module = { - STANDARD_MODULE_STUFF, - init_mime, /* initializer */ - create_mime_dir_config, - merge_mime_dir_configs, - NULL, /* server config */ - NULL, /* merge server config */ - mime_cmds, - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - find_ct, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_negotiation.c b/usr.sbin/httpd/src/mod_negotiation.c deleted file mode 100644 index 84e15f0ec4e..00000000000 --- a/usr.sbin/httpd/src/mod_negotiation.c +++ /dev/null @@ -1,2052 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_negotiation.c: keeps track of MIME types the client is willing to - * accept, and contains code to handle type arbitration. - * - * rst - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_log.h" -#include "util_script.h" - -/* define TCN_02 to allow for Holtman I-D transparent negotiation. - * This file currently implements the draft-02, except for - * anything to do with features and cache-control (max-age etc) - * - * Since the draft is just that, and we don't yet implement - * everything, regard the transparent negotiation stuff as experimental. - */ -/*#define TCN_02*/ - -/* Commands --- configuring document caching on a per (virtual?) - * server basis... - */ - -typedef struct { - array_header *language_priority; -} neg_dir_config; - -module negotiation_module; - -char *merge_string_array (pool *p, array_header *arr, char *sep) -{ - int i; - char *t = ""; - - for (i = 0; i < arr->nelts; i++) { - t = pstrcat(p, t, i ? sep : "", ((char**)arr->elts)[i], NULL); - } - return t; -} - -void *create_neg_dir_config (pool *p, char *dummy) -{ - neg_dir_config *new = - (neg_dir_config *) palloc (p, sizeof (neg_dir_config)); - - new->language_priority = make_array (p, 4, sizeof (char *)); - return new; -} - -void *merge_neg_dir_configs (pool *p, void *basev, void *addv) -{ - neg_dir_config *base = (neg_dir_config *)basev; - neg_dir_config *add = (neg_dir_config *)addv; - neg_dir_config *new = - (neg_dir_config *) palloc (p, sizeof (neg_dir_config)); - - /* give priority to the config in the subdirectory */ - new->language_priority = append_arrays (p, add->language_priority, - base->language_priority); - return new; -} - -const char *set_language_priority (cmd_parms *cmd, void *n, char *lang) -{ - array_header *arr = ((neg_dir_config *) n)->language_priority; - char **langp = (char **) push_array (arr); - - *langp = pstrdup (arr->pool, lang); - return NULL; -} - -const char *cache_negotiated_docs (cmd_parms *cmd, void *dummy, char *dummy2) -{ - void *server_conf = cmd->server->module_config; - - set_module_config (server_conf, &negotiation_module, "Cache"); - return NULL; -} - -int do_cache_negotiated_docs (server_rec *s) -{ - return (get_module_config (s->module_config, &negotiation_module) != NULL); -} - -command_rec negotiation_cmds[] = { -{ "CacheNegotiatedDocs", cache_negotiated_docs, NULL, RSRC_CONF, RAW_ARGS, - NULL }, -{ "LanguagePriority", set_language_priority, NULL, OR_FILEINFO, ITERATE, - NULL }, -{ NULL } -}; - -/* Record of available info on a media type specified by the client - * (we also use 'em for encodings and languages) - */ - -typedef struct accept_rec { - char *type_name; - float quality; - float max_bytes; - float level; - char *charset; /* for content-type only */ -} accept_rec; - -/* Record of available info on a particular variant - * - * Note that a few of these fields are updated by the actual negotiation - * code. These are: - * - * level_matched --- initialized to zero. Set to the value of level - * if the client actually accepts this media type at that - * level (and *not* if it got in on a wildcard). See level_cmp - * below. - */ - -typedef struct var_rec { - request_rec *sub_req; /* May be NULL (is, for map files) */ - char *type_name; - char *file_name; - char *content_encoding; - array_header *content_languages; /* list of languages for this variant */ - char *content_charset; - char *description; - - /* The next five items give the quality values for the dimensions - * of negotiation for this variant. They are obtained from the - * appropriate header lines, except for accept_type_quality, which - * is obtained from the variant itself (the 'qs' parameter value - * from the variant's mime-type). Apart from type_quality, - * these values are set when we find the quality for each variant - * (see best_match()). type_quality is set from the 'qs' parameter - * of the variant description or mime type: see set_mime_fields(). - */ - float lang_quality; /* quality of this variant's language */ - int encoding_quality; /* ditto encoding (1 or 0 only) */ - float charset_quality; /* ditto charset */ - float accept_type_quality; /* ditto media type */ - float type_quality; /* quality of source for this type */ - - /* Now some special values */ - float level; /* Auxiliary to content-type... */ - float bytes; /* content length, if known */ - int lang_index; /* pre HTTP/1.1 language priority stuff */ - int is_pseudo_html; /* text/html, *or* the INCLUDES_MAGIC_TYPEs */ - - /* Above are all written-once properties of the variant. The - * three fields below are changed during negotiation: - */ - - float level_matched; - int mime_stars; - int definite; -} var_rec; - -/* Something to carry around the state of negotiation (and to keep - * all of this thread-safe)... - */ - -typedef struct { - pool *pool; - request_rec *r; - char *dir_name; - int accept_q; /* 1 if an Accept item has a q= param */ - float default_lang_quality; /* fiddle lang q for variants with no lang */ - - - array_header *accepts; /* accept_recs */ - int have_accept_header; /* 1 if Accept-Header present */ - array_header *accept_encodings; /* accept_recs */ - array_header *accept_charsets; /* accept_recs */ - array_header *accept_langs; /* accept_recs */ - array_header *avail_vars; /* available variants */ - - int ua_can_negotiate; /* 1 if ua can do transparent negotiate */ - int use_transparent_neg; /* 1 if we are using transparent neg */ - int short_accept_headers; /* 1 if ua does trans neg & sent short accpt */ -} negotiation_state; - -/* A few functions to manipulate var_recs. - * Cleaning out the fields... - */ - -void clean_var_rec (var_rec *mime_info) -{ - mime_info->sub_req = NULL; - mime_info->type_name = ""; - mime_info->file_name = ""; - mime_info->content_encoding = ""; - mime_info->content_languages = NULL; - mime_info->content_charset = ""; - mime_info->description = ""; - - mime_info->is_pseudo_html = 0; - mime_info->level = 0.0; - mime_info->level_matched = 0.0; - mime_info->bytes = 0; - mime_info->lang_index = -1; - mime_info->mime_stars = 0; - mime_info->definite = 1; - - mime_info->charset_quality = 1.0; - mime_info->type_quality = 0.0; - mime_info->encoding_quality = 1; - mime_info->lang_quality = 1.0; - mime_info->accept_type_quality = 1.0; -} - -/* Initializing the relevant fields of a variant record from the - * accept_info read out of its content-type, one way or another. - */ - -void set_mime_fields (var_rec *var, accept_rec *mime_info) -{ - var->type_name = mime_info->type_name; - var->type_quality = mime_info->quality; - var->level = mime_info->level; - var->content_charset = mime_info->charset; - - var->is_pseudo_html = - (!strcmp (var->type_name, "text/html") - || !strcmp (var->type_name, INCLUDES_MAGIC_TYPE) - || !strcmp (var->type_name, INCLUDES_MAGIC_TYPE3)); -} - -/***************************************************************** - * - * Parsing (lists of) media types and their parameters, as seen in - * HTTPD header lines and elsewhere. - */ - -/* - * Get a single mime type entry --- one media type and parameters; - * enter the values we recognize into the argument accept_rec - */ - -char *get_entry (pool *p, accept_rec *result, char *accept_line) -{ - result->quality = 1.0; - result->max_bytes = 0.0; - result->level = 0.0; - result->charset = ""; - - /* Note that this handles what I gather is the "old format", - * - * Accept: text/html text/plain moo/zot - * - * without any compatibility kludges --- if the token after the - * MIME type begins with a semicolon, we know we're looking at parms, - * otherwise, we know we aren't. (So why all the pissing and moaning - * in the CERN server code? I must be missing something). - */ - - result->type_name = get_token (p, &accept_line, 0); - str_tolower (result->type_name); /* You want case-insensitive, - * you'll *get* case-insensitive. - */ - - - /* KLUDGE!!! Default HTML to level 2.0 unless the browser - * *explicitly* says something else. - */ - - if (!strcmp (result->type_name, "text/html") - && result->level == 0.0) - result->level = 2.0; - else if (!strcmp (result->type_name, INCLUDES_MAGIC_TYPE)) - result->level = 2.0; - else if (!strcmp (result->type_name, INCLUDES_MAGIC_TYPE3)) - result->level = 3.0; - - while (*accept_line == ';') { - /* Parameters ... */ - - char *parm; - char *cp; - char *end; - - ++accept_line; - parm = get_token (p, &accept_line, 1); - - /* Look for 'var = value' --- and make sure the var is in lcase. */ - - for (cp = parm; *cp && !isspace(*cp) && *cp != '='; ++cp) - *cp = tolower(*cp); - - if (!*cp) continue; /* No '='; just ignore it. */ - - *cp++ = '\0'; /* Delimit var */ - while (*cp && (isspace(*cp) || *cp == '=')) - ++cp; - - if (*cp == '"') { - ++cp; - for (end = cp; *end && - *end != '\n' && *end != '\r' && *end != '\"'; - end++) - ; - } - else { - for (end = cp; *end && !isspace(*end); end++) - ; - } - if (*end) - *end = '\0'; /* strip ending quote or return */ - str_tolower(cp); - - if (parm[0] == 'q' - && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0'))) - result->quality = atof(cp); - else if (parm[0] == 'm' && parm[1] == 'x' && - parm[2] == 'b' && parm[3] == '\0') - result->max_bytes = atof(cp); - else if (parm[0] == 'l' && !strcmp (&parm[1], "evel")) - result->level = atof(cp); - else if (!strcmp(parm, "charset")) - result->charset = cp; - } - - if (*accept_line == ',') ++accept_line; - - return accept_line; -} - -/***************************************************************** - * - * Dealing with header lines ... - * - * Accept, Accept-Charset, Accept-Language and Accept-Encoding - * are handled by do_header_line() - they all have the same - * basic structure of a list of items of the format - * name; q=N; charset=TEXT - * - * where q is only valid in Accept, Accept-Charset and Accept-Languages, - * and charset is only valid in Accept. - */ - -array_header *do_header_line (pool *p, char *accept_line) -{ - array_header *accept_recs = make_array (p, 40, sizeof (accept_rec)); - - if (!accept_line) return accept_recs; - - while (*accept_line) { - accept_rec *new = (accept_rec *)push_array (accept_recs); - accept_line = get_entry (p, new, accept_line); - } - - return accept_recs; -} - -/* Given the text of the Content-Languages: line from the var map file, - * return an array containing the languages of this variant - */ - -array_header *do_languages_line (pool *p, char **lang_line) -{ - array_header *lang_recs = make_array (p, 2, sizeof (char *)); - - if (!lang_line) return lang_recs; - - while (**lang_line) { - char **new = (char **)push_array (lang_recs); - *new = get_token (p, lang_line, 0); - str_tolower (*new); - if (**lang_line == ',' || **lang_line == ';') - ++(*lang_line); - } - - return lang_recs; -} - -/***************************************************************** - * - * Handling header lines from clients... - */ - -negotiation_state *parse_accept_headers (request_rec *r) -{ - negotiation_state *new = - (negotiation_state *)pcalloc (r->pool, sizeof (negotiation_state)); - accept_rec *elts; - table *hdrs = r->headers_in; - int i; - char *hdr; - - new->pool = r->pool; - new->r = r; - new->dir_name = make_dirstr(r->pool, r->filename, count_dirs(r->filename)); - - new->accepts = do_header_line (r->pool, table_get (hdrs, "Accept")); - - hdr = table_get (hdrs, "Accept-encoding"); - if (hdr) - new->have_accept_header = 1; - new->accept_encodings = do_header_line (r->pool, hdr); - - new->accept_langs = - do_header_line (r->pool, table_get (hdrs, "Accept-language")); - new->accept_charsets = - do_header_line (r->pool, table_get (hdrs, "Accept-charset")); - new->avail_vars = make_array (r->pool, 40, sizeof (var_rec)); - -#ifdef TCN_02 - if (table_get(r->headers_in, "Negotiate")) { - /* Negotiate: header tells us UA does transparent negotiation - * We have to decide whether we want to ... for now, yes, - * we do */ - - new->ua_can_negotiate = 1; - if (r->method_number == M_GET) - new->use_transparent_neg = 1; /* should be configurable */ - - /* Check for 'Short Accept', ie either no Accept: header, - * or just "Accept: * / *" */ - if (new->accepts->nelts == 0 || - (new->accepts->nelts == 1 && - (!strcmp(((accept_rec *)new->accepts->elts)[0].type_name, - "*/*")))) { - /* Using short accept header */ - new->short_accept_headers = 1; - } - } -#endif - - if (!new->use_transparent_neg) { - /* Now we check for q-values. If they're all 1.0, we assume the - * client is "broken", and we are allowed to fiddle with the - * values later. Otherwise, we leave them alone. - */ - - elts = (accept_rec *)new->accepts->elts; - - for (i = 0; i < new->accepts->nelts; ++i) - if (elts[i].quality < 1.0) new->accept_q = 1; - } - else new->accept_q = 1; - - return new; -} - -/* Sometimes clients will give us no Accept info at all; this routine sets - * up the standard default for that case, and also arranges for us to be - * willing to run a CGI script if we find one. (In fact, we set up to - * dramatically prefer CGI scripts in cases where that's appropriate, - * e.g., POST). - */ - -void maybe_add_default_encodings(negotiation_state *neg, int prefer_scripts) -{ - accept_rec *new_accept = (accept_rec *)push_array (neg->accepts); - - new_accept->type_name = CGI_MAGIC_TYPE; - new_accept->quality = prefer_scripts ? 1e-20 : 1e20; - new_accept->level = 0.0; - new_accept->max_bytes = 0.0; - - if (neg->accepts->nelts > 1) return; - - new_accept = (accept_rec *)push_array (neg->accepts); - - new_accept->type_name = "*/*"; - new_accept->quality = 1.0; - new_accept->level = 0.0; - new_accept->max_bytes = 0.0; -} - -/***************************************************************** - * - * Parsing type-map files, in Roy's meta/http format augmented with - * #-comments. - */ - -/* Reading RFC822-style header lines, ignoring #-comments and - * handling continuations. - */ - -enum header_state { header_eof, header_seen, header_sep }; - -enum header_state get_header_line (char *buffer, int len, FILE *map) -{ - char *buf_end = buffer + len; - char *cp; - int c; - - /* Get a noncommented line */ - - do { - if (fgets(buffer, MAX_STRING_LEN, map) == NULL) - return header_eof; - } while (buffer[0] == '#'); - - /* If blank, just return it --- this ends information on this variant */ - - for (cp = buffer; *cp && isspace (*cp); ++cp) - continue; - - if (*cp == '\0') return header_sep; - - /* If non-blank, go looking for header lines, but note that we still - * have to treat comments specially... - */ - - cp += strlen(cp); - - while ((c = getc(map)) != EOF) - { - if (c == '#') { - /* Comment line */ - while ((c = getc(map)) != EOF && c != '\n') - continue; - } else if (isspace(c)) { - /* Leading whitespace. POSSIBLE continuation line - * Also, possibly blank --- if so, we ungetc() the final newline - * so that we will pick up the blank line the next time 'round. - */ - - while (c != EOF && c != '\n' && isspace(c)) - c = getc(map); - - ungetc (c, map); - - if (c == '\n') return header_seen; /* Blank line */ - - /* Continuation */ - - while (cp < buf_end - 2 && (c = getc(map)) != EOF && c != '\n') - *cp++ = c; - - *cp++ = '\n'; - *cp = '\0'; - } else { - - /* Line beginning with something other than whitespace */ - - ungetc (c, map); - return header_seen; - } - } - - return header_seen; -} - -/* Stripping out RFC822 comments */ - -void strip_paren_comments (char *hdr) -{ - /* Hmmm... is this correct? In Roy's latest draft, (comments) can nest! */ - - while (*hdr) { - if (*hdr == '"') { - while (*++hdr && *hdr != '"') - continue; - ++hdr; - } - else if (*hdr == '(') { - while (*hdr && *hdr != ')') *hdr++ = ' '; - - if (*hdr) *hdr++ = ' '; - } - else ++hdr; - } -} - -/* Getting to a header body from the header */ - -char *lcase_header_name_return_body (char *header, request_rec *r) -{ - char *cp = header; - - for ( ; *cp && *cp != ':' ; ++cp) { - *cp = tolower(*cp); - } - - if (!*cp) { - log_reason ("Syntax error in type map --- no ':'", r->filename, r); - return NULL; - } - - do ++cp; while (*cp && isspace (*cp)); - - if (!*cp) { - log_reason ("Syntax error in type map --- no header body", - r->filename, r); - return NULL; - } - - return cp; -} - -static int read_type_map (negotiation_state *neg, request_rec *rr) -{ - request_rec *r = neg->r; - FILE *map; - char buffer[MAX_STRING_LEN]; - enum header_state hstate; - struct var_rec mime_info; - - if (rr->status != HTTP_OK) { - return rr->status; - } - map = pfopen (neg->pool, rr->filename, "r"); - if (map == NULL) { - log_reason("cannot access type map file", rr->filename, r); - return FORBIDDEN; - } - - clean_var_rec (&mime_info); - - do { - hstate = get_header_line (buffer, MAX_STRING_LEN, map); - - if (hstate == header_seen) { - char *body = lcase_header_name_return_body (buffer, neg->r); - - if (body == NULL) return SERVER_ERROR; - - strip_paren_comments (body); - - if (!strncmp (buffer, "uri:", 4)) { - mime_info.file_name = get_token (neg->pool, &body, 0); - } - else if (!strncmp (buffer, "content-type:", 13)) { - struct accept_rec accept_info; - - get_entry (neg->pool, &accept_info, body); - set_mime_fields (&mime_info, &accept_info); - } - else if (!strncmp (buffer, "content-length:", 15)) { - mime_info.bytes = atoi(body); - } - else if (!strncmp (buffer, "content-language:", 17)) { - mime_info.content_languages = - do_languages_line(neg->pool, &body); - } - else if (!strncmp (buffer, "content-encoding:", 17)) { - mime_info.content_encoding = get_token (neg->pool, &body, 0); - str_tolower (mime_info.content_encoding); - } - else if (!strncmp (buffer, "description:", 12)) { - mime_info.description = get_token (neg->pool, &body, 0); - } - } else { - if (mime_info.type_quality > 0 && *mime_info.file_name) - { - void *new_var = push_array (neg->avail_vars); - memcpy (new_var, (void *)&mime_info, sizeof (var_rec)); - } - - - clean_var_rec(&mime_info); - } - } while (hstate != header_eof); - - pfclose (neg->pool, map); - return OK; -} - -/***************************************************************** - * - * Same, except we use a filtered directory listing as the map... - */ - -int read_types_multi (negotiation_state *neg) -{ - request_rec *r = neg->r; - - char *filp; - int prefix_len; - DIR *dirp; - struct DIR_TYPE *dir_entry; - struct var_rec mime_info; - struct accept_rec accept_info; - void *new_var; - - clean_var_rec (&mime_info); - - if (!(filp = strrchr (r->filename, '/'))) return DECLINED; /* Weird... */ - - if (strncmp(r->filename, "proxy:", 6) == 0) - return DECLINED; - - ++filp; - prefix_len = strlen (filp); - - dirp = opendir (neg->dir_name); /* Not pool protected; sigh... */ - - if (dirp == NULL) { - log_reason("cannot read directory for multi", neg->dir_name, r); - return FORBIDDEN; - } - - while ((dir_entry = readdir (dirp))) { - - request_rec *sub_req; - - /* Do we have a match? */ - - if (strncmp (dir_entry->d_name, filp, prefix_len)) continue; - if (dir_entry->d_name[prefix_len] != '.') continue; - - /* Yep. See if it's something which we have access to, and - * which has a known type and encoding (as opposed to something - * which we'll be slapping default_type on later). - */ - - sub_req = sub_req_lookup_file (dir_entry->d_name, r); - - /* If it has a handler, we'll pretend it's a CGI script, - * since that's a good indication of the sort of thing it - * might be doing. - */ - if (sub_req->handler && !sub_req->content_type) - sub_req->content_type = CGI_MAGIC_TYPE; - - if (sub_req->status != HTTP_OK || !sub_req->content_type) { - destroy_sub_req(sub_req); - continue; - } - - /* If it's a map file, we use that instead of the map - * we're building... - */ - - if (((sub_req->content_type) && - !strcmp (sub_req->content_type, MAP_FILE_MAGIC_TYPE)) || - ((sub_req->handler) && - !strcmp (sub_req->handler, "type-map"))) { - closedir(dirp); - - neg->avail_vars->nelts = 0; - return read_type_map (neg, sub_req); - } - - /* Have reasonable variant --- gather notes. - */ - - mime_info.sub_req = sub_req; - mime_info.file_name = pstrdup(neg->pool, dir_entry->d_name); - if (sub_req->content_encoding) { - mime_info.content_encoding = sub_req->content_encoding; - str_tolower(mime_info.content_encoding); - } - if (sub_req->content_languages) { - int i; - mime_info.content_languages = sub_req->content_languages; - if (mime_info.content_languages) - for (i = 0; i < mime_info.content_languages->nelts; ++i) - str_tolower(((char**) - (mime_info.content_languages->elts))[i]); - } - - get_entry (neg->pool, &accept_info, sub_req->content_type); - set_mime_fields (&mime_info, &accept_info); - - new_var = push_array (neg->avail_vars); - memcpy (new_var, (void *)&mime_info, sizeof (var_rec)); - - clean_var_rec(&mime_info); - } - - closedir(dirp); - return OK; -} - - -/***************************************************************** - * And now for the code you've been waiting for... actually - * finding a match to the client's requirements. - */ - -/* Matching MIME types ... the star/star and foo/star commenting conventions - * are implemented here. (You know what I mean by star/star, but just - * try mentioning those three characters in a C comment). Using strcmp() - * is legit, because everything has already been smashed to lowercase. - * - * Note also that if we get an exact match on the media type, we update - * level_matched for use in level_cmp below... - * - * We also give a value for mime_stars, which is used later. It should - * be 1 for star/star, 2 for type/star and 3 for type/subtype. - */ - -int mime_match (accept_rec *accept, var_rec *avail) -{ - char *accept_type = accept->type_name; - char *avail_type = avail->type_name; - int len = strlen(accept_type); - - if (accept_type[0] == '*') { /* Anything matches star/star */ - if (avail->mime_stars < 1) - avail->mime_stars = 1; - return 1; - } - else if ((accept_type[len - 1] == '*') && - !strncmp (accept_type, avail_type, len - 2)) { - if (avail->mime_stars < 2) - avail->mime_stars = 2; - return 1; - } - else if (!strcmp (accept_type, avail_type) - || (!strcmp (accept_type, "text/html") - && (!strcmp(avail_type, INCLUDES_MAGIC_TYPE) - || !strcmp(avail_type, INCLUDES_MAGIC_TYPE3)))) { - if (accept->level >= avail->level) { - avail->level_matched = avail->level; - avail->mime_stars = 3; - return 1; - } - } - - return OK; -} - -/* This code implements a piece of the tie-breaking algorithm between - * variants of equal quality. This piece is the treatment of variants - * of the same base media type, but different levels. What we want to - * return is the variant at the highest level that the client explicitly - * claimed to accept. - * - * If all the variants available are at a higher level than that, or if - * the client didn't say anything specific about this media type at all - * and these variants just got in on a wildcard, we prefer the lowest - * level, on grounds that that's the one that the client is least likely - * to choke on. - * - * (This is all motivated by treatment of levels in HTML --- we only - * want to give level 3 to browsers that explicitly ask for it; browsers - * that don't, including HTTP/0.9 browsers that only get the implicit - * "Accept: * / *" [space added to avoid confusing cpp --- no, that - * syntax doesn't really work] should get HTML2 if available). - * - * (Note that this code only comes into play when we are choosing among - * variants of equal quality, where the draft standard gives us a fair - * bit of leeway about what to do. It ain't specified by the standard; - * rather, it is a choice made by this server about what to do in cases - * where the standard does not specify a unique course of action). - */ - -int level_cmp (var_rec *var1, var_rec *var2) -{ - /* Levels are only comparable between matching media types */ - - if (var1->is_pseudo_html && !var2->is_pseudo_html) - return 0; - - if (!var1->is_pseudo_html && strcmp (var1->type_name, var2->type_name)) - return 0; - - /* Take highest level that matched, if either did match. */ - - if (var1->level_matched > var2->level_matched) return 1; - if (var1->level_matched < var2->level_matched) return -1; - - /* Neither matched. Take lowest level, if there's a difference. */ - - if (var1->level < var2->level) return 1; - if (var1->level > var2->level) return -1; - - /* Tied */ - - return 0; -} - -/* Finding languages. The main entry point is set_language_quality() - * which is called for each variant. It sets two elements in the - * variant record: - * language_quality - the 'q' value of the 'best' matching language - * from Accept-Language: header (HTTP/1.1) - * lang_index - Pre HTTP/1.1 language priority, using - * position of language on the Accept-Language: - * header, if present, else LanguagePriority - * directive order. - * - * When we do the variant checking for best variant, we use language - * quality first, and if a tie, language_index next (this only - * applies when _not_ using the network algorithm). If using - * network algorithm, lang_index is never used. - * - * set_language_quality() calls find_lang_index() and find_default_index() - * to set lang_index. - */ - -int find_lang_index (array_header *accept_langs, char *lang) -{ - accept_rec *accs; - int i; - - if (!lang) - return -1; - - accs = (accept_rec *)accept_langs->elts; - - for (i = 0; i < accept_langs->nelts; ++i) - if (!strncmp (lang, accs[i].type_name, strlen(accs[i].type_name))) - return i; - - return -1; -} - -/* This function returns the priority of a given language - * according to LanguagePriority. It is used in case of a tie - * between several languages. - */ - -int find_default_index (neg_dir_config *conf, char *lang) -{ - array_header *arr; - int nelts; - char **elts; - int i; - - if (!lang) - return -1; - - arr = conf->language_priority; - nelts = arr->nelts; - elts = (char **) arr->elts; - - for (i = 0; i < nelts; ++i) - if (!strcasecmp (elts[i], lang)) - return i; - - return -1; -} - -/* set_default_lang_quality() sets the quality we apply to variants - * which have no language assigned to them. If none of the variants - * have a language, we are not negotiating on language, so all are - * acceptable, and we set the default q value to 1.0. However if - * some of the variants have languages, we set this default to 0.001. - * The value of this default will be applied to all variants with - * no explicit language -- which will have the effect of making them - * acceptable, but only if no variants with an explicit language - * are acceptable. The default q value set here is assigned to variants - * with no language type in set_language_quality(). - * - * Note that if using the transparent negotiation network algorythm, - * we don't use this fiddle. - */ - -void set_default_lang_quality(negotiation_state *neg) -{ - var_rec *avail_recs = (var_rec *)neg->avail_vars->elts; - int j; - - if (!neg->use_transparent_neg) - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; - if (variant->content_languages && - variant->content_languages->nelts) { - neg->default_lang_quality = 0.001; - return; - } - } - - neg->default_lang_quality = 1.0; -} - -/* Set the language_quality value in the variant record. Also - * assigns lang_index for back-compat. - * - * To find the language_quality value, we look for the 'q' value - * of the 'best' matching language on the Accept-Language: - * header. The'best' match is the language on Accept-Language: - * header which matches the language of this variant either fully, - * or as far as the prefix marker (-). If two or more languages - * match, use the longest string from the Accept-Language: header - * (see HTTP/1.1 [14.4]) - * - * When a variant has multiple languages, we find the 'best' - * match for each variant language tag as above, then select the - * one with the highest q value. Because both the accept-header - * and variant can have multiple languages, we now have a hairy - * loop-within-a-loop here. - * - * If the variant has no language and we have no Accept-Language - * items, leave the quality at 1.0 and return. - * - * If the variant has no language, we use the default as set by - * set_default_lang_quality() (1.0 if we are not negotiating on - * language, 0.001 if we are). - * - * Following the setting of the language quality, we drop through to - * set the old 'lang_index'. This is set based on either the order - * of the languages on the Accept-Language header, or the - * order on the LanguagePriority directive. This is only used - * in the negotiation if the language qualities tie. - */ - -void set_language_quality(negotiation_state *neg, var_rec *variant) -{ - int i; - int naccept = neg->accept_langs->nelts; - int index; - neg_dir_config *conf = NULL; - char *firstlang; - - if (naccept == 0) - conf = (neg_dir_config *) get_module_config (neg->r->per_dir_config, - &negotiation_module); - - if (naccept == 0 && (!variant->content_languages || - !variant->content_languages->nelts)) - return; /* no accept-language and no variant lang */ - - if (!variant->content_languages || !variant->content_languages->nelts) { - /* This variant has no content-language, so use the default - * quality factor for variants with no content-language - * (previously set by set_default_lang_quality()). */ - variant->lang_quality = neg->default_lang_quality; - - if (naccept == 0) - return; /* no accept-language items */ - - } - else if (naccept) { - /* Variant has one (or more) languages, and we have one (or more) - * language ranges on the Accept-Language header. Look for - * the best match. We do this by going through each language - * on the variant description looking for a match on the - * Accept-Language header. The best match is the longest matching - * language on the header. The final result is the best q value - * from all the languages on the variant description. - */ - int j; - float fiddle_q = 0.0; - accept_rec *accs = (accept_rec *)neg->accept_langs->elts; - accept_rec *best = NULL, *star = NULL; - char *p; - - for (j = 0; j < variant->content_languages->nelts; ++j) { - char *lang; /* language from variant description */ - accept_rec *bestthistag = NULL; - int prefixlen = 0; - int longest_lang_range_len = 0; - int len; - /* lang is the variant's language-tag, which is the one - * we are allowed to use the prefix of in HTTP/1.1 - */ - lang = ((char **)(variant->content_languages->elts))[j]; - p = strchr(lang, '-'); /* find prefix part (if any) */ - if (p) - prefixlen = p - lang; - - /* now find the best (i.e. longest) matching Accept-Language - * header language. We put the best match for this tag in - * bestthistag. We cannot update the overall best (based on - * q value) because the best match for this tag is the longest - * language item on the accept header, not necessarily the - * highest q. - */ - for (i = 0; i < neg->accept_langs->nelts; ++i) { - if (!strcmp(accs[i].type_name, "*")) { - if (!star) - star = &accs[i]; - continue; - } - - /* Find language. We match if either the variant language - * tag exactly matches, or the prefix of the tag up to the - * '-' character matches the whole of the language in the - * Accept-Language header. We only use this accept-language - * item as the best match for the current tag if it - * is longer than the previous best match */ - if ((!strcmp (lang, accs[i].type_name) || - (prefixlen && - !strncmp(lang, accs[i].type_name, prefixlen) && - (accs[i].type_name[prefixlen] == '\0'))) && - ((len = strlen(accs[i].type_name)) > - longest_lang_range_len)) { - longest_lang_range_len = len; - bestthistag = &accs[i]; - } - - if (! bestthistag) { - /* The next bit is a fiddle. Some browsers might be - * configured to send more specific language ranges - * than desirable. For example, an Accept-Language of - * en-US should never match variants with languages en - * or en-GB. But US English speakers might pick en-US - * as their language choice. So this fiddle checks if - * the language range has a prefix, and if so, it - * matches variants which match that prefix with a - * priority of 0.001. So a request for en-US would - * match variants of types en and en-GB, but at much - * lower priority than matches of en-US directly, or - * of any other language listed on the Accept-Language - * header - */ - if ((p = strchr(accs[i].type_name, '-'))) { - int plen = p - accs[i].type_name; - if (!strncmp(lang, accs[i].type_name, plen)) - fiddle_q = 0.001; - } - } - } - /* Finished looking at Accept-Language headers, the best - * (longest) match is in bestthistag, or NULL if no match - */ - if (!best || - (bestthistag && bestthistag->quality > best->quality)) - best = bestthistag; - } - - variant->lang_quality = best ? best->quality : - (star ? star->quality : fiddle_q); - } - - /* Now set the old lang_index field. Since this is old - * stuff anyway, don't both with handling multiple languages - * per variant, just use the first one assigned to it - */ - index = 0; - if (variant->content_languages && variant->content_languages->nelts) - firstlang = ((char**)variant->content_languages->elts)[0]; - else - firstlang = ""; - if (naccept == 0) /* Client doesn't care */ - index = find_default_index (conf, firstlang); - else /* Client has Accept-Language */ - index = find_lang_index (neg->accept_langs, firstlang); - variant->lang_index = index; - - return; -} - -/* Determining the content length --- if the map didn't tell us, - * we have to do a stat() and remember for next time. - * - * Grump. For Apache, even the first stat here may well be - * redundant (for multiviews) with a stat() done by the sub_req - * machinery. At some point, that ought to be fixed. - */ - -int find_content_length(negotiation_state *neg, var_rec *variant) -{ - struct stat statb; - - if (variant->bytes == 0) { - char *fullname = make_full_path (neg->pool, neg->dir_name, - variant->file_name); - - if (stat (fullname, &statb) >= 0) variant->bytes = statb.st_size; - } - - return variant->bytes; -} - -/* For a given variant, find the best matching Accept: header - * and assign the Accept: header's quality value to the - * accept_type_quality field of the variant, for later use in - * determining the best matching variant. - */ - -void set_accept_quality(negotiation_state *neg, var_rec *variant) -{ - int i; - accept_rec *accept_recs = (accept_rec *)neg->accepts->elts; - float q = 0.0; - int q_definite = 1; - - /* if no Accept: header, leave quality alone (will - * remain at the default value of 1) */ - if (!neg->accepts || neg->accepts->nelts == 0) - return; - - /* - * Go through each of the ranges on the Accept: header, - * looking for the 'best' match with this variant's - * content-type. We use the best match's quality - * value (from the Accept: header) for this variant's - * accept_type_quality field. - * - * The best match is determined like this: - * type/type is better than type/ * is better than * / * - * if match is type/type, use the level mime param if available - */ - for (i = 0; i < neg->accepts->nelts; ++i) { - - accept_rec *type = &accept_recs[i]; - int prev_mime_stars; - - prev_mime_stars = variant->mime_stars; - - if (!mime_match(type, variant)) - continue; /* didn't match the content type at all */ - else - /* did match - see if there were less or more stars than - * in previous match - */ - if (prev_mime_stars == variant->mime_stars) - continue; /* more stars => not as good a match */ - - /* Check maxbytes -- not in HTTP/1.1 or Holtman */ - - if (type->max_bytes > 0 - && (find_content_length(neg, variant) - > type->max_bytes)) - continue; - - /* If we are allowed to mess with the q-values, - * make wildcards very low, so we have a low chance - * of ending up with them if there's something better. - */ - - if (!neg->accept_q && variant->mime_stars == 1) q = 0.01; - else if (!neg->accept_q && variant->mime_stars == 2) q = 0.02; - else q = type->quality; - - q_definite = (variant->mime_stars == 3); - } - variant->accept_type_quality = q; - variant->definite=variant->definite && q_definite; - - /* if the _best_ quality we got for this variant was 0.0, - * eliminate it now */ -} - -/* For a given variant, find the 'q' value of the charset given - * on the Accept-Charset line. If not charsets are listed, - * assume value of '1'. - */ - -void set_charset_quality(negotiation_state *neg, var_rec *variant) -{ - int i; - accept_rec *accept_recs = (accept_rec *)neg->accept_charsets->elts; - char *charset = variant->content_charset; - accept_rec *star = NULL; - - /* if no Accept-Charset: header, leave quality alone (will - * remain at the default value of 1) */ - if (!neg->accept_charsets || neg->accept_charsets->nelts == 0) - return; - - if (charset == NULL || !*charset) charset = "iso-8859-1"; - - /* - * Go through each of the items on the Accept-Charset: header, - * looking for a match with this variant's charset. If none - * match, charset is unacceptable, so set quality to 0. - */ - for (i = 0; i < neg->accept_charsets->nelts; ++i) { - - accept_rec *type = &accept_recs[i]; - - if (!strcmp(type->type_name, charset)) { - variant->charset_quality = type->quality; - return; - } else - if (strcmp(type->type_name, "*") == 0) { - star = type; - } - } - /* No explicit match */ - if (star) { - variant->charset_quality = star->quality; - return; - } - /* If this variant is in charset iso-8859-1, the default is 1.0 */ - if (strcmp(charset, "iso-8859-1") == 0) { - variant->charset_quality = 1.0; - } else { - variant->charset_quality = 0.0; - } -} - -/* For a given variant, find the best matching Accept: header - * and assign the Accept: header's quality value to the - * accept_type_quality field of the variant, for later use in - * determining the best matching variant. - */ - -/* is_identity_encoding is included for back-compat, but does anyone - * use 7bit, 8bin or binary in their var files?? - */ - -int is_identity_encoding (char *enc) -{ - return (!enc || !enc[0] || !strcmp (enc, "7bit") || !strcmp (enc, "8bit") - || !strcmp (enc, "binary")); -} - -void set_encoding_quality(negotiation_state *neg, var_rec *variant) -{ - int i; - accept_rec *accept_recs = (accept_rec *)neg->accept_encodings->elts; - char *enc = variant->content_encoding; - - if (!enc || is_identity_encoding(enc)) - return; - - - /* if no Accept: header, leave quality alone (will - * remain at the default value of 1) */ - if (neg->accept_encodings->nelts == 0) { - /* If we had an empty Accept-Encoding header, assume that - * no encodings are acceptable, else all encodings are ok */ - variant->encoding_quality = neg->have_accept_header ? 0 : 1; - return; - } - - /* Go through each of the encodings on the Accept-Encoding: header, - * looking for a match with our encoding - */ - for (i = 0; i < neg->accept_encodings->nelts; ++i) { - char *name = accept_recs[i].type_name; - - if (!strcmp(name, enc)) { - variant->encoding_quality = 1; - return; - } - } - - /* Encoding not found on Accept-Encoding: header, so it is - * _not_ acceptable */ - variant->encoding_quality = 0; -} - -/* Possible results of the network algorithm */ -enum algorithm_results { - na_not_applied = -1, /* net algorithm not used */ - na_choice = 1, /* choose variant */ - na_list /* list variants */ -}; - -/* - * This is a heavily-rewritten 'best_match' function. For a start, it - * now returns an int, which has one of the three values: na_not_applied, - * na_choice or na_list, which give the result of the network algorithm - * (if it was not applied, the return value is na_not_applied). - * The best variable is returned in *pbest. It also has two possible - * algorithms for determining the best match: the network algorithm, - * and the standard Apache algorithm. These are split out into - * separate functions (is_variant_better_na() and is_variant_better()). - * - * Previously, best_match iterated first through the content_types - * in the Accept: header, then checked each variant, and eliminated - * those that didn't match the variant's type. We cannot do this because - * we need full information, including language, charset, etc - * quality for _every_ variant, for the Alternates: header, - * and (possibly) the human-readable choice responses or 406 errors. - * - * After the 'best' (if any) is determined, the overall result of - * the negotiation is obtained. If the network algorithm was not - * in use, the result is na_not_applied. Else the result is - * na_list if 'short accept header' is in use, else na_list - * if _no_ best match was found, or na_choice if a best match - * was found. - */ - -/* Firstly, the negotiation 'network algorithm' from Holtman. - */ - -int is_variant_better_na(negotiation_state *neg, var_rec *variant, var_rec *best, float *p_bestq) -{ - float bestq = *p_bestq, q; - - /* Note: Encoding is not negotiated in the Holtman - * transparent neg draft, so we ignored it here. But - * it does mean we could return encodings the UA - * or proxy cannot handle. Eek. */ - - q = variant->accept_type_quality * - variant->type_quality * - variant->charset_quality * - variant->lang_quality; - -#ifdef NEG_DEBUG - fprintf(stderr, "Variant: file=%s type=%s lang=%s acceptq=%1.3f langq=%1.3f typeq=%1.3f q=%1.3f definite=%d\n", - variant->file_name ? variant->file_name : "", - variant->type_name ? variant->type_name : "", - variant->content_languages ? merge_string_array(neg->pool, variant->content_languages, ",") : "", - variant->accept_type_quality, - variant->lang_quality, - variant->type_quality, - q, - variant->definite - ); -#endif - - if (q > bestq) { - *p_bestq = q; - return 1; - } - if (q == bestq) { - /* If the best variant's charset is ISO-8859-1 and this variant has - the same charset quality, then we prefer this variant */ - if (variant->charset_quality == best->charset_quality && - (variant->content_charset != NULL && - *variant->content_charset != '\0' && - strcmp(variant->content_charset, "iso-8859-1") != 0) && - (best->content_charset == NULL || - *best->content_charset == '\0' || - strcmp(best->content_charset, "iso-8859-1") == 0)) { - *p_bestq = q; - return 1; - } - } - return 0; -} - -/* Negotiation algorithm as used by previous versions of Apache - * (just about). - */ - -float is_variant_better(negotiation_state *neg, var_rec *variant, var_rec *best, float *p_bestq) -{ - float bestq = *p_bestq, q; - int levcmp; - - /* - * For non-transparent negotiation, server can choose how - * to handle the negotiation. We'll use the following in - * order: content-type, language, content-type level, charset, - * content length. - * - * For each check, we have three possible outcomes: - * This variant is worse than current best: return 0 - * This variant is better than the current best: - * assign this variant's q to *p_bestq, and return 1 - * This variant is just as desirable as the current best: - * drop through to the next test. - * - * This code is written in this long-winded way to allow future - * customisation, either by the addition of additional - * checks, or to allow the order of the checks to be determined - * by configuration options (e.g. we might prefer to check - * language quality _before_ content type). - */ - - /* First though, eliminate this variant if it is not - * acceptable by type, charset, encoding or language. - */ - - if (variant->encoding_quality == 0 || - variant->lang_quality == 0 || - variant->type_quality == 0 || - variant->charset_quality == 0 || - variant->accept_type_quality == 0) - return 0; /* don't consider unacceptables */ - - q = variant->accept_type_quality * variant->type_quality; - if (q == 0.0 || q < bestq) return 0; - if (q > bestq || !best) { - *p_bestq = q; - return 1; - } - - /* language */ - if (variant->lang_quality < best->lang_quality) - return 0; - if (variant->lang_quality > best->lang_quality) { - *p_bestq = q; - return 1; - } - - /* if language qualities were equal, try the LanguagePriority - * stuff */ - if (best->lang_index != -1 && variant->lang_index > best->lang_index) - return 0; - if (variant->lang_index != -1 && - (variant->lang_index < best->lang_index || best->lang_index == -1)) { - *p_bestq = q; - return 1; - } - - /* content-type level (text/html only?) */ - levcmp = level_cmp (variant, best); - if (levcmp == -1) return 0; - if (levcmp == 1) { - *p_bestq = q; - return 1; - } - - /* encoding -- can only be 1 or 0, and if 0 we eliminated this - * variant at the start of this function. However we - * prefer variants with no encoding over those with encoding */ - if (!*best->content_encoding && *variant->content_encoding) - return 0; - if (*best->content_encoding && !*variant->content_encoding) { - *p_bestq = q; - return 1; - } - - - /* charset */ - if (variant->charset_quality < best->charset_quality) - return 0; - /* If the best variant's charset is ISO-8859-1 and this variant has - the same charset quality, then we prefer this variant */ - if (variant->charset_quality > best->charset_quality || - ((variant->content_charset != NULL && - *variant->content_charset != '\0' && - strcmp(variant->content_charset, "iso-8859-1") != 0) && - (best->content_charset == NULL || - *best->content_charset == '\0' || - strcmp(best->content_charset, "iso-8859-1") == 0))) { - *p_bestq = q; - return 1; - } - - - /* content length if all else equal */ - if (find_content_length(neg, variant) - >= - find_content_length(neg, best)) - return 0; - - /* ok, to get here means every thing turned out equal, except - * we have a shorter content length, so use this variant */ - *p_bestq = q; - return 1; -} - -int best_match(negotiation_state *neg, var_rec **pbest) -{ - int j; - var_rec *best = NULL; - float bestq = 0.0; - enum algorithm_results algorithm_result = na_not_applied; - - var_rec *avail_recs = (var_rec *)neg->avail_vars->elts; - - set_default_lang_quality(neg); - - /* - * Find the 'best' variant - */ - - for (j = 0; j < neg->avail_vars->nelts; ++j) { - - var_rec *variant = &avail_recs[j]; - - /* Find all the relevant 'quality' values from the - * Accept... headers, and store in the variant - */ - set_accept_quality(neg, variant); - set_language_quality(neg, variant); - set_encoding_quality(neg, variant); - set_charset_quality(neg, variant); - - /* Now find out if this variant is better than the current - * best, either using the network algorithm, or Apache's - * internal server-driven algorithm. Presumably other - * server-driven algorithms are possible, and could be - * implemented here. - */ - - if (neg->use_transparent_neg) { - if (is_variant_better_na(neg, variant, best, &bestq)) - best = variant; - } - else { - if (is_variant_better(neg, variant, best, &bestq)) - best = variant; - } - } - - /* We now either have a best variant, or no best variant - */ - if (neg->use_transparent_neg) { - if (neg->short_accept_headers) - algorithm_result = na_list; - else { - /* From Holtman, result is: - * If variant & URI are not neigbors, list_ua or list_os - * Else - * If UA can do trans neg - * IF best is definite && best q > 0, choice_ua - * ELSE list_ua - * ELSE - * IF best q > 0, choose_os - * ELSE list_os (or forward_os on proxy) - */ - - /* assume variant and URI are neigbors (since URI in - * var map must be in same directory) */ - - if(neg->use_transparent_neg) - algorithm_result = (best && best->definite) && (bestq>0) - ? na_choice : na_list; - else - algorithm_result = bestq>0 ? na_choice : na_list; - } - } - - *pbest = best; - return algorithm_result; -} - -/* - * Sets the Alternates and Vary headers, used if we are going to - * return 406 Not Acceptable status, a 300 Multiple Choice status, - * or a Choice response. - * - * 'type' is the result of the network algorithm, if applied. - * We do different things if the network algorithm was not applied - * (type == na_not_applied): no Alternates header, and Vary: - * does not include 'negotiate'. - * - * We should also add a max-age lifetime for the Alternates header, - * but how long we we give it? Presumably this should be - * configurable in the map file. - */ - -void set_neg_headers(request_rec *r, negotiation_state *neg, int na_result) -{ - int j; - var_rec *avail_recs = (var_rec *)neg->avail_vars->elts; - char *sample_type = NULL; - char *sample_language = NULL; - char *sample_encoding = NULL; - char *sample_charset = NULL; - int vary_by_type = 0; - int vary_by_language = 0; - int vary_by_charset = 0; - int vary_by_encoding = 0; - array_header *hdrs; - - /* Put headers into err_headers_out, new send_http_header() - * outputs both headers_out and err_headers_out */ - hdrs = r->err_headers_out; - - for (j = 0; j < neg->avail_vars->nelts; ++j) { - - var_rec *variant = &avail_recs[j]; - char *rec; - char qstr[6]; - long len; - char lenstr[22]; /* enough for 2^64 */ - - ap_snprintf(qstr, sizeof(qstr), "%1.3f", variant->type_quality); - - /* Strip trailing zeros (saves those valuable network bytes) */ - if (qstr[4] == '0') { - qstr[4] = '\0'; - if (qstr[3] == '0') { - qstr[3] = '\0'; - if (qstr[2] == '0') { - qstr[1] = '\0'; - } - } - } - - rec = pstrcat(r->pool, "{\"", variant->file_name, "\" ", qstr, NULL); - if (variant->type_name) { - if (*variant->type_name) - rec = pstrcat(r->pool, rec, " {type ", - variant->type_name, "}", NULL); - if (!sample_type) sample_type = variant->type_name; - else if (strcmp(sample_type, variant->type_name)) - vary_by_type = 1; - } - if (variant->content_languages && variant->content_languages->nelts) { - char *langs = - merge_string_array (r->pool, variant->content_languages, ","); - rec = pstrcat(r->pool, rec, " {language ", langs, "}", NULL); - if (!sample_language) sample_language = langs; - else if (strcmp(sample_language, langs)) - vary_by_language = 1; - } - if (variant->content_encoding) { - if (!sample_encoding) sample_encoding = variant->content_encoding; - else if (strcmp(sample_encoding, variant->content_encoding)) - vary_by_encoding = 1; - } - if (variant->content_charset) { - if (*variant->content_charset) - rec = pstrcat(r->pool, rec, " {charset ", - variant->content_charset, "}", NULL); - if (!sample_charset) sample_charset = variant->content_charset; - else if (strcmp(sample_charset, variant->content_charset)) - vary_by_charset = 1; - } - if ((len = find_content_length(neg, variant)) != 0) { - ap_snprintf(lenstr, sizeof(lenstr), "%ld", len); - rec = pstrcat(r->pool, rec, " {length ", lenstr, "}", NULL); - } - - rec = pstrcat(r->pool, rec, "}", NULL); - - if (na_result != na_not_applied) - table_merge(hdrs, "Alternates", rec); - } - - if (na_result != na_not_applied) - table_merge(hdrs, "Vary", "negotiate"); - if (vary_by_type) - table_merge(hdrs, "Vary", "accept"); - if (vary_by_language) - table_merge(hdrs, "Vary", "accept-language"); - if (vary_by_charset) - table_merge(hdrs, "Vary", "accept-charset"); - if (vary_by_encoding && na_result == na_not_applied) - table_merge(hdrs, "Vary", "accept-encoding"); -} - -/********************************************************************** - * - * Return an HTML list of variants. This is output as part of the - * 300 or 406 status body. - */ - -char *make_variant_list (request_rec *r, negotiation_state *neg) -{ - int i; - char *t; - - t = pstrdup(r->pool, "Available variants:\n<ul>\n"); - for (i = 0; i < neg->avail_vars->nelts; ++i) { - var_rec *variant = &((var_rec *)neg->avail_vars->elts)[i]; - char *filename = variant->file_name ? variant->file_name : ""; - array_header *languages = variant->content_languages; - char *description = variant->description ? variant->description : ""; - - /* The format isn't very neat, and it would be nice to make - * the tags human readable (eg replace 'language en' with - * 'English'). */ - t = pstrcat(r->pool, t, "<li><a href=\"", filename, "\">", - filename, "</a> ", description, NULL); - if (variant->type_name && *variant->type_name) - t = pstrcat(r->pool, t, ", type ", variant->type_name, NULL); - if (languages && languages->nelts) - t = pstrcat(r->pool, t, ", language ", - merge_string_array(r->pool, languages, ", "), - NULL); - if (variant->content_charset && *variant->content_charset) - t = pstrcat(r->pool, t, ", charset ", variant->content_charset, NULL); - t = pstrcat(r->pool, t, "\n", NULL); - } - t = pstrcat(r->pool, t, "</ul>\n", NULL); - - return t; -} - -void store_variant_list (request_rec *r, negotiation_state *neg) -{ - if (r->main == NULL) { - table_set (r->notes, "variant-list", make_variant_list (r, neg)); - } else { - table_set (r->main->notes, "variant-list", make_variant_list (r->main, neg)); - } -} - -/* Called if we got a "Choice" response from the network algorithm. - * It checks the result of the chosen variant to see if it - * is itself negotiated (if so, return error VARIANT_ALSO_VARIES). - * Otherwise, add the appropriate headers to the current response. - */ - -int setup_choice_response(request_rec *r, negotiation_state *neg, var_rec *variant) -{ - request_rec *sub_req; - char *sub_vary; - - if (!variant->sub_req) { - int status; - - sub_req = sub_req_lookup_file(variant->file_name, r); - status = sub_req->status; - if (status != HTTP_OK && status != HTTP_MULTIPLE_CHOICES) { - destroy_sub_req(sub_req); - return status; - } - variant->sub_req = sub_req; - } - else - sub_req = variant->sub_req; - - - /* The network algorithm told us to return a "Choice" - * response. This is the normal variant response, with - * some extra headers. First, ensure that the chosen - * variant did not itself return a "List" or "Choice" response. - * If not, set the appropriate headers, and fall through to - * the normal variant handling - */ - - if ((sub_req->status == HTTP_MULTIPLE_CHOICES) || - (table_get(sub_req->err_headers_out, "Alternates")) || - (table_get(sub_req->err_headers_out, "Content-Location"))) - return VARIANT_ALSO_VARIES; - - if ((sub_vary = table_get(sub_req->err_headers_out, "Vary")) != NULL) - table_set(r->err_headers_out, "Variant-Vary", sub_vary); - table_set(r->err_headers_out, "Content-Location", variant->file_name); - set_neg_headers(r, neg, na_choice); /* add Alternates and Vary */ - /* to do: add Expires */ - - return 0; -} - -/**************************************************************** - * - * Executive... - */ - -int handle_map_file (request_rec *r) -{ - negotiation_state *neg = parse_accept_headers (r); - var_rec *best; - int res; - int na_result; - - char *udir; - - if ((res = read_type_map (neg, r))) return res; - - maybe_add_default_encodings(neg, 0); - - na_result = best_match(neg, &best); - - /* na_result is one of - * na_not_applied: we didn't use the network algorithm - * na_choice: return a "Choice" response - * na_list: return a "List" response (no variant chosen) - */ - - if (na_result == na_list) { - set_neg_headers(r, neg, na_list); - store_variant_list (r, neg); - return MULTIPLE_CHOICES; - } - - if (!best) { - log_reason ("no acceptable variant", r->filename, r); - - set_neg_headers(r, neg, na_result); - store_variant_list (r, neg); - return NOT_ACCEPTABLE; - } - - if (na_result == na_choice) - if ((res = setup_choice_response(r, neg, best)) != 0) - return res; - - /* Make sure caching works - Vary should handle HTTP/1.1, but for - * HTTP/1.0, we can't allow caching at all. NB that we merge the - * header in case some other module negotiates on something else. - */ - if (!do_cache_negotiated_docs(r->server) && (r->proto_num < 1001)) - r->no_cache = 1; - - if (na_result == na_not_applied) - set_neg_headers(r, neg, na_not_applied); - - if (r->path_info && *r->path_info) { - r->uri[find_path_info(r->uri, r->path_info)] = '\0'; - } - udir = make_dirstr (r->pool, r->uri, count_dirs (r->uri)); - udir = escape_uri(r->pool, udir); - internal_redirect(pstrcat(r->pool, udir, best->file_name, r->path_info, - NULL), r); - return OK; -} - -int handle_multi (request_rec *r) -{ - negotiation_state *neg; - var_rec *best, *avail_recs; - request_rec *sub_req; - int res; - int j; - int na_result; /* result of network algorithm */ - - if (r->finfo.st_mode != 0 || !(allow_options (r) & OPT_MULTI)) - return DECLINED; - - neg = parse_accept_headers (r); - - if ((res = read_types_multi (neg))) { -return_from_multi: - /* free all allocated memory from subrequests */ - avail_recs = (var_rec *)neg->avail_vars->elts; - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; - if (variant->sub_req) { - destroy_sub_req(variant->sub_req); - } - } - return res; - } - if (neg->avail_vars->nelts == 0) return DECLINED; - - maybe_add_default_encodings(neg, - r->method_number != M_GET - || r->args || r->path_info); - - na_result = best_match(neg, &best); - if (na_result == na_list) { - /* - * Network algorithm tols us to output a "List" response. - * This is output at a 300 status code, which we will - * return. The list of variants will be stored in r->notes - * under the name "variants-list". - */ - set_neg_headers(r, neg, na_list); /* set Alternates: and Vary: */ - - store_variant_list (r, neg); - res = MULTIPLE_CHOICES; - goto return_from_multi; - } - - if (!best) { - log_reason ("no acceptable variant", r->filename, r); - - set_neg_headers (r, neg, na_result); - store_variant_list (r, neg); - res = NOT_ACCEPTABLE; - goto return_from_multi; - } - - if (na_result == na_choice) - if ((res = setup_choice_response(r, neg, best)) != 0) { - goto return_from_multi; - } - - if (! (sub_req = best->sub_req)) { - /* We got this out of a map file, so we don't actually have - * a sub_req structure yet. Get one now. - */ - - sub_req = sub_req_lookup_file (best->file_name, r); - if (sub_req->status != HTTP_OK) { - res = sub_req->status; - destroy_sub_req(sub_req); - goto return_from_multi; - } - } - - /* BLETCH --- don't multi-resolve non-ordinary files */ - - if (!S_ISREG(sub_req->finfo.st_mode)) { - res = NOT_FOUND; - goto return_from_multi; - } - - /* Otherwise, use it. */ - - if (!do_cache_negotiated_docs(r->server) && (r->proto_num < 1001)) - r->no_cache = 1; - - if (na_result == na_not_applied) - set_neg_headers(r, neg, na_not_applied); - - r->filename = sub_req->filename; - r->handler = sub_req->handler; - r->content_type = sub_req->content_type; - r->content_encoding = sub_req->content_encoding; - r->content_languages = sub_req->content_languages; - r->content_language = sub_req->content_language; - r->finfo = sub_req->finfo; - r->per_dir_config = sub_req->per_dir_config; - /* copy output headers from subrequest, but leave negotiation headers */ - r->notes = overlay_tables(r->pool, sub_req->notes, r->notes); - r->headers_out = overlay_tables(r->pool, sub_req->headers_out, - r->headers_out); - r->err_headers_out = overlay_tables(r->pool, sub_req->err_headers_out, - r->err_headers_out); - r->subprocess_env = overlay_tables(r->pool, sub_req->subprocess_env, - r->subprocess_env); - avail_recs = (var_rec *)neg->avail_vars->elts; - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; - if (variant != best && variant->sub_req) { - destroy_sub_req(variant->sub_req); - } - } - return OK; -} - -handler_rec negotiation_handlers[] = { -{ MAP_FILE_MAGIC_TYPE, handle_map_file }, -{ "type-map", handle_map_file }, -{ NULL } -}; - -module negotiation_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - create_neg_dir_config, /* dir config creater */ - merge_neg_dir_configs, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - negotiation_cmds, /* command table */ - negotiation_handlers, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - handle_multi, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_rewrite.c b/usr.sbin/httpd/src/mod_rewrite.c deleted file mode 100644 index 15fb1d8dffa..00000000000 --- a/usr.sbin/httpd/src/mod_rewrite.c +++ /dev/null @@ -1,3335 +0,0 @@ - -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - - -/* _ _ _ -** _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___ -** | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \ -** | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/ -** |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___| -** |_____| -** -** URL Rewriting Module -** -** This module uses a rule-based rewriting engine (based on a -** regular-expression parser) to rewrite requested URLs on the fly. -** -** It supports an unlimited number of additional rule conditions (which can -** operate on a lot of variables, even on HTTP headers) for granular -** matching and even external database lookups (either via plain text -** tables, DBM hash files or even external processes) for advanced URL -** substitution. -** -** It operates on the full URLs (including the PATH_INFO part) both in -** per-server context (httpd.conf) and per-dir context (.htaccess) and even -** can generate QUERY_STRING parts on result. The rewriting result finally -** can lead to internal subprocessing, external request redirection or even -** to internal proxy throughput. -** -** This module was originally written in April 1996 and -** gifted exclusively to the The Apache Group in July 1997 by -** -** Ralf S. Engelschall -** rse@engelschall.com -** www.engelschall.com -*/ - - - - - /* from the underlaying Unix system ... */ -#include <string.h> -#include <stdarg.h> -#include <time.h> -#include <signal.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <netinet/in.h> - - /* from the Apache server ... */ -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_log.h" - - /* now our own stuff ... */ -#include "mod_rewrite.h" - - - - -/* -** +-------------------------------------------------------+ -** | | -** | static module configuration -** | | -** +-------------------------------------------------------+ -*/ - - -/* -** -** our interface to the Apache server kernel -** -** keep in mind: -** -** o Runtime logic of a request is as following: -** -** while(request or subrequest) { -** foreach(stage #1...#9) { -** foreach(module) { (**) -** try to run hook -** } -** } -** } -** -** o the order of modules at (**) is the inverted order as -** given in the "Configuration" file, i.e. the last module -** specified is the first one called for each hook! -** The core module is always the last! -** -** o there are two different types of result checking and -** continue processing: -** for hook #1,#4,#5,#6,#8: -** hook run loop stops on first modules which gives -** back a result != DECLINED, i.e. it usually returns OK -** which says "OK, module has handled this _stage_" and for #1 -** this have not to mean "Ok, the filename is now valid". -** for hook #2,#3,#7,#9: -** all hooks are run, independend of result -** -** o at the last stage, the core module always -** - says "BAD_REQUEST" if r->filename does not begin with "/" -** - prefix URL with document_root or replaced server_root -** with document_root and sets r->filename -** - always return a "OK" independed if the file really exists -** or not! -** -*/ - - /* the table of commands we provide */ -static command_rec command_table[] = { - { "RewriteEngine", cmd_rewriteengine, NULL, OR_FILEINFO, FLAG, - "On or Off to enable or disable (default) the whole rewriting engine" }, - { "RewriteOptions", cmd_rewriteoptions, NULL, OR_FILEINFO, ITERATE, - "List of option strings to set" }, - { "RewriteBase", cmd_rewritebase, NULL, OR_FILEINFO, TAKE1, - "the base URL of the per-directory context" }, - { "RewriteCond", cmd_rewritecond, NULL, OR_FILEINFO, RAW_ARGS, - "a input string and a to be applied regexp-pattern" }, - { "RewriteRule", cmd_rewriterule, NULL, OR_FILEINFO, RAW_ARGS, - "a URL-applied regexp-pattern and a substitution URL" }, - { "RewriteMap", cmd_rewritemap, NULL, RSRC_CONF, TAKE2, - "a mapname and a filename" }, - { "RewriteLog", cmd_rewritelog, NULL, RSRC_CONF, TAKE1, - "the filename of the rewriting logfile" }, - { "RewriteLogLevel", cmd_rewriteloglevel, NULL, RSRC_CONF, TAKE1, - "the level of the rewriting logfile verbosity (0=none, 1=std, .., 9=max)" }, - { NULL } -}; - - /* the table of content handlers we provide */ -static handler_rec handler_table[] = { - { "redirect-handler", handler_redirect }, - { NULL } -}; - - /* the main config structure */ -module rewrite_module = { - STANDARD_MODULE_STUFF, - - init_module, /* module initializer */ - - config_perdir_create, /* create per-dir config structures */ - config_perdir_merge, /* merge per-dir config structures */ - config_server_create, /* create per-server config structures */ - config_server_merge, /* merge per-server config structures */ - command_table, /* table of config file commands */ - - handler_table, /* [#8] table of MIME-typed-dispatched request action handlers */ - - hook_uri2file, /* [#1] URI to filename translation */ - - NULL, /* [#4] check_user_id: get and validate user id from the HTTP request */ - NULL, /* [#5] check_auth: check if the user is ok _here_ */ - NULL, /* [#2] check_access: check access by host address, etc. */ - - hook_mimetype, /* [#6] determine MIME type */ - - hook_fixup, /* [#7] pre-run fixups */ - NULL, /* [#9] log a transaction */ - NULL /* [#3] header parser */ -}; - - /* the cache */ -static cache *cachep; - - /* whether proxy module is available or not */ -static int proxy_available; - - /* the txt mapfile parsing stuff */ -#define MAPFILE_PATTERN "^([^ \t]+)[ \t]+([^ \t]+).*$" -#define MAPFILE_OUTPUT "$1,$2" -static regex_t *lookup_map_txtfile_regexp = NULL; -static regmatch_t lookup_map_txtfile_regmatch[10]; - - - - -/* -** +-------------------------------------------------------+ -** | | -** | configuration directive handling -** | | -** +-------------------------------------------------------+ -*/ - - -/* -** -** per-server configuration structure handling -** -*/ - -static void *config_server_create(pool *p, server_rec *s) -{ - rewrite_server_conf *a; - - a = (rewrite_server_conf *)pcalloc(p, sizeof(rewrite_server_conf)); - - a->state = ENGINE_DISABLED; - a->options = OPTION_NONE; - a->rewritelogfile = NULL; - a->rewritelogfp = -1; - a->rewriteloglevel = 1; - a->rewritemaps = make_array(p, 2, sizeof(rewritemap_entry)); - a->rewriteconds = make_array(p, 2, sizeof(rewritecond_entry)); - a->rewriterules = make_array(p, 2, sizeof(rewriterule_entry)); - - return (void *)a; -} - -static void *config_server_merge(pool *p, void *basev, void *overridesv) -{ - rewrite_server_conf *a, *base, *overrides; - - a = (rewrite_server_conf *)pcalloc(p, sizeof(rewrite_server_conf)); - base = (rewrite_server_conf *)basev; - overrides = (rewrite_server_conf *)overridesv; - - a->state = overrides->state; - a->options = overrides->options; - a->rewritelogfile = base->rewritelogfile != NULL ? base->rewritelogfile : overrides->rewritelogfile; - a->rewritelogfp = base->rewritelogfp != -1 ? base->rewritelogfp : overrides->rewritelogfp; - a->rewriteloglevel = overrides->rewriteloglevel; - - if (a->options & OPTION_INHERIT) { - a->rewritemaps = append_arrays(p, overrides->rewritemaps, base->rewritemaps); - a->rewriteconds = append_arrays(p, overrides->rewriteconds, base->rewriteconds); - a->rewriterules = append_arrays(p, overrides->rewriterules, base->rewriterules); - } - else { - a->rewritemaps = overrides->rewritemaps; - a->rewriteconds = overrides->rewriteconds; - a->rewriterules = overrides->rewriterules; - } - - return (void *)a; -} - - -/* -** -** per-directory configuration structure handling -** -*/ - -static void *config_perdir_create(pool *p, char *path) -{ - rewrite_perdir_conf *a; - - a = (rewrite_perdir_conf *)pcalloc(p, sizeof(rewrite_perdir_conf)); - - a->state = ENGINE_DISABLED; - a->options = OPTION_NONE; - a->baseurl = NULL; - a->rewriteconds = make_array(p, 2, sizeof(rewritecond_entry)); - a->rewriterules = make_array(p, 2, sizeof(rewriterule_entry)); - - if (path == NULL) - a->directory = NULL; - else { - /* make sure it has a trailing slash */ - if (path[strlen(path)-1] == '/') - a->directory = pstrdup(p, path); - else - a->directory = pstrcat(p, path, "/", NULL); - } - - return (void *)a; -} - -static void *config_perdir_merge(pool *p, void *basev, void *overridesv) -{ - rewrite_perdir_conf *a, *base, *overrides; - - a = (rewrite_perdir_conf *)pcalloc(p, sizeof(rewrite_perdir_conf)); - base = (rewrite_perdir_conf *)basev; - overrides = (rewrite_perdir_conf *)overridesv; - - a->state = overrides->state; - a->options = overrides->options; - a->directory = overrides->directory; - a->baseurl = overrides->baseurl; - - if (a->options & OPTION_INHERIT) { - a->rewriteconds = append_arrays(p, overrides->rewriteconds, base->rewriteconds); - a->rewriterules = append_arrays(p, overrides->rewriterules, base->rewriterules); - } - else { - a->rewriteconds = overrides->rewriteconds; - a->rewriterules = overrides->rewriterules; - } - - return (void *)a; -} - - -/* -** -** the configuration commands -** -*/ - -static const char *cmd_rewriteengine(cmd_parms *cmd, rewrite_perdir_conf *dconf, int flag) -{ - rewrite_server_conf *sconf; - - sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); - if (cmd->path == NULL) /* is server command */ - sconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED); - else /* is per-directory command */ - dconf->state = (flag ? ENGINE_ENABLED : ENGINE_DISABLED); - - return NULL; -} - -static const char *cmd_rewriteoptions(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *option) -{ - rewrite_server_conf *sconf; - const char *err; - - sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); - if (cmd->path == NULL) /* is server command */ - err = cmd_rewriteoptions_setoption(cmd->pool, &(sconf->options), option); - else /* is per-directory command */ - err = cmd_rewriteoptions_setoption(cmd->pool, &(dconf->options), option); - - return err; -} - -static const char *cmd_rewriteoptions_setoption(pool *p, int *options, char *name) -{ - if (strcasecmp(name, "inherit") == 0) - *options |= OPTION_INHERIT; - else - return pstrcat(p, "RewriteOptions: unknown option '", name, "'\n", NULL); - return NULL; -} - -static const char *cmd_rewritelog(cmd_parms *cmd, void *dconf, char *a1) -{ - rewrite_server_conf *sconf; - - sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); - sconf->rewritelogfile = a1; - - return NULL; -} - -static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1) -{ - rewrite_server_conf *sconf; - - sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); - sconf->rewriteloglevel = atoi(a1); - - return NULL; -} - -static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, char *a1, char *a2) -{ - rewrite_server_conf *sconf; - rewritemap_entry *new; - struct stat st; - - sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); - new = push_array(sconf->rewritemaps); - - new->name = a1; - if (strncmp(a2, "txt:", 4) == 0) { - new->type = MAPTYPE_TXT; - new->datafile = a2+4; - new->checkfile = a2+4; - } - else if (strncmp(a2, "dbm:", 4) == 0) { -#ifdef HAS_NDBM_LIB - new->type = MAPTYPE_DBM; - new->datafile = a2+4; - new->checkfile = pstrcat(cmd->pool, a2+4, NDBM_FILE_SUFFIX, NULL); -#else - return pstrdup(cmd->pool, "RewriteMap: cannot use NDBM mapfile, because no NDBM support compiled in"); -#endif - } - else if (strncmp(a2, "prg:", 4) == 0) { - new->type = MAPTYPE_PRG; - new->datafile = a2+4; - new->checkfile = a2+4; - } - else { - new->type = MAPTYPE_TXT; - new->datafile = a2; - new->checkfile = a2; - } - new->fpin = 0; - new->fpout = 0; - - if (new->checkfile) - if (stat(new->checkfile, &st) == -1) - return pstrcat(cmd->pool, "RewriteMap: map file or program not found:", new->checkfile, NULL); - - return NULL; -} - -static const char *cmd_rewritebase(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *a1) -{ - if (cmd->path == NULL || dconf == NULL) - return "RewriteBase: only valid in per-directory config files"; - if (a1[0] != '/') - return "RewriteBase: argument is not a valid URL"; - if (a1[0] == '\0') - return "RewriteBase: empty URL not allowed"; - - dconf->baseurl = pstrdup(cmd->pool, a1); - - return NULL; -} - -static const char *cmd_rewritecond(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str) -{ - rewrite_server_conf *sconf; - rewritecond_entry *new; - regex_t *regexp; - char *a1; - char *a2; - char *a3; - char *cp; - const char *err; - int rc; - - sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); - - /* make a new entry in the internal temporary rewrite rule list */ - if (cmd->path == NULL) /* is server command */ - new = push_array(sconf->rewriteconds); - else /* is per-directory command */ - new = push_array(dconf->rewriteconds); - - /* parse the argument line ourself */ - if (parseargline(str, &a1, &a2, &a3)) - return pstrcat(cmd->pool, "RewriteCond: bad argument line '", str, "'\n", NULL); - - /* arg1: the input string */ - new->input = pstrdup(cmd->pool, a1); - - /* arg3: optional flags field - (this have to be first parsed, because we need to - know if the regex should be compiled with ICASE!) */ - new->flags = CONDFLAG_NONE; - if (a3 != NULL) { - if ((err = cmd_rewritecond_parseflagfield(cmd->pool, new, a3)) != NULL) - return err; - } - - /* arg2: the pattern - try to compile the regexp to test if is ok */ - cp = a2; - if (cp[0] == '!') { - new->flags |= CONDFLAG_NOTMATCH; - cp++; - } - - /* now be careful: Under the POSIX regex library - we can compile the pattern for case-insensitive matching, - under the old V8 library we have to do it self via a hack */ - if (new->flags & CONDFLAG_NOCASE) - rc = ((regexp = pregcomp(cmd->pool, cp, REG_EXTENDED|REG_ICASE)) == NULL); - else - rc = ((regexp = pregcomp(cmd->pool, cp, REG_EXTENDED)) == NULL); - if (rc) - return pstrcat(cmd->pool, "RewriteCond: cannot compile regular expression '", a2, "'\n", NULL); - new->pattern = pstrdup(cmd->pool, cp); - new->regexp = regexp; - - return NULL; -} - -static const char *cmd_rewritecond_parseflagfield(pool *p, rewritecond_entry *cfg, char *str) -{ - char *cp; - char *cp1; - char *cp2; - char *cp3; - char *key; - char *val; - const char *err; - - if (str[0] != '[' || str[strlen(str)-1] != ']') - return pstrdup(p, "RewriteCond: bad flag delimiters"); - - cp = str+1; - str[strlen(str)-1] = ','; /* for simpler parsing */ - for ( ; *cp != '\0'; ) { - /* skip whitespaces */ - for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++) - ; - if (*cp == '\0') - break; - cp1 = cp; - if ((cp2 = strchr(cp, ',')) != NULL) { - cp = cp2+1; - for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--) - ; - *cp2 = '\0'; - if ((cp3 = strchr(cp1, '=')) != NULL) { - *cp3 = '\0'; - key = cp1; - val = cp3+1; - } - else { - key = cp1; - val = ""; - } - if ((err = cmd_rewritecond_setflag(p, cfg, key, val)) != NULL) - return err; - } - else - break; - } - - return NULL; -} - -static const char *cmd_rewritecond_setflag(pool *p, rewritecond_entry *cfg, char *key, char *val) -{ - if ( strcasecmp(key, "nocase") == 0 - || strcasecmp(key, "NC") == 0 ) { - cfg->flags |= CONDFLAG_NOCASE; - } - else if ( strcasecmp(key, "ornext") == 0 - || strcasecmp(key, "OR") == 0 ) { - cfg->flags |= CONDFLAG_ORNEXT; - } - else { - return pstrcat(p, "RewriteCond: unknown flag '", key, "'\n", NULL); - } - return NULL; -} - -/* NON static */ -const char *cmd_rewriterule(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str) -{ - rewrite_server_conf *sconf; - rewriterule_entry *new; - regex_t *regexp; - char *a1; - char *a2; - char *a3; - char *cp; - const char *err; - - sconf = (rewrite_server_conf *)get_module_config(cmd->server->module_config, &rewrite_module); - - /* make a new entry in the internal rewrite rule list */ - if (cmd->path == NULL) /* is server command */ - new = push_array(sconf->rewriterules); - else /* is per-directory command */ - new = push_array(dconf->rewriterules); - - /* parse the argument line ourself */ - if (parseargline(str, &a1, &a2, &a3)) - return pstrcat(cmd->pool, "RewriteRule: bad argument line '", str, "'\n", NULL); - - /* arg1: the pattern - try to compile the regexp to test if is ok */ - new->flags = RULEFLAG_NONE; - cp = a1; - if (cp[0] == '!') { - new->flags |= RULEFLAG_NOTMATCH; - cp++; - } - if ((regexp = pregcomp(cmd->pool, cp, REG_EXTENDED)) == NULL) - return pstrcat(cmd->pool, "RewriteRule: cannot compile regular expression '", a1, "'\n", NULL); - new->pattern = pstrdup(cmd->pool, cp); - new->regexp = regexp; - - /* arg2: the output string - replace the $<N> by \<n> which is needed by the currently - used Regular Expression library */ - new->output = pstrdup(cmd->pool, a2); - - /* arg3: optional flags field */ - new->forced_mimetype = NULL; - new->forced_responsecode = HTTP_MOVED_TEMPORARILY; - new->env[0] = NULL; - new->skip = 0; - if (a3 != NULL) { - if ((err = cmd_rewriterule_parseflagfield(cmd->pool, new, a3)) != NULL) - return err; - } - - /* now, if the server or per-dir config holds an - array of RewriteCond entries, we take it for us - and clear the array */ - if (cmd->path == NULL) { /* is server command */ - new->rewriteconds = sconf->rewriteconds; - sconf->rewriteconds = make_array(cmd->pool, 2, sizeof(rewritecond_entry)); - } - else { /* is per-directory command */ - new->rewriteconds = dconf->rewriteconds; - dconf->rewriteconds = make_array(cmd->pool, 2, sizeof(rewritecond_entry)); - } - - return NULL; -} - -static const char *cmd_rewriterule_parseflagfield(pool *p, rewriterule_entry *cfg, char *str) -{ - char *cp; - char *cp1; - char *cp2; - char *cp3; - char *key; - char *val; - const char *err; - - if (str[0] != '[' || str[strlen(str)-1] != ']') - return pstrdup(p, "RewriteRule: bad flag delimiters"); - - cp = str+1; - str[strlen(str)-1] = ','; /* for simpler parsing */ - for ( ; *cp != '\0'; ) { - /* skip whitespaces */ - for ( ; (*cp == ' ' || *cp == '\t') && *cp != '\0'; cp++) - ; - if (*cp == '\0') - break; - cp1 = cp; - if ((cp2 = strchr(cp, ',')) != NULL) { - cp = cp2+1; - for ( ; (*(cp2-1) == ' ' || *(cp2-1) == '\t'); cp2--) - ; - *cp2 = '\0'; - if ((cp3 = strchr(cp1, '=')) != NULL) { - *cp3 = '\0'; - key = cp1; - val = cp3+1; - } - else { - key = cp1; - val = ""; - } - if ((err = cmd_rewriterule_setflag(p, cfg, key, val)) != NULL) - return err; - } - else - break; - } - - return NULL; -} - -static const char *cmd_rewriterule_setflag(pool *p, rewriterule_entry *cfg, char *key, char *val) -{ - int status = 0; - int i; - - if ( strcasecmp(key, "redirect") == 0 - || strcasecmp(key, "R") == 0 ) { - cfg->flags |= RULEFLAG_FORCEREDIRECT; - if (strlen(val) > 0) { - if (strcasecmp(val, "permanent") == 0) - status = HTTP_MOVED_PERMANENTLY; - else if (strcasecmp(val, "temp") == 0) - status = HTTP_MOVED_TEMPORARILY; - else if (strcasecmp(val, "seeother") == 0) - status = HTTP_SEE_OTHER; - else if (isdigit(*val)) - status = atoi(val); - if (!is_HTTP_REDIRECT(status)) - return pstrdup(p, "RewriteRule: invalid HTTP response code for flag 'R'"); - cfg->forced_responsecode = status; - } - } - else if ( strcasecmp(key, "last") == 0 - || strcasecmp(key, "L") == 0 ) { - cfg->flags |= RULEFLAG_LASTRULE; - } - else if ( strcasecmp(key, "next") == 0 - || strcasecmp(key, "N") == 0 ) { - cfg->flags |= RULEFLAG_NEWROUND; - } - else if ( strcasecmp(key, "chain") == 0 - || strcasecmp(key, "C") == 0 ) { - cfg->flags |= RULEFLAG_CHAIN; - } - else if ( strcasecmp(key, "type") == 0 - || strcasecmp(key, "T") == 0 ) { - cfg->forced_mimetype = pstrdup(p, val); - } - else if ( strcasecmp(key, "env") == 0 - || strcasecmp(key, "E") == 0 ) { - for (i = 0; (cfg->env[i] != NULL) && (i < MAX_ENV_FLAGS); i++) - ; - if (i < MAX_ENV_FLAGS) { - cfg->env[i] = pstrdup(p, val); - cfg->env[i+1] = NULL; - } - else - return pstrdup(p, "RewriteRule: to much environment flags 'E'"); - } - else if ( strcasecmp(key, "nosubreq") == 0 - || strcasecmp(key, "NS") == 0 ) { - cfg->flags |= RULEFLAG_IGNOREONSUBREQ; - } - else if ( strcasecmp(key, "proxy") == 0 - || strcasecmp(key, "P") == 0 ) { - cfg->flags |= RULEFLAG_PROXY; - } - else if ( strcasecmp(key, "passthrough") == 0 - || strcasecmp(key, "PT") == 0 ) { - cfg->flags |= RULEFLAG_PASSTHROUGH; - } - else if ( strcasecmp(key, "skip") == 0 - || strcasecmp(key, "S") == 0 ) { - cfg->skip = atoi(val); - } - else if ( strcasecmp(key, "forbidden") == 0 - || strcasecmp(key, "F") == 0 ) { - cfg->flags |= RULEFLAG_FORBIDDEN; - } - else if ( strcasecmp(key, "gone") == 0 - || strcasecmp(key, "G") == 0 ) { - cfg->flags |= RULEFLAG_GONE; - } - else if ( strcasecmp(key, "qsappend") == 0 - || strcasecmp(key, "QSA") == 0 ) { - cfg->flags |= RULEFLAG_QSAPPEND; - } - else { - return pstrcat(p, "RewriteRule: unknown flag '", key, "'\n", NULL); - } - return NULL; -} - - -/* -** -** module initialisation -** [called from read_config() after all -** config commands were already called] -** -*/ - -static void init_module(server_rec *s, pool *p) -{ - /* step through the servers and - - open eachs rewriting logfile - - open the RewriteMap prg:xxx programs */ - for (; s; s = s->next) { - open_rewritelog(s, p); - run_rewritemap_programs(s, p); - } - - /* create the lookup cache */ - cachep = init_cache(p); - - /* check if proxy module is available */ - proxy_available = is_proxy_available(s); - - /* precompile a static pattern - for the txt mapfile parsing */ - lookup_map_txtfile_regexp = pregcomp(p, MAPFILE_PATTERN, REG_EXTENDED); -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | runtime hooks -** | | -** +-------------------------------------------------------+ -*/ - - -/* -** -** URI-to-filename hook -** -** [used for the rewriting engine triggered by -** the per-server 'RewriteRule' directives] -** -*/ - -static int hook_uri2file(request_rec *r) -{ - void *sconf; - rewrite_server_conf *conf; - char *var; - char *thisserver, *thisport, *thisurl; - char buf[512]; - char docroot[512]; - char *cp, *cp2; - struct stat finfo; - int n; - int l; - - /* - * retrieve the config structures - */ - sconf = r->server->module_config; - conf = (rewrite_server_conf *)get_module_config(sconf, &rewrite_module); - - /* - * only do something under runtime if the engine is really enabled, - * else return immediately! - */ - if (conf->state == ENGINE_DISABLED) - return DECLINED; - - /* - * add the SCRIPT_URL variable to the env. this is a bit complicated - * due to the fact that apache uses subrequests and internal redirects - */ - - if (r->main == NULL) { - var = pstrcat(r->pool, "REDIRECT_", ENVVAR_SCRIPT_URL, NULL); - var = table_get(r->subprocess_env, var); - if (var == NULL) - table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, pstrdup(r->pool, r->uri)); - else - table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, pstrdup(r->pool, var)); - } - else { - var = table_get(r->main->subprocess_env, ENVVAR_SCRIPT_URL); - table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, pstrdup(r->pool, var)); - } - - /* - * create the SCRIPT_URI variable for the env - */ - - /* add the canonical URI of this URL */ - thisserver = r->server->server_hostname; -#ifdef APACHE_SSL - if (((!r->connection->client->ssl) && (r->server->port == DEFAULT_PORT)) || - ((r->connection->client->ssl) && (r->server->port == 443))) -#else - if (r->server->port == DEFAULT_PORT) -#endif - thisport = ""; - else { - ap_snprintf(buf, sizeof(buf), ":%u", r->server->port); - thisport = pstrdup(r->pool, buf); - } - thisurl = table_get(r->subprocess_env, ENVVAR_SCRIPT_URL); - - /* set the variable */ -#ifdef APACHE_SSL - var = pstrcat(r->pool, http_method(r), "://", thisserver, thisport, thisurl, NULL); -#else - var = pstrcat(r->pool, "http://", thisserver, thisport, thisurl, NULL); -#endif - table_set(r->subprocess_env, ENVVAR_SCRIPT_URI, pstrdup(r->pool, var)); - - - /* if filename was not initially set, - we start with the requested URI */ - if (r->filename == NULL) { - r->filename = pstrdup(r->pool, r->uri); - rewritelog(r, 2, "init rewrite engine with requested uri %s", r->filename); - } - - /* - * now apply the rules ... - */ - if (apply_rewrite_list(r, conf->rewriterules, NULL)) { - - if (strlen(r->filename) > 6 && - strncmp(r->filename, "proxy:", 6) == 0) { - /* it should be go on as an internal proxy request */ - - /* check if the proxy module is enabled, so - we can actually use it! */ - if (!proxy_available) { - log_reason("attempt to make remote request from mod_rewrite " - "without proxy enabled", r->filename, r); - return FORBIDDEN; - } - - /* make sure the QUERY_STRING and - PATH_INFO parts get incorporated */ - r->filename = pstrcat(r->pool, r->filename, - r->path_info ? r->path_info : "", - r->args ? "?" : NULL, r->args, - NULL); - - /* now make sure the request gets handled by the - proxy handler */ - r->proxyreq = 1; - r->handler = "proxy-server"; - - rewritelog(r, 1, "go-ahead with proxy request %s [OK]", r->filename); - return OK; - } - else if ( (strlen(r->filename) > 7 && - strncasecmp(r->filename, "http://", 7) == 0) - || (strlen(r->filename) > 8 && - strncasecmp(r->filename, "https://", 8) == 0) - || (strlen(r->filename) > 9 && - strncasecmp(r->filename, "gopher://", 9) == 0) - || (strlen(r->filename) > 6 && - strncasecmp(r->filename, "ftp://", 6) == 0) ) { - /* it was finally rewritten to a remote URL */ - - /* skip 'scheme:' */ - for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++) - ; - /* skip '://' */ - cp += 3; - /* skip host part */ - for ( ; *cp != '/' && *cp != '\0'; cp++) - ; - if (*cp != '\0') { - rewritelog(r, 1, "escaping %s for redirect", r->filename); - cp2 = escape_uri(r->pool, cp); - *cp = '\0'; - r->filename = pstrcat(r->pool, r->filename, cp2, NULL); - } - - /* append the QUERY_STRING part */ - if (r->args != NULL) - r->filename = pstrcat(r->pool, r->filename, "?", r->args, NULL); - - /* determine HTTP redirect response code */ - if (is_HTTP_REDIRECT(r->status)) { - n = r->status; - r->status = HTTP_OK; /* make Apache kernel happy */ - } - else - n = REDIRECT; - - /* now do the redirection */ - table_set(r->headers_out, "Location", r->filename); - rewritelog(r, 1, "redirect to %s [REDIRECT/%d]", r->filename, n); - return n; - } - else if (strlen(r->filename) > 10 && - strncmp(r->filename, "forbidden:", 10) == 0) { - /* This URLs is forced to be forbidden for the requester */ - return FORBIDDEN; - } - else if (strlen(r->filename) > 5 && - strncmp(r->filename, "gone:", 5) == 0) { - /* This URLs is forced to be gone */ - return HTTP_GONE; - } - else if (strlen(r->filename) > 12 && - strncmp(r->filename, "passthrough:", 12) == 0) { - /* Hack because of underpowered API: passing the current - rewritten filename through to other URL-to-filename handlers - just as it were the requested URL. This is to enable - post-processing by mod_alias, etc. which always act on - r->uri! The difference here is: We do not try to - add the document root */ - r->uri = pstrdup(r->pool, r->filename+12); - return DECLINED; - } - else { - /* it was finally rewritten to a local path */ - - /* expand "/~user" prefix */ - r->filename = expand_tildepaths(r, r->filename); - - rewritelog(r, 2, "local path result: %s", r->filename); - - /* the filename has to start with a slash! */ - if (r->filename[0] != '/') - return BAD_REQUEST; - - /* if there is no valid prefix, we have - to emulate the translator from the core and - prefix the filename with document_root - - NOTICE: - We cannot leave out the prefix_stat because - - when we always prefix with document_root - then no absolute path can be created, e.g. via - emulating a ScriptAlias directive, etc. - - when we always NOT prefix with document_root - then the files under document_root have to - be references directly and document_root - gets never used and will be a dummy parameter - - this is also bad - - BUT: - Under real Unix systems this is no problem, - because we only do stat() on the first directory - and this gets cached by the kernel for along time! - */ - n = prefix_stat(r->filename, &finfo); - if (n == 0) { - if ((cp = document_root(r)) != NULL) { - strncpy(docroot, cp, sizeof(docroot)-1); - EOS_PARANOIA(docroot); - - /* always NOT have a trailing slash */ - l = strlen(docroot); - if (docroot[l-1] == '/') { - docroot[l-1] = '\0'; - } - if (r->server->path && !strncmp(r->filename, r->server->path, r->server->pathlen)) - r->filename = pstrcat(r->pool, docroot, (r->filename + r->server->pathlen), NULL); - else - r->filename = pstrcat(r->pool, docroot, r->filename, NULL); - rewritelog(r, 2, "prefixed with document_root to %s", r->filename); - } - } - - rewritelog(r, 1, "go-ahead with %s [OK]", r->filename); - return OK; - } - } - else { - rewritelog(r, 1, "pass through %s", r->filename); - return DECLINED; - } -} - - -/* -** -** MIME-type hook -** -** [used to support the forced-MIME-type feature] -** -*/ - -static int hook_mimetype(request_rec *r) -{ - char *t; - - /* now check if we have to force a MIME-type */ - t = table_get(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR); - if (t == NULL) - return DECLINED; - else { - rewritelog(r, 1, "force filename %s to have MIME-type '%s'", r->filename, t); - r->content_type = t; - return OK; - } -} - - -/* -** -** Fixup hook -** -** [used for the rewriting engine triggered by -** the per-directory 'RewriteRule' directives] -** -*/ - -static int hook_fixup(request_rec *r) -{ - rewrite_perdir_conf *dconf; - char *cp; - char *cp2; - char *prefix; - int l; - int n; - char *ofilename; - - dconf = (rewrite_perdir_conf *)get_module_config(r->per_dir_config, &rewrite_module); - - /* if there is no per-dir config we return immediately */ - if (dconf == NULL) - return DECLINED; - - /* we shouldn't do anything in subrequests */ - if (r->main != NULL) - return DECLINED; - - /* if there are no real (i.e. no RewriteRule directives!) - per-dir config of us, we return also immediately */ - if (dconf->directory == NULL) - return DECLINED; - - /* - * only do something under runtime if the engine is really enabled, - * for this directory, else return immediately! - */ - if (!(allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER))) { - /* FollowSymLinks is mandatory! */ - log_reason("Options FollowSymLinks or SymLinksIfOwnerMatch is off which implies that RewriteRule directive is forbidden", r->filename, r); - return FORBIDDEN; - } - else { - /* FollowSymLinks is given, but the user can - still turn off the rewriting engine */ - if (dconf->state == ENGINE_DISABLED) - return DECLINED; - } - - /* - * remember the current filename before rewriting for later check - * to prevent deadlooping because of internal redirects - * on final URL/filename which can be equal to the inital one. - */ - ofilename = r->filename; - - /* - * now apply the rules ... - */ - if (apply_rewrite_list(r, dconf->rewriterules, dconf->directory)) { - - if (strlen(r->filename) > 6 && - strncmp(r->filename, "proxy:", 6) == 0) { - /* it should go on as an internal proxy request */ - - /* make sure the QUERY_STRING and - PATH_INFO parts get incorporated */ - r->filename = pstrcat(r->pool, r->filename, - /* r->path_info was already - appended by the rewriting engine - because of the per-dir context! */ - r->args ? "?" : NULL, r->args, - NULL); - - /* now make sure the request gets handled by the - proxy handler */ - r->proxyreq = 1; - r->handler = "proxy-server"; - - rewritelog(r, 1, "[per-dir %s] go-ahead with proxy request %s [OK]", dconf->directory, r->filename); - return OK; - } - else if ( (strlen(r->filename) > 7 && - strncasecmp(r->filename, "http://", 7) == 0) - || (strlen(r->filename) > 8 && - strncasecmp(r->filename, "https://", 8) == 0) - || (strlen(r->filename) > 9 && - strncasecmp(r->filename, "gopher://", 9) == 0) - || (strlen(r->filename) > 6 && - strncasecmp(r->filename, "ftp://", 6) == 0) ) { - /* it was finally rewritten to a remote URL */ - - /* because we are in a per-dir context - first try to replace the directory with its base-URL - if there is a base-URL available */ - if (dconf->baseurl != NULL) { - /* skip 'scheme:' */ - for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++) - ; - /* skip '://' */ - cp += 3; - if ((cp = strchr(cp, '/')) != NULL) { - rewritelog(r, 2, "[per-dir %s] trying to replace prefix %s with %s", dconf->directory, dconf->directory, dconf->baseurl); - cp2 = subst_prefix_path(r, cp, dconf->directory, dconf->baseurl); - if (strcmp(cp2, cp) != 0) { - *cp = '\0'; - r->filename = pstrcat(r->pool, r->filename, cp2, NULL); - } - } - } - - /* now prepare the redirect... */ - - /* skip 'scheme:' */ - for (cp = r->filename; *cp != ':' && *cp != '\0'; cp++) - ; - /* skip '://' */ - cp += 3; - /* skip host part */ - for ( ; *cp != '/' && *cp != '\0'; cp++) - ; - if (*cp != '\0') { - rewritelog(r, 1, "[per-dir %s] escaping %s for redirect", dconf->directory, r->filename); - cp2 = escape_uri(r->pool, cp); - *cp = '\0'; - r->filename = pstrcat(r->pool, r->filename, cp2, NULL); - } - - /* append the QUERY_STRING part */ - if (r->args != NULL) - r->filename = pstrcat(r->pool, r->filename, "?", r->args, NULL); - - /* determine HTTP redirect response code */ - if (is_HTTP_REDIRECT(r->status)) { - n = r->status; - r->status = HTTP_OK; /* make Apache kernel happy */ - } - else - n = REDIRECT; - - /* now do the redirection */ - table_set(r->headers_out, "Location", r->filename); - rewritelog(r, 1, "[per-dir %s] redirect to %s [REDIRECT/%d]", dconf->directory, r->filename, n); - return n; - } - else if (strlen(r->filename) > 10 && - strncmp(r->filename, "forbidden:", 10) == 0) { - /* This URLs is forced to be forbidden for the requester */ - return FORBIDDEN; - } - else if (strlen(r->filename) > 5 && - strncmp(r->filename, "gone:", 5) == 0) { - /* This URLs is forced to be gone */ - return HTTP_GONE; - } - else { - /* it was finally rewritten to a local path */ - - /* if someone used the PASSTHROUGH flag in per-dir - context we just ignore it. It is only useful - in per-server context */ - if (strlen(r->filename) > 12 && - strncmp(r->filename, "passthrough:", 12) == 0) { - r->filename = pstrdup(r->pool, r->filename+12); - } - - /* the filename has to start with a slash! */ - if (r->filename[0] != '/') - return BAD_REQUEST; - - /* Check for deadlooping: - * At this point we KNOW that at least one rewriting - * rule was applied, but when the resulting URL is - * the same as the initial URL, we are not allowed to - * use the following internal redirection stuff because - * this would lead to a deadloop. - */ - if (strcmp(r->filename, ofilename) == 0) { - rewritelog(r, 1, "[per-dir %s] initial URL equal rewritten URL: %s [IGNORING REWRITE]", dconf->directory, r->filename); - return OK; - } - - /* if there is a valid base-URL then substitute - the per-dir prefix with this base-URL if the - current filename still is inside this per-dir - context. If not then treat the result as a - plain URL */ - if (dconf->baseurl != NULL) { - rewritelog(r, 2, "[per-dir %s] trying to replace prefix %s with %s", dconf->directory, dconf->directory, dconf->baseurl); - r->filename = subst_prefix_path(r, r->filename, dconf->directory, dconf->baseurl); - } - else { - /* if no explicit base-URL exists we assume - that the directory prefix is also a valid URL - for this webserver and only try to remove the - document_root if it is prefix */ - - if ((cp = document_root(r)) != NULL) { - prefix = pstrdup(r->pool, cp); - /* always NOT have a trailing slash */ - l = strlen(prefix); - if (prefix[l-1] == '/') { - prefix[l-1] = '\0'; - l--; - } - if (strncmp(r->filename, prefix, l) == 0) { - rewritelog(r, 2, "[per-dir %s] strip document_root prefix: %s -> %s", dconf->directory, r->filename, r->filename+l); - r->filename = pstrdup(r->pool, r->filename+l); - } - } - } - - /* now initiate the internal redirect */ - rewritelog(r, 1, "[per-dir %s] internal redirect with %s [INTERNAL REDIRECT]", dconf->directory, r->filename); - r->filename = pstrcat(r->pool, "redirect:", r->filename, NULL); - r->handler = "redirect-handler"; - return OK; - } - } - else { - rewritelog(r, 1, "[per-dir %s] pass through %s", dconf->directory, r->filename); - return DECLINED; - } -} - - -/* -** -** Content-Handlers -** -** [used for redirect support] -** -*/ - -static int handler_redirect(request_rec *r) -{ - /* just make sure that we are really meant! */ - if (strncmp(r->filename, "redirect:", 9) != 0) - return DECLINED; - - /* now do the internal redirect */ - internal_redirect(pstrcat(r->pool, r->filename+9, - r->args ? "?" : NULL, r->args, NULL), r); - - /* and return gracefully */ - return OK; -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | rewriting engine -** | | -** +-------------------------------------------------------+ -*/ - - -static int apply_rewrite_list(request_rec *r, array_header *rewriterules, char *perdir) -{ - rewriterule_entry *entries; - rewriterule_entry *p; - int i; - int changed; - int rc; - int s; - - entries = (rewriterule_entry *)rewriterules->elts; - changed = 0; - loop: - for (i = 0; i < rewriterules->nelts; i++) { - p = &entries[i]; - - /* ignore this rule on subrequests if we are explicitly asked to do so - or this is a proxy throughput or a forced redirect rule */ - if (r->main != NULL && - (p->flags & RULEFLAG_IGNOREONSUBREQ || - p->flags & RULEFLAG_PROXY || - p->flags & RULEFLAG_FORCEREDIRECT )) - continue; - - /* apply the current rule */ - rc = apply_rewrite_rule(r, p, perdir); - if (rc) { - if (rc != 2) /* not a match-only rule */ - changed = 1; - if (p->flags & RULEFLAG_PASSTHROUGH) { - rewritelog(r, 2, "forcing '%s' to get passed through to next URI-to-filename handler", r->filename); - r->filename = pstrcat(r->pool, "passthrough:", r->filename, NULL); - changed = 1; - break; - } - if (p->flags & RULEFLAG_FORBIDDEN) { - rewritelog(r, 2, "forcing '%s' to be forbidden", r->filename); - r->filename = pstrcat(r->pool, "forbidden:", r->filename, NULL); - changed = 1; - break; - } - if (p->flags & RULEFLAG_GONE) { - rewritelog(r, 2, "forcing '%s' to be gone", r->filename); - r->filename = pstrcat(r->pool, "gone:", r->filename, NULL); - changed = 1; - break; - } - if (p->flags & RULEFLAG_PROXY) - break; - if (p->flags & RULEFLAG_LASTRULE) - break; - if (p->flags & RULEFLAG_NEWROUND) - goto loop; - - /* if we are forced to skip N next rules, do it now */ - if (p->skip > 0) { - s = p->skip; - while ( i < rewriterules->nelts - && s > 0) { - i++; - p = &entries[i]; - s--; - } - } - } - else { - /* if current rule is chained with next rule(s), - skip all this next rule(s) */ - while ( i < rewriterules->nelts - && p->flags & RULEFLAG_CHAIN) { - i++; - p = &entries[i]; - } - } - } - return changed; -} - -static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p, char *perdir) -{ - char *uri; - char *output; - int flags; - char newuri[MAX_STRING_LEN]; - char env[MAX_STRING_LEN]; - char port[32]; - char env2[MAX_STRING_LEN]; - regex_t *regexp; - regmatch_t regmatch[10]; - int rc; - int prefixstrip; - int i; - int failed; - array_header *rewriteconds; - rewritecond_entry *conds; - rewritecond_entry *c; - - uri = r->filename; - regexp = p->regexp; - output = p->output; - flags = p->flags; - - if (perdir != NULL && r->path_info != NULL && r->path_info[0] != '\0') { - rewritelog(r, 3, "[per-dir %s] add path-info postfix: %s -> %s%s", perdir, uri, uri, r->path_info); - uri = pstrcat(r->pool, uri, r->path_info, NULL); - } - - prefixstrip = 0; - if (perdir != NULL) { - /* this is a per-directory match */ - if ( strlen(uri) >= strlen(perdir) - && strncmp(uri, perdir, strlen(perdir)) == 0) { - rewritelog(r, 3, "[per-dir %s] strip per-dir prefix: %s -> %s", perdir, uri, uri+strlen(perdir)); - uri = uri+strlen(perdir); - prefixstrip = 1; - } - } - - if (perdir != NULL) - rewritelog(r, 3, "[per-dir %s] applying pattern '%s' to uri '%s'", perdir, p->pattern, uri); - - rc = (regexec(regexp, uri, regexp->re_nsub+1, regmatch, 0) == 0); /* try to match the pattern */ - if (( rc && !(p->flags & RULEFLAG_NOTMATCH)) || - (!rc && (p->flags & RULEFLAG_NOTMATCH)) ) { - - /* ok, the pattern matched, but we now additionally have to check - for any preconditions which have to be also true. We do this - at this very late stage to avoid unnessesary checks which - slow down the rewriting engine!! */ - rewriteconds = p->rewriteconds; - conds = (rewritecond_entry *)rewriteconds->elts; - failed = 0; - for (i = 0; i < rewriteconds->nelts; i++) { - c = &conds[i]; - rc = apply_rewrite_cond(r, c, perdir); - if (c->flags & CONDFLAG_ORNEXT) { - /* there is a "or" flag */ - if (rc == 0) { - /* one cond is false, but another can be true... */ - continue; - } - else { - /* one true cond is enough, so skip the other conds - of the "ornext" chained conds */ - while ( i < rewriteconds->nelts - && c->flags & CONDFLAG_ORNEXT) { - i++; - c = &conds[i]; - } - continue; - } - } - else { - /* no "or" flag, so a single fail means total fail */ - if (rc == 0) { /* failed */ - failed = 1; - break; - } - } - } - if (failed) - return 0; /* if any condition fails this complete rule fails */ - - /* if this is a pure matching rule we return immediately */ - if (strcmp(output, "-") == 0) { - /* but before we set the env variables... */ - for (i = 0; p->env[i] != NULL; i++) { - strncpy(env2, p->env[i], sizeof(env2)-1); - EOS_PARANOIA(env2); - strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1); /* substitute in output */ - EOS_PARANOIA(env); - add_env_variable(r, env); - } - return 2; - } - - /* if this is a forced proxy request ... */ - if (p->flags & RULEFLAG_PROXY) { - if (p->flags & RULEFLAG_NOTMATCH) { - output = pstrcat(r->pool, "proxy:", output, NULL); - strncpy(newuri, output, sizeof(newuri)-1); - EOS_PARANOIA(newuri); - expand_variables_inbuffer(r, newuri, sizeof(newuri));/* expand %{...} */ - expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ - } - else { - output = pstrcat(r->pool, "proxy:", output, NULL); - strncpy(newuri, pregsub(r->pool, output, uri, regexp->re_nsub+1, regmatch), sizeof(newuri)-1); /* substitute in output */ - EOS_PARANOIA(newuri); - for (i = 0; p->env[i] != NULL; i++) { - strncpy(env2, p->env[i], sizeof(env2)-1); - EOS_PARANOIA(env2); - strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1); /* substitute in output */ - EOS_PARANOIA(env); - add_env_variable(r, env); - } - expand_variables_inbuffer(r, newuri, sizeof(newuri)); /* expand %{...} */ - expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ - } - if (perdir == NULL) - rewritelog(r, 2, "rewrite %s -> %s", r->filename, newuri); - else - rewritelog(r, 2, "[per-dir %s] rewrite %s -> %s", perdir, r->filename, newuri); - r->filename = pstrdup(r->pool, newuri); - return 1; - } - - /* if this is an implicit redirect in a per-dir rule */ - i = strlen(output); - if (perdir != NULL - && ( (i > 7 && strncasecmp(output, "http://", 7) == 0) - || (i > 8 && strncasecmp(output, "https://", 8) == 0) - || (i > 9 && strncasecmp(output, "gopher://", 9) == 0) - || (i > 6 && strncasecmp(output, "ftp://", 6) == 0) ) ) { - if (p->flags & RULEFLAG_NOTMATCH) { - strncpy(newuri, output, sizeof(newuri)-1); - EOS_PARANOIA(newuri); - expand_variables_inbuffer(r, newuri, sizeof(newuri));/* expand %{...} */ - expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ - } - else { - strncpy(newuri, pregsub(r->pool, output, uri, regexp->re_nsub+1, regmatch), sizeof(newuri)-1); /* substitute in output */ - EOS_PARANOIA(newuri); - for (i = 0; p->env[i] != NULL; i++) { - strncpy(env2, p->env[i], sizeof(env2)-1); - EOS_PARANOIA(env2); - strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1); /* substitute in output */ - EOS_PARANOIA(env); - add_env_variable(r, env); - } - expand_variables_inbuffer(r, newuri, sizeof(newuri));/* expand %{...} */ - expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ - } - rewritelog(r, 2, "[per-dir %s] redirect %s -> %s", perdir, r->filename, newuri); - r->filename = pstrdup(r->pool, newuri); - splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND); - r->status = p->forced_responsecode; - return 1; - } - - /* add again the previously stripped perdir prefix if the new - URI is not a new one (i.e. prefixed by a slash which means - that it is not for this per-dir context) */ - if (prefixstrip && output[0] != '/') { - rewritelog(r, 3, "[per-dir %s] add per-dir prefix: %s -> %s%s", perdir, output, perdir, output); - output = pstrcat(r->pool, perdir, output, NULL); - } - - if (p->flags & RULEFLAG_NOTMATCH) { - /* just overtake the URI */ - strncpy(newuri, output, sizeof(newuri)-1); - EOS_PARANOIA(newuri); - } - else { - /* substitute in output */ - strncpy(newuri, pregsub(r->pool, output, uri, regexp->re_nsub+1, regmatch), sizeof(newuri)-1); /* substitute in output */ - EOS_PARANOIA(newuri); - for (i = 0; p->env[i] != NULL; i++) { - strncpy(env2, p->env[i], sizeof(env2)-1); - EOS_PARANOIA(env2); - strncpy(env, pregsub(r->pool, env2, uri, regexp->re_nsub+1, regmatch), sizeof(env)-1); /* substitute in output */ - EOS_PARANOIA(env); - add_env_variable(r, env); - } - } - expand_variables_inbuffer(r, newuri, sizeof(newuri)); /* expand %{...} */ - expand_map_lookups(r, newuri, sizeof(newuri)); /* expand ${...} */ - - if (perdir == NULL) - rewritelog(r, 2, "rewrite %s -> %s", uri, newuri); - else - rewritelog(r, 2, "[per-dir %s] rewrite %s -> %s", perdir, uri, newuri); - - r->filename = pstrdup(r->pool, newuri); - - /* reduce http[s]://<ourhost>[:<port>] */ - reduce_uri(r); - - /* split out on-the-fly generated QUERY_STRING '....?xxxxx&xxxx...' */ - splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND); - - /* if a MIME-type should be later forced for this URL, then remember this */ - if (p->forced_mimetype != NULL) { - table_set(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR, p->forced_mimetype); - if (perdir == NULL) - rewritelog(r, 2, "remember %s to have MIME-type '%s'", r->filename, p->forced_mimetype); - else - rewritelog(r, 2, "[per-dir %s] remember %s to have MIME-type '%s'", perdir, r->filename, p->forced_mimetype); - } - - /* if we are forced to do a explicit redirect by [R] flag - and the current URL still is not a fully qualified one we - finally prefix it with http[s]://<ourname> explicitly */ - if (flags & RULEFLAG_FORCEREDIRECT) { - r->status = p->forced_responsecode; - if ( !(strlen(r->filename) > 7 && - strncasecmp(r->filename, "http://", 7) == 0) - && !(strlen(r->filename) > 8 && - strncasecmp(r->filename, "https://", 8) == 0) - && !(strlen(r->filename) > 9 && - strncasecmp(r->filename, "gopher://", 9) == 0) - && !(strlen(r->filename) > 6 && - strncasecmp(r->filename, "ftp://", 6) == 0) ) { - -#ifdef APACHE_SSL - if ((!r->connection->client->ssl && r->server->port == DEFAULT_PORT) || - ( r->connection->client->ssl && r->server->port == 443) ) -#else - if (r->server->port == DEFAULT_PORT) -#endif - port[0] = '\0'; - else - ap_snprintf(port, sizeof(port), ":%u", r->server->port); - if (r->filename[0] == '/') -#ifdef APACHE_SSL - ap_snprintf(newuri, sizeof(newuri), "%s://%s%s%s", http_method(r), r->server->server_hostname, port, r->filename); -#else - ap_snprintf(newuri, sizeof(newuri), "http://%s%s%s", r->server->server_hostname, port, r->filename); -#endif - else -#ifdef APACHE_SSL - ap_snprintf(newuri, sizeof(newuri), "%s://%s%s/%s", http_method(r), r->server->server_hostname, port, r->filename); -#else - ap_snprintf(newuri, sizeof(newuri), "http://%s%s/%s", r->server->server_hostname, port, r->filename); -#endif - if (perdir == NULL) - rewritelog(r, 2, "prepare forced redirect %s -> %s", r->filename, newuri); - else - rewritelog(r, 2, "[per-dir %s] prepare forced redirect %s -> %s", perdir, r->filename, newuri); - r->filename = pstrdup(r->pool, newuri); - return 1; - } - } - - return 1; - } - return 0; -} - -static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p, char *perdir) -{ - char *input; - int rc; - struct stat sb; - request_rec *rsub; - - /* first, we have to expand the input string to match */ - input = expand_variables(r, p->input); - - rc = 0; - if (strcmp(p->pattern, "-f") == 0) { - if (stat(input, &sb) == 0) - if (S_ISREG(sb.st_mode)) - rc = 1; - } - else if (strcmp(p->pattern, "-s") == 0) { - if (stat(input, &sb) == 0) - if (S_ISREG(sb.st_mode) && sb.st_size > 0) - rc = 1; - } - else if (strcmp(p->pattern, "-l") == 0) { -#ifndef __EMX__ -/* OS/2 dosen't support links. */ - if (stat(input, &sb) == 0) - if (S_ISLNK(sb.st_mode)) - rc = 1; -#endif - } - else if (strcmp(p->pattern, "-d") == 0) { - if (stat(input, &sb) == 0) - if (S_ISDIR(sb.st_mode)) - rc = 1; - } - else if (strcmp(p->pattern, "-U") == 0) { - /* avoid infinite subrequest recursion */ - if (strlen(input) > 0 /* nonempty path, and */ - && ( r->main == NULL /* - either not in a subrequest */ - || ( r->main->uri != NULL /* - or in a subrequest...*/ - && r->uri != NULL /* ...and then URIs aren't NULL... */ - /* ...and sub and main URIs differ */ - && strcmp(r->main->uri, r->uri) != 0) ) ) { - - /* run a URI-based subrequest */ - rsub = sub_req_lookup_uri(input, r); - - /* URI exists for any result up to 3xx, redirects allowed */ - if (rsub->status < 400) - rc = 1; - - /* log it */ - rewritelog(r, 5, "RewriteCond URI (-U) check: path=%s -> status=%d", input, rsub->status); - - /* cleanup by destroying the subrequest */ - destroy_sub_req(rsub); - } - } - else if (strcmp(p->pattern, "-F") == 0) { - /* avoid infinite subrequest recursion */ - if (strlen(input) > 0 /* nonempty path, and */ - && ( r->main == NULL /* - either not in a subrequest */ - || ( r->main->uri != NULL /* - or in a subrequest...*/ - && r->uri != NULL /* ...and then URIs aren't NULL... */ - /* ...and sub and main URIs differ */ - && strcmp(r->main->uri, r->uri) != 0) ) ) { - - /* process a file-based subrequest: - this differs from -U in that no path translation is done. */ - rsub = sub_req_lookup_file(input, r); - - /* file exists for any result up to 2xx, no redirects */ - if (rsub->status < 300 && - /* double-check that file exists since default result is 200 */ - stat(rsub->filename, &sb) == 0) - rc = 1; - - /* log it */ - rewritelog(r, 5, "RewriteCond file (-F) check: path=%s -> file=%s status=%d", input, rsub->filename, rsub->status); - - /* cleanup by destroying the subrequest */ - destroy_sub_req(rsub); - } - } - else if (strlen(p->pattern) > 1 && *(p->pattern) == '>') { - rc = (compare_lexicography(input, p->pattern+1) == 1 ? 1 : 0); - } - else if (strlen(p->pattern) > 1 && *(p->pattern) == '<') { - rc = (compare_lexicography(input, p->pattern+1) == -1 ? 1 : 0); - } - else if (strlen(p->pattern) > 1 && *(p->pattern) == '=') { - rc = (strcmp(input, p->pattern+1) == 0 ? 1 : 0); - } - else { - /* it is really a regexp pattern, so apply it */ - rc = (regexec(p->regexp, input, 0, NULL, 0) == 0); - } - - /* if this is a non-matching regexp, just negate the result */ - if (p->flags & CONDFLAG_NOTMATCH) - rc = !rc; - - rewritelog(r, 4, "RewriteCond: input='%s' pattern='%s%s' => %s", - input, (p->flags & CONDFLAG_NOTMATCH ? "!" : ""), - p->pattern, rc ? "matched" : "not-matched"); - - /* end just return the result */ - return rc; -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | URL transformation functions -** | | -** +-------------------------------------------------------+ -*/ - - -/* -** -** split out a QUERY_STRING part from -** the current URI string -** -*/ - -static void splitout_queryargs(request_rec *r, int qsappend) -{ - char *q; - char *olduri; - - q = strchr(r->filename, '?'); - if (q != NULL) { - olduri = pstrdup(r->pool, r->filename); - *q++ = '\0'; - if (qsappend) - r->args = pstrcat(r->pool, q, "&", r->args, NULL); - else - r->args = pstrdup(r->pool, q); - if (strlen(r->args) == 0) { - r->args = NULL; - rewritelog(r, 3, "split uri=%s -> uri=%s, args=<none>", olduri, r->filename); - } - else { - if (r->args[strlen(r->args)-1] == '&') - r->args[strlen(r->args)-1] = '\0'; - rewritelog(r, 3, "split uri=%s -> uri=%s, args=%s", olduri, r->filename, r->args); - } - } - return; -} - - -/* -** -** strip 'http[s]://ourhost/' from URI -** -*/ - -static void reduce_uri(request_rec *r) -{ - char *cp; - unsigned short port; - char *portp; - char *hostp; - char *url; - char c; - char host[LONG_STRING_LEN]; - char buf[MAX_STRING_LEN]; - char *olduri; - -#ifdef APACHE_SSL - if ( (!r->connection->client->ssl && - strncasecmp(r->filename, "http://", 7) == 0) - || (r->connection->client->ssl && - strncasecmp(r->filename, "https://", 8) == 0)) { -#else - if (strncasecmp(r->filename, "http://", 7) == 0) { -#endif - /* there was really a rewrite to a remote path */ - - olduri = pstrdup(r->pool, r->filename); /* save for logging */ - - /* cut the hostname and port out of the URI */ -#ifdef APACHE_SSL - strncpy(buf, r->filename+strlen(http_method(r))+3, sizeof(buf)-1); -#else - strncpy(buf, r->filename+7, sizeof(buf)-1); -#endif - EOS_PARANOIA(buf); - hostp = buf; - for (cp = hostp; *cp != '\0' && *cp != '/' && *cp != ':'; cp++) - ; - if (*cp == ':') { - /* set host */ - *cp++ = '\0'; - strncpy(host, hostp, sizeof(host)-1); - EOS_PARANOIA(host); - /* set port */ - portp = cp; - for (; *cp != '\0' && *cp != '/'; cp++) - ; - c = *cp; - *cp = '\0'; - port = atoi(portp); - *cp = c; - /* set remaining url */ - url = cp; - } - else if (*cp == '/') { - /* set host */ - *cp = '\0'; - strncpy(host, hostp, sizeof(host)-1); - EOS_PARANOIA(host); - *cp = '/'; - /* set port */ - port = DEFAULT_PORT; - /* set remaining url */ - url = cp; - } - else { - /* set host */ - strncpy(host, hostp, sizeof(host)-1); - EOS_PARANOIA(host); - /* set port */ - port = DEFAULT_PORT; - /* set remaining url */ - url = "/"; - } - - /* now check whether we could reduce it to a local path... */ - if (is_this_our_host(r, host) && port == r->server->port) { - /* this is our host, so only the URL remains */ - r->filename = pstrdup(r->pool, url); - rewritelog(r, 3, "reduce %s -> %s", olduri, r->filename); - } - } - return; -} - - -/* -** -** Expand tilde-paths (~user) through -** Unix /etc/passwd database information -** -*/ - -static char *expand_tildepaths(request_rec *r, char *uri) -{ - char user[LONG_STRING_LEN]; - struct passwd *pw; - char *newuri; - int i, j; - - newuri = uri; - if (uri != NULL && strlen(uri) > 2 && uri[0] == '/' && uri[1] == '~') { - /* cut out the username */ - for (j = 0, i = 2; j < sizeof(user)-1 && uri[i] != '\0' && - ( (uri[i] >= '0' && uri[i] <= '9') - || (uri[i] >= 'a' && uri[i] <= 'z') - || (uri[i] >= 'A' && uri[i] <= 'Z')); ) - user[j++] = uri[i++]; - user[j] = '\0'; - - /* lookup username in systems passwd file */ - if ((pw = getpwnam(user)) != NULL) { - /* ok, user was found, so expand the ~user string */ - if (uri[i] != '\0') { - /* ~user/anything... has to be expanded */ - if (pw->pw_dir[strlen(pw->pw_dir)-1] == '/') - pw->pw_dir[strlen(pw->pw_dir)-1] = '\0'; - newuri = pstrcat(r->pool, pw->pw_dir, uri+i, NULL); - } - else { - /* only ~user has to be expanded */ - newuri = pstrdup(r->pool, pw->pw_dir); - } - } - } - return newuri; -} - - -/* -** -** mapfile expansion support -** i.e. expansion of MAP lookup directives -** ${<mapname>:<key>} in RewriteRule rhs -** -*/ - -#define limit_length(n) (n > LONG_STRING_LEN-1 ? LONG_STRING_LEN-1 : n) - -static void expand_map_lookups(request_rec *r, char *uri, int uri_len) -{ - char newuri[MAX_STRING_LEN]; - char *cpI; - char *cpIE; - char *cpO; - char *cpT; - char *cpT2; - char mapname[LONG_STRING_LEN]; - char mapkey[LONG_STRING_LEN]; - char defaultvalue[LONG_STRING_LEN]; - int n; - - cpI = uri; - cpIE = cpI+strlen(cpI); - cpO = newuri; - while (cpI < cpIE) { - if (cpI+6 < cpIE && strncmp(cpI, "${", 2) == 0) { - /* missing delimiter -> take it as plain text */ - if ( strchr(cpI+2, ':') == NULL - || strchr(cpI+2, '}') == NULL) { - memcpy(cpO, cpI, 2); - cpO += 2; - cpI += 2; - continue; - } - cpI += 2; - - cpT = strchr(cpI, ':'); - n = cpT-cpI; - memcpy(mapname, cpI, limit_length(n)); - mapname[limit_length(n)] = '\0'; - cpI += n+1; - - cpT2 = strchr(cpI, '|'); - cpT = strchr(cpI, '}'); - if (cpT2 != NULL && cpT2 < cpT) { - n = cpT2-cpI; - memcpy(mapkey, cpI, limit_length(n)); - mapkey[limit_length(n)] = '\0'; - cpI += n+1; - - n = cpT-cpI; - memcpy(defaultvalue, cpI, limit_length(n)); - defaultvalue[limit_length(n)] = '\0'; - cpI += n+1; - } - else { - n = cpT-cpI; - memcpy(mapkey, cpI, limit_length(n)); - mapkey[limit_length(n)] = '\0'; - cpI += n+1; - - defaultvalue[0] = '\0'; - } - - cpT = lookup_map(r, mapname, mapkey); - if (cpT != NULL) { - n = strlen(cpT); - if (cpO + n >= newuri + sizeof(newuri)) { - log_printf(r->server, "insufficient space in expand_map_lookups, aborting"); - return; - } - memcpy(cpO, cpT, n); - cpO += n; - } - else { - n = strlen(defaultvalue); - if (cpO + n >= newuri + sizeof(newuri)) { - log_printf(r->server, "insufficient space in expand_map_lookups, aborting"); - return; - } - memcpy(cpO, defaultvalue, n); - cpO += n; - } - } - else { - cpT = strstr(cpI, "${"); - if (cpT == NULL) - cpT = cpI+strlen(cpI); - n = cpT-cpI; - if (cpO + n >= newuri + sizeof(newuri)) { - log_printf(r->server, "insufficient space in expand_map_lookups, aborting"); - return; - } - memcpy(cpO, cpI, n); - cpO += n; - cpI += n; - } - } - *cpO = '\0'; - strncpy(uri, newuri, uri_len-1); - uri[uri_len-1] = '\0'; - return; -} - -#undef limit_length - - - -/* -** +-------------------------------------------------------+ -** | | -** | DBM hashfile support -** | | -** +-------------------------------------------------------+ -*/ - - -static char *lookup_map(request_rec *r, char *name, char *key) -{ - void *sconf; - rewrite_server_conf *conf; - array_header *rewritemaps; - rewritemap_entry *entries; - rewritemap_entry *s; - char *value; - struct stat st; - int i; - - /* get map configuration */ - sconf = r->server->module_config; - conf = (rewrite_server_conf *)get_module_config(sconf, &rewrite_module); - rewritemaps = conf->rewritemaps; - - entries = (rewritemap_entry *)rewritemaps->elts; - for (i = 0; i < rewritemaps->nelts; i++) { - s = &entries[i]; - if (strcmp(s->name, name) == 0) { - if (s->type == MAPTYPE_TXT) { - stat(s->checkfile, &st); /* existence was checked at startup! */ - value = get_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key); - if (value == NULL) { - rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup"); - if ((value = lookup_map_txtfile(r, s->datafile, key)) != NULL) { - rewritelog(r, 5, "map lookup OK: map=%s key=%s[txt] -> val=%s", s->name, key, value); - set_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key, value); - return value; - } - else { - rewritelog(r, 5, "map lookup FAILED: map=%s[txt] key=%s", s->name, key); - return NULL; - } - } - else { - rewritelog(r, 5, "cache lookup OK: map=%s[txt] key=%s -> val=%s", s->name, key, value); - return value; - } - } - else if (s->type == MAPTYPE_DBM) { -#if HAS_NDBM_LIB - stat(s->checkfile, &st); /* existence was checked at startup! */ - value = get_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key); - if (value == NULL) { - rewritelog(r, 6, "cache lookup FAILED, forcing new map lookup"); - if ((value = lookup_map_dbmfile(r, s->datafile, key)) != NULL) { - rewritelog(r, 5, "map lookup OK: map=%s[dbm] key=%s -> val=%s", s->name, key, value); - set_cache_string(cachep, s->name, CACHEMODE_TS, st.st_mtime, key, value); - return value; - } - else { - rewritelog(r, 5, "map lookup FAILED: map=%s[dbm] key=%s", s->name, key); - return NULL; - } - } - else { - rewritelog(r, 5, "cache lookup OK: map=%s[dbm] key=%s -> val=%s", s->name, key, value); - return value; - } -#else - return NULL; -#endif - } - else if (s->type == MAPTYPE_PRG) { - if ((value = lookup_map_program(r, s->fpin, s->fpout, key)) != NULL) { - rewritelog(r, 5, "map lookup OK: map=%s key=%s -> val=%s", s->name, key, value); - return value; - } - else { - rewritelog(r, 5, "map lookup FAILED: map=%s key=%s", s->name, key); - } - } - } - } - return NULL; -} - - -static char *lookup_map_txtfile(request_rec *r, char *file, char *key) -{ - FILE *fp = NULL; - char line[1024]; - char output[1024]; - char result[1024]; - char *value = NULL; - char *cpT; - char *curkey; - char *curval; - - if ((fp = pfopen(r->pool, file, "r")) == NULL) - return NULL; - - strncpy(output, MAPFILE_OUTPUT, sizeof(output)-1); - EOS_PARANOIA(output); - while (fgets(line, sizeof(line), fp) != NULL) { - if (line[strlen(line)-1] == '\n') - line[strlen(line)-1] = '\0'; - if (regexec(lookup_map_txtfile_regexp, line, lookup_map_txtfile_regexp->re_nsub+1, lookup_map_txtfile_regmatch, 0) == 0) { - strncpy(result, pregsub(r->pool, output, line, lookup_map_txtfile_regexp->re_nsub+1, lookup_map_txtfile_regmatch), sizeof(result)-1); /* substitute in output */ - EOS_PARANOIA(result); - cpT = strchr(result, ','); - *cpT = '\0'; - curkey = result; - curval = cpT+1; - - if (strcmp(curkey, key) == 0) { - value = pstrdup(r->pool, curval); - break; - } - } - } - pfclose(r->pool, fp); - return value; -} - -#if HAS_NDBM_LIB -static char *lookup_map_dbmfile(request_rec *r, char *file, char *key) -{ - DBM *dbmfp = NULL; - datum dbmkey; - datum dbmval; - char *value = NULL; - char buf[MAX_STRING_LEN]; - - dbmkey.dptr = key; - dbmkey.dsize = (strlen(key) < sizeof(buf) - 1 ? strlen(key) : sizeof(buf)-1); - if ((dbmfp = dbm_open(file, O_RDONLY, 0666)) != NULL) { - dbmval = dbm_fetch(dbmfp, dbmkey); - if (dbmval.dptr != NULL) { - memcpy(buf, dbmval.dptr, dbmval.dsize); - buf[dbmval.dsize] = '\0'; - value = pstrdup(r->pool, buf); - } - dbm_close(dbmfp); - } - return value; -} -#endif - -static char *lookup_map_program(request_rec *r, int fpin, int fpout, char *key) -{ - char buf[LONG_STRING_LEN]; - char c; - int i; - - /* lock the channel */ -#ifdef USE_PIPE_LOCKING - fd_lock(fpin); -#endif - - /* write out the request key */ - write(fpin, key, strlen(key)); - write(fpin, "\n", 1); - - /* read in the response value */ - i = 0; - while (read(fpout, &c, 1) == 1 && (i < LONG_STRING_LEN-1)) { - if (c == '\n') - break; - buf[i++] = c; - } - buf[i] = '\0'; - - /* unlock the channel */ -#ifdef USE_PIPE_LOCKING - fd_unlock(fpin); -#endif - - if (strcasecmp(buf, "NULL") == 0) - return NULL; - else - return pstrdup(r->pool, buf); -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | rewriting logfile support -** | | -** +-------------------------------------------------------+ -*/ - - -static void open_rewritelog(server_rec *s, pool *p) -{ - rewrite_server_conf *conf; - char *fname; - FILE *fp; - int rewritelog_flags = ( O_WRONLY|O_APPEND|O_CREAT ); - mode_t rewritelog_mode = ( S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH ); - - conf = get_module_config(s->module_config, &rewrite_module); - - if (conf->rewritelogfile == NULL) - return; - if (*(conf->rewritelogfile) == '\0') - return; - if (conf->rewritelogfp > 0) - return; /* virtual log shared w/main server */ - - fname = server_root_relative(p, conf->rewritelogfile); - - if (*conf->rewritelogfile == '|') { - if (!spawn_child(p, rewritelog_child, (void *)(conf->rewritelogfile+1), - kill_after_timeout, &fp, NULL)) { - perror("spawn_child"); - fprintf (stderr, "mod_rewrite: could not fork child for RewriteLog process\n"); - exit (1); - } - conf->rewritelogfp = fileno(fp); - } - else if (*conf->rewritelogfile != '\0') { - if ((conf->rewritelogfp = popenf(p, fname, rewritelog_flags, rewritelog_mode)) < 0) { - perror("open"); - fprintf(stderr, "mod_rewrite: could not open RewriteLog file %s.\n", fname); - exit(1); - } - } - return; -} - -/* Child process code for 'RewriteLog "|..."' */ -static void rewritelog_child(void *cmd) -{ - cleanup_for_exec(); - signal(SIGHUP, SIG_IGN); -#ifdef __EMX__ - /* OS/2 needs a '/' */ - execl(SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); -#else - execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); -#endif - exit(1); -} - -static void rewritelog(request_rec *r, int level, const char *text, ...) -{ - rewrite_server_conf *conf; - conn_rec *connect; - char *str1; - char str2[512]; - char str3[1024]; - char type[20]; - char redir[20]; - va_list ap; - int i; - request_rec *req; - char *ruser; - const char *rhost; - - va_start(ap, text); - conf = get_module_config(r->server->module_config, &rewrite_module); - connect = r->connection; - - if (conf->rewritelogfp <0) - return; - if (conf->rewritelogfile == NULL) - return; - if (*(conf->rewritelogfile) == '\0') - return; - - if (level > conf->rewriteloglevel) - return; - - if (connect->user == NULL) { - ruser = "-"; - } - else if (strlen (connect->user) != 0) { - ruser = connect->user; - } - else { - ruser = "\"\""; - } - - rhost = get_remote_host(connect, r->server->module_config, REMOTE_NOLOOKUP); - if (rhost == NULL) - rhost = "UNKNOWN-HOST"; - - str1 = pstrcat(r->pool, rhost, " ", - (connect->remote_logname != NULL ? connect->remote_logname : "-"), " ", - ruser, NULL); - ap_vsnprintf(str2, sizeof(str2), text, ap); - - if (r->main == NULL) - strcpy(type, "initial"); - else - strcpy(type, "subreq"); - - for (i = 0, req = r; req->prev != NULL; req = req->prev) - i++; - if (i == 0) - redir[0] = '\0'; - else - ap_snprintf(redir, sizeof(redir), "/redir#%d", i); - - ap_snprintf(str3, sizeof(str3), "%s %s [%s/sid#%x][rid#%x/%s%s] (%d) %s\n", str1, current_logtime(r), r->server->server_hostname, (unsigned int)(r->server), (unsigned int)r, type, redir, level, str2); - - fd_lock(conf->rewritelogfp); - write(conf->rewritelogfp, str3, strlen(str3)); - fd_unlock(conf->rewritelogfp); - - va_end(ap); - return; -} - -static char *current_logtime(request_rec *r) -{ - int timz; - struct tm *t; - char tstr[80]; - char sign; - - t = get_gmtoff(&timz); - sign = (timz < 0 ? '-' : '+'); - if(timz < 0) - timz = -timz; - - strftime(tstr, 80, "[%d/%b/%Y:%H:%M:%S ", t); - ap_snprintf(tstr + strlen(tstr), 80-strlen(tstr), "%c%.2d%.2d]", sign, timz/60, timz%60); - return pstrdup(r->pool, tstr); -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | program map support -** | | -** +-------------------------------------------------------+ -*/ - -static void run_rewritemap_programs(server_rec *s, pool *p) -{ - rewrite_server_conf *conf; - char *fname; - FILE *fpin; - FILE *fpout; - array_header *rewritemaps; - rewritemap_entry *entries; - rewritemap_entry *map; - int i; - int rc; - - conf = get_module_config(s->module_config, &rewrite_module); - - rewritemaps = conf->rewritemaps; - entries = (rewritemap_entry *)rewritemaps->elts; - for (i = 0; i < rewritemaps->nelts; i++) { - map = &entries[i]; - if (map->type != MAPTYPE_PRG) - continue; - if (map->datafile == NULL || - *(map->datafile) == '\0' || - map->fpin > 0 || - map->fpout > 0 ) - continue; - fname = server_root_relative(p, map->datafile); - fpin = NULL; - fpout = NULL; - rc = spawn_child(p, rewritemap_program_child, (void *)map->datafile, kill_after_timeout, &fpin, &fpout); - if (rc == 0 || fpin == NULL || fpout == NULL) { - perror("spawn_child"); - fprintf(stderr, "mod_rewrite: could not fork child for RewriteMap process\n"); - exit(1); - } - map->fpin = fileno(fpin); - map->fpout = fileno(fpout); - } - return; -} - -/* child process code */ -static void rewritemap_program_child(void *cmd) -{ - cleanup_for_exec(); - signal(SIGHUP, SIG_IGN); -#ifdef __EMX__ - /* OS/2 needs a '/' */ - execl(SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL); -#else - execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL); -#endif - exit(1); -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | environment variable support -** | | -** +-------------------------------------------------------+ -*/ - - -static void expand_variables_inbuffer(request_rec *r, char *buf, int buf_len) -{ - char *newbuf; - newbuf = expand_variables(r, buf); - if (strcmp(newbuf, buf) != 0) { - strncpy(buf, newbuf, buf_len-1); - buf[buf_len-1] = '\0'; - } - return; -} - -static char *expand_variables(request_rec *r, char *str) -{ - char output[MAX_STRING_LEN]; - char input[MAX_STRING_LEN]; - char *cp; - char *cp2; - char *cp3; - int expanded; - - strncpy(input, str, sizeof(input)-1); - EOS_PARANOIA(input); - output[0] = '\0'; - expanded = 0; - for (cp = input; cp < input+MAX_STRING_LEN; ) { - if ((cp2 = strstr(cp, "%{")) != NULL) { - if ((cp3 = strstr(cp2, "}")) != NULL) { - *cp2 = '\0'; - strncpy(&output[strlen(output)], cp, sizeof(output)-strlen(output)-1); - - cp2 += 2; - *cp3 = '\0'; - strncpy(&output[strlen(output)], lookup_variable(r, cp2), sizeof(output)-strlen(output)-1); - - cp = cp3+1; - expanded = 1; - continue; - } - } - strncpy(&output[strlen(output)], cp, sizeof(output)-strlen(output)-1); - EOS_PARANOIA(output); - break; - } - return expanded ? pstrdup(r->pool, output) : str; -} - -static char *lookup_variable(request_rec *r, char *var) -{ - char *result; - char resultbuf[LONG_STRING_LEN]; - time_t tc; - struct tm *tm; - request_rec *rsub; - struct passwd *pw; - struct group *gr; - struct stat finfo; - - result = NULL; - - /* HTTP headers */ - if (strcasecmp(var, "HTTP_USER_AGENT") == 0) { - result = lookup_header(r, "User-Agent"); - } - else if (strcasecmp(var, "HTTP_REFERER") == 0) { - result = lookup_header(r, "Referer"); - } - else if (strcasecmp(var, "HTTP_COOKIE") == 0) { - result = lookup_header(r, "Cookie"); - } - else if (strcasecmp(var, "HTTP_FORWARDED") == 0) { - result = lookup_header(r, "Forwarded"); - } - else if (strcasecmp(var, "HTTP_HOST") == 0) { - result = lookup_header(r, "Host"); - } - else if (strcasecmp(var, "HTTP_PROXY_CONNECTION") == 0) { - result = lookup_header(r, "Proxy-Connection"); - } - else if (strcasecmp(var, "HTTP_ACCEPT") == 0) { - result = lookup_header(r, "Accept"); - } - /* all other headers from which we are still not know about */ - else if (strlen(var) > 5 && strncasecmp(var, "HTTP:", 5) == 0) { - result = lookup_header(r, var+5); - } - - /* connection stuff */ - else if (strcasecmp(var, "REMOTE_ADDR") == 0) { - result = r->connection->remote_ip; - } - else if (strcasecmp(var, "REMOTE_HOST") == 0) { - result = (char *)get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); - } - else if (strcasecmp(var, "REMOTE_USER") == 0) { - result = r->connection->user; - } - else if (strcasecmp(var, "REMOTE_IDENT") == 0) { - result = (char *)get_remote_logname(r); - } - - /* request stuff */ - else if (strcasecmp(var, "THE_REQUEST") == 0) { /* non-standard */ - result = r->the_request; - } - else if (strcasecmp(var, "REQUEST_METHOD") == 0) { - result = r->method; - } - else if (strcasecmp(var, "REQUEST_URI") == 0) { /* non-standard */ - result = r->uri; - } - else if (strcasecmp(var, "SCRIPT_FILENAME") == 0 || - strcasecmp(var, "REQUEST_FILENAME") == 0 ) { - result = r->filename; - } - else if (strcasecmp(var, "PATH_INFO") == 0) { - result = r->path_info; - } - else if (strcasecmp(var, "QUERY_STRING") == 0) { - result = r->args; - } - else if (strcasecmp(var, "AUTH_TYPE") == 0) { - result = r->connection->auth_type; - } - else if (strcasecmp(var, "IS_SUBREQ") == 0) { /* non-standard */ - result = (r->main != NULL ? "true" : "false"); - } - - /* internal server stuff */ - else if (strcasecmp(var, "DOCUMENT_ROOT") == 0) { - result = document_root(r); - } - else if (strcasecmp(var, "SERVER_ADMIN") == 0) { - result = r->server->server_admin; - } - else if (strcasecmp(var, "SERVER_NAME") == 0) { - result = r->server->server_hostname; - } - else if (strcasecmp(var, "SERVER_PORT") == 0) { - ap_snprintf(resultbuf, sizeof(resultbuf), "%u", r->server->port); - result = resultbuf; - } - else if (strcasecmp(var, "SERVER_PROTOCOL") == 0) { - result = r->protocol; - } - else if (strcasecmp(var, "SERVER_SOFTWARE") == 0) { - result = pstrdup(r->pool, SERVER_VERSION); - } - else if (strcasecmp(var, "API_VERSION") == 0) { /* non-standard */ - ap_snprintf(resultbuf, sizeof(resultbuf), "%d", MODULE_MAGIC_NUMBER); - result = resultbuf; - } - - /* underlaying Unix system stuff */ - else if (strcasecmp(var, "TIME_YEAR") == 0) { - tc = time(NULL); - tm = localtime(&tc); - ap_snprintf(resultbuf, sizeof(resultbuf), "%02d%02d", (tm->tm_year / 100) + 19, tm->tm_year % 100); - result = resultbuf; - } -#define MKTIMESTR(format, tmfield) \ - tc = time(NULL); \ - tm = localtime(&tc); \ - ap_snprintf(resultbuf, sizeof(resultbuf), format, tm->tmfield); \ - result = resultbuf; - else if (strcasecmp(var, "TIME_MON") == 0) { - MKTIMESTR("%02d", tm_mon+1) - } - else if (strcasecmp(var, "TIME_DAY") == 0) { - MKTIMESTR("%02d", tm_mday) - } - else if (strcasecmp(var, "TIME_HOUR") == 0) { - MKTIMESTR("%02d", tm_hour) - } - else if (strcasecmp(var, "TIME_MIN") == 0) { - MKTIMESTR("%02d", tm_min) - } - else if (strcasecmp(var, "TIME_SEC") == 0) { - MKTIMESTR("%02d", tm_sec) - } - else if (strcasecmp(var, "TIME_WDAY") == 0) { - MKTIMESTR("%d", tm_wday) - } - else if (strcasecmp(var, "TIME") == 0) { - tc = time(NULL); - tm = localtime(&tc); - ap_snprintf(resultbuf, sizeof(resultbuf), "%02d%02d%02d%02d%02d%02d%02d", - (tm->tm_year / 100) + 19, (tm->tm_year % 100), - tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - result = resultbuf; - rewritelog(r, 1, "RESULT='%s'", result); - } - - /* all other env-variables from the parent Apache process */ - else if (strlen(var) > 4 && strncasecmp(var, "ENV:", 4) == 0) { - /* first try the internal Apache notes structure */ - result = table_get(r->notes, var+4); - /* second try the internal Apache env structure */ - if (result == NULL) - result = table_get(r->subprocess_env, var+4); - /* third try the external OS env */ - if (result == NULL) - result = getenv(var+4); - } - -#define LOOKAHEAD(subrecfunc) \ - if ( \ - /* filename is safe to use */ \ - r->filename != NULL \ - /* - and we're either not in a subrequest */ \ - && ( r->main == NULL \ - /* - or in a subrequest where paths are non-NULL... */ \ - || ( r->main->uri != NULL && r->uri != NULL \ - /* ...and sub and main paths differ */ \ - && strcmp(r->main->uri, r->uri) != 0))) { \ - /* process a file-based subrequest */ \ - rsub = subrecfunc(r->filename, r); \ - /* now recursively lookup the variable in the sub_req */ \ - result = lookup_variable(rsub, var+5); \ - /* copy it up to our scope before we destroy the sub_req's pool */ \ - result = pstrdup(r->pool, result); \ - /* cleanup by destroying the subrequest */ \ - destroy_sub_req(rsub); \ - /* log it */ \ - rewritelog(r, 5, "lookahead: path=%s var=%s -> val=%s", r->filename, var+5, result); \ - /* return ourself to prevent re-pstrdup */ \ - return result; \ - } - - /* look-ahead for parameter through URI-based sub-request */ - else if (strlen(var) > 5 && strncasecmp(var, "LA-U:", 5) == 0) { - LOOKAHEAD(sub_req_lookup_uri) - } - /* look-ahead for parameter through file-based sub-request */ - else if (strlen(var) > 5 && strncasecmp(var, "LA-F:", 5) == 0) { - LOOKAHEAD(sub_req_lookup_file) - } - - /* file stuff */ - else if (strcasecmp(var, "SCRIPT_USER") == 0) { - result = pstrdup(r->pool, "<unknown>"); - if (r->finfo.st_mode != 0) { - if ((pw = getpwuid(r->finfo.st_uid)) != NULL) { - result = pstrdup(r->pool, pw->pw_name); - } - } - else { - if (stat(r->filename, &finfo) == 0) { - if ((pw = getpwuid(finfo.st_uid)) != NULL) { - result = pstrdup(r->pool, pw->pw_name); - } - } - } - } - else if (strcasecmp(var, "SCRIPT_GROUP") == 0) { - result = pstrdup(r->pool, "<unknown>"); - if (r->finfo.st_mode != 0) { - if ((gr = getgrgid(r->finfo.st_gid)) != NULL) { - result = pstrdup(r->pool, gr->gr_name); - } - } - else { - if (stat(r->filename, &finfo) == 0) { - if ((gr = getgrgid(finfo.st_gid)) != NULL) { - result = pstrdup(r->pool, gr->gr_name); - } - } - } - } - - if (result == NULL) - return pstrdup(r->pool, ""); - else - return pstrdup(r->pool, result); -} - -static char *lookup_header(request_rec *r, const char *name) -{ - array_header *hdrs_arr; - table_entry *hdrs; - int i; - - hdrs_arr = table_elts(r->headers_in); - hdrs = (table_entry *)hdrs_arr->elts; - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (hdrs[i].key == NULL) - continue; - if (strcasecmp(hdrs[i].key, name) == 0) - return hdrs[i].val; - } - return NULL; -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | caching support -** | | -** +-------------------------------------------------------+ -*/ - - -static cache *init_cache(pool *p) -{ - cache *c; - - c = (cache *)palloc(p, sizeof(cache)); - c->pool = make_sub_pool(p); - c->lists = make_array(c->pool, 2, sizeof(cachelist)); - return c; -} - -static void set_cache_string(cache *c, char *res, int mode, time_t time, char *key, char *value) -{ - cacheentry ce; - - ce.time = time; - ce.key = key; - ce.value = value; - store_cache_string(c, res, &ce); - return; -} - -static char *get_cache_string(cache *c, char *res, int mode, time_t time, char *key) -{ - cacheentry *ce; - - ce = retrieve_cache_string(c, res, key); - if (ce == NULL) - return NULL; - if (mode & CACHEMODE_TS) { - if (time != ce->time) - return NULL; - } - else if (mode & CACHEMODE_TTL) { - if (time > ce->time) - return NULL; - } - return pstrdup(c->pool, ce->value); -} - -static void store_cache_string(cache *c, char *res, cacheentry *ce) -{ - int i; - int j; - cachelist *l; - cacheentry *e; - int found_list; - - found_list = 0; - /* first try to edit an existing entry */ - for (i = 0; i < c->lists->nelts; i++) { - l = &(((cachelist *)c->lists->elts)[i]); - if (strcmp(l->resource, res) == 0) { - found_list = 1; - for (j = 0; j < l->entries->nelts; j++) { - e = &(((cacheentry *)l->entries->elts)[j]); - if (strcmp(e->key, ce->key) == 0) { - e->time = ce->time; - e->value = pstrdup(c->pool, ce->value); - return; - } - } - } - } - - /* create a needed new list */ - if (!found_list) { - l = push_array(c->lists); - l->resource = pstrdup(c->pool, res); - l->entries = make_array(c->pool, 2, sizeof(cacheentry)); - } - - /* create the new entry */ - for (i = 0; i < c->lists->nelts; i++) { - l = &(((cachelist *)c->lists->elts)[i]); - if (strcmp(l->resource, res) == 0) { - e = push_array(l->entries); - e->time = ce->time; - e->key = pstrdup(c->pool, ce->key); - e->value = pstrdup(c->pool, ce->value); - return; - } - } - - /* not reached, but when it is no problem... */ - return; -} - -static cacheentry *retrieve_cache_string(cache *c, char *res, char *key) -{ - int i; - int j; - cachelist *l; - cacheentry *e; - - for (i = 0; i < c->lists->nelts; i++) { - l = &(((cachelist *)c->lists->elts)[i]); - if (strcmp(l->resource, res) == 0) { - for (j = 0; j < l->entries->nelts; j++) { - e = &(((cacheentry *)l->entries->elts)[j]); - if (strcmp(e->key, key) == 0) { - return e; - } - } - } - } - return NULL; -} - - - - -/* -** +-------------------------------------------------------+ -** | | -** | misc functions -** | | -** +-------------------------------------------------------+ -*/ - -static char *subst_prefix_path(request_rec *r, char *input, char *match, char *subst) -{ - char matchbuf[LONG_STRING_LEN]; - char substbuf[LONG_STRING_LEN]; - char *output; - int l; - - output = input; - - /* first create a match string which always has a trailing slash */ - strncpy(matchbuf, match, sizeof(matchbuf)-1); - EOS_PARANOIA(matchbuf); - l = strlen(matchbuf); - if (matchbuf[l-1] != '/') { - matchbuf[l] = '/'; - matchbuf[l+1] = '\0'; - l++; - } - /* now compare the prefix */ - if (strncmp(input, matchbuf, l) == 0) { - rewritelog(r, 5, "strip matching prefix: %s -> %s", output, output+l); - output = pstrdup(r->pool, output+l); - - /* and now add the base-URL as replacement prefix */ - strncpy(substbuf, subst, sizeof(substbuf)-1); - EOS_PARANOIA(substbuf); - l = strlen(substbuf); - if (substbuf[l-1] != '/') { - substbuf[l] = '/'; - substbuf[l+1] = '\0'; - l++; - } - if (output[0] == '/') { - rewritelog(r, 4, "add subst prefix: %s -> %s%s", output, substbuf, output+1); - output = pstrcat(r->pool, substbuf, output+1, NULL); - } - else { - rewritelog(r, 4, "add subst prefix: %s -> %s%s", output, substbuf, output); - output = pstrcat(r->pool, substbuf, output, NULL); - } - } - return output; -} - - -/* -** -** own command line parser which don't have the '\\' problem -** -*/ - -static int parseargline(char *str, char **a1, char **a2, char **a3) -{ - char *cp; - int isquoted; - -#define SKIP_WHITESPACE(cp) \ - for ( ; *cp == ' ' || *cp == '\t'; ) \ - cp++; - -#define CHECK_QUOTATION(cp,isquoted) \ - isquoted = 0; \ - if (*cp == '"') { \ - isquoted = 1; \ - cp++; \ - } - -#define DETERMINE_NEXTSTRING(cp,isquoted) \ - for ( ; *cp != '\0'; cp++) { \ - if ( (isquoted && (*cp == ' ' || *cp == '\t')) \ - || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t'))) { \ - cp++; \ - continue; \ - } \ - if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \ - || (isquoted && *cp == '"') ) \ - break; \ - } - - cp = str; - SKIP_WHITESPACE(cp); - - /* determine first argument */ - CHECK_QUOTATION(cp, isquoted); - *a1 = cp; - DETERMINE_NEXTSTRING(cp, isquoted); - if (*cp == '\0') - return 1; - *cp++ = '\0'; - - SKIP_WHITESPACE(cp); - - /* determine second argument */ - CHECK_QUOTATION(cp, isquoted); - *a2 = cp; - DETERMINE_NEXTSTRING(cp, isquoted); - if (*cp == '\0') { - *cp++ = '\0'; - *a3 = NULL; - return 0; - } - *cp++ = '\0'; - - SKIP_WHITESPACE(cp); - - /* again check if there are only two arguments */ - if (*cp == '\0') { - *cp++ = '\0'; - *a3 = NULL; - return 0; - } - - /* determine second argument */ - CHECK_QUOTATION(cp, isquoted); - *a3 = cp; - DETERMINE_NEXTSTRING(cp, isquoted); - *cp++ = '\0'; - - return 0; -} - - -static void add_env_variable(request_rec *r, char *s) -{ - char var[MAX_STRING_LEN]; - char val[MAX_STRING_LEN]; - char *cp; - int n; - - if ((cp = strchr(s, ':')) != NULL) { - n = ((cp-s) > MAX_STRING_LEN-1 ? MAX_STRING_LEN-1 : (cp-s)); - memcpy(var, s, n); - var[n] = '\0'; - strncpy(val, cp+1, sizeof(val)-1); - EOS_PARANOIA(val); - table_set(r->subprocess_env, pstrdup(r->pool, var), pstrdup(r->pool, val)); - rewritelog(r, 5, "setting env variable '%s' to '%s'", var, val); - } -} - - - -/* -** -** stat() for only the prefix of a path -** -*/ - -static int prefix_stat(const char *path, struct stat *sb) -{ - char curpath[LONG_STRING_LEN]; - char *cp; - - strncpy(curpath, path, sizeof(curpath)-1); - EOS_PARANOIA(curpath); - if (curpath[0] != '/') - return 0; - if ((cp = strchr(curpath+1, '/')) != NULL) - *cp = '\0'; - if (stat(curpath, sb) == 0) - return 1; - else - return 0; -} - - -/* -** -** special DNS lookup functions -** -*/ - -static int is_this_our_host(request_rec *r, char *testhost) -{ - char **cppHNLour; - char **cppHNLtest; - char *ourhostname; - char *ourhostip; - const char *names; - char *name; - int i, j; - server_addr_rec *sar; - - /* we can check: - r-> - char *hostname Host, as set by full URI or Host: - int hostlen Length of http://host:port in full URI - r->server-> - int is_virtual 0=main, 1=ip-virtual, 2=non-ip-virtual - char *server_hostname used on compare to r->hostname - inet_ntoa(r->connection->local_addr.sin_addr) - used on compare to r->hostname - unsigned short port for redirects - char *path name of ServerPath - int pathlen len of ServerPath - char *names Wildcarded names for ServerAlias servers - r->server->addrs-> - struct in_addr host_addr The bound address, for this server - short host_port The bound port, for this server - char *virthost The name given in <VirtualHost> - */ - - ourhostname = r->server->server_hostname; - ourhostip = inet_ntoa(r->connection->local_addr.sin_addr); - - /* just a simple common case */ - if (strcmp(testhost, ourhostname) == 0 || - strcmp(testhost, ourhostip) == 0 ) - return YES; - - /* now the complicated cases */ - if (!r->server->is_virtual) { - /* main servers */ - - /* check for the alternative IP addresses */ - if ((cppHNLour = resolv_ipaddr_list(r, ourhostname)) == NULL) - return NO; - if ((cppHNLtest = resolv_ipaddr_list(r, testhost)) == NULL) - return NO; - for (i = 0; cppHNLtest[i] != NULL; i++) { - for (j = 0; cppHNLour[j] != NULL; j++) { - if (strcmp(cppHNLtest[i], cppHNLour[j]) == 0) { - return YES; - } - } - } - } - else if (r->server->is_virtual) { - /* virtual servers */ - - /* check for the names supplied in the VirtualHost directive */ - for(sar = r->server->addrs; sar != NULL; sar = sar->next) { - if(strcasecmp(sar->virthost, testhost) == 0) - return YES; - } - - /* check for the virtual-server aliases */ - if (r->server->names != NULL && r->server->names[0] != '\0') { - names = r->server->names; - while (*names != '\0') { - name = getword_conf(r->pool, &names); - if ((is_matchexp(name) && !strcasecmp_match(testhost, name)) || - (strcasecmp(testhost, name) == 0) ) { - return YES; - } - } - } - } - return NO; -} - -static int isaddr(char *host) -{ - char *cp; - - /* Null pointers and empty strings - are not addresses. */ - if (host == NULL) - return NO; - if (*host == '\0') - return NO; - /* Make sure it has only digits and dots. */ - for (cp = host; *cp; cp++) { - if (!isdigit(*cp) && *cp != '.') - return NO; - } - /* If it has a trailing dot, - don't treat it as an address. */ - if (*(cp-1) == '.') - return NO; - return YES; -} - -static char **resolv_ipaddr_list(request_rec *r, char *name) -{ - char **cppHNL; - struct hostent *hep; - int i; - - if (isaddr(name)) - hep = gethostbyaddr(name, sizeof(struct in_addr), AF_INET); - else - hep = gethostbyname(name); - if (hep == NULL) - return NULL; - for (i = 0; hep->h_addr_list[i]; i++) - ; - cppHNL = (char **)palloc(r->pool, sizeof(char *)*(i+1)); - for (i = 0; hep->h_addr_list[i]; i++) - cppHNL[i] = pstrdup(r->pool, inet_ntoa(*((struct in_addr *)(hep->h_addr_list[i]))) ); - cppHNL[i] = NULL; - return cppHNL; -} - - -/* -** -** check if proxy module is available -** i.e. if it is compiled in and turned on -** -*/ - -static int is_proxy_available(server_rec *s) -{ - return (find_linked_module("mod_proxy.c") != NULL); -} - - -/* -** -** File locking -** -*/ - -#ifdef USE_FCNTL -static struct flock lock_it; -static struct flock unlock_it; -#endif - -static void fd_lock(int fd) -{ - int rc; - -#ifdef USE_FCNTL - lock_it.l_whence = SEEK_SET; /* from current point */ - lock_it.l_start = 0; /* -"- */ - lock_it.l_len = 0; /* until end of file */ - lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ - lock_it.l_pid = 0; /* pid not actually interesting */ - - while ( ((rc = fcntl(fd, F_SETLKW, &lock_it)) < 0) - && (errno == EINTR) ) - continue; -#endif -#ifdef USE_FLOCK - while ( ((rc = flock(fd, LOCK_EX)) < 0) - && (errno == EINTR) ) - continue; -#endif - - if (rc < 0) { -#ifdef USE_FLOCK - perror("flock"); -#else - perror("fcntl"); -#endif - fprintf(stderr, "Error getting lock. Exiting!"); - exit(1); - } - return; -} - -static void fd_unlock(int fd) -{ - int rc; - -#ifdef USE_FCNTL - unlock_it.l_whence = SEEK_SET; /* from current point */ - unlock_it.l_start = 0; /* -"- */ - unlock_it.l_len = 0; /* until end of file */ - unlock_it.l_type = F_UNLCK; /* unlock */ - unlock_it.l_pid = 0; /* pid not actually interesting */ - - rc = fcntl(fd, F_SETLKW, &unlock_it); -#endif -#ifdef USE_FLOCK - rc = flock(fd, LOCK_UN); -#endif - - if (rc < 0) { -#ifdef USE_FLOCK - perror("flock"); -#else - perror("fcntl"); -#endif - fprintf(stderr, "Error freeing lock. Exiting!"); - exit(1); - } -} - -/* -** -** Lexicographic Compare -** -*/ - -static int compare_lexicography(char *cpNum1, char *cpNum2) -{ - int i; - int n1, n2; - - n1 = strlen(cpNum1); - n2 = strlen(cpNum2); - if (n1 > n2) - return 1; - if (n1 < n2) - return -1; - for (i = 0; i < n1; i++) { - if (cpNum1[i] > cpNum2[i]) - return 1; - if (cpNum1[i] < cpNum2[i]) - return -1; - } - return 0; -} - - -/*EOF*/ diff --git a/usr.sbin/httpd/src/mod_rewrite.h b/usr.sbin/httpd/src/mod_rewrite.h deleted file mode 100644 index 10f91070a85..00000000000 --- a/usr.sbin/httpd/src/mod_rewrite.h +++ /dev/null @@ -1,400 +0,0 @@ - -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - - -#ifndef _MOD_REWRITE_H -#define _MOD_REWRITE_H 1 - -/* -** _ _ _ -** _ __ ___ ___ __| | _ __ _____ ___ __(_) |_ ___ -** | '_ ` _ \ / _ \ / _` | | '__/ _ \ \ /\ / / '__| | __/ _ \ -** | | | | | | (_) | (_| | | | | __/\ V V /| | | | || __/ -** |_| |_| |_|\___/ \__,_|___|_| \___| \_/\_/ |_| |_|\__\___| -** |_____| -** -** URL Rewriting Module -** -** This module uses a rule-based rewriting engine (based on a -** regular-expression parser) to rewrite requested URLs on the fly. -** -** It supports an unlimited number of additional rule conditions (which can -** operate on a lot of variables, even on HTTP headers) for granular -** matching and even external database lookups (either via plain text -** tables, DBM hash files or even external processes) for advanced URL -** substitution. -** -** It operates on the full URLs (including the PATH_INFO part) both in -** per-server context (httpd.conf) and per-dir context (.htaccess) and even -** can generate QUERY_STRING parts on result. The rewriting result finally -** can lead to internal subprocessing, external request redirection or even -** to internal proxy throughput. -** -** This module was originally written in April 1996 and -** gifted exclusively to the The Apache Group in July 1997 by -** -** Ralf S. Engelschall -** rse@engelschall.com -** www.engelschall.com -*/ - - - - - /* The NDBM support: - We support only NDBM files. - But we have to stat the file for the mtime, - so we also need to know the file extension */ -#if HAS_NDBM_LIB -#include <ndbm.h> -#if (__FreeBSD__) -#define NDBM_FILE_SUFFIX ".db" -#else -#define NDBM_FILE_SUFFIX ".pag" -#endif -#endif - - - /* The locking support: - Try to determine whether we should use fcntl() or flock(). - Would be better conf.h could provide this... :-( */ -#if defined(USE_FCNTL_SERIALIZED_ACCEPT) -#define USE_FCNTL 1 -#include <fcntl.h> -#endif -#if defined(USE_FLOCK_SERIALIZED_ACCEPT) -#define USE_FLOCK 1 -#include <sys/file.h> -#endif -#if !defined(USE_FCNTL) && !defined(USE_FLOCK) -#define USE_FLOCK 1 -#ifndef MPE -#include <sys/file.h> -#endif -#ifndef LOCK_UN -#undef USE_FLOCK -#define USE_FCNTL 1 -#include <fcntl.h> -#endif -#endif -#ifdef AIX -#undef USE_FLOCK -#define USE_FCNTL 1 -#include <fcntl.h> -#endif - - /* The locking support for the RewriteMap programs: - Locking a pipe to the child works fine under most - Unix derivates, but braindead SunOS 4.1.x has - problems with this approach... */ -#define USE_PIPE_LOCKING 1 -#ifdef SUNOS4 -#undef USE_PIPE_LOCKING -#endif - - -/* -** -** Some defines -** -*/ - -#define ENVVAR_SCRIPT_URL "SCRIPT_URL" -#define ENVVAR_SCRIPT_URI "SCRIPT_URI" - -#ifndef SUPPORT_DBM_REWRITEMAP -#define SUPPORT_DBM_REWRITEMAP 0 -#endif - -#define REWRITE_FORCED_MIMETYPE_NOTEVAR "rewrite-forced-mimetype" - -#define CONDFLAG_NONE 1<<0 -#define CONDFLAG_NOCASE 1<<1 -#define CONDFLAG_NOTMATCH 1<<2 -#define CONDFLAG_ORNEXT 1<<3 - -#define RULEFLAG_NONE 1<<0 -#define RULEFLAG_FORCEREDIRECT 1<<1 -#define RULEFLAG_LASTRULE 1<<2 -#define RULEFLAG_NEWROUND 1<<3 -#define RULEFLAG_CHAIN 1<<4 -#define RULEFLAG_IGNOREONSUBREQ 1<<5 -#define RULEFLAG_NOTMATCH 1<<6 -#define RULEFLAG_PROXY 1<<7 -#define RULEFLAG_PASSTHROUGH 1<<8 -#define RULEFLAG_FORBIDDEN 1<<9 -#define RULEFLAG_GONE 1<<10 -#define RULEFLAG_QSAPPEND 1<<11 - -#define MAPTYPE_TXT 1<<0 -#define MAPTYPE_DBM 1<<1 -#define MAPTYPE_PRG 1<<2 - -#define ENGINE_DISABLED 1<<0 -#define ENGINE_ENABLED 1<<1 - -#define OPTION_NONE 1<<0 -#define OPTION_INHERIT 1<<1 - -#define CACHEMODE_TS 1<<0 -#define CACHEMODE_TTL 1<<1 - -#ifndef FALSE -#define FALSE 0 -#define TRUE !FALSE -#endif - -#ifndef NO -#define NO FALSE -#define YES TRUE -#endif - -#ifndef LONG_STRING_LEN -#define LONG_STRING_LEN 2048 -#endif - -#define MAX_ENV_FLAGS 5 - -#define EOS_PARANOIA(ca) ca[sizeof(ca)-1] = '\0' - - -/* -** -** our private data structures we handle with -** -*/ - - /* the list structures for holding the mapfile information - and the rewrite rules */ - -typedef struct { - char *name; /* the name of the map */ - char *datafile; /* the file which contains the data of the map */ - char *checkfile; /* the file which stays for existence of the map */ - int type; /* the type of the map */ - int fpin; /* in filepointer for program maps */ - int fpout; /* out filepointer for program maps */ -} rewritemap_entry; - -typedef struct { - char *input; /* Input string of RewriteCond */ - char *pattern; /* the RegExp pattern string */ - regex_t *regexp; - int flags; /* Flags which control the match */ -} rewritecond_entry; - -typedef struct { - array_header *rewriteconds; /* the corresponding RewriteCond entries */ - char *pattern; /* the RegExp pattern string */ - regex_t *regexp; /* the RegExp pattern compilation */ - char *output; /* the Substitution string */ - int flags; /* Flags which control the substitution */ - char *forced_mimetype; /* forced MIME type of substitution */ - int forced_responsecode; /* forced HTTP redirect response status */ - char *env[MAX_ENV_FLAGS+1];/* added environment variables */ - int skip; /* number of next rules to skip */ -} rewriterule_entry; - - - /* the per-server or per-virtual-server configuration - statically generated once on startup for every server */ - -typedef struct { - int state; /* the RewriteEngine state */ - int options; /* the RewriteOption state */ - char *rewritelogfile; /* the RewriteLog filename */ - int rewritelogfp; /* the RewriteLog open filepointer */ - int rewriteloglevel; /* the RewriteLog level of verbosity */ - array_header *rewritemaps; /* the RewriteMap entries */ - array_header *rewriteconds; /* the RewriteCond entries (temporary) */ - array_header *rewriterules; /* the RewriteRule entries */ -} rewrite_server_conf; - - - /* the per-directory configuration - individually generated on-the-fly by Apache server for current request */ - -typedef struct { - int state; /* the RewriteEngine state */ - int options; /* the RewriteOption state */ - array_header *rewriteconds; /* the RewriteCond entries (temporary) */ - array_header *rewriterules; /* the RewriteRule entries */ - char *directory; /* the directory where it applies */ - char *baseurl; /* the base-URL where it applies */ -} rewrite_perdir_conf; - - - /* the cache structures */ - -typedef struct cacheentry { - time_t time; - char *key; - char *value; -} cacheentry; - -typedef struct cachelist { - char *resource; - array_header *entries; -} cachelist; - -typedef struct cache { - pool *pool; - array_header *lists; -} cache; - - -/* -** -** forward declarations -** -*/ - - /* config structure handling */ -static void *config_server_create(pool *p, server_rec *s); -static void *config_server_merge (pool *p, void *basev, void *overridesv); -static void *config_perdir_create(pool *p, char *path); -static void *config_perdir_merge (pool *p, void *basev, void *overridesv); - - /* config directive handling */ -static const char *cmd_rewriteengine (cmd_parms *cmd, rewrite_perdir_conf *dconf, int flag); -static const char *cmd_rewriteoptions (cmd_parms *cmd, rewrite_perdir_conf *dconf, char *option); -static const char *cmd_rewriteoptions_setoption(pool *p, int *options, char *name); -static const char *cmd_rewritelog (cmd_parms *cmd, void *dconf, char *a1); -static const char *cmd_rewriteloglevel(cmd_parms *cmd, void *dconf, char *a1); -static const char *cmd_rewritemap (cmd_parms *cmd, void *dconf, char *a1, char *a2); - -static const char *cmd_rewritebase(cmd_parms *cmd, rewrite_perdir_conf *dconf, char *a1); - -static const char *cmd_rewritecond (cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str); -static const char *cmd_rewritecond_parseflagfield(pool *p, rewritecond_entry *new, char *str); -static const char *cmd_rewritecond_setflag (pool *p, rewritecond_entry *cfg, char *key, char *val); - -extern const char *cmd_rewriterule (cmd_parms *cmd, rewrite_perdir_conf *dconf, char *str); -static const char *cmd_rewriterule_parseflagfield(pool *p, rewriterule_entry *new, char *str); -static const char *cmd_rewriterule_setflag (pool *p, rewriterule_entry *cfg, char *key, char *val); - - /* initialisation */ -static void init_module(server_rec *s, pool *p); - - /* runtime hooks */ -static int hook_uri2file (request_rec *r); -static int hook_mimetype (request_rec *r); -static int hook_fixup (request_rec *r); -static int handler_redirect(request_rec *r); - - /* rewriting engine */ -static int apply_rewrite_list(request_rec *r, array_header *rewriterules, char *perdir); -static int apply_rewrite_rule(request_rec *r, rewriterule_entry *p, char *perdir); -static int apply_rewrite_cond(request_rec *r, rewritecond_entry *p, char *perdir); - - /* URI transformation function */ -static void splitout_queryargs(request_rec *r, int qsappend); -static void reduce_uri(request_rec *r); -static char *expand_tildepaths(request_rec *r, char *uri); -static void expand_map_lookups(request_rec *r, char *uri, int uri_len); - - /* DBM hashfile support functions */ -static char *lookup_map(request_rec *r, char *name, char *key); -static char *lookup_map_txtfile(request_rec *r, char *file, char *key); -#if HAS_NDBM_LIB -static char *lookup_map_dbmfile(request_rec *r, char *file, char *key); -#endif -static char *lookup_map_program(request_rec *r, int fpin, int fpout, char *key); - - /* rewriting logfile support */ -static void open_rewritelog(server_rec *s, pool *p); -static void rewritelog_child(void *cmd); -static void rewritelog(request_rec *r, int level, const char *text, ...); -static char *current_logtime(request_rec *r); - - /* program map support */ -static void run_rewritemap_programs(server_rec *s, pool *p); -static void rewritemap_program_child(void *cmd); - - /* env variable support */ -static void expand_variables_inbuffer(request_rec *r, char *buf, int buf_len); -static char *expand_variables(request_rec *r, char *str); -static char *lookup_variable(request_rec *r, char *var); -static char *lookup_header(request_rec *r, const char *name); - - /* caching functions */ -static cache *init_cache(pool *p); -static char *get_cache_string(cache *c, char *res, int mode, time_t mtime, char *key); -static void set_cache_string(cache *c, char *res, int mode, time_t mtime, char *key, char *value); -static cacheentry *retrieve_cache_string(cache *c, char *res, char *key); -static void store_cache_string(cache *c, char *res, cacheentry *ce); - - /* misc functions */ -static char *subst_prefix_path(request_rec *r, char *input, char *match, char *subst); -static int parseargline(char *str, char **a1, char **a2, char **a3); -static int prefix_stat(const char *path, struct stat *sb); -static void add_env_variable(request_rec *r, char *s); - - /* DNS functions */ -static int is_this_our_host(request_rec *r, char *testhost); -static int isaddr(char *host); -static char **resolv_ipaddr_list(request_rec *r, char *name); - - /* Proxy Module check */ -static int is_proxy_available(server_rec *s); - - /* File locking */ -static void fd_lock(int fd); -static void fd_unlock(int fd); - - /* Lexicographic Comparison */ -static int compare_lexicography(char *cpNum1, char *cpNum2); - -#endif /* _MOD_REWRITE_H */ - -/*EOF*/ diff --git a/usr.sbin/httpd/src/mod_status.c b/usr.sbin/httpd/src/mod_status.c deleted file mode 100644 index c00a3a4d5f9..00000000000 --- a/usr.sbin/httpd/src/mod_status.c +++ /dev/null @@ -1,643 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* Status Module. Display lots of internal data about how Apache is - * performing and the state of all children processes. - * - * To enable this, add the following lines into any config file: - * - * <Location /server-status> - * SetHandler server-status - * </Location> - * - * You may want to protect this location by password or domain so no one - * else can look at it. Then you can access the statistics with a URL like: - * - * http://your_server_name/server-status - * - * /server-status - Returns page using tables - * /server-status?notable - Returns page for browsers without table support - * /server-status?refresh - Returns page with 1 second refresh - * /server-status?refresh=6 - Returns page with refresh every 6 seconds - * /server-status?auto - Returns page with data for automatic parsing - * - * Mark Cox, mark@ukweb.com, November 1995 - * - * 12.11.95 Initial version for www.telescope.org - * 13.3.96 Updated to remove rprintf's [Mark] - * 18.3.96 Added CPU usage, process information, and tidied [Ben Laurie] - * 18.3.96 Make extra Scoreboard variables #definable - * 25.3.96 Make short report have full precision [Ben Laurie suggested] - * 25.3.96 Show uptime better [Mark/Ben Laurie] - * 29.3.96 Better HTML and explanation [Mark/Rob Hartill suggested] - * 09.4.96 Added message for non-STATUS compiled version - * 18.4.96 Added per child and per slot counters [Jim Jagielski] - * 01.5.96 Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.] - * 18.5.96 Adapted to use new rprintf() routine, incidentally fixing a missing - * piece in short reports [Ben Laurie] - * 21.5.96 Additional Status codes (DNS and LOGGING only enabled if - extended STATUS is enabled) [George Burgyan/Jim J.] */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "util_script.h" -#include <time.h> -#include "scoreboard.h" -#include "http_log.h" - -#ifdef NEXT -#include <machine/param.h> -#endif - -#define STATUS_MAXLINE 64 - -#define KBYTE 1024 -#define MBYTE 1048576L -#define GBYTE 1073741824L - -module status_module; - -/* Format the number of bytes nicely */ - -void format_byte_out(request_rec *r,unsigned long bytes) -{ - if (bytes < (5 * KBYTE)) - rprintf(r,"%d B",(int)bytes); - else if (bytes < (MBYTE / 2)) - rprintf(r,"%.1f kB",(float)bytes/KBYTE); - else if (bytes < (GBYTE / 2)) - rprintf(r,"%.1f MB",(float)bytes/MBYTE); - else - rprintf(r,"%.1f GB",(float)bytes/GBYTE); -} - -void format_kbyte_out(request_rec *r,unsigned long kbytes) -{ - if (kbytes < KBYTE) - rprintf(r,"%d kB",(int)kbytes); - else if (kbytes < MBYTE) - rprintf(r,"%.1f MB",(float)kbytes/KBYTE); - else - rprintf(r,"%.1f GB",(float)kbytes/MBYTE); -} - -void show_time(request_rec *r,time_t tsecs) -{ - long days,hrs,mins,secs; - char buf[100]; - char *s; - - secs=tsecs%60; - tsecs/=60; - mins=tsecs%60; - tsecs/=60; - hrs=tsecs%24; - days=tsecs/24; - s=buf; - *s='\0'; - if(days) - rprintf(r," %ld day%s",days,days==1?"":"s"); - if(hrs) - rprintf(r," %ld hour%s",hrs,hrs==1?"":"s"); - if(mins) - rprintf(r," %ld minute%s",mins,mins==1?"":"s"); - if(secs) - rprintf(r," %ld second%s",secs,secs==1?"":"s"); -} - -#if defined(SUNOS4) -double -difftime(time1, time0) - time_t time1, time0; -{ - return(time1 - time0); -} -#endif - -/* Main handler for x-httpd-status requests */ - -/* ID values for command table */ - -#define STAT_OPT_END -1 -#define STAT_OPT_REFRESH 0 -#define STAT_OPT_NOTABLE 1 -#define STAT_OPT_AUTO 2 - -struct stat_opt -{ - int id; - char *form_data_str; - char *hdr_out_str; -}; - -int status_handler (request_rec *r) -{ - struct stat_opt options[] = /* see #defines above */ - { - { STAT_OPT_REFRESH, "refresh", "Refresh" }, - { STAT_OPT_NOTABLE, "notable", NULL }, - { STAT_OPT_AUTO, "auto", NULL }, - { STAT_OPT_END, NULL, NULL } - }; - char *loc; - time_t nowtime=time(NULL); - time_t up_time; - int i,res; - int ready=0; - int busy=0; -#if defined(STATUS) - unsigned long count=0; - unsigned long lres,bytes; - unsigned long my_lres,my_bytes,conn_bytes; - unsigned short conn_lres; - unsigned long bcount=0; - unsigned long kbcount=0; -#ifdef NEXT - float tick=HZ; -#else - float tick=sysconf(_SC_CLK_TCK); -#endif -#endif /* STATUS */ - int short_report=0; - int no_table_report=0; - server_rec *server = r->server; - short_score score_record; - char status[]="??????????"; - char stat_buffer[HARD_SERVER_LIMIT]; - clock_t tu,ts,tcu,tcs; - - tu=ts=tcu=tcs=0; - - status[SERVER_DEAD]='.'; /* We don't want to assume these are in */ - status[SERVER_READY]='_'; /* any particular order in scoreboard.h */ - status[SERVER_STARTING]='S'; - status[SERVER_BUSY_READ]='R'; - status[SERVER_BUSY_WRITE]='W'; - status[SERVER_BUSY_KEEPALIVE]='K'; - status[SERVER_BUSY_LOG]='L'; - status[SERVER_BUSY_DNS]='D'; - status[SERVER_GRACEFUL]='G'; - - if (!exists_scoreboard_image()) { - log_printf(r->server, "Server status unavailable in inetd mode"); - return HTTP_NOT_IMPLEMENTED; - } - r->allowed = (1 << M_GET) | (1 << M_TRACE); - if (r->method_number != M_GET) return HTTP_METHOD_NOT_ALLOWED; - - r->content_type = "text/html"; - - /* - * Simple table-driven form data set parser that lets you alter the header - */ - - if (r->args) - { - i = 0; - while (options[i].id != STAT_OPT_END) - { - if ((loc = strstr(r->args,options[i].form_data_str)) != NULL) - { - switch (options[i].id) - { - case STAT_OPT_REFRESH: - if(*(loc + strlen(options[i].form_data_str)) == '=') - table_set(r->headers_out,options[i].hdr_out_str, - loc+strlen(options[i].hdr_out_str)+1); - else - table_set(r->headers_out,options[i].hdr_out_str,"1"); - break; - case STAT_OPT_NOTABLE: - no_table_report = 1; - break; - case STAT_OPT_AUTO: - r->content_type = "text/plain"; - short_report = 1; - break; - } - } - i++; - } - } - - send_http_header(r); - - if (r->header_only) - return 0; - - sync_scoreboard_image(); - for (i = 0; i<HARD_SERVER_LIMIT; ++i) - { - score_record = get_scoreboard_info(i); - res = score_record.status; - stat_buffer[i] = status[res]; - if (res == SERVER_READY) - ready++; - else if (res == SERVER_BUSY_READ || res==SERVER_BUSY_WRITE || - res == SERVER_STARTING || res==SERVER_BUSY_KEEPALIVE || - res == SERVER_BUSY_LOG || res==SERVER_BUSY_DNS || - res == SERVER_GRACEFUL) - busy++; -#if defined(STATUS) - lres = score_record.access_count; - bytes= score_record.bytes_served; - if (lres!=0 || (score_record.status != SERVER_READY - && score_record.status != SERVER_DEAD)) - { - tu+=score_record.times.tms_utime; - ts+=score_record.times.tms_stime; - tcu+=score_record.times.tms_cutime; - tcs+=score_record.times.tms_cstime; - count+=lres; - bcount+=bytes; - if (bcount>=KBYTE) { - kbcount += (bcount >> 10); - bcount = bcount & 0x3ff; - } - } -#endif /* STATUS */ - } - - up_time=nowtime-restart_time; - - hard_timeout("send status info", r); - - if (!short_report) - { - rputs("<HTML><HEAD>\n<TITLE>Apache Status</TITLE>\n</HEAD><BODY>\n",r); - rputs("<H1>Apache Server Status for ",r); - rvputs(r,server->server_hostname,"</H1>\n\n",NULL); - rvputs(r,"Current Time: ",asctime(localtime(&nowtime)),"<br>\n",NULL); - rvputs(r,"Restart Time: ",asctime(localtime(&restart_time)),"<br>\n", - NULL); - rputs("Server uptime: ",r); - show_time(r,up_time); - rputs("<br>\n",r); - } - -#if defined(STATUS) - if (short_report) - { - rprintf(r,"Total Accesses: %lu\nTotal kBytes: %lu\n",count,kbcount); - -#ifndef __EMX__ - /* Allow for OS/2 not having CPU stats */ - if(ts || tu || tcu || tcs) - rprintf(r,"CPULoad: %g\n",(tu+ts+tcu+tcs)/tick/up_time*100.); -#endif - - rprintf(r,"Uptime: %ld\n",(long)(up_time)); - if (up_time>0) - rprintf(r,"ReqPerSec: %g\n",(float)count/(float)up_time); - - if (up_time>0) - rprintf(r,"BytesPerSec: %g\n",KBYTE*(float)kbcount/(float)up_time); - - if (count>0) - rprintf(r,"BytesPerReq: %g\n",KBYTE*(float)kbcount/(float)count); - } else /* !short_report */ - { - rprintf(r,"Total accesses: %lu - Total Traffic: ", count); - format_kbyte_out(r,kbcount); - -#ifndef __EMX__ - /* Allow for OS/2 not having CPU stats */ - rputs("<br>\n",r); - rprintf(r,"CPU Usage: u%g s%g cu%g cs%g", - tu/tick,ts/tick,tcu/tick,tcs/tick); - - if(ts || tu || tcu || tcs) - rprintf(r," - %.3g%% CPU load",(tu+ts+tcu+tcs)/tick/up_time*100.); -#endif - - rputs("<br>\n",r); - - if (up_time>0) - rprintf(r,"%.3g requests/sec - ", - (float)count/(float)up_time); - - if (up_time>0) - { - format_byte_out(r,KBYTE*(float)kbcount/(float)up_time); - rputs("/second - ",r); - } - - if (count>0) - { - format_byte_out(r,KBYTE*(float)kbcount/(float)count); - rputs("/request",r); - } - - rputs("<br>\n",r); - } /* short_report */ -#endif /* STATUS */ - - if (!short_report) - rprintf(r,"\n%d requests currently being processed, %d idle servers\n" - ,busy,ready); - else - rprintf(r,"BusyServers: %d\nIdleServers: %d\n",busy,ready); - - /* send the scoreboard 'table' out */ - - if(!short_report) - rputs("<PRE>",r); - else - rputs("Scoreboard: ",r); - - for (i = 0; i<HARD_SERVER_LIMIT; ++i) - { - rputc(stat_buffer[i], r); - if((i%STATUS_MAXLINE == (STATUS_MAXLINE - 1))&&!short_report) - rputs("\n",r); - } - - if (short_report) - rputs("\n",r); - else { - rputs("</PRE>\n",r); - rputs("Scoreboard Key: <br>\n",r); - rputs("\"<B><code>_</code></B>\" Waiting for Connection, \n",r); - rputs("\"<B><code>S</code></B>\" Starting up, \n",r); - rputs("\"<B><code>R</code></B>\" Reading Request,<BR>\n",r); - rputs("\"<B><code>W</code></B>\" Sending Reply, \n",r); - rputs("\"<B><code>K</code></B>\" Keepalive (read), \n",r); - rputs("\"<B><code>D</code></B>\" DNS Lookup,<BR>\n",r); - rputs("\"<B><code>L</code></B>\" Logging, \n",r); - rputs("\"<B><code>G</code></B>\" Gracefully finishing, \n",r); - rputs("\"<B><code>.</code></B>\" Open slot with no current process<P>\n",r); - } - -#if defined(STATUS) - if (!short_report) - if(no_table_report) - rputs("<p><hr><h2>Server Details</h2>\n\n",r); - else -#ifdef __EMX__ - /* Allow for OS/2 not having CPU stats */ - rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M\n<th>SS<th>Conn<th>Child<th>Slot<th>Host<th>VHost<th>Request</tr>\n\n",r); -#else - rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M<th>CPU\n<th>SS<th>Conn<th>Child<th>Slot<th>Host<th>VHost<th>Request</tr>\n\n",r); -#endif - - - for (i = 0; i<HARD_SERVER_LIMIT; ++i) - { - score_record=get_scoreboard_info(i); - lres = score_record.access_count; - my_lres = score_record.my_access_count; - conn_lres = score_record.conn_count; - bytes= score_record.bytes_served; - my_bytes = score_record.my_bytes_served; - conn_bytes = score_record.conn_bytes; - if (lres!=0 || (score_record.status != SERVER_READY - && score_record.status != SERVER_DEAD)) - { - if (!short_report) - { - if (no_table_report) - { - rprintf(r,"<b>Server %d</b> (%d): %d|%lu|%lu [", - i,(int)score_record.pid,(int)conn_lres,my_lres,lres); - - switch (score_record.status) - { - case SERVER_READY: - rputs("Ready",r); - break; - case SERVER_STARTING: - rputs("Starting",r); - break; - case SERVER_BUSY_READ: - rputs("<b>Read</b>",r); - break; - case SERVER_BUSY_WRITE: - rputs("<b>Write</b>",r); - break; - case SERVER_BUSY_KEEPALIVE: - rputs("<b>Keepalive</b>",r); - break; - case SERVER_BUSY_LOG: - rputs("<b>Logging</b>",r); - break; - case SERVER_BUSY_DNS: - rputs("<b>DNS lookup</b>",r); - break; - case SERVER_DEAD: - rputs("Dead",r); - break; - case SERVER_GRACEFUL: - rputs("Graceful",r); - break; - default: - rputs("?STATE?",r); - break; - } -#ifdef __EMX__ - /* Allow for OS/2 not having CPU stats */ - rprintf(r,"]\n %s (", -#else - - rprintf(r,"] u%g s%g cu%g cs%g\n %s (", - score_record.times.tms_utime/tick, - score_record.times.tms_stime/tick, - score_record.times.tms_cutime/tick, - score_record.times.tms_cstime/tick, -#endif - asctime(localtime(&score_record.last_used))); - format_byte_out(r,conn_bytes); - rputs("|",r); - format_byte_out(r,my_bytes); - rputs("|",r); - format_byte_out(r,bytes); - rputs(")\n",r); - rprintf(r," <i>%s {%s}</i><br>\n\n", - score_record.client, - escape_html(r->pool, score_record.request)); - } - else /* !no_table_report */ - { - rprintf(r,"<tr><td><b>%d</b><td>%d<td>%d/%lu/%lu", - i,(int)score_record.pid,(int)conn_lres,my_lres,lres); - - switch (score_record.status) - { - case SERVER_READY: - rputs("<td>_",r); - break; - case SERVER_STARTING: - rputs("<td><b>S</b>",r); - break; - case SERVER_BUSY_READ: - rputs("<td><b>R</b>",r); - break; - case SERVER_BUSY_WRITE: - rputs("<td><b>W</b>",r); - break; - case SERVER_BUSY_KEEPALIVE: - rputs("<td><b>K</b>",r); - break; - case SERVER_BUSY_LOG: - rputs("<td><b>L</b>",r); - break; - case SERVER_BUSY_DNS: - rputs("<td><b>D</b>",r); - break; - case SERVER_DEAD: - rputs("<td>.",r); - break; - case SERVER_GRACEFUL: - rputs("<td>G",r); - break; - default: - rputs("<td>?",r); - break; - } -#ifdef __EMX__ - /* Allow for OS/2 not having CPU stats */ - rprintf(r,"\n<td>%.0f", -#else - rprintf(r,"\n<td>%.2f<td>%.0f", - (score_record.times.tms_utime + - score_record.times.tms_stime + - score_record.times.tms_cutime + - score_record.times.tms_cstime)/tick, -#endif - difftime(nowtime, score_record.last_used)); - rprintf(r,"<td>%-1.1f<td>%-2.2f<td>%-2.2f\n", - (float)conn_bytes/KBYTE, (float)my_bytes/MBYTE, - (float)bytes/MBYTE); - rprintf(r,"<td>%s<td nowrap>%s<td nowrap>%s</tr>\n\n", - score_record.client, score_record.vhost, - escape_html(r->pool, score_record.request)); - } /* no_table_report */ - } /* !short_report */ - } /* if (<active child>) */ - } /* for () */ - - if (!(short_report || no_table_report)) - { -#ifdef __EMX__ - rputs("</table>\n \ -<hr> \ -<table>\n \ -<tr><th>Srv<td>Server number\n \ -<tr><th>PID<td>OS process ID\n \ -<tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \ -<tr><th>M<td>Mode of operation\n \ -<tr><th>SS<td>Seconds since beginning of most recent request\n \ -<tr><th>Conn<td>Kilobytes transferred this connection\n \ -<tr><th>Child<td>Megabytes transferred this child\n \ -<tr><th>Slot<td>Total megabytes transferred this slot\n \ -</table>\n",r); -#else - rputs("</table>\n \ -<hr> \ -<table>\n \ -<tr><th>Srv<td>Server number\n \ -<tr><th>PID<td>OS process ID\n \ -<tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \ -<tr><th>M<td>Mode of operation\n \ -<tr><th>CPU<td>CPU usage, number of seconds\n \ -<tr><th>SS<td>Seconds since beginning of most recent request\n \ -<tr><th>Conn<td>Kilobytes transferred this connection\n \ -<tr><th>Child<td>Megabytes transferred this child\n \ -<tr><th>Slot<td>Total megabytes transferred this slot\n \ -</table>\n",r); -#endif - } - -#else /* !defined(STATUS) */ - - rputs("<hr>To obtain a full report with current status information and",r); - rputs(" DNS and LOGGING status codes \n",r); - rputs("you need to recompile Apache after adding the line <pre>",r); - rputs("Rule STATUS=yes</pre>into the file <code>Configuration</code>\n",r); - -#endif /* STATUS */ - - if (!short_report) - rputs("</BODY></HTML>\n",r); - - kill_timeout(r); - return 0; -} - -handler_rec status_handlers[] = -{ -{ STATUS_MAGIC_TYPE, status_handler }, -{ "server-status", status_handler }, -{ NULL } -}; - -module status_module = -{ - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - NULL, /* command table */ - status_handlers, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_userdir.c b/usr.sbin/httpd/src/mod_userdir.c deleted file mode 100644 index d251e92b60b..00000000000 --- a/usr.sbin/httpd/src/mod_userdir.c +++ /dev/null @@ -1,214 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * mod_userdir... implement the UserDir command. Broken away from the - * Alias stuff for a couple of good and not-so-good reasons: - * - * 1) It shows a real minimal working example of how to do something like - * this. - * 2) I know people who are actually interested in changing this *particular* - * aspect of server functionality without changing the rest of it. That's - * what this whole modular arrangement is supposed to be good at... - * - * Modified by Alexei Kosut to support the following constructs - * (server running at www.foo.com, request for /~bar/one/two.html) - * - * UserDir public_html -> ~bar/public_html/one/two.html - * UserDir /usr/web -> /usr/web/bar/one/two.html - * UserDir /home/ * /www -> /home/bar/www/one/two.html - * NOTE: theses ^ ^ space only added allow it to work in a comment, ignore - * UserDir http://x/users -> (302) http://x/users/bar/one/two.html - * UserDir http://x/ * /y -> (302) http://x/bar/y/one/two.html - * NOTE: here also ^ ^ - * - * In addition, you can use multiple entries, to specify alternate - * user directories (a la Directory Index). For example: - * - * UserDir public_html /usr/web http://www.xyz.com/users - * - */ - -#include "httpd.h" -#include "http_config.h" - -module userdir_module; - -/* - * Sever config for this module is a little unconventional... - * It's just one string anyway, so why pretend? - */ - -void *create_userdir_config (pool *dummy, server_rec *s) { - return (void*)DEFAULT_USER_DIR; -} - -const char *set_user_dir (cmd_parms *cmd, void *dummy, char *arg) -{ - void *server_conf = cmd->server->module_config; - - set_module_config (server_conf, &userdir_module, pstrdup (cmd->pool, arg)); - return NULL; -} - -command_rec userdir_cmds[] = { -{ "UserDir", set_user_dir, NULL, RSRC_CONF, RAW_ARGS, - "the public subdirectory in users' home directories, or 'disabled'" }, -{ NULL } -}; - -int translate_userdir (request_rec *r) -{ - void *server_conf = r->server->module_config; - const char *userdirs = (char *)get_module_config(server_conf, - &userdir_module); - char *name = r->uri; - const char *w, *dname, *redirect; - char *x = NULL; - struct stat statbuf; - - if (userdirs == NULL || !strcasecmp(userdirs, "disabled") || - (name[0] != '/') || (name[1] != '~')) { - return DECLINED; - } - - while (*userdirs) { - const char *userdir = getword_conf (r->pool, &userdirs); - char *filename = NULL; - - dname = name + 2; - w = getword(r->pool, &dname, '/'); - - /* disallow the empty username, . and .. */ - if (w[0] == '\0' || (w[1] == '.' && (w[2] == '\0' || (w[2] == '.' && w[3] == '\0')))) - return DECLINED; - - /* The 'dname' funny business involves backing it up to capture - * the '/' delimiting the "/~user" part from the rest of the URL, - * in case there was one (the case where there wasn't being just - * "GET /~user HTTP/1.0", for which we don't want to tack on a - * '/' onto the filename). - */ - - if (dname[-1] == '/') --dname; - - if (strchr(userdir, '*')) - x = getword(r->pool, &userdir, '*'); - -#ifdef __EMX__ - /* Add support for OS/2 drive letters */ - if ((userdir[0] == '/') || (userdir[1] == ':') || (userdir[0] == '\0')) { -#else - if ((userdir[0] == '/') || (userdir[0] == '\0')) { -#endif - if (x) { - if (strchr(x, ':')) { - redirect = pstrcat(r->pool, x, w, userdir, dname, NULL); - table_set (r->headers_out, "Location", redirect); - return REDIRECT; - } - else - filename = pstrcat (r->pool, x, w, userdir, NULL); - } - else - filename = pstrcat (r->pool, userdir, "/", w, NULL); - } - else if (strchr(userdir, ':')) { - redirect = pstrcat(r->pool, userdir, "/", w, dname, NULL); - table_set (r->headers_out, "Location", redirect); - return REDIRECT; - } - else { - struct passwd *pw; - if((pw=getpwnam(w))) -#ifdef __EMX__ - /* Need to manually add user name for OS/2 */ - filename = pstrcat (r->pool, pw->pw_dir, w, "/", userdir, NULL); -#else - filename = pstrcat (r->pool, pw->pw_dir, "/", userdir, NULL); -#endif - - } - - /* Now see if it exists, or we're at the last entry. If we are at the - last entry, then use the filename generated (if there is one) anyway, - in the hope that some handler might handle it. This can be used, for - example, to run a CGI script for the user. - */ - if (filename && (!*userdirs || stat(filename, &statbuf) != -1)) { - r->filename = pstrcat(r->pool, filename, dname, NULL); - r->finfo = statbuf; - return OK; - } - } - - return DECLINED; -} - -module userdir_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - create_userdir_config, /* server config */ - NULL, /* merge server config */ - userdir_cmds, /* command table */ - NULL, /* handlers */ - translate_userdir, /*filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - NULL, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/mod_usertrack.c b/usr.sbin/httpd/src/mod_usertrack.c deleted file mode 100644 index 5be43124151..00000000000 --- a/usr.sbin/httpd/src/mod_usertrack.c +++ /dev/null @@ -1,328 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* User Tracking Module (Was mod_cookies.c) - * - * This Apache module is designed to track users paths through a site. - * It uses the client-side state ("Cookie") protocol developed by Netscape. - * It is known to work on Netscape browsers, Microsoft Internet - * Explorer and others currently being developed. - * - * Each time a page is requested we look to see if the browser is sending - * us a Cookie: header that we previously generated. - * - * If we don't find one then the user hasn't been to this site since - * starting their browser or their browser doesn't support cookies. So - * we generate a unique Cookie for the transaction and send it back to - * the browser (via a "Set-Cookie" header) - * Future requests from the same browser should keep the same Cookie line. - * - * By matching up all the requests with the same cookie you can - * work out exactly what path a user took through your site. To log - * the cookie use the " %{Cookie}n " directive in a custom access log; - * - * Example 1 : If you currently use the standard Log file format (CLF) - * and use the command "TransferLog somefilename", add the line - * LogFormat "%h %l %u %t \"%r\" %s %b %{Cookie}n" - * to your config file. - * - * Example 2 : If you used to use the old "CookieLog" directive, you - * can emulate it by adding the following command to your config file - * CustomLog filename "%{Cookie}n \"%r\" %t" - * - * Notes: - * 1. This code now logs the initial transaction (the one that created - * the cookie to start with). - * 2. This module has been designed to not interfere with other Cookies - * your site may be using; just avoid sending out cookies with - * the name "Apache=" or things will get confused. - * 3. If you want you can modify the Set-Cookie line so that the Cookie - * never expires. You would then get the same Cookie each time the - * user revisits your site. - * - * Mark Cox, mark@ukweb.com, 6 July 95 - * - * This file replaces mod_cookies.c - */ - -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#ifndef MPE -#include <sys/time.h> -#endif - -module usertrack_module; - -typedef struct { - int always; - time_t expires; -} cookie_log_state; - -/* Define this to allow post-2000 cookies. Cookies use two-digit dates, - * so it might be dicey. (Netscape does it correctly, but others may not) - */ -#define MILLENIAL_COOKIES - -/* Make Cookie: Now we have to generate something that is going to be - * pretty unique. We can base it on the pid, time, hostip */ - -#define COOKIE_NAME "Apache=" - -void make_cookie(request_rec *r) -{ - cookie_log_state *cls = get_module_config (r->server->module_config, - &usertrack_module); -#ifdef MPE - clock_t mpe_times; - struct tms mpe_tms; -#else - struct timeval tv; - struct timezone tz = { 0 , 0 }; -#endif - /* 1024 == hardcoded constants */ - char *new_cookie = palloc( r->pool, 1024); - char *cookiebuf = palloc( r->pool, 1024); - char *dot; - const char *rname = pstrdup(r->pool, - get_remote_host(r->connection, r->per_dir_config, - REMOTE_NAME)); - - if ((dot = strchr(rname,'.'))) *dot='\0'; /* First bit of hostname */ - -#ifdef MPE -/* MPE lacks gettimeofday(), so we must use time() to obtain the epoch - seconds, and then times() to obtain CPU clock ticks (milliseconds). - Combine this together to obtain a hopefully unique cookie ID. */ - - mpe_times=times(&mpe_tms); - - ap_snprintf(cookiebuf, 1024, "%s%d%ld%ld", rname, (int)getpid(), - (long)time(NULL), (long)mpe_tms.tms_utime); -#else - gettimeofday(&tv, &tz); - - ap_snprintf(cookiebuf, 1024, "%s%d%ld%d", rname, (int)getpid(), - (long)tv.tv_sec, (int)tv.tv_usec/1000); -#endif - - if (cls->expires) { - static const char *const days[7]= - {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; - struct tm *tms; - time_t when = time(NULL) + cls->expires; - -#ifndef MILLENIAL_COOKIES - /* Only two-digit date string, so we can't trust "00" or more. - * Therefore, we knock it all back to just before midnight on - * 1/1/2000 (which is 946684799) - */ - - if (when > 946684799) - when = 946684799; -#endif - tms = gmtime(&when); - - /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */ - ap_snprintf(new_cookie, 1024, - "%s%s; path=/; expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT", - COOKIE_NAME, cookiebuf, days[tms->tm_wday], - tms->tm_mday, month_snames[tms->tm_mon], - (tms->tm_year >= 100) ? tms->tm_year - 100 : tms->tm_year, - tms->tm_hour, tms->tm_min, tms->tm_sec); - } - else - ap_snprintf(new_cookie, 1024, "%s%s; path=/", COOKIE_NAME, cookiebuf); - - table_set(r->headers_out,"Set-Cookie",new_cookie); - table_set(r->notes, "cookie", cookiebuf); /* log first time */ - return; -} - -int spot_cookie(request_rec *r) -{ - int *enable = (int *)get_module_config(r->per_dir_config, - &usertrack_module); - char *cookie; - char *value; - - if (!*enable) return DECLINED; - - if ((cookie = table_get (r->headers_in, "Cookie"))) - if ((value=strstr(cookie,COOKIE_NAME))) { - char *cookiebuf, *cookieend; - - value+=strlen(COOKIE_NAME); - cookiebuf=pstrdup( r->pool, value ); - cookieend=strchr(cookiebuf,';'); - if (cookieend) *cookieend='\0'; /* Ignore anything after a ; */ - - /* Set the cookie in a note, for logging */ - table_set(r->notes, "cookie", cookiebuf); - - return DECLINED; /* Theres already a cookie, no new one */ - } - make_cookie(r); - return OK; /* We set our cookie */ -} - -void *make_cookie_log_state (pool *p, server_rec *s) -{ - cookie_log_state *cls = - (cookie_log_state *)palloc (p, sizeof (cookie_log_state)); - - cls->expires = 0; - - return (void *)cls; -} - -void *make_cookie_dir (pool *p, char *d) { - return (void *)pcalloc(p, sizeof(int)); -} - -const char *set_cookie_enable (cmd_parms *cmd, int *c, int arg) -{ - *c = arg; - return NULL; -} - -const char *set_cookie_exp (cmd_parms *parms, void *dummy, const char *arg) -{ - cookie_log_state *cls = get_module_config (parms->server->module_config, - &usertrack_module); - time_t factor, modifier = 0; - time_t num = 0; - char *word; - - /* The simple case first - all numbers (we assume) */ - if (isdigit(arg[0]) && isdigit(arg[strlen(arg)-1])) { - cls->expires = atol(arg); - return NULL; - } - - /* The harder case - stolen from mod_expires - * CookieExpires "[plus] {<num> <type>}*" - */ - - word = getword_conf( parms->pool, &arg ); - if ( !strncasecmp( word, "plus", 1 ) ) { - word = getword_conf( parms->pool, &arg ); - }; - - /* {<num> <type>}* */ - while ( word[0] ) { - /* <num> */ - if ( strchr("0123456789", word[0]) != NULL ) - num = atoi( word ); - else - return "bad expires code, numeric value expected."; - - /* <type> */ - word = getword_conf( parms->pool, &arg ); - if (!word[0] ) - return "bad expires code, missing <type>"; - - factor = 0; - if ( !strncasecmp( word, "years", 1 ) ) - factor = 60*60*24*365; - else if ( !strncasecmp( word, "months", 2 ) ) - factor = 60*60*24*30; - else if ( !strncasecmp( word, "weeks", 1 ) ) - factor = 60*60*24*7; - else if ( !strncasecmp( word, "days", 1 ) ) - factor = 60*60*24; - else if ( !strncasecmp( word, "hours", 1 ) ) - factor = 60*60; - else if ( !strncasecmp( word, "minutes", 2 ) ) - factor = 60; - else if ( !strncasecmp( word, "seconds", 1 ) ) - factor = 1; - else - return "bad expires code, unrecognized type"; - - modifier = modifier + factor * num; - - /* next <num> */ - word = getword_conf( parms->pool, &arg ); - } - - cls->expires = modifier; - - return NULL; -} - -command_rec cookie_log_cmds[] = { -{ "CookieExpires", set_cookie_exp, NULL, RSRC_CONF, TAKE1, - "an expiry date code" }, -{ "CookieTracking", set_cookie_enable, NULL, OR_FILEINFO, FLAG, - "whether or not to enable cookies" }, -{ NULL } -}; - -module usertrack_module = { - STANDARD_MODULE_STUFF, - NULL, /* initializer */ - make_cookie_dir, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - make_cookie_log_state, /* server config */ - NULL, /* merge server configs */ - cookie_log_cmds, /* command table */ - NULL, /* handlers */ - NULL, /* filename translation */ - NULL, /* check_user_id */ - NULL, /* check auth */ - NULL, /* check access */ - NULL, /* type_checker */ - spot_cookie, /* fixups */ - NULL, /* logger */ - NULL /* header parser */ -}; diff --git a/usr.sbin/httpd/src/modules/example/Makefile b/usr.sbin/httpd/src/modules/example/Makefile deleted file mode 100644 index 9bec391a3bf..00000000000 --- a/usr.sbin/httpd/src/modules/example/Makefile +++ /dev/null @@ -1,107 +0,0 @@ -# ==================================================================== -# Copyright (c) 1995-1997 The Apache Group. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. All advertising materials mentioning features or use of this -# software must display the following acknowledgment: -# "This product includes software developed by the Apache Group -# for use in the Apache HTTP server project (http://www.apache.org/)." -# -# 4. The names "Apache Server" and "Apache Group" must not be used to -# endorse or promote products derived from this software without -# prior written permission. -# -# 5. Redistributions of any form whatsoever must retain the following -# acknowledgment: -# "This product includes software developed by the Apache Group -# for use in the Apache HTTP server project (http://www.apache.org/)." -# -# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR -# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -# OF THE POSSIBILITY OF SUCH DAMAGE. -# ==================================================================== -# -# This software consists of voluntary contributions made by many -# individuals on behalf of the Apache Group and was originally based -# on public domain software written at the National Center for -# Supercomputing Applications, University of Illinois, Urbana-Champaign. -# For more information on the Apache Group and the Apache HTTP server -# project, please see <http://www.apache.org/>. -# -# Makefile for the Apache example module -# - -# -# This normally lives in modules/example under the Apache source -# directory. If the depth or relationship changes, the following line -# may need to be changed. -# -INCDIR=../.. - -# -# Everything below this point should be invariant. -# -SHELL=/bin/sh - -# -# We inherit the definitions of CC, AUX_CFLAGS, and RANLIB from an -# upline make(1) call. -# -CFLAGS=-I$(INCDIR) $(AUX_CFLAGS) - -MODULES=mod_example.o -OBJS= \ - $(MODULES) - -# -# Now the rules saying how things are built. -# -.c.o: - $(CC) -c $(CFLAGS) $< - -all: $(OBJS) - -clean: - rm -f $(OBJS) - -# -# Finally, what depnds upon which, so make can figure out what it needs -# to do. -# - -# -# Make sure that things get rebuilt if the Makefiles are changed. -# -$(OBJS): \ - Makefile \ - $(INCDIR)/Makefile - -mod_example.o: \ - $(INCDIR)/httpd.h \ - $(INCDIR)/http_config.h \ - $(INCDIR)/http_core.h \ - $(INCDIR)/http_log.h \ - $(INCDIR)/http_main.h \ - $(INCDIR)/http_protocol.h \ - $(INCDIR)/util_script.h \ - mod_example.c diff --git a/usr.sbin/httpd/src/modules/proxy/Makefile b/usr.sbin/httpd/src/modules/proxy/Makefile deleted file mode 100644 index 102dea2a25f..00000000000 --- a/usr.sbin/httpd/src/modules/proxy/Makefile +++ /dev/null @@ -1,89 +0,0 @@ -# ==================================================================== -# Copyright (c) 1995-1997 The Apache Group. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. All advertising materials mentioning features or use of this -# software must display the following acknowledgment: -# "This product includes software developed by the Apache Group -# for use in the Apache HTTP server project (http://www.apache.org/)." -# -# 4. The names "Apache Server" and "Apache Group" must not be used to -# endorse or promote products derived from this software without -# prior written permission. -# -# 5. Redistributions of any form whatsoever must retain the following -# acknowledgment: -# "This product includes software developed by the Apache Group -# for use in the Apache HTTP server project (http://www.apache.org/)." -# -# THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR -# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -# OF THE POSSIBILITY OF SUCH DAMAGE. -# ==================================================================== -# -# This software consists of voluntary contributions made by many -# individuals on behalf of the Apache Group and was originally based -# on public domain software written at the National Center for -# Supercomputing Applications, University of Illinois, Urbana-Champaign. -# For more information on the Apache Group and the Apache HTTP server -# project, please see <http://www.apache.org/>. -# -# Makefile for the Apache proxy library -# - -SHELL = /bin/sh - -INCDIR = ../.. - -LIB=libproxy.a - -# AUX_CFLAGS comes from higher level Makefile -CFLAGS=-I$(INCDIR) $(AUX_CFLAGS) - -# Internal stuff, should not need changing. -PROXYSRC=mod_proxy.c proxy_cache.c proxy_connect.c proxy_ftp.c proxy_http.c \ -proxy_util.c - -OBJS=$(PROXYSRC:.c=.o) - -default: force $(LIB) - -.c.a: - $(MAKE) $(CFLAGS) $< - -force: - rm -f $(LIB) - -$(LIB): $(OBJS) - ar crv $@ $(OBJS) - $(RANLIB) $@ - -clean: - rm -f *.o libproxy.a - -# dependencies -$(OBJS): mod_proxy.h $(INCDIR)/httpd.h $(INCDIR)/http_config.h $(INCDIR)/http_protocol.h -proxy_cache.o proxy_connect.o proxy_ftp.o proxy_http.o proxy_util.o: $(INCDIR)/http_main.h -proxy_cache.o proxy_connect.o proxy_http.o: $(INCDIR)/http_log.h -proxy_cache.o proxy_http.o: $(INCDIR)/util_date.h -proxy_cache.o proxy_util.o: $(INCDIR)/md5.h diff --git a/usr.sbin/httpd/src/regex/Makefile b/usr.sbin/httpd/src/regex/Makefile deleted file mode 100644 index e4ea0154bea..00000000000 --- a/usr.sbin/httpd/src/regex/Makefile +++ /dev/null @@ -1,133 +0,0 @@ -SHELL = /bin/sh - -# You probably want to take -DREDEBUG out of CFLAGS, and put something like -# -O in, *after* testing (-DREDEBUG strengthens testing by enabling a lot of -# internal assertion checking and some debugging facilities). -# Put -Dconst= in for a pre-ANSI compiler. -# Do not take -DPOSIX_MISTAKE out. -# REGCFLAGS isn't important to you (it's for my use in some special contexts). -CFLAGS=-I. -DPOSIX_MISTAKE $(AUX_CFLAGS) - -# If you have a pre-ANSI compiler, put -o into MKHFLAGS. If you want -# the Berkeley __P macro, put -b in. -MKHFLAGS= - -# Flags for linking but not compiling, if any. -LDFLAGS= - -# Extra libraries for linking, if any. -LIBS= - -# Internal stuff, should not need changing. -OBJPRODN=regcomp.o regexec.o regerror.o regfree.o -OBJS=$(OBJPRODN) split.o debug.o main.o -H=cclass.h cname.h regex2.h utils.h -REGSRC=regcomp.c regerror.c regexec.c regfree.c -ALLSRC=$(REGSRC) engine.c debug.c main.c split.c - -# Stuff that matters only if you're trying to lint the package. -LINTFLAGS=-I. -Dstatic= -Dconst= -DREDEBUG -LINTC=regcomp.c regexec.c regerror.c regfree.c debug.c main.c -JUNKLINT=possible pointer alignment|null effect - -# arrangements to build forward-reference header files -.SUFFIXES: .ih .h -.c.ih: - sh ./mkh $(MKHFLAGS) -p $< >$@ - -default: r - -lib: purge $(OBJPRODN) - rm -f libregex.a - ar crv libregex.a $(OBJPRODN) - $(RANLIB) libregex.a - -purge: - rm -f *.o - -# stuff to build regex.h -REGEXH=regex.h -REGEXHSRC=regex2.h $(REGSRC) -$(REGEXH): $(REGEXHSRC) mkh - sh ./mkh $(MKHFLAGS) -i _REGEX_H_ $(REGEXHSRC) >regex.tmp - cmp -s regex.tmp regex.h 2>/dev/null || cp regex.tmp regex.h - rm -f regex.tmp - -# dependencies -$(OBJPRODN) debug.o: utils.h regex.h regex2.h -regcomp.o: cclass.h cname.h regcomp.ih -regexec.o: engine.c engine.ih -regerror.o: regerror.ih -debug.o: debug.ih -main.o: main.ih - -# tester -re: $(OBJS) - $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ - -# regression test -r: re tests - ./re <tests - ./re -el <tests - ./re -er <tests - -# 57 variants, and other stuff, for development use -- not useful to you -ra: ./re tests - -./re <tests - -./re -el <tests - -./re -er <tests - -rx: ./re tests - ./re -x <tests - ./re -x -el <tests - ./re -x -er <tests - -t: ./re tests - -time ./re <tests - -time ./re -cs <tests - -time ./re -el <tests - -time ./re -cs -el <tests - -l: $(LINTC) - lint $(LINTFLAGS) -h $(LINTC) 2>&1 | egrep -v '$(JUNKLINT)' | tee lint - -fullprint: - ti README WHATSNEW notes todo | list - ti *.h | list - list *.c - list regex.3 regex.7 - -print: - ti README WHATSNEW notes todo | list - ti *.h | list - list reg*.c engine.c - - -mf.tmp: Makefile - sed '/^REGEXH=/s/=.*/=regex.h/' Makefile | sed '/#DEL$$/d' >$@ - -DTRH=cclass.h cname.h regex2.h utils.h -PRE=COPYRIGHT README WHATSNEW -POST=mkh regex.3 regex.7 tests $(DTRH) $(ALLSRC) fake/*.[ch] -FILES=$(PRE) Makefile $(POST) -DTR=$(PRE) Makefile=mf.tmp $(POST) -dtr: $(FILES) mf.tmp - makedtr $(DTR) >$@ - rm mf.tmp - -cio: $(FILES) - cio $(FILES) - -rdf: $(FILES) - rcsdiff -c $(FILES) 2>&1 | p - -# various forms of cleanup -tidy: - rm -f junk* core core.* *.core dtr *.tmp lint - -clean: tidy - rm -f *.o *.s *.ih re libregex.a - -# don't do this one unless you know what you're doing -spotless: clean - rm -f mkh regex.h diff --git a/usr.sbin/httpd/src/regex/regex.h b/usr.sbin/httpd/src/regex/regex.h deleted file mode 100644 index dde954d8332..00000000000 --- a/usr.sbin/httpd/src/regex/regex.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _REGEX_H_ -#define _REGEX_H_ /* never again */ -/* ========= begin header generated by ./mkh ========= */ -#ifdef __cplusplus -extern "C" { -#endif - -/* === regex2.h === */ -typedef off_t regoff_t; -typedef struct { - int re_magic; - size_t re_nsub; /* number of parenthesized subexpressions */ - const char *re_endp; /* end pointer for REG_PEND */ - struct re_guts *re_g; /* none of your business :-) */ -} regex_t; -typedef struct { - regoff_t rm_so; /* start of match */ - regoff_t rm_eo; /* end of match */ -} regmatch_t; - - -/* === regcomp.c === */ -extern int regcomp(regex_t *, const char *, int); -#define REG_BASIC 0000 -#define REG_EXTENDED 0001 -#define REG_ICASE 0002 -#define REG_NOSUB 0004 -#define REG_NEWLINE 0010 -#define REG_NOSPEC 0020 -#define REG_PEND 0040 -#define REG_DUMP 0200 - - -/* === regerror.c === */ -#define REG_NOMATCH 1 -#define REG_BADPAT 2 -#define REG_ECOLLATE 3 -#define REG_ECTYPE 4 -#define REG_EESCAPE 5 -#define REG_ESUBREG 6 -#define REG_EBRACK 7 -#define REG_EPAREN 8 -#define REG_EBRACE 9 -#define REG_BADBR 10 -#define REG_ERANGE 11 -#define REG_ESPACE 12 -#define REG_BADRPT 13 -#define REG_EMPTY 14 -#define REG_ASSERT 15 -#define REG_INVARG 16 -#define REG_ATOI 255 /* convert name to number (!) */ -#define REG_ITOA 0400 /* convert number to name (!) */ -extern size_t regerror(int, const regex_t *, char *, size_t); - - -/* === regexec.c === */ -extern int regexec(const regex_t *, const char *, size_t, regmatch_t [], int); -#define REG_NOTBOL 00001 -#define REG_NOTEOL 00002 -#define REG_STARTEND 00004 -#define REG_TRACE 00400 /* tracing of execution */ -#define REG_LARGE 01000 /* force large representation */ -#define REG_BACKR 02000 /* force use of backref code */ - - -/* === regfree.c === */ -extern void regfree(regex_t *); - -#ifdef __cplusplus -} -#endif -/* ========= end header generated by ./mkh ========= */ -#endif diff --git a/usr.sbin/httpd/src/rfc1413.c b/usr.sbin/httpd/src/rfc1413.c deleted file mode 100644 index 69f7cda92de..00000000000 --- a/usr.sbin/httpd/src/rfc1413.c +++ /dev/null @@ -1,239 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * rfc1413() speaks a common subset of the RFC 1413, AUTH, TAP and IDENT - * protocols. The code queries an RFC 1413 etc. compatible daemon on a remote - * host to look up the owner of a connection. The information should not be - * used for authentication purposes. This routine intercepts alarm signals. - * - * Diagnostics are reported through syslog(3). - * - * Author: Wietse Venema, Eindhoven University of Technology, - * The Netherlands. - */ - -/* Some small additions for Apache --- ditch the "sccsid" var if - * compiling with gcc (it *has* changed), include conf.h for the - * prototypes it defines on at least one system (SunlOSs) which has - * them missing from the standard header files, and one minor change - * below (extra parens around assign "if (foo = bar) ..." to shut up - * gcc -Wall). - */ - -/* Rewritten by David Robinson */ - -#include "httpd.h" /* for server_rec, conn_rec, ap_longjmp, etc. */ -#include "http_log.h" /* for log_unixerr */ -#include "rfc1413.h" - -#ifndef SCO -extern char *strchr(); -extern char *inet_ntoa(); -#endif - -/* Local stuff. */ -/* Semi-well-known port */ -#define RFC1413_PORT 113 -/* maximum allowed length of userid */ -#define RFC1413_USERLEN 512 -/* rough limit on the amount of data we accept. */ -#define RFC1413_MAXDATA 1000 - -#ifndef RFC1413_TIMEOUT -#define RFC1413_TIMEOUT 30 -#endif -#define ANY_PORT 0 /* Any old port will do */ -#define FROM_UNKNOWN "unknown" - -int rfc1413_timeout = RFC1413_TIMEOUT; /* Global so it can be changed */ - -JMP_BUF timebuf; - -/* bind_connect - bind both ends of a socket */ - -static int -get_rfc1413(int sock, const struct sockaddr_in *our_sin, - const struct sockaddr_in *rmt_sin, char user[RFC1413_USERLEN+1], - server_rec *srv) -{ - struct sockaddr_in rmt_query_sin, our_query_sin; - unsigned int rmt_port, our_port; - int i; - char *cp; - char buffer[RFC1413_MAXDATA+1]; - - /* - * Bind the local and remote ends of the query socket to the same - * IP addresses as the connection under investigation. We go - * through all this trouble because the local or remote system - * might have more than one network address. The RFC1413 etc. - * client sends only port numbers; the server takes the IP - * addresses from the query socket. - */ - - our_query_sin = *our_sin; - our_query_sin.sin_port = htons(ANY_PORT); - rmt_query_sin = *rmt_sin; - rmt_query_sin.sin_port = htons(RFC1413_PORT); - - if (bind(sock, (struct sockaddr *)&our_query_sin, - sizeof(struct sockaddr_in)) < 0) - { - log_unixerr("bind", NULL, "rfc1413: Error binding to local port", srv); - return -1; - } - -/* - * errors from connect usually imply the remote machine doesn't support - * the service - */ - if (connect(sock, (struct sockaddr *)&rmt_query_sin, - sizeof(struct sockaddr_in)) < 0) - return -1; - -/* send the data */ - ap_snprintf(buffer, sizeof(buffer), "%u,%u\r\n", ntohs(rmt_sin->sin_port), - ntohs(our_sin->sin_port)); - - /* send query to server. Handle short write. */ - i = 0; - while(i < strlen(buffer)) { - int j; - j = write(sock, buffer+i, (strlen(buffer+i))); - if (j < 0 && errno != EINTR) { - log_unixerr("write", NULL, "rfc1413: error sending request", srv); - return -1; - } - else if (j > 0) { - i+=j; - } - } - - /* - * Read response from server. - the response should be newline - * terminated according to rfc - make sure it doesn't stomp it's - * way out of the buffer. - */ - i = 0; - memset(buffer, 0, sizeof(buffer)); - while((cp = strchr(buffer, '\n')) == NULL && i < sizeof(buffer) - 1) { - int j; - j = read(sock, buffer+i, (sizeof(buffer) - 1) - i); - if (j < 0 && errno != EINTR) { - log_unixerr("read", NULL, "rfc1413: error reading response", srv); - return -1; - } - else if (j > 0) { - i+=j; - } - } - -/* RFC1413_USERLEN = 512 */ - if (sscanf(buffer, "%u , %u : USERID :%*[^:]:%512s", &rmt_port, &our_port, - user) != 3 || ntohs(rmt_sin->sin_port) != rmt_port - || ntohs(our_sin->sin_port) != our_port) return -1; - - /* - * Strip trailing carriage return. It is part of the - * protocol, not part of the data. - */ - - if ((cp = strchr(user, '\r'))) *cp = '\0'; - - return 0; -} - -/* ident_timeout - handle timeouts */ -static void -ident_timeout(int sig) -{ - ap_longjmp(timebuf, sig); -} - -/* rfc1413 - return remote user name, given socket structures */ -char * -rfc1413(conn_rec *conn, server_rec *srv) -{ - static char user[RFC1413_USERLEN+1]; /* XXX */ - static char *result; - static int sock; - - result = FROM_UNKNOWN; - - sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) - { - log_unixerr("socket", NULL, "rfc1413: error creating socket", srv); - conn->remote_logname = result; - } - - /* - * Set up a timer so we won't get stuck while waiting for the server. - */ - if (ap_setjmp(timebuf) == 0) - { - signal(SIGALRM, ident_timeout); - alarm(rfc1413_timeout); - - if (get_rfc1413(sock, &conn->local_addr, &conn->remote_addr, user, - srv) - >= 0) - result = user; - - alarm(0); - } - close(sock); - conn->remote_logname = result; - - return conn->remote_logname; -} diff --git a/usr.sbin/httpd/src/rfc1413.h b/usr.sbin/httpd/src/rfc1413.h deleted file mode 100644 index 91bf42e4aef..00000000000 --- a/usr.sbin/httpd/src/rfc1413.h +++ /dev/null @@ -1,53 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -extern char *rfc1413(conn_rec *conn, server_rec *srv); diff --git a/usr.sbin/httpd/src/scoreboard.h b/usr.sbin/httpd/src/scoreboard.h deleted file mode 100644 index 5aa808cb4d6..00000000000 --- a/usr.sbin/httpd/src/scoreboard.h +++ /dev/null @@ -1,110 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#include <sys/times.h> - -/* Scoreboard info on a process is, for now, kept very brief --- - * just status value and pid (the latter so that the caretaker process - * can properly update the scoreboard when a process dies). We may want - * to eventually add a separate set of long_score structures which would - * give, for each process, the number of requests serviced, and info on - * the current, or most recent, request. - * - * Status values: - */ - -#define SERVER_UNKNOWN (-1) /* should never be in this state */ -#define SERVER_DEAD 0 -#define SERVER_READY 1 /* Waiting for connection (or accept() lock) */ -#define SERVER_STARTING 3 /* Server Starting up */ -#define SERVER_BUSY_READ 2 /* Reading a client request */ -#define SERVER_BUSY_WRITE 4 /* Processing a client request */ -#define SERVER_BUSY_KEEPALIVE 5 /* Waiting for more requests via keepalive */ -#define SERVER_BUSY_LOG 6 /* Logging the request */ -#define SERVER_BUSY_DNS 7 /* Looking up a hostname */ -#define SERVER_GRACEFUL 8 /* server is gracefully finishing request */ - -typedef struct { - pid_t pid; - char status; -#if defined(STATUS) - unsigned long access_count; - unsigned long bytes_served; - unsigned long my_access_count; - unsigned long my_bytes_served; - unsigned long conn_bytes; - unsigned short conn_count; - struct tms times; - time_t last_used; - char client[32]; /* Keep 'em small... */ - char request[64]; /* We just want an idea... */ - char vhost[32]; /* What virtual host is being accessed? */ -#endif -} short_score; - -typedef struct - { - int exit_generation; /* Set by the main process if a graceful - restart is required */ - } global_score; - -typedef struct - { - short_score servers[HARD_SERVER_LIMIT]; - global_score global; - } scoreboard; - -#define SCOREBOARD_SIZE sizeof(scoreboard) - -extern void sync_scoreboard_image(void); -short_score get_scoreboard_info(int x); -int exists_scoreboard_image (); diff --git a/usr.sbin/httpd/src/util.c b/usr.sbin/httpd/src/util.c deleted file mode 100644 index 12096af0932..00000000000 --- a/usr.sbin/httpd/src/util.c +++ /dev/null @@ -1,1369 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * util.c: string utility things - * - * 3/21/93 Rob McCool - * 1995-96 Many changes by the Apache Group - * - */ - -#include "httpd.h" -#include "http_conf_globals.h" /* for user_id & group_id */ - -const char month_snames[12][4] = { - "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" -}; - -char *get_time() { - time_t t; - char *time_string; - - t=time(NULL); - time_string = ctime(&t); - time_string[strlen(time_string) - 1] = '\0'; - return (time_string); -} - -char *ht_time(pool *p, time_t t, const char *fmt, int gmt) { - char ts[MAX_STRING_LEN]; - struct tm *tms; - - tms = (gmt ? gmtime(&t) : localtime(&t)); - - /* check return code? */ - strftime(ts,MAX_STRING_LEN,fmt,tms); - ts[MAX_STRING_LEN - 1] = '\0'; - return pstrdup (p, ts); -} - -char *gm_timestr_822(pool *p, time_t sec) { - static const char *const days[7]= - {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; - char ts[50]; - struct tm *tms; - - tms = gmtime(&sec); - -/* RFC date format; as strftime '%a, %d %b %Y %T GMT' */ - ap_snprintf(ts, sizeof(ts), - "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", days[tms->tm_wday], - tms->tm_mday, month_snames[tms->tm_mon], tms->tm_year + 1900, - tms->tm_hour, tms->tm_min, tms->tm_sec); - - return pstrdup (p, ts); -} - -/* What a pain in the ass. */ -#if defined(HAVE_GMTOFF) -struct tm *get_gmtoff(int *tz) { - time_t tt = time(NULL); - struct tm *t; - - t = localtime(&tt); - *tz = (int) (t->tm_gmtoff / 60); - return t; -} -#else -struct tm *get_gmtoff(int *tz) { - time_t tt = time(NULL); - struct tm gmt; - struct tm *t; - int days, hours, minutes; - - /* Assume we are never more than 24 hours away. */ - gmt = *gmtime(&tt); /* remember gmtime/localtime return ptr to static */ - t = localtime(&tt); /* buffer... so be careful */ - days = t->tm_yday - gmt.tm_yday; - hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) - + t->tm_hour - gmt.tm_hour); - minutes = hours * 60 + t->tm_min - gmt.tm_min; - *tz = minutes; - return t; -} -#endif - - -/* Match = 0, NoMatch = 1, Abort = -1 */ -/* Based loosely on sections of wildmat.c by Rich Salz - * Hmmm... shouldn't this really go component by component? - */ -int strcmp_match(const char *str, const char *exp) { - int x,y; - - for(x=0,y=0;exp[y];++y,++x) { - if((!str[x]) && (exp[y] != '*')) - return -1; - if(exp[y] == '*') { - while(exp[++y] == '*'); - if(!exp[y]) - return 0; - while(str[x]) { - int ret; - if((ret = strcmp_match(&str[x++],&exp[y])) != 1) - return ret; - } - return -1; - } else - if((exp[y] != '?') && (str[x] != exp[y])) - return 1; - } - return (str[x] != '\0'); -} - -int strcasecmp_match(const char *str, const char *exp) { - int x,y; - - for(x=0,y=0;exp[y];++y,++x) { - if((!str[x]) && (exp[y] != '*')) - return -1; - if(exp[y] == '*') { - while(exp[++y] == '*'); - if(!exp[y]) - return 0; - while(str[x]) { - int ret; - if((ret = strcasecmp_match(&str[x++],&exp[y])) != 1) - return ret; - } - return -1; - } else - if((exp[y] != '?') && (tolower(str[x]) != tolower(exp[y]))) - return 1; - } - return (str[x] != '\0'); -} - -int is_matchexp(const char *str) { - register int x; - - for(x=0;str[x];x++) - if((str[x] == '*') || (str[x] == '?')) - return 1; - return 0; -} - -/* This function substitutes for $0-$9, filling in regular expression - * submatches. Pass it the same nmatch and pmatch arguments that you - * passed regexec(). pmatch should not be greater than the maximum number - * of subexpressions - i.e. one more than the re_nsub member of regex_t. - * - * input should be the string with the $-expressions, source should be the - * string that was matched against. - * - * It returns the substituted string, or NULL on error. - * - * Parts of this code are based on Henry Spencer's regsub(), from his - * AT&T V8 regexp package. - */ - -char *pregsub(pool *p, const char *input, const char *source, - size_t nmatch, regmatch_t pmatch[]) { - const char *src = input; - char *dest, *dst; - char c; - int no, len; - - if (!source) return NULL; - if (!nmatch) return pstrdup(p, src); - - /* First pass, find the size */ - - len = 0; - - while ((c = *src++) != '\0') { - if (c == '&') - no = 0; - else if (c == '$' && isdigit(*src)) - no = *src++ - '0'; - else - no = -1; - - if (no < 0) { /* Ordinary character. */ - if (c == '\\' && (*src == '$' || *src == '&')) - c = *src++; - len++; - } else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { - len += pmatch[no].rm_eo - pmatch[no].rm_so; - } - - } - - dest = dst = pcalloc(p, len + 1); - - /* Now actually fill in the string */ - - src = input; - - while ((c = *src++) != '\0') { - if (c == '&') - no = 0; - else if (c == '$' && isdigit(*src)) - no = *src++ - '0'; - else - no = -1; - - if (no < 0) { /* Ordinary character. */ - if (c == '\\' && (*src == '$' || *src == '&')) - c = *src++; - *dst++ = c; - } else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { - len = pmatch[no].rm_eo - pmatch[no].rm_so; - strncpy(dst, source + pmatch[no].rm_so, len); - dst += len; - if (*(dst-1) == '\0') /* strncpy hit NULL. */ - return NULL; - } - - } - *dst = '\0'; - - return dest; -} - -/* - * Parse .. so we don't compromise security - */ -void getparents(char *name) -{ - int l, w; - - /* Four paseses, as per RFC 1808 */ - /* a) remove ./ path segments */ - - for (l=0, w=0; name[l] != '\0';) - { - if (name[l] == '.' && name[l+1] == '/' && (l == 0 || name[l-1] == '/')) - l += 2; - else - name[w++] = name[l++]; - } - - /* b) remove trailing . path, segment */ - if (w == 1 && name[0] == '.') w--; - else if (w > 1 && name[w-1] == '.' && name[w-2] == '/') w--; - name[w] = '\0'; - - /* c) remove all xx/../ segments. (including leading ../ and /../) */ - l = 0; - - while(name[l]!='\0') { - if(name[l] == '.' && name[l+1] == '.' && name[l+2] == '/' && - (l == 0 || name[l-1] == '/')) { - register int m=l+3,n; - - l=l-2; - if(l>=0) { - while(l >= 0 && name[l] != '/') l--; - l++; - } - else l=0; - n=l; - while((name[n]=name[m])) (++n,++m); - } - else ++l; - } - - /* d) remove trailing xx/.. segment. */ - if (l == 2 && name[0] == '.' && name[1] == '.') name[0] = '\0'; - else if (l > 2 && name[l-1] == '.' && name[l-2] == '.' && name[l-3] == '/') - { - l = l - 4; - if (l >= 0) - { - while (l >= 0 && name[l] != '/') l--; - l++; - } - else l = 0; - name[l] = '\0'; - } -} - -void no2slash(char *name) -{ - char *d, *s; - - s = d = name; - while (*s) { - if ((*d++ = *s) == '/') { - do { - ++s; - } while (*s == '/'); - } - else { - ++s; - } - } - *d = '\0'; -} - -char *make_dirstr(pool *p, const char *s, int n) { - register int x,f; - char *res; - - for(x=0,f=0;s[x];x++) { - if(s[x] == '/') - if((++f) == n) { - res = palloc(p, x + 2); - strncpy (res, s, x); - res[x] = '/'; - res[x+1] = '\0'; - return res; - } - } - - if (s[strlen(s) - 1] == '/') - return pstrdup (p, s); - else - return pstrcat (p, s, "/", NULL); -} - -int count_dirs(const char *path) { - register int x,n; - - for(x=0,n=0;path[x];x++) - if(path[x] == '/') n++; - return n; -} - - -void chdir_file(const char *file) { - int i; - - if((i = rind(file,'/')) == -1) - return; - ((char *)file)[i] = '\0'; - chdir(file); - ((char *)file)[i] = '/'; -} - -char *getword_nc(pool* atrans, char **line, char stop) - { - return getword(atrans,(const char **)line,stop); - } - -char *getword(pool* atrans, const char **line, char stop) { - int pos = ind(*line, stop); - char *res; - - if (pos == -1) { - res = pstrdup (atrans, *line); - *line += strlen (*line); - return res; - } - - res = palloc(atrans, pos + 1); - strncpy (res, *line, pos); - res[pos] = '\0'; - - while ((*line)[pos] == stop) ++pos; - - *line += pos; - - return res; -} - -char *getword_white_nc(pool* atrans, char **line) -{ - return getword_white(atrans,(const char **)line); -} - -char *getword_white(pool* atrans, const char **line) { - int pos = -1, x; - char *res; - - for(x=0;(*line)[x];x++) { - if (isspace((*line)[x])) { - pos=x; - break; - } - } - - if (pos == -1) { - res = pstrdup (atrans, *line); - *line += strlen (*line); - return res; - } - - res = palloc(atrans, pos + 1); - strncpy (res, *line, pos); - res[pos] = '\0'; - - while (isspace((*line)[pos])) ++pos; - - *line += pos; - - return res; -} - -char *getword_nulls_nc(pool* atrans, char **line, char stop) -{ - return getword_nulls(atrans,(const char **)line,stop); -} - -char *getword_nulls(pool* atrans, const char **line, char stop) { - int pos = ind(*line, stop); - char *res; - - if (pos == -1) { - res = pstrdup (atrans, *line); - *line += strlen (*line); - return res; - } - - res = palloc(atrans, pos + 1); - strncpy (res, *line, pos); - res[pos] = '\0'; - - ++pos; - - *line += pos; - - return res; -} - -/* Get a word, (new) config-file style --- quoted strings and backslashes - * all honored - */ - -static char *substring_conf (pool *p, const char *start, int len, char quote) -{ - char *result = palloc (p, len + 2); - char *resp = result; - int i; - - for (i = 0; i < len; ++i) { - if (start[i] == '\\' && (start[i+1] == '/' - || (quote && start[i+1] == quote))) - *resp++ = start[++i]; - else - *resp++ = start[i]; - } - - *resp++ = '\0'; - return result; -} - -char *getword_conf_nc(pool* p, char **line) { - return getword_conf(p,(const char **)line); -} - -char *getword_conf(pool* p, const char **line) { - const char *str = *line, *strend; - char *res; - char quote; - - while (*str && isspace (*str)) - ++str; - - if (!*str) { - *line = str; - return ""; - } - - if ((quote = *str) == '"' || quote == '\'') { - strend = str + 1; - while (*strend && *strend != quote) { - if (*strend == '\\' && strend[1] && strend[1] == quote) - strend += 2; - else ++strend; - } - res = substring_conf (p, str + 1, strend - str - 1, quote); - - if (*strend == quote) ++strend; - } else { - strend = str; - while (*strend && !isspace (*strend)) - ++strend; - - res = substring_conf (p, str, strend - str, 0); - } - - while (*strend && isspace(*strend)) ++ strend; - *line = strend; - return res; -} - -#ifdef UNDEF -/* this function is dangerous, and superceded by getword_white, so don't use it - */ -void cfg_getword(char *word, char *line) { - int x=0,y; - - for(x=0;line[x] && isspace(line[x]);x++); - y=0; - while(1) { - if(!(word[y] = line[x])) - break; - if(isspace(line[x])) - if((!x) || (line[x-1] != '\\')) - break; - if(line[x] != '\\') ++y; - ++x; - } - word[y] = '\0'; - while(line[x] && isspace(line[x])) ++x; - for(y=0;(line[y] = line[x]);++x,++y); -} -#endif - -int -cfg_getline(char *s, int n, FILE *f) { - register int i=0, c; - - s[0] = '\0'; - /* skip leading whitespace */ - do { - c = getc(f); - } while (c == '\t' || c == ' '); - - if(c == EOF) - return 1; - - if(n < 2) { - /* too small, assume caller is crazy */ - return 1; - } - - while(1) { - if((c == '\t') || (c == ' ')) { - s[i++] = ' '; - while((c == '\t') || (c == ' ')) - c = getc(f); - } - if(c == CR) { - c = getc(f); - } - if(c == EOF || c == 0x4 || c == LF || i >= (n-2)) { - /* blast trailing whitespace */ - while(i && (s[i-1] == ' ')) --i; - s[i] = '\0'; - return 0; - } - s[i] = c; - ++i; - c = getc(f); - } -} - -/* Retrieve a token, spacing over it and returning a pointer to - * the first non-white byte afterwards. Note that these tokens - * are delimited by semis and commas; and can also be delimited - * by whitespace at the caller's option. - */ - -char *get_token (pool *p, char **accept_line, int accept_white) -{ - char *ptr = *accept_line; - char *tok_start; - char *token; - int tok_len; - - /* Find first non-white byte */ - - while (*ptr && isspace(*ptr)) - ++ptr; - - tok_start = ptr; - - /* find token end, skipping over quoted strings. - * (comments are already gone). - */ - - while (*ptr && (accept_white || !isspace(*ptr)) - && *ptr != ';' && *ptr != ',') - { - if (*ptr++ == '"') - while (*ptr) - if (*ptr++ == '"') break; - } - - tok_len = ptr - tok_start; - token = palloc (p, tok_len + 1); - strncpy (token, tok_start, tok_len); - token[tok_len] = '\0'; - - /* Advance accept_line pointer to the next non-white byte */ - - while (*ptr && isspace(*ptr)) - ++ptr; - - *accept_line = ptr; - return token; -} - -static char* tspecials = " \t()<>@,;:\\/[]?={}"; - -/* Next HTTP token from a header line. Warning --- destructive! - * Use only with a copy! - */ - -static char *next_token (char **toks) { - char *cp = *toks; - char *ret; - - while (*cp && (iscntrl (*cp) || strchr (tspecials, *cp))) { - if (*cp == '"') - while (*cp && (*cp != '"')) ++cp; - else - ++cp; - } - - if (!*cp) ret = NULL; - else { - ret = cp; - - while (*cp && !iscntrl(*cp) && !strchr (tspecials, *cp)) - ++cp; - - if (*cp) { - *toks = cp + 1; - *cp = '\0'; - } - else *toks = cp; - } - - return ret; -} - -int find_token (pool *p, const char *line, const char *tok) { - char *ltok; - char *lcopy; - - if (!line) return 0; - - lcopy = pstrdup (p, line); - while ((ltok = next_token (&lcopy))) - if (!strcasecmp (ltok, tok)) - return 1; - - return 0; -} - -int find_last_token (pool *p, const char *line, const char *tok) -{ - int llen, tlen, lidx; - - if (!line) return 0; - - llen = strlen(line); - tlen = strlen(tok); - lidx = llen - tlen; - - if ((lidx < 0) || - ((lidx > 0) && !(isspace(line[lidx-1]) || line[lidx-1] == ','))) - return 0; - - return (strncasecmp(&line[lidx], tok, tlen) == 0); -} - -char *escape_shell_cmd(pool *p, const char *s) { - register int x,y,l; - char *cmd; - - l=strlen(s); - cmd = palloc (p, 2 * l + 1); /* Be safe */ - strcpy (cmd, s); - - for(x=0;cmd[x];x++) { - -#ifdef __EMX__ - /* Don't allow '&' in parameters under OS/2. */ - /* This can be used to send commands to the shell. */ - if (cmd[x] == '&') { - cmd[x] = ' '; - } -#endif - - if(ind("&;`'\"|*?~<>^()[]{}$\\\n",cmd[x]) != -1){ - for(y=l+1;y>x;y--) - cmd[y] = cmd[y-1]; - l++; /* length has been increased */ - cmd[x] = '\\'; - x++; /* skip the character */ - } - } - - return cmd; -} - -void plustospace(char *str) { - register int x; - - for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' '; -} - -void spacetoplus(char *str) { - register int x; - - for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+'; -} - -static char x2c(const char *what) { - register char digit; - - digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0')); - digit *= 16; - digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0')); - return(digit); -} - -/* - * Unescapes a URL. - * Returns 0 on success, non-zero on error - * Failure is due to - * bad % escape returns BAD_REQUEST - * - * decoding %00 -> \0 - * decoding %2f -> / (a special character) - * returns NOT_FOUND - */ -int -unescape_url(char *url) { - register int x,y, badesc, badpath; - - badesc = 0; - badpath = 0; - for(x=0,y=0;url[y];++x,++y) { - if (url[y] != '%') url[x] = url[y]; - else - { - if (!isxdigit(url[y+1]) || !isxdigit(url[y+2])) - { - badesc = 1; - url[x] = '%'; - } else - { - url[x] = x2c(&url[y+1]); - y += 2; - if (url[x] == '/' || url[x] == '\0') badpath = 1; - } - } - } - url[x] = '\0'; - if (badesc) return BAD_REQUEST; - else if (badpath) return NOT_FOUND; - else return OK; -} - -char *construct_server(pool *p, const char *hostname, unsigned port) { - char portnum[22]; - /* Long enough, even if port > 16 bits for some reason */ - - if (port == DEFAULT_PORT) - return (char *)hostname; - else { - ap_snprintf (portnum, sizeof(portnum), "%u", port); - return pstrcat (p, hostname, ":", portnum, NULL); - } -} - -char *construct_url(pool *p, const char *uri, const server_rec *s) { - return pstrcat (p, "http://", - construct_server(p, s->server_hostname, s->port), - uri, NULL); -} - -#define c2x(what,where) sprintf(where,"%%%02x",(unsigned char)what) - -/* -escape_path_segment() escapes a path segment, as defined in RFC 1808. This -routine is (should be) OS independent. - -os_escape_path() converts an OS path to a URL, in an OS dependent way. In all -cases if a ':' occurs before the first '/' in the URL, the URL should be -prefixed with "./" (or the ':' escaped). In the case of Unix, this means -leaving '/' alone, but otherwise doing what escape_path_segment() does. For -efficiency reasons, we don't use escape_path_segment(), which is provided for -reference. Again, RFC 1808 is where this stuff is defined. - -If partial is set, os_escape_path() assumes that the path will be appended to -something with a '/' in it (and thus does not prefix "./"). -*/ - -char *escape_path_segment(pool *p, const char *segment) { - register int x,y; - char *copy = palloc (p, 3 * strlen (segment) + 1); - - for(x=0,y=0; segment[x]; x++,y++) { - char c=segment[x]; - if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9') - && ind("$-_.+!*'(),:@&=~",c) == -1) - { - c2x(c,©[y]); - y+=2; - } - else - copy[y]=c; - } - copy[y] = '\0'; - return copy; -} - -char *os_escape_path(pool *p,const char *path,int partial) { - char *copy=palloc(p,3*strlen(path)+3); - char *s=copy; - - if(!partial) - { - int colon=ind(path,':'); - int slash=ind(path,'/'); - - if(colon >= 0 && (colon < slash || slash < 0)) - { - *s++='.'; - *s++='/'; - } - } - for( ; *path ; ++path) - { - char c=*path; - if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9') - && ind("$-_.+!*'(),:@&=/~",c) == -1) - { - c2x(c,s); - s+=3; - } - else - *s++=c; - } - *s='\0'; - return copy; -} - -/* escape_uri is now a macro for os_escape_path */ - -char *escape_html(pool *p, const char *s) -{ - int i, j; - char *x; - -/* first, count the number of extra characters */ - for (i=0, j=0; s[i] != '\0'; i++) - if (s[i] == '<' || s[i] == '>') j += 3; - else if (s[i] == '&') j += 4; - - if (j == 0) return pstrdup(p, s); - x = palloc(p, i + j + 1); - for (i=0, j=0; s[i] != '\0'; i++, j++) - if (s[i] == '<') - { - memcpy(&x[j], "<", 4); - j += 3; - } else if (s[i] == '>') - { - memcpy(&x[j], ">", 4); - j += 3; - } else if (s[i] == '&') - { - memcpy(&x[j], "&", 5); - j += 4; - } else - x[j] = s[i]; - - x[j] = '\0'; - return x; -} - -int is_directory(const char *path) { - struct stat finfo; - - if(stat(path,&finfo) == -1) - return 0; /* in error condition, just return no */ - - return(S_ISDIR(finfo.st_mode)); -} - -char *make_full_path(pool *a, const char *src1, const char *src2) { - register int x; - - x = strlen(src1); - if (x == 0) return pstrcat (a, "/", src2, NULL); - - if (src1[x - 1] != '/') return pstrcat (a, src1, "/", src2, NULL); - else return pstrcat (a, src1, src2, NULL); -} - -/* - * Check for an absoluteURI syntax (see section 3.2 in RFC2068). - */ -int is_url(const char *u) { - register int x; - - for (x = 0; u[x] != ':'; x++) { - if ((! u[x]) || - ((! isalpha(u[x])) && (! isdigit(u[x])) && - (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) { - return 0; - } - } - - return (x ? 1 : 0); /* If the first character is ':', it's broken, too */ -} - -int can_exec(const struct stat *finfo) { -#ifdef MULTIPLE_GROUPS - int cnt; -#endif -#ifdef __EMX__ - /* OS/2 dosen't have Users and Groups */ - return 1; -#else - if(user_id == finfo->st_uid) - if(finfo->st_mode & S_IXUSR) - return 1; - if(group_id == finfo->st_gid) - if(finfo->st_mode & S_IXGRP) - return 1; -#ifdef MULTIPLE_GROUPS - for(cnt=0; cnt < NGROUPS_MAX; cnt++) { - if(group_id_list[cnt] == finfo->st_gid) - if(finfo->st_mode & S_IXGRP) - return 1; - } -#endif - return (finfo->st_mode & S_IXOTH); -#endif -} - -#ifdef NEED_STRDUP -char *strdup (const char *str) -{ - char *dup; - - if(!(dup = (char *)malloc (strlen (str) + 1))) - return NULL; - dup = strcpy (dup, str); - - return dup; -} -#endif - -/* The following two routines were donated for SVR4 by Andreas Vogel */ -#ifdef NEED_STRCASECMP -int strcasecmp (const char *a, const char *b) -{ - const char *p = a; - const char *q = b; - for (p = a, q = b; *p && *q; p++, q++) - { - int diff = tolower(*p) - tolower(*q); - if (diff) return diff; - } - if (*p) return 1; /* p was longer than q */ - if (*q) return -1; /* p was shorter than q */ - return 0; /* Exact match */ -} - -#endif - -#ifdef NEED_STRNCASECMP -int strncasecmp (const char *a, const char *b, int n) -{ - const char *p = a; - const char *q = b; - - for (p = a, q = b; /*NOTHING*/; p++, q++) - { - int diff; - if (p == a + n) return 0; /* Match up to n characters */ - if (!(*p && *q)) return *p - *q; - diff = tolower(*p) - tolower(*q); - if (diff) return diff; - } - /*NOTREACHED*/ -} -#endif - - - -#ifdef NEED_INITGROUPS -int initgroups(const char *name, gid_t basegid) -{ -#if defined(QNX) || defined(MPE) -/* QNX and MPE do not appear to support supplementary groups. */ - return 0; -#else /* ndef QNX */ - gid_t groups[NGROUPS_MAX]; - struct group *g; - int index = 0; - - setgrent(); - - groups[index++] = basegid; - - while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) - if (g->gr_gid != basegid) - { - char **names; - - for (names = g->gr_mem; *names != NULL; ++names) - if (!strcmp(*names, name)) - groups[index++] = g->gr_gid; - } - - endgrent(); - - return setgroups(index, groups); -#endif /* def QNX */ -} -#endif /* def NEED_INITGROUPS */ - -#ifdef NEED_WAITPID -/* From ikluft@amdahl.com */ -/* this is not ideal but it works for SVR3 variants */ -/* httpd does not use the options so this doesn't implement them */ -int waitpid(pid_t pid, int *statusp, int options) -{ - int tmp_pid; - if ( kill ( pid,0 ) == -1) { - errno=ECHILD; - return -1; - } - while ((( tmp_pid = wait(statusp)) != pid) && ( tmp_pid != -1 )); - return tmp_pid; -} -#endif - -int ind(const char *s, char c) { - register int x; - - for(x=0;s[x];x++) - if(s[x] == c) return x; - - return -1; -} - -int rind(const char *s, char c) { - register int x; - - for(x=strlen(s)-1;x != -1;x--) - if(s[x] == c) return x; - - return -1; -} - -void str_tolower(char *str) { - while(*str) { - *str = tolower(*str); - ++str; - } -} - -uid_t uname2id(const char *name) { - struct passwd *ent; - - if(name[0] == '#') - return(atoi(&name[1])); - - if(!(ent = getpwnam(name))) { - fprintf(stderr,"httpd: bad user name %s\n",name); - exit(1); - } - return(ent->pw_uid); -} - -gid_t gname2id(const char *name) { - struct group *ent; - - if(name[0] == '#') - return(atoi(&name[1])); - - if(!(ent = getgrnam(name))) { - fprintf(stderr,"httpd: bad group name %s\n",name); - exit(1); - } - return(ent->gr_gid); -} - -#if 0 -int get_portnum(int sd) { - struct sockaddr addr; - int len; - - len = sizeof(struct sockaddr); - if(getsockname(sd,&addr,&len) < 0) - return -1; - return ntohs(((struct sockaddr_in *)&addr)->sin_port); -} - -struct in_addr get_local_addr(int sd) { - struct sockaddr addr; - int len; - - len = sizeof(struct sockaddr); - if(getsockname(sd,&addr,&len) < 0) { - perror ("getsockname"); - fprintf (stderr, "Can't get local host address!\n"); - exit(1); - } - - return ((struct sockaddr_in *)&addr)->sin_addr; -} -#endif - -/* - * Parses a host of the form <address>[:port] - * :port is permitted if 'port' is not NULL - */ -unsigned long get_virthost_addr (const char *w, unsigned short *ports) { - struct hostent *hep; - unsigned long my_addr; - char *p; - - p = strchr(w, ':'); - if (ports != NULL) - { - *ports = 0; - if (p != NULL && strcmp(p+1, "*") != 0) *ports = atoi(p+1); - } - - if (p != NULL) *p = '\0'; - if (strcmp(w, "*") == 0) - { - if (p != NULL) *p = ':'; - return htonl(INADDR_ANY); - } - -#ifdef DGUX - my_addr = inet_network(w); -#else - my_addr = inet_addr(w); -#endif - if (my_addr != INADDR_NONE) - { - if (p != NULL) *p = ':'; - return my_addr; - } - - hep = gethostbyname(w); - - if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) { - fprintf (stderr, "Cannot resolve host name %s --- exiting!\n", w); - exit(1); - } - - if (hep->h_addr_list[1]) { - fprintf(stderr, "Host %s has multiple addresses ---\n", w); - fprintf(stderr, "you must choose one explicitly for use as\n"); - fprintf(stderr, "a virtual host. Exiting!!!\n"); - exit(1); - } - - if (p != NULL) *p = ':'; - - return ((struct in_addr *)(hep->h_addr))->s_addr; -} - - -static char *find_fqdn(pool *a, struct hostent *p) { - int x; - - if(ind(p->h_name,'.') == -1) { - for(x=0;p->h_aliases[x];++x) { - if((ind(p->h_aliases[x],'.') != -1) && - (!strncasecmp(p->h_aliases[x],p->h_name,strlen(p->h_name)))) - return pstrdup(a, p->h_aliases[x]); - } - return NULL; - } - return pstrdup(a, (void *)p->h_name); -} - -char *get_local_host(pool *a) -{ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - char str[MAXHOSTNAMELEN+1]; - char *server_hostname; - struct hostent *p; - - if( gethostname( str, sizeof( str ) - 1 ) != 0 ) { - perror( "Unable to gethostname" ); - exit(1); - } - str[MAXHOSTNAMELEN] = '\0'; - if((!(p=gethostbyname(str))) || (!(server_hostname = find_fqdn(a, p)))) { - fprintf(stderr,"httpd: cannot determine local host name.\n"); - fprintf(stderr,"Use ServerName to set it manually.\n"); - exit(1); - } - - return server_hostname; -} - -/* aaaack but it's fast and const should make it shared text page. */ -const int pr2six[256]={ - 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, - 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63, - 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9, - 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27, - 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51, - 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, - 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, - 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, - 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, - 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, - 64,64,64,64,64,64,64,64,64,64,64,64,64 -}; - -char *uudecode(pool *p, const char *bufcoded) { - int nbytesdecoded; - register unsigned char *bufin; - register char *bufplain; - register unsigned char *bufout; - register int nprbytes; - - /* Strip leading whitespace. */ - - while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++; - - /* Figure out how many characters are in the input buffer. - * Allocate this many from the per-transaction pool for the result. - */ - bufin = (unsigned char *)bufcoded; - while(pr2six[*(bufin++)] <= 63); - nprbytes = (char *)bufin - bufcoded - 1; - nbytesdecoded = ((nprbytes+3)/4) * 3; - - bufplain = palloc(p, nbytesdecoded + 1); - bufout = (unsigned char *)bufplain; - - bufin = (unsigned char *)bufcoded; - - while (nprbytes > 0) { - *(bufout++) = - (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); - *(bufout++) = - (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); - *(bufout++) = - (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); - bufin += 4; - nprbytes -= 4; - } - - if(nprbytes & 03) { - if(pr2six[bufin[-2]] > 63) - nbytesdecoded -= 2; - else - nbytesdecoded -= 1; - } - bufplain[nbytesdecoded] = '\0'; - return bufplain; -} - -#ifdef __EMX__ -void os2pathname(char *path) { - char newpath[MAX_STRING_LEN]; - int loop; - int offset; - - offset = 0; - for (loop=0; loop < (strlen(path) + 1) && loop < sizeof(newpath)-1; loop++) { - if (path[loop] == '/') { - newpath[offset] = '\\'; - /* - offset = offset + 1; - newpath[offset] = '\\'; - */ - } else - newpath[offset] = path[loop]; - offset = offset + 1; - }; - /* Debugging code */ - /* fprintf(stderr, "%s \n", newpath); */ - - strcpy(path, newpath); -}; -#endif - - -#ifdef NEED_STRERROR -char * -strerror (int err) { - - char *p; - extern char *const sys_errlist[]; - - p = sys_errlist[err]; - return (p); -} -#endif - - -int ap_slack (int fd, int line) -{ -#if !defined(F_DUPFD) || defined(NO_SLACK) - return fd; -#else - int new_fd; - -#ifdef HIGH_SLACK_LINE - if (line == AP_SLACK_HIGH) { - new_fd = fcntl (fd, F_DUPFD, HIGH_SLACK_LINE); - if (new_fd != -1) { - close (fd); - return new_fd; - } - } -#endif - /* otherwise just assume line == AP_SLACK_LOW */ - new_fd = fcntl (fd, F_DUPFD, LOW_SLACK_LINE); - if (new_fd == -1) { - return fd; - } - close (fd); - return new_fd; -#endif -} diff --git a/usr.sbin/httpd/src/util_date.c b/usr.sbin/httpd/src/util_date.c deleted file mode 100644 index e544a0fe1cc..00000000000 --- a/usr.sbin/httpd/src/util_date.c +++ /dev/null @@ -1,296 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * util_date.c: date parsing utility routines - * These routines are (hopefully) platform-independent. - * - * 27 Oct 1996 Roy Fielding - * Extracted (with many modifications) from mod_proxy.c and - * tested with over 50,000 randomly chosen valid date strings - * and several hundred variations of invalid date strings. - * - */ - -#include "util_date.h" -#include <ctype.h> -#include <string.h> - -/* - * Compare a string to a mask - * Mask characters (arbitrary maximum is 256 characters, just in case): - * @ - uppercase letter - * $ - lowercase letter - * & - hex digit - * # - digit - * ~ - digit or space - * * - swallow remaining characters - * <x> - exact match for any other character - */ -int checkmask(const char *data, const char *mask) -{ - int i; - char d; - - for (i = 0; i < 256; i++) { - d = data[i]; - switch (mask[i]) { - case '\0': return (d == '\0'); - - case '*': return 1; - - case '@': if (!isupper(d)) return 0; - break; - case '$': if (!islower(d)) return 0; - break; - case '#': if (!isdigit(d)) return 0; - break; - case '&': if (!isxdigit(d)) return 0; - break; - case '~': if ((d != ' ') && !isdigit(d)) return 0; - break; - default: if (mask[i] != d) return 0; - break; - } - } - return 0; /* We only get here if mask is corrupted (exceeds 256) */ -} - -/* - * tm2sec converts a GMT tm structure into the number of seconds since - * 1st January 1970 UT. Note that we ignore tm_wday, tm_yday, and tm_dst. - * - * The return value is always a valid time_t value -- (time_t)0 is returned - * if the input date is outside that capable of being represented by time(), - * i.e., before Thu, 01 Jan 1970 00:00:00 for all systems and - * beyond 2038 for 32bit systems. - * - * This routine is intended to be very fast, much faster than mktime(). - */ -time_t tm2sec(const struct tm *t) -{ - int year; - time_t days; - const int dayoffset[12] = - {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; - - year = t->tm_year; - - if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138))) - return BAD_DATE; - - /* shift new year to 1st March in order to make leap year calc easy */ - - if (t->tm_mon < 2) year--; - - /* Find number of days since 1st March 1900 (in the Gregorian calendar). */ - - days = year * 365 + year/4 - year/100 + (year/100 + 3)/4; - days += dayoffset[t->tm_mon] + t->tm_mday - 1; - days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */ - - days = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec; - - if (days < 0) - return BAD_DATE; /* must have overflowed */ - else - return days; /* must be a valid time */ -} - -/* - * Parses an HTTP date in one of three standard forms: - * - * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 - * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 - * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format - * - * and returns the time_t number of seconds since 1 Jan 1970 GMT, or - * 0 if this would be out of range or if the date is invalid. - * - * The restricted HTTP syntax is - * - * HTTP-date = rfc1123-date | rfc850-date | asctime-date - * - * rfc1123-date = wkday "," SP date1 SP time SP "GMT" - * rfc850-date = weekday "," SP date2 SP time SP "GMT" - * asctime-date = wkday SP date3 SP time SP 4DIGIT - * - * date1 = 2DIGIT SP month SP 4DIGIT - * ; day month year (e.g., 02 Jun 1982) - * date2 = 2DIGIT "-" month "-" 2DIGIT - * ; day-month-year (e.g., 02-Jun-82) - * date3 = month SP ( 2DIGIT | ( SP 1DIGIT )) - * ; month day (e.g., Jun 2) - * - * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT - * ; 00:00:00 - 23:59:59 - * - * wkday = "Mon" | "Tue" | "Wed" - * | "Thu" | "Fri" | "Sat" | "Sun" - * - * weekday = "Monday" | "Tuesday" | "Wednesday" - * | "Thursday" | "Friday" | "Saturday" | "Sunday" - * - * month = "Jan" | "Feb" | "Mar" | "Apr" - * | "May" | "Jun" | "Jul" | "Aug" - * | "Sep" | "Oct" | "Nov" | "Dec" - * - * However, for the sake of robustness (and Netscapeness), we ignore the - * weekday and anything after the time field (including the timezone). - * - * This routine is intended to be very fast; 10x faster than using sscanf. - * - * Originally from Andrew Daviel <andrew@vancouver-webpages.com>, 29 Jul 96 - * but many changes since then. - * - */ -time_t parseHTTPdate(const char *date) -{ - struct tm ds; - int mint, mon; - const char *monstr, *timstr; - const int months[12] = { - ('J' << 16) | ( 'a' << 8) | 'n', ('F' << 16) | ( 'e' << 8) | 'b', - ('M' << 16) | ( 'a' << 8) | 'r', ('A' << 16) | ( 'p' << 8) | 'r', - ('M' << 16) | ( 'a' << 8) | 'y', ('J' << 16) | ( 'u' << 8) | 'n', - ('J' << 16) | ( 'u' << 8) | 'l', ('A' << 16) | ( 'u' << 8) | 'g', - ('S' << 16) | ( 'e' << 8) | 'p', ('O' << 16) | ( 'c' << 8) | 't', - ('N' << 16) | ( 'o' << 8) | 'v', ('D' << 16) | ( 'e' << 8) | 'c'}; - - if (!date) - return BAD_DATE; - - while (*date && isspace(*date)) /* Find first non-whitespace char */ - ++date; - - if (*date == '\0') - return BAD_DATE; - - if ((date = strchr(date,' ')) == NULL) /* Find space after weekday */ - return BAD_DATE; - - ++date; /* Now pointing to first char after space, which should be */ - /* start of the actual date information for all 3 formats. */ - - if (checkmask(date, "## @$$ #### ##:##:## *")) { /* RFC 1123 format */ - ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100; - if (ds.tm_year < 0) - return BAD_DATE; - - ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0'); - - ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); - - monstr = date + 3; - timstr = date + 12; - } - else if (checkmask(date, "##-@$$-## ##:##:## *")) { /* RFC 850 format */ - ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0'); - if (ds.tm_year < 70) - ds.tm_year += 100; - - ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); - - monstr = date + 3; - timstr = date + 10; - } - else if (checkmask(date, "@$$ ~# ##:##:## ####*")) { /* asctime format */ - ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100; - if (ds.tm_year < 0) - return BAD_DATE; - - ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0'); - - if (date[4] == ' ') - ds.tm_mday = 0; - else - ds.tm_mday = (date[4] - '0') * 10; - - ds.tm_mday += (date[5] - '0'); - - monstr = date; - timstr = date + 7; - } - else return BAD_DATE; - - if (ds.tm_mday <= 0 || ds.tm_mday > 31) - return BAD_DATE; - - ds.tm_hour = ((timstr[0] - '0') * 10) + (timstr[1] - '0'); - ds.tm_min = ((timstr[3] - '0') * 10) + (timstr[4] - '0'); - ds.tm_sec = ((timstr[6] - '0') * 10) + (timstr[7] - '0'); - - if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61)) - return BAD_DATE; - - mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2]; - for (mon=0; mon < 12; mon++) - if (mint == months[mon]) - break; - if (mon == 12) - return BAD_DATE; - - if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10)) - return BAD_DATE; - - /* February gets special check for leapyear */ - - if ((mon == 1) && ((ds.tm_mday > 29) || - ((ds.tm_mday == 29) && ((ds.tm_year & 3) || - (((ds.tm_year % 100) == 0) && (((ds.tm_year % 400) != 100))))))) - return BAD_DATE; - - ds.tm_mon = mon; - - return tm2sec(&ds); -} - diff --git a/usr.sbin/httpd/src/util_date.h b/usr.sbin/httpd/src/util_date.h deleted file mode 100644 index edfd34ad431..00000000000 --- a/usr.sbin/httpd/src/util_date.h +++ /dev/null @@ -1,63 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1996,1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/* - * util_date.h: prototypes for date parsing utility routines - */ - -#include <time.h> - -#define BAD_DATE (time_t)0 - -int checkmask (const char *data, const char *mask); -time_t tm2sec (const struct tm *t); -time_t parseHTTPdate (const char *date); diff --git a/usr.sbin/httpd/src/util_md5.c b/usr.sbin/httpd/src/util_md5.c deleted file mode 100644 index bf5565e21f0..00000000000 --- a/usr.sbin/httpd/src/util_md5.c +++ /dev/null @@ -1,192 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -/************************************************************************ - * 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: 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 "httpd.h" -#include "util_md5.h" - -char *md5 (pool *p, unsigned char *string) -{ - MD5_CTX my_md5; - unsigned char hash[16]; - char *r, result[33]; - int i; - - /* - * Take the MD5 hash of the string argument. - */ - - MD5Init(&my_md5); - MD5Update(&my_md5, string, strlen((const char *)string)); - MD5Final(hash, &my_md5); - - for (i=0, r=result; i<16; i++, r+=2) - sprintf(r, "%02x", hash[i]); - *r = '\0'; - - return pstrdup(p, result); -} - -/* 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(pool *a, MD5_CTX *context) -{ - unsigned char digest[18]; - char *encodedDigest; - int i; - char *p; - - encodedDigest = (char *)pcalloc(a, 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) | ((int)(digest[i+1] & 0xF0)>>4)]; - *p++ = basis_64[((digest[i+1] & 0xF)<<2) | ((int)(digest[i+2] & 0xC0)>>6)]; - *p++ = basis_64[digest[i+2] & 0x3F]; - } - *p-- = '\0'; - *p-- = '='; - *p-- = '='; - return encodedDigest; -} - -char *md5digest(pool *p, FILE *infile) -{ - MD5_CTX context; - unsigned 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(p, &context); -} - diff --git a/usr.sbin/httpd/src/util_md5.h b/usr.sbin/httpd/src/util_md5.h deleted file mode 100644 index 63e2c37cd2b..00000000000 --- a/usr.sbin/httpd/src/util_md5.h +++ /dev/null @@ -1,58 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#include "md5.h" - -char *md5(pool *a, unsigned char *string); -char *md5contextTo64(pool *p, MD5_CTX *context); -char *md5digest(pool *p, FILE *infile); - diff --git a/usr.sbin/httpd/src/util_script.c b/usr.sbin/httpd/src/util_script.c deleted file mode 100644 index 3fcd3a66cd2..00000000000 --- a/usr.sbin/httpd/src/util_script.c +++ /dev/null @@ -1,641 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_config.h" -#include "http_conf_globals.h" -#include "http_main.h" -#include "http_log.h" -#include "http_protocol.h" -#include "http_core.h" /* For document_root. Sigh... */ -#include "http_request.h" /* for sub_req_lookup_uri() */ -#include "util_script.h" -#include <assert.h> - -/* - * Various utility functions which are common to a whole lot of - * script-type extensions mechanisms, and might as well be gathered - * in one place (if only to avoid creating inter-module dependancies - * where there don't have to be). - */ - -#define MALFORMED_MESSAGE "malformed header from script. Bad header=" -#define MALFORMED_HEADER_LENGTH_TO_SHOW 30 - -/* If a request includes query info in the URL (stuff after "?"), and - * the query info does not contain "=" (indicative of a FORM submission), - * then this routine is called to create the argument list to be passed - * to the CGI script. When suexec is enabled, the suexec path, user, and - * group are the first three arguments to be passed; if not, all three - * must be NULL. The query info is split into separate arguments, where - * "+" is the separator between keyword arguments. - */ -static char **create_argv(pool *p, char *path, char *user, char *group, - char *av0, const char *args) -{ - int x, numwords; - char **av; - char *w; - int idx = 0; - - /* count the number of keywords */ - - for (x = 0, numwords = 1; args[x]; x++) - if (args[x] == '+') ++numwords; - - if (numwords > APACHE_ARG_MAX - 5) { - numwords = APACHE_ARG_MAX - 5; /* Truncate args to prevent overrun */ - } - av = (char **)palloc(p, (numwords + 5) * sizeof(char *)); - - if (path) - av[idx++] = path; - if (user) - av[idx++] = user; - if (group) - av[idx++] = group; - - av[idx++] = av0; - - for (x = 1; x <= numwords; x++) { - w = getword_nulls(p, &args, '+'); - unescape_url(w); - av[idx++] = escape_shell_cmd(p, w); - } - av[idx] = NULL; - return av; -} - - -static char *http2env(pool *a, char *w) -{ - char *res = pstrcat (a, "HTTP_", w, NULL); - char *cp = res; - - while (*++cp) - if (*cp == '-') *cp = '_'; - else *cp = toupper(*cp); - - return res; -} - -char **create_environment(pool *p, table *t) -{ - array_header *env_arr = table_elts (t); - table_entry *elts = (table_entry *)env_arr->elts; - char **env = (char **)palloc (p, (env_arr->nelts + 2) *sizeof (char *)); - int i, j; - char *tz; - - j = 0; - tz = getenv("TZ"); - if (tz!= NULL) env[j++] = pstrcat(p, "TZ=", tz, NULL); - for (i = 0; i < env_arr->nelts; ++i) { - if (!elts[i].key) continue; - env[j++] = pstrcat (p, elts[i].key, "=", elts[i].val, NULL); - } - - env[j] = NULL; - return env; -} - -void add_common_vars(request_rec *r) -{ - table *e = r->subprocess_env; - server_rec *s = r->server; - conn_rec *c = r->connection; - const char *rem_logname; - - char port[40],*env_path; - - array_header *hdrs_arr = table_elts (r->headers_in); - table_entry *hdrs = (table_entry *)hdrs_arr->elts; - int i; - - /* First, add environment vars from headers... this is as per - * CGI specs, though other sorts of scripting interfaces see - * the same vars... - */ - - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (!hdrs[i].key) continue; - - /* A few headers are special cased --- Authorization to prevent - * rogue scripts from capturing passwords; content-type and -length - * for no particular reason. - */ - - if (!strcasecmp (hdrs[i].key, "Content-type")) - table_set (e, "CONTENT_TYPE", hdrs[i].val); - else if (!strcasecmp (hdrs[i].key, "Content-length")) - table_set (e, "CONTENT_LENGTH", hdrs[i].val); - else if (!strcasecmp (hdrs[i].key, "Authorization")) - continue; - else - table_set (e, http2env (r->pool, hdrs[i].key), hdrs[i].val); - } - - ap_snprintf(port, sizeof(port), "%u", s->port); - - if(!(env_path = getenv("PATH"))) - env_path=DEFAULT_PATH; - - table_set (e, "PATH", env_path); - table_set (e, "SERVER_SOFTWARE", SERVER_VERSION); - table_set (e, "SERVER_NAME", s->server_hostname); - table_set (e, "SERVER_PORT", port); - table_set (e, "REMOTE_HOST", - get_remote_host(c, r->per_dir_config, REMOTE_NAME)); - table_set (e, "REMOTE_ADDR", c->remote_ip); - table_set (e, "DOCUMENT_ROOT", document_root(r)); /* Apache */ - table_set (e, "SERVER_ADMIN", s->server_admin); /* Apache */ - table_set (e, "SCRIPT_FILENAME", r->filename); /* Apache */ - - ap_snprintf(port, sizeof(port), "%d", ntohs(c->remote_addr.sin_port)); - table_set (e, "REMOTE_PORT", port); /* Apache */ - - if (c->user) table_set(e, "REMOTE_USER", c->user); - if (c->auth_type) table_set(e, "AUTH_TYPE", c->auth_type); - rem_logname = get_remote_logname(r); - if (rem_logname) table_set(e, "REMOTE_IDENT", rem_logname); - - /* Apache custom error responses. If we have redirected set two new vars */ - - if (r->prev) { - if (r->prev->args) table_set(e,"REDIRECT_QUERY_STRING", r->prev->args); - if (r->prev->uri) table_set (e, "REDIRECT_URL", r->prev->uri); - } -} - -/* This "cute" little function comes about because the path info on - * filenames and URLs aren't always the same. So we take the two, - * and find as much of the two that match as possible. - */ - -int find_path_info (char *uri, char *path_info) -{ - int lu = strlen(uri); - int lp = strlen(path_info); - - while (lu-- && lp-- && uri[lu] == path_info[lp]); - - if (lu == -1) - lu=0; - - while (uri[lu] != '\0' && uri[lu] != '/') - lu++; - - return lu; -} - -/* Obtain the Request-URI from the original request-line, returning - * a new string from the request pool containing the URI or "". - */ -static char *original_uri(request_rec *r) -{ - char *first, *last; - - if (r->the_request == NULL) - return (char *)pcalloc(r->pool, 1); - - first = r->the_request; /* use the request-line */ - - while (*first && !isspace(*first)) ++first; /* skip over the method */ - while (isspace(*first)) ++first; /* and the space(s) */ - - last = first; - while (*last && !isspace(*last)) ++last; /* end at next whitespace */ - - return pstrndup(r->pool, first, last - first); -} - -void add_cgi_vars(request_rec *r) -{ - table *e = r->subprocess_env; - - table_set (e, "GATEWAY_INTERFACE","CGI/1.1"); - table_set (e, "SERVER_PROTOCOL", r->protocol); - table_set (e, "REQUEST_METHOD", r->method); - table_set (e, "QUERY_STRING", r->args ? r->args : ""); - table_set (e, "REQUEST_URI", original_uri(r)); - - /* Note that the code below special-cases scripts run from includes, - * because it "knows" that the sub_request has been hacked to have the - * args and path_info of the original request, and not any that may have - * come with the script URI in the include command. Ugh. - */ - - if (!strcmp (r->protocol, "INCLUDED")) { - table_set (e, "SCRIPT_NAME", r->uri); - if (r->path_info && *r->path_info) - table_set (e, "PATH_INFO", r->path_info); - } else if (!r->path_info || !*r->path_info) { - table_set (e, "SCRIPT_NAME", r->uri); - } else { - int path_info_start = find_path_info (r->uri, r->path_info); - - table_set (e, "SCRIPT_NAME", pstrndup(r->pool, r->uri, - path_info_start)); - - table_set (e, "PATH_INFO", r->path_info); - } - - if (r->path_info && r->path_info[0]) { - /* - * To get PATH_TRANSLATED, treat PATH_INFO as a URI path. - * Need to re-escape it for this, since the entire URI was - * un-escaped before we determined where the PATH_INFO began. - */ - request_rec *pa_req = sub_req_lookup_uri( - escape_uri(r->pool, r->path_info), r); - - /* Don't bother destroying pa_req --- it's only created in - * child processes which are about to jettison their address - * space anyway. BTW, we concatenate filename and path_info - * from the sub_request to be compatible in case the PATH_INFO - * is pointing to an object which doesn't exist. - */ - - if (pa_req->filename) - table_set (e, "PATH_TRANSLATED", - pstrcat (r->pool, pa_req->filename, pa_req->path_info, - NULL)); - } -} - -int scan_script_header_err(request_rec *r, FILE *f, char *buffer) -{ - char x[MAX_STRING_LEN]; - char *w, *l; - int p; - - if (buffer) *buffer = '\0'; - w = buffer ? buffer : x; - - hard_timeout ("read script header", r); - - while(1) { - - if (fgets(w, MAX_STRING_LEN-1, f) == NULL) { - kill_timeout (r); - log_reason ("Premature end of script headers", r->filename, r); - return SERVER_ERROR; - } - - /* Delete terminal (CR?)LF */ - - p = strlen(w); - if (p > 0 && w[p-1] == '\n') - { - if (p > 1 && w[p-2] == '\015') w[p-2] = '\0'; - else w[p-1] = '\0'; - } - - if(w[0] == '\0') { - kill_timeout (r); - return OK; - } - - /* if we see a bogus header don't ignore it. Shout and scream */ - - if(!(l = strchr(w,':'))) { - char malformed[(sizeof MALFORMED_MESSAGE)+1+MALFORMED_HEADER_LENGTH_TO_SHOW]; - strcpy(malformed, MALFORMED_MESSAGE); - strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW); - - if (!buffer) - /* Soak up all the script output --- may save an outright kill */ - while (fgets(w, MAX_STRING_LEN-1, f) != NULL) - continue; - - kill_timeout (r); - log_reason (malformed, r->filename, r); - return SERVER_ERROR; - } - - *l++ = '\0'; - while (*l && isspace (*l)) ++l; - - if(!strcasecmp(w,"Content-type")) { - - /* Nuke trailing whitespace */ - - char *endp = l + strlen(l) - 1; - while (endp > l && isspace(*endp)) *endp-- = '\0'; - - r->content_type = pstrdup (r->pool, l); - } - else if(!strcasecmp(w,"Status")) { - sscanf(l, "%d", &r->status); - r->status_line = pstrdup(r->pool, l); - } - else if(!strcasecmp(w,"Location")) { - table_set (r->headers_out, w, l); - } - else if(!strcasecmp(w,"Content-Length")) { - table_set (r->headers_out, w, l); - } - else if(!strcasecmp(w,"Transfer-Encoding")) { - table_set (r->headers_out, w, l); - } - -/* The HTTP specification says that it is legal to merge duplicate - * headers into one. Some browsers that support Cookies don't like - * merged headers and prefer that each Set-Cookie header is sent - * separately. Lets humour those browsers. - */ - else if(!strcasecmp(w, "Set-Cookie")) { - table_add(r->err_headers_out, w, l); - } - else { - table_merge (r->err_headers_out, w, l); - } - } -} - -void send_size(size_t size, request_rec *r) { - char ss[20]; - - if(size == -1) - strcpy(ss, " -"); - else if(!size) - strcpy(ss, " 0k"); - else if(size < 1024) - strcpy(ss, " 1k"); - else if(size < 1048576) - ap_snprintf(ss, sizeof(ss), "%4dk", (size + 512) / 1024); - else if(size < 103809024) - ap_snprintf(ss, sizeof(ss), "%4.1fM", size / 1048576.0); - else - ap_snprintf(ss, sizeof(ss), "%4dM", (size + 524288) / 1048576); - rputs(ss, r); -} - -#ifdef __EMX__ -static char **create_argv_cmd(pool *p, char *av0, const char *args, char *path) -{ - register int x,n; - char **av; - char *w; - - for(x=0,n=2;args[x];x++) - if(args[x] == '+') ++n; - - /* Add extra strings to array. */ - n = n + 2; - - av = (char **)palloc(p, (n+1)*sizeof(char *)); - av[0] = av0; - - /* Now insert the extra strings we made room for above. */ - av[1] = strdup("/C"); - av[2] = strdup(path); - - for(x=(1+2);x<n;x++) { - w = getword(p, &args, '+'); - unescape_url(w); - av[x] = escape_shell_cmd(p, w); - } - av[n] = NULL; - return av; -} -#endif - - -void call_exec (request_rec *r, char *argv0, char **env, int shellcmd) -{ -#if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \ - defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) - - core_dir_config *conf = - (core_dir_config *)get_module_config(r->per_dir_config, &core_module); - -#endif - - /* the fd on r->server->error_log is closed, but we need somewhere to - * put the error messages from the log_* functions. So, we use stderr, - * since that is better than allowing errors to go unnoticed. - */ - r->server->error_log = stderr; - -#ifdef RLIMIT_CPU - if (conf->limit_cpu != NULL) - if ((setrlimit (RLIMIT_CPU, conf->limit_cpu)) != 0) - log_unixerr("setrlimit", NULL, "failed to set CPU usage limit", - r->server); -#endif -#ifdef RLIMIT_NPROC - if (conf->limit_nproc != NULL) - if ((setrlimit (RLIMIT_NPROC, conf->limit_nproc)) != 0) - log_unixerr("setrlimit", NULL, "failed to set process limit", - r->server); -#endif -#ifdef RLIMIT_DATA - if (conf->limit_mem != NULL) - if ((setrlimit (RLIMIT_DATA, conf->limit_mem)) != 0) - log_unixerr("setrlimit", NULL, "failed to set memory usage limit", - r->server); -#endif -#ifdef RLIMIT_VMEM - if (conf->limit_mem != NULL) - if ((setrlimit (RLIMIT_VMEM, conf->limit_mem)) != 0) - log_unixerr("setrlimit", NULL, "failed to set memory usage limit", - r->server); -#endif - -#ifdef __EMX__ - { - /* Additions by Alec Kloss, to allow exec'ing of scripts under OS/2 */ - int is_script; - char interpreter[2048]; /* hope this is large enough for the interpreter path */ - FILE * program; - program = fopen (r->filename, "r"); - if (!program) { - char err_string[HUGE_STRING_LEN]; - ap_snprintf(err_string, sizeof(err_string), - "open of %s failed, reason: fopen: %s (errno = %d)\n", - r->filename, strerror(errno), errno); - - /* write(2, err_string, strlen(err_string)); */ - /* exit(0); */ - log_unixerr("fopen", NULL, err_string, r->server); - return; - } - fgets (interpreter, 2048, program); - fclose (program); - if (!strncmp (interpreter, "#!", 2)) { - is_script = 1; - interpreter[strlen(interpreter)-1] = '\0'; - } else { - is_script = 0; - } - - if ((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) { - int emxloop; - char *emxtemp; - - /* For OS/2 place the variables in the current - enviornment then it will be inherited. This way - the program will also get all of OS/2's other SETs. */ - for (emxloop=0; ((emxtemp = env[emxloop]) != NULL); emxloop++) - putenv(emxtemp); - - /* Additions by Alec Kloss, to allow exec'ing of scripts under OS/2 */ - if (is_script) { - /* here's the stuff to run the interpreter */ - execl (interpreter+2, interpreter+2, r->filename, NULL); - } else - - if (strstr(strupr(r->filename), ".CMD") > 0) { - /* Special case to allow use of REXX commands as scripts. */ - os2pathname(r->filename); - execl("CMD.EXE", "CMD.EXE", "/C", r->filename, NULL); - } - else { - execl(r->filename, argv0, NULL); - } - } - else { - int emxloop; - char *emxtemp; - - /* For OS/2 place the variables in the current - environment so that they will be inherited. This way - the program will also get all of OS/2's other SETs. */ - for (emxloop=0; ((emxtemp = env[emxloop]) != NULL); emxloop++) - putenv(emxtemp); - - if (strstr(strupr(r->filename), ".CMD") > 0) { - /* Special case to allow use of REXX commands as scripts. */ - os2pathname(r->filename); - execv("CMD.EXE", create_argv_cmd(r->pool, argv0, r->args, r->filename)); - } - else - execv(r->filename, - create_argv(r->pool, NULL, NULL, NULL, argv0, r->args)); - } - } -#else - if ( suexec_enabled && - ((r->server->server_uid != user_id) || - (r->server->server_gid != group_id) || - (!strncmp("/~",r->uri,2))) ) { - - char *execuser, *grpname; - struct passwd *pw; - struct group *gr; - - if (!strncmp("/~",r->uri,2)) { - gid_t user_gid; - char *username = pstrdup(r->pool, r->uri + 2); - int pos = ind(username, '/'); - - if (pos >= 0) username[pos] = '\0'; - - if ((pw = getpwnam(username)) == NULL) { - log_unixerr("getpwnam",username,"invalid username",r->server); - return; - } - execuser = pstrcat(r->pool, "~", pw->pw_name, NULL); - user_gid = pw->pw_gid; - - if ((gr = getgrgid(user_gid)) == NULL) { - if ((grpname = palloc (r->pool, 16)) == NULL) - return; - else - ap_snprintf(grpname, 16, "%d", user_gid); - } - else - grpname = gr->gr_name; - } - else { - if ((pw = getpwuid (r->server->server_uid)) == NULL) { - log_unixerr("getpwuid", NULL, "invalid userid", r->server); - return; - } - execuser = pstrdup(r->pool, pw->pw_name); - - if ((gr = getgrgid (r->server->server_gid)) == NULL) { - log_unixerr("getgrgid", NULL, "invalid groupid", r->server); - return; - } - grpname = gr->gr_name; - } - - if (shellcmd) - execle(SUEXEC_BIN, SUEXEC_BIN, execuser, grpname, argv0, NULL, env); - - else if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) - execle(SUEXEC_BIN, SUEXEC_BIN, execuser, grpname, argv0, NULL, env); - - else { - execve(SUEXEC_BIN, - create_argv(r->pool, SUEXEC_BIN, execuser, grpname, - argv0, r->args), - env); - } - } - else { - if (shellcmd) - execle(SHELL_PATH, SHELL_PATH, "-c", argv0, NULL, env); - - else if((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) - execle(r->filename, argv0, NULL, env); - - else - execve(r->filename, - create_argv(r->pool, NULL, NULL, NULL, argv0, r->args), - env); - } -#endif -} diff --git a/usr.sbin/httpd/src/util_script.h b/usr.sbin/httpd/src/util_script.h deleted file mode 100644 index 28258767781..00000000000 --- a/usr.sbin/httpd/src/util_script.h +++ /dev/null @@ -1,69 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - */ - -#ifndef APACHE_ARG_MAX -#ifdef _POSIX_ARG_MAX -#define APACHE_ARG_MAX _POSIX_ARG_MAX -#else -#define APACHE_ARG_MAX 512 -#endif -#endif - -char **create_environment(pool *p, table *t); -int find_path_info(char *uri, char *path_info); -void add_cgi_vars(request_rec *r); -void add_common_vars(request_rec *r); -#define scan_script_header(a1,a2) scan_script_header_err(a1,a2,NULL) -int scan_script_header_err(request_rec *r, FILE *f, char *buffer); -void send_size(size_t size, request_rec *r); -void call_exec (request_rec *r, char *argv0, char **env, int shellcmd); - diff --git a/usr.sbin/httpd/src/util_snprintf.c b/usr.sbin/httpd/src/util_snprintf.c deleted file mode 100644 index d37c634f753..00000000000 --- a/usr.sbin/httpd/src/util_snprintf.c +++ /dev/null @@ -1,949 +0,0 @@ -/* ==================================================================== - * Copyright (c) 1995-1997 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. - * - * 5. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see <http://www.apache.org/>. - * - * This code is based on, and used with the permission of, the - * SIO stdio-replacement strx_* functions by Panos Tsirigotis - * <panos@alumni.cs.colorado.edu> for xinetd. - */ - -#include "conf.h" - -#ifndef HAVE_SNPRINTF - -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> -#include <stdarg.h> -#include <string.h> -#include <stdlib.h> -#include <math.h> - -#ifdef HAVE_CVT - -# define ap_ecvt ecvt -# define ap_fcvt fcvt -# define ap_gcvt gcvt - -#else - -/* - * cvt.c - IEEE floating point formatting routines for FreeBSD - * from GNU libc-4.6.27 - */ - -/* - * ap_ecvt converts to decimal - * the number of digits is specified by ndigit - * decpt is set to the position of the decimal point - * sign is set to 0 for positive, 1 for negative - */ - -#define NDIG 80 - -static char * - ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag) -{ - register int r2; - double fi, fj; - register char *p, *p1; - static char buf[NDIG]; - - if (ndigits >= NDIG - 1) - ndigits = NDIG - 2; - r2 = 0; - *sign = 0; - p = &buf[0]; - if (arg < 0) { - *sign = 1; - arg = -arg; - } - arg = modf(arg, &fi); - p1 = &buf[NDIG]; - /* - * Do integer part - */ - if (fi != 0) { - p1 = &buf[NDIG]; - while (fi != 0) { - fj = modf(fi / 10, &fi); - *--p1 = (int) ((fj + .03) * 10) + '0'; - r2++; - } - while (p1 < &buf[NDIG]) - *p++ = *p1++; - } - else if (arg > 0) { - while ((fj = arg * 10) < 1) { - arg = fj; - r2--; - } - } - p1 = &buf[ndigits]; - if (eflag == 0) - p1 += r2; - *decpt = r2; - if (p1 < &buf[0]) { - buf[0] = '\0'; - return (buf); - } - while (p <= p1 && p < &buf[NDIG]) { - arg *= 10; - arg = modf(arg, &fj); - *p++ = (int) fj + '0'; - } - if (p1 >= &buf[NDIG]) { - buf[NDIG - 1] = '\0'; - return (buf); - } - p = p1; - *p1 += 5; - while (*p1 > '9') { - *p1 = '0'; - if (p1 > buf) - ++ * --p1; - else { - *p1 = '1'; - (*decpt)++; - if (eflag == 0) { - if (p > buf) - *p = '0'; - p++; - } - } - } - *p = '\0'; - return (buf); -} - -static char * - ap_ecvt(double arg, int ndigits, int *decpt, int *sign) -{ - return (ap_cvt(arg, ndigits, decpt, sign, 1)); -} - -static char * - ap_fcvt(double arg, int ndigits, int *decpt, int *sign) -{ - return (ap_cvt(arg, ndigits, decpt, sign, 0)); -} - -/* - * ap_gcvt - Floating output conversion to - * minimal length string - */ - -static char * - ap_gcvt(double number, int ndigit, char *buf) -{ - int sign, decpt; - register char *p1, *p2; - register i; - - p1 = ap_ecvt(number, ndigit, &decpt, &sign); - p2 = buf; - if (sign) - *p2++ = '-'; - for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) - ndigit--; - if ((decpt >= 0 && decpt - ndigit > 4) - || (decpt < 0 && decpt < -3)) { /* use E-style */ - decpt--; - *p2++ = *p1++; - *p2++ = '.'; - for (i = 1; i < ndigit; i++) - *p2++ = *p1++; - *p2++ = 'e'; - if (decpt < 0) { - decpt = -decpt; - *p2++ = '-'; - } - else - *p2++ = '+'; - if (decpt / 100 > 0) - *p2++ = decpt / 100 + '0'; - if (decpt / 10 > 0) - *p2++ = (decpt % 100) / 10 + '0'; - *p2++ = decpt % 10 + '0'; - } - else { - if (decpt <= 0) { - if (*p1 != '0') - *p2++ = '.'; - while (decpt < 0) { - decpt++; - *p2++ = '0'; - } - } - for (i = 1; i <= ndigit; i++) { - *p2++ = *p1++; - if (i == decpt) - *p2++ = '.'; - } - if (ndigit < decpt) { - while (ndigit++ < decpt) - *p2++ = '0'; - *p2++ = '.'; - } - } - if (p2[-1] == '.') - p2--; - *p2 = '\0'; - return (buf); -} - -#endif /* HAVE_CVT */ - -typedef enum { - NO = 0, YES = 1 -} boolean_e; - -#define FALSE 0 -#define TRUE 1 -#define NUL '\0' -#define INT_NULL ((int *)0) -#define WIDE_INT long - -typedef WIDE_INT wide_int; -typedef unsigned WIDE_INT u_wide_int; -typedef int bool_int; - -#define S_NULL "(null)" -#define S_NULL_LEN 6 - -#define FLOAT_DIGITS 6 -#define EXPONENT_LENGTH 10 - -/* - * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions - * - * XXX: this is a magic number; do not decrease it - */ -#define NUM_BUF_SIZE 512 - - -/* - * Descriptor for buffer area - */ -struct buf_area { - char *buf_end; - char *nextb; /* pointer to next byte to read/write */ -}; - -typedef struct buf_area buffy; - -/* - * The INS_CHAR macro inserts a character in the buffer and writes - * the buffer back to disk if necessary - * It uses the char pointers sp and bep: - * sp points to the next available character in the buffer - * bep points to the end-of-buffer+1 - * While using this macro, note that the nextb pointer is NOT updated. - * - * NOTE: Evaluation of the c argument should not have any side-effects - */ -#define INS_CHAR( c, sp, bep, cc ) \ - { \ - if ( sp < bep ) \ - { \ - *sp++ = c ; \ - cc++ ; \ - } \ - } - -#define NUM( c ) ( c - '0' ) - -#define STR_TO_DEC( str, num ) \ - num = NUM( *str++ ) ; \ - while ( isdigit( *str ) ) \ - { \ - num *= 10 ; \ - num += NUM( *str++ ) ; \ - } - -/* - * This macro does zero padding so that the precision - * requirement is satisfied. The padding is done by - * adding '0's to the left of the string that is going - * to be printed. - */ -#define FIX_PRECISION( adjust, precision, s, s_len ) \ - if ( adjust ) \ - while ( s_len < precision ) \ - { \ - *--s = '0' ; \ - s_len++ ; \ - } - -/* - * Macro that does padding. The padding is done by printing - * the character ch. - */ -#define PAD( width, len, ch ) do \ - { \ - INS_CHAR( ch, sp, bep, cc ) ; \ - width-- ; \ - } \ - while ( width > len ) - -/* - * Prefix the character ch to the string str - * Increase length - * Set the has_prefix flag - */ -#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES - - -/* - * Convert num to its decimal format. - * Return value: - * - a pointer to a string containing the number (no sign) - * - len contains the length of the string - * - is_negative is set to TRUE or FALSE depending on the sign - * of the number (always set to FALSE if is_unsigned is TRUE) - * - * The caller provides a buffer for the string: that is the buf_end argument - * which is a pointer to the END of the buffer + 1 (i.e. if the buffer - * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) - */ -static char * - conv_10(register wide_int num, register bool_int is_unsigned, - register bool_int * is_negative, char *buf_end, register int *len) -{ - register char *p = buf_end; - register u_wide_int magnitude; - - if (is_unsigned) { - magnitude = (u_wide_int) num; - *is_negative = FALSE; - } - else { - *is_negative = (num < 0); - - /* - * On a 2's complement machine, negating the most negative integer - * results in a number that cannot be represented as a signed integer. - * Here is what we do to obtain the number's magnitude: - * a. add 1 to the number - * b. negate it (becomes positive) - * c. convert it to unsigned - * d. add 1 - */ - if (*is_negative) { - wide_int t = num + 1; - - magnitude = ((u_wide_int) - t) + 1; - } - else - magnitude = (u_wide_int) num; - } - - /* - * We use a do-while loop so that we write at least 1 digit - */ - do { - register u_wide_int new_magnitude = magnitude / 10; - - *--p = magnitude - new_magnitude * 10 + '0'; - magnitude = new_magnitude; - } - while (magnitude); - - *len = buf_end - p; - return (p); -} - - - -/* - * Convert a floating point number to a string formats 'f', 'e' or 'E'. - * The result is placed in buf, and len denotes the length of the string - * The sign is returned in the is_negative argument (and is not placed - * in buf). - */ -static char * - conv_fp(register char format, register double num, -boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len) -{ - register char *s = buf; - register char *p; - int decimal_point; - - if (format == 'f') - p = ap_fcvt(num, precision, &decimal_point, is_negative); - else /* either e or E format */ - p = ap_ecvt(num, precision + 1, &decimal_point, is_negative); - - /* - * Check for Infinity and NaN - */ - if (isalpha(*p)) { - *len = strlen(strcpy(buf, p)); - *is_negative = FALSE; - return (buf); - } - - if (format == 'f') - if (decimal_point <= 0) { - *s++ = '0'; - if (precision > 0) { - *s++ = '.'; - while (decimal_point++ < 0) - *s++ = '0'; - } - else if (add_dp) - *s++ = '.'; - } - else { - while (decimal_point-- > 0) - *s++ = *p++; - if (precision > 0 || add_dp) - *s++ = '.'; - } - else { - *s++ = *p++; - if (precision > 0 || add_dp) - *s++ = '.'; - } - - /* - * copy the rest of p, the NUL is NOT copied - */ - while (*p) - *s++ = *p++; - - if (format != 'f') { - char temp[EXPONENT_LENGTH]; /* for exponent conversion */ - int t_len; - bool_int exponent_is_negative; - - *s++ = format; /* either e or E */ - decimal_point--; - if (decimal_point != 0) { - p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, - &temp[EXPONENT_LENGTH], &t_len); - *s++ = exponent_is_negative ? '-' : '+'; - - /* - * Make sure the exponent has at least 2 digits - */ - if (t_len == 1) - *s++ = '0'; - while (t_len--) - *s++ = *p++; - } - else { - *s++ = '+'; - *s++ = '0'; - *s++ = '0'; - } - } - - *len = s - buf; - return (buf); -} - - -/* - * Convert num to a base X number where X is a power of 2. nbits determines X. - * For example, if nbits is 3, we do base 8 conversion - * Return value: - * a pointer to a string containing the number - * - * The caller provides a buffer for the string: that is the buf_end argument - * which is a pointer to the END of the buffer + 1 (i.e. if the buffer - * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) - */ -static char * - conv_p2(register u_wide_int num, register int nbits, - char format, char *buf_end, register int *len) -{ - register int mask = (1 << nbits) - 1; - register char *p = buf_end; - static char low_digits[] = "0123456789abcdef"; - static char upper_digits[] = "0123456789ABCDEF"; - register char *digits = (format == 'X') ? upper_digits : low_digits; - - do { - *--p = digits[num & mask]; - num >>= nbits; - } - while (num); - - *len = buf_end - p; - return (p); -} - - -/* - * Do format conversion placing the output in buffer - */ -static int format_converter(register buffy * odp, const char *fmt, - va_list ap) -{ - register char *sp; - register char *bep; - register int cc = 0; - register int i; - - register char *s = NULL; - char *q; - int s_len; - - register int min_width = 0; - int precision = 0; - enum { - LEFT, RIGHT - } adjust; - char pad_char; - char prefix_char; - - double fp_num; - wide_int i_num = (wide_int) 0; - u_wide_int ui_num; - - char num_buf[NUM_BUF_SIZE]; - char char_buf[2]; /* for printing %% and %<unknown> */ - - /* - * Flag variables - */ - boolean_e is_long; - boolean_e alternate_form; - boolean_e print_sign; - boolean_e print_blank; - boolean_e adjust_precision; - boolean_e adjust_width; - bool_int is_negative; - - sp = odp->nextb; - bep = odp->buf_end; - - while (*fmt) { - if (*fmt != '%') { - INS_CHAR(*fmt, sp, bep, cc); - } - else { - /* - * Default variable settings - */ - adjust = RIGHT; - alternate_form = print_sign = print_blank = NO; - pad_char = ' '; - prefix_char = NUL; - - fmt++; - - /* - * Try to avoid checking for flags, width or precision - */ - if (isascii(*fmt) && !islower(*fmt)) { - /* - * Recognize flags: -, #, BLANK, + - */ - for (;; fmt++) { - if (*fmt == '-') - adjust = LEFT; - else if (*fmt == '+') - print_sign = YES; - else if (*fmt == '#') - alternate_form = YES; - else if (*fmt == ' ') - print_blank = YES; - else if (*fmt == '0') - pad_char = '0'; - else - break; - } - - /* - * Check if a width was specified - */ - if (isdigit(*fmt)) { - STR_TO_DEC(fmt, min_width); - adjust_width = YES; - } - else if (*fmt == '*') { - min_width = va_arg(ap, int); - fmt++; - adjust_width = YES; - if (min_width < 0) { - adjust = LEFT; - min_width = -min_width; - } - } - else - adjust_width = NO; - - /* - * Check if a precision was specified - * - * XXX: an unreasonable amount of precision may be specified - * resulting in overflow of num_buf. Currently we - * ignore this possibility. - */ - if (*fmt == '.') { - adjust_precision = YES; - fmt++; - if (isdigit(*fmt)) { - STR_TO_DEC(fmt, precision); - } - else if (*fmt == '*') { - precision = va_arg(ap, int); - fmt++; - if (precision < 0) - precision = 0; - } - else - precision = 0; - } - else - adjust_precision = NO; - } - else - adjust_precision = adjust_width = NO; - - /* - * Modifier check - */ - if (*fmt == 'l') { - is_long = YES; - fmt++; - } - else - is_long = NO; - - /* - * Argument extraction and printing. - * First we determine the argument type. - * Then, we convert the argument to a string. - * On exit from the switch, s points to the string that - * must be printed, s_len has the length of the string - * The precision requirements, if any, are reflected in s_len. - * - * NOTE: pad_char may be set to '0' because of the 0 flag. - * It is reset to ' ' by non-numeric formats - */ - switch (*fmt) { - case 'u': - if (is_long) - i_num = va_arg(ap, u_wide_int); - else - i_num = (wide_int) va_arg(ap, unsigned int); - /* - * The rest also applies to other integer formats, so fall - * into that case. - */ - case 'd': - case 'i': - /* - * Get the arg if we haven't already. - */ - if ((*fmt) != 'u') { - if (is_long) - i_num = va_arg(ap, wide_int); - else - i_num = (wide_int) va_arg(ap, int); - }; - s = conv_10(i_num, (*fmt) == 'u', &is_negative, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - - if (*fmt != 'u') { - if (is_negative) - prefix_char = '-'; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - } - break; - - - case 'o': - if (is_long) - ui_num = va_arg(ap, u_wide_int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = conv_p2(ui_num, 3, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - if (alternate_form && *s != '0') { - *--s = '0'; - s_len++; - } - break; - - - case 'x': - case 'X': - if (is_long) - ui_num = (u_wide_int) va_arg(ap, u_wide_int); - else - ui_num = (u_wide_int) va_arg(ap, unsigned int); - s = conv_p2(ui_num, 4, *fmt, - &num_buf[NUM_BUF_SIZE], &s_len); - FIX_PRECISION(adjust_precision, precision, s, s_len); - if (alternate_form && i_num != 0) { - *--s = *fmt; /* 'x' or 'X' */ - *--s = '0'; - s_len += 2; - } - break; - - - case 's': - s = va_arg(ap, char *); - if (s != NULL) { - s_len = strlen(s); - if (adjust_precision && precision < s_len) - s_len = precision; - } - else { - s = S_NULL; - s_len = S_NULL_LEN; - } - pad_char = ' '; - break; - - - case 'f': - case 'e': - case 'E': - fp_num = va_arg(ap, double); - - s = conv_fp(*fmt, fp_num, alternate_form, - (adjust_precision == NO) ? FLOAT_DIGITS : precision, - &is_negative, &num_buf[1], &s_len); - if (is_negative) - prefix_char = '-'; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - break; - - - case 'g': - case 'G': - if (adjust_precision == NO) - precision = FLOAT_DIGITS; - else if (precision == 0) - precision = 1; - /* - * * We use &num_buf[ 1 ], so that we have room for the sign - */ - s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]); - if (*s == '-') - prefix_char = *s++; - else if (print_sign) - prefix_char = '+'; - else if (print_blank) - prefix_char = ' '; - - s_len = strlen(s); - - if (alternate_form && (q = strchr(s, '.')) == NULL) - s[s_len++] = '.'; - if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) - *q = 'E'; - break; - - - case 'c': - char_buf[0] = (char) (va_arg(ap, int)); - s = &char_buf[0]; - s_len = 1; - pad_char = ' '; - break; - - - case '%': - char_buf[0] = '%'; - s = &char_buf[0]; - s_len = 1; - pad_char = ' '; - break; - - - case 'n': - *(va_arg(ap, int *)) = cc; - break; - - /* - * Always extract the argument as a "char *" pointer. We - * should be using "void *" but there are still machines - * that don't understand it. - * If the pointer size is equal to the size of an unsigned - * integer we convert the pointer to a hex number, otherwise - * we print "%p" to indicate that we don't handle "%p". - */ - case 'p': - ui_num = (u_wide_int) va_arg(ap, char *); - - if (sizeof(char *) <= sizeof(u_wide_int)) - s = conv_p2(ui_num, 4, 'x', - &num_buf[NUM_BUF_SIZE], &s_len); - else { - s = "%p"; - s_len = 2; - } - pad_char = ' '; - break; - - - case NUL: - /* - * The last character of the format string was %. - * We ignore it. - */ - continue; - - - /* - * The default case is for unrecognized %'s. - * We print %<char> to help the user identify what - * option is not understood. - * This is also useful in case the user wants to pass - * the output of format_converter to another function - * that understands some other %<char> (like syslog). - * Note that we can't point s inside fmt because the - * unknown <char> could be preceded by width etc. - */ - default: - char_buf[0] = '%'; - char_buf[1] = *fmt; - s = char_buf; - s_len = 2; - pad_char = ' '; - break; - } - - if (prefix_char != NUL) { - *--s = prefix_char; - s_len++; - } - - if (adjust_width && adjust == RIGHT && min_width > s_len) { - if (pad_char == '0' && prefix_char != NUL) { - INS_CHAR(*s, sp, bep, cc) - s++; - s_len--; - min_width--; - } - PAD(min_width, s_len, pad_char); - } - - /* - * Print the string s. - */ - for (i = s_len; i != 0; i--) { - INS_CHAR(*s, sp, bep, cc); - s++; - } - - if (adjust_width && adjust == LEFT && min_width > s_len) - PAD(min_width, s_len, pad_char); - } - fmt++; - } - odp->nextb = sp; - return (cc); -} - - -/* - * This is the general purpose conversion function. - */ -static void strx_printv(int *ccp, char *buf, size_t len, const char *format, - va_list ap) -{ - buffy od; - int cc; - - /* - * First initialize the descriptor - * Notice that if no length is given, we initialize buf_end to the - * highest possible address. - */ - od.buf_end = len ? &buf[len] : (char *) ~0; - od.nextb = buf; - - /* - * Do the conversion - */ - cc = format_converter(&od, format, ap); - if (len == 0 || od.nextb <= od.buf_end) - *(od.nextb) = '\0'; - if (ccp) - *ccp = cc; -} - - -int ap_snprintf(char *buf, size_t len, const char *format,...) -{ - int cc; - va_list ap; - - va_start(ap, format); - strx_printv(&cc, buf, (len - 1), format, ap); - va_end(ap); - return (cc); -} - - -int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap) -{ - int cc; - - strx_printv(&cc, buf, (len - 1), format, ap); - return (cc); -} - -#endif /* HAVE_SNPRINTF */ |