summaryrefslogtreecommitdiff
path: root/usr.sbin/httpd
diff options
context:
space:
mode:
authorBob Beck <beck@cvs.openbsd.org>1999-09-29 06:30:12 +0000
committerBob Beck <beck@cvs.openbsd.org>1999-09-29 06:30:12 +0000
commitcab2f998e0720f3f692dd83cf9444f29ea8f8d26 (patch)
tree6a43cb426458cf0d210496c2dba0a532dfbb3cc5 /usr.sbin/httpd
parentd7a28c8e58fea890c759cc33cd38ab83a7c526c6 (diff)
import apache 1.3.26 + mod_ssl 2.8.10
Diffstat (limited to 'usr.sbin/httpd')
-rw-r--r--usr.sbin/httpd/htdocs/manual/mod/mod_auth_digest.html430
-rw-r--r--usr.sbin/httpd/htdocs/manual/mod/mod_vhost_alias.html311
-rw-r--r--usr.sbin/httpd/htdocs/manual/search/manual-index.cgi246
-rw-r--r--usr.sbin/httpd/htdocs/manual/vhosts/mass.html417
-rw-r--r--usr.sbin/httpd/icons/small/doc.gifbin0 -> 191 bytes
-rw-r--r--usr.sbin/httpd/icons/small/patch.gifbin0 -> 182 bytes
-rw-r--r--usr.sbin/httpd/icons/small/ps.gifbin0 -> 184 bytes
-rw-r--r--usr.sbin/httpd/src/ApacheCoreOS2.def366
-rw-r--r--usr.sbin/httpd/src/ap/ap_base64.c272
-rw-r--r--usr.sbin/httpd/src/ap/ap_checkpass.c111
-rw-r--r--usr.sbin/httpd/src/ap/ap_getpass.c167
-rw-r--r--usr.sbin/httpd/src/ap/ap_md5c.c583
-rw-r--r--usr.sbin/httpd/src/ap/ap_sha1.c383
-rw-r--r--usr.sbin/httpd/src/helpers/getuid.sh65
-rw-r--r--usr.sbin/httpd/src/include/ap_sha1.h102
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/CHANGES41
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/Makefile.tmpl26
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/asciitab.h62
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/expat.html73
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/hashtable.c151
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/hashtable.h69
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/iasciitab.h63
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/latin1tab.h62
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/nametab.h150
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/utf8tab.h63
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmldef.h70
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmlparse.c3256
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmlparse.h482
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmlrole.c1113
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmlrole.h111
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmltok.c1527
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmltok.h307
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmltok_impl.c1746
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmltok_impl.h71
-rw-r--r--usr.sbin/httpd/src/lib/expat-lite/xmltok_ns.c96
-rw-r--r--usr.sbin/httpd/src/modules/experimental/mod_auth_digest.c1919
-rw-r--r--usr.sbin/httpd/src/modules/proxy/Makefile.OS26
-rw-r--r--usr.sbin/httpd/src/modules/standard/Makefile.OS2115
-rw-r--r--usr.sbin/httpd/src/modules/standard/mod_vhost_alias.c482
-rw-r--r--usr.sbin/httpd/src/os/tpf/cgetop.c151
-rw-r--r--usr.sbin/httpd/src/os/win32/apache.icobin0 -> 766 bytes
-rw-r--r--usr.sbin/httpd/src/os/win32/apache.rc84
-rw-r--r--usr.sbin/httpd/src/os/win32/resource.h17
-rw-r--r--usr.sbin/httpd/src/support/README62
-rw-r--r--usr.sbin/httpd/src/support/SHA1/README.sha134
-rw-r--r--usr.sbin/httpd/src/support/SHA1/convert-sha1.pl36
-rw-r--r--usr.sbin/httpd/src/support/SHA1/htpasswd-sha1.pl22
-rw-r--r--usr.sbin/httpd/src/support/SHA1/ldif-sha1.example19
-rw-r--r--usr.sbin/httpd/src/support/ab.8210
-rw-r--r--usr.sbin/httpd/src/support/apachectl.8133
-rw-r--r--usr.sbin/httpd/src/support/htdigest.dsp103
-rw-r--r--usr.sbin/httpd/src/support/htdigest.mak297
-rw-r--r--usr.sbin/httpd/src/support/htpasswd.dsp119
-rw-r--r--usr.sbin/httpd/src/support/htpasswd.mak550
54 files changed, 17351 insertions, 0 deletions
diff --git a/usr.sbin/httpd/htdocs/manual/mod/mod_auth_digest.html b/usr.sbin/httpd/htdocs/manual/mod/mod_auth_digest.html
new file mode 100644
index 00000000000..6b2c044d412
--- /dev/null
+++ b/usr.sbin/httpd/htdocs/manual/mod/mod_auth_digest.html
@@ -0,0 +1,430 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_auth_digest</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.3
+ </H3>
+</DIV>
+
+<H1 ALIGN="CENTER">Module mod_auth_digest</H1>
+
+This module is contained in the <CODE>mod_auth_digest.c</CODE> file, and is
+not compiled in by default. It is only available in Apache 1.3.8 and
+later. It provides for user authentication using MD5 Digest
+Authentication.
+
+<P>Note this is an updated version of <A
+HREF="mod_digest.html">mod_digest</A>. However, it has not been
+extensively tested and is therefore marked experimental. If you use this
+module, you must make sure to <em>not</em> use mod_digest (because they
+share some of the same configuration directives).
+
+
+<MENU>
+<LI><A HREF="#authdigestfile">AuthDigestFile</A>
+<LI><A HREF="#authdigestgroupfile">AuthDigestGroupFile</A>
+<LI><A HREF="#authdigestqop">AuthDigestQop</A>
+<LI><A HREF="#authdigestnoncelifetime">AuthDigestNonceLifetime</A>
+<LI><A HREF="#authdigestnonceformat">AuthDigestNonceFormat</A>
+<LI><A HREF="#authdigestnccheck">AuthDigestNcCheck</A>
+<LI><A HREF="#authdigestalgorithm">AuthDigestAlgorithm</A>
+<LI><A HREF="#authdigestdomain">AuthDigestDomain</A>
+<LI><A HREF="#usingdigest">Using Digest Authentication</A>
+</MENU>
+<HR>
+
+
+<H2><A NAME="authdigestfile">AuthDigestFile</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> AuthDigestFile <EM>filename</EM><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> directory, .htaccess<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> AuthConfig<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_auth_digest<BR>
+
+<P>The AuthDigestFile directive sets the name of a textual file containing
+the list of users and encoded passwords for digest authentication.
+<EM>Filename</EM> is the absolute path to the user file.
+
+<P>The digest file uses a special format. Files in this format can be
+created using the "htdigest" utility found in the support/ subdirectory of
+the Apache distribution.
+
+<HR>
+
+<H2><A NAME="authdigestgroupfile">AuthDigestGroupFile</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> AuthDigestGroupFile <EM>filename</EM><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> directory, .htaccess<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> AuthConfig<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_auth_digest<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Available in Apache 1.3.8 and later
+
+<P>The AuthDigestGroupFile directive sets the name of a textual file
+containing the list of groups and their members (user names).
+<EM>Filename</EM> is the absolute path to the group file.
+
+<P>Each line of the group file contains a groupname followed by a colon,
+followed by the member usernames separated by spaces. Example:
+<BLOCKQUOTE><CODE>mygroup: bob joe anne</CODE></BLOCKQUOTE>
+Note that searching large text files is <EM>very</EM> inefficient.
+
+<P>Security: make sure that the AuthGroupFile is stored outside the
+document tree of the web-server; do <EM>not</EM> put it in the directory
+that it protects. Otherwise, clients will be able to download the
+AuthGroupFile.
+
+<HR>
+
+<H2><A NAME="authdigestqop">AuthDigestQop</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> AuthDigestQop <EM>none | 1*{ auth | auth-int }</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <CODE>AuthDigestQop auth</CODE><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> directory, .htaccess<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> AuthConfig<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_auth_digest<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Available in Apache 1.3.8 and later
+
+<P>The AuthDigestQop directive determines the quality-of-protection to use.
+<EM>auth</EM> will only do authentication (username/password);
+<EM>auth-int</EM> is authentication plus integrity checking (an MD5 hash
+of the entity is also computed and checked); <EM>none</EM> will cause the
+module to use the old RFC-2069 digest algorithm (which does not include
+integrity checking). Both <EM>auth</em> and <EM>auth-int</EM> may be
+specified, in which the case the browser will choose which of these to
+use. <EM>none</EM> should only be used if the browser for some reason
+does not like the challenge it receives otherwise.
+
+<P><STRONG><EM>auth-int</EM> is not implemented yet</STRONG>.
+
+<HR>
+
+<H2><A NAME="authdigestnoncelifetime">AuthDigestNonceLifetime</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> AuthDigestNonceLifetime <EM>&lt;time&gt;</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <CODE>AuthDigestNonceLifetime 300</CODE><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> directory, .htaccess<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> AuthConfig<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_auth_digest<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Available in Apache 1.3.8 and later
+
+<P>The AuthDigestNonceLifetime directive controls how long the server
+nonce is valid. When the client contacts the server using an expired
+nonce the server will send back a 401 with <code>stale=true</code>. If
+<EM>&lt;time&gt;</EM> is greater than 0 then it specifies the number of
+seconds the nonce is valid; this should probably never be set to less
+than 10 seconds. If <EM>&lt;time&gt;</EM> is less than 0 then the nonce
+never expires.
+
+<!-- Not implemented yet
+If <EM>&lt;time&gt;</EM> is 0 then the nonce may be used exactly once
+by the client. Note that while one-time-nonces provide higher security
+against replay attacks, they also have significant performance
+implications, as the browser cannot pipeline or multiple connections
+for the requests. Because browsers cannot easily detect that
+one-time-nonces are being used, this may lead to browsers trying to
+pipeline requests and receiving 401 responses for all but the first
+request, requiring the browser to resend the requests. Note also that
+the protection against reply attacks only makes sense for dynamically
+generated content and things like POST requests; for static content
+the attacker may already have the complete response, so one-time-nonces
+do not make sense here.
+-->
+
+<HR>
+<H2><A NAME="authdigestnonceformat">AuthDigestNonceFormat</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> AuthDigestNonceFormat <EM>???</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <CODE>AuthDigestNonceFormat ???</CODE><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> directory, .htaccess<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> AuthConfig<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_auth_digest<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Available in Apache 1.3.8 and later
+
+<P><STRONG>Not implemented yet.</STRONG>
+<!--
+<P>The AuthDigestNonceFormat directive determines how the nonce is
+generated.
+-->
+
+<HR>
+<H2><A NAME="authdigestnccheck">AuthDigestNcCheck</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> AuthDigestNcCheck <EM>On/Off</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <CODE>AuthDigestNcCheck Off</CODE><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> <EM>Not applicable</EM><BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_auth_digest<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Available in Apache 1.3.8 and later
+
+<P><STRONG>Not implemented yet.</STRONG>
+<!--
+<P>The AuthDigestNcCheck directive enables or disables the checking of the
+nonce-count sent by the server.
+
+<P>While recommended from a security standpoint, turning this directive
+On has one important performance implication. To check the nonce-count
+*all* requests (which have an Authorization header, irrespective of
+whether they require digest authentication) must be serialized through
+a critical section. If the server is handling a large number of
+requests which contain the Authorization header then this may noticeably
+impact performance.
+-->
+
+<HR>
+<H2><A NAME="authdigestalgorithm">AuthDigestAlgorithm</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> AuthDigestAlgorithm <EM>MD5 | MD5-sess</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <CODE>AuthDigestAlgorithm MD5</CODE><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> directory, .htaccess<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> AuthConfig<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_auth_digest<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Available in Apache 1.3.8 and later
+
+<P>The AuthDigestAlgorithm directive selects the algorithm used to calculate
+the challenge and response hashes.
+
+<P><STRONG><EM>MD5-sess</EM> is not correctly implemented yet</STRONG>.
+<!--
+<P>To use <EM>MD5-sess</EM> you must first code up the
+<VAR>get_userpw_hash()</VAR> function in <VAR>mod_auth_digest.c</VAR> .
+-->
+
+<HR>
+<H2><A NAME="authdigestdomain">AuthDigestDomain</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> AuthDigestDomain <EM>URI URI ...</EM><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> directory, .htaccess<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> AuthConfig<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_auth_digest<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> Available in Apache 1.3.8 and later
+
+<P>The AuthDigestDomain directive allows you to specify one or more URIs
+which are in the same protection space (i.e. use the same realm and
+username/password info). The specified URIs are prefixes, i.e. the client
+will assume that all URIs "below" these are also protected by the same
+username/password. The URIs may be either absolute URIs (i.e. inluding a
+scheme, host, port, etc) or relative URIs.
+
+<P>This directive <em>should</em> always be specified and contain at least
+the (set of) root URI(s) for this space. Omiting to do so will cause the
+client to send the Authorization header for <em>every request</em> sent to
+this server. Apart from increasing the size of the request, it may also
+have a detrimental effect on performance if "AuthDigestNcCheck" is on.
+
+<P>The URIs specified can also point to different servers, in which case
+clients (which understand this) will then share username/password info
+across multiple servers without prompting the user each time.
+
+
+<HR>
+
+<H3><A NAME="usingdigest">Using Digest Authentication</A></H3>
+
+<P>Using MD5 Digest authentication is very simple. Simply set up
+authentication normally, using "AuthType Digest" and "AuthDigestFile"
+instead of the normal "AuthType Basic" and "AuthUserFile"; also,
+replace any "AuthGroupFile" with "AuthDigestGroupFile". Then add a
+"AuthDigestDomain" directive containing at least the root URI(s) for
+this protection space. Example:
+
+<PRE>
+ &lt;Location /private/&gt;
+ AuthType Digest
+ AuthName "private area"
+ AuthDigestDomain /private/ http://mirror.my.dom/private2/
+ AuthDigestFile /web/auth/.digest_pw
+ require valid-user
+ &lt;/Location&gt;
+</PRE>
+
+<P><strong>Note:</strong> MD5 authentication provides a more secure
+password system than Basic authentication, but only works with supporting
+browsers. As of this writing (July 1999), the only major browsers which
+support digest authentication are <A
+HREF="http://www.microsoft.com/windows/ie/">Internet Exploder 5.0</A> and
+<A HREF="http://www.w3.org/Amaya/">Amaya</A>. Therefore, we do not
+recommend using this feature on a large Internet site. However, for
+personal and intra-net use, where browser users can be controlled, it is
+ideal.
+
+<HR>
+
+<H3 ALIGN="CENTER">
+ Apache HTTP Server Version 1.3
+</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_vhost_alias.html b/usr.sbin/httpd/htdocs/manual/mod/mod_vhost_alias.html
new file mode 100644
index 00000000000..17506e3042b
--- /dev/null
+++ b/usr.sbin/httpd/htdocs/manual/mod/mod_vhost_alias.html
@@ -0,0 +1,311 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<TITLE>Apache module mod_vhost_alias</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.3
+ </H3>
+</DIV>
+
+<H1 ALIGN="CENTER">Module mod_vhost_alias</H1>
+
+<P>
+This module is contained in the <CODE>mod_vhost_alias.c</CODE> file
+and is not compiled in by default. It should be mentioned near the
+start of the <CODE>Configuration</CODE> file so that it doesn't
+override the behaviour of other modules that do filename translation,
+<EM>e.g.</EM>, <A HREF="mod_userdir.html"><CODE>mod_userdir</CODE></A> and
+<A HREF="mod_alias.html"><CODE>mod_alias</CODE></A>. It provides
+support for <A HREF="../vhosts/mass.html">dynamically configured mass
+virtual hosting</A>.
+</P>
+
+<H2>Directory Name Interpolation</H2>
+
+<P>
+All the directives in this module interpolate a string into a
+pathname. The interpolated string (henceforth called the "name") may
+be either the server name (see the
+<A HREF="core.html#usecanonicalname"><CODE>UseCanonicalName</CODE></A>
+directive for details on how this is determined) or the IP address of
+the virtual host on the server in dotted-quad format. The
+interpolation is controlled by specifiers inspired by
+<CODE>printf</CODE> which have a number of formats:
+<DL>
+ <DT><CODE>%%</CODE>
+ <DD>insert a <CODE>%</CODE>
+ <DT><CODE>%p</CODE>
+ <DD>insert the port number of the virtual host
+ <DT><CODE>%N.M</CODE>
+ <DD>insert (part of) the name
+</DL>
+</P>
+
+<P>
+<CODE>N</CODE> and <CODE>M</CODE> are used to specify substrings of
+the name. <CODE>N</CODE> selects from the dot-separated components of
+the name, and <CODE>M</CODE> selects characters within whatever
+<CODE>N</CODE> has selected. <CODE>M</CODE> is optional and defaults
+to zero if it isn't present; the dot must be present if and only if
+<CODE>M</CODE> is present. The interpretation is as follows:
+<DL>
+ <DT><CODE>0</CODE>
+ <DD>the whole name
+ <DT><CODE>1</CODE>
+ <DD>the first part
+ <DT><CODE>2</CODE>
+ <DD>the second part
+ <DT><CODE>-1</CODE>
+ <DD>the last part
+ <DT><CODE>-2</CODE>
+ <DD>the penultimate part
+ <DT><CODE>2+</CODE>
+ <DD>the second and all subsequent parts
+ <DT><CODE>-2+</CODE>
+ <DD>the penultimate and all preceding parts
+ <DT><CODE>1+</CODE> and <CODE>-1+</CODE>
+ <DD>the same as <CODE>0</CODE>
+</DL>
+If <CODE>N</CODE> or <CODE>M</CODE> is greater than the number of
+parts available a single underscore is interpolated.
+</P>
+
+<H3>Examples</H3>
+
+<P>
+For simple name-based virtual hosts you might use the following
+directives in your server configuration file:
+<PRE>
+ UseCanonicalName Off
+ VirtualDocumentRoot /usr/local/apache/vhosts/%0
+</PRE>
+A request for <CODE>http://www.example.com/directory/file.html</CODE>
+will be satisfied by the file
+<CODE>/usr/local/apache/vhosts/www.example.com/directory/file.html</CODE>.
+</P>
+
+<P>
+For a very large number of virtual hosts it is a good idea to arrange
+the files to reduce the size of the <CODE>vhosts</CODE> directory. To
+do this you might use the following in your configuration file:
+<PRE>
+ UseCanonicalName Off
+ VirtualDocumentRoot /usr/local/apache/vhosts/%3+/%2.1/%2.2/%2.3/%2
+</PRE>
+A request for <CODE>http://www.example.isp.com/directory/file.html</CODE>
+will be satisfied by the file
+<CODE>/usr/local/apache/isp.com/e/x/a/example/directory/file.html</CODE>.
+A more even spread of files can be achieved by hashing from the end of
+the name, for example:
+<PRE>
+ VirtualDocumentRoot /usr/local/apache/vhosts/%3+/%2.-1/%2.-2/%2.-3/%2
+</PRE>
+The example request would come from
+<CODE>/usr/local/apache/vhosts/isp.com/e/l/p/example/directory/file.html</CODE>.
+Alternatively you might use:
+<PRE>
+ VirtualDocumentRoot /usr/local/apache/vhosts/%3+/%2.1/%2.2/%2.3/%2.4+
+</PRE>
+The example request would come from
+<CODE>/usr/local/apache/vhosts/isp.com/e/x/a/mple/directory/file.html</CODE>.
+</P>
+
+<P>
+For IP-based virtual hosting you might use the following in your
+configuration file:
+<PRE>
+ UseCanonicalName DNS
+ VirtualDocumentRootIP /usr/local/apache/vhost/%1/%2/%3/%4/docs
+ VirtualScriptAliasIP /usr/local/apache/vhost/%1/%2/%3/%4/cgi-bin
+</PRE>
+A request for <CODE>http://www.example.isp.com/directory/file.html</CODE>
+would be satisfied by the file
+<CODE>/usr/local/apache/10/20/30/40/docs/directory/file.html</CODE> if
+the IP address of <CODE>www.example.com</CODE> were 10.20.30.40.
+A request for <CODE>http://www.example.isp.com/cgi-bin/script.pl</CODE>
+would be satisfied by executing the program
+<CODE>/usr/local/apache/10/20/30/40/cgi-bin/script.pl</CODE>.
+</P>
+
+<P>
+The <A HREF="mod_log_config.html#formats">LogFormat directives</A>
+<CODE>%V</CODE> and <CODE>%A</CODE> are useful in conjunction with
+this module.
+</P>
+
+<HR>
+
+<H2>Directives</H2>
+<UL>
+ <LI><A HREF="#VirtualDocumentRoot">VirtualDocumentRoot</A>
+ <LI><A HREF="#VirtualDocumentRootIP">VirtualDocumentRootIP</A>
+ <LI><A HREF="#VirtualScriptAlias">VirtualScriptAlias</A>
+ <LI><A HREF="#VirtualScriptAliasIP">VirtualScriptAliasIP</A>
+</UL>
+<HR>
+
+<H2><A NAME="VirtualDocumentRoot">VirtualDocumentRoot directive</A></H2>
+<P>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> VirtualDocumentRoot <EM>interpolated-directory</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> None<BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Extension<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_vhost_alias<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> VirtualDocumentRoot is only available in 1.3.7 and later.</P>
+<P>
+The <CODE>VirtualDocumentRoot</CODE> directive allows you to determine
+where Apache will find your documents based on the value of the server
+name. The result of expanding <EM>interpolated-directory</EM> is used
+as the root of the document tree in a similar manner to the
+<A HREF="core.html#documentroot"><CODE>DocumentRoot</CODE></A>
+directive's argument. If <EM>interpolated-directory</EM> is
+<CODE>none</CODE> then <CODE>VirtaulDocumentRoot</CODE> is turned off.
+This directive cannot be used in the same context as
+<A HREF="#VirtualDocumentRootIP"><CODE>VirtualDocumentRootIP</CODE></A>.
+</P>
+<HR>
+
+<H2><A NAME="VirtualDocumentRootIP">VirtualDocumentRootIP directive</A></H2>
+<P>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> VirtualDocumentRootIP <EM>interpolated-directory</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> None<BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Extension<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_vhost_alias<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> VirtualDocumentRootIP is only available in 1.3.7 and later.</P>
+<P>
+The <CODE>VirtualDocumentRootIP</CODE> directive is like the
+<A HREF="#VirtualDocumentRoot"><CODE>VirtualDocumentRoot</CODE></A> directive,
+except that it uses the IP address of the server end of the connection
+instead of the server name.
+</P>
+<HR>
+
+<H2><A NAME="VirtualScriptAlias">VirtualScriptAlias directive</A></H2>
+<P>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> VirtualScriptAlias <EM>interpolated-directory</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> None<BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Extension<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_vhost_alias<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> VirtualScriptAlias is only available in 1.3.7 and later.</P>
+<P>
+The <CODE>VirtualScriptAlias</CODE> directive allows you to determine
+where Apache will find CGI scripts in a similar manner to
+<A HREF="#VirtualDocumentRoot"><CODE>VirtualDocumentRoot</CODE></A>
+does for other documents. It matches requests for URIs starting
+<CODE>/cgi-bin/</CODE>, much like
+<CODE><A HREF="mod_alias.html#scriptalias">ScriptAlias</A> /cgi-bin/</CODE>
+would.
+</P>
+<HR>
+
+<H2><A NAME="VirtualScriptAlias">VirtualScriptAliasIP directive</A></H2>
+<P>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> VirtualScriptAliasIP <EM>interpolated-directory</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> None<BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Extension<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_vhost_alias<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> VirtualScriptAliasIP is only available in 1.3.7 and later.</P>
+<P>
+The <CODE>VirtualScriptAliasIP</CODE> directibe is like the
+<A HREF="#VirtualScriptAlias"><CODE>VirtualScriptAlias</CODE></A> directive,
+except that it uses the IP address of the server end of the connection
+instead of the server name.
+</P>
+<HR>
+
+<H3 ALIGN="CENTER">
+ Apache HTTP Server Version 1.3
+</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/search/manual-index.cgi b/usr.sbin/httpd/htdocs/manual/search/manual-index.cgi
new file mode 100644
index 00000000000..033529937fd
--- /dev/null
+++ b/usr.sbin/httpd/htdocs/manual/search/manual-index.cgi
@@ -0,0 +1,246 @@
+#!/usr/local/bin/perl5 -w
+# ====================================================================
+# 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.
+# ====================================================================
+#
+# manual-index.cgi script
+# originally written by Ken Coar <Coar@DECUS.Org> in May 1997
+#
+# This script either displays a form in order to find documents in which
+# a word appears, or displays the results of such a search. It is
+# called as a CGI script.
+#
+# [FILE]PATH_INFO is the prefix to add to to the files names found in
+# the index (URL prefix, not filesystem prefix), and QUERY_STRING is the
+# word to be found.
+#
+#***
+#***
+# You may need to tweak the following line to point to the correct
+# location of the index file on your system (it's in the
+# apache/htdocs/manual directory of the Apache distribution tree).
+#***
+#***
+$INDEX = "/www/apache.org/manual-index-data";
+
+#***
+#***
+# You shouldn't have to modify anything else.
+#***
+#***
+
+$HTML = "";
+
+#
+# If we have a FILEPATH_INFO or PATH_INFO, it's there to remap the
+# documents to the manual root directory. If this script is already in
+# that directory, this isn't needed.
+#
+$prefix = $ENV{'FILEPATH_INFO'} || $ENV{'PATH_INFO'};
+$prefix .= "/" if ($prefix && ($prefix !~ m:/$:));
+
+#
+# QUERY_STRING, if present, contains the word for which we are to
+# search. We also use its [non]presence to determine wha we display.
+#
+$word = $ENV{'QUERY_STRING'};
+
+#
+# Make sure our HTTP header makes it to the server by causing Perl to do
+# a fflush() after every write to STDOUT.
+#
+select (STDOUT);
+$| = 1;
+printf ("Content-type: text/html\n\n");
+
+#
+# Fine, now buffering can go back to normal.
+#
+$| = 0;
+
+#
+# Set up the HTML page title
+$title = "Apache Documentation Search";
+$title .= ": Results for \"$word\"" if ($word);
+
+#
+# We'll re-use the HTML scalar several times; we use it with here
+# documents for multi-line static HTML code. Lets' do the standard page
+# header.
+#
+$HTML = <<EOHT;
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+ <HEAD>
+ <TITLE>$title
+ </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="${prefix}images/sub.gif"
+ ALT=""
+ >
+ </DIV>
+ <H1 ALIGN="CENTER">
+ Apache Documentation Search
+ </H1>
+ <P>
+ This script performs a very simple search across the Apache
+ documentation for any single case-insensitive word. No combinations,
+ wildcards, regular expressions, word-stubbing, or other fancy options
+ are supported; this is just to help you find topics quickly. Only
+ those pages which include the <EM>exact</EM> word you type will be
+ listed.
+ </P>
+ <P>
+ Documents containing the search word are <EM>not</EM> listed in any
+ sort of priority order.
+ </P>
+ <ISINDEX PROMPT="Enter word to find and press ENTER: ">
+EOHT
+
+printf ($HTML);
+
+#
+# Now set up the next section, which is only displayed if we've been
+# given a word to find.
+#
+$HTML = <<EOHT;
+ <HR>
+ <H2>
+ Results of Search for <SAMP>$word</SAMP>
+ </H2>
+EOHT
+
+#
+# We enblock the next section so problems can drop out to the common
+# closure code.
+#
+QUERY:
+ {
+ if ($word) {
+ #
+ # Try and open the index file; complain bitterly if we can't.
+ #
+ if (! open (INDEX, "<$INDEX")) {
+ printf ("Can't find documentation index!");
+ last QUERY;
+ }
+ #
+ # Got it; display the search-results header.
+ #
+ printf ($HTML);
+ #
+ # Read the entire index in and turn it into an hash for the
+ # lookup.
+ #
+ @index = <INDEX>;
+ close (INDEX);
+ chomp (@index);
+ foreach (@index) {
+ ($key, $files) = split (/:/, $_);
+ $Index{$key} = $files;
+ }
+ #
+ # The dictionary is all lowercase words. Smash our query value
+ # and try to find it.
+ #
+ $word = lc ($word);
+ if (! exists ($Index{$word})) {
+ printf (" <P>\n <EM>Sorry, no matches found.</EM>\n </P>\n");
+ last QUERY;
+ }
+ #
+ # Found an entry, so turn the hash value (a comma-separated list
+ # of relative file names) into an array for display.
+ # Incidentally, tell the user how many there are.
+ #
+ @files = split (/,/, $Index{$word});
+ printf (" <P>Total of %d match", scalar (@files));
+ #
+ # Be smart about plurals.
+ #
+ if (scalar (@files) != 1) {
+ printf ("es") ;
+ }
+ printf (" found.\n </P>\n");
+ #
+ # Right. Now display the files as they're listed.
+ #
+ printf (" <OL>\n");
+ foreach (@files) {
+ printf (" <LI><A HREF=\"${prefix}$_\">");
+ printf ("<SAMP>$_</SAMP></A>\n");
+ printf (" </LI>\n");
+ }
+ printf (" </OL>\n");
+ #
+ # C'est tout!
+ #
+ }
+ }
+
+#
+# Back to common code - the exit path. Display the page trailer.
+#
+$HTML = <<EOHT;
+ <A
+ HREF="/"
+ ><IMG
+ SRC="/images/apache_home.gif"
+ ALT="Home"
+ ></A>
+ <HR>
+ </BODY>
+</HTML>
+EOHT
+
+printf ($HTML);
+exit (0);
diff --git a/usr.sbin/httpd/htdocs/manual/vhosts/mass.html b/usr.sbin/httpd/htdocs/manual/vhosts/mass.html
new file mode 100644
index 00000000000..364293b9804
--- /dev/null
+++ b/usr.sbin/httpd/htdocs/manual/vhosts/mass.html
@@ -0,0 +1,417 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML><HEAD>
+<TITLE>Dynamically configured mass virtual hosting</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.3
+ </H3>
+</DIV>
+
+<H1 ALIGN="CENTER">Dynamically configured mass virtual hosting</H1>
+
+<P>This document describes how to efficiently serve an arbitrary number
+of virtual hosts with Apache 1.3.
+
+<!--
+
+Written by Tony Finch (fanf@demon.net) (dot@dotat.at).
+
+Some examples were derived from Ralf S. Engleschall's document
+ http://www.engelschall.com/pw/apache/rewriteguide/
+
+Some suggestions were made by Brian Behlendorf.
+
+-->
+
+<H2><A NAME="contents">Contents:</A></H2>
+
+<UL>
+<LI><A HREF="#motivation">Motivation</A>
+<LI><A HREF="#overview">Overview</A>
+<LI><A HREF="#simple">Simple dynamic virtual hosts</A>
+<LI><A HREF="#homepages">A virtually hosted homepages system</A>
+<LI><A HREF="#combinations">Using more than one virtual hosting system on the same server</A>
+<LI><A HREF="#ipbased">More efficient IP-based virtual hosting</A>
+<LI><A HREF="#oldversion">Using older versions of Apache</A>
+<LI><A HREF="#simple.rewrite">Simple dynamic virtual hosts using <CODE>mod_rewrite</CODE></A>
+<LI><A HREF="#homepages.rewrite">A homepages system using <CODE>mod_rewrite</CODE></A>
+<LI><A HREF="#xtra-conf">Using a separate virtual host configuration file</A>
+</UL>
+
+<HR><H2><A NAME="motivation">Motivation</A></H2>
+
+<P>The techniques described here are of interest if your
+<CODE>httpd.conf</CODE> contains many
+<CODE>&lt;VirtualHost&gt;</CODE> sections that are substantially the
+same, for example:
+<PRE>
+NameVirtualHost 111.22.33.44
+&lt;VirtualHost 111.22.33.44&gt;
+ ServerName www.customer-1.com
+ DocumentRoot /www/hosts/www.customer-1.com/docs
+ ScriptAlias /cgi-bin/ /www/hosts/www.customer-1.com/cgi-bin
+&lt;/VirtualHost&gt;
+&lt;VirtualHost 111.22.33.44&gt;
+ ServerName www.customer-2.com
+ DocumentRoot /www/hosts/www.customer-2.com/docs
+ ScriptAlias /cgi-bin/ /www/hosts/www.customer-2.com/cgi-bin
+&lt;/VirtualHost&gt;
+# blah blah blah
+&lt;VirtualHost 111.22.33.44&gt;
+ ServerName www.customer-N.com
+ DocumentRoot /www/hosts/www.customer-N.com/docs
+ ScriptAlias /cgi-bin/ /www/hosts/www.customer-N.com/cgi-bin
+&lt;/VirtualHost&gt;
+</PRE>
+</P>
+
+<P>The basic idea is to replace all of the static
+<CODE>&lt;VirtualHost&gt;</CODE> configuration with a mechanism that
+works it out dynamically. This has a number of advantages:
+<OL>
+ <LI>Your configuration file is smaller so Apache starts faster and
+ uses less memory.
+ <LI>Adding virtual hosts is simply a matter of creating the
+ appropriate directories in the filesystem and entries in the DNS -
+ you don't need to reconfigure or restart Apache.
+</OL>
+</P>
+
+<P>The main disadvantage is that you cannot have a different log file
+for each virtual host; however if you have very many virtual hosts
+then doing this is dubious anyway because it eats file descriptors. It
+is better to log to a pipe or a fifo and arrange for the process at
+the other end to distribute the logs to the customers (it can also
+accumulate statistics, etc.).</P>
+
+
+<HR><H2><A NAME="overview">Overview</A></H2>
+
+<P>A virtual host is defined by two pieces of information: its IP
+address, and the contents of the <CODE>Host:</CODE> header in the HTTP
+request. The dynamic mass virtual hosting technique is based on
+automatically inserting this information into the pathname of the file
+that is used to satisfy the request. This is done most easily using
+<A HREF="../mod/mod_vhost_alias.html"><CODE>mod_vhost_alias</CODE></A>,
+but if you are using a version of Apache up to 1.3.6 then you must use
+<A HREF="../mod/mod_rewrite.html"><CODE>mod_rewrite</CODE></A>. Both
+of these modules are disabled by default; you must enable one of them
+when configuring and building Apache if you want to use this technique.</P>
+
+<P>A couple of things need to be `faked' to make the dynamic virtual
+host look like a normal one. The most important is the server name
+which is used by Apache to generate self-referential URLs, etc. It
+is configured with the <CODE>ServerName</CODE> directive, and it is
+available to CGIs via the <CODE>SERVER_NAME</CODE> environment
+variable. The actual value used at run time is controlled by the
+<A HREF="../mod/core.html#usecanonicalname"><CODE>UseCanonicalName</CODE></A>
+setting. With <CODE>UseCanonicalName Off</CODE> the server name
+comes from the contents of the <CODE>Host:</CODE> header in the
+request. With <CODE>UseCanonicalName DNS</CODE> it comes from a
+reverse DNS lookup of the virtual host's IP address. The former
+setting is used for name-based dynamic virtual hosting, and the latter
+is used for IP-based hosting. If Apache cannot work out the server
+name because there is no <CODE>Host:</CODE> header or the DNS lookup
+fails then the value configured with <CODE>ServerName</CODE> is used
+instead.</P>
+
+<P>The other thing to `fake' is the document root (configured
+with <CODE>DocumentRoot</CODE> and available to CGIs via the
+<CODE>DOCUMENT_ROOT</CODE> environment variable). This setting
+is used by the core module when mapping URIs to filenames, but
+when the server is configured to do dynamic virtual hosting that
+job is taken over by another module. If any CGIs or SSI documents
+make use of the <CODE>DOCUMENT_ROOT</CODE> environment variable
+they will therefore get a misleading value; there isn't any way to
+change <CODE>DOCUMENT_ROOT</CODE> dynamically.</P>
+
+
+<HR><H2><A NAME="simple">Simple dynamic virtual hosts</A></H2>
+
+<P>This extract from <CODE>httpd.conf</CODE> implements the virtual
+host arrangement outlined in the <A HREF="#motivation">Motivation</A>
+section above, but in a generic fashion using
+<CODE>mod_vhost_alias</CODE>.</P>
+
+<PRE>
+# get the server name from the Host: header
+UseCanonicalName Off
+
+# this log format can be split per-virtual-host based on the first field
+LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon
+CustomLog logs/access_log vcommon
+
+# include the server name in the filenames used to satisfy requests
+VirtualDocumentRoot /www/hosts/%0/docs
+VirtualScriptAlias /www/hosts/%0/cgi-bin
+</PRE>
+
+<P>This configuration can be changed into an IP-based virtual hosting
+solution by just turning <CODE>UseCanonicalName Off</CODE> into
+<CODE>UseCanonicalName DNS</CODE>. The server name that is inserted
+into the filename is then derived from the IP address of the virtual
+host.</P>
+
+
+<HR><H2><A NAME="homepages">A virtually hosted homepages system</A></H2>
+
+<P>This is an adjustment of the above system tailored for an ISP's
+homepages server. Using a slightly more complicated configuration we
+can select substrings of the server name to use in the filename so
+that e.g. the documents for <SAMP>www.user.isp.com</SAMP> are found in
+<CODE>/home/user/</CODE>. It uses a single <CODE>cgi-bin</CODE>
+directory instead of one per virtual host.</P>
+
+<PRE>
+# all the preliminary stuff is the same as above, then
+
+# include part of the server name in the filenames
+VirtualDocumentRoot /www/hosts/%2/docs
+
+# single cgi-bin directory
+ScriptAlias /cgi-bin/ /www/std-cgi/
+</PRE>
+
+<P>There are examples of more complicated
+<CODE>VirtualDocumentRoot</CODE> settings in
+<A HREF="../mod/mod_vhost_alias.html">the
+<CODE>mod_vhost_alias</CODE> documentation</A>.</P>
+
+
+<HR><H2><A NAME="combinations">Using more than one virtual hosting
+system on the same server</A></H2>
+
+<P>With more complicated setups you can use Apache's normal
+<CODE>&lt;VirtualHost&gt;</CODE> directives to control the scope of
+the various virtual hosting configurations. For example, you could
+have one IP address for homepages customers and another for commercial
+customers with the following setup. This can of course be combined
+with conventional <CODE>&lt;VirtualHost&gt;</CODE> configuration
+sections.</P>
+
+<PRE>
+UseCanonicalName Off
+
+LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon
+
+&lt;Directory /www/commercial&gt;
+ Options FollowSymLinks
+ AllowOverride All
+&lt;/Directory&gt;
+
+&lt;Directory /www/homepages&gt;
+ Options FollowSymLinks
+ AllowOverride None
+&lt;/Directory&gt;
+
+&lt;VirtualHost 111.22.33.44&gt;
+ ServerName www.commercial.isp.com
+
+ CustomLog logs/access_log.commercial vcommon
+
+ VirtualDocumentRoot /www/commercial/%0/docs
+ VirtualScriptAlias /www/commercial/%0/cgi-bin
+&lt;/VirtualHost&gt;
+
+&lt;VirtualHost 111.22.33.45&gt;
+ ServerName www.homepages.isp.com
+
+ CustomLog logs/access_log.homepages vcommon
+
+ VirtualDocumentRoot /www/homepages/%0/docs
+ ScriptAlias /cgi-bin/ /www/std-cgi/
+&lt;/VirtualHost&gt;
+</PRE>
+
+
+<HR><H2><A NAME="ipbased">More efficient IP-based virtual hosting</A></H2>
+
+<P>After <A HREF="#simple">the first example</A> I noted that it is
+easy to turn it into an IP-based virtual hosting setup. Unfortunately
+that configuration is not very efficient because it requires a DNS
+lookup for every request. This can be avoided by laying out the
+filesystem according to the IP addresses themselves rather than the
+corresponding names and changing the logging similarly. Apache will
+then usually not need to work out the server name and so incur a DNS
+lookup.</P>
+
+<PRE>
+# get the server name from the reverse DNS of the IP address
+UseCanonicalName DNS
+
+# include the IP address in the logs so they may be split
+LogFormat "%A %h %l %u %t \"%r\" %s %b" vcommon
+CustomLog logs/access_log vcommon
+
+# include the IP address in the filenames
+VirtualDocumentRootIP /www/hosts/%0/docs
+VirtualScriptAliasIP /www/hosts/%0/cgi-bin
+</PRE>
+
+
+<HR><H2><A NAME="oldversion">Using older versions of Apache</A></H2>
+
+<P>The examples above rely on <CODE>mod_vhost_alias</CODE> which
+appeared after version 1.3.6. If you are using a version of Apache
+without <CODE>mod_vhost_alias</CODE> then you can implement this
+technique with <CODE>mod_rewrite</CODE> as illustrated below, but
+only for Host:-header-based virtual hosts.</P>
+
+<P>In addition there are some things to beware of with logging. Apache
+1.3.6 is the first version to include the <CODE>%V</CODE> log format
+directive; in versions 1.3.0 - 1.3.3 the <CODE>%v</CODE> option did
+what <CODE>%V</CODE> does; version 1.3.4 has no equivalent. In
+all these versions of Apache the <CODE>UseCanonicalName</CODE>
+directive can appear in <CODE>.htaccess</CODE> files which means that
+customers can cause the wrong thing to be logged. Therefore the best
+thing to do is use the <CODE>%{Host}i</CODE> directive which logs the
+<CODE>Host:</CODE> header directly; note that this may include
+<CODE>:port</CODE> on the end which is not the case for
+<CODE>%V</CODE>.</P>
+
+
+<HR><H2><A NAME="simple.rewrite">Simple dynamic virtual hosts
+using <CODE>mod_rewrite</CODE></A></H2>
+
+<P>This extract from <CODE>httpd.conf</CODE> does the same thing as
+<A HREF="#simple">the first example</A>. The first half is very
+similar to the corresponding part above but with some changes for
+backward compatibility and to make the <CODE>mod_rewrite</CODE> part
+work properly; the second half configures <CODE>mod_rewrite</CODE> to
+do the actual work.</P>
+
+<P>There are a couple of especially tricky bits: By default,
+<CODE>mod_rewrite</CODE> runs before the other URI translation modules
+(<CODE>mod_alias</CODE> etc.) so if they are used then
+<CODE>mod_rewrite</CODE> must be configured to accommodate them.
+Also, mome magic must be performed to do a per-dynamic-virtual-host
+equivalent of <CODE>ScriptAlias</CODE>.</P>
+
+<PRE>
+# get the server name from the Host: header
+UseCanonicalName Off
+
+# splittable logs
+LogFormat "%{Host}i %h %l %u %t \"%r\" %s %b" vcommon
+CustomLog logs/access_log vcommon
+
+&lt;Directory /www/hosts&gt;
+ # ExecCGI is needed here because we can't force
+ # CGI execution in the way that ScriptAlias does
+ Options FollowSymLinks ExecCGI
+&lt;/Directory&gt;
+
+# now for the hard bit
+
+RewriteEngine On
+
+# a ServerName derived from a Host: header may be any case at all
+RewriteMap lowercase int:tolower
+
+## deal with normal documents first:
+# allow Alias /icons/ to work - repeat for other aliases
+RewriteCond %{REQUEST_URI} !^/icons/
+# allow CGIs to work
+RewriteCond %{REQUEST_URI} !^/cgi-bin/
+# do the magic
+RewriteRule ^/(.*)$ /www/hosts/${lowercase:%{SERVER_NAME}}/docs/$1
+
+## and now deal with CGIs - we have to force a MIME type
+RewriteCond %{REQUEST_URI} ^/cgi-bin/
+RewriteRule ^/(.*)$ /www/hosts/${lowercase:%{SERVER_NAME}}/cgi-bin/$1 [T=application/x-httpd-cgi]
+
+# that's it!
+</PRE>
+
+
+<HR><H2><A NAME="homepages.rewrite">A homepages system
+using <CODE>mod_rewrite</CODE></A></H2>
+
+<P>This does the same thing as <A HREF="#homepages">the
+second example</A>.</P>
+
+<PRE>
+RewriteEngine on
+
+RewriteMap lowercase int:tolower
+
+# allow CGIs to work
+RewriteCond %{REQUEST_URI} !^/cgi-bin/
+
+# check the hostname is right so that the RewriteRule works
+RewriteCond ${lowercase:%{SERVER_NAME}} ^www\.[a-z-]+\.isp\.com$
+
+# concatenate the virtual host name onto the start of the URI
+# the [C] means do the next rewrite on the result of this one
+RewriteRule ^(.+) ${lowercase:%{SERVER_NAME}}$1 [C]
+
+# now create the real file name
+RewriteRule ^www\.([a-z-]+)\.isp\.com/(.*) /home/$1/$2
+
+# define the global CGI directory
+ScriptAlias /cgi-bin/ /www/std-cgi/
+</PRE>
+
+
+<HR><H2><A NAME="xtra-conf">Using a separate virtual host configuration file</A></H2>
+
+<P>This arrangement uses more advanced <CODE>mod_rewrite</CODE>
+features to get the translation from virtual host to document root
+from a separate configuration file. This provides more flexibility but
+requires more complicated configuration.</P>
+
+<P>The <CODE>vhost.map</CODE> file contains something like this:
+<PRE>
+www.customer-1.com /www/customers/1
+www.customer-2.com /www/customers/2
+# ...
+www.customer-N.com /www/customers/N
+</PRE>
+</P>
+
+<P>The <CODE>http.conf</CODE> contains this:
+<PRE>
+RewriteEngine on
+
+RewriteMap lowercase int:tolower
+
+# define the map file
+RewriteMap vhost txt:/www/conf/vhost.map
+
+# deal with aliases as above
+RewriteCond %{REQUEST_URI} !^/icons/
+RewriteCond %{REQUEST_URI} !^/cgi-bin/
+RewriteCond ${lowercase:%{SERVER_NAME}} ^(.+)$
+# this does the file-based remap
+RewriteCond ${vhost:%1} ^(/.*)$
+RewriteRule ^/(.*)$ %1/docs/$1
+
+RewriteCond %{REQUEST_URI} ^/cgi-bin/
+RewriteCond ${lowercase:%{SERVER_NAME}} ^(.+)$
+RewriteCond ${vhost:%1} ^(/.*)$
+RewriteRule ^/(.*)$ %1/cgi-bin/$1
+</PRE>
+</P>
+
+<HR>
+
+<H3 ALIGN="CENTER">
+ Apache HTTP Server Version 1.3
+</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/icons/small/doc.gif b/usr.sbin/httpd/icons/small/doc.gif
new file mode 100644
index 00000000000..0fcf18db2a8
--- /dev/null
+++ b/usr.sbin/httpd/icons/small/doc.gif
Binary files differ
diff --git a/usr.sbin/httpd/icons/small/patch.gif b/usr.sbin/httpd/icons/small/patch.gif
new file mode 100644
index 00000000000..100484e5982
--- /dev/null
+++ b/usr.sbin/httpd/icons/small/patch.gif
Binary files differ
diff --git a/usr.sbin/httpd/icons/small/ps.gif b/usr.sbin/httpd/icons/small/ps.gif
new file mode 100644
index 00000000000..fa4bcfce30f
--- /dev/null
+++ b/usr.sbin/httpd/icons/small/ps.gif
Binary files differ
diff --git a/usr.sbin/httpd/src/ApacheCoreOS2.def b/usr.sbin/httpd/src/ApacheCoreOS2.def
new file mode 100644
index 00000000000..5476d091dc9
--- /dev/null
+++ b/usr.sbin/httpd/src/ApacheCoreOS2.def
@@ -0,0 +1,366 @@
+; ApacheCoreOS2.def :
+
+LIBRARY libhttpd INITINSTANCE
+DESCRIPTION 'Apache Web Server'
+
+EXPORTS
+ ; Add new API calls to the end of this list.
+ ap_MD5Final @1
+ ap_MD5Init @2
+ ap_MD5Update @3
+; ap_acquire_mutex @4
+ ap_add_cgi_vars @5
+ ap_add_common_vars @6
+ ap_add_loaded_module @7
+ ap_add_module @8
+ ap_add_named_module @9
+ ap_add_per_dir_conf @10
+ ap_add_per_url_conf @11
+ ap_add_version_component @12
+ ap_allow_options @13
+ ap_allow_overrides @14
+ ap_append_arrays @15
+ ap_array_cat @16
+ ap_auth_name @17
+ ap_auth_type @18
+ ap_basic_http_header @19
+ ap_bclose @20
+ ap_bcreate @21
+ ap_bfilbuf @22
+ ap_bfileno @23
+ ap_bflsbuf @24
+ ap_bflush @25
+ ap_bgetopt @26
+ ap_bgets @27
+ ap_bhalfduplex @28
+ ap_block_alarms @29
+ ap_blookc @30
+ ap_bnonblock @31
+ ap_bonerror @32
+ ap_bpushfd @33
+; ap_bpushh @34
+ ap_bputs @35
+ ap_bread @36
+ ap_bsetflag @37
+ ap_bsetopt @38
+ ap_bskiplf @39
+ ap_bspawn_child @40
+ ap_bwrite @41
+ ap_bytes_in_free_blocks @42
+ ap_bytes_in_pool @43
+ ap_call_exec @44
+ ap_can_exec @45
+ ap_cfg_closefile @46
+ ap_cfg_getc @47
+ ap_cfg_getline @48
+ ap_chdir_file @49
+; ap_check_alarm @50
+ ap_check_cmd_context @51
+ ap_checkmask @52
+ ap_cleanup_for_exec @53
+ ap_clear_module_list @54
+ ap_clear_pool @55
+ ap_clear_table @56
+ ap_close_piped_log @57
+ ap_construct_server @58
+ ap_construct_url @59
+ ap_content_type_tolower @60
+ ap_copy_array @61
+ ap_copy_array_hdr @62
+ ap_copy_table @63
+ ap_count_dirs @64
+ ap_cpystrn @65
+ ap_create_environment @66
+; ap_create_mutex @67
+ ap_create_per_dir_config @68
+ ap_custom_response @69
+ ap_default_port_for_request @70
+ ap_default_port_for_scheme @71
+ ap_default_type @72
+; ap_destroy_mutex @73
+ ap_destroy_pool @74
+ ap_destroy_sub_req @75
+ ap_die @76
+ ap_discard_request_body @77
+ ap_document_root @78
+ ap_each_byterange @79
+ ap_error_log2stderr @80
+ ap_escape_html @81
+ ap_escape_path_segment @82
+ ap_escape_quotes @83
+ ap_escape_shell_cmd @84
+ ap_exists_scoreboard_image @85
+ ap_finalize_request_protocol @86
+ ap_find_command @87
+ ap_find_command_in_modules @88
+ ap_find_last_token @89
+ ap_find_linked_module @90
+ ap_find_module_name @91
+ ap_find_path_info @92
+ ap_find_token @93
+ ap_get_basic_auth_pw @94
+ ap_get_client_block @95
+ ap_get_gmtoff @96
+ ap_get_limit_req_body @97
+ ap_get_remote_host @98
+ ap_get_remote_logname @99
+ ap_get_server_built @100
+ ap_get_server_name @101
+ ap_get_server_port @102
+ ap_get_server_version @103
+ ap_get_time @104
+ ap_get_token @105
+ ap_getparents @106
+ ap_getword @107
+ ap_getword_conf @108
+ ap_getword_conf_nc @109
+ ap_getword_nc @110
+ ap_getword_nulls @111
+ ap_getword_nulls_nc @112
+ ap_getword_white @113
+ ap_getword_white_nc @114
+ ap_gm_timestr_822 @115
+ ap_gname2id @116
+ ap_handle_command @117
+ ap_hard_timeout @118
+ ap_ht_time @119
+ ap_ind @120
+ ap_index_of_response @121
+ ap_init_virtual_host @122
+ ap_internal_redirect @123
+ ap_internal_redirect_handler @124
+ ap_is_directory @125
+ ap_is_fnmatch @126
+ ap_is_initial_req @127
+ ap_is_matchexp @128
+ ap_is_url @129
+ ap_kill_cleanup @130
+ ap_kill_cleanups_for_fd @131
+ ap_kill_cleanups_for_socket @132
+ ap_kill_timeout @133
+ ap_log_assert @134
+ ap_log_error_old @135
+ ap_log_reason @136
+ ap_log_unixerr @137
+ ap_make_array @138
+ ap_make_dirstr @139
+ ap_make_dirstr_parent @140
+ ap_make_dirstr_prefix @141
+ ap_make_full_path @142
+ ap_make_sub_pool @143
+ ap_make_table @144
+ ap_matches_request_vhost @145
+ ap_md5 @146
+ ap_md5_binary @147
+ ap_md5contextTo64 @148
+ ap_md5digest @149
+ ap_meets_conditions @150
+ ap_no2slash @151
+ ap_note_auth_failure @152
+ ap_note_basic_auth_failure @153
+ ap_note_cleanups_for_fd @154
+ ap_note_cleanups_for_file @155
+; ap_note_cleanups_for_h @156
+ ap_note_cleanups_for_socket @157
+ ap_note_digest_auth_failure @158
+ ap_note_subprocess @159
+; ap_open_mutex @160
+ ap_open_piped_log @161
+ ap_os_canonical_filename @162
+ ap_os_escape_path @163
+ ap_overlap_tables @164
+ ap_overlay_tables @165
+ ap_palloc @166
+ ap_parseHTTPdate @167
+ ap_parse_hostinfo_components @168
+ ap_parse_uri @169
+ ap_parse_uri_components @170
+ ap_pcalloc @171
+ ap_pcfg_open_custom @172
+ ap_pcfg_openfile @173
+ ap_pclosedir @174
+ ap_pclosef @175
+; ap_pcloseh @176
+ ap_pclosesocket @177
+ ap_pduphostent @178
+ ap_pfclose @179
+ ap_pfdopen @180
+ ap_pfopen @181
+ ap_pgethostbyname @182
+ ap_popendir @183
+ ap_popenf @184
+ ap_pregcomp @185
+ ap_pregfree @186
+ ap_pregsub @187
+ ap_psignature @188
+ ap_psocket @189
+ ap_pstrdup @190
+ ap_pstrndup @191
+ ap_push_array @192
+ ap_pvsprintf @193
+ ap_rationalize_mtime @194
+ ap_register_cleanup @195
+; ap_release_mutex @196
+ ap_remove_loaded_module @197
+ ap_remove_module @198
+ ap_requires @199
+ ap_reset_timeout @200
+ ap_rflush @201
+ ap_rind @202
+ ap_rputc @203
+ ap_rputs @204
+ ap_run_cleanup @205
+ ap_run_sub_req @206
+ ap_rwrite @207
+ ap_satisfies @208
+ ap_scan_script_header_err @209
+ ap_scan_script_header_err_buff @210
+ ap_scan_script_header_err_core @211
+ ap_send_fb @212
+ ap_send_fb_length @213
+ ap_send_fd @214
+ ap_send_fd_length @215
+ ap_send_http_header @216
+ ap_send_http_trace @217
+ ap_send_mmap @218
+ ap_send_size @219
+ ap_server_root_relative @220
+ ap_set_byterange @221
+ ap_set_content_length @222
+ ap_set_etag @223
+ ap_set_keepalive @224
+ ap_set_last_modified @225
+ ap_setup_client_block @226
+ ap_should_client_block @227
+ ap_soft_timeout @228
+ ap_some_auth_required @229
+ ap_spawn_child @230
+ ap_srm_command_loop @231
+ ap_str_tolower @232
+ ap_strcasecmp_match @233
+ ap_strcmp_match @234
+ ap_sub_req_lookup_file @235
+ ap_sub_req_lookup_uri @236
+ ap_sync_scoreboard_image @237
+ ap_table_add @238
+ ap_table_addn @239
+ ap_table_get @240
+ ap_table_merge @241
+ ap_table_mergen @242
+ ap_table_set @243
+ ap_table_setn @244
+ ap_table_unset @245
+ ap_tm2sec @246
+ ap_uname2id @247
+ ap_unblock_alarms @248
+ ap_unescape_url @249
+ ap_unparse_uri_components @250
+ ap_update_mtime @251
+ ap_uudecode @252
+ ap_uuencode @253
+ ap_vbprintf @254
+ ap_vformatter @255
+ ap_vsnprintf @256
+; closedir @257
+; opendir @258
+; os_spawnv @259
+; os_spawnve @260
+; os_stat @261
+; readdir @262
+ regcomp @263
+ regexec @264
+ regfree @265
+; access_module @266
+; alias_module @267
+ ap_bprintf @268
+ ap_bvputs @269
+ ap_day_snames @270
+ ap_extended_status @271
+ ap_limit_section @272
+ ap_loaded_modules @273
+ ap_log_error @274
+ ap_log_printf @275
+ ap_log_rerror @276
+ ap_month_snames @277
+ ap_null_cleanup @278
+ ap_psprintf @279
+ ap_pstrcat @280
+ ap_restart_time @281
+ ap_rprintf @282
+ ap_rvputs @283
+ ap_scoreboard_image @284
+ ap_send_header_field @285
+ ap_server_argv0 @286
+ ap_server_root @287
+ ap_set_file_slot @288
+ ap_set_flag_slot @289
+ ap_set_string_slot @290
+ ap_set_string_slot_lower @291
+ ap_snprintf @292
+ ap_suexec_enabled @293
+ ap_table_do @294
+ ap_main @295
+; asis_module @296
+; auth_module @297
+; autoindex_module @298
+; cgi_module @299
+; config_log_module @300
+ core_module @301
+; dir_module @302
+; env_module @303
+; imap_module @304
+; includes_module @305
+; mime_module @306
+; negotiation_module @307
+; os_spawnle @308
+; setenvif_module @309
+ so_module @310
+ top_module @311
+ ap_fnmatch @312
+ ap_method_number_of @313
+ ap_exists_config_define @314
+ ap_single_module_configure @315
+ ap_make_etag @317
+ ap_array_pstrcat @318
+; ap_os_is_filename_valid @319
+ ap_find_list_item @320
+ ap_MD5Encode @321
+ ap_validate_password @322
+ ap_size_list_item @323
+ ap_get_list_item @324
+ ap_scoreboard_fname @325
+ ap_pid_fname @326
+ ap_excess_requests_per_child @327
+ ap_threads_per_child @328
+ ap_max_requests_per_child @329
+ ap_daemons_to_start @330
+ ap_daemons_min_free @331
+ ap_daemons_max_free @332
+ ap_daemons_limit @333
+ ap_user_name @334
+ ap_user_id @335
+ ap_group_id @336
+ ap_standalone @337
+ ap_server_confname @338
+ ap_sub_req_method_uri @339
+ strcasecmp @340
+ strncasecmp @341
+ ap_my_generation @342
+ ap_dummy_mutex @343
+ ap_signal @344
+ ap_regerror @345
+ ap_regexec @346
+ ap_field_noparam @347
+ ap_pbase64decode @348
+ ap_pbase64encode @349
+ ap_base64encode @350
+ ap_base64encode_binary @351
+ ap_base64encode_len @352
+ ap_base64decode @353
+ ap_base64decode_binary @354
+ ap_base64decode_len @355
+ ap_SHA1Init @356
+ ap_SHA1Update_binary @357
+ ap_SHA1Update @358
+ ap_SHA1Final @359
+ ap_sha1_base64 @360
diff --git a/usr.sbin/httpd/src/ap/ap_base64.c b/usr.sbin/httpd/src/ap/ap_base64.c
new file mode 100644
index 00000000000..89cda4b5c26
--- /dev/null
+++ b/usr.sbin/httpd/src/ap/ap_base64.c
@@ -0,0 +1,272 @@
+/* ====================================================================
+ * Copyright (c) 1995-1999 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. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * 6. 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/>.
+ *
+ */
+
+/* base64 encoder/decoder. Originally part of main/util.c
+ * but moved here so that support/ab and ap_sha1.c could
+ * use it. This meant removing the ap_palloc()s and adding
+ * ugly 'len' functions, which is quite a nasty cost.
+ */
+
+#include <string.h>
+
+#include "ap_config.h"
+#include "ap.h"
+
+#ifdef CHARSET_EBCDIC
+#include "ebcdic.h"
+#endif /* CHARSET_EBCDIC */
+
+/* aaaack but it's fast and const should make it shared text page. */
+static const unsigned char pr2six[256] =
+{
+#ifndef CHARSET_EBCDIC
+ /* ASCII table */
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 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
+#else /*CHARSET_EBCDIC*/
+ /* EBCDIC table */
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 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, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 64, 64, 64, 64, 64, 64,
+ 64, 35, 36, 37, 38, 39, 40, 41, 42, 43, 64, 64, 64, 64, 64, 64,
+ 64, 64, 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, 0, 1, 2, 3, 4, 5, 6, 7, 8, 64, 64, 64, 64, 64, 64,
+ 64, 9, 10, 11, 12, 13, 14, 15, 16, 17, 64, 64, 64, 64, 64, 64,
+ 64, 64, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64
+#endif /*CHARSET_EBCDIC*/
+};
+
+API_EXPORT(int) ap_base64decode_len(const char *bufcoded)
+{
+ int nbytesdecoded;
+ register const unsigned char *bufin;
+ register int nprbytes;
+
+ bufin = (const unsigned char *) bufcoded;
+ while (pr2six[*(bufin++)] <= 63);
+
+ nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
+ nbytesdecoded = ((nprbytes + 3) / 4) * 3;
+
+ return nbytesdecoded + 1;
+}
+
+API_EXPORT(int) ap_base64decode(char *bufplain, const char *bufcoded)
+{
+#ifdef CHARSET_EBCDIC
+ int i;
+#endif /* CHARSET_EBCDIC */
+ int len;
+
+ len = ap_base64decode_binary((unsigned char *) bufplain, bufcoded);
+#ifdef CHARSET_EBCDIC
+ for (i = 0; i < len; i++)
+ bufplain[i] = os_toebcdic[bufplain[i]];
+#endif /* CHARSET_EBCDIC */
+ return len;
+}
+
+/* This is the same as ap_base64udecode() except on EBCDIC machines, where
+ * the conversion of the output to ebcdic is left out.
+ */
+API_EXPORT(int) ap_base64decode_binary(unsigned char *bufplain,
+ const char *bufcoded)
+{
+ int nbytesdecoded;
+ register const unsigned char *bufin;
+ register unsigned char *bufout;
+ register int nprbytes;
+
+ bufin = (const unsigned char *) bufcoded;
+ while (pr2six[*(bufin++)] <= 63);
+ nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
+ nbytesdecoded = ((nprbytes + 3) / 4) * 3;
+
+ bufout = (unsigned char *) bufplain;
+ bufin = (const unsigned char *) bufcoded;
+
+ while (nprbytes > 4) {
+ *(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;
+ }
+
+ /* Note: (nprbytes == 1) would be an error, so just ingore that case */
+ if (nprbytes > 1) {
+ *(bufout++) =
+ (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
+ }
+ if (nprbytes > 2) {
+ *(bufout++) =
+ (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
+ }
+ if (nprbytes > 3) {
+ *(bufout++) =
+ (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
+ }
+
+ *(bufout++) = '\0';
+ nbytesdecoded -= (4 - nprbytes) & 3;
+ return nbytesdecoded;
+}
+
+static const char basis_64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+API_EXPORT(int) ap_base64encode_len(int len)
+{
+ return ((len + 2) / 3 * 4) + 1;
+}
+
+API_EXPORT(int) ap_base64encode(char *encoded, const char *string, int len)
+{
+#ifndef CHARSET_EBCDIC
+ return ap_base64encode_binary(encoded, (const unsigned char *) string, len);
+#else /* CHARSET_EBCDIC */
+ int i;
+ char *p;
+
+ p = encoded;
+ for (i = 0; i < len - 2; i += 3) {
+ *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F];
+ *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) |
+ ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)];
+ *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2) |
+ ((int) (os_toascii[string[i + 2]] & 0xC0) >> 6)];
+ *p++ = basis_64[os_toascii[string[i + 2]] & 0x3F];
+ }
+ if (i < len) {
+ *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F];
+ if (i == (len - 1)) {
+ *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4)];
+ *p++ = '=';
+ }
+ else {
+ *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) |
+ ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)];
+ *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2)];
+ }
+ *p++ = '=';
+ }
+
+ *p++ = '\0';
+ return p - encoded;
+#endif /* CHARSET_EBCDIC */
+}
+
+/* This is the same as ap_base64encode() except on EBCDIC machines, where
+ * the conversion of the input to ascii is left out.
+ */
+API_EXPORT(int) ap_base64encode_binary(char *encoded,
+ const unsigned char *string, int len)
+{
+ int i;
+ char *p;
+
+ p = encoded;
+ for (i = 0; i < len - 2; i += 3) {
+ *p++ = basis_64[(string[i] >> 2) & 0x3F];
+ *p++ = basis_64[((string[i] & 0x3) << 4) |
+ ((int) (string[i + 1] & 0xF0) >> 4)];
+ *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
+ ((int) (string[i + 2] & 0xC0) >> 6)];
+ *p++ = basis_64[string[i + 2] & 0x3F];
+ }
+ if (i < len) {
+ *p++ = basis_64[(string[i] >> 2) & 0x3F];
+ if (i == (len - 1)) {
+ *p++ = basis_64[((string[i] & 0x3) << 4)];
+ *p++ = '=';
+ }
+ else {
+ *p++ = basis_64[((string[i] & 0x3) << 4) |
+ ((int) (string[i + 1] & 0xF0) >> 4)];
+ *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
+ }
+ *p++ = '=';
+ }
+
+ *p++ = '\0';
+ return p - encoded;
+}
diff --git a/usr.sbin/httpd/src/ap/ap_checkpass.c b/usr.sbin/httpd/src/ap/ap_checkpass.c
new file mode 100644
index 00000000000..63258c9e275
--- /dev/null
+++ b/usr.sbin/httpd/src/ap/ap_checkpass.c
@@ -0,0 +1,111 @@
+/* ====================================================================
+ * Copyright (c) 1996-1999 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. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * 6. 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/>.
+ *
+ * Simple password verify, which 'know's about various password
+ * types, such as the simple base64 encoded crypt()s, MD5 $ marked
+ * FreeBSD style and netscape SHA1's.
+ */
+#include <string.h>
+
+#include "ap_config.h"
+#include "ap_md5.h"
+#include "ap_sha1.h"
+#include "ap.h"
+#if HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+/*
+ * Validate a plaintext password against a smashed one. Use either
+ * crypt() (if available), ap_MD5Encode() or ap_SHA1Encode depending
+ * upon the format of the smashed input password.
+ *
+ * Return NULL if they match, or an explanatory text string if they don't.
+ */
+
+API_EXPORT(char *) ap_validate_password(const char *passwd, const char *hash)
+{
+ char sample[120];
+
+
+ /* FreeBSD style MD5 string
+ */
+ if (strncmp(hash, AP_MD5PW_ID, AP_MD5PW_IDLEN) == 0) {
+
+ ap_MD5Encode((const unsigned char *)passwd,
+ (const unsigned char *)hash, sample, sizeof(sample));
+ }
+ /* Netscape / SHA1 ldap style strng
+ */
+ else if (strncmp(hash, AP_SHA1PW_ID, AP_SHA1PW_IDLEN) == 0) {
+
+ ap_sha1_base64(passwd, strlen(passwd), sample);
+ }
+ else {
+ /*
+ * It's not our algorithm, so feed it to crypt() if possible.
+ */
+#if defined(WIN32) || defined(TPF)
+ /*
+ * On Windows, the only alternative to our MD5 algorithm is plain
+ * text.
+ */
+ ap_cpystrn(sample, passwd, sizeof(sample) - 1);
+#else
+ ap_cpystrn(sample, (char *)crypt(passwd, hash), sizeof(sample) - 1);
+#endif
+ }
+ return (strcmp(sample, hash) == 0) ? NULL : "password mismatch";
+}
diff --git a/usr.sbin/httpd/src/ap/ap_getpass.c b/usr.sbin/httpd/src/ap/ap_getpass.c
new file mode 100644
index 00000000000..80988d16fdd
--- /dev/null
+++ b/usr.sbin/httpd/src/ap/ap_getpass.c
@@ -0,0 +1,167 @@
+/* ====================================================================
+ * Copyright (c) 1995-1999 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. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * 6. 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/>.
+ *
+ */
+/*
+ * ap_getpass.c: abstraction to provide for obtaining a password from the
+ * command line in whatever way the OS supports. In the best case, it's a
+ * wrapper for the system library's getpass() routine; otherwise, we
+ * use one we define ourselves.
+ */
+
+#include "ap_config.h"
+#include <sys/types.h>
+#include <errno.h>
+#include "ap.h"
+
+#ifdef WIN32
+#include <conio.h>
+#endif
+
+#ifndef CHARSET_EBCDIC
+#define LF 10
+#define CR 13
+#else /* CHARSET_EBCDIC */
+#define LF '\n'
+#define CR '\r'
+#endif /* CHARSET_EBCDIC */
+
+#define MAX_STRING_LEN 256
+
+#define ERR_OVERFLOW 5
+
+#ifdef MPE
+/*
+ * MPE lacks getpass() and a way to suppress stdin echo. So for now, just
+ * issue the prompt and read the results with echo. (Ugh).
+ */
+
+static char *getpass(const char *prompt)
+{
+ static char password[MAX_STRING_LEN];
+
+ fputs(prompt, stderr);
+ gets((char *) &password);
+
+ if (strlen((char *) &password) > (MAX_STRING_LEN - 1)) {
+ password[MAX_STRING_LEN - 1] = '\0';
+ }
+
+ return (char *) &password;
+}
+
+#endif
+
+#ifdef WIN32
+/*
+ * Windows lacks getpass(). So we'll re-implement it here.
+ */
+
+static char *getpass(const char *prompt)
+{
+ static char password[MAX_STRING_LEN];
+ int n = 0;
+
+ fputs(prompt, stderr);
+
+ while ((password[n] = _getch()) != '\r') {
+ if (password[n] >= ' ' && password[n] <= '~') {
+ n++;
+ printf("*");
+ }
+ else {
+ printf("\n");
+ fputs(prompt, stderr);
+ n = 0;
+ }
+ }
+
+ password[n] = '\0';
+ printf("\n");
+
+ if (n > (MAX_STRING_LEN - 1)) {
+ password[MAX_STRING_LEN - 1] = '\0';
+ }
+
+ return (char *) &password;
+}
+#endif
+
+/*
+ * Use the OS getpass() routine (or our own) to obtain a password from
+ * the input stream.
+ *
+ * Exit values:
+ * 0: Success
+ * 5: Partial success; entered text truncated to the size of the
+ * destination buffer
+ *
+ * Restrictions: Truncation also occurs according to the host system's
+ * getpass() semantics, or at position 255 if our own version is used,
+ * but the caller is *not* made aware of it.
+ */
+
+API_EXPORT(int) ap_getpass(const char *prompt, char *pwbuf, size_t bufsiz)
+{
+ char *pw_got;
+ int result = 0;
+
+ pw_got = getpass(prompt);
+ if (strlen(pw_got) > (bufsiz - 1)) {
+ result = ERR_OVERFLOW;
+ }
+ ap_cpystrn(pwbuf, pw_got, bufsiz);
+ return result;
+}
diff --git a/usr.sbin/httpd/src/ap/ap_md5c.c b/usr.sbin/httpd/src/ap/ap_md5c.c
new file mode 100644
index 00000000000..7a8aee5965d
--- /dev/null
+++ b/usr.sbin/httpd/src/ap/ap_md5c.c
@@ -0,0 +1,583 @@
+/*
+ * 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-1999 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. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * 6. 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 ap_MD5Encode() routine uses much code obtained from the FreeBSD 3.0
+ * MD5 crypt() function, which is licenced as follows:
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <string.h>
+
+#include "ap_config.h"
+#include "ap_md5.h"
+#include "ap.h"
+#ifdef CHARSET_EBCDIC
+#include "ebcdic.h"
+#endif /*CHARSET_EBCDIC*/
+#if HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+/* 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.
+ */
+API_EXPORT(void) ap_MD5Init(AP_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.
+ */
+API_EXPORT(void) ap_MD5Update(AP_MD5_CTX *context, const unsigned char *input,
+ unsigned int inputLen)
+{
+ unsigned int i, idx, partLen;
+
+ /* Compute number of bytes mod 64 */
+ idx = (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 - idx;
+
+ /* Transform as many times as possible. */
+#ifndef CHARSET_EBCDIC
+ if (inputLen >= partLen) {
+ memcpy(&context->buffer[idx], input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64) {
+ MD5Transform(context->state, &input[i]);
+ }
+
+ idx = 0;
+ }
+ else {
+ i = 0;
+ }
+
+ /* Buffer remaining input */
+ memcpy(&context->buffer[idx], &input[i], inputLen - i);
+#else /*CHARSET_EBCDIC*/
+ if (inputLen >= partLen) {
+ ebcdic2ascii_strictly(&context->buffer[idx], input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64) {
+ unsigned char inp_tmp[64];
+ ebcdic2ascii_strictly(inp_tmp, &input[i], 64);
+ MD5Transform(context->state, inp_tmp);
+ }
+
+ idx = 0;
+ }
+ else {
+ i = 0;
+ }
+
+ /* Buffer remaining input */
+ ebcdic2ascii_strictly(&context->buffer[idx], &input[i], inputLen - i);
+#endif /*CHARSET_EBCDIC*/
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+API_EXPORT(void) ap_MD5Final(unsigned char digest[16], AP_MD5_CTX *context)
+{
+ unsigned char bits[8];
+ unsigned int idx, padLen;
+
+
+ /* Save number of bits */
+ Encode(bits, context->count, 8);
+
+#ifdef CHARSET_EBCDIC
+ /* XXX: @@@: In order to make this no more complex than necessary,
+ * this kludge converts the bits[] array using the ascii-to-ebcdic
+ * table, because the following ap_MD5Update() re-translates
+ * its input (ebcdic-to-ascii).
+ * Otherwise, we would have to pass a "conversion" flag to ap_MD5Update()
+ */
+ ascii2ebcdic(bits,bits,8);
+
+ /* Since everything is converted to ascii within ap_MD5Update(),
+ * the initial 0x80 (PADDING[0]) must be stored as 0x20
+ */
+ PADDING[0] = os_toebcdic[0x80];
+#endif /*CHARSET_EBCDIC*/
+
+ /* Pad out to 56 mod 64. */
+ idx = (unsigned int) ((context->count[0] >> 3) & 0x3f);
+ padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+ ap_MD5Update(context, (const unsigned char *)PADDING, padLen);
+
+ /* Append length (before padding) */
+ ap_MD5Update(context, (const unsigned char *)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);
+}
+
+/*
+ * The following MD5 password encryption code was largely borrowed from
+ * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
+ * licenced as stated at the top of this file.
+ */
+API_EXPORT(void) ap_to64(char *s, unsigned long v, int n)
+{
+ static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+API_EXPORT(void) ap_MD5Encode(const unsigned char *pw,
+ const unsigned char *salt,
+ char *result, size_t nbytes)
+{
+ /*
+ * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
+ * plus 4 for the '$' separators, plus the password hash itself.
+ * Let's leave a goodly amount of leeway.
+ */
+
+ char passwd[120], *p;
+ const unsigned char *sp, *ep;
+ unsigned char final[16];
+ int i;
+ unsigned int sl;
+ int pl;
+ unsigned int pwlen;
+ AP_MD5_CTX ctx, ctx1;
+ unsigned long l;
+
+ /*
+ * Refine the salt first. It's possible we were given an already-hashed
+ * string as the salt argument, so extract the actual salt value from it
+ * if so. Otherwise just use the string up to the first '$' as the salt.
+ */
+ sp = salt;
+
+ /*
+ * If it starts with the magic string, then skip that.
+ */
+ if (strncmp((char *)sp, AP_MD5PW_ID, AP_MD5PW_IDLEN) == 0) {
+ sp += AP_MD5PW_IDLEN;
+ }
+
+ /*
+ * It stops at the first '$' or 8 chars, whichever comes first
+ */
+ for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) {
+ continue;
+ }
+
+ /*
+ * Get the length of the true salt
+ */
+ sl = ep - sp;
+
+ /*
+ * 'Time to make the doughnuts..'
+ */
+ ap_MD5Init(&ctx);
+
+ pwlen = strlen((char *)pw);
+ /*
+ * The password first, since that is what is most unknown
+ */
+ ap_MD5Update(&ctx, pw, pwlen);
+
+ /*
+ * Then our magic string
+ */
+ ap_MD5Update(&ctx, (const unsigned char *) AP_MD5PW_ID, AP_MD5PW_IDLEN);
+
+ /*
+ * Then the raw salt
+ */
+ ap_MD5Update(&ctx, sp, sl);
+
+ /*
+ * Then just as many characters of the MD5(pw, salt, pw)
+ */
+ ap_MD5Init(&ctx1);
+ ap_MD5Update(&ctx1, pw, pwlen);
+ ap_MD5Update(&ctx1, sp, sl);
+ ap_MD5Update(&ctx1, pw, pwlen);
+ ap_MD5Final(final, &ctx1);
+ for(pl = pwlen; pl > 0; pl -= 16) {
+ ap_MD5Update(&ctx, final, (pl > 16) ? 16 : (unsigned int) pl);
+ }
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ memset(final, 0, sizeof(final));
+
+ /*
+ * Then something really weird...
+ */
+ for (i = pwlen; i != 0; i >>= 1) {
+ if (i & 1) {
+ ap_MD5Update(&ctx, final, 1);
+ }
+ else {
+ ap_MD5Update(&ctx, pw, 1);
+ }
+ }
+
+ /*
+ * Now make the output string. We know our limitations, so we
+ * can use the string routines without bounds checking.
+ */
+ ap_cpystrn(passwd, AP_MD5PW_ID, AP_MD5PW_IDLEN + 1);
+ ap_cpystrn(passwd + AP_MD5PW_IDLEN, (char *)sp, sl + 1);
+ passwd[AP_MD5PW_IDLEN + sl] = '$';
+ passwd[AP_MD5PW_IDLEN + sl + 1] = '\0';
+
+ ap_MD5Final(final, &ctx);
+
+ /*
+ * And now, just to make sure things don't run too fast..
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for (i = 0; i < 1000; i++) {
+ ap_MD5Init(&ctx1);
+ if (i & 1) {
+ ap_MD5Update(&ctx1, pw, pwlen);
+ }
+ else {
+ ap_MD5Update(&ctx1, final, 16);
+ }
+ if (i % 3) {
+ ap_MD5Update(&ctx1, sp, sl);
+ }
+
+ if (i % 7) {
+ ap_MD5Update(&ctx1, pw, pwlen);
+ }
+
+ if (i & 1) {
+ ap_MD5Update(&ctx1, final, 16);
+ }
+ else {
+ ap_MD5Update(&ctx1, pw, pwlen);
+ }
+ ap_MD5Final(final,&ctx1);
+ }
+
+ p = passwd + strlen(passwd);
+
+ l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; ap_to64(p, l, 4); p += 4;
+ l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; ap_to64(p, l, 4); p += 4;
+ l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; ap_to64(p, l, 4); p += 4;
+ l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; ap_to64(p, l, 4); p += 4;
+ l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; ap_to64(p, l, 4); p += 4;
+ l = final[11] ; ap_to64(p, l, 2); p += 2;
+ *p = '\0';
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ memset(final, 0, sizeof(final));
+
+ ap_cpystrn(result, passwd, nbytes - 1);
+}
diff --git a/usr.sbin/httpd/src/ap/ap_sha1.c b/usr.sbin/httpd/src/ap/ap_sha1.c
new file mode 100644
index 00000000000..1d4d9ea49b6
--- /dev/null
+++ b/usr.sbin/httpd/src/ap/ap_sha1.c
@@ -0,0 +1,383 @@
+/* ====================================================================
+ * Copyright (c) 1996-1999 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. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * 6. 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 exported function:
+ *
+ * ap_sha1_base64(const char *clear, int len, char *out);
+ *
+ * provides a means to SHA1 crypt/encode a plaintext password in
+ * a way which makes password files compatible with those commonly
+ * used in netscape web and ldap installations. It was put together
+ * by Clinton Wong <clintdw@netcom.com>, who also notes that:
+ *
+ * Note: SHA1 support is useful for migration purposes, but is less
+ * secure than Apache's password format, since Apache's (MD5)
+ * password format uses a random eight character salt to generate
+ * one of many possible hashes for the same password. Netscape
+ * uses plain SHA1 without a salt, so the same password
+ * will always generate the same hash, making it easier
+ * to break since the search space is smaller.
+ *
+ * See also the documentation in support/SHA1 as to hints on how to
+ * migrate an existing netscape installation and other supplied utitlites.
+ *
+ * This software also makes use of the following component:
+ *
+ * NIST Secure Hash Algorithm
+ * heavily modified by Uwe Hollerbach uh@alumni.caltech edu
+ * from Peter C. Gutmann's implementation as found in
+ * Applied Cryptography by Bruce Schneier
+ * This code is hereby placed in the public domain
+ */
+
+#include <string.h>
+
+#include "ap_config.h"
+#include "ap_sha1.h"
+#include "ap.h"
+#ifdef CHARSET_EBCDIC
+#include "ebcdic.h"
+#endif /*CHARSET_EBCDIC*/
+
+/* a bit faster & bigger, if defined */
+#define UNROLL_LOOPS
+
+/* NIST's proposed modification to SHA, 7/11/94 */
+#define USE_MODIFIED_SHA
+
+/* SHA f()-functions */
+#define f1(x,y,z) ((x & y) | (~x & z))
+#define f2(x,y,z) (x ^ y ^ z)
+#define f3(x,y,z) ((x & y) | (x & z) | (y & z))
+#define f4(x,y,z) (x ^ y ^ z)
+
+/* SHA constants */
+#define CONST1 0x5a827999L
+#define CONST2 0x6ed9eba1L
+#define CONST3 0x8f1bbcdcL
+#define CONST4 0xca62c1d6L
+
+/* 32-bit rotate */
+
+#define ROT32(x,n) ((x << n) | (x >> (32 - n)))
+
+#define FUNC(n,i) \
+ temp = ROT32(A,5) + f##n(B,C,D) + E + W[i] + CONST##n; \
+ E = D; D = C; C = ROT32(B,30); B = A; A = temp
+
+#define SHA_BLOCKSIZE 64
+
+typedef unsigned char AP_BYTE;
+
+/* do SHA transformation */
+static void sha_transform(AP_SHA1_CTX *sha_info)
+{
+ int i;
+ AP_LONG temp, A, B, C, D, E, W[80];
+
+ for (i = 0; i < 16; ++i) {
+ W[i] = sha_info->data[i];
+ }
+ for (i = 16; i < 80; ++i) {
+ W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16];
+#ifdef USE_MODIFIED_SHA
+ W[i] = ROT32(W[i], 1);
+#endif /* USE_MODIFIED_SHA */
+ }
+ A = sha_info->digest[0];
+ B = sha_info->digest[1];
+ C = sha_info->digest[2];
+ D = sha_info->digest[3];
+ E = sha_info->digest[4];
+#ifdef UNROLL_LOOPS
+ FUNC(1, 0); FUNC(1, 1); FUNC(1, 2); FUNC(1, 3); FUNC(1, 4);
+ FUNC(1, 5); FUNC(1, 6); FUNC(1, 7); FUNC(1, 8); FUNC(1, 9);
+ FUNC(1,10); FUNC(1,11); FUNC(1,12); FUNC(1,13); FUNC(1,14);
+ FUNC(1,15); FUNC(1,16); FUNC(1,17); FUNC(1,18); FUNC(1,19);
+
+ FUNC(2,20); FUNC(2,21); FUNC(2,22); FUNC(2,23); FUNC(2,24);
+ FUNC(2,25); FUNC(2,26); FUNC(2,27); FUNC(2,28); FUNC(2,29);
+ FUNC(2,30); FUNC(2,31); FUNC(2,32); FUNC(2,33); FUNC(2,34);
+ FUNC(2,35); FUNC(2,36); FUNC(2,37); FUNC(2,38); FUNC(2,39);
+
+ FUNC(3,40); FUNC(3,41); FUNC(3,42); FUNC(3,43); FUNC(3,44);
+ FUNC(3,45); FUNC(3,46); FUNC(3,47); FUNC(3,48); FUNC(3,49);
+ FUNC(3,50); FUNC(3,51); FUNC(3,52); FUNC(3,53); FUNC(3,54);
+ FUNC(3,55); FUNC(3,56); FUNC(3,57); FUNC(3,58); FUNC(3,59);
+
+ FUNC(4,60); FUNC(4,61); FUNC(4,62); FUNC(4,63); FUNC(4,64);
+ FUNC(4,65); FUNC(4,66); FUNC(4,67); FUNC(4,68); FUNC(4,69);
+ FUNC(4,70); FUNC(4,71); FUNC(4,72); FUNC(4,73); FUNC(4,74);
+ FUNC(4,75); FUNC(4,76); FUNC(4,77); FUNC(4,78); FUNC(4,79);
+#else /* !UNROLL_LOOPS */
+ for (i = 0; i < 20; ++i) {
+ FUNC(1,i);
+ }
+ for (i = 20; i < 40; ++i) {
+ FUNC(2,i);
+ }
+ for (i = 40; i < 60; ++i) {
+ FUNC(3,i);
+ }
+ for (i = 60; i < 80; ++i) {
+ FUNC(4,i);
+ }
+#endif /* !UNROLL_LOOPS */
+ sha_info->digest[0] += A;
+ sha_info->digest[1] += B;
+ sha_info->digest[2] += C;
+ sha_info->digest[3] += D;
+ sha_info->digest[4] += E;
+}
+
+union endianTest {
+ long Long;
+ char Char[sizeof(long)];
+};
+
+static char isLittleEndian(void)
+{
+ static union endianTest u;
+ u.Long = 1;
+ return (u.Char[0] == 1);
+}
+
+/* change endianness of data */
+
+/* count is the number of bytes to do an endian flip */
+static void maybe_byte_reverse(AP_LONG *buffer, int count)
+{
+ int i;
+ AP_BYTE ct[4], *cp;
+
+ if (isLittleEndian()) { /* do the swap only if it is little endian */
+ count /= sizeof(AP_LONG);
+ cp = (AP_BYTE *) buffer;
+ for (i = 0; i < count; ++i) {
+ ct[0] = cp[0];
+ ct[1] = cp[1];
+ ct[2] = cp[2];
+ ct[3] = cp[3];
+ cp[0] = ct[3];
+ cp[1] = ct[2];
+ cp[2] = ct[1];
+ cp[3] = ct[0];
+ cp += sizeof(AP_LONG);
+ }
+ }
+}
+
+/* initialize the SHA digest */
+
+API_EXPORT(void) ap_SHA1Init(AP_SHA1_CTX *sha_info)
+{
+ sha_info->digest[0] = 0x67452301L;
+ sha_info->digest[1] = 0xefcdab89L;
+ sha_info->digest[2] = 0x98badcfeL;
+ sha_info->digest[3] = 0x10325476L;
+ sha_info->digest[4] = 0xc3d2e1f0L;
+ sha_info->count_lo = 0L;
+ sha_info->count_hi = 0L;
+ sha_info->local = 0;
+}
+
+/* update the SHA digest */
+
+API_EXPORT(void) ap_SHA1Update_binary(AP_SHA1_CTX *sha_info,
+ const unsigned char *buffer,
+ unsigned int count)
+{
+ unsigned int i;
+
+ if ((sha_info->count_lo + ((AP_LONG) count << 3)) < sha_info->count_lo) {
+ ++sha_info->count_hi;
+ }
+ sha_info->count_lo += (AP_LONG) count << 3;
+ sha_info->count_hi += (AP_LONG) count >> 29;
+ if (sha_info->local) {
+ i = SHA_BLOCKSIZE - sha_info->local;
+ if (i > count) {
+ i = count;
+ }
+ memcpy(((AP_BYTE *) sha_info->data) + sha_info->local, buffer, i);
+ count -= i;
+ buffer += i;
+ sha_info->local += i;
+ if (sha_info->local == SHA_BLOCKSIZE) {
+ maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE);
+ sha_transform(sha_info);
+ }
+ else {
+ return;
+ }
+ }
+ while (count >= SHA_BLOCKSIZE) {
+ memcpy(sha_info->data, buffer, SHA_BLOCKSIZE);
+ buffer += SHA_BLOCKSIZE;
+ count -= SHA_BLOCKSIZE;
+ maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE);
+ sha_transform(sha_info);
+ }
+ memcpy(sha_info->data, buffer, count);
+ sha_info->local = count;
+}
+
+API_EXPORT(void) ap_SHA1Update(AP_SHA1_CTX *sha_info, const char *buf,
+ unsigned int count)
+{
+#ifdef CHARSET_EBCDIC
+ int i;
+ const AP_BYTE *buffer = (const AP_BYTE *) buf;
+
+ if ((sha_info->count_lo + ((AP_LONG) count << 3)) < sha_info->count_lo) {
+ ++sha_info->count_hi;
+ }
+ sha_info->count_lo += (AP_LONG) count << 3;
+ sha_info->count_hi += (AP_LONG) count >> 29;
+ /* Is there a remainder of the previous Update operation? */
+ if (sha_info->local) {
+ i = SHA_BLOCKSIZE - sha_info->local;
+ if (i > count) {
+ i = count;
+ }
+ ebcdic2ascii_strictly(((AP_BYTE *) sha_info->data) + sha_info->local,
+ buffer, i);
+ count -= i;
+ buffer += i;
+ sha_info->local += i;
+ if (sha_info->local == SHA_BLOCKSIZE) {
+ maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE);
+ sha_transform(sha_info);
+ }
+ else {
+ return;
+ }
+ }
+ while (count >= SHA_BLOCKSIZE) {
+ ebcdic2ascii_strictly((AP_BYTE *)sha_info->data, buffer, SHA_BLOCKSIZE);
+ buffer += SHA_BLOCKSIZE;
+ count -= SHA_BLOCKSIZE;
+ maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE);
+ sha_transform(sha_info);
+ }
+ ebcdic2ascii_strictly((AP_BYTE *)sha_info->data, buffer, count);
+ sha_info->local = count;
+#else
+ ap_SHA1Update_binary(sha_info, (const unsigned char *) buf, count);
+#endif
+}
+
+/* finish computing the SHA digest */
+
+API_EXPORT(void) ap_SHA1Final(unsigned char digest[SHA_DIGESTSIZE],
+ AP_SHA1_CTX *sha_info)
+{
+ int count, i, j;
+ AP_LONG lo_bit_count, hi_bit_count, k;
+
+ lo_bit_count = sha_info->count_lo;
+ hi_bit_count = sha_info->count_hi;
+ count = (int) ((lo_bit_count >> 3) & 0x3f);
+ ((AP_BYTE *) sha_info->data)[count++] = 0x80;
+ if (count > SHA_BLOCKSIZE - 8) {
+ memset(((AP_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count);
+ maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE);
+ sha_transform(sha_info);
+ memset((AP_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8);
+ }
+ else {
+ memset(((AP_BYTE *) sha_info->data) + count, 0,
+ SHA_BLOCKSIZE - 8 - count);
+ }
+ maybe_byte_reverse(sha_info->data, SHA_BLOCKSIZE);
+ sha_info->data[14] = hi_bit_count;
+ sha_info->data[15] = lo_bit_count;
+ sha_transform(sha_info);
+
+ for (i = 0, j = 0; j < SHA_DIGESTSIZE; i++) {
+ k = sha_info->digest[i];
+ digest[j++] = (unsigned char) ((k >> 24) & 0xff);
+ digest[j++] = (unsigned char) ((k >> 16) & 0xff);
+ digest[j++] = (unsigned char) ((k >> 8) & 0xff);
+ digest[j++] = (unsigned char) (k & 0xff);
+ }
+}
+
+
+API_EXPORT(void) ap_sha1_base64(const char *clear, int len, char *out)
+{
+ int l;
+ AP_SHA1_CTX context;
+ AP_BYTE digest[SHA_DIGESTSIZE];
+
+ if (strncmp(clear, AP_SHA1PW_ID, AP_SHA1PW_IDLEN) == 0) {
+ clear += AP_SHA1PW_IDLEN;
+ }
+
+ ap_SHA1Init(&context);
+ ap_SHA1Update(&context, clear, len);
+ ap_SHA1Final(digest, &context);
+
+ /* private marker. */
+ ap_cpystrn(out, AP_SHA1PW_ID, AP_SHA1PW_IDLEN + 1);
+
+ /* SHA1 hash is always 20 chars */
+ l = ap_base64encode_binary(out + AP_SHA1PW_IDLEN, digest, sizeof(digest));
+ out[l + AP_SHA1PW_IDLEN] = '\0';
+
+ /*
+ * output of base64 encoded SHA1 is always 28 chars + AP_SHA1PW_IDLEN
+ */
+}
diff --git a/usr.sbin/httpd/src/helpers/getuid.sh b/usr.sbin/httpd/src/helpers/getuid.sh
new file mode 100644
index 00000000000..42cdf0d6e5d
--- /dev/null
+++ b/usr.sbin/httpd/src/helpers/getuid.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Return the uid of the process being run. If we cannot
+# determine what it is, return '?'.
+#
+# Initially written by Jim Jagielski for the Apache configuration mechanism
+#
+# This script falls under the Apache License.
+# See http://www.apache.org/docs/LICENSE
+
+# First we try 'id'
+if `./src/helpers/PrintPath -s id` ; then
+ AP_IDPATH=`./src/helpers/PrintPath id`
+ # See if it's a POSIX 'id'
+ if `$AP_IDPATH -u >/dev/null 2>&1` ; then
+ AP_RETVAL=`$AP_IDPATH -u`
+ echo $AP_RETVAL
+ exit 0
+ else
+ AP_RETVAL=`$AP_IDPATH | \
+ sed -e 's/^.*uid[ ]*=[ ]*[^0123456789]*//' | \
+ sed -e 's/[ ]*(.*$//'`
+ echo $AP_RETVAL
+ exit 0
+ fi
+fi
+
+#
+# Ugg. Now we have to grab the login name of the process, and
+# scan /etc/passwd.
+#
+# Try 'whoami' first, then 'who am i' (making sure to strip away
+# the who crud) and finally just copy $LOGNAME
+#
+if `./src/helpers/PrintPath -s whoami` ; then
+ AP_WAIPATH=`./src/helpers/PrintPath whoami`
+ AP_LOGNAME=`$AP_WAIPATH`
+else
+ AP_LOGNAME=`who am i | tail -1 | sed -e 's/[ ][ ]*.*$//'`
+fi
+
+#
+# See if we have a valid login name.
+#
+if [ "x$AP_LOGNAME" = "x" ]; then
+ AP_LOGNAME=$LOGNAME
+ if [ "x$AP_LOGNAME" = "x" ]; then
+ echo "?"
+ exit 1
+ fi
+fi
+
+#
+# Ok, now we scan through /etc/passwd
+#
+AP_RETVAL=`egrep \^${AP_LOGNAME}: /etc/passwd | \
+ sed -e 's/[^:]*:[^:]*://' | \
+ sed -e 's/:.*$//'`
+
+if [ "x$AP_RETVAL" = "x" ]; then
+ echo "?"
+ exit 1
+else
+ echo $AP_RETVAL
+ exit 0
+fi
diff --git a/usr.sbin/httpd/src/include/ap_sha1.h b/usr.sbin/httpd/src/include/ap_sha1.h
new file mode 100644
index 00000000000..42a4f5788b2
--- /dev/null
+++ b/usr.sbin/httpd/src/include/ap_sha1.h
@@ -0,0 +1,102 @@
+/* ====================================================================
+ * Copyright (c) 1996-1999 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. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * 6. 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/>.
+ *
+ * NIST Secure Hash Algorithm
+ * heavily modified by Uwe Hollerbach uh@alumni.caltech edu
+ * from Peter C. Gutmann's implementation as found in
+ * Applied Cryptography by Bruce Schneier
+ * This code is hereby placed in the public domain
+ */
+
+#ifndef APACHE_SHA1_H
+#define APACHE_SHA1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SHA_DIGESTSIZE 20
+
+/*
+ * Define the Magic String prefix that identifies a password as being
+ * hashed using our algorithm.
+ */
+#define AP_SHA1PW_ID "{SHA}"
+#define AP_SHA1PW_IDLEN 5
+
+typedef unsigned long AP_LONG; /* a 32-bit quantity */
+
+typedef struct {
+ AP_LONG digest[5]; /* message digest */
+ AP_LONG count_lo, count_hi; /* 64-bit bit count */
+ AP_LONG data[16]; /* SHA data buffer */
+ int local; /* unprocessed amount in data */
+} AP_SHA1_CTX;
+
+API_EXPORT(void) ap_sha1_base64(const char *clear, int len, char *out);
+API_EXPORT(void) ap_SHA1Init(AP_SHA1_CTX *context);
+API_EXPORT(void) ap_SHA1Update(AP_SHA1_CTX *context, const char *input,
+ unsigned int inputLen);
+API_EXPORT(void) ap_SHA1Update_binary(AP_SHA1_CTX *context,
+ const unsigned char *input,
+ unsigned int inputLen);
+API_EXPORT(void) ap_SHA1Final(unsigned char digest[SHA_DIGESTSIZE],
+ AP_SHA1_CTX *context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !APACHE_SHA1_H */
diff --git a/usr.sbin/httpd/src/lib/expat-lite/CHANGES b/usr.sbin/httpd/src/lib/expat-lite/CHANGES
new file mode 100644
index 00000000000..e424068ed91
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/CHANGES
@@ -0,0 +1,41 @@
+=== PURPOSE ===
+
+This file documents the changes made by the Apache Group to James
+Clark's Expat parser. The original Expat distribution can be found at
+http://www.jclark.com/xml/expat.html.
+
+
+=== SUBSET INFORMATION ===
+
+Apache does not choose (or need) to use the entire Expat parser
+distribution. The subset that Apache will use will be referred to as
+"expat-lite". In particular, this directory contains the files from
+the following Expat distribution subdirectories:
+
+ expat/xmltok/*
+ expat/xmlparse/*
+
+We also retain expat/expat.html for attribution to James Clark and
+licensing information.
+
+In addition, we remove expat/xmltok/dllmain.c from our version since
+we statically link expat-lite into the executable (rather than
+building a DLL on the Win32 platform). The *.dsp files are also
+removed, since we place those elsewhere in the Apache source
+distribution and they will have a very different structure.
+
+Makefile.tmpl has been created from scratch to provide build
+instructions to the Apache build system.
+
+This file (CHANGES) has been added to document changes from the
+original Expat distribution.
+
+
+=== CHANGES TO ORIGINAL ===
+
+There have been no changes made to any Expat file at this point in
+time (May 31, 1999).
+
+The files, in their original state from the Expat distribution, have
+been tagged within CVS with the "EXPAT_1_1" tag. That tag may be used
+as a reference for changes made by the Apache Group.
diff --git a/usr.sbin/httpd/src/lib/expat-lite/Makefile.tmpl b/usr.sbin/httpd/src/lib/expat-lite/Makefile.tmpl
new file mode 100644
index 00000000000..646af3b9810
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/Makefile.tmpl
@@ -0,0 +1,26 @@
+#
+# default definition of these two. dunno how to get it prepended when the
+# Makefile is built, so we do it manually
+#
+CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -DAPACHE
+INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES)
+
+OBJS=xmltok.o xmlrole.o xmlparse.o hashtable.o
+
+all lib: libexpat.a
+
+libexpat.a: $(OBJS)
+ rm -f libexpat.a
+ ar cr libexpat.a $(OBJS)
+ $(RANLIB) libexpat.a
+
+clean:
+ rm -f $(OBJS) libexpat.a
+
+distclean: clean
+ -rm -f Makefile
+
+.SUFFIXES: .o
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $<
diff --git a/usr.sbin/httpd/src/lib/expat-lite/asciitab.h b/usr.sbin/httpd/src/lib/expat-lite/asciitab.h
new file mode 100644
index 00000000000..8a8a2dd388d
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/asciitab.h
@@ -0,0 +1,62 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/usr.sbin/httpd/src/lib/expat-lite/expat.html b/usr.sbin/httpd/src/lib/expat-lite/expat.html
new file mode 100644
index 00000000000..3806ca8d0e2
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/expat.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
+"http://www.w3.org/TR/REC-html40/loose.dtd">
+
+<HTML>
+
+<TITLE>expat</TITLE>
+
+<BODY>
+
+<H1>expat - XML Parser Toolkit</H1>
+
+<H3>Version 1.1</H3>
+
+<P>Copyright (c) 1998, 1999 James Clark. Expat is subject to the <A
+HREF="http://www.mozilla.org/NPL/NPL-1_1Final.html">Mozilla Public
+License Version 1.1</A>. Alternatively you may use expat under the <A
+href="http://www.gnu.org/copyleft/gpl.html">GNU General Public
+License</A> instead. Please contact me if you wish to negotiate an
+alternative license.</P>
+
+<P>Expat is an <A
+HREF="http://www.w3.org/TR/1998/REC-xml-19980210">XML 1.0</A> parser
+written in C. It aims to be fully conforming. It is currently not a
+validating XML processor. The current production version of expat can
+be downloaded from <A href = "ftp://ftp.jclark.com/pub/xml/expat.zip"
+>ftp://ftp.jclark.com/pub/xml/expat.zip</A>.</P>
+
+<P>The directory <SAMP>xmltok</SAMP> contains a low-level library for
+tokenizing XML. The interface is documented in
+<SAMP>xmltok/xmltok.h</SAMP>.</P>
+
+<P>The directory <SAMP>xmlparse</SAMP> contains an XML parser library
+which is built on top of the <SAMP>xmltok</SAMP> library. The
+interface is documented in <SAMP>xmlparse/xmlparse.h</SAMP>. The
+directory <SAMP>sample</SAMP> contains a simple example program using
+this interface; <SAMP>sample/build.bat</SAMP> is a batch file to build
+the example using Visual C++.</P>
+
+<P>The directory <SAMP>xmlwf</SAMP> contains the <SAMP>xmlwf</SAMP>
+application, which uses the <SAMP>xmlparse</SAMP> library. The
+arguments to <SAMP>xmlwf</SAMP> are one or more files which are each
+to be checked for well-formedness. An option <SAMP>-d
+<VAR>dir</VAR></SAMP> can be specified; for each well-formed input
+file the corresponding <A
+href="http://www.jclark.com/xml/canonxml.html">canonical XML</A> will
+be written to <SAMP>dir/<VAR>f</VAR></SAMP>, where
+<SAMP><VAR>f</VAR></SAMP> is the filename (without any path) of the
+input file. A <CODE>-x</CODE> option will cause references to
+external general entities to be processed. A <CODE>-s</CODE> option
+will make documents that are not standalone cause an error (a document
+is considered standalone if either it is intrinsically standalone
+because it has no external subset and no references to parameter
+entities in the internal subset or it is declared as standalone in the
+XML declaration).</P>
+
+<P>The <SAMP>bin</SAMP> directory contains Win32 executables. The
+<SAMP>lib</SAMP> directory contains Win32 import libraries.</P>
+
+<P>Answers to some frequently asked questions about expat can be found
+in the <A HREF="http://www.jclark.com/xml/expatfaq.html">expat
+FAQ</A>.</P>
+
+<P></P>
+
+<ADDRESS>
+
+<A HREF="mailto:jjc@jclark.com">James Clark</A>
+
+</ADDRESS>
+
+</BODY>
+
+</HTML>
diff --git a/usr.sbin/httpd/src/lib/expat-lite/hashtable.c b/usr.sbin/httpd/src/lib/expat-lite/hashtable.c
new file mode 100644
index 00000000000..780a0610414
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/hashtable.c
@@ -0,0 +1,151 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+csompliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+#include "xmldef.h"
+
+#ifdef XML_UNICODE_WCHAR_T
+#ifndef XML_UNICODE
+#define XML_UNICODE
+#endif
+#endif
+
+#include "hashtable.h"
+
+#define INIT_SIZE 64
+
+static
+int keyeq(KEY s1, KEY s2)
+{
+ for (; *s1 == *s2; s1++, s2++)
+ if (*s1 == 0)
+ return 1;
+ return 0;
+}
+
+static
+unsigned long hash(KEY s)
+{
+ unsigned long h = 0;
+ while (*s)
+ h = (h << 5) + h + (unsigned char)*s++;
+ return h;
+}
+
+NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize)
+{
+ size_t i;
+ if (table->size == 0) {
+ if (!createSize)
+ return 0;
+ table->v = calloc(INIT_SIZE, sizeof(NAMED *));
+ if (!table->v)
+ return 0;
+ table->size = INIT_SIZE;
+ table->usedLim = INIT_SIZE / 2;
+ i = hash(name) & (table->size - 1);
+ }
+ else {
+ unsigned long h = hash(name);
+ for (i = h & (table->size - 1);
+ table->v[i];
+ i == 0 ? i = table->size - 1 : --i) {
+ if (keyeq(name, table->v[i]->name))
+ return table->v[i];
+ }
+ if (!createSize)
+ return 0;
+ if (table->used == table->usedLim) {
+ /* check for overflow */
+ size_t newSize = table->size * 2;
+ NAMED **newV = calloc(newSize, sizeof(NAMED *));
+ if (!newV)
+ return 0;
+ for (i = 0; i < table->size; i++)
+ if (table->v[i]) {
+ size_t j;
+ for (j = hash(table->v[i]->name) & (newSize - 1);
+ newV[j];
+ j == 0 ? j = newSize - 1 : --j)
+ ;
+ newV[j] = table->v[i];
+ }
+ free(table->v);
+ table->v = newV;
+ table->size = newSize;
+ table->usedLim = newSize/2;
+ for (i = h & (table->size - 1);
+ table->v[i];
+ i == 0 ? i = table->size - 1 : --i)
+ ;
+ }
+ }
+ table->v[i] = calloc(1, createSize);
+ if (!table->v[i])
+ return 0;
+ table->v[i]->name = name;
+ (table->used)++;
+ return table->v[i];
+}
+
+void hashTableDestroy(HASH_TABLE *table)
+{
+ size_t i;
+ for (i = 0; i < table->size; i++) {
+ NAMED *p = table->v[i];
+ if (p)
+ free(p);
+ }
+ free(table->v);
+}
+
+void hashTableInit(HASH_TABLE *p)
+{
+ p->size = 0;
+ p->usedLim = 0;
+ p->used = 0;
+ p->v = 0;
+}
+
+void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table)
+{
+ iter->p = table->v;
+ iter->end = iter->p + table->size;
+}
+
+NAMED *hashTableIterNext(HASH_TABLE_ITER *iter)
+{
+ while (iter->p != iter->end) {
+ NAMED *tem = *(iter->p)++;
+ if (tem)
+ return tem;
+ }
+ return 0;
+}
+
diff --git a/usr.sbin/httpd/src/lib/expat-lite/hashtable.h b/usr.sbin/httpd/src/lib/expat-lite/hashtable.h
new file mode 100644
index 00000000000..df8ab8a4c83
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/hashtable.h
@@ -0,0 +1,69 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+
+#include <stddef.h>
+
+#ifdef XML_UNICODE
+
+#ifdef XML_UNICODE_WCHAR_T
+typedef const wchar_t *KEY;
+#else /* not XML_UNICODE_WCHAR_T */
+typedef const unsigned short *KEY;
+#endif /* not XML_UNICODE_WCHAR_T */
+
+#else /* not XML_UNICODE */
+
+typedef const char *KEY;
+
+#endif /* not XML_UNICODE */
+
+typedef struct {
+ KEY name;
+} NAMED;
+
+typedef struct {
+ NAMED **v;
+ size_t size;
+ size_t used;
+ size_t usedLim;
+} HASH_TABLE;
+
+NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize);
+void hashTableInit(HASH_TABLE *);
+void hashTableDestroy(HASH_TABLE *);
+
+typedef struct {
+ NAMED **p;
+ NAMED **end;
+} HASH_TABLE_ITER;
+
+void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
+NAMED *hashTableIterNext(HASH_TABLE_ITER *);
diff --git a/usr.sbin/httpd/src/lib/expat-lite/iasciitab.h b/usr.sbin/httpd/src/lib/expat-lite/iasciitab.h
new file mode 100644
index 00000000000..333d6bb779d
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/iasciitab.h
@@ -0,0 +1,63 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/usr.sbin/httpd/src/lib/expat-lite/latin1tab.h b/usr.sbin/httpd/src/lib/expat-lite/latin1tab.h
new file mode 100644
index 00000000000..48609aa8f9f
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/latin1tab.h
@@ -0,0 +1,62 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
+/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
diff --git a/usr.sbin/httpd/src/lib/expat-lite/nametab.h b/usr.sbin/httpd/src/lib/expat-lite/nametab.h
new file mode 100644
index 00000000000..b05e62c77a6
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/nametab.h
@@ -0,0 +1,150 @@
+static const unsigned namingBitmap[] = {
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE,
+0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
+0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF,
+0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
+0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
+0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
+0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
+0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
+0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF,
+0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000,
+0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
+0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003,
+0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003,
+0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
+0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001,
+0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003,
+0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
+0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
+0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003,
+0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000,
+0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
+0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF,
+0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB,
+0x40000000, 0xF580C900, 0x00000007, 0x02010800,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
+0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
+0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
+0x00000000, 0x00004C40, 0x00000000, 0x00000000,
+0x00000007, 0x00000000, 0x00000000, 0x00000000,
+0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF,
+0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF,
+0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
+0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
+0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF,
+0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
+0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003,
+0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
+0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
+0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
+0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
+0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
+0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF,
+0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF,
+0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
+0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF,
+0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
+0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
+0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3,
+0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
+0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
+0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3,
+0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000,
+0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000,
+0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
+0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
+0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
+0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF,
+};
+static const unsigned char nmstrtPages[] = {
+0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00,
+0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
+0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+static const unsigned char namePages[] = {
+0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00,
+0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
+0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
diff --git a/usr.sbin/httpd/src/lib/expat-lite/utf8tab.h b/usr.sbin/httpd/src/lib/expat-lite/utf8tab.h
new file mode 100644
index 00000000000..a38fe624e88
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/utf8tab.h
@@ -0,0 +1,63 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+
+/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
+/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmldef.h b/usr.sbin/httpd/src/lib/expat-lite/xmldef.h
new file mode 100644
index 00000000000..20c31844d8b
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmldef.h
@@ -0,0 +1,70 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+#include <string.h>
+
+#ifdef XML_WINLIB
+
+#define WIN32_LEAN_AND_MEAN
+#define STRICT
+#include <windows.h>
+
+#define malloc(x) HeapAlloc(GetProcessHeap(), 0, (x))
+#define calloc(x, y) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x)*(y))
+#define free(x) HeapFree(GetProcessHeap(), 0, (x))
+#define realloc(x, y) HeapReAlloc(GetProcessHeap(), 0, x, y)
+#define abort() /* as nothing */
+
+#else /* not XML_WINLIB */
+
+#include <stdlib.h>
+
+#endif /* not XML_WINLIB */
+
+/* This file can be used for any definitions needed in
+particular environments. */
+
+#ifdef MOZILLA
+
+#include "nspr.h"
+#define malloc(x) PR_Malloc(x)
+#define realloc(x, y) PR_Realloc((x), (y))
+#define calloc(x, y) PR_Calloc((x),(y))
+#define free(x) PR_Free(x)
+#define int int32
+
+#endif /* MOZILLA */
+
+#ifdef APACHE
+
+#include "ap_config.h"
+#define XML_BYTE_ORDER AP_BYTE_ORDER
+
+#endif /* APACHE */
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmlparse.c b/usr.sbin/httpd/src/lib/expat-lite/xmlparse.c
new file mode 100644
index 00000000000..8f9d09c86ee
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmlparse.c
@@ -0,0 +1,3256 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+#include "xmldef.h"
+#include "xmlparse.h"
+
+#ifdef XML_UNICODE
+#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
+#define XmlConvert XmlUtf16Convert
+#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
+#define XmlEncode XmlUtf16Encode
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1))
+typedef unsigned short ICHAR;
+#else
+#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
+#define XmlConvert XmlUtf8Convert
+#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
+#define XmlEncode XmlUtf8Encode
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
+typedef char ICHAR;
+#endif
+
+
+#ifndef XML_NS
+
+#define XmlInitEncodingNS XmlInitEncoding
+#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
+#undef XmlGetInternalEncodingNS
+#define XmlGetInternalEncodingNS XmlGetInternalEncoding
+#define XmlParseXmlDeclNS XmlParseXmlDecl
+
+#endif
+
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_T(x) L ## x
+#else
+#define XML_T(x) x
+#endif
+
+/* Round up n to be a multiple of sz, where sz is a power of 2. */
+#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
+
+#include "xmltok.h"
+#include "xmlrole.h"
+#include "hashtable.h"
+
+#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
+#define INIT_DATA_BUF_SIZE 1024
+#define INIT_ATTS_SIZE 16
+#define INIT_BLOCK_SIZE 1024
+#define INIT_BUFFER_SIZE 1024
+
+#define EXPAND_SPARE 24
+
+typedef struct binding {
+ struct prefix *prefix;
+ struct binding *nextTagBinding;
+ struct binding *prevPrefixBinding;
+ const struct attribute_id *attId;
+ XML_Char *uri;
+ int uriLen;
+ int uriAlloc;
+} BINDING;
+
+typedef struct prefix {
+ const XML_Char *name;
+ BINDING *binding;
+} PREFIX;
+
+typedef struct {
+ const XML_Char *str;
+ const XML_Char *localPart;
+ int uriLen;
+} TAG_NAME;
+
+typedef struct tag {
+ struct tag *parent;
+ const char *rawName;
+ int rawNameLength;
+ TAG_NAME name;
+ char *buf;
+ char *bufEnd;
+ BINDING *bindings;
+} TAG;
+
+typedef struct {
+ const XML_Char *name;
+ const XML_Char *textPtr;
+ int textLen;
+ const XML_Char *systemId;
+ const XML_Char *base;
+ const XML_Char *publicId;
+ const XML_Char *notation;
+ char open;
+} ENTITY;
+
+typedef struct block {
+ struct block *next;
+ int size;
+ XML_Char s[1];
+} BLOCK;
+
+typedef struct {
+ BLOCK *blocks;
+ BLOCK *freeBlocks;
+ const XML_Char *end;
+ XML_Char *ptr;
+ XML_Char *start;
+} STRING_POOL;
+
+/* The XML_Char before the name is used to determine whether
+an attribute has been specified. */
+typedef struct attribute_id {
+ XML_Char *name;
+ PREFIX *prefix;
+ char maybeTokenized;
+ char xmlns;
+} ATTRIBUTE_ID;
+
+typedef struct {
+ const ATTRIBUTE_ID *id;
+ char isCdata;
+ const XML_Char *value;
+} DEFAULT_ATTRIBUTE;
+
+typedef struct {
+ const XML_Char *name;
+ PREFIX *prefix;
+ int nDefaultAtts;
+ int allocDefaultAtts;
+ DEFAULT_ATTRIBUTE *defaultAtts;
+} ELEMENT_TYPE;
+
+typedef struct {
+ HASH_TABLE generalEntities;
+ HASH_TABLE elementTypes;
+ HASH_TABLE attributeIds;
+ HASH_TABLE prefixes;
+ STRING_POOL pool;
+ int complete;
+ int standalone;
+ const XML_Char *base;
+ PREFIX defaultPrefix;
+} DTD;
+
+typedef struct open_internal_entity {
+ const char *internalEventPtr;
+ const char *internalEventEndPtr;
+ struct open_internal_entity *next;
+ ENTITY *entity;
+} OPEN_INTERNAL_ENTITY;
+
+typedef enum XML_Error Processor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr);
+
+static Processor prologProcessor;
+static Processor prologInitProcessor;
+static Processor contentProcessor;
+static Processor cdataSectionProcessor;
+static Processor epilogProcessor;
+#if 0
+static Processor errorProcessor;
+#endif
+static Processor externalEntityInitProcessor;
+static Processor externalEntityInitProcessor2;
+static Processor externalEntityInitProcessor3;
+static Processor externalEntityContentProcessor;
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *, const char *);
+static enum XML_Error
+initializeEncoding(XML_Parser parser);
+static enum XML_Error
+doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+ const char *start, const char *end, const char **endPtr);
+static enum XML_Error
+doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr);
+static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *, const char *s,
+ TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
+static
+int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr);
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, int isCdata, const XML_Char *dfltValue);
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *,
+ STRING_POOL *);
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *,
+ STRING_POOL *);
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
+static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+static enum XML_Error
+storeEntityValue(XML_Parser parser, const char *start, const char *end);
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
+static int
+reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
+
+static const XML_Char *getContext(XML_Parser parser);
+static int setContext(XML_Parser parser, const XML_Char *context);
+static void normalizePublicId(XML_Char *s);
+static int dtdInit(DTD *);
+static void dtdDestroy(DTD *);
+static int dtdCopy(DTD *newDtd, const DTD *oldDtd);
+static void poolInit(STRING_POOL *);
+static void poolClear(STRING_POOL *);
+static void poolDestroy(STRING_POOL *);
+static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
+static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
+static int poolGrow(STRING_POOL *pool);
+static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s);
+static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
+
+#define poolStart(pool) ((pool)->start)
+#define poolEnd(pool) ((pool)->ptr)
+#define poolLength(pool) ((pool)->ptr - (pool)->start)
+#define poolChop(pool) ((void)--(pool->ptr))
+#define poolLastChar(pool) (((pool)->ptr)[-1])
+#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
+#define poolFinish(pool) ((pool)->start = (pool)->ptr)
+#define poolAppendChar(pool, c) \
+ (((pool)->ptr == (pool)->end && !poolGrow(pool)) \
+ ? 0 \
+ : ((*((pool)->ptr)++ = c), 1))
+
+typedef struct {
+ /* The first member must be userData so that the XML_GetUserData macro works. */
+ void *m_userData;
+ void *m_handlerArg;
+ char *m_buffer;
+ /* first character to be parsed */
+ const char *m_bufferPtr;
+ /* past last character to be parsed */
+ char *m_bufferEnd;
+ /* allocated end of buffer */
+ const char *m_bufferLim;
+ long m_parseEndByteIndex;
+ const char *m_parseEndPtr;
+ XML_Char *m_dataBuf;
+ XML_Char *m_dataBufEnd;
+ XML_StartElementHandler m_startElementHandler;
+ XML_EndElementHandler m_endElementHandler;
+ XML_CharacterDataHandler m_characterDataHandler;
+ XML_ProcessingInstructionHandler m_processingInstructionHandler;
+ XML_CommentHandler m_commentHandler;
+ XML_StartCdataSectionHandler m_startCdataSectionHandler;
+ XML_EndCdataSectionHandler m_endCdataSectionHandler;
+ XML_DefaultHandler m_defaultHandler;
+ XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
+ XML_NotationDeclHandler m_notationDeclHandler;
+ XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
+ XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
+ XML_NotStandaloneHandler m_notStandaloneHandler;
+ XML_ExternalEntityRefHandler m_externalEntityRefHandler;
+ void *m_externalEntityRefHandlerArg;
+ XML_UnknownEncodingHandler m_unknownEncodingHandler;
+ const ENCODING *m_encoding;
+ INIT_ENCODING m_initEncoding;
+ const XML_Char *m_protocolEncodingName;
+ int m_ns;
+ void *m_unknownEncodingMem;
+ void *m_unknownEncodingData;
+ void *m_unknownEncodingHandlerData;
+ void (*m_unknownEncodingRelease)(void *);
+ PROLOG_STATE m_prologState;
+ Processor *m_processor;
+ enum XML_Error m_errorCode;
+ const char *m_eventPtr;
+ const char *m_eventEndPtr;
+ const char *m_positionPtr;
+ OPEN_INTERNAL_ENTITY *m_openInternalEntities;
+ int m_defaultExpandInternalEntities;
+ int m_tagLevel;
+ ENTITY *m_declEntity;
+ const XML_Char *m_declNotationName;
+ const XML_Char *m_declNotationPublicId;
+ ELEMENT_TYPE *m_declElementType;
+ ATTRIBUTE_ID *m_declAttributeId;
+ char m_declAttributeIsCdata;
+ DTD m_dtd;
+ TAG *m_tagStack;
+ TAG *m_freeTagList;
+ BINDING *m_inheritedBindings;
+ BINDING *m_freeBindingList;
+ int m_attsSize;
+ int m_nSpecifiedAtts;
+ ATTRIBUTE *m_atts;
+ POSITION m_position;
+ STRING_POOL m_tempPool;
+ STRING_POOL m_temp2Pool;
+ char *m_groupConnector;
+ unsigned m_groupSize;
+ int m_hadExternalDoctype;
+ XML_Char m_namespaceSeparator;
+} Parser;
+
+#define userData (((Parser *)parser)->m_userData)
+#define handlerArg (((Parser *)parser)->m_handlerArg)
+#define startElementHandler (((Parser *)parser)->m_startElementHandler)
+#define endElementHandler (((Parser *)parser)->m_endElementHandler)
+#define characterDataHandler (((Parser *)parser)->m_characterDataHandler)
+#define processingInstructionHandler (((Parser *)parser)->m_processingInstructionHandler)
+#define commentHandler (((Parser *)parser)->m_commentHandler)
+#define startCdataSectionHandler (((Parser *)parser)->m_startCdataSectionHandler)
+#define endCdataSectionHandler (((Parser *)parser)->m_endCdataSectionHandler)
+#define defaultHandler (((Parser *)parser)->m_defaultHandler)
+#define unparsedEntityDeclHandler (((Parser *)parser)->m_unparsedEntityDeclHandler)
+#define notationDeclHandler (((Parser *)parser)->m_notationDeclHandler)
+#define startNamespaceDeclHandler (((Parser *)parser)->m_startNamespaceDeclHandler)
+#define endNamespaceDeclHandler (((Parser *)parser)->m_endNamespaceDeclHandler)
+#define notStandaloneHandler (((Parser *)parser)->m_notStandaloneHandler)
+#define externalEntityRefHandler (((Parser *)parser)->m_externalEntityRefHandler)
+#define externalEntityRefHandlerArg (((Parser *)parser)->m_externalEntityRefHandlerArg)
+#define unknownEncodingHandler (((Parser *)parser)->m_unknownEncodingHandler)
+#define encoding (((Parser *)parser)->m_encoding)
+#define initEncoding (((Parser *)parser)->m_initEncoding)
+#define unknownEncodingMem (((Parser *)parser)->m_unknownEncodingMem)
+#define unknownEncodingData (((Parser *)parser)->m_unknownEncodingData)
+#define unknownEncodingHandlerData \
+ (((Parser *)parser)->m_unknownEncodingHandlerData)
+#define unknownEncodingRelease (((Parser *)parser)->m_unknownEncodingRelease)
+#define protocolEncodingName (((Parser *)parser)->m_protocolEncodingName)
+#define ns (((Parser *)parser)->m_ns)
+#define prologState (((Parser *)parser)->m_prologState)
+#define processor (((Parser *)parser)->m_processor)
+#define errorCode (((Parser *)parser)->m_errorCode)
+#define eventPtr (((Parser *)parser)->m_eventPtr)
+#define eventEndPtr (((Parser *)parser)->m_eventEndPtr)
+#define positionPtr (((Parser *)parser)->m_positionPtr)
+#define position (((Parser *)parser)->m_position)
+#define openInternalEntities (((Parser *)parser)->m_openInternalEntities)
+#define defaultExpandInternalEntities (((Parser *)parser)->m_defaultExpandInternalEntities)
+#define tagLevel (((Parser *)parser)->m_tagLevel)
+#define buffer (((Parser *)parser)->m_buffer)
+#define bufferPtr (((Parser *)parser)->m_bufferPtr)
+#define bufferEnd (((Parser *)parser)->m_bufferEnd)
+#define parseEndByteIndex (((Parser *)parser)->m_parseEndByteIndex)
+#define parseEndPtr (((Parser *)parser)->m_parseEndPtr)
+#define bufferLim (((Parser *)parser)->m_bufferLim)
+#define dataBuf (((Parser *)parser)->m_dataBuf)
+#define dataBufEnd (((Parser *)parser)->m_dataBufEnd)
+#define dtd (((Parser *)parser)->m_dtd)
+#define declEntity (((Parser *)parser)->m_declEntity)
+#define declNotationName (((Parser *)parser)->m_declNotationName)
+#define declNotationPublicId (((Parser *)parser)->m_declNotationPublicId)
+#define declElementType (((Parser *)parser)->m_declElementType)
+#define declAttributeId (((Parser *)parser)->m_declAttributeId)
+#define declAttributeIsCdata (((Parser *)parser)->m_declAttributeIsCdata)
+#define freeTagList (((Parser *)parser)->m_freeTagList)
+#define freeBindingList (((Parser *)parser)->m_freeBindingList)
+#define inheritedBindings (((Parser *)parser)->m_inheritedBindings)
+#define tagStack (((Parser *)parser)->m_tagStack)
+#define atts (((Parser *)parser)->m_atts)
+#define attsSize (((Parser *)parser)->m_attsSize)
+#define nSpecifiedAtts (((Parser *)parser)->m_nSpecifiedAtts)
+#define tempPool (((Parser *)parser)->m_tempPool)
+#define temp2Pool (((Parser *)parser)->m_temp2Pool)
+#define groupConnector (((Parser *)parser)->m_groupConnector)
+#define groupSize (((Parser *)parser)->m_groupSize)
+#define hadExternalDoctype (((Parser *)parser)->m_hadExternalDoctype)
+#define namespaceSeparator (((Parser *)parser)->m_namespaceSeparator)
+
+#ifdef _MSC_VER
+#ifdef _DEBUG
+Parser *asParser(XML_Parser parser)
+{
+ return parser;
+}
+#endif
+#endif
+
+XML_Parser XML_ParserCreate(const XML_Char *encodingName)
+{
+ XML_Parser parser = malloc(sizeof(Parser));
+ if (!parser)
+ return parser;
+ processor = prologInitProcessor;
+ XmlPrologStateInit(&prologState);
+ userData = 0;
+ handlerArg = 0;
+ startElementHandler = 0;
+ endElementHandler = 0;
+ characterDataHandler = 0;
+ processingInstructionHandler = 0;
+ commentHandler = 0;
+ startCdataSectionHandler = 0;
+ endCdataSectionHandler = 0;
+ defaultHandler = 0;
+ unparsedEntityDeclHandler = 0;
+ notationDeclHandler = 0;
+ startNamespaceDeclHandler = 0;
+ endNamespaceDeclHandler = 0;
+ notStandaloneHandler = 0;
+ externalEntityRefHandler = 0;
+ externalEntityRefHandlerArg = parser;
+ unknownEncodingHandler = 0;
+ buffer = 0;
+ bufferPtr = 0;
+ bufferEnd = 0;
+ parseEndByteIndex = 0;
+ parseEndPtr = 0;
+ bufferLim = 0;
+ declElementType = 0;
+ declAttributeId = 0;
+ declEntity = 0;
+ declNotationName = 0;
+ declNotationPublicId = 0;
+ memset(&position, 0, sizeof(POSITION));
+ errorCode = XML_ERROR_NONE;
+ eventPtr = 0;
+ eventEndPtr = 0;
+ positionPtr = 0;
+ openInternalEntities = 0;
+ tagLevel = 0;
+ tagStack = 0;
+ freeTagList = 0;
+ freeBindingList = 0;
+ inheritedBindings = 0;
+ attsSize = INIT_ATTS_SIZE;
+ atts = malloc(attsSize * sizeof(ATTRIBUTE));
+ nSpecifiedAtts = 0;
+ dataBuf = malloc(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
+ groupSize = 0;
+ groupConnector = 0;
+ hadExternalDoctype = 0;
+ unknownEncodingMem = 0;
+ unknownEncodingRelease = 0;
+ unknownEncodingData = 0;
+ unknownEncodingHandlerData = 0;
+ namespaceSeparator = '!';
+ ns = 0;
+ poolInit(&tempPool);
+ poolInit(&temp2Pool);
+ protocolEncodingName = encodingName ? poolCopyString(&tempPool, encodingName) : 0;
+ if (!dtdInit(&dtd) || !atts || !dataBuf
+ || (encodingName && !protocolEncodingName)) {
+ XML_ParserFree(parser);
+ return 0;
+ }
+ dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
+ XmlInitEncoding(&initEncoding, &encoding, 0);
+ return parser;
+}
+
+XML_Parser XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
+{
+ static
+ const XML_Char implicitContext[] = {
+ XML_T('x'), XML_T('m'), XML_T('l'), XML_T('='),
+ XML_T('h'), XML_T('t'), XML_T('t'), XML_T('p'), XML_T(':'),
+ XML_T('/'), XML_T('/'), XML_T('w'), XML_T('w'), XML_T('w'),
+ XML_T('.'), XML_T('w'), XML_T('3'),
+ XML_T('.'), XML_T('o'), XML_T('r'), XML_T('g'),
+ XML_T('/'), XML_T('X'), XML_T('M'), XML_T('L'),
+ XML_T('/'), XML_T('1'), XML_T('9'), XML_T('9'), XML_T('8'),
+ XML_T('/'), XML_T('n'), XML_T('a'), XML_T('m'), XML_T('e'),
+ XML_T('s'), XML_T('p'), XML_T('a'), XML_T('c'), XML_T('e'),
+ XML_T('\0')
+ };
+
+ XML_Parser parser = XML_ParserCreate(encodingName);
+ if (parser) {
+ XmlInitEncodingNS(&initEncoding, &encoding, 0);
+ ns = 1;
+ namespaceSeparator = nsSep;
+ }
+ if (!setContext(parser, implicitContext)) {
+ XML_ParserFree(parser);
+ return 0;
+ }
+ return parser;
+}
+
+int XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+ if (!encodingName)
+ protocolEncodingName = 0;
+ else {
+ protocolEncodingName = poolCopyString(&tempPool, encodingName);
+ if (!protocolEncodingName)
+ return 0;
+ }
+ return 1;
+}
+
+XML_Parser XML_ExternalEntityParserCreate(XML_Parser oldParser,
+ const XML_Char *context,
+ const XML_Char *encodingName)
+{
+ XML_Parser parser = oldParser;
+ DTD *oldDtd = &dtd;
+ XML_StartElementHandler oldStartElementHandler = startElementHandler;
+ XML_EndElementHandler oldEndElementHandler = endElementHandler;
+ XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
+ XML_ProcessingInstructionHandler oldProcessingInstructionHandler = processingInstructionHandler;
+ XML_CommentHandler oldCommentHandler = commentHandler;
+ XML_StartCdataSectionHandler oldStartCdataSectionHandler = startCdataSectionHandler;
+ XML_EndCdataSectionHandler oldEndCdataSectionHandler = endCdataSectionHandler;
+ XML_DefaultHandler oldDefaultHandler = defaultHandler;
+ XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler = startNamespaceDeclHandler;
+ XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler = endNamespaceDeclHandler;
+ XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
+ XML_ExternalEntityRefHandler oldExternalEntityRefHandler = externalEntityRefHandler;
+ XML_UnknownEncodingHandler oldUnknownEncodingHandler = unknownEncodingHandler;
+ void *oldUserData = userData;
+ void *oldHandlerArg = handlerArg;
+ int oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
+ void *oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+
+ parser = (ns
+ ? XML_ParserCreateNS(encodingName, namespaceSeparator)
+ : XML_ParserCreate(encodingName));
+ if (!parser)
+ return 0;
+ startElementHandler = oldStartElementHandler;
+ endElementHandler = oldEndElementHandler;
+ characterDataHandler = oldCharacterDataHandler;
+ processingInstructionHandler = oldProcessingInstructionHandler;
+ commentHandler = oldCommentHandler;
+ startCdataSectionHandler = oldStartCdataSectionHandler;
+ endCdataSectionHandler = oldEndCdataSectionHandler;
+ defaultHandler = oldDefaultHandler;
+ startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
+ endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
+ notStandaloneHandler = oldNotStandaloneHandler;
+ externalEntityRefHandler = oldExternalEntityRefHandler;
+ unknownEncodingHandler = oldUnknownEncodingHandler;
+ userData = oldUserData;
+ if (oldUserData == oldHandlerArg)
+ handlerArg = userData;
+ else
+ handlerArg = parser;
+ if (oldExternalEntityRefHandlerArg != oldParser)
+ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
+ defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
+ if (!dtdCopy(&dtd, oldDtd) || !setContext(parser, context)) {
+ XML_ParserFree(parser);
+ return 0;
+ }
+ processor = externalEntityInitProcessor;
+ return parser;
+}
+
+static
+void destroyBindings(BINDING *bindings)
+{
+ for (;;) {
+ BINDING *b = bindings;
+ if (!b)
+ break;
+ bindings = b->nextTagBinding;
+ free(b->uri);
+ free(b);
+ }
+}
+
+void XML_ParserFree(XML_Parser parser)
+{
+ for (;;) {
+ TAG *p;
+ if (tagStack == 0) {
+ if (freeTagList == 0)
+ break;
+ tagStack = freeTagList;
+ freeTagList = 0;
+ }
+ p = tagStack;
+ tagStack = tagStack->parent;
+ free(p->buf);
+ destroyBindings(p->bindings);
+ free(p);
+ }
+ destroyBindings(freeBindingList);
+ destroyBindings(inheritedBindings);
+ poolDestroy(&tempPool);
+ poolDestroy(&temp2Pool);
+ dtdDestroy(&dtd);
+ free((void *)atts);
+ free(groupConnector);
+ free(buffer);
+ free(dataBuf);
+ free(unknownEncodingMem);
+ if (unknownEncodingRelease)
+ unknownEncodingRelease(unknownEncodingData);
+ free(parser);
+}
+
+void XML_UseParserAsHandlerArg(XML_Parser parser)
+{
+ handlerArg = parser;
+}
+
+void XML_SetUserData(XML_Parser parser, void *p)
+{
+ if (handlerArg == userData)
+ handlerArg = userData = p;
+ else
+ userData = p;
+}
+
+int XML_SetBase(XML_Parser parser, const XML_Char *p)
+{
+ if (p) {
+ p = poolCopyString(&dtd.pool, p);
+ if (!p)
+ return 0;
+ dtd.base = p;
+ }
+ else
+ dtd.base = 0;
+ return 1;
+}
+
+const XML_Char *XML_GetBase(XML_Parser parser)
+{
+ return dtd.base;
+}
+
+int XML_GetSpecifiedAttributeCount(XML_Parser parser)
+{
+ return nSpecifiedAtts;
+}
+
+void XML_SetElementHandler(XML_Parser parser,
+ XML_StartElementHandler start,
+ XML_EndElementHandler end)
+{
+ startElementHandler = start;
+ endElementHandler = end;
+}
+
+void XML_SetCharacterDataHandler(XML_Parser parser,
+ XML_CharacterDataHandler handler)
+{
+ characterDataHandler = handler;
+}
+
+void XML_SetProcessingInstructionHandler(XML_Parser parser,
+ XML_ProcessingInstructionHandler handler)
+{
+ processingInstructionHandler = handler;
+}
+
+void XML_SetCommentHandler(XML_Parser parser,
+ XML_CommentHandler handler)
+{
+ commentHandler = handler;
+}
+
+void XML_SetCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start,
+ XML_EndCdataSectionHandler end)
+{
+ startCdataSectionHandler = start;
+ endCdataSectionHandler = end;
+}
+
+void XML_SetDefaultHandler(XML_Parser parser,
+ XML_DefaultHandler handler)
+{
+ defaultHandler = handler;
+ defaultExpandInternalEntities = 0;
+}
+
+void XML_SetDefaultHandlerExpand(XML_Parser parser,
+ XML_DefaultHandler handler)
+{
+ defaultHandler = handler;
+ defaultExpandInternalEntities = 1;
+}
+
+void XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+ XML_UnparsedEntityDeclHandler handler)
+{
+ unparsedEntityDeclHandler = handler;
+}
+
+void XML_SetNotationDeclHandler(XML_Parser parser,
+ XML_NotationDeclHandler handler)
+{
+ notationDeclHandler = handler;
+}
+
+void XML_SetNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start,
+ XML_EndNamespaceDeclHandler end)
+{
+ startNamespaceDeclHandler = start;
+ endNamespaceDeclHandler = end;
+}
+
+void XML_SetNotStandaloneHandler(XML_Parser parser,
+ XML_NotStandaloneHandler handler)
+{
+ notStandaloneHandler = handler;
+}
+
+void XML_SetExternalEntityRefHandler(XML_Parser parser,
+ XML_ExternalEntityRefHandler handler)
+{
+ externalEntityRefHandler = handler;
+}
+
+void XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
+{
+ if (arg)
+ externalEntityRefHandlerArg = arg;
+ else
+ externalEntityRefHandlerArg = parser;
+}
+
+void XML_SetUnknownEncodingHandler(XML_Parser parser,
+ XML_UnknownEncodingHandler handler,
+ void *data)
+{
+ unknownEncodingHandler = handler;
+ unknownEncodingHandlerData = data;
+}
+
+int XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
+{
+ if (len == 0) {
+ if (!isFinal)
+ return 1;
+ positionPtr = bufferPtr;
+ errorCode = processor(parser, bufferPtr, parseEndPtr = bufferEnd, 0);
+ if (errorCode == XML_ERROR_NONE)
+ return 1;
+ eventEndPtr = eventPtr;
+ return 0;
+ }
+ else if (bufferPtr == bufferEnd) {
+ const char *end;
+ int nLeftOver;
+ parseEndByteIndex += len;
+ positionPtr = s;
+ if (isFinal) {
+ errorCode = processor(parser, s, parseEndPtr = s + len, 0);
+ if (errorCode == XML_ERROR_NONE)
+ return 1;
+ eventEndPtr = eventPtr;
+ return 0;
+ }
+ errorCode = processor(parser, s, parseEndPtr = s + len, &end);
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ return 0;
+ }
+ XmlUpdatePosition(encoding, positionPtr, end, &position);
+ nLeftOver = s + len - end;
+ if (nLeftOver) {
+ if (buffer == 0 || nLeftOver > bufferLim - buffer) {
+ /* FIXME avoid integer overflow */
+ buffer = buffer == 0 ? malloc(len * 2) : realloc(buffer, len * 2);
+ if (!buffer) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ eventPtr = eventEndPtr = 0;
+ return 0;
+ }
+ bufferLim = buffer + len * 2;
+ }
+ memcpy(buffer, end, nLeftOver);
+ bufferPtr = buffer;
+ bufferEnd = buffer + nLeftOver;
+ }
+ return 1;
+ }
+ else {
+ memcpy(XML_GetBuffer(parser, len), s, len);
+ return XML_ParseBuffer(parser, len, isFinal);
+ }
+}
+
+int XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
+{
+ const char *start = bufferPtr;
+ positionPtr = start;
+ bufferEnd += len;
+ parseEndByteIndex += len;
+ errorCode = processor(parser, start, parseEndPtr = bufferEnd,
+ isFinal ? (const char **)0 : &bufferPtr);
+ if (errorCode == XML_ERROR_NONE) {
+ if (!isFinal)
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ return 1;
+ }
+ else {
+ eventEndPtr = eventPtr;
+ return 0;
+ }
+}
+
+void *XML_GetBuffer(XML_Parser parser, int len)
+{
+ if (len > bufferLim - bufferEnd) {
+ /* FIXME avoid integer overflow */
+ int neededSize = len + (bufferEnd - bufferPtr);
+ if (neededSize <= bufferLim - buffer) {
+ memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
+ bufferEnd = buffer + (bufferEnd - bufferPtr);
+ bufferPtr = buffer;
+ }
+ else {
+ char *newBuf;
+ int bufferSize = bufferLim - bufferPtr;
+ if (bufferSize == 0)
+ bufferSize = INIT_BUFFER_SIZE;
+ do {
+ bufferSize *= 2;
+ } while (bufferSize < neededSize);
+ newBuf = malloc(bufferSize);
+ if (newBuf == 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return 0;
+ }
+ bufferLim = newBuf + bufferSize;
+ if (bufferPtr) {
+ memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
+ free(buffer);
+ }
+ bufferEnd = newBuf + (bufferEnd - bufferPtr);
+ bufferPtr = buffer = newBuf;
+ }
+ }
+ return bufferEnd;
+}
+
+enum XML_Error XML_GetErrorCode(XML_Parser parser)
+{
+ return errorCode;
+}
+
+long XML_GetCurrentByteIndex(XML_Parser parser)
+{
+ if (eventPtr)
+ return parseEndByteIndex - (parseEndPtr - eventPtr);
+ return -1;
+}
+
+int XML_GetCurrentByteCount(XML_Parser parser)
+{
+ if (eventEndPtr && eventPtr)
+ return eventEndPtr - eventPtr;
+ return 0;
+}
+
+int XML_GetCurrentLineNumber(XML_Parser parser)
+{
+ if (eventPtr) {
+ XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+ positionPtr = eventPtr;
+ }
+ return position.lineNumber + 1;
+}
+
+int XML_GetCurrentColumnNumber(XML_Parser parser)
+{
+ if (eventPtr) {
+ XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+ positionPtr = eventPtr;
+ }
+ return position.columnNumber;
+}
+
+void XML_DefaultCurrent(XML_Parser parser)
+{
+ if (defaultHandler) {
+ if (openInternalEntities)
+ reportDefault(parser,
+ ns ? XmlGetInternalEncodingNS() : XmlGetInternalEncoding(),
+ openInternalEntities->internalEventPtr,
+ openInternalEntities->internalEventEndPtr);
+ else
+ reportDefault(parser, encoding, eventPtr, eventEndPtr);
+ }
+}
+
+const XML_LChar *XML_ErrorString(int code)
+{
+ static const XML_LChar *message[] = {
+ 0,
+ XML_T("out of memory"),
+ XML_T("syntax error"),
+ XML_T("no element found"),
+ XML_T("not well-formed"),
+ XML_T("unclosed token"),
+ XML_T("unclosed token"),
+ XML_T("mismatched tag"),
+ XML_T("duplicate attribute"),
+ XML_T("junk after document element"),
+ XML_T("illegal parameter entity reference"),
+ XML_T("undefined entity"),
+ XML_T("recursive entity reference"),
+ XML_T("asynchronous entity"),
+ XML_T("reference to invalid character number"),
+ XML_T("reference to binary entity"),
+ XML_T("reference to external entity in attribute"),
+ XML_T("xml processing instruction not at start of external entity"),
+ XML_T("unknown encoding"),
+ XML_T("encoding specified in XML declaration is incorrect"),
+ XML_T("unclosed CDATA section"),
+ XML_T("error in processing external entity reference"),
+ XML_T("document is not standalone")
+ };
+ if (code > 0 && code < sizeof(message)/sizeof(message[0]))
+ return message[code];
+ return 0;
+}
+
+static
+enum XML_Error contentProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ return doContent(parser, 0, encoding, start, end, endPtr);
+}
+
+static
+enum XML_Error externalEntityInitProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+ processor = externalEntityInitProcessor2;
+ return externalEntityInitProcessor2(parser, start, end, endPtr);
+}
+
+static
+enum XML_Error externalEntityInitProcessor2(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ const char *next;
+ int tok = XmlContentTok(encoding, start, end, &next);
+ switch (tok) {
+ case XML_TOK_BOM:
+ start = next;
+ break;
+ case XML_TOK_PARTIAL:
+ if (endPtr) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (endPtr) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_PARTIAL_CHAR;
+ }
+ processor = externalEntityInitProcessor3;
+ return externalEntityInitProcessor3(parser, start, end, endPtr);
+}
+
+static
+enum XML_Error externalEntityInitProcessor3(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ const char *next;
+ int tok = XmlContentTok(encoding, start, end, &next);
+ switch (tok) {
+ case XML_TOK_XML_DECL:
+ {
+ enum XML_Error result = processXmlDecl(parser, 1, start, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ start = next;
+ }
+ break;
+ case XML_TOK_PARTIAL:
+ if (endPtr) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (endPtr) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_PARTIAL_CHAR;
+ }
+ processor = externalEntityContentProcessor;
+ tagLevel = 1;
+ return doContent(parser, 1, encoding, start, end, endPtr);
+}
+
+static
+enum XML_Error externalEntityContentProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ return doContent(parser, 1, encoding, start, end, endPtr);
+}
+
+static enum XML_Error
+doContent(XML_Parser parser,
+ int startTagLevel,
+ const ENCODING *enc,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const ENCODING *internalEnc = ns ? XmlGetInternalEncodingNS() : XmlGetInternalEncoding();
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+ for (;;) {
+ const char *next = s; /* XmlContentTok doesn't always set the last arg */
+ int tok = XmlContentTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_TRAILING_CR:
+ if (nextPtr) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ *eventEndPP = end;
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, end);
+ if (startTagLevel == 0)
+ return XML_ERROR_NO_ELEMENTS;
+ if (tagLevel != startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ return XML_ERROR_NONE;
+ case XML_TOK_NONE:
+ if (nextPtr) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ if (startTagLevel > 0) {
+ if (tagLevel != startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_NO_ELEMENTS;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (nextPtr) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (nextPtr) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_ENTITY_REF:
+ {
+ const XML_Char *name;
+ ENTITY *entity;
+ XML_Char ch = XmlPredefinedEntityName(enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (ch) {
+ if (characterDataHandler)
+ characterDataHandler(handlerArg, &ch, 1);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ name = poolStoreString(&dtd.pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0);
+ poolDiscard(&dtd.pool);
+ if (!entity) {
+ if (dtd.complete || dtd.standalone)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ if (entity->open)
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ if (entity->notation)
+ return XML_ERROR_BINARY_ENTITY_REF;
+ if (entity) {
+ if (entity->textPtr) {
+ enum XML_Error result;
+ OPEN_INTERNAL_ENTITY openEntity;
+ if (defaultHandler && !defaultExpandInternalEntities) {
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ entity->open = 1;
+ openEntity.next = openInternalEntities;
+ openInternalEntities = &openEntity;
+ openEntity.entity = entity;
+ openEntity.internalEventPtr = 0;
+ openEntity.internalEventEndPtr = 0;
+ result = doContent(parser,
+ tagLevel,
+ internalEnc,
+ (char *)entity->textPtr,
+ (char *)(entity->textPtr + entity->textLen),
+ 0);
+ entity->open = 0;
+ openInternalEntities = openEntity.next;
+ if (result)
+ return result;
+ }
+ else if (externalEntityRefHandler) {
+ const XML_Char *context;
+ entity->open = 1;
+ context = getContext(parser);
+ entity->open = 0;
+ if (!context)
+ return XML_ERROR_NO_MEMORY;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ context,
+ dtd.base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ poolDiscard(&tempPool);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ }
+ case XML_TOK_START_TAG_WITH_ATTS:
+ if (!startElementHandler) {
+ enum XML_Error result = storeAtts(parser, enc, s, 0, 0);
+ if (result)
+ return result;
+ }
+ /* fall through */
+ case XML_TOK_START_TAG_NO_ATTS:
+ {
+ TAG *tag;
+ if (freeTagList) {
+ tag = freeTagList;
+ freeTagList = freeTagList->parent;
+ }
+ else {
+ tag = malloc(sizeof(TAG));
+ if (!tag)
+ return XML_ERROR_NO_MEMORY;
+ tag->buf = malloc(INIT_TAG_BUF_SIZE);
+ if (!tag->buf)
+ return XML_ERROR_NO_MEMORY;
+ tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
+ }
+ tag->bindings = 0;
+ tag->parent = tagStack;
+ tagStack = tag;
+ tag->name.localPart = 0;
+ tag->rawName = s + enc->minBytesPerChar;
+ tag->rawNameLength = XmlNameLength(enc, tag->rawName);
+ if (nextPtr) {
+ /* Need to guarantee that:
+ tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)) <= tag->bufEnd - sizeof(XML_Char) */
+ if (tag->rawNameLength + (int)(sizeof(XML_Char) - 1) + (int)sizeof(XML_Char) > tag->bufEnd - tag->buf) {
+ int bufSize = tag->rawNameLength * 4;
+ bufSize = ROUND_UP(bufSize, sizeof(XML_Char));
+ tag->buf = realloc(tag->buf, bufSize);
+ if (!tag->buf)
+ return XML_ERROR_NO_MEMORY;
+ tag->bufEnd = tag->buf + bufSize;
+ }
+ memcpy(tag->buf, tag->rawName, tag->rawNameLength);
+ tag->rawName = tag->buf;
+ }
+ ++tagLevel;
+ if (startElementHandler) {
+ enum XML_Error result;
+ XML_Char *toPtr;
+ for (;;) {
+ const char *rawNameEnd = tag->rawName + tag->rawNameLength;
+ const char *fromPtr = tag->rawName;
+ int bufSize;
+ if (nextPtr)
+ toPtr = (XML_Char *)(tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)));
+ else
+ toPtr = (XML_Char *)tag->buf;
+ tag->name.str = toPtr;
+ XmlConvert(enc,
+ &fromPtr, rawNameEnd,
+ (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
+ if (fromPtr == rawNameEnd)
+ break;
+ bufSize = (tag->bufEnd - tag->buf) << 1;
+ tag->buf = realloc(tag->buf, bufSize);
+ if (!tag->buf)
+ return XML_ERROR_NO_MEMORY;
+ tag->bufEnd = tag->buf + bufSize;
+ if (nextPtr)
+ tag->rawName = tag->buf;
+ }
+ *toPtr = XML_T('\0');
+ result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
+ if (result)
+ return result;
+ startElementHandler(handlerArg, tag->name.str, (const XML_Char **)atts);
+ poolClear(&tempPool);
+ }
+ else {
+ tag->name.str = 0;
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ }
+ case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
+ if (!startElementHandler) {
+ enum XML_Error result = storeAtts(parser, enc, s, 0, 0);
+ if (result)
+ return result;
+ }
+ /* fall through */
+ case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
+ if (startElementHandler || endElementHandler) {
+ const char *rawName = s + enc->minBytesPerChar;
+ enum XML_Error result;
+ BINDING *bindings = 0;
+ TAG_NAME name;
+ name.str = poolStoreString(&tempPool, enc, rawName,
+ rawName + XmlNameLength(enc, rawName));
+ if (!name.str)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ result = storeAtts(parser, enc, s, &name, &bindings);
+ if (result)
+ return result;
+ poolFinish(&tempPool);
+ if (startElementHandler)
+ startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
+ if (endElementHandler) {
+ if (startElementHandler)
+ *eventPP = *eventEndPP;
+ endElementHandler(handlerArg, name.str);
+ }
+ poolClear(&tempPool);
+ while (bindings) {
+ BINDING *b = bindings;
+ if (endNamespaceDeclHandler)
+ endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ bindings = bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ b->prefix->binding = b->prevPrefixBinding;
+ }
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ if (tagLevel == 0)
+ return epilogProcessor(parser, next, end, nextPtr);
+ break;
+ case XML_TOK_END_TAG:
+ if (tagLevel == startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ else {
+ int len;
+ const char *rawName;
+ TAG *tag = tagStack;
+ tagStack = tag->parent;
+ tag->parent = freeTagList;
+ freeTagList = tag;
+ rawName = s + enc->minBytesPerChar*2;
+ len = XmlNameLength(enc, rawName);
+ if (len != tag->rawNameLength
+ || memcmp(tag->rawName, rawName, len) != 0) {
+ *eventPP = rawName;
+ return XML_ERROR_TAG_MISMATCH;
+ }
+ --tagLevel;
+ if (endElementHandler && tag->name.str) {
+ if (tag->name.localPart) {
+ XML_Char *to = (XML_Char *)tag->name.str + tag->name.uriLen;
+ const XML_Char *from = tag->name.localPart;
+ while ((*to++ = *from++) != 0)
+ ;
+ }
+ endElementHandler(handlerArg, tag->name.str);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ while (tag->bindings) {
+ BINDING *b = tag->bindings;
+ if (endNamespaceDeclHandler)
+ endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ tag->bindings = tag->bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ b->prefix->binding = b->prevPrefixBinding;
+ }
+ if (tagLevel == 0)
+ return epilogProcessor(parser, next, end, nextPtr);
+ }
+ break;
+ case XML_TOK_CHAR_REF:
+ {
+ int n = XmlCharRefNumber(enc, s);
+ if (n < 0)
+ return XML_ERROR_BAD_CHAR_REF;
+ if (characterDataHandler) {
+ XML_Char buf[XML_ENCODE_MAX];
+ characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ case XML_TOK_XML_DECL:
+ return XML_ERROR_MISPLACED_XML_PI;
+ case XML_TOK_DATA_NEWLINE:
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_CDATA_SECT_OPEN:
+ {
+ enum XML_Error result;
+ if (startCdataSectionHandler)
+ startCdataSectionHandler(handlerArg);
+#if 0
+ /* Suppose you doing a transformation on a document that involves
+ changing only the character data. You set up a defaultHandler
+ and a characterDataHandler. The defaultHandler simply copies
+ characters through. The characterDataHandler does the transformation
+ and writes the characters out escaping them as necessary. This case
+ will fail to work if we leave out the following two lines (because &
+ and < inside CDATA sections will be incorrectly escaped).
+
+ However, now we have a start/endCdataSectionHandler, so it seems
+ easier to let the user deal with this. */
+
+ else if (characterDataHandler)
+ characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ result = doCdataSection(parser, enc, &next, end, nextPtr);
+ if (!next) {
+ processor = cdataSectionProcessor;
+ return result;
+ }
+ }
+ break;
+ case XML_TOK_TRAILING_RSQB:
+ if (nextPtr) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ if (characterDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf);
+ }
+ else
+ characterDataHandler(handlerArg,
+ (XML_Char *)s,
+ (XML_Char *)end - (XML_Char *)s);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, end);
+ if (startTagLevel == 0) {
+ *eventPP = end;
+ return XML_ERROR_NO_ELEMENTS;
+ }
+ if (tagLevel != startTagLevel) {
+ *eventPP = end;
+ return XML_ERROR_ASYNC_ENTITY;
+ }
+ return XML_ERROR_NONE;
+ case XML_TOK_DATA_CHARS:
+ if (characterDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = s;
+ characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf);
+ if (s == next)
+ break;
+ *eventPP = s;
+ }
+ }
+ else
+ characterDataHandler(handlerArg,
+ (XML_Char *)s,
+ (XML_Char *)next - (XML_Char *)s);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_PI:
+ if (!reportProcessingInstruction(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_COMMENT:
+ if (!reportComment(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ default:
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ *eventPP = s = next;
+ }
+ /* not reached */
+}
+
+/* If tagNamePtr is non-null, build a real list of attributes,
+otherwise just check the attributes for well-formedness. */
+
+static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc,
+ const char *s, TAG_NAME *tagNamePtr,
+ BINDING **bindingsPtr)
+{
+ ELEMENT_TYPE *elementType = 0;
+ int nDefaultAtts = 0;
+ const XML_Char **appAtts;
+ int attIndex = 0;
+ int i;
+ int n;
+ int nPrefixes = 0;
+ BINDING *binding;
+ const XML_Char *localPart;
+
+ if (tagNamePtr) {
+ elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagNamePtr->str, 0);
+ if (!elementType) {
+ tagNamePtr->str = poolCopyString(&dtd.pool, tagNamePtr->str);
+ if (!tagNamePtr->str)
+ return XML_ERROR_NO_MEMORY;
+ elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagNamePtr->str, sizeof(ELEMENT_TYPE));
+ if (!elementType)
+ return XML_ERROR_NO_MEMORY;
+ if (ns && !setElementTypePrefix(parser, elementType))
+ return XML_ERROR_NO_MEMORY;
+ }
+ nDefaultAtts = elementType->nDefaultAtts;
+ }
+ n = XmlGetAttributes(enc, s, attsSize, atts);
+ if (n + nDefaultAtts > attsSize) {
+ int oldAttsSize = attsSize;
+ attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+ atts = realloc((void *)atts, attsSize * sizeof(ATTRIBUTE));
+ if (!atts)
+ return XML_ERROR_NO_MEMORY;
+ if (n > oldAttsSize)
+ XmlGetAttributes(enc, s, n, atts);
+ }
+ appAtts = (const XML_Char **)atts;
+ for (i = 0; i < n; i++) {
+ ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name,
+ atts[i].name
+ + XmlNameLength(enc, atts[i].name));
+ if (!attId)
+ return XML_ERROR_NO_MEMORY;
+ if ((attId->name)[-1]) {
+ if (enc == encoding)
+ eventPtr = atts[i].name;
+ return XML_ERROR_DUPLICATE_ATTRIBUTE;
+ }
+ (attId->name)[-1] = 1;
+ appAtts[attIndex++] = attId->name;
+ if (!atts[i].normalized) {
+ enum XML_Error result;
+ int isCdata = 1;
+
+ if (attId->maybeTokenized) {
+ int j;
+ for (j = 0; j < nDefaultAtts; j++) {
+ if (attId == elementType->defaultAtts[j].id) {
+ isCdata = elementType->defaultAtts[j].isCdata;
+ break;
+ }
+ }
+ }
+
+ result = storeAttributeValue(parser, enc, isCdata,
+ atts[i].valuePtr, atts[i].valueEnd,
+ &tempPool);
+ if (result)
+ return result;
+ if (tagNamePtr) {
+ appAtts[attIndex] = poolStart(&tempPool);
+ poolFinish(&tempPool);
+ }
+ else
+ poolDiscard(&tempPool);
+ }
+ else if (tagNamePtr) {
+ appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, atts[i].valueEnd);
+ if (appAtts[attIndex] == 0)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ }
+ if (attId->prefix && tagNamePtr) {
+ if (attId->xmlns) {
+ if (!addBinding(parser, attId->prefix, attId, appAtts[attIndex], bindingsPtr))
+ return XML_ERROR_NO_MEMORY;
+ --attIndex;
+ }
+ else {
+ attIndex++;
+ nPrefixes++;
+ (attId->name)[-1] = 2;
+ }
+ }
+ else
+ attIndex++;
+ }
+ nSpecifiedAtts = attIndex;
+ if (tagNamePtr) {
+ int j;
+ for (j = 0; j < nDefaultAtts; j++) {
+ const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + j;
+ if (!(da->id->name)[-1] && da->value) {
+ if (da->id->prefix) {
+ if (da->id->xmlns) {
+ if (!addBinding(parser, da->id->prefix, da->id, da->value, bindingsPtr))
+ return XML_ERROR_NO_MEMORY;
+ }
+ else {
+ (da->id->name)[-1] = 2;
+ nPrefixes++;
+ appAtts[attIndex++] = da->id->name;
+ appAtts[attIndex++] = da->value;
+ }
+ }
+ else {
+ (da->id->name)[-1] = 1;
+ appAtts[attIndex++] = da->id->name;
+ appAtts[attIndex++] = da->value;
+ }
+ }
+ }
+ appAtts[attIndex] = 0;
+ }
+ i = 0;
+ if (nPrefixes) {
+ for (; i < attIndex; i += 2) {
+ if (appAtts[i][-1] == 2) {
+ ATTRIBUTE_ID *id;
+ ((XML_Char *)(appAtts[i]))[-1] = 0;
+ id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, appAtts[i], 0);
+ if (id->prefix->binding) {
+ int j;
+ const BINDING *b = id->prefix->binding;
+ const XML_Char *ss = appAtts[i];
+ for (j = 0; j < b->uriLen; j++) {
+ if (!poolAppendChar(&tempPool, b->uri[j]))
+ return XML_ERROR_NO_MEMORY;
+ }
+ while (*ss++ != ':')
+ ;
+ do {
+ if (!poolAppendChar(&tempPool, *ss))
+ return XML_ERROR_NO_MEMORY;
+ } while (*ss++);
+ appAtts[i] = poolStart(&tempPool);
+ poolFinish(&tempPool);
+ }
+ if (!--nPrefixes)
+ break;
+ }
+ else
+ ((XML_Char *)(appAtts[i]))[-1] = 0;
+ }
+ }
+ for (; i < attIndex; i += 2)
+ ((XML_Char *)(appAtts[i]))[-1] = 0;
+ if (!tagNamePtr)
+ return XML_ERROR_NONE;
+ for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
+ binding->attId->name[-1] = 0;
+ if (elementType->prefix) {
+ binding = elementType->prefix->binding;
+ if (!binding)
+ return XML_ERROR_NONE;
+ localPart = tagNamePtr->str;
+ while (*localPart++ != XML_T(':'))
+ ;
+ }
+ else if (dtd.defaultPrefix.binding) {
+ binding = dtd.defaultPrefix.binding;
+ localPart = tagNamePtr->str;
+ }
+ else
+ return XML_ERROR_NONE;
+ tagNamePtr->localPart = localPart;
+ tagNamePtr->uriLen = binding->uriLen;
+ i = binding->uriLen;
+ do {
+ if (i == binding->uriAlloc) {
+ binding->uri = realloc(binding->uri, binding->uriAlloc *= 2);
+ if (!binding->uri)
+ return XML_ERROR_NO_MEMORY;
+ }
+ binding->uri[i++] = *localPart;
+ } while (*localPart++);
+ tagNamePtr->str = binding->uri;
+ return XML_ERROR_NONE;
+}
+
+static
+int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr)
+{
+ BINDING *b;
+ int len;
+ for (len = 0; uri[len]; len++)
+ ;
+ if (namespaceSeparator)
+ len++;
+ if (freeBindingList) {
+ b = freeBindingList;
+ if (len > b->uriAlloc) {
+ b->uri = realloc(b->uri, len + EXPAND_SPARE);
+ if (!b->uri)
+ return 0;
+ b->uriAlloc = len + EXPAND_SPARE;
+ }
+ freeBindingList = b->nextTagBinding;
+ }
+ else {
+ b = malloc(sizeof(BINDING));
+ if (!b)
+ return 0;
+ b->uri = malloc(sizeof(XML_Char) * len + EXPAND_SPARE);
+ if (!b->uri) {
+ free(b);
+ return 0;
+ }
+ b->uriAlloc = len;
+ }
+ b->uriLen = len;
+ memcpy(b->uri, uri, len * sizeof(XML_Char));
+ if (namespaceSeparator)
+ b->uri[len - 1] = namespaceSeparator;
+ b->prefix = prefix;
+ b->attId = attId;
+ b->prevPrefixBinding = prefix->binding;
+ if (*uri == XML_T('\0') && prefix == &dtd.defaultPrefix)
+ prefix->binding = 0;
+ else
+ prefix->binding = b;
+ b->nextTagBinding = *bindingsPtr;
+ *bindingsPtr = b;
+ if (startNamespaceDeclHandler)
+ startNamespaceDeclHandler(handlerArg, prefix->name,
+ prefix->binding ? uri : 0);
+ return 1;
+}
+
+/* The idea here is to avoid using stack for each CDATA section when
+the whole file is parsed with one call. */
+
+static
+enum XML_Error cdataSectionProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doCdataSection(parser, encoding, &start, end, endPtr);
+ if (start) {
+ processor = contentProcessor;
+ return contentProcessor(parser, start, end, endPtr);
+ }
+ return result;
+}
+
+/* startPtr gets set to non-null is the section is closed, and to null if
+the section is not yet closed. */
+
+static
+enum XML_Error doCdataSection(XML_Parser parser,
+ const ENCODING *enc,
+ const char **startPtr,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *s = *startPtr;
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ *eventPP = s;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+ *startPtr = 0;
+ for (;;) {
+ const char *next;
+ int tok = XmlCdataSectionTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_CDATA_SECT_CLOSE:
+ if (endCdataSectionHandler)
+ endCdataSectionHandler(handlerArg);
+#if 0
+ /* see comment under XML_TOK_CDATA_SECT_OPEN */
+ else if (characterDataHandler)
+ characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ *startPtr = next;
+ return XML_ERROR_NONE;
+ case XML_TOK_DATA_NEWLINE:
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_DATA_CHARS:
+ if (characterDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = next;
+ characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf);
+ if (s == next)
+ break;
+ *eventPP = s;
+ }
+ }
+ else
+ characterDataHandler(handlerArg,
+ (XML_Char *)s,
+ (XML_Char *)next - (XML_Char *)s);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (nextPtr) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_PARTIAL:
+ case XML_TOK_NONE:
+ if (nextPtr) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_CDATA_SECTION;
+ default:
+ abort();
+ }
+ *eventPP = s = next;
+ }
+ /* not reached */
+}
+
+static enum XML_Error
+initializeEncoding(XML_Parser parser)
+{
+ const char *s;
+#ifdef XML_UNICODE
+ char encodingBuf[128];
+ if (!protocolEncodingName)
+ s = 0;
+ else {
+ int i;
+ for (i = 0; protocolEncodingName[i]; i++) {
+ if (i == sizeof(encodingBuf) - 1
+ || protocolEncodingName[i] >= 0x80
+ || protocolEncodingName[i] < 0) {
+ encodingBuf[0] = '\0';
+ break;
+ }
+ encodingBuf[i] = (char)protocolEncodingName[i];
+ }
+ encodingBuf[i] = '\0';
+ s = encodingBuf;
+ }
+#else
+ s = protocolEncodingName;
+#endif
+ if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
+ return XML_ERROR_NONE;
+ return handleUnknownEncoding(parser, protocolEncodingName);
+}
+
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+ const char *s, const char *next)
+{
+ const char *encodingName = 0;
+ const ENCODING *newEncoding = 0;
+ const char *version;
+ int standalone = -1;
+ if (!(ns
+ ? XmlParseXmlDeclNS
+ : XmlParseXmlDecl)(isGeneralTextEntity,
+ encoding,
+ s,
+ next,
+ &eventPtr,
+ &version,
+ &encodingName,
+ &newEncoding,
+ &standalone))
+ return XML_ERROR_SYNTAX;
+ if (!isGeneralTextEntity && standalone == 1)
+ dtd.standalone = 1;
+ if (defaultHandler)
+ reportDefault(parser, encoding, s, next);
+ if (!protocolEncodingName) {
+ if (newEncoding) {
+ if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) {
+ eventPtr = encodingName;
+ return XML_ERROR_INCORRECT_ENCODING;
+ }
+ encoding = newEncoding;
+ }
+ else if (encodingName) {
+ enum XML_Error result;
+ const XML_Char *ss = poolStoreString(&tempPool,
+ encoding,
+ encodingName,
+ encodingName
+ + XmlNameLength(encoding, encodingName));
+ if (!ss)
+ return XML_ERROR_NO_MEMORY;
+ result = handleUnknownEncoding(parser, ss);
+ poolDiscard(&tempPool);
+ if (result == XML_ERROR_UNKNOWN_ENCODING)
+ eventPtr = encodingName;
+ return result;
+ }
+ }
+ return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+ if (unknownEncodingHandler) {
+ XML_Encoding info;
+ int i;
+ for (i = 0; i < 256; i++)
+ info.map[i] = -1;
+ info.convert = 0;
+ info.data = 0;
+ info.release = 0;
+ if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, &info)) {
+ ENCODING *enc;
+ unknownEncodingMem = malloc(XmlSizeOfUnknownEncoding());
+ if (!unknownEncodingMem) {
+ if (info.release)
+ info.release(info.data);
+ return XML_ERROR_NO_MEMORY;
+ }
+ enc = (ns
+ ? XmlInitUnknownEncodingNS
+ : XmlInitUnknownEncoding)(unknownEncodingMem,
+ info.map,
+ info.convert,
+ info.data);
+ if (enc) {
+ unknownEncodingData = info.data;
+ unknownEncodingRelease = info.release;
+ encoding = enc;
+ return XML_ERROR_NONE;
+ }
+ }
+ if (info.release)
+ info.release(info.data);
+ }
+ return XML_ERROR_UNKNOWN_ENCODING;
+}
+
+static enum XML_Error
+prologInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+ processor = prologProcessor;
+ return prologProcessor(parser, s, end, nextPtr);
+}
+
+static enum XML_Error
+prologProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ for (;;) {
+ const char *next;
+ int tok = XmlPrologTok(encoding, s, end, &next);
+ if (tok <= 0) {
+ if (nextPtr != 0 && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_NONE:
+ return XML_ERROR_NO_ELEMENTS;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_TRAILING_CR:
+ eventPtr = s + encoding->minBytesPerChar;
+ return XML_ERROR_NO_ELEMENTS;
+ default:
+ abort();
+ }
+ }
+ switch (XmlTokenRole(&prologState, tok, s, next, encoding)) {
+ case XML_ROLE_XML_DECL:
+ {
+ enum XML_Error result = processXmlDecl(parser, 0, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_SYSTEM_ID:
+ if (!dtd.standalone
+ && notStandaloneHandler
+ && !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ hadExternalDoctype = 1;
+ break;
+ case XML_ROLE_DOCTYPE_PUBLIC_ID:
+ case XML_ROLE_ENTITY_PUBLIC_ID:
+ if (!XmlIsPublicId(encoding, s, next, &eventPtr))
+ return XML_ERROR_SYNTAX;
+ if (declEntity) {
+ XML_Char *tem = poolStoreString(&dtd.pool,
+ encoding,
+ s + encoding->minBytesPerChar,
+ next - encoding->minBytesPerChar);
+ if (!tem)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(tem);
+ declEntity->publicId = tem;
+ poolFinish(&dtd.pool);
+ }
+ break;
+ case XML_ROLE_INSTANCE_START:
+ processor = contentProcessor;
+ if (hadExternalDoctype)
+ dtd.complete = 0;
+ return contentProcessor(parser, s, end, nextPtr);
+ case XML_ROLE_ATTLIST_ELEMENT_NAME:
+ {
+ const XML_Char *name = poolStoreString(&dtd.pool, encoding, s, next);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ declElementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, name, sizeof(ELEMENT_TYPE));
+ if (!declElementType)
+ return XML_ERROR_NO_MEMORY;
+ if (declElementType->name != name)
+ poolDiscard(&dtd.pool);
+ else {
+ poolFinish(&dtd.pool);
+ if (!setElementTypePrefix(parser, declElementType))
+ return XML_ERROR_NO_MEMORY;
+ }
+ break;
+ }
+ case XML_ROLE_ATTRIBUTE_NAME:
+ declAttributeId = getAttributeId(parser, encoding, s, next);
+ if (!declAttributeId)
+ return XML_ERROR_NO_MEMORY;
+ declAttributeIsCdata = 0;
+ break;
+ case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
+ declAttributeIsCdata = 1;
+ break;
+ case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
+ case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
+ if (dtd.complete
+ && !defineAttribute(declElementType, declAttributeId, declAttributeIsCdata, 0))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
+ case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
+ {
+ const XML_Char *attVal;
+ enum XML_Error result
+ = storeAttributeValue(parser, encoding, declAttributeIsCdata,
+ s + encoding->minBytesPerChar,
+ next - encoding->minBytesPerChar,
+ &dtd.pool);
+ if (result)
+ return result;
+ attVal = poolStart(&dtd.pool);
+ poolFinish(&dtd.pool);
+ if (dtd.complete
+ && !defineAttribute(declElementType, declAttributeId, declAttributeIsCdata, attVal))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ }
+ case XML_ROLE_ENTITY_VALUE:
+ {
+ enum XML_Error result = storeEntityValue(parser, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ }
+ break;
+ case XML_ROLE_ENTITY_SYSTEM_ID:
+ if (declEntity) {
+ declEntity->systemId = poolStoreString(&dtd.pool, encoding,
+ s + encoding->minBytesPerChar,
+ next - encoding->minBytesPerChar);
+ if (!declEntity->systemId)
+ return XML_ERROR_NO_MEMORY;
+ declEntity->base = dtd.base;
+ poolFinish(&dtd.pool);
+ }
+ break;
+ case XML_ROLE_ENTITY_NOTATION_NAME:
+ if (declEntity) {
+ declEntity->notation = poolStoreString(&dtd.pool, encoding, s, next);
+ if (!declEntity->notation)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&dtd.pool);
+ if (unparsedEntityDeclHandler) {
+ eventPtr = eventEndPtr = s;
+ unparsedEntityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ declEntity->notation);
+ }
+
+ }
+ break;
+ case XML_ROLE_GENERAL_ENTITY_NAME:
+ {
+ const XML_Char *name;
+ if (XmlPredefinedEntityName(encoding, s, next)) {
+ declEntity = 0;
+ break;
+ }
+ name = poolStoreString(&dtd.pool, encoding, s, next);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ if (dtd.complete) {
+ declEntity = (ENTITY *)lookup(&dtd.generalEntities, name, sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ if (declEntity->name != name) {
+ poolDiscard(&dtd.pool);
+ declEntity = 0;
+ }
+ else
+ poolFinish(&dtd.pool);
+ }
+ else {
+ poolDiscard(&dtd.pool);
+ declEntity = 0;
+ }
+ }
+ break;
+ case XML_ROLE_PARAM_ENTITY_NAME:
+ declEntity = 0;
+ break;
+ case XML_ROLE_NOTATION_NAME:
+ declNotationPublicId = 0;
+ declNotationName = 0;
+ if (notationDeclHandler) {
+ declNotationName = poolStoreString(&tempPool, encoding, s, next);
+ if (!declNotationName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ }
+ break;
+ case XML_ROLE_NOTATION_PUBLIC_ID:
+ if (!XmlIsPublicId(encoding, s, next, &eventPtr))
+ return XML_ERROR_SYNTAX;
+ if (declNotationName) {
+ XML_Char *tem = poolStoreString(&tempPool,
+ encoding,
+ s + encoding->minBytesPerChar,
+ next - encoding->minBytesPerChar);
+ if (!tem)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(tem);
+ declNotationPublicId = tem;
+ poolFinish(&tempPool);
+ }
+ break;
+ case XML_ROLE_NOTATION_SYSTEM_ID:
+ if (declNotationName && notationDeclHandler) {
+ const XML_Char *systemId
+ = poolStoreString(&tempPool, encoding,
+ s + encoding->minBytesPerChar,
+ next - encoding->minBytesPerChar);
+ if (!systemId)
+ return XML_ERROR_NO_MEMORY;
+ eventPtr = eventEndPtr = s;
+ notationDeclHandler(handlerArg,
+ declNotationName,
+ dtd.base,
+ systemId,
+ declNotationPublicId);
+ }
+ poolClear(&tempPool);
+ break;
+ case XML_ROLE_NOTATION_NO_SYSTEM_ID:
+ if (declNotationPublicId && notationDeclHandler) {
+ eventPtr = eventEndPtr = s;
+ notationDeclHandler(handlerArg,
+ declNotationName,
+ dtd.base,
+ 0,
+ declNotationPublicId);
+ }
+ poolClear(&tempPool);
+ break;
+ case XML_ROLE_ERROR:
+ eventPtr = s;
+ switch (tok) {
+ case XML_TOK_PARAM_ENTITY_REF:
+ return XML_ERROR_PARAM_ENTITY_REF;
+ case XML_TOK_XML_DECL:
+ return XML_ERROR_MISPLACED_XML_PI;
+ default:
+ return XML_ERROR_SYNTAX;
+ }
+ case XML_ROLE_GROUP_OPEN:
+ if (prologState.level >= groupSize) {
+ if (groupSize)
+ groupConnector = realloc(groupConnector, groupSize *= 2);
+ else
+ groupConnector = malloc(groupSize = 32);
+ if (!groupConnector)
+ return XML_ERROR_NO_MEMORY;
+ }
+ groupConnector[prologState.level] = 0;
+ break;
+ case XML_ROLE_GROUP_SEQUENCE:
+ if (groupConnector[prologState.level] == '|') {
+ eventPtr = s;
+ return XML_ERROR_SYNTAX;
+ }
+ groupConnector[prologState.level] = ',';
+ break;
+ case XML_ROLE_GROUP_CHOICE:
+ if (groupConnector[prologState.level] == ',') {
+ eventPtr = s;
+ return XML_ERROR_SYNTAX;
+ }
+ groupConnector[prologState.level] = '|';
+ break;
+ case XML_ROLE_PARAM_ENTITY_REF:
+ if (!dtd.standalone
+ && notStandaloneHandler
+ && !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ dtd.complete = 0;
+ break;
+ case XML_ROLE_NONE:
+ switch (tok) {
+ case XML_TOK_PI:
+ eventPtr = s;
+ eventEndPtr = next;
+ if (!reportProcessingInstruction(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_COMMENT:
+ eventPtr = s;
+ eventEndPtr = next;
+ if (!reportComment(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ }
+ break;
+ }
+ if (defaultHandler) {
+ switch (tok) {
+ case XML_TOK_PI:
+ case XML_TOK_COMMENT:
+ case XML_TOK_BOM:
+ case XML_TOK_XML_DECL:
+ break;
+ default:
+ eventPtr = s;
+ eventEndPtr = next;
+ reportDefault(parser, encoding, s, next);
+ }
+ }
+ s = next;
+ }
+ /* not reached */
+}
+
+static
+enum XML_Error epilogProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ processor = epilogProcessor;
+ eventPtr = s;
+ for (;;) {
+ const char *next;
+ int tok = XmlPrologTok(encoding, s, end, &next);
+ eventEndPtr = next;
+ switch (tok) {
+ case XML_TOK_TRAILING_CR:
+ if (defaultHandler) {
+ eventEndPtr = end;
+ reportDefault(parser, encoding, s, end);
+ }
+ /* fall through */
+ case XML_TOK_NONE:
+ if (nextPtr)
+ *nextPtr = end;
+ return XML_ERROR_NONE;
+ case XML_TOK_PROLOG_S:
+ if (defaultHandler)
+ reportDefault(parser, encoding, s, next);
+ break;
+ case XML_TOK_PI:
+ if (!reportProcessingInstruction(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_COMMENT:
+ if (!reportComment(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_INVALID:
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (nextPtr) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (nextPtr) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ default:
+ return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
+ }
+ eventPtr = s = next;
+ }
+}
+
+#if 0
+static
+enum XML_Error errorProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ return errorCode;
+}
+#endif
+
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata,
+ const char *ptr, const char *end,
+ STRING_POOL *pool)
+{
+ enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
+ if (result)
+ return result;
+ if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+ poolChop(pool);
+ if (!poolAppendChar(pool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata,
+ const char *ptr, const char *end,
+ STRING_POOL *pool)
+{
+ const ENCODING *internalEnc = ns ? XmlGetInternalEncodingNS() : XmlGetInternalEncoding();
+ for (;;) {
+ const char *next;
+ int tok = XmlAttributeValueTok(enc, ptr, end, &next);
+ switch (tok) {
+ case XML_TOK_NONE:
+ return XML_ERROR_NONE;
+ case XML_TOK_INVALID:
+ if (enc == encoding)
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_CHAR_REF:
+ {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(enc, ptr);
+ if (n < 0) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BAD_CHAR_REF;
+ }
+ if (!isCdata
+ && n == 0x20 /* space */
+ && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ break;
+ n = XmlEncode(n, (ICHAR *)buf);
+ if (!n) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BAD_CHAR_REF;
+ }
+ for (i = 0; i < n; i++) {
+ if (!poolAppendChar(pool, buf[i]))
+ return XML_ERROR_NO_MEMORY;
+ }
+ }
+ break;
+ case XML_TOK_DATA_CHARS:
+ if (!poolAppend(pool, enc, ptr, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ break;
+ case XML_TOK_TRAILING_CR:
+ next = ptr + enc->minBytesPerChar;
+ /* fall through */
+ case XML_TOK_ATTRIBUTE_VALUE_S:
+ case XML_TOK_DATA_NEWLINE:
+ if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ break;
+ if (!poolAppendChar(pool, 0x20))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_ENTITY_REF:
+ {
+ const XML_Char *name;
+ ENTITY *entity;
+ XML_Char ch = XmlPredefinedEntityName(enc,
+ ptr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (ch) {
+ if (!poolAppendChar(pool, ch))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ }
+ name = poolStoreString(&temp2Pool, enc,
+ ptr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0);
+ poolDiscard(&temp2Pool);
+ if (!entity) {
+ if (dtd.complete) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_UNDEFINED_ENTITY;
+ }
+ }
+ else if (entity->open) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ }
+ else if (entity->notation) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BINARY_ENTITY_REF;
+ }
+ else if (!entity->textPtr) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
+ }
+ else {
+ enum XML_Error result;
+ const XML_Char *textEnd = entity->textPtr + entity->textLen;
+ entity->open = 1;
+ result = appendAttributeValue(parser, internalEnc, isCdata, (char *)entity->textPtr, (char *)textEnd, pool);
+ entity->open = 0;
+ if (result)
+ return result;
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+ ptr = next;
+ }
+ /* not reached */
+}
+
+static
+enum XML_Error storeEntityValue(XML_Parser parser,
+ const char *entityTextPtr,
+ const char *entityTextEnd)
+{
+#if 0
+ const ENCODING *internalEnc = ns ? XmlGetInternalEncodingNS() : XmlGetInternalEncoding();
+#endif
+ STRING_POOL *pool = &(dtd.pool);
+ entityTextPtr += encoding->minBytesPerChar;
+ entityTextEnd -= encoding->minBytesPerChar;
+ for (;;) {
+ const char *next;
+ int tok = XmlEntityValueTok(encoding, entityTextPtr, entityTextEnd, &next);
+ switch (tok) {
+ case XML_TOK_PARAM_ENTITY_REF:
+ eventPtr = entityTextPtr;
+ return XML_ERROR_SYNTAX;
+ case XML_TOK_NONE:
+ if (declEntity) {
+ declEntity->textPtr = pool->start;
+ declEntity->textLen = pool->ptr - pool->start;
+ poolFinish(pool);
+ }
+ else
+ poolDiscard(pool);
+ return XML_ERROR_NONE;
+ case XML_TOK_ENTITY_REF:
+ case XML_TOK_DATA_CHARS:
+ if (!poolAppend(pool, encoding, entityTextPtr, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_TRAILING_CR:
+ next = entityTextPtr + encoding->minBytesPerChar;
+ /* fall through */
+ case XML_TOK_DATA_NEWLINE:
+ if (pool->end == pool->ptr && !poolGrow(pool))
+ return XML_ERROR_NO_MEMORY;
+ *(pool->ptr)++ = 0xA;
+ break;
+ case XML_TOK_CHAR_REF:
+ {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(encoding, entityTextPtr);
+ if (n < 0) {
+ eventPtr = entityTextPtr;
+ return XML_ERROR_BAD_CHAR_REF;
+ }
+ n = XmlEncode(n, (ICHAR *)buf);
+ if (!n) {
+ eventPtr = entityTextPtr;
+ return XML_ERROR_BAD_CHAR_REF;
+ }
+ for (i = 0; i < n; i++) {
+ if (pool->end == pool->ptr && !poolGrow(pool))
+ return XML_ERROR_NO_MEMORY;
+ *(pool->ptr)++ = buf[i];
+ }
+ }
+ break;
+ case XML_TOK_PARTIAL:
+ eventPtr = entityTextPtr;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_INVALID:
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ default:
+ abort();
+ }
+ entityTextPtr = next;
+ }
+ /* not reached */
+}
+
+static void
+normalizeLines(XML_Char *s)
+{
+ XML_Char *p;
+ for (;; s++) {
+ if (*s == XML_T('\0'))
+ return;
+ if (*s == 0xD)
+ break;
+ }
+ p = s;
+ do {
+ if (*s == 0xD) {
+ *p++ = 0xA;
+ if (*++s == 0xA)
+ s++;
+ }
+ else
+ *p++ = *s++;
+ } while (*s);
+ *p = XML_T('\0');
+}
+
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end)
+{
+ const XML_Char *target;
+ XML_Char *data;
+ const char *tem;
+ if (!processingInstructionHandler) {
+ if (defaultHandler)
+ reportDefault(parser, enc, start, end);
+ return 1;
+ }
+ start += enc->minBytesPerChar * 2;
+ tem = start + XmlNameLength(enc, start);
+ target = poolStoreString(&tempPool, enc, start, tem);
+ if (!target)
+ return 0;
+ poolFinish(&tempPool);
+ data = poolStoreString(&tempPool, enc,
+ XmlSkipS(enc, tem),
+ end - enc->minBytesPerChar*2);
+ if (!data)
+ return 0;
+ normalizeLines(data);
+ processingInstructionHandler(handlerArg, target, data);
+ poolClear(&tempPool);
+ return 1;
+}
+
+static int
+reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end)
+{
+ XML_Char *data;
+ if (!commentHandler) {
+ if (defaultHandler)
+ reportDefault(parser, enc, start, end);
+ return 1;
+ }
+ data = poolStoreString(&tempPool,
+ enc,
+ start + enc->minBytesPerChar * 4,
+ end - enc->minBytesPerChar * 3);
+ if (!data)
+ return 0;
+ normalizeLines(data);
+ commentHandler(handlerArg, data);
+ poolClear(&tempPool);
+ return 1;
+}
+
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc, const char *s, const char *end)
+{
+ if (MUST_CONVERT(enc, s)) {
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ do {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = s;
+ defaultHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf);
+ *eventPP = s;
+ } while (s != end);
+ }
+ else
+ defaultHandler(handlerArg, (XML_Char *)s, (XML_Char *)end - (XML_Char *)s);
+}
+
+
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, int isCdata, const XML_Char *value)
+{
+ DEFAULT_ATTRIBUTE *att;
+ if (type->nDefaultAtts == type->allocDefaultAtts) {
+ if (type->allocDefaultAtts == 0) {
+ type->allocDefaultAtts = 8;
+ type->defaultAtts = malloc(type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE));
+ }
+ else {
+ type->allocDefaultAtts *= 2;
+ type->defaultAtts = realloc(type->defaultAtts,
+ type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE));
+ }
+ if (!type->defaultAtts)
+ return 0;
+ }
+ att = type->defaultAtts + type->nDefaultAtts;
+ att->id = attId;
+ att->value = value;
+ att->isCdata = isCdata;
+ if (!isCdata)
+ attId->maybeTokenized = 1;
+ type->nDefaultAtts += 1;
+ return 1;
+}
+
+static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
+{
+ const XML_Char *name;
+ for (name = elementType->name; *name; name++) {
+ if (*name == XML_T(':')) {
+ PREFIX *prefix;
+ const XML_Char *s;
+ for (s = elementType->name; s != name; s++) {
+ if (!poolAppendChar(&dtd.pool, *s))
+ return 0;
+ }
+ if (!poolAppendChar(&dtd.pool, XML_T('\0')))
+ return 0;
+ prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX));
+ if (!prefix)
+ return 0;
+ if (prefix->name == poolStart(&dtd.pool))
+ poolFinish(&dtd.pool);
+ else
+ poolDiscard(&dtd.pool);
+ elementType->prefix = prefix;
+
+ }
+ }
+ return 1;
+}
+
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end)
+{
+ ATTRIBUTE_ID *id;
+ const XML_Char *name;
+ if (!poolAppendChar(&dtd.pool, XML_T('\0')))
+ return 0;
+ name = poolStoreString(&dtd.pool, enc, start, end);
+ if (!name)
+ return 0;
+ ++name;
+ id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, name, sizeof(ATTRIBUTE_ID));
+ if (!id)
+ return 0;
+ if (id->name != name)
+ poolDiscard(&dtd.pool);
+ else {
+ poolFinish(&dtd.pool);
+ if (!ns)
+ ;
+ else if (name[0] == 'x'
+ && name[1] == 'm'
+ && name[2] == 'l'
+ && name[3] == 'n'
+ && name[4] == 's'
+ && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) {
+ if (name[5] == '\0')
+ id->prefix = &dtd.defaultPrefix;
+ else
+ id->prefix = (PREFIX *)lookup(&dtd.prefixes, name + 6, sizeof(PREFIX));
+ id->xmlns = 1;
+ }
+ else {
+ int i;
+ for (i = 0; name[i]; i++) {
+ if (name[i] == XML_T(':')) {
+ int j;
+ for (j = 0; j < i; j++) {
+ if (!poolAppendChar(&dtd.pool, name[j]))
+ return 0;
+ }
+ if (!poolAppendChar(&dtd.pool, XML_T('\0')))
+ return 0;
+ id->prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX));
+ if (id->prefix->name == poolStart(&dtd.pool))
+ poolFinish(&dtd.pool);
+ else
+ poolDiscard(&dtd.pool);
+ break;
+ }
+ }
+ }
+ }
+ return id;
+}
+
+#define CONTEXT_SEP XML_T('\f')
+
+static
+const XML_Char *getContext(XML_Parser parser)
+{
+ HASH_TABLE_ITER iter;
+ int needSep = 0;
+
+ if (dtd.defaultPrefix.binding) {
+ int i;
+ int len;
+ if (!poolAppendChar(&tempPool, XML_T('=')))
+ return 0;
+ len = dtd.defaultPrefix.binding->uriLen;
+ if (namespaceSeparator != XML_T('\0'))
+ len--;
+ for (i = 0; i < len; i++)
+ if (!poolAppendChar(&tempPool, dtd.defaultPrefix.binding->uri[i]))
+ return 0;
+ needSep = 1;
+ }
+
+ hashTableIterInit(&iter, &(dtd.prefixes));
+ for (;;) {
+ int i;
+ int len;
+ const XML_Char *s;
+ PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
+ if (!prefix)
+ break;
+ if (!prefix->binding)
+ continue;
+ if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ return 0;
+ for (s = prefix->name; *s; s++)
+ if (!poolAppendChar(&tempPool, *s))
+ return 0;
+ if (!poolAppendChar(&tempPool, XML_T('=')))
+ return 0;
+ len = prefix->binding->uriLen;
+ if (namespaceSeparator != XML_T('\0'))
+ len--;
+ for (i = 0; i < len; i++)
+ if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+ return 0;
+ needSep = 1;
+ }
+
+
+ hashTableIterInit(&iter, &(dtd.generalEntities));
+ for (;;) {
+ const XML_Char *s;
+ ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (!e->open)
+ continue;
+ if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ return 0;
+ for (s = e->name; *s; s++)
+ if (!poolAppendChar(&tempPool, *s))
+ return 0;
+ needSep = 1;
+ }
+
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return 0;
+ return tempPool.start;
+}
+
+static
+int setContext(XML_Parser parser, const XML_Char *context)
+{
+ const XML_Char *s = context;
+
+ while (*context != XML_T('\0')) {
+ if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
+ ENTITY *e;
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return 0;
+ e = (ENTITY *)lookup(&dtd.generalEntities, poolStart(&tempPool), 0);
+ if (e)
+ e->open = 1;
+ if (*s != XML_T('\0'))
+ s++;
+ context = s;
+ poolDiscard(&tempPool);
+ }
+ else if (*s == '=') {
+ PREFIX *prefix;
+ if (poolLength(&tempPool) == 0)
+ prefix = &dtd.defaultPrefix;
+ else {
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return 0;
+ prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&tempPool), sizeof(PREFIX));
+ if (!prefix)
+ return 0;
+ if (prefix->name == poolStart(&tempPool))
+ poolFinish(&tempPool);
+ else
+ poolDiscard(&tempPool);
+ }
+ for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0'); context++)
+ if (!poolAppendChar(&tempPool, *context))
+ return 0;
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return 0;
+ if (!addBinding(parser, prefix, 0, poolStart(&tempPool), &inheritedBindings))
+ return 0;
+ poolDiscard(&tempPool);
+ if (*context != XML_T('\0'))
+ ++context;
+ s = context;
+ }
+ else {
+ if (!poolAppendChar(&tempPool, *s))
+ return 0;
+ s++;
+ }
+ }
+ return 1;
+}
+
+
+static
+void normalizePublicId(XML_Char *publicId)
+{
+ XML_Char *p = publicId;
+ XML_Char *s;
+ for (s = publicId; *s; s++) {
+ switch (*s) {
+ case 0x20:
+ case 0xD:
+ case 0xA:
+ if (p != publicId && p[-1] != 0x20)
+ *p++ = 0x20;
+ break;
+ default:
+ *p++ = *s;
+ }
+ }
+ if (p != publicId && p[-1] == 0x20)
+ --p;
+ *p = XML_T('\0');
+}
+
+static int dtdInit(DTD *p)
+{
+ poolInit(&(p->pool));
+ hashTableInit(&(p->generalEntities));
+ hashTableInit(&(p->elementTypes));
+ hashTableInit(&(p->attributeIds));
+ hashTableInit(&(p->prefixes));
+ p->complete = 1;
+ p->standalone = 0;
+ p->base = 0;
+ p->defaultPrefix.name = 0;
+ p->defaultPrefix.binding = 0;
+ return 1;
+}
+
+static void dtdDestroy(DTD *p)
+{
+ HASH_TABLE_ITER iter;
+ hashTableIterInit(&iter, &(p->elementTypes));
+ for (;;) {
+ ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (e->allocDefaultAtts != 0)
+ free(e->defaultAtts);
+ }
+ hashTableDestroy(&(p->generalEntities));
+ hashTableDestroy(&(p->elementTypes));
+ hashTableDestroy(&(p->attributeIds));
+ hashTableDestroy(&(p->prefixes));
+ poolDestroy(&(p->pool));
+}
+
+/* Do a deep copy of the DTD. Return 0 for out of memory; non-zero otherwise.
+The new DTD has already been initialized. */
+
+static int dtdCopy(DTD *newDtd, const DTD *oldDtd)
+{
+ HASH_TABLE_ITER iter;
+
+ if (oldDtd->base) {
+ const XML_Char *tem = poolCopyString(&(newDtd->pool), oldDtd->base);
+ if (!tem)
+ return 0;
+ newDtd->base = tem;
+ }
+
+ /* Copy the prefix table. */
+
+ hashTableIterInit(&iter, &(oldDtd->prefixes));
+ for (;;) {
+ const XML_Char *name;
+ const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
+ if (!oldP)
+ break;
+ name = poolCopyString(&(newDtd->pool), oldP->name);
+ if (!name)
+ return 0;
+ if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX)))
+ return 0;
+ }
+
+ hashTableIterInit(&iter, &(oldDtd->attributeIds));
+
+ /* Copy the attribute id table. */
+
+ for (;;) {
+ ATTRIBUTE_ID *newA;
+ const XML_Char *name;
+ const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
+
+ if (!oldA)
+ break;
+ /* Remember to allocate the scratch byte before the name. */
+ if (!poolAppendChar(&(newDtd->pool), XML_T('\0')))
+ return 0;
+ name = poolCopyString(&(newDtd->pool), oldA->name);
+ if (!name)
+ return 0;
+ ++name;
+ newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID));
+ if (!newA)
+ return 0;
+ newA->maybeTokenized = oldA->maybeTokenized;
+ if (oldA->prefix) {
+ newA->xmlns = oldA->xmlns;
+ if (oldA->prefix == &oldDtd->defaultPrefix)
+ newA->prefix = &newDtd->defaultPrefix;
+ else
+ newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), oldA->prefix->name, 0);
+ }
+ }
+
+ /* Copy the element type table. */
+
+ hashTableIterInit(&iter, &(oldDtd->elementTypes));
+
+ for (;;) {
+ int i;
+ ELEMENT_TYPE *newE;
+ const XML_Char *name;
+ const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!oldE)
+ break;
+ name = poolCopyString(&(newDtd->pool), oldE->name);
+ if (!name)
+ return 0;
+ newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE));
+ if (!newE)
+ return 0;
+ if (oldE->nDefaultAtts) {
+ newE->defaultAtts = (DEFAULT_ATTRIBUTE *)malloc(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+ if (!newE->defaultAtts)
+ return 0;
+ }
+ newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
+ if (oldE->prefix)
+ newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), oldE->prefix->name, 0);
+ for (i = 0; i < newE->nDefaultAtts; i++) {
+ newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
+ newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
+ if (oldE->defaultAtts[i].value) {
+ newE->defaultAtts[i].value = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
+ if (!newE->defaultAtts[i].value)
+ return 0;
+ }
+ else
+ newE->defaultAtts[i].value = 0;
+ }
+ }
+
+ /* Copy the entity table. */
+
+ hashTableIterInit(&iter, &(oldDtd->generalEntities));
+
+ for (;;) {
+ ENTITY *newE;
+ const XML_Char *name;
+ const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
+ if (!oldE)
+ break;
+ name = poolCopyString(&(newDtd->pool), oldE->name);
+ if (!name)
+ return 0;
+ newE = (ENTITY *)lookup(&(newDtd->generalEntities), name, sizeof(ENTITY));
+ if (!newE)
+ return 0;
+ if (oldE->systemId) {
+ const XML_Char *tem = poolCopyString(&(newDtd->pool), oldE->systemId);
+ if (!tem)
+ return 0;
+ newE->systemId = tem;
+ if (oldE->base) {
+ if (oldE->base == oldDtd->base)
+ newE->base = newDtd->base;
+ tem = poolCopyString(&(newDtd->pool), oldE->base);
+ if (!tem)
+ return 0;
+ newE->base = tem;
+ }
+ }
+ else {
+ const XML_Char *tem = poolCopyStringN(&(newDtd->pool), oldE->textPtr, oldE->textLen);
+ if (!tem)
+ return 0;
+ newE->textPtr = tem;
+ newE->textLen = oldE->textLen;
+ }
+ if (oldE->notation) {
+ const XML_Char *tem = poolCopyString(&(newDtd->pool), oldE->notation);
+ if (!tem)
+ return 0;
+ newE->notation = tem;
+ }
+ }
+
+ newDtd->complete = oldDtd->complete;
+ newDtd->standalone = oldDtd->standalone;
+ return 1;
+}
+
+static
+void poolInit(STRING_POOL *pool)
+{
+ pool->blocks = 0;
+ pool->freeBlocks = 0;
+ pool->start = 0;
+ pool->ptr = 0;
+ pool->end = 0;
+}
+
+static
+void poolClear(STRING_POOL *pool)
+{
+ if (!pool->freeBlocks)
+ pool->freeBlocks = pool->blocks;
+ else {
+ BLOCK *p = pool->blocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ p->next = pool->freeBlocks;
+ pool->freeBlocks = p;
+ p = tem;
+ }
+ }
+ pool->blocks = 0;
+ pool->start = 0;
+ pool->ptr = 0;
+ pool->end = 0;
+}
+
+static
+void poolDestroy(STRING_POOL *pool)
+{
+ BLOCK *p = pool->blocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ free(p);
+ p = tem;
+ }
+ pool->blocks = 0;
+ p = pool->freeBlocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ free(p);
+ p = tem;
+ }
+ pool->freeBlocks = 0;
+ pool->ptr = 0;
+ pool->start = 0;
+ pool->end = 0;
+}
+
+static
+XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end)
+{
+ if (!pool->ptr && !poolGrow(pool))
+ return 0;
+ for (;;) {
+ XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+ if (ptr == end)
+ break;
+ if (!poolGrow(pool))
+ return 0;
+ }
+ return pool->start;
+}
+
+static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s)
+{
+ do {
+ if (!poolAppendChar(pool, *s))
+ return 0;
+ } while (*s++);
+ s = pool->start;
+ poolFinish(pool);
+ return s;
+}
+
+static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
+{
+ if (!pool->ptr && !poolGrow(pool))
+ return 0;
+ for (; n > 0; --n, s++) {
+ if (!poolAppendChar(pool, *s))
+ return 0;
+
+ }
+ s = pool->start;
+ poolFinish(pool);
+ return s;
+}
+
+static
+XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end)
+{
+ if (!poolAppend(pool, enc, ptr, end))
+ return 0;
+ if (pool->ptr == pool->end && !poolGrow(pool))
+ return 0;
+ *(pool->ptr)++ = 0;
+ return pool->start;
+}
+
+static
+int poolGrow(STRING_POOL *pool)
+{
+ if (pool->freeBlocks) {
+ if (pool->start == 0) {
+ pool->blocks = pool->freeBlocks;
+ pool->freeBlocks = pool->freeBlocks->next;
+ pool->blocks->next = 0;
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + pool->blocks->size;
+ pool->ptr = pool->start;
+ return 1;
+ }
+ if (pool->end - pool->start < pool->freeBlocks->size) {
+ BLOCK *tem = pool->freeBlocks->next;
+ pool->freeBlocks->next = pool->blocks;
+ pool->blocks = pool->freeBlocks;
+ pool->freeBlocks = tem;
+ memcpy(pool->blocks->s, pool->start, (pool->end - pool->start) * sizeof(XML_Char));
+ pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + pool->blocks->size;
+ return 1;
+ }
+ }
+ if (pool->blocks && pool->start == pool->blocks->s) {
+ int blockSize = (pool->end - pool->start)*2;
+ pool->blocks = realloc(pool->blocks, offsetof(BLOCK, s) + blockSize * sizeof(XML_Char));
+ if (!pool->blocks)
+ return 0;
+ pool->blocks->size = blockSize;
+ pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + blockSize;
+ }
+ else {
+ BLOCK *tem;
+ int blockSize = pool->end - pool->start;
+ if (blockSize < INIT_BLOCK_SIZE)
+ blockSize = INIT_BLOCK_SIZE;
+ else
+ blockSize *= 2;
+ tem = malloc(offsetof(BLOCK, s) + blockSize * sizeof(XML_Char));
+ if (!tem)
+ return 0;
+ tem->size = blockSize;
+ tem->next = pool->blocks;
+ pool->blocks = tem;
+ memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char));
+ pool->ptr = tem->s + (pool->ptr - pool->start);
+ pool->start = tem->s;
+ pool->end = tem->s + blockSize;
+ }
+ return 1;
+}
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmlparse.h b/usr.sbin/httpd/src/lib/expat-lite/xmlparse.h
new file mode 100644
index 00000000000..f2f9c9be1c0
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmlparse.h
@@ -0,0 +1,482 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+#ifndef XmlParse_INCLUDED
+#define XmlParse_INCLUDED 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XMLPARSEAPI
+#define XMLPARSEAPI /* as nothing */
+#endif
+
+typedef void *XML_Parser;
+
+#ifdef XML_UNICODE_WCHAR_T
+
+/* XML_UNICODE_WCHAR_T will work only if sizeof(wchar_t) == 2 and wchar_t
+uses Unicode. */
+/* Information is UTF-16 encoded as wchar_ts */
+
+#ifndef XML_UNICODE
+#define XML_UNICODE
+#endif
+
+#include <stddef.h>
+typedef wchar_t XML_Char;
+typedef wchar_t XML_LChar;
+
+#else /* not XML_UNICODE_WCHAR_T */
+
+#ifdef XML_UNICODE
+
+/* Information is UTF-16 encoded as unsigned shorts */
+typedef unsigned short XML_Char;
+typedef char XML_LChar;
+
+#else /* not XML_UNICODE */
+
+/* Information is UTF-8 encoded. */
+typedef char XML_Char;
+typedef char XML_LChar;
+
+#endif /* not XML_UNICODE */
+
+#endif /* not XML_UNICODE_WCHAR_T */
+
+
+/* Constructs a new parser; encoding is the encoding specified by the external
+protocol or null if there is none specified. */
+
+XML_Parser XMLPARSEAPI
+XML_ParserCreate(const XML_Char *encoding);
+
+/* Constructs a new parser and namespace processor. Element type names
+and attribute names that belong to a namespace will be expanded;
+unprefixed attribute names are never expanded; unprefixed element type
+names are expanded only if there is a default namespace. The expanded
+name is the concatenation of the namespace URI, the namespace separator character,
+and the local part of the name. If the namespace separator is '\0' then
+the namespace URI and the local part will be concatenated without any
+separator. When a namespace is not declared, the name and prefix will be
+passed through without expansion. */
+
+XML_Parser XMLPARSEAPI
+XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
+
+
+/* atts is array of name/value pairs, terminated by 0;
+ names and values are 0 terminated. */
+
+typedef void (*XML_StartElementHandler)(void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+typedef void (*XML_EndElementHandler)(void *userData,
+ const XML_Char *name);
+
+/* s is not 0 terminated. */
+typedef void (*XML_CharacterDataHandler)(void *userData,
+ const XML_Char *s,
+ int len);
+
+/* target and data are 0 terminated */
+typedef void (*XML_ProcessingInstructionHandler)(void *userData,
+ const XML_Char *target,
+ const XML_Char *data);
+
+/* data is 0 terminated */
+typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data);
+
+typedef void (*XML_StartCdataSectionHandler)(void *userData);
+typedef void (*XML_EndCdataSectionHandler)(void *userData);
+
+/* This is called for any characters in the XML document for
+which there is no applicable handler. This includes both
+characters that are part of markup which is of a kind that is
+not reported (comments, markup declarations), or characters
+that are part of a construct which could be reported but
+for which no handler has been supplied. The characters are passed
+exactly as they were in the XML document except that
+they will be encoded in UTF-8. Line boundaries are not normalized.
+Note that a byte order mark character is not passed to the default handler.
+There are no guarantees about how characters are divided between calls
+to the default handler: for example, a comment might be split between
+multiple calls. */
+
+typedef void (*XML_DefaultHandler)(void *userData,
+ const XML_Char *s,
+ int len);
+
+/* This is called for a declaration of an unparsed (NDATA)
+entity. The base argument is whatever was set by XML_SetBase.
+The entityName, systemId and notationName arguments will never be null.
+The other arguments may be. */
+
+typedef void (*XML_UnparsedEntityDeclHandler)(void *userData,
+ const XML_Char *entityName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName);
+
+/* This is called for a declaration of notation.
+The base argument is whatever was set by XML_SetBase.
+The notationName will never be null. The other arguments can be. */
+
+typedef void (*XML_NotationDeclHandler)(void *userData,
+ const XML_Char *notationName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* When namespace processing is enabled, these are called once for
+each namespace declaration. The call to the start and end element
+handlers occur between the calls to the start and end namespace
+declaration handlers. For an xmlns attribute, prefix will be null.
+For an xmlns="" attribute, uri will be null. */
+
+typedef void (*XML_StartNamespaceDeclHandler)(void *userData,
+ const XML_Char *prefix,
+ const XML_Char *uri);
+
+typedef void (*XML_EndNamespaceDeclHandler)(void *userData,
+ const XML_Char *prefix);
+
+/* This is called if the document is not standalone (it has an
+external subset or a reference to a parameter entity, but does not
+have standalone="yes"). If this handler returns 0, then processing
+will not continue, and the parser will return a
+XML_ERROR_NOT_STANDALONE error. */
+
+typedef int (*XML_NotStandaloneHandler)(void *userData);
+
+/* This is called for a reference to an external parsed general entity.
+The referenced entity is not automatically parsed.
+The application can parse it immediately or later using
+XML_ExternalEntityParserCreate.
+The parser argument is the parser parsing the entity containing the reference;
+it can be passed as the parser argument to XML_ExternalEntityParserCreate.
+The systemId argument is the system identifier as specified in the entity declaration;
+it will not be null.
+The base argument is the system identifier that should be used as the base for
+resolving systemId if systemId was relative; this is set by XML_SetBase;
+it may be null.
+The publicId argument is the public identifier as specified in the entity declaration,
+or null if none was specified; the whitespace in the public identifier
+will have been normalized as required by the XML spec.
+The context argument specifies the parsing context in the format
+expected by the context argument to
+XML_ExternalEntityParserCreate; context is valid only until the handler
+returns, so if the referenced entity is to be parsed later, it must be copied.
+The handler should return 0 if processing should not continue because of
+a fatal error in the handling of the external entity.
+In this case the calling parser will return an XML_ERROR_EXTERNAL_ENTITY_HANDLING
+error.
+Note that unlike other handlers the first argument is the parser, not userData. */
+
+typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* This structure is filled in by the XML_UnknownEncodingHandler
+to provide information to the parser about encodings that are unknown
+to the parser.
+The map[b] member gives information about byte sequences
+whose first byte is b.
+If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar value c.
+If map[b] is -1, then the byte sequence is malformed.
+If map[b] is -n, where n >= 2, then b is the first byte of an n-byte
+sequence that encodes a single Unicode scalar value.
+The data member will be passed as the first argument to the convert function.
+The convert function is used to convert multibyte sequences;
+s will point to a n-byte sequence where map[(unsigned char)*s] == -n.
+The convert function must return the Unicode scalar value
+represented by this byte sequence or -1 if the byte sequence is malformed.
+The convert function may be null if the encoding is a single-byte encoding,
+that is if map[b] >= -1 for all bytes b.
+When the parser is finished with the encoding, then if release is not null,
+it will call release passing it the data member;
+once release has been called, the convert function will not be called again.
+
+Expat places certain restrictions on the encodings that are supported
+using this mechanism.
+
+1. Every ASCII character that can appear in a well-formed XML document,
+other than the characters
+
+ $@\^`{}~
+
+must be represented by a single byte, and that byte must be the
+same byte that represents that character in ASCII.
+
+2. No character may require more than 4 bytes to encode.
+
+3. All characters encoded must have Unicode scalar values <= 0xFFFF,
+(ie characters that would be encoded by surrogates in UTF-16
+are not allowed). Note that this restriction doesn't apply to
+the built-in support for UTF-8 and UTF-16.
+
+4. No Unicode character may be encoded by more than one distinct sequence
+of bytes. */
+
+typedef struct {
+ int map[256];
+ void *data;
+ int (*convert)(void *data, const char *s);
+ void (*release)(void *data);
+} XML_Encoding;
+
+/* This is called for an encoding that is unknown to the parser.
+The encodingHandlerData argument is that which was passed as the
+second argument to XML_SetUnknownEncodingHandler.
+The name argument gives the name of the encoding as specified in
+the encoding declaration.
+If the callback can provide information about the encoding,
+it must fill in the XML_Encoding structure, and return 1.
+Otherwise it must return 0.
+If info does not describe a suitable encoding,
+then the parser will return an XML_UNKNOWN_ENCODING error. */
+
+typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData,
+ const XML_Char *name,
+ XML_Encoding *info);
+
+void XMLPARSEAPI
+XML_SetElementHandler(XML_Parser parser,
+ XML_StartElementHandler start,
+ XML_EndElementHandler end);
+
+void XMLPARSEAPI
+XML_SetCharacterDataHandler(XML_Parser parser,
+ XML_CharacterDataHandler handler);
+
+void XMLPARSEAPI
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+ XML_ProcessingInstructionHandler handler);
+void XMLPARSEAPI
+XML_SetCommentHandler(XML_Parser parser,
+ XML_CommentHandler handler);
+
+void XMLPARSEAPI
+XML_SetCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start,
+ XML_EndCdataSectionHandler end);
+
+/* This sets the default handler and also inhibits expansion of internal entities.
+The entity reference will be passed to the default handler. */
+
+void XMLPARSEAPI
+XML_SetDefaultHandler(XML_Parser parser,
+ XML_DefaultHandler handler);
+
+/* This sets the default handler but does not inhibit expansion of internal entities.
+The entity reference will not be passed to the default handler. */
+
+void XMLPARSEAPI
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+ XML_DefaultHandler handler);
+
+void XMLPARSEAPI
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+ XML_UnparsedEntityDeclHandler handler);
+
+void XMLPARSEAPI
+XML_SetNotationDeclHandler(XML_Parser parser,
+ XML_NotationDeclHandler handler);
+
+void XMLPARSEAPI
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start,
+ XML_EndNamespaceDeclHandler end);
+
+void XMLPARSEAPI
+XML_SetNotStandaloneHandler(XML_Parser parser,
+ XML_NotStandaloneHandler handler);
+
+void XMLPARSEAPI
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+ XML_ExternalEntityRefHandler handler);
+
+/* If a non-null value for arg is specified here, then it will be passed
+as the first argument to the external entity ref handler instead
+of the parser object. */
+void XMLPARSEAPI
+XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg);
+
+void XMLPARSEAPI
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+ XML_UnknownEncodingHandler handler,
+ void *encodingHandlerData);
+
+/* This can be called within a handler for a start element, end element,
+processing instruction or character data. It causes the corresponding
+markup to be passed to the default handler. */
+void XMLPARSEAPI XML_DefaultCurrent(XML_Parser parser);
+
+/* This value is passed as the userData argument to callbacks. */
+void XMLPARSEAPI
+XML_SetUserData(XML_Parser parser, void *userData);
+
+/* Returns the last value set by XML_SetUserData or null. */
+#define XML_GetUserData(parser) (*(void **)(parser))
+
+/* This is equivalent to supplying an encoding argument
+to XML_CreateParser. It must not be called after XML_Parse
+or XML_ParseBuffer. */
+
+int XMLPARSEAPI
+XML_SetEncoding(XML_Parser parser, const XML_Char *encoding);
+
+/* If this function is called, then the parser will be passed
+as the first argument to callbacks instead of userData.
+The userData will still be accessible using XML_GetUserData. */
+
+void XMLPARSEAPI
+XML_UseParserAsHandlerArg(XML_Parser parser);
+
+/* Sets the base to be used for resolving relative URIs in system identifiers in
+declarations. Resolving relative identifiers is left to the application:
+this value will be passed through as the base argument to the
+XML_ExternalEntityRefHandler, XML_NotationDeclHandler
+and XML_UnparsedEntityDeclHandler. The base argument will be copied.
+Returns zero if out of memory, non-zero otherwise. */
+
+int XMLPARSEAPI
+XML_SetBase(XML_Parser parser, const XML_Char *base);
+
+const XML_Char XMLPARSEAPI *
+XML_GetBase(XML_Parser parser);
+
+/* Returns the number of the attributes passed in last call to the
+XML_StartElementHandler that were specified in the start-tag rather
+than defaulted. */
+
+int XMLPARSEAPI XML_GetSpecifiedAttributeCount(XML_Parser parser);
+
+/* Parses some input. Returns 0 if a fatal error is detected.
+The last call to XML_Parse must have isFinal true;
+len may be zero for this call (or any other). */
+int XMLPARSEAPI
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal);
+
+void XMLPARSEAPI *
+XML_GetBuffer(XML_Parser parser, int len);
+
+int XMLPARSEAPI
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
+
+/* Creates an XML_Parser object that can parse an external general entity;
+context is a '\0'-terminated string specifying the parse context;
+encoding is a '\0'-terminated string giving the name of the externally specified encoding,
+or null if there is no externally specified encoding.
+The context string consists of a sequence of tokens separated by formfeeds (\f);
+a token consisting of a name specifies that the general entity of the name
+is open; a token of the form prefix=uri specifies the namespace for a particular
+prefix; a token of the form =uri specifies the default namespace.
+This can be called at any point after the first call to an ExternalEntityRefHandler
+so longer as the parser has not yet been freed.
+The new parser is completely independent and may safely be used in a separate thread.
+The handlers and userData are initialized from the parser argument.
+Returns 0 if out of memory. Otherwise returns a new XML_Parser object. */
+XML_Parser XMLPARSEAPI
+XML_ExternalEntityParserCreate(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *encoding);
+
+enum XML_Error {
+ XML_ERROR_NONE,
+ XML_ERROR_NO_MEMORY,
+ XML_ERROR_SYNTAX,
+ XML_ERROR_NO_ELEMENTS,
+ XML_ERROR_INVALID_TOKEN,
+ XML_ERROR_UNCLOSED_TOKEN,
+ XML_ERROR_PARTIAL_CHAR,
+ XML_ERROR_TAG_MISMATCH,
+ XML_ERROR_DUPLICATE_ATTRIBUTE,
+ XML_ERROR_JUNK_AFTER_DOC_ELEMENT,
+ XML_ERROR_PARAM_ENTITY_REF,
+ XML_ERROR_UNDEFINED_ENTITY,
+ XML_ERROR_RECURSIVE_ENTITY_REF,
+ XML_ERROR_ASYNC_ENTITY,
+ XML_ERROR_BAD_CHAR_REF,
+ XML_ERROR_BINARY_ENTITY_REF,
+ XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF,
+ XML_ERROR_MISPLACED_XML_PI,
+ XML_ERROR_UNKNOWN_ENCODING,
+ XML_ERROR_INCORRECT_ENCODING,
+ XML_ERROR_UNCLOSED_CDATA_SECTION,
+ XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ XML_ERROR_NOT_STANDALONE
+};
+
+/* If XML_Parse or XML_ParseBuffer have returned 0, then XML_GetErrorCode
+returns information about the error. */
+
+enum XML_Error XMLPARSEAPI XML_GetErrorCode(XML_Parser parser);
+
+/* These functions return information about the current parse location.
+They may be called when XML_Parse or XML_ParseBuffer return 0;
+in this case the location is the location of the character at which
+the error was detected.
+They may also be called from any other callback called to report
+some parse event; in this the location is the location of the first
+of the sequence of characters that generated the event. */
+
+int XMLPARSEAPI XML_GetCurrentLineNumber(XML_Parser parser);
+int XMLPARSEAPI XML_GetCurrentColumnNumber(XML_Parser parser);
+long XMLPARSEAPI XML_GetCurrentByteIndex(XML_Parser parser);
+
+/* Return the number of bytes in the current event.
+Returns 0 if the event is in an internal entity. */
+
+int XMLPARSEAPI XML_GetCurrentByteCount(XML_Parser parser);
+
+/* For backwards compatibility with previous versions. */
+#define XML_GetErrorLineNumber XML_GetCurrentLineNumber
+#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
+#define XML_GetErrorByteIndex XML_GetCurrentByteIndex
+
+/* Frees memory used by the parser. */
+void XMLPARSEAPI
+XML_ParserFree(XML_Parser parser);
+
+/* Returns a string describing the error. */
+const XML_LChar XMLPARSEAPI *XML_ErrorString(int code);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlParse_INCLUDED */
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmlrole.c b/usr.sbin/httpd/src/lib/expat-lite/xmlrole.c
new file mode 100644
index 00000000000..b18e35eb3c4
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmlrole.c
@@ -0,0 +1,1113 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+#include "xmldef.h"
+#include "xmlrole.h"
+
+/* Doesn't check:
+
+ that ,| are not mixed in a model group
+ content of literals
+
+*/
+
+#ifndef MIN_BYTES_PER_CHAR
+#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar)
+#endif
+
+typedef int PROLOG_HANDLER(struct prolog_state *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc);
+
+static PROLOG_HANDLER
+ prolog0, prolog1, prolog2,
+ doctype0, doctype1, doctype2, doctype3, doctype4, doctype5,
+ internalSubset,
+ entity0, entity1, entity2, entity3, entity4, entity5, entity6,
+ entity7, entity8, entity9,
+ notation0, notation1, notation2, notation3, notation4,
+ attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6,
+ attlist7, attlist8, attlist9,
+ element0, element1, element2, element3, element4, element5, element6,
+ element7,
+ declClose,
+ error;
+
+static
+int syntaxError(PROLOG_STATE *);
+
+static
+int prolog0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ state->handler = prolog1;
+ return XML_ROLE_NONE;
+ case XML_TOK_XML_DECL:
+ state->handler = prolog1;
+ return XML_ROLE_XML_DECL;
+ case XML_TOK_PI:
+ state->handler = prolog1;
+ return XML_ROLE_NONE;
+ case XML_TOK_COMMENT:
+ state->handler = prolog1;
+ case XML_TOK_BOM:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (!XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ "DOCTYPE"))
+ break;
+ state->handler = doctype0;
+ return XML_ROLE_NONE;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return syntaxError(state);
+}
+
+static
+int prolog1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_PI:
+ case XML_TOK_COMMENT:
+ case XML_TOK_BOM:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (!XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ "DOCTYPE"))
+ break;
+ state->handler = doctype0;
+ return XML_ROLE_NONE;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return syntaxError(state);
+}
+
+static
+int prolog2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_PI:
+ case XML_TOK_COMMENT:
+ return XML_ROLE_NONE;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return syntaxError(state);
+}
+
+static
+int doctype0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = doctype1;
+ return XML_ROLE_DOCTYPE_NAME;
+ }
+ return syntaxError(state);
+}
+
+static
+int doctype1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = internalSubset;
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) {
+ state->handler = doctype3;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) {
+ state->handler = doctype2;
+ return XML_ROLE_NONE;
+ }
+ break;
+ }
+ return syntaxError(state);
+}
+
+static
+int doctype2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = doctype3;
+ return XML_ROLE_DOCTYPE_PUBLIC_ID;
+ }
+ return syntaxError(state);
+}
+
+static
+int doctype3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = doctype4;
+ return XML_ROLE_DOCTYPE_SYSTEM_ID;
+ }
+ return syntaxError(state);
+}
+
+static
+int doctype4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = internalSubset;
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ }
+ return syntaxError(state);
+}
+
+static
+int doctype5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ }
+ return syntaxError(state);
+}
+
+static
+int internalSubset(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ "ENTITY")) {
+ state->handler = entity0;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ "ATTLIST")) {
+ state->handler = attlist0;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ "ELEMENT")) {
+ state->handler = element0;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ "NOTATION")) {
+ state->handler = notation0;
+ return XML_ROLE_NONE;
+ }
+ break;
+ case XML_TOK_PI:
+ case XML_TOK_COMMENT:
+ return XML_ROLE_NONE;
+ case XML_TOK_PARAM_ENTITY_REF:
+ return XML_ROLE_PARAM_ENTITY_REF;
+ case XML_TOK_CLOSE_BRACKET:
+ state->handler = doctype5;
+ return XML_ROLE_NONE;
+ }
+ return syntaxError(state);
+}
+
+static
+int entity0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_PERCENT:
+ state->handler = entity1;
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ state->handler = entity2;
+ return XML_ROLE_GENERAL_ENTITY_NAME;
+ }
+ return syntaxError(state);
+}
+
+static
+int entity1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ state->handler = entity7;
+ return XML_ROLE_PARAM_ENTITY_NAME;
+ }
+ return syntaxError(state);
+}
+
+static
+int entity2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) {
+ state->handler = entity4;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) {
+ state->handler = entity3;
+ return XML_ROLE_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ return XML_ROLE_ENTITY_VALUE;
+ }
+ return syntaxError(state);
+}
+
+static
+int entity3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity4;
+ return XML_ROLE_ENTITY_PUBLIC_ID;
+ }
+ return syntaxError(state);
+}
+
+
+static
+int entity4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity5;
+ return XML_ROLE_ENTITY_SYSTEM_ID;
+ }
+ return syntaxError(state);
+}
+
+static
+int entity5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = internalSubset;
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, "NDATA")) {
+ state->handler = entity6;
+ return XML_ROLE_NONE;
+ }
+ break;
+ }
+ return syntaxError(state);
+}
+
+static
+int entity6(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ state->handler = declClose;
+ return XML_ROLE_ENTITY_NOTATION_NAME;
+ }
+ return syntaxError(state);
+}
+
+static
+int entity7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) {
+ state->handler = entity9;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) {
+ state->handler = entity8;
+ return XML_ROLE_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ return XML_ROLE_ENTITY_VALUE;
+ }
+ return syntaxError(state);
+}
+
+static
+int entity8(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity9;
+ return XML_ROLE_ENTITY_PUBLIC_ID;
+ }
+ return syntaxError(state);
+}
+
+static
+int entity9(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ return XML_ROLE_ENTITY_SYSTEM_ID;
+ }
+ return syntaxError(state);
+}
+
+static
+int notation0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ state->handler = notation1;
+ return XML_ROLE_NOTATION_NAME;
+ }
+ return syntaxError(state);
+}
+
+static
+int notation1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) {
+ state->handler = notation3;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) {
+ state->handler = notation2;
+ return XML_ROLE_NONE;
+ }
+ break;
+ }
+ return syntaxError(state);
+}
+
+static
+int notation2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = notation4;
+ return XML_ROLE_NOTATION_PUBLIC_ID;
+ }
+ return syntaxError(state);
+}
+
+static
+int notation3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ return XML_ROLE_NOTATION_SYSTEM_ID;
+ }
+ return syntaxError(state);
+}
+
+static
+int notation4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ return XML_ROLE_NOTATION_SYSTEM_ID;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = internalSubset;
+ return XML_ROLE_NOTATION_NO_SYSTEM_ID;
+ }
+ return syntaxError(state);
+}
+
+static
+int attlist0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist1;
+ return XML_ROLE_ATTLIST_ELEMENT_NAME;
+ }
+ return syntaxError(state);
+}
+
+static
+int attlist1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = internalSubset;
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist2;
+ return XML_ROLE_ATTRIBUTE_NAME;
+ }
+ return syntaxError(state);
+}
+
+static
+int attlist2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ {
+ static const char *types[] = {
+ "CDATA",
+ "ID",
+ "IDREF",
+ "IDREFS",
+ "ENTITY",
+ "ENTITIES",
+ "NMTOKEN",
+ "NMTOKENS",
+ };
+ int i;
+ for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++)
+ if (XmlNameMatchesAscii(enc, ptr, types[i])) {
+ state->handler = attlist8;
+ return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i;
+ }
+ }
+ if (XmlNameMatchesAscii(enc, ptr, "NOTATION")) {
+ state->handler = attlist5;
+ return XML_ROLE_NONE;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = attlist3;
+ return XML_ROLE_NONE;
+ }
+ return syntaxError(state);
+}
+
+static
+int attlist3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NMTOKEN:
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist4;
+ return XML_ROLE_ATTRIBUTE_ENUM_VALUE;
+ }
+ return syntaxError(state);
+}
+
+static
+int attlist4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = attlist8;
+ return XML_ROLE_NONE;
+ case XML_TOK_OR:
+ state->handler = attlist3;
+ return XML_ROLE_NONE;
+ }
+ return syntaxError(state);
+}
+
+static
+int attlist5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = attlist6;
+ return XML_ROLE_NONE;
+ }
+ return syntaxError(state);
+}
+
+
+static
+int attlist6(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ state->handler = attlist7;
+ return XML_ROLE_ATTRIBUTE_NOTATION_VALUE;
+ }
+ return syntaxError(state);
+}
+
+static
+int attlist7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = attlist8;
+ return XML_ROLE_NONE;
+ case XML_TOK_OR:
+ state->handler = attlist6;
+ return XML_ROLE_NONE;
+ }
+ return syntaxError(state);
+}
+
+/* default value */
+static
+int attlist8(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_POUND_NAME:
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ "IMPLIED")) {
+ state->handler = attlist1;
+ return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ "REQUIRED")) {
+ state->handler = attlist1;
+ return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ "FIXED")) {
+ state->handler = attlist9;
+ return XML_ROLE_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = attlist1;
+ return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE;
+ }
+ return syntaxError(state);
+}
+
+static
+int attlist9(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = attlist1;
+ return XML_ROLE_FIXED_ATTRIBUTE_VALUE;
+ }
+ return syntaxError(state);
+}
+
+static
+int element0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element1;
+ return XML_ROLE_ELEMENT_NAME;
+ }
+ return syntaxError(state);
+}
+
+static
+int element1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, "EMPTY")) {
+ state->handler = declClose;
+ return XML_ROLE_CONTENT_EMPTY;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, "ANY")) {
+ state->handler = declClose;
+ return XML_ROLE_CONTENT_ANY;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = element2;
+ state->level = 1;
+ return XML_ROLE_GROUP_OPEN;
+ }
+ return syntaxError(state);
+}
+
+static
+int element2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_POUND_NAME:
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ "PCDATA")) {
+ state->handler = element3;
+ return XML_ROLE_CONTENT_PCDATA;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->level = 2;
+ state->handler = element6;
+ return XML_ROLE_GROUP_OPEN;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT;
+ case XML_TOK_NAME_QUESTION:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_OPT;
+ case XML_TOK_NAME_ASTERISK:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_REP;
+ case XML_TOK_NAME_PLUS:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_PLUS;
+ }
+ return syntaxError(state);
+}
+
+static
+int element3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->handler = declClose;
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_OR:
+ state->handler = element4;
+ return XML_ROLE_NONE;
+ }
+ return syntaxError(state);
+}
+
+static
+int element4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element5;
+ return XML_ROLE_CONTENT_ELEMENT;
+ }
+ return syntaxError(state);
+}
+
+static
+int element5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->handler = declClose;
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_OR:
+ state->handler = element4;
+ return XML_ROLE_NONE;
+ }
+ return syntaxError(state);
+}
+
+static
+int element6(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_PAREN:
+ state->level += 1;
+ return XML_ROLE_GROUP_OPEN;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT;
+ case XML_TOK_NAME_QUESTION:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_OPT;
+ case XML_TOK_NAME_ASTERISK:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_REP;
+ case XML_TOK_NAME_PLUS:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_PLUS;
+ }
+ return syntaxError(state);
+}
+
+static
+int element7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->level -= 1;
+ if (state->level == 0)
+ state->handler = declClose;
+ return XML_ROLE_GROUP_CLOSE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->level -= 1;
+ if (state->level == 0)
+ state->handler = declClose;
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_CLOSE_PAREN_QUESTION:
+ state->level -= 1;
+ if (state->level == 0)
+ state->handler = declClose;
+ return XML_ROLE_GROUP_CLOSE_OPT;
+ case XML_TOK_CLOSE_PAREN_PLUS:
+ state->level -= 1;
+ if (state->level == 0)
+ state->handler = declClose;
+ return XML_ROLE_GROUP_CLOSE_PLUS;
+ case XML_TOK_COMMA:
+ state->handler = element6;
+ return XML_ROLE_GROUP_SEQUENCE;
+ case XML_TOK_OR:
+ state->handler = element6;
+ return XML_ROLE_GROUP_CHOICE;
+ }
+ return syntaxError(state);
+}
+
+static
+int declClose(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = internalSubset;
+ return XML_ROLE_NONE;
+ }
+ return syntaxError(state);
+}
+
+#if 0
+
+static
+int ignore(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_DECL_CLOSE:
+ state->handler = internalSubset;
+ return 0;
+ default:
+ return XML_ROLE_NONE;
+ }
+ return syntaxError(state);
+}
+#endif
+
+static
+int error(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ return XML_ROLE_NONE;
+}
+
+static
+int syntaxError(PROLOG_STATE *state)
+{
+ state->handler = error;
+ return XML_ROLE_ERROR;
+}
+
+void XmlPrologStateInit(PROLOG_STATE *state)
+{
+ state->handler = prolog0;
+}
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmlrole.h b/usr.sbin/httpd/src/lib/expat-lite/xmlrole.h
new file mode 100644
index 00000000000..877c40ba1f8
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmlrole.h
@@ -0,0 +1,111 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+#ifndef XmlRole_INCLUDED
+#define XmlRole_INCLUDED 1
+
+#include "xmltok.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ XML_ROLE_ERROR = -1,
+ XML_ROLE_NONE = 0,
+ XML_ROLE_XML_DECL,
+ XML_ROLE_INSTANCE_START,
+ XML_ROLE_DOCTYPE_NAME,
+ XML_ROLE_DOCTYPE_SYSTEM_ID,
+ XML_ROLE_DOCTYPE_PUBLIC_ID,
+ XML_ROLE_DOCTYPE_CLOSE,
+ XML_ROLE_GENERAL_ENTITY_NAME,
+ XML_ROLE_PARAM_ENTITY_NAME,
+ XML_ROLE_ENTITY_VALUE,
+ XML_ROLE_ENTITY_SYSTEM_ID,
+ XML_ROLE_ENTITY_PUBLIC_ID,
+ XML_ROLE_ENTITY_NOTATION_NAME,
+ XML_ROLE_NOTATION_NAME,
+ XML_ROLE_NOTATION_SYSTEM_ID,
+ XML_ROLE_NOTATION_NO_SYSTEM_ID,
+ XML_ROLE_NOTATION_PUBLIC_ID,
+ XML_ROLE_ATTRIBUTE_NAME,
+ XML_ROLE_ATTRIBUTE_TYPE_CDATA,
+ XML_ROLE_ATTRIBUTE_TYPE_ID,
+ XML_ROLE_ATTRIBUTE_TYPE_IDREF,
+ XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
+ XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
+ XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
+ XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
+ XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
+ XML_ROLE_ATTRIBUTE_ENUM_VALUE,
+ XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
+ XML_ROLE_ATTLIST_ELEMENT_NAME,
+ XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
+ XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
+ XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
+ XML_ROLE_FIXED_ATTRIBUTE_VALUE,
+ XML_ROLE_ELEMENT_NAME,
+ XML_ROLE_CONTENT_ANY,
+ XML_ROLE_CONTENT_EMPTY,
+ XML_ROLE_CONTENT_PCDATA,
+ XML_ROLE_GROUP_OPEN,
+ XML_ROLE_GROUP_CLOSE,
+ XML_ROLE_GROUP_CLOSE_REP,
+ XML_ROLE_GROUP_CLOSE_OPT,
+ XML_ROLE_GROUP_CLOSE_PLUS,
+ XML_ROLE_GROUP_CHOICE,
+ XML_ROLE_GROUP_SEQUENCE,
+ XML_ROLE_CONTENT_ELEMENT,
+ XML_ROLE_CONTENT_ELEMENT_REP,
+ XML_ROLE_CONTENT_ELEMENT_OPT,
+ XML_ROLE_CONTENT_ELEMENT_PLUS,
+ XML_ROLE_PARAM_ENTITY_REF
+};
+
+typedef struct prolog_state {
+ int (*handler)(struct prolog_state *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc);
+ unsigned level;
+} PROLOG_STATE;
+
+void XMLTOKAPI XmlPrologStateInit(PROLOG_STATE *);
+
+#define XmlTokenRole(state, tok, ptr, end, enc) \
+ (((state)->handler)(state, tok, ptr, end, enc))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlRole_INCLUDED */
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmltok.c b/usr.sbin/httpd/src/lib/expat-lite/xmltok.c
new file mode 100644
index 00000000000..f0570d81456
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmltok.c
@@ -0,0 +1,1527 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+#include "xmldef.h"
+#include "xmltok.h"
+#include "nametab.h"
+
+#define VTABLE1 \
+ { PREFIX(prologTok), PREFIX(contentTok), PREFIX(cdataSectionTok) }, \
+ { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
+ PREFIX(sameName), \
+ PREFIX(nameMatchesAscii), \
+ PREFIX(nameLength), \
+ PREFIX(skipS), \
+ PREFIX(getAtts), \
+ PREFIX(charRefNumber), \
+ PREFIX(predefinedEntityName), \
+ PREFIX(updatePosition), \
+ PREFIX(isPublicId)
+
+#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
+
+#define UCS2_GET_NAMING(pages, hi, lo) \
+ (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F)))
+
+/* A 2 byte UTF-8 representation splits the characters 11 bits
+between the bottom 5 and 6 bits of the bytes.
+We need 8 bits to index into pages, 3 bits to add to that index and
+5 bits to generate the mask. */
+#define UTF8_GET_NAMING2(pages, byte) \
+ (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
+ + ((((byte)[0]) & 3) << 1) \
+ + ((((byte)[1]) >> 5) & 1)] \
+ & (1 << (((byte)[1]) & 0x1F)))
+
+/* A 3 byte UTF-8 representation splits the characters 16 bits
+between the bottom 4, 6 and 6 bits of the bytes.
+We need 8 bits to index into pages, 3 bits to add to that index and
+5 bits to generate the mask. */
+#define UTF8_GET_NAMING3(pages, byte) \
+ (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \
+ + ((((byte)[1]) >> 2) & 0xF)] \
+ << 3) \
+ + ((((byte)[1]) & 3) << 1) \
+ + ((((byte)[2]) >> 5) & 1)] \
+ & (1 << (((byte)[2]) & 0x1F)))
+
+#define UTF8_GET_NAMING(pages, p, n) \
+ ((n) == 2 \
+ ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
+ : ((n) == 3 \
+ ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \
+ : 0))
+
+#define UTF8_INVALID3(p) \
+ ((*p) == 0xED \
+ ? (((p)[1] & 0x20) != 0) \
+ : ((*p) == 0xEF \
+ ? ((p)[1] == 0xBF && ((p)[2] == 0xBF || (p)[2] == 0xBE)) \
+ : 0))
+
+#define UTF8_INVALID4(p) ((*p) == 0xF4 && ((p)[1] & 0x30) != 0)
+
+static
+int isNever(const ENCODING *enc, const char *p)
+{
+ return 0;
+}
+
+static
+int utf8_isName2(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
+}
+
+static
+int utf8_isName3(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
+}
+
+#define utf8_isName4 isNever
+
+static
+int utf8_isNmstrt2(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
+}
+
+static
+int utf8_isNmstrt3(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
+}
+
+#define utf8_isNmstrt4 isNever
+
+#define utf8_isInvalid2 isNever
+
+static
+int utf8_isInvalid3(const ENCODING *enc, const char *p)
+{
+ return UTF8_INVALID3((const unsigned char *)p);
+}
+
+static
+int utf8_isInvalid4(const ENCODING *enc, const char *p)
+{
+ return UTF8_INVALID4((const unsigned char *)p);
+}
+
+struct normal_encoding {
+ ENCODING enc;
+ unsigned char type[256];
+#ifdef XML_MIN_SIZE
+ int (*byteType)(const ENCODING *, const char *);
+ int (*isNameMin)(const ENCODING *, const char *);
+ int (*isNmstrtMin)(const ENCODING *, const char *);
+ int (*byteToAscii)(const ENCODING *, const char *);
+ int (*charMatches)(const ENCODING *, const char *, int);
+#endif /* XML_MIN_SIZE */
+ int (*isName2)(const ENCODING *, const char *);
+ int (*isName3)(const ENCODING *, const char *);
+ int (*isName4)(const ENCODING *, const char *);
+ int (*isNmstrt2)(const ENCODING *, const char *);
+ int (*isNmstrt3)(const ENCODING *, const char *);
+ int (*isNmstrt4)(const ENCODING *, const char *);
+ int (*isInvalid2)(const ENCODING *, const char *);
+ int (*isInvalid3)(const ENCODING *, const char *);
+ int (*isInvalid4)(const ENCODING *, const char *);
+};
+
+#ifdef XML_MIN_SIZE
+
+#define STANDARD_VTABLE(E) \
+ E ## byteType, \
+ E ## isNameMin, \
+ E ## isNmstrtMin, \
+ E ## byteToAscii, \
+ E ## charMatches,
+
+#else
+
+#define STANDARD_VTABLE(E) /* as nothing */
+
+#endif
+
+#define NORMAL_VTABLE(E) \
+ E ## isName2, \
+ E ## isName3, \
+ E ## isName4, \
+ E ## isNmstrt2, \
+ E ## isNmstrt3, \
+ E ## isNmstrt4, \
+ E ## isInvalid2, \
+ E ## isInvalid3, \
+ E ## isInvalid4
+
+static int checkCharRefNumber(int);
+
+#include "xmltok_impl.h"
+
+#ifdef XML_MIN_SIZE
+#define sb_isNameMin isNever
+#define sb_isNmstrtMin isNever
+#endif
+
+#ifdef XML_MIN_SIZE
+#define MINBPC(enc) ((enc)->minBytesPerChar)
+#else
+/* minimum bytes per character */
+#define MINBPC(enc) 1
+#endif
+
+#define SB_BYTE_TYPE(enc, p) \
+ (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
+
+#ifdef XML_MIN_SIZE
+static
+int sb_byteType(const ENCODING *enc, const char *p)
+{
+ return SB_BYTE_TYPE(enc, p);
+}
+#define BYTE_TYPE(enc, p) \
+ (((const struct normal_encoding *)(enc))->byteType(enc, p))
+#else
+#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define BYTE_TO_ASCII(enc, p) \
+ (((const struct normal_encoding *)(enc))->byteToAscii(enc, p))
+static
+int sb_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return *p;
+}
+#else
+#define BYTE_TO_ASCII(enc, p) (*p)
+#endif
+
+#define IS_NAME_CHAR(enc, p, n) \
+ (((const struct normal_encoding *)(enc))->isName ## n(enc, p))
+#define IS_NMSTRT_CHAR(enc, p, n) \
+ (((const struct normal_encoding *)(enc))->isNmstrt ## n(enc, p))
+#define IS_INVALID_CHAR(enc, p, n) \
+ (((const struct normal_encoding *)(enc))->isInvalid ## n(enc, p))
+
+#ifdef XML_MIN_SIZE
+#define IS_NAME_CHAR_MINBPC(enc, p) \
+ (((const struct normal_encoding *)(enc))->isNameMin(enc, p))
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ (((const struct normal_encoding *)(enc))->isNmstrtMin(enc, p))
+#else
+#define IS_NAME_CHAR_MINBPC(enc, p) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define CHAR_MATCHES(enc, p, c) \
+ (((const struct normal_encoding *)(enc))->charMatches(enc, p, c))
+static
+int sb_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return *p == c;
+}
+#else
+/* c is an ASCII character */
+#define CHAR_MATCHES(enc, p, c) (*(p) == c)
+#endif
+
+#define PREFIX(ident) normal_ ## ident
+#include "xmltok_impl.c"
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */
+ UTF8_cval1 = 0x00,
+ UTF8_cval2 = 0xc0,
+ UTF8_cval3 = 0xe0,
+ UTF8_cval4 = 0xf0
+};
+
+static
+void utf8_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ char *to;
+ const char *from;
+ if (fromLim - *fromP > toLim - *toP) {
+ /* Avoid copying partial characters. */
+ for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--)
+ if (((unsigned char)fromLim[-1] & 0xc0) != 0x80)
+ break;
+ }
+ for (to = *toP, from = *fromP; from != fromLim; from++, to++)
+ *to = *from;
+ *fromP = from;
+ *toP = to;
+}
+
+static
+void utf8_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ unsigned short *to = *toP;
+ const char *from = *fromP;
+ while (from != fromLim && to != toLim) {
+ switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
+ case BT_LEAD2:
+ *to++ = ((from[0] & 0x1f) << 6) | (from[1] & 0x3f);
+ from += 2;
+ break;
+ case BT_LEAD3:
+ *to++ = ((from[0] & 0xf) << 12) | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f);
+ from += 3;
+ break;
+ case BT_LEAD4:
+ {
+ unsigned long n;
+ if (to + 1 == toLim)
+ break;
+ n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
+ n -= 0x10000;
+ to[0] = (unsigned short)((n >> 10) | 0xD800);
+ to[1] = (unsigned short)((n & 0x3FF) | 0xDC00);
+ to += 2;
+ from += 4;
+ }
+ break;
+ default:
+ *to++ = *from++;
+ break;
+ }
+ }
+ *fromP = from;
+ *toP = to;
+}
+
+#ifdef XML_NS
+static const struct normal_encoding utf8_encoding_ns = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#include "asciitab.h"
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+#endif
+
+static const struct normal_encoding utf8_encoding = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_utf8_encoding_ns = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#include "iasciitab.h"
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#endif
+
+static const struct normal_encoding internal_utf8_encoding = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+static
+void latin1_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ for (;;) {
+ unsigned char c;
+ if (*fromP == fromLim)
+ break;
+ c = (unsigned char)**fromP;
+ if (c & 0x80) {
+ if (toLim - *toP < 2)
+ break;
+ *(*toP)++ = ((c >> 6) | UTF8_cval2);
+ *(*toP)++ = ((c & 0x3f) | 0x80);
+ (*fromP)++;
+ }
+ else {
+ if (*toP == toLim)
+ break;
+ *(*toP)++ = *(*fromP)++;
+ }
+ }
+}
+
+static
+void latin1_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ while (*fromP != fromLim && *toP != toLim)
+ *(*toP)++ = (unsigned char)*(*fromP)++;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding latin1_encoding_ns = {
+ { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(sb_)
+};
+
+#endif
+
+static const struct normal_encoding latin1_encoding = {
+ { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(sb_)
+};
+
+static
+void ascii_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ while (*fromP != fromLim && *toP != toLim)
+ *(*toP)++ = *(*fromP)++;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding ascii_encoding_ns = {
+ { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+ {
+#include "asciitab.h"
+/* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_)
+};
+
+#endif
+
+static const struct normal_encoding ascii_encoding = {
+ { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+/* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_)
+};
+
+static int unicode_byte_type(char hi, char lo)
+{
+ switch ((unsigned char)hi) {
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+ return BT_LEAD4;
+ case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ return BT_TRAIL;
+ case 0xFF:
+ switch ((unsigned char)lo) {
+ case 0xFF:
+ case 0xFE:
+ return BT_NONXML;
+ }
+ break;
+ }
+ return BT_NONASCII;
+}
+
+#define DEFINE_UTF16_TO_UTF8(E) \
+static \
+void E ## toUtf8(const ENCODING *enc, \
+ const char **fromP, const char *fromLim, \
+ char **toP, const char *toLim) \
+{ \
+ const char *from; \
+ for (from = *fromP; from != fromLim; from += 2) { \
+ int plane; \
+ unsigned char lo2; \
+ unsigned char lo = GET_LO(from); \
+ unsigned char hi = GET_HI(from); \
+ switch (hi) { \
+ case 0: \
+ if (lo < 0x80) { \
+ if (*toP == toLim) { \
+ *fromP = from; \
+ return; \
+ } \
+ *(*toP)++ = lo; \
+ break; \
+ } \
+ /* fall through */ \
+ case 0x1: case 0x2: case 0x3: \
+ case 0x4: case 0x5: case 0x6: case 0x7: \
+ if (toLim - *toP < 2) { \
+ *fromP = from; \
+ return; \
+ } \
+ *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ default: \
+ if (toLim - *toP < 3) { \
+ *fromP = from; \
+ return; \
+ } \
+ /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
+ *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
+ *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
+ if (toLim - *toP < 4) { \
+ *fromP = from; \
+ return; \
+ } \
+ plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
+ *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
+ *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
+ from += 2; \
+ lo2 = GET_LO(from); \
+ *(*toP)++ = (((lo & 0x3) << 4) \
+ | ((GET_HI(from) & 0x3) << 2) \
+ | (lo2 >> 6) \
+ | 0x80); \
+ *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
+ break; \
+ } \
+ } \
+ *fromP = from; \
+}
+
+#define DEFINE_UTF16_TO_UTF16(E) \
+static \
+void E ## toUtf16(const ENCODING *enc, \
+ const char **fromP, const char *fromLim, \
+ unsigned short **toP, const unsigned short *toLim) \
+{ \
+ /* Avoid copying first half only of surrogate */ \
+ if (fromLim - *fromP > ((toLim - *toP) << 1) \
+ && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \
+ fromLim -= 2; \
+ for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \
+ *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
+}
+
+#define SET2(ptr, ch) \
+ (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[0])
+#define GET_HI(ptr) ((unsigned char)(ptr)[1])
+
+DEFINE_UTF16_TO_UTF8(little2_)
+DEFINE_UTF16_TO_UTF16(little2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define SET2(ptr, ch) \
+ (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[1])
+#define GET_HI(ptr) ((unsigned char)(ptr)[0])
+
+DEFINE_UTF16_TO_UTF8(big2_)
+DEFINE_UTF16_TO_UTF16(big2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define LITTLE2_BYTE_TYPE(enc, p) \
+ ((p)[1] == 0 \
+ ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
+ : unicode_byte_type((p)[1], (p)[0]))
+#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1)
+#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c)
+#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
+#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
+
+#ifdef XML_MIN_SIZE
+
+static
+int little2_byteType(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_BYTE_TYPE(enc, p);
+}
+
+static
+int little2_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_BYTE_TO_ASCII(enc, p);
+}
+
+static
+int little2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return LITTLE2_CHAR_MATCHES(enc, p, c);
+}
+
+static
+int little2_isNameMin(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static
+int little2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) little2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#include "xmltok_impl.c"
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding little2_encoding_ns = {
+ { VTABLE, 2, 0,
+#if XML_BYTE_ORDER == 12
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_)
+};
+
+#endif
+
+static const struct normal_encoding little2_encoding = {
+ { VTABLE, 2, 0,
+#if XML_BYTE_ORDER == 12
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_)
+};
+
+#if XML_BYTE_ORDER != 21
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_little2_encoding_ns = {
+ { VTABLE, 2, 0, 1 },
+ {
+#include "iasciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_)
+};
+
+#endif
+
+static const struct normal_encoding internal_little2_encoding = {
+ { VTABLE, 2, 0, 1 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_)
+};
+
+#endif
+
+
+#define BIG2_BYTE_TYPE(enc, p) \
+ ((p)[0] == 0 \
+ ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
+ : unicode_byte_type((p)[0], (p)[1]))
+#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1)
+#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c)
+#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
+#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
+
+#ifdef XML_MIN_SIZE
+
+static
+int big2_byteType(const ENCODING *enc, const char *p)
+{
+ return BIG2_BYTE_TYPE(enc, p);
+}
+
+static
+int big2_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return BIG2_BYTE_TO_ASCII(enc, p);
+}
+
+static
+int big2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return BIG2_CHAR_MATCHES(enc, p, c);
+}
+
+static
+int big2_isNameMin(const ENCODING *enc, const char *p)
+{
+ return BIG2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static
+int big2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+ return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) big2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#include "xmltok_impl.c"
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding big2_encoding_ns = {
+ { VTABLE, 2, 0,
+#if XML_BYTE_ORDER == 21
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_)
+};
+
+#endif
+
+static const struct normal_encoding big2_encoding = {
+ { VTABLE, 2, 0,
+#if XML_BYTE_ORDER == 21
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_)
+};
+
+#if XML_BYTE_ORDER != 12
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_big2_encoding_ns = {
+ { VTABLE, 2, 0, 1 },
+ {
+#include "iasciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_)
+};
+
+#endif
+
+static const struct normal_encoding internal_big2_encoding = {
+ { VTABLE, 2, 0, 1 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_)
+};
+
+#endif
+
+#undef PREFIX
+
+static
+int streqci(const char *s1, const char *s2)
+{
+ for (;;) {
+ char c1 = *s1++;
+ char c2 = *s2++;
+ if ('a' <= c1 && c1 <= 'z')
+ c1 += 'A' - 'a';
+ if ('a' <= c2 && c2 <= 'z')
+ c2 += 'A' - 'a';
+ if (c1 != c2)
+ return 0;
+ if (!c1)
+ break;
+ }
+ return 1;
+}
+
+static
+void initUpdatePosition(const ENCODING *enc, const char *ptr,
+ const char *end, POSITION *pos)
+{
+ normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
+}
+
+static
+int toAscii(const ENCODING *enc, const char *ptr, const char *end)
+{
+ char buf[1];
+ char *p = buf;
+ XmlUtf8Convert(enc, &ptr, end, &p, p + 1);
+ if (p == buf)
+ return -1;
+ else
+ return buf[0];
+}
+
+static
+int isSpace(int c)
+{
+ switch (c) {
+ case 0x20:
+ case 0xD:
+ case 0xA:
+ case 0x9:
+ return 1;
+ }
+ return 0;
+}
+
+/* Return 1 if there's just optional white space
+or there's an S followed by name=val. */
+static
+int parsePseudoAttribute(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **namePtr,
+ const char **valPtr,
+ const char **nextTokPtr)
+{
+ int c;
+ char openchar;
+ if (ptr == end) {
+ *namePtr = 0;
+ return 1;
+ }
+ if (!isSpace(toAscii(enc, ptr, end))) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ do {
+ ptr += enc->minBytesPerChar;
+ } while (isSpace(toAscii(enc, ptr, end)));
+ if (ptr == end) {
+ *namePtr = 0;
+ return 1;
+ }
+ *namePtr = ptr;
+ for (;;) {
+ c = toAscii(enc, ptr, end);
+ if (c == -1) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ if (c == '=')
+ break;
+ if (isSpace(c)) {
+ do {
+ ptr += enc->minBytesPerChar;
+ } while (isSpace(c = toAscii(enc, ptr, end)));
+ if (c != '=') {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ break;
+ }
+ ptr += enc->minBytesPerChar;
+ }
+ if (ptr == *namePtr) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ ptr += enc->minBytesPerChar;
+ c = toAscii(enc, ptr, end);
+ while (isSpace(c)) {
+ ptr += enc->minBytesPerChar;
+ c = toAscii(enc, ptr, end);
+ }
+ if (c != '"' && c != '\'') {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ openchar = c;
+ ptr += enc->minBytesPerChar;
+ *valPtr = ptr;
+ for (;; ptr += enc->minBytesPerChar) {
+ c = toAscii(enc, ptr, end);
+ if (c == openchar)
+ break;
+ if (!('a' <= c && c <= 'z')
+ && !('A' <= c && c <= 'Z')
+ && !('0' <= c && c <= '9')
+ && c != '.'
+ && c != '-'
+ && c != '_') {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ }
+ *nextTokPtr = ptr + enc->minBytesPerChar;
+ return 1;
+}
+
+static
+int doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
+ const char *,
+ const char *),
+ int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **encodingName,
+ const ENCODING **encoding,
+ int *standalone)
+{
+ const char *val = 0;
+ const char *name = 0;
+ ptr += 5 * enc->minBytesPerChar;
+ end -= 2 * enc->minBytesPerChar;
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr) || !name) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!XmlNameMatchesAscii(enc, name, "version")) {
+ if (!isGeneralTextEntity) {
+ *badPtr = name;
+ return 0;
+ }
+ }
+ else {
+ if (versionPtr)
+ *versionPtr = val;
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!name) {
+ if (isGeneralTextEntity) {
+ /* a TextDecl must have an EncodingDecl */
+ *badPtr = ptr;
+ return 0;
+ }
+ return 1;
+ }
+ }
+ if (XmlNameMatchesAscii(enc, name, "encoding")) {
+ int c = toAscii(enc, val, end);
+ if (!('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z')) {
+ *badPtr = val;
+ return 0;
+ }
+ if (encodingName)
+ *encodingName = val;
+ if (encoding)
+ *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar);
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!name)
+ return 1;
+ }
+ if (!XmlNameMatchesAscii(enc, name, "standalone") || isGeneralTextEntity) {
+ *badPtr = name;
+ return 0;
+ }
+ if (XmlNameMatchesAscii(enc, val, "yes")) {
+ if (standalone)
+ *standalone = 1;
+ }
+ else if (XmlNameMatchesAscii(enc, val, "no")) {
+ if (standalone)
+ *standalone = 0;
+ }
+ else {
+ *badPtr = val;
+ return 0;
+ }
+ while (isSpace(toAscii(enc, ptr, end)))
+ ptr += enc->minBytesPerChar;
+ if (ptr != end) {
+ *badPtr = ptr;
+ return 0;
+ }
+ return 1;
+}
+
+static
+int checkCharRefNumber(int result)
+{
+ switch (result >> 8) {
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+ case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ return -1;
+ case 0:
+ if (latin1_encoding.type[result] == BT_NONXML)
+ return -1;
+ break;
+ case 0xFF:
+ if (result == 0xFFFE || result == 0xFFFF)
+ return -1;
+ break;
+ }
+ return result;
+}
+
+int XmlUtf8Encode(int c, char *buf)
+{
+ enum {
+ /* minN is minimum legal resulting value for N byte sequence */
+ min2 = 0x80,
+ min3 = 0x800,
+ min4 = 0x10000
+ };
+
+ if (c < 0)
+ return 0;
+ if (c < min2) {
+ buf[0] = (c | UTF8_cval1);
+ return 1;
+ }
+ if (c < min3) {
+ buf[0] = ((c >> 6) | UTF8_cval2);
+ buf[1] = ((c & 0x3f) | 0x80);
+ return 2;
+ }
+ if (c < min4) {
+ buf[0] = ((c >> 12) | UTF8_cval3);
+ buf[1] = (((c >> 6) & 0x3f) | 0x80);
+ buf[2] = ((c & 0x3f) | 0x80);
+ return 3;
+ }
+ if (c < 0x110000) {
+ buf[0] = ((c >> 18) | UTF8_cval4);
+ buf[1] = (((c >> 12) & 0x3f) | 0x80);
+ buf[2] = (((c >> 6) & 0x3f) | 0x80);
+ buf[3] = ((c & 0x3f) | 0x80);
+ return 4;
+ }
+ return 0;
+}
+
+int XmlUtf16Encode(int charNum, unsigned short *buf)
+{
+ if (charNum < 0)
+ return 0;
+ if (charNum < 0x10000) {
+ buf[0] = charNum;
+ return 1;
+ }
+ if (charNum < 0x110000) {
+ charNum -= 0x10000;
+ buf[0] = (charNum >> 10) + 0xD800;
+ buf[1] = (charNum & 0x3FF) + 0xDC00;
+ return 2;
+ }
+ return 0;
+}
+
+struct unknown_encoding {
+ struct normal_encoding normal;
+ int (*convert)(void *userData, const char *p);
+ void *userData;
+ unsigned short utf16[256];
+ char utf8[256][4];
+};
+
+int XmlSizeOfUnknownEncoding(void)
+{
+ return sizeof(struct unknown_encoding);
+}
+
+static
+int unknown_isName(const ENCODING *enc, const char *p)
+{
+ int c = ((const struct unknown_encoding *)enc)
+ ->convert(((const struct unknown_encoding *)enc)->userData, p);
+ if (c & ~0xFFFF)
+ return 0;
+ return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF);
+}
+
+static
+int unknown_isNmstrt(const ENCODING *enc, const char *p)
+{
+ int c = ((const struct unknown_encoding *)enc)
+ ->convert(((const struct unknown_encoding *)enc)->userData, p);
+ if (c & ~0xFFFF)
+ return 0;
+ return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF);
+}
+
+static
+int unknown_isInvalid(const ENCODING *enc, const char *p)
+{
+ int c = ((const struct unknown_encoding *)enc)
+ ->convert(((const struct unknown_encoding *)enc)->userData, p);
+ return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
+}
+
+static
+void unknown_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ char buf[XML_UTF8_ENCODE_MAX];
+ for (;;) {
+ const char *utf8;
+ int n;
+ if (*fromP == fromLim)
+ break;
+ utf8 = ((const struct unknown_encoding *)enc)->utf8[(unsigned char)**fromP];
+ n = *utf8++;
+ if (n == 0) {
+ int c = ((const struct unknown_encoding *)enc)
+ ->convert(((const struct unknown_encoding *)enc)->userData, *fromP);
+ n = XmlUtf8Encode(c, buf);
+ if (n > toLim - *toP)
+ break;
+ utf8 = buf;
+ *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP]
+ - (BT_LEAD2 - 2);
+ }
+ else {
+ if (n > toLim - *toP)
+ break;
+ (*fromP)++;
+ }
+ do {
+ *(*toP)++ = *utf8++;
+ } while (--n != 0);
+ }
+}
+
+static
+void unknown_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ while (*fromP != fromLim && *toP != toLim) {
+ unsigned short c
+ = ((const struct unknown_encoding *)enc)->utf16[(unsigned char)**fromP];
+ if (c == 0) {
+ c = (unsigned short)((const struct unknown_encoding *)enc)
+ ->convert(((const struct unknown_encoding *)enc)->userData, *fromP);
+ *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP]
+ - (BT_LEAD2 - 2);
+ }
+ else
+ (*fromP)++;
+ *(*toP)++ = c;
+ }
+}
+
+ENCODING *
+XmlInitUnknownEncoding(void *mem,
+ int *table,
+ int (*convert)(void *userData, const char *p),
+ void *userData)
+{
+ int i;
+ struct unknown_encoding *e = mem;
+ for (i = 0; i < sizeof(struct normal_encoding); i++)
+ ((char *)mem)[i] = ((char *)&latin1_encoding)[i];
+ for (i = 0; i < 128; i++)
+ if (latin1_encoding.type[i] != BT_OTHER
+ && latin1_encoding.type[i] != BT_NONXML
+ && table[i] != i)
+ return 0;
+ for (i = 0; i < 256; i++) {
+ int c = table[i];
+ if (c == -1) {
+ e->normal.type[i] = BT_MALFORM;
+ /* This shouldn't really get used. */
+ e->utf16[i] = 0xFFFF;
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = 0;
+ }
+ else if (c < 0) {
+ if (c < -4)
+ return 0;
+ e->normal.type[i] = BT_LEAD2 - (c + 2);
+ e->utf8[i][0] = 0;
+ e->utf16[i] = 0;
+ }
+ else if (c < 0x80) {
+ if (latin1_encoding.type[c] != BT_OTHER
+ && latin1_encoding.type[c] != BT_NONXML
+ && c != i)
+ return 0;
+ e->normal.type[i] = latin1_encoding.type[c];
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = (char)c;
+ e->utf16[i] = c == 0 ? 0xFFFF : c;
+ }
+ else if (checkCharRefNumber(c) < 0) {
+ e->normal.type[i] = BT_NONXML;
+ /* This shouldn't really get used. */
+ e->utf16[i] = 0xFFFF;
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = 0;
+ }
+ else {
+ if (c > 0xFFFF)
+ return 0;
+ if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff))
+ e->normal.type[i] = BT_NMSTRT;
+ else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff))
+ e->normal.type[i] = BT_NAME;
+ else
+ e->normal.type[i] = BT_OTHER;
+ e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1);
+ e->utf16[i] = c;
+ }
+ }
+ e->userData = userData;
+ e->convert = convert;
+ if (convert) {
+ e->normal.isName2 = unknown_isName;
+ e->normal.isName3 = unknown_isName;
+ e->normal.isName4 = unknown_isName;
+ e->normal.isNmstrt2 = unknown_isNmstrt;
+ e->normal.isNmstrt3 = unknown_isNmstrt;
+ e->normal.isNmstrt4 = unknown_isNmstrt;
+ e->normal.isInvalid2 = unknown_isInvalid;
+ e->normal.isInvalid3 = unknown_isInvalid;
+ e->normal.isInvalid4 = unknown_isInvalid;
+ }
+ e->normal.enc.utf8Convert = unknown_toUtf8;
+ e->normal.enc.utf16Convert = unknown_toUtf16;
+ return &(e->normal.enc);
+}
+
+/* If this enumeration is changed, getEncodingIndex and encodings
+must also be changed. */
+enum {
+ UNKNOWN_ENC = -1,
+ ISO_8859_1_ENC = 0,
+ US_ASCII_ENC,
+ UTF_8_ENC,
+ UTF_16_ENC,
+ UTF_16BE_ENC,
+ UTF_16LE_ENC,
+ /* must match encodingNames up to here */
+ NO_ENC
+};
+
+static
+int getEncodingIndex(const char *name)
+{
+ static const char *encodingNames[] = {
+ "ISO-8859-1",
+ "US-ASCII",
+ "UTF-8",
+ "UTF-16",
+ "UTF-16BE"
+ "UTF-16LE",
+ };
+ int i;
+ if (name == 0)
+ return NO_ENC;
+ for (i = 0; i < sizeof(encodingNames)/sizeof(encodingNames[0]); i++)
+ if (streqci(name, encodingNames[i]))
+ return i;
+ return UNKNOWN_ENC;
+}
+
+/* For binary compatibility, we store the index of the encoding specified
+at initialization in the isUtf16 member. */
+
+#define INIT_ENC_INDEX(enc) ((enc)->initEnc.isUtf16)
+
+/* This is what detects the encoding.
+encodingTable maps from encoding indices to encodings;
+INIT_ENC_INDEX(enc) is the index of the external (protocol) specified encoding;
+state is XML_CONTENT_STATE if we're parsing an external text entity,
+and XML_PROLOG_STATE otherwise.
+*/
+
+
+static
+int initScan(const ENCODING **encodingTable,
+ const INIT_ENCODING *enc,
+ int state,
+ const char *ptr,
+ const char *end,
+ const char **nextTokPtr)
+{
+ const ENCODING **encPtr;
+
+ if (ptr == end)
+ return XML_TOK_NONE;
+ encPtr = enc->encPtr;
+ if (ptr + 1 == end) {
+ /* only a single byte available for auto-detection */
+ /* a well-formed document entity must have more than one byte */
+ if (state != XML_CONTENT_STATE)
+ return XML_TOK_PARTIAL;
+ /* so we're parsing an external text entity... */
+ /* if UTF-16 was externally specified, then we need at least 2 bytes */
+ switch (INIT_ENC_INDEX(enc)) {
+ case UTF_16_ENC:
+ case UTF_16LE_ENC:
+ case UTF_16BE_ENC:
+ return XML_TOK_PARTIAL;
+ }
+ switch ((unsigned char)*ptr) {
+ case 0xFE:
+ case 0xFF:
+ case 0xEF: /* possibly first byte of UTF-8 BOM */
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ /* fall through */
+ case 0x00:
+ case 0x3C:
+ return XML_TOK_PARTIAL;
+ }
+ }
+ else {
+ switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) {
+ case 0xFEFF:
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ *nextTokPtr = ptr + 2;
+ *encPtr = encodingTable[UTF_16BE_ENC];
+ return XML_TOK_BOM;
+ /* 00 3C is handled in the default case */
+ case 0x3C00:
+ if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC
+ || INIT_ENC_INDEX(enc) == UTF_16_ENC)
+ && state == XML_CONTENT_STATE)
+ break;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ case 0xFFFE:
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ *nextTokPtr = ptr + 2;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XML_TOK_BOM;
+ case 0xEFBB:
+ /* Maybe a UTF-8 BOM (EF BB BF) */
+ /* If there's an explicitly specified (external) encoding
+ of ISO-8859-1 or some flavour of UTF-16
+ and this is an external text entity,
+ don't look for the BOM,
+ because it might be a legal data. */
+ if (state == XML_CONTENT_STATE) {
+ int e = INIT_ENC_INDEX(enc);
+ if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC || e == UTF_16LE_ENC || e == UTF_16_ENC)
+ break;
+ }
+ if (ptr + 2 == end)
+ return XML_TOK_PARTIAL;
+ if ((unsigned char)ptr[2] == 0xBF) {
+ *encPtr = encodingTable[UTF_8_ENC];
+ return XML_TOK_BOM;
+ }
+ break;
+ default:
+ if (ptr[0] == '\0') {
+ /* 0 isn't a legal data character. Furthermore a document entity can only
+ start with ASCII characters. So the only way this can fail to be big-endian
+ UTF-16 if it it's an external parsed general entity that's labelled as
+ UTF-16LE. */
+ if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC)
+ break;
+ *encPtr = encodingTable[UTF_16BE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ }
+ else if (ptr[1] == '\0') {
+ /* We could recover here in the case:
+ - parsing an external entity
+ - second byte is 0
+ - no externally specified encoding
+ - no encoding declaration
+ by assuming UTF-16LE. But we don't, because this would mean when
+ presented just with a single byte, we couldn't reliably determine
+ whether we needed further bytes. */
+ if (state == XML_CONTENT_STATE)
+ break;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ }
+ break;
+ }
+ }
+ *encPtr = encodingTable[(int)INIT_ENC_INDEX(enc)];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+}
+
+
+#define NS(x) x
+#define ns(x) x
+#include "xmltok_ns.c"
+#undef NS
+#undef ns
+
+#ifdef XML_NS
+
+#define NS(x) x ## NS
+#define ns(x) x ## _ns
+
+#include "xmltok_ns.c"
+
+#undef NS
+#undef ns
+
+ENCODING *
+XmlInitUnknownEncodingNS(void *mem,
+ int *table,
+ int (*convert)(void *userData, const char *p),
+ void *userData)
+{
+ ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData);
+ if (enc)
+ ((struct normal_encoding *)enc)->type[':'] = BT_COLON;
+ return enc;
+}
+
+#endif /* XML_NS */
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmltok.h b/usr.sbin/httpd/src/lib/expat-lite/xmltok.h
new file mode 100644
index 00000000000..fd0ed08e34b
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmltok.h
@@ -0,0 +1,307 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+#ifndef XmlTok_INCLUDED
+#define XmlTok_INCLUDED 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XMLTOKAPI
+#define XMLTOKAPI /* as nothing */
+#endif
+
+/* The following token may be returned by XmlContentTok */
+#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be start of
+ illegal ]]> sequence */
+/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */
+#define XML_TOK_NONE -4 /* The string to be scanned is empty */
+#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan;
+ might be part of CRLF sequence */
+#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
+#define XML_TOK_PARTIAL -1 /* only part of a token */
+#define XML_TOK_INVALID 0
+
+/* The following tokens are returned by XmlContentTok; some are also
+ returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok */
+
+#define XML_TOK_START_TAG_WITH_ATTS 1
+#define XML_TOK_START_TAG_NO_ATTS 2
+#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
+#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
+#define XML_TOK_END_TAG 5
+#define XML_TOK_DATA_CHARS 6
+#define XML_TOK_DATA_NEWLINE 7
+#define XML_TOK_CDATA_SECT_OPEN 8
+#define XML_TOK_ENTITY_REF 9
+#define XML_TOK_CHAR_REF 10 /* numeric character reference */
+
+/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */
+#define XML_TOK_PI 11 /* processing instruction */
+#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
+#define XML_TOK_COMMENT 13
+#define XML_TOK_BOM 14 /* Byte order mark */
+
+/* The following tokens are returned only by XmlPrologTok */
+#define XML_TOK_PROLOG_S 15
+#define XML_TOK_DECL_OPEN 16 /* <!foo */
+#define XML_TOK_DECL_CLOSE 17 /* > */
+#define XML_TOK_NAME 18
+#define XML_TOK_NMTOKEN 19
+#define XML_TOK_POUND_NAME 20 /* #name */
+#define XML_TOK_OR 21 /* | */
+#define XML_TOK_PERCENT 22
+#define XML_TOK_OPEN_PAREN 23
+#define XML_TOK_CLOSE_PAREN 24
+#define XML_TOK_OPEN_BRACKET 25
+#define XML_TOK_CLOSE_BRACKET 26
+#define XML_TOK_LITERAL 27
+#define XML_TOK_PARAM_ENTITY_REF 28
+#define XML_TOK_INSTANCE_START 29
+
+/* The following occur only in element type declarations */
+#define XML_TOK_NAME_QUESTION 30 /* name? */
+#define XML_TOK_NAME_ASTERISK 31 /* name* */
+#define XML_TOK_NAME_PLUS 32 /* name+ */
+#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
+#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
+#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
+#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
+#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
+#define XML_TOK_COMMA 38
+
+/* The following token is returned only by XmlAttributeValueTok */
+#define XML_TOK_ATTRIBUTE_VALUE_S 39
+
+/* The following token is returned only by XmlCdataSectionTok */
+#define XML_TOK_CDATA_SECT_CLOSE 40
+
+/* With namespace processing this is returned by XmlPrologTok
+ for a name with a colon. */
+#define XML_TOK_PREFIXED_NAME 41
+
+#define XML_N_STATES 3
+#define XML_PROLOG_STATE 0
+#define XML_CONTENT_STATE 1
+#define XML_CDATA_SECTION_STATE 2
+
+#define XML_N_LITERAL_TYPES 2
+#define XML_ATTRIBUTE_VALUE_LITERAL 0
+#define XML_ENTITY_VALUE_LITERAL 1
+
+/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
+#define XML_UTF8_ENCODE_MAX 4
+/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
+#define XML_UTF16_ENCODE_MAX 2
+
+typedef struct position {
+ /* first line and first column are 0 not 1 */
+ unsigned long lineNumber;
+ unsigned long columnNumber;
+} POSITION;
+
+typedef struct {
+ const char *name;
+ const char *valuePtr;
+ const char *valueEnd;
+ char normalized;
+} ATTRIBUTE;
+
+struct encoding;
+typedef struct encoding ENCODING;
+
+struct encoding {
+ int (*scanners[XML_N_STATES])(const ENCODING *,
+ const char *,
+ const char *,
+ const char **);
+ int (*literalScanners[XML_N_LITERAL_TYPES])(const ENCODING *,
+ const char *,
+ const char *,
+ const char **);
+ int (*sameName)(const ENCODING *,
+ const char *, const char *);
+ int (*nameMatchesAscii)(const ENCODING *,
+ const char *, const char *);
+ int (*nameLength)(const ENCODING *, const char *);
+ const char *(*skipS)(const ENCODING *, const char *);
+ int (*getAtts)(const ENCODING *enc, const char *ptr,
+ int attsMax, ATTRIBUTE *atts);
+ int (*charRefNumber)(const ENCODING *enc, const char *ptr);
+ int (*predefinedEntityName)(const ENCODING *, const char *, const char *);
+ void (*updatePosition)(const ENCODING *,
+ const char *ptr,
+ const char *end,
+ POSITION *);
+ int (*isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **badPtr);
+ void (*utf8Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ char **toP,
+ const char *toLim);
+ void (*utf16Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ unsigned short **toP,
+ const unsigned short *toLim);
+ int minBytesPerChar;
+ char isUtf8;
+ char isUtf16;
+};
+
+/*
+Scan the string starting at ptr until the end of the next complete token,
+but do not scan past eptr. Return an integer giving the type of token.
+
+Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
+
+Return XML_TOK_PARTIAL when the string does not contain a complete token;
+nextTokPtr will not be set.
+
+Return XML_TOK_INVALID when the string does not start a valid token; nextTokPtr
+will be set to point to the character which made the token invalid.
+
+Otherwise the string starts with a valid token; nextTokPtr will be set to point
+to the character following the end of that token.
+
+Each data character counts as a single token, but adjacent data characters
+may be returned together. Similarly for characters in the prolog outside
+literals, comments and processing instructions.
+*/
+
+
+#define XmlTok(enc, state, ptr, end, nextTokPtr) \
+ (((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
+
+#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
+
+#define XmlContentTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
+
+#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
+
+/* This is used for performing a 2nd-level tokenization on
+the content of a literal that has already been returned by XmlTok. */
+
+#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
+ (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
+
+#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
+
+#define XmlNameMatchesAscii(enc, ptr1, ptr2) \
+ (((enc)->nameMatchesAscii)(enc, ptr1, ptr2))
+
+#define XmlNameLength(enc, ptr) \
+ (((enc)->nameLength)(enc, ptr))
+
+#define XmlSkipS(enc, ptr) \
+ (((enc)->skipS)(enc, ptr))
+
+#define XmlGetAttributes(enc, ptr, attsMax, atts) \
+ (((enc)->getAtts)(enc, ptr, attsMax, atts))
+
+#define XmlCharRefNumber(enc, ptr) \
+ (((enc)->charRefNumber)(enc, ptr))
+
+#define XmlPredefinedEntityName(enc, ptr, end) \
+ (((enc)->predefinedEntityName)(enc, ptr, end))
+
+#define XmlUpdatePosition(enc, ptr, end, pos) \
+ (((enc)->updatePosition)(enc, ptr, end, pos))
+
+#define XmlIsPublicId(enc, ptr, end, badPtr) \
+ (((enc)->isPublicId)(enc, ptr, end, badPtr))
+
+#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
+ (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
+
+#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
+ (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
+
+typedef struct {
+ ENCODING initEnc;
+ const ENCODING **encPtr;
+} INIT_ENCODING;
+
+int XMLTOKAPI XmlParseXmlDecl(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **encodingNamePtr,
+ const ENCODING **namedEncodingPtr,
+ int *standalonePtr);
+
+int XMLTOKAPI XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING XMLTOKAPI *XmlGetUtf8InternalEncoding(void);
+const ENCODING XMLTOKAPI *XmlGetUtf16InternalEncoding(void);
+int XMLTOKAPI XmlUtf8Encode(int charNumber, char *buf);
+int XMLTOKAPI XmlUtf16Encode(int charNumber, unsigned short *buf);
+
+int XMLTOKAPI XmlSizeOfUnknownEncoding(void);
+ENCODING XMLTOKAPI *
+XmlInitUnknownEncoding(void *mem,
+ int *table,
+ int (*conv)(void *userData, const char *p),
+ void *userData);
+
+int XMLTOKAPI XmlParseXmlDeclNS(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **encodingNamePtr,
+ const ENCODING **namedEncodingPtr,
+ int *standalonePtr);
+int XMLTOKAPI XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING XMLTOKAPI *XmlGetUtf8InternalEncodingNS(void);
+const ENCODING XMLTOKAPI *XmlGetUtf16InternalEncodingNS(void);
+ENCODING XMLTOKAPI *
+XmlInitUnknownEncodingNS(void *mem,
+ int *table,
+ int (*conv)(void *userData, const char *p),
+ void *userData);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlTok_INCLUDED */
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmltok_impl.c b/usr.sbin/httpd/src/lib/expat-lite/xmltok_impl.c
new file mode 100644
index 00000000000..5dfe29f1b9e
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmltok_impl.c
@@ -0,0 +1,1746 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+#ifndef IS_INVALID_CHAR
+#define IS_INVALID_CHAR(enc, ptr, n) (0)
+#endif
+
+#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_INVALID_CHAR(enc, ptr, n)) { \
+ *(nextTokPtr) = (ptr); \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define INVALID_CASES(ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(2, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(3, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(4, ptr, nextTokPtr) \
+ case BT_NONXML: \
+ case BT_MALFORM: \
+ case BT_TRAIL: \
+ *(nextTokPtr) = (ptr); \
+ return XML_TOK_INVALID;
+
+#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (!IS_NAME_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ case BT_DIGIT: \
+ case BT_NAME: \
+ case BT_MINUS: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr)
+
+#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr)
+
+#ifndef PREFIX
+#define PREFIX(ident) ident
+#endif
+
+/* ptr points to character following "<!-" */
+
+static
+int PREFIX(scanComment)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr != end) {
+ if (!CHAR_MATCHES(enc, ptr, '-')) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_MINUS:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, '-')) {
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, '>')) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COMMENT;
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<!" */
+
+static
+int PREFIX(scanDecl)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_MINUS:
+ return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LSQB:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COND_SECT_OPEN;
+ case BT_NMSTRT:
+ case BT_HEX:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_PERCNT:
+ if (ptr + MINBPC(enc) == end)
+ return XML_TOK_PARTIAL;
+ /* don't allow <!ENTITY% foo "whatever"> */
+ switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) {
+ case BT_S: case BT_CR: case BT_LF: case BT_PERCNT:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ /* fall through */
+ case BT_S: case BT_CR: case BT_LF:
+ *nextTokPtr = ptr;
+ return XML_TOK_DECL_OPEN;
+ case BT_NMSTRT:
+ case BT_HEX:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static
+int PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, const char *end, int *tokPtr)
+{
+ int upper = 0;
+ *tokPtr = XML_TOK_PI;
+ if (end - ptr != MINBPC(enc)*3)
+ return 1;
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case 'x':
+ break;
+ case 'X':
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ ptr += MINBPC(enc);
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case 'm':
+ break;
+ case 'M':
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ ptr += MINBPC(enc);
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case 'l':
+ break;
+ case 'L':
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ if (upper)
+ return 0;
+ *tokPtr = XML_TOK_XML_DECL;
+ return 1;
+}
+
+/* ptr points to character following "<?" */
+
+static
+int PREFIX(scanPi)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ int tok;
+ const char *target = ptr;
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_QUEST:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, '>')) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return tok;
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+ case BT_QUEST:
+ if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, '>')) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return tok;
+ }
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+
+static
+int PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ int i;
+ /* CDATA[ */
+ if (end - ptr < 6 * MINBPC(enc))
+ return XML_TOK_PARTIAL;
+ for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
+ if (!CHAR_MATCHES(enc, ptr, "CDATA["[i])) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_CDATA_SECT_OPEN;
+}
+
+static
+int PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ']'))
+ break;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, '>')) {
+ ptr -= MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CDATA_SECT_CLOSE;
+ case BT_CR:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ case BT_LF:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ INVALID_CASES(ptr, nextTokPtr)
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONXML:
+ case BT_MALFORM:
+ case BT_TRAIL:
+ case BT_CR:
+ case BT_LF:
+ case BT_RSQB:
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "</" */
+
+static
+int PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_CR: case BT_LF:
+ break;
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_END_TAG;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+#ifdef XML_NS
+ case BT_COLON:
+ /* no need to check qname syntax here, since end-tag must match exactly */
+ ptr += MINBPC(enc);
+ break;
+#endif
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_END_TAG;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#X" */
+
+static
+int PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ break;
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CHAR_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#" */
+
+static
+int PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr != end) {
+ if (CHAR_MATCHES(enc, ptr, 'x'))
+ return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ break;
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CHAR_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&" */
+
+static
+int PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_NUM:
+ return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_ENTITY_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following first character of attribute name */
+
+static
+int PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+#ifdef XML_NS
+ int hadColon = 0;
+#endif
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+ case BT_COLON:
+ if (hadColon) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ hadColon = 1;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+#endif
+ case BT_S: case BT_CR: case BT_LF:
+ for (;;) {
+ int t;
+
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ t = BYTE_TYPE(enc, ptr);
+ if (t == BT_EQUALS)
+ break;
+ switch (t) {
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ /* fall through */
+ case BT_EQUALS:
+ {
+ int opentype;
+#ifdef XML_NS
+ hadColon = 0;
+#endif
+ for (;;) {
+
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ opentype = BYTE_TYPE(enc, ptr);
+ if (opentype == BT_QUOT || opentype == BT_APOS)
+ break;
+ switch (opentype) {
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ ptr += MINBPC(enc);
+ /* in attribute value */
+ for (;;) {
+ int t;
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ t = BYTE_TYPE(enc, ptr);
+ if (t == opentype)
+ break;
+ switch (t) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_AMP:
+ {
+ int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr);
+ if (tok <= 0) {
+ if (tok == XML_TOK_INVALID)
+ *nextTokPtr = ptr;
+ return tok;
+ }
+ break;
+ }
+ case BT_LT:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ break;
+ case BT_SOL:
+ goto sol;
+ case BT_GT:
+ goto gt;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ /* ptr points to closing quote */
+ for (;;) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ continue;
+ case BT_GT:
+ gt:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_START_TAG_WITH_ATTS;
+ case BT_SOL:
+ sol:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, '>')) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_EMPTY_ELEMENT_WITH_ATTS;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+ }
+ break;
+ }
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<" */
+
+static
+int PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+#ifdef XML_NS
+ int hadColon;
+#endif
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_EXCL:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_MINUS:
+ return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LSQB:
+ return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_QUEST:
+ return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_SOL:
+ return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+#ifdef XML_NS
+ hadColon = 0;
+#endif
+ /* we have a start-tag */
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+ case BT_COLON:
+ if (hadColon) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ hadColon = 1;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+#endif
+ case BT_S: case BT_CR: case BT_LF:
+ {
+ ptr += MINBPC(enc);
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_GT:
+ goto gt;
+ case BT_SOL:
+ goto sol;
+ case BT_S: case BT_CR: case BT_LF:
+ ptr += MINBPC(enc);
+ continue;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr);
+ }
+ return XML_TOK_PARTIAL;
+ }
+ case BT_GT:
+ gt:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_START_TAG_NO_ATTS;
+ case BT_SOL:
+ sol:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, '>')) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_EMPTY_ELEMENT_NO_ATTS;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static
+int PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_LT:
+ return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_AMP:
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_CR:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ case BT_LF:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_RSQB;
+ if (!CHAR_MATCHES(enc, ptr, ']'))
+ break;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_RSQB;
+ if (!CHAR_MATCHES(enc, ptr, '>')) {
+ ptr -= MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ INVALID_CASES(ptr, nextTokPtr)
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_RSQB:
+ if (ptr + MINBPC(enc) != end) {
+ if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ']')) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ if (ptr + 2*MINBPC(enc) != end) {
+ if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), '>')) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr + 2*MINBPC(enc);
+ return XML_TOK_INVALID;
+ }
+ }
+ /* fall through */
+ case BT_AMP:
+ case BT_LT:
+ case BT_NONXML:
+ case BT_MALFORM:
+ case BT_TRAIL:
+ case BT_CR:
+ case BT_LF:
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "%" */
+
+static
+int PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
+ *nextTokPtr = ptr;
+ return XML_TOK_PERCENT;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_PARAM_ENTITY_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static
+int PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_CR: case BT_LF: case BT_S:
+ case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR:
+ *nextTokPtr = ptr;
+ return XML_TOK_POUND_NAME;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static
+int PREFIX(scanLit)(int opentype, const ENCODING *enc,
+ const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ while (ptr != end) {
+ int t = BYTE_TYPE(enc, ptr);
+ switch (t) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_QUOT:
+ case BT_APOS:
+ ptr += MINBPC(enc);
+ if (t != opentype)
+ break;
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ *nextTokPtr = ptr;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_CR: case BT_LF:
+ case BT_GT: case BT_PERCNT: case BT_LSQB:
+ return XML_TOK_LITERAL;
+ default:
+ return XML_TOK_INVALID;
+ }
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static
+int PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ int tok;
+ if (ptr == end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_QUOT:
+ return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_APOS:
+ return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LT:
+ {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_EXCL:
+ return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_QUEST:
+ return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_NMSTRT:
+ case BT_HEX:
+ case BT_NONASCII:
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ *nextTokPtr = ptr - MINBPC(enc);
+ return XML_TOK_INSTANCE_START;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ case BT_CR:
+ if (ptr + MINBPC(enc) == end)
+ return XML_TOK_TRAILING_CR;
+ /* fall through */
+ case BT_S: case BT_LF:
+ for (;;) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ break;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_LF:
+ break;
+ case BT_CR:
+ /* don't split CR/LF pair */
+ if (ptr + MINBPC(enc) != end)
+ break;
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_PROLOG_S;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_PROLOG_S;
+ case BT_PERCNT:
+ return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_COMMA:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COMMA;
+ case BT_LSQB:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OPEN_BRACKET;
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ']')) {
+ if (ptr + MINBPC(enc) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr + MINBPC(enc), '>')) {
+ *nextTokPtr = ptr + 2*MINBPC(enc);
+ return XML_TOK_COND_SECT_CLOSE;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_CLOSE_BRACKET;
+ case BT_LPAR:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OPEN_PAREN;
+ case BT_RPAR:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_AST:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_ASTERISK;
+ case BT_QUEST:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_QUESTION;
+ case BT_PLUS:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_PLUS;
+ case BT_CR: case BT_LF: case BT_S:
+ case BT_GT: case BT_COMMA: case BT_VERBAR:
+ case BT_RPAR:
+ *nextTokPtr = ptr;
+ return XML_TOK_CLOSE_PAREN;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_VERBAR:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OR;
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DECL_CLOSE;
+ case BT_NUM:
+ return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NAME; \
+ break; \
+ } \
+ if (IS_NAME_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NMTOKEN; \
+ break; \
+ } \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NMSTRT:
+ case BT_HEX:
+ tok = XML_TOK_NAME;
+ ptr += MINBPC(enc);
+ break;
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ tok = XML_TOK_NMTOKEN;
+ ptr += MINBPC(enc);
+ break;
+ case BT_NONASCII:
+ if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) {
+ ptr += MINBPC(enc);
+ tok = XML_TOK_NAME;
+ break;
+ }
+ if (IS_NAME_CHAR_MINBPC(enc, ptr)) {
+ ptr += MINBPC(enc);
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_GT: case BT_RPAR: case BT_COMMA:
+ case BT_VERBAR: case BT_LSQB: case BT_PERCNT:
+ case BT_S: case BT_CR: case BT_LF:
+ *nextTokPtr = ptr;
+ return tok;
+#ifdef XML_NS
+ case BT_COLON:
+ ptr += MINBPC(enc);
+ switch (tok) {
+ case XML_TOK_NAME:
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ tok = XML_TOK_PREFIXED_NAME;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ break;
+ case XML_TOK_PREFIXED_NAME:
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ break;
+#endif
+ case BT_PLUS:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_PLUS;
+ case BT_AST:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_ASTERISK;
+ case BT_QUEST:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_QUESTION;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static
+int PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ const char *start;
+ if (ptr == end)
+ return XML_TOK_NONE;
+ start = ptr;
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_AMP:
+ if (ptr == start)
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_LT:
+ /* this is for inside entity references */
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_LF:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_CR:
+ if (ptr == start) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_S:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_ATTRIBUTE_VALUE_S;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+static
+int PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ const char *start;
+ if (ptr == end)
+ return XML_TOK_NONE;
+ start = ptr;
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_AMP:
+ if (ptr == start)
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_PERCNT:
+ if (ptr == start)
+ return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_LF:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_CR:
+ if (ptr == start) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+static
+int PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **badPtr)
+{
+ ptr += MINBPC(enc);
+ end -= MINBPC(enc);
+ for (; ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ case BT_MINUS:
+ case BT_APOS:
+ case BT_LPAR:
+ case BT_RPAR:
+ case BT_PLUS:
+ case BT_COMMA:
+ case BT_SOL:
+ case BT_EQUALS:
+ case BT_QUEST:
+ case BT_CR:
+ case BT_LF:
+ case BT_SEMI:
+ case BT_EXCL:
+ case BT_AST:
+ case BT_PERCNT:
+ case BT_NUM:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ break;
+ case BT_S:
+ if (CHAR_MATCHES(enc, ptr, '\t')) {
+ *badPtr = ptr;
+ return 0;
+ }
+ break;
+ case BT_NAME:
+ case BT_NMSTRT:
+ if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
+ break;
+ default:
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case 0x24: /* $ */
+ case 0x40: /* @ */
+ break;
+ default:
+ *badPtr = ptr;
+ return 0;
+ }
+ break;
+ }
+ }
+ return 1;
+}
+
+/* This must only be called for a well-formed start-tag or empty element tag.
+Returns the number of attributes. Pointers to the first attsMax attributes
+are stored in atts. */
+
+static
+int PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
+ int attsMax, ATTRIBUTE *atts)
+{
+ enum { other, inName, inValue } state = inName;
+ int nAtts = 0;
+ int opentype = 0;
+
+ for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define START_NAME \
+ if (state == other) { \
+ if (nAtts < attsMax) { \
+ atts[nAtts].name = ptr; \
+ atts[nAtts].normalized = 1; \
+ } \
+ state = inName; \
+ }
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONASCII:
+ case BT_NMSTRT:
+ case BT_HEX:
+ START_NAME
+ break;
+#undef START_NAME
+ case BT_QUOT:
+ if (state != inValue) {
+ if (nAtts < attsMax)
+ atts[nAtts].valuePtr = ptr + MINBPC(enc);
+ state = inValue;
+ opentype = BT_QUOT;
+ }
+ else if (opentype == BT_QUOT) {
+ state = other;
+ if (nAtts < attsMax)
+ atts[nAtts].valueEnd = ptr;
+ nAtts++;
+ }
+ break;
+ case BT_APOS:
+ if (state != inValue) {
+ if (nAtts < attsMax)
+ atts[nAtts].valuePtr = ptr + MINBPC(enc);
+ state = inValue;
+ opentype = BT_APOS;
+ }
+ else if (opentype == BT_APOS) {
+ state = other;
+ if (nAtts < attsMax)
+ atts[nAtts].valueEnd = ptr;
+ nAtts++;
+ }
+ break;
+ case BT_AMP:
+ if (nAtts < attsMax)
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_S:
+ if (state == inName)
+ state = other;
+ else if (state == inValue
+ && nAtts < attsMax
+ && atts[nAtts].normalized
+ && (ptr == atts[nAtts].valuePtr
+ || BYTE_TO_ASCII(enc, ptr) != ' '
+ || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ' '
+ || BYTE_TYPE(enc, ptr + MINBPC(enc)) == opentype))
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_CR: case BT_LF:
+ /* This case ensures that the first attribute name is counted
+ Apart from that we could just change state on the quote. */
+ if (state == inName)
+ state = other;
+ else if (state == inValue && nAtts < attsMax)
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_GT:
+ case BT_SOL:
+ if (state != inValue)
+ return nAtts;
+ break;
+ default:
+ break;
+ }
+ }
+ /* not reached */
+}
+
+static
+int PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
+{
+ int result = 0;
+ /* skip &# */
+ ptr += 2*MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, 'x')) {
+ for (ptr += MINBPC(enc); !CHAR_MATCHES(enc, ptr, ';'); ptr += MINBPC(enc)) {
+ int c = BYTE_TO_ASCII(enc, ptr);
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ result <<= 4;
+ result |= (c - '0');
+ break;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ result <<= 4;
+ result += 10 + (c - 'A');
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ result <<= 4;
+ result += 10 + (c - 'a');
+ break;
+ }
+ if (result >= 0x110000)
+ return -1;
+ }
+ }
+ else {
+ for (; !CHAR_MATCHES(enc, ptr, ';'); ptr += MINBPC(enc)) {
+ int c = BYTE_TO_ASCII(enc, ptr);
+ result *= 10;
+ result += (c - '0');
+ if (result >= 0x110000)
+ return -1;
+ }
+ }
+ return checkCharRefNumber(result);
+}
+
+static
+int PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, const char *end)
+{
+ switch ((end - ptr)/MINBPC(enc)) {
+ case 2:
+ if (CHAR_MATCHES(enc, ptr + MINBPC(enc), 't')) {
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case 'l':
+ return '<';
+ case 'g':
+ return '>';
+ }
+ }
+ break;
+ case 3:
+ if (CHAR_MATCHES(enc, ptr, 'a')) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, 'm')) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, 'p'))
+ return '&';
+ }
+ }
+ break;
+ case 4:
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case 'q':
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, 'u')) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, 'o')) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, 't'))
+ return '"';
+ }
+ }
+ break;
+ case 'a':
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, 'p')) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, 'o')) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, 's'))
+ return '\'';
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static
+int PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
+{
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr1)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (*ptr1++ != *ptr2++) \
+ return 0;
+ LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2)
+#undef LEAD_CASE
+ /* fall through */
+ if (*ptr1++ != *ptr2++)
+ return 0;
+ break;
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 1) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 2) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 3) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ }
+ }
+ }
+ break;
+ default:
+ if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
+ return 1;
+ switch (BYTE_TYPE(enc, ptr2)) {
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ return 0;
+ default:
+ return 1;
+ }
+ }
+ }
+ /* not reached */
+}
+
+static
+int PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, const char *ptr2)
+{
+ for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
+ if (!CHAR_MATCHES(enc, ptr1, *ptr2))
+ return 0;
+ }
+ switch (BYTE_TYPE(enc, ptr1)) {
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+static
+int PREFIX(nameLength)(const ENCODING *enc, const char *ptr)
+{
+ const char *start = ptr;
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ return ptr - start;
+ }
+ }
+}
+
+static
+const char *PREFIX(skipS)(const ENCODING *enc, const char *ptr)
+{
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_LF:
+ case BT_CR:
+ case BT_S:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ return ptr;
+ }
+ }
+}
+
+static
+void PREFIX(updatePosition)(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ POSITION *pos)
+{
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_LF:
+ pos->columnNumber = (unsigned)-1;
+ pos->lineNumber++;
+ ptr += MINBPC(enc);
+ break;
+ case BT_CR:
+ pos->lineNumber++;
+ ptr += MINBPC(enc);
+ if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ pos->columnNumber = (unsigned)-1;
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ pos->columnNumber++;
+ }
+}
+
+#undef DO_LEAD_CASE
+#undef MULTIBYTE_CASES
+#undef INVALID_CASES
+#undef CHECK_NAME_CASE
+#undef CHECK_NAME_CASES
+#undef CHECK_NMSTRT_CASE
+#undef CHECK_NMSTRT_CASES
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmltok_impl.h b/usr.sbin/httpd/src/lib/expat-lite/xmltok_impl.h
new file mode 100644
index 00000000000..e72b225c838
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmltok_impl.h
@@ -0,0 +1,71 @@
+/*
+The contents of this file are subject to the Mozilla Public License
+Version 1.1 (the "License"); you may not use this file except in
+compliance with the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations
+under the License.
+
+The Original Code is expat.
+
+The Initial Developer of the Original Code is James Clark.
+Portions created by James Clark are Copyright (C) 1998, 1999
+James Clark. All Rights Reserved.
+
+Contributor(s):
+
+Alternatively, the contents of this file may be used under the terms
+of the GNU General Public License (the "GPL"), in which case the
+provisions of the GPL are applicable instead of those above. If you
+wish to allow use of your version of this file only under the terms of
+the GPL and not to allow others to use your version of this file under
+the MPL, indicate your decision by deleting the provisions above and
+replace them with the notice and other provisions required by the
+GPL. If you do not delete the provisions above, a recipient may use
+your version of this file under either the MPL or the GPL.
+*/
+
+enum {
+ BT_NONXML,
+ BT_MALFORM,
+ BT_LT,
+ BT_AMP,
+ BT_RSQB,
+ BT_LEAD2,
+ BT_LEAD3,
+ BT_LEAD4,
+ BT_TRAIL,
+ BT_CR,
+ BT_LF,
+ BT_GT,
+ BT_QUOT,
+ BT_APOS,
+ BT_EQUALS,
+ BT_QUEST,
+ BT_EXCL,
+ BT_SOL,
+ BT_SEMI,
+ BT_NUM,
+ BT_LSQB,
+ BT_S,
+ BT_NMSTRT,
+ BT_COLON,
+ BT_HEX,
+ BT_DIGIT,
+ BT_NAME,
+ BT_MINUS,
+ BT_OTHER, /* known not to be a name or name start character */
+ BT_NONASCII, /* might be a name or name start character */
+ BT_PERCNT,
+ BT_LPAR,
+ BT_RPAR,
+ BT_AST,
+ BT_PLUS,
+ BT_COMMA,
+ BT_VERBAR
+};
+
+#include <stddef.h>
diff --git a/usr.sbin/httpd/src/lib/expat-lite/xmltok_ns.c b/usr.sbin/httpd/src/lib/expat-lite/xmltok_ns.c
new file mode 100644
index 00000000000..a32c5774580
--- /dev/null
+++ b/usr.sbin/httpd/src/lib/expat-lite/xmltok_ns.c
@@ -0,0 +1,96 @@
+const ENCODING *NS(XmlGetUtf8InternalEncoding)(void)
+{
+ return &ns(internal_utf8_encoding).enc;
+}
+
+const ENCODING *NS(XmlGetUtf16InternalEncoding)(void)
+{
+#if XML_BYTE_ORDER == 12
+ return &ns(internal_little2_encoding).enc;
+#elif XML_BYTE_ORDER == 21
+ return &ns(internal_big2_encoding).enc;
+#else
+ const short n = 1;
+ return *(const char *)&n ? &ns(internal_little2_encoding).enc : &ns(internal_big2_encoding).enc;
+#endif
+}
+
+static
+const ENCODING *NS(encodings)[] = {
+ &ns(latin1_encoding).enc,
+ &ns(ascii_encoding).enc,
+ &ns(utf8_encoding).enc,
+ &ns(big2_encoding).enc,
+ &ns(big2_encoding).enc,
+ &ns(little2_encoding).enc,
+ &ns(utf8_encoding).enc /* NO_ENC */
+};
+
+static
+int NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE, ptr, end, nextTokPtr);
+}
+
+static
+int NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE, ptr, end, nextTokPtr);
+}
+
+int NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, const char *name)
+{
+ int i = getEncodingIndex(name);
+ if (i == UNKNOWN_ENC)
+ return 0;
+ INIT_ENC_INDEX(p) = (char)i;
+ p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
+ p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
+ p->initEnc.updatePosition = initUpdatePosition;
+ p->encPtr = encPtr;
+ *encPtr = &(p->initEnc);
+ return 1;
+}
+
+static
+const ENCODING *NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
+{
+#define ENCODING_MAX 128
+ char buf[ENCODING_MAX];
+ char *p = buf;
+ int i;
+ XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
+ if (ptr != end)
+ return 0;
+ *p = 0;
+ if (streqci(buf, "UTF-16") && enc->minBytesPerChar == 2)
+ return enc;
+ i = getEncodingIndex(buf);
+ if (i == UNKNOWN_ENC)
+ return 0;
+ return NS(encodings)[i];
+}
+
+int NS(XmlParseXmlDecl)(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **encodingName,
+ const ENCODING **encoding,
+ int *standalone)
+{
+ return doParseXmlDecl(NS(findEncoding),
+ isGeneralTextEntity,
+ enc,
+ ptr,
+ end,
+ badPtr,
+ versionPtr,
+ encodingName,
+ encoding,
+ standalone);
+}
diff --git a/usr.sbin/httpd/src/modules/experimental/mod_auth_digest.c b/usr.sbin/httpd/src/modules/experimental/mod_auth_digest.c
new file mode 100644
index 00000000000..43795221f86
--- /dev/null
+++ b/usr.sbin/httpd/src/modules/experimental/mod_auth_digest.c
@@ -0,0 +1,1919 @@
+/* ====================================================================
+ * Copyright (c) 1995-1999 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. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * 6. 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_auth_digest: MD5 digest authentication
+ *
+ * Originally by Alexei Kosut <akosut@nueva.pvt.k12.ca.us>
+ * Updated to RFC-2617 by Ronald Tschalär <ronald@innovation.ch>
+ * based on mod_auth, by Rob McCool and Robert S. Thau
+ *
+ * This module an updated version of modules/standard/mod_digest.c
+ * However, it has not been extensively tested yet, and is therefore
+ * currently marked experimental. Send problem reports to me
+ * (ronald@innovation.ch)
+ *
+ * Requires either /dev/random (or equivalent) or the truerand library,
+ * available for instance from
+ * ftp://research.att.com/dist/mab/librand.shar
+ *
+ * Open Issues:
+ * - qop=auth-int (when streams and trailer support available)
+ * - nonce-format configurability
+ * - Proxy-Authorization-Info header is set by this module, but is
+ * currently ignored by mod_proxy (needs patch to mod_proxy)
+ * - generating the secret takes a while (~ 8 seconds) if using the
+ * truerand library
+ * - shared-mem not completely tested yet. Seems to work ok for me,
+ * but... (definitely won't work on Windoze)
+ */
+
+/* The section for the Configure script:
+ * MODULE-DEFINITION-START
+ * Name: digest_auth_module
+ * ConfigStart
+
+ RULE_DEV_RANDOM=`./helpers/CutRule DEV_RANDOM $file`
+ if [ "$RULE_DEV_RANDOM" = "default" ]; then
+ if [ -r "/dev/random" ]; then
+ RULE_DEV_RANDOM="/dev/random"
+ elif [ -r "/dev/urandom" ]; then
+ RULE_DEV_RANDOM="/dev/urandom"
+ else
+ RULE_DEV_RANDOM="truerand"
+ if helpers/TestCompile func randbyte; then
+ :
+ elif helpers/TestCompile lib rand randbyte; then
+ :
+ else
+ echo " (mod_auth_digest) truerand library missing!"
+ echo "** This will most probably defeat successful compilation."
+ echo "** See Rule DEV_RANDOM in src/Configuration.tmpl for more information."
+ fi
+ fi
+ fi
+ if [ "$RULE_DEV_RANDOM" = "truerand" ]; then
+ echo " using truerand library (-lrand) for the random seed"
+ LIBS="$LIBS -L/usr/local/lib -lrand"
+ else
+ echo " using $RULE_DEV_RANDOM for the random seed"
+ CFLAGS="$CFLAGS -DDEV_RANDOM=$RULE_DEV_RANDOM"
+ fi
+
+ * ConfigEnd
+ * MODULE-DEFINITION-END
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_conf_globals.h"
+#include "http_core.h"
+#include "http_request.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "ap_config.h"
+#include "ap_ctype.h"
+#include "util_uri.h"
+#include "util_md5.h"
+#include "ap_sha1.h"
+#ifdef HAVE_SHMEM_MM
+#include "mm.h"
+#endif /* HAVE_SHMEM_MM */
+
+
+/* struct to hold the configuration info */
+
+typedef struct digest_config_struct {
+ const char *dir_name;
+ const char *pwfile;
+ const char *grpfile;
+ const char *realm;
+ const char **qop_list;
+ AP_SHA1_CTX nonce_ctx;
+ long nonce_lifetime;
+ const char *nonce_format;
+ int check_nc;
+ const char *algorithm;
+ char *uri_list;
+ const char *ha1;
+} digest_config_rec;
+
+
+#define DFLT_ALGORITHM "MD5"
+
+#define DFLT_NONCE_LIFE 300L
+#define NEXTNONCE_DELTA 30
+
+
+#define NONCE_TIME_LEN (((sizeof(time_t)+2)/3)*4)
+#define NONCE_HASH_LEN 40
+#define NONCE_LEN (NONCE_TIME_LEN + NONCE_HASH_LEN)
+
+#define SECRET_LEN 20
+
+
+/* client list definitions */
+
+typedef struct hash_entry {
+ unsigned long key; /* the key for this entry */
+ struct hash_entry *next; /* next entry in the bucket */
+ unsigned long nonce_count; /* for nonce-count checking */
+ char ha1[17]; /* for algorithm=MD5-sess */
+ char last_nonce[NONCE_LEN+1]; /* for one-time nonce's */
+} client_entry;
+
+static struct hash_table {
+ client_entry **table;
+ unsigned long tbl_len;
+ unsigned long num_entries;
+ unsigned long num_created;
+ unsigned long num_removed;
+ unsigned long num_renewed;
+} *client_list;
+
+
+/* struct to hold a parsed Authorization header */
+
+enum hdr_sts { NO_HEADER, NOT_DIGEST, INVALID, VALID };
+
+typedef struct digest_header_struct {
+ const char *scheme;
+ const char *realm;
+ const char *username;
+ char *nonce;
+ const char *uri;
+ const char *digest;
+ const char *algorithm;
+ const char *cnonce;
+ const char *opaque;
+ unsigned long opaque_num;
+ const char *message_qop;
+ const char *nonce_count;
+ /* the following fields are not (directly) from the header */
+ time_t nonce_time;
+ enum hdr_sts auth_hdr_sts;
+ uri_components *request_uri;
+ int needed_auth;
+ client_entry *client;
+} digest_header_rec;
+
+
+/* (mostly) nonce stuff */
+
+typedef union time_union {
+ time_t time;
+ unsigned char arr[sizeof(time_t)];
+} time_rec;
+
+
+static unsigned char secret[SECRET_LEN];
+static int call_cnt = 0;
+
+
+#ifdef HAVE_SHMEM_MM
+/* opaque stuff */
+
+static MM *opaque_mm;
+static unsigned long *opaque_cntr;
+
+static MM *client_mm;
+
+static MM *otn_count_mm;
+static time_t *otn_counter; /* one-time-nonce counter */
+
+#define SHMEM_SIZE 1000 /* ~ 12 entries */
+#define NUM_BUCKETS 15UL
+
+#else /* HAVE_SHMEM_MM */
+static void *client_mm = NULL;
+#endif /* HAVE_SHMEM_MM */
+
+module MODULE_VAR_EXPORT digest_auth_module;
+
+/*
+ * initialization code
+ */
+
+#ifdef HAVE_SHMEM_MM
+static void cleanup_tables(void *not_used)
+{
+ fprintf(stderr, "Digest: cleaning up shared memory\n");
+ fflush(stderr);
+
+ if (client_mm) {
+ mm_destroy(client_mm);
+ client_mm = NULL;
+ }
+
+ if (opaque_mm) {
+ mm_destroy(opaque_mm);
+ opaque_mm = NULL;
+ }
+
+ if (otn_count_mm) {
+ mm_destroy(otn_count_mm);
+ otn_count_mm = NULL;
+ }
+}
+#endif /* HAVE_SHMEM_MM */
+
+static void initialize_secret(server_rec *s)
+{
+#ifdef DEV_RANDOM
+ FILE *rnd;
+ size_t got, tot;
+#else
+ extern int randbyte(void); /* from the truerand library */
+ unsigned int idx;
+#endif
+
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s,
+ "Digest: generating secret for digest authentication ...");
+
+#ifdef DEV_RANDOM
+#define XSTR(x) #x
+#define STR(x) XSTR(x)
+ if ((rnd = fopen(STR(DEV_RANDOM), "rb")) == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, s,
+ "Digest: Couldn't open " STR(DEV_RANDOM));
+ exit(EXIT_FAILURE);
+ }
+ if (setvbuf(rnd, NULL, _IONBF, 0) != 0) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, s,
+ "Digest: Error trying to disable buffering for " STR(DEV_RANDOM));
+ exit(EXIT_FAILURE);
+ }
+ for (tot=0; tot<sizeof(secret); tot += got) {
+ if ((got = fread(secret+tot, 1, sizeof(secret)-tot, rnd)) < 1) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, s,
+ "Digest: Error reading " STR(DEV_RANDOM));
+ exit(EXIT_FAILURE);
+ }
+ }
+ fclose(rnd);
+#undef STR
+#undef XSTR
+#else /* use truerand */
+ /* this will increase the startup time of the server, unfortunately...
+ * (generating 20 bytes takes about 8 seconds)
+ */
+ for (idx=0; idx<sizeof(secret); idx++)
+ secret[idx] = (unsigned char) randbyte();
+#endif /* DEV_RANDOM */
+
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, s, "Digest: done");
+}
+
+#ifdef HAVE_SHMEM_MM
+static void initialize_tables(server_rec *s)
+{
+ unsigned long idx;
+
+ /* set up client list */
+
+ client_mm = mm_create(SHMEM_SIZE, tmpnam(NULL));
+ if (client_mm == NULL)
+ goto failed;
+#ifdef MPE
+ if (geteuid() == 1) {
+#else
+ if (geteuid() == 0) {
+#endif
+ if (mm_permission(client_mm, 0600, ap_user_id, ap_group_id))
+ goto failed;
+ }
+ client_list = mm_malloc(client_mm, sizeof(*client_list) +
+ sizeof(client_entry*)*NUM_BUCKETS);
+ if (!client_list) goto failed;
+ client_list->table = (client_entry**) (client_list + 1);
+ for (idx=0; idx<NUM_BUCKETS; idx++)
+ client_list->table[idx] = NULL;
+ client_list->tbl_len = NUM_BUCKETS;
+ client_list->num_entries = 0;
+
+
+ /* setup opaque */
+
+ opaque_mm = mm_create(sizeof(*opaque_cntr), tmpnam(NULL));
+ if (opaque_mm == NULL)
+ goto failed;
+#ifdef MPE
+ if (geteuid() == 1) {
+#else
+ if (geteuid() == 0) {
+#endif
+ if (mm_permission(opaque_mm, 0600, ap_user_id, ap_group_id))
+ goto failed;
+ }
+ opaque_cntr = mm_malloc(opaque_mm, sizeof(*opaque_cntr));
+ if (opaque_cntr == NULL)
+ goto failed;
+ *opaque_cntr = 1UL;
+
+
+ /* setup one-time-nonce counter */
+
+ otn_count_mm = mm_create(sizeof(*otn_counter), tmpnam(NULL));
+ if (otn_count_mm == NULL)
+ goto failed;
+#ifdef MPE
+ if (geteuid() == 1) {
+#else
+ if (geteuid() == 0) {
+#endif
+ if (mm_permission(otn_count_mm, 0600, ap_user_id, ap_group_id))
+ goto failed;
+ }
+ otn_counter = mm_malloc(otn_count_mm, sizeof(*otn_counter));
+ if (otn_counter == NULL)
+ goto failed;
+ *otn_counter = 0;
+
+
+ /* success */
+ return;
+
+failed:
+ if (!client_mm || (client_list && client_list->table && !opaque_mm)
+ || (opaque_cntr && !otn_count_mm))
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s,
+ "Digest: failed to create shared memory segments; reason "
+ "was `%s' - all nonce-count checking, one-time nonces, "
+ "and MD5-sess algorithm disabled", mm_error());
+ else
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, s,
+ "Digest: failed to allocate shared mem; reason was `%s' "
+ "- all nonce-count checking, one-time nonces, and "
+ "MD5-sess algorithm disabled", mm_error());
+
+ cleanup_tables(NULL);
+}
+#endif /* HAVE_SHMEM_MM */
+
+static void initialize_module(server_rec *s, pool *p)
+{
+ /* keep from doing the init more than once at startup, and delay
+ * the init until the second round
+ */
+ if (++call_cnt < 2)
+ return;
+
+ /* only initialize the secret on startup, not on restarts */
+ if (call_cnt == 2)
+ initialize_secret(s);
+
+#ifdef HAVE_SHMEM_MM
+ /* Note: this stuff is currently fixed for the lifetime of the server,
+ * i.e. even across restarts. This means that A) any shmem-size
+ * configuration changes are ignored, and B) certain optimizations,
+ * such as only allocating the smallest necessary entry for each
+ * client, can't be done. However, the alternative is a nightmare:
+ * we can't call mm_destroy on a graceful restart because there will
+ * be children using the tables, and we also don't know when the
+ * last child dies. Therefore we can never clean up the old stuff,
+ * creating a creeping memory leak.
+ */
+ initialize_tables(s);
+ /* atexit(cleanup_tables); */
+ ap_register_cleanup(p, NULL, cleanup_tables, ap_null_cleanup);
+#endif /* HAVE_SHMEM_MM */
+}
+
+
+/*
+ * configuration code
+ */
+
+static void *create_digest_dir_config(pool *p, char *dir)
+{
+ digest_config_rec *conf;
+
+ if (dir == NULL) return NULL;
+
+ conf = (digest_config_rec *) ap_pcalloc(p, sizeof(digest_config_rec));
+ if (conf) {
+ conf->qop_list = ap_palloc(p, sizeof(char*));
+ conf->qop_list[0] = NULL;
+ conf->nonce_lifetime = DFLT_NONCE_LIFE;
+ conf->dir_name = ap_pstrdup(p, dir);
+ conf->algorithm = DFLT_ALGORITHM;
+ }
+
+ return conf;
+}
+
+static const char *set_realm(cmd_parms *cmd, void *config, const char *realm)
+{
+ digest_config_rec *conf = (digest_config_rec *) config;
+
+ /* The core already handles the realm, but it's just too convenient to
+ * grab it ourselves too and cache some setups. However, we need to
+ * let the core get at it too, which is why we decline at the end -
+ * this relies on the fact that http_core is last in the list.
+ */
+ conf->realm = realm;
+
+ /* we precompute the part of the nonce hash that is constant (well,
+ * the host:port would be too, but that varies for .htaccess files
+ * and directives outside a virtual host section)
+ */
+ ap_SHA1Init(&conf->nonce_ctx);
+ ap_SHA1Update_binary(&conf->nonce_ctx, (const unsigned char *) realm,
+ strlen(realm));
+ ap_SHA1Update_binary(&conf->nonce_ctx, secret, sizeof(secret));
+
+ return DECLINE_CMD;
+}
+
+static const char *set_digest_file(cmd_parms *cmd, void *config,
+ const char *file)
+{
+ ((digest_config_rec *) config)->pwfile = file;
+ return NULL;
+}
+
+static const char *set_group_file(cmd_parms *cmd, void *config,
+ const char *file)
+{
+ ((digest_config_rec *) config)->grpfile = file;
+ return NULL;
+}
+
+static const char *set_qop(cmd_parms *cmd, void *config, const char *op)
+{
+ digest_config_rec *conf = (digest_config_rec *) config;
+ const char **tmp;
+ int cnt;
+
+ if (!strcasecmp(op, "none")) {
+ if (conf->qop_list[0] == NULL) {
+ conf->qop_list = ap_palloc(cmd->pool, 2 * sizeof(char*));
+ conf->qop_list[1] = NULL;
+ }
+ conf->qop_list[0] = "none";
+ return NULL;
+ }
+
+ if (!strcasecmp(op, "auth-int"))
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, cmd->server,
+ "Digest: WARNING: qop `auth-int' currently only works "
+ "correctly for responses with no entity");
+ else if (strcasecmp(op, "auth"))
+ return ap_pstrcat(cmd->pool, "Unrecognized qop: ", op, NULL);
+
+ for (cnt=0; conf->qop_list[cnt] != NULL; cnt++)
+ ;
+ tmp = ap_palloc(cmd->pool, (cnt+2)*sizeof(char*));
+ memcpy(tmp, conf->qop_list, cnt*sizeof(char*));
+ tmp[cnt] = ap_pstrdup(cmd->pool, op);
+ tmp[cnt+1] = NULL;
+ conf->qop_list = tmp;
+
+ return NULL;
+}
+
+static const char *set_nonce_lifetime(cmd_parms *cmd, void *config,
+ const char *t)
+{
+ char *endptr;
+ long lifetime;
+
+ lifetime = strtol(t, &endptr, 10);
+ if (endptr < (t+strlen(t)) && !ap_isspace(*endptr))
+ return ap_pstrcat(cmd->pool, "Invalid time in AuthDigestNonceLifetime: ", t, NULL);
+
+ ((digest_config_rec *) config)->nonce_lifetime = lifetime;
+ return NULL;
+}
+
+static const char *set_nonce_format(cmd_parms *cmd, void *config,
+ const char *fmt)
+{
+ ((digest_config_rec *) config)->nonce_format = fmt;
+ return "AuthDigestNonceFormat is not implemented (yet)";
+}
+
+static const char *set_nc_check(cmd_parms *cmd, void *config, int flag)
+{
+ ((digest_config_rec *) config)->check_nc = flag;
+ return NULL;
+}
+
+static const char *set_algorithm(cmd_parms *cmd, void *config, const char *alg)
+{
+ if (!strcasecmp(alg, "MD5-sess"))
+#ifdef HAVE_SHMEM_MM
+ ;
+#else /* HAVE_SHMEM_MM */
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, cmd->server,
+ "Digest: WARNING: algorithm `MD5-sess' is currently not "
+ "correctly implemented");
+#endif /* HAVE_SHMEM_MM */
+ else if (strcasecmp(alg, "MD5"))
+ return ap_pstrcat(cmd->pool, "Invalid algorithm in AuthDigestAlgorithm: ", alg, NULL);
+
+ ((digest_config_rec *) config)->algorithm = alg;
+ return NULL;
+}
+
+static const char *set_uri_list(cmd_parms *cmd, void *config, const char *uri)
+{
+ digest_config_rec *c = (digest_config_rec *) config;
+ if (c->uri_list) {
+ c->uri_list[strlen(c->uri_list)-1] = '\0';
+ c->uri_list = ap_pstrcat(cmd->pool, c->uri_list, " ", uri, "\"", NULL);
+ }
+ else
+ c->uri_list = ap_pstrcat(cmd->pool, ", domain=\"", uri, "\"", NULL);
+ return NULL;
+}
+
+static const command_rec digest_cmds[] =
+{
+ {"AuthName", set_realm, NULL, OR_AUTHCFG, TAKE1,
+ "The authentication realm (e.g. \"Members Only\")"},
+ {"AuthDigestFile", set_digest_file, NULL, OR_AUTHCFG, TAKE1,
+ "The name of the file containing the usernames and password hashes"},
+ {"AuthDigestGroupFile", set_group_file, NULL, OR_AUTHCFG, TAKE1,
+ "The name of the file containing the group names and members"},
+ {"AuthDigestQop", set_qop, NULL, OR_AUTHCFG, ITERATE,
+ "A list of quality-of-protection options"},
+ {"AuthDigestNonceLifetime", set_nonce_lifetime, NULL, OR_AUTHCFG, TAKE1,
+ "Maximum lifetime of the server nonce (seconds)"},
+ {"AuthDigestNonceFormat", set_nonce_format, NULL, OR_AUTHCFG, TAKE1,
+ "The format to use when generating the server nonce"},
+ {"AuthDigestNcCheck", set_nc_check, NULL, OR_AUTHCFG, FLAG,
+ "Whether or not to check the nonce-count sent by the client"},
+ {"AuthDigestAlgorithm", set_algorithm, NULL, OR_AUTHCFG, TAKE1,
+ "The algorithm used for the hash calculation"},
+ {"AuthDigestDomain", set_uri_list, NULL, OR_AUTHCFG, ITERATE,
+ "A list of URI's which belong to the same protection space as the current URI"},
+ {NULL}
+};
+
+
+#ifdef HAVE_SHMEM_MM
+/*
+ * client list code
+ *
+ * Each client is assigned a number, which is transfered in the opaque
+ * field of the WWW-Authenticate and Authorization headers. The number
+ * is just a simple counter which is incremented for each new client.
+ * Clients can't forge this number because it is hashed up into the
+ * server nonce, and that is checked.
+ *
+ * The clients are kept in a simple hash table, which consists of an
+ * array of client_entry's, each with a linked list of entries hanging
+ * off it. The client's number modulo the size of the array gives the
+ * bucket number.
+ *
+ * The clients are garbage collected whenever a new client is allocated
+ * but there is not enough space left in the shared memory segment. A
+ * simple semi-LRU is used for this: whenever a client entry is accessed
+ * it is moved to the beginning of the linked list in its bucket (this
+ * also makes for faster lookups for current clients). The garbage
+ * collecter then just removes the oldest entry (i.e. the one at the
+ * end of the list) in each bucket.
+ *
+ * The main advantages of the above scheme are that it's easy to implement
+ * and it keeps the hash table evenly balanced (i.e. same number of entries
+ * in each bucket). The major disadvantage is that you may be throwing
+ * entries out which are in active use. This is not tragic, as these
+ * clients will just be sent a new client id (opaque field) and nonce
+ * with a stale=true (i.e. it will just look like the nonce expired,
+ * thereby forcing an extra round trip). If the shared memory segment
+ * has enough headroom over the current client set size then this should
+ * not occur too often.
+ *
+ * To help tune the size of the shared memory segment (and see if the
+ * above algorithm is really sufficient) a set of counters is kept
+ * indicating the number of clients held, the number of garbage collected
+ * clients, and the number of erroneously purged clients. These are printed
+ * out at each garbage collection run. Note that access to the counters is
+ * not synchronized because they are just indicaters, and whether they are
+ * off by a few doesn't matter; and for the same reason no attempt is made
+ * to guarantee the num_renewed is correct in the face of clients spoofing
+ * the opaque field.
+ */
+
+/*
+ * Get the client given its client number (the key). Returns the entry,
+ * or NULL if its not found.
+ *
+ * Access to the list itself is synchronized via locks. However, access
+ * to the entry returned by get_client() is NOT synchronized. This means
+ * that there are potentially problems if a client uses multiple,
+ * simultaneous connections to access url's within the same protection
+ * space. However, these problems are not new: when using multiple
+ * connections you have no guarantee of the order the requests are
+ * processed anyway, so you have problems with the nonce-count and
+ * one-time nonces anyway.
+ */
+static client_entry *get_client(unsigned long key, const request_rec *r)
+{
+ int bucket;
+ client_entry *entry, *prev = NULL;
+
+
+ if (!key || !client_mm) return NULL;
+
+ bucket = key % client_list->tbl_len;
+ entry = client_list->table[bucket];
+
+ mm_lock(client_mm, MM_LOCK_RD);
+
+ while(entry && key != entry->key) {
+ prev = entry;
+ entry = entry->next;
+ }
+
+ if (entry && prev) { /* move entry to front of list */
+ prev->next = entry->next;
+ entry->next = client_list->table[bucket];
+ client_list->table[bucket] = entry;
+ }
+
+ mm_unlock(client_mm);
+
+ if (entry)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
+ "get_client(): client %lu found", key);
+ else
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
+ "get_client(): client %lu not found", key);
+
+ return entry;
+}
+
+
+/* A simple garbage-collecter to remove unused clients. It removes the
+ * last entry in each bucket and updates the counters. Returns the
+ * number of removed entries.
+ */
+static long gc(void)
+{
+ client_entry *entry, *prev;
+ unsigned long num_removed = 0, idx;
+
+ /* garbage collect all last entries */
+
+ for (idx=0; idx<client_list->tbl_len; idx++) {
+ entry = client_list->table[idx];
+ prev = NULL;
+ while (entry->next) { /* find last entry */
+ prev = entry;
+ entry = entry->next;
+ }
+ if (prev) prev->next = NULL; /* cut list */
+ else client_list->table[idx] = NULL;
+ if (entry) { /* remove entry */
+ mm_free(client_mm, entry);
+ num_removed++;
+ }
+ }
+
+ /* update counters and log */
+
+ client_list->num_entries -= num_removed;
+ client_list->num_removed += num_removed;
+
+ return num_removed;
+}
+
+
+/*
+ * Add a new client to the list. Returns the entry if successful, NULL
+ * otherwise. This triggers the garbage collection is memory is low.
+ */
+static client_entry *add_client(unsigned long key, client_entry *new,
+ server_rec *s)
+{
+ int bucket;
+ client_entry *entry;
+
+
+ if (!key || !client_mm) return NULL;
+
+ bucket = key % client_list->tbl_len;
+ entry = client_list->table[bucket];
+
+ mm_lock(client_mm, MM_LOCK_RW);
+
+ /* try to allocate a new entry */
+
+ entry = mm_malloc(client_mm, sizeof(client_entry));
+ if (!entry) {
+ long num_removed = gc();
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, s,
+ "Digest: gc'd %ld client entries. Total new clients: "
+ "%ld; Total removed clients: %ld; Total renewed clients: "
+ "%ld", num_removed,
+ client_list->num_created - client_list->num_renewed,
+ client_list->num_removed, client_list->num_renewed);
+ entry = mm_malloc(client_mm, sizeof(client_entry));
+ if (!entry) return NULL; /* give up */
+ }
+
+ /* now add the entry */
+
+ memcpy(entry, new, sizeof(client_entry));
+ entry->key = key;
+ entry->next = client_list->table[bucket];
+ client_list->table[bucket] = entry;
+ client_list->num_created++;
+ client_list->num_entries++;
+
+ mm_unlock(client_mm);
+
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, s,
+ "allocated new client %lu", key);
+
+ return entry;
+}
+#else /* HAVE_SHMEM_MM */
+static client_entry *get_client(unsigned long key, const request_rec *r)
+{
+ return NULL;
+}
+#endif /* HAVE_SHMEM_MM */
+
+
+/*
+ * Authorization header parser code
+ */
+
+/* Parse the Authorization header, if it exists */
+static int get_digest_rec(request_rec *r, digest_header_rec *resp)
+{
+ const char *auth_line = ap_table_get(r->headers_in,
+ r->proxyreq ? "Proxy-Authorization"
+ : "Authorization");
+ size_t l;
+ int vk = 0, vv = 0;
+ char *key, *value;
+
+
+ if (!auth_line) {
+ resp->auth_hdr_sts = NO_HEADER;
+ return !OK;
+ }
+
+ resp->scheme = ap_getword_white(r->pool, &auth_line);
+ if (strcasecmp(resp->scheme, "Digest")) {
+ resp->auth_hdr_sts = NOT_DIGEST;
+ return !OK;
+ }
+
+ l = strlen(auth_line);
+
+ key = ap_palloc(r->pool, l+1);
+ value = ap_palloc(r->pool, l+1);
+
+ while (auth_line[0] != '\0') {
+
+ /* find key */
+
+ while (ap_isspace(auth_line[0])) auth_line++;
+ vk = 0;
+ while (auth_line[0] != '=' && auth_line[0] != ','
+ && auth_line[0] != '\0' && !ap_isspace(auth_line[0]))
+ key[vk++] = *auth_line++;
+ key[vk] = '\0';
+ while (ap_isspace(auth_line[0])) auth_line++;
+
+ /* find value */
+
+ if (auth_line[0] == '=') {
+ auth_line++;
+ while (ap_isspace(auth_line[0])) auth_line++;
+
+ vv = 0;
+ if (auth_line[0] == '\"') { /* quoted string */
+ auth_line++;
+ while (auth_line[0] != '\"' && auth_line[0] != '\0') {
+ if (auth_line[0] == '\\' && auth_line[1] != '\0')
+ auth_line++; /* escaped char */
+ value[vv++] = *auth_line++;
+ }
+ if (auth_line[0] != '\0') auth_line++;
+ }
+ else { /* token */
+ while (auth_line[0] != ',' && auth_line[0] != '\0'
+ && !ap_isspace(auth_line[0]))
+ value[vv++] = *auth_line++;
+ }
+ value[vv] = '\0';
+ }
+
+ while (auth_line[0] != ',' && auth_line[0] != '\0') auth_line++;
+ if (auth_line[0] != '\0') auth_line++;
+
+ if (!strcasecmp(key, "username"))
+ resp->username = ap_pstrdup(r->pool, value);
+ else if (!strcasecmp(key, "realm"))
+ resp->realm = ap_pstrdup(r->pool, value);
+ else if (!strcasecmp(key, "nonce"))
+ resp->nonce = ap_pstrdup(r->pool, value);
+ else if (!strcasecmp(key, "uri"))
+ resp->uri = ap_pstrdup(r->pool, value);
+ else if (!strcasecmp(key, "response"))
+ resp->digest = ap_pstrdup(r->pool, value);
+ else if (!strcasecmp(key, "algorithm"))
+ resp->algorithm = ap_pstrdup(r->pool, value);
+ else if (!strcasecmp(key, "cnonce"))
+ resp->cnonce = ap_pstrdup(r->pool, value);
+ else if (!strcasecmp(key, "opaque"))
+ resp->opaque = ap_pstrdup(r->pool, value);
+ else if (!strcasecmp(key, "qop"))
+ resp->message_qop = ap_pstrdup(r->pool, value);
+ else if (!strcasecmp(key, "nc"))
+ resp->nonce_count = ap_pstrdup(r->pool, value);
+ }
+
+ if (!resp->username || !resp->realm || !resp->nonce || !resp->uri
+ || !resp->digest) {
+ resp->auth_hdr_sts = INVALID;
+ return !OK;
+ }
+
+ if (resp->opaque)
+ resp->opaque_num = (unsigned long) strtol(resp->opaque, NULL, 16);
+
+ resp->auth_hdr_sts = VALID;
+ return OK;
+}
+
+
+/* Because the browser may preemptively send auth info, incrementing the
+ * nonce-count when it does, and because the client does not get notified
+ * if the URI didn't need authentication after all, we need to be sure to
+ * update the nonce-count each time we receive an Authorization header no
+ * matter what the final outcome of the request. Furthermore this is a
+ * convenient place to get the request-uri (before any subrequests etc
+ * are initiated) and to initialize the request_config.
+ *
+ * Note that this must be called after mod_proxy had its go so that
+ * r->proxyreq is set correctly.
+ */
+static int update_nonce_count(request_rec *r)
+{
+ digest_header_rec *resp;
+ int res;
+
+ if (!ap_is_initial_req(r))
+ return DECLINED;
+
+ resp = ap_pcalloc(r->pool, sizeof(digest_header_rec));
+ resp->request_uri = &r->parsed_uri;
+ resp->needed_auth = 0;
+ ap_set_module_config(r->request_config, &digest_auth_module, resp);
+
+ res = get_digest_rec(r, resp);
+ resp->client = get_client(resp->opaque_num, r);
+ if (res == OK && resp->client)
+ resp->client->nonce_count++;
+
+ return DECLINED;
+}
+
+
+/*
+ * Nonce generation code
+ */
+
+/* The hash part of the nonce is a SHA-1 hash of the time, realm, opaque,
+ * and our secret.
+ */
+static void gen_nonce_hash(char *hash, const char *timestr, const char *opaque,
+ const server_rec *server,
+ const digest_config_rec *conf)
+{
+ const char *hex = "0123456789abcdef";
+ unsigned char sha1[SHA_DIGESTSIZE];
+ AP_SHA1_CTX ctx;
+ int idx;
+
+ memcpy(&ctx, &conf->nonce_ctx, sizeof(ctx));
+ ap_SHA1Update_binary(&ctx, (const unsigned char *) server->server_hostname,
+ strlen(server->server_hostname));
+ ap_SHA1Update_binary(&ctx, (const unsigned char *) &server->port,
+ sizeof(server->port));
+ ap_SHA1Update_binary(&ctx, (const unsigned char *) timestr, strlen(timestr));
+ if (opaque)
+ ap_SHA1Update_binary(&ctx, (const unsigned char *) opaque,
+ strlen(opaque));
+ ap_SHA1Final(sha1, &ctx);
+
+ for (idx=0; idx<SHA_DIGESTSIZE; idx++) {
+ *hash++ = hex[sha1[idx] >> 4];
+ *hash++ = hex[sha1[idx] & 0xF];
+ }
+
+ *hash++ = '\0';
+}
+
+
+/* The nonce has the format b64(time)+hash .
+ */
+static const char *gen_nonce(pool *p, time_t now, const char *opaque,
+ const server_rec *server,
+ const digest_config_rec *conf)
+{
+ char *nonce = ap_palloc(p, NONCE_LEN+1);
+ time_rec t;
+
+ if (conf->nonce_lifetime != 0)
+ t.time = now;
+ else
+#ifdef HAVE_SHMEM_MM
+ /* this counter is not synch'd, because it doesn't really matter
+ * if it counts exactly.
+ */
+ t.time = (*otn_counter)++;
+#else /* HAVE_SHMEM_MM */
+ t.time = 42;
+#endif /* HAVE_SHMEM_MM */
+ ap_base64encode_binary(nonce, t.arr, sizeof(t.arr));
+ gen_nonce_hash(nonce+NONCE_TIME_LEN, nonce, opaque, server, conf);
+
+ return nonce;
+}
+
+
+/*
+ * Opaque and hash-table management
+ */
+
+#ifdef HAVE_SHMEM_MM
+/*
+ * Generate a new client entry, add it to the list, and return the
+ * entry. Returns NULL if failed.
+ */
+static client_entry *gen_client(const request_rec *r)
+{
+ unsigned long op;
+ client_entry new = { 0, NULL, 0, "", "" }, *entry;
+
+ if (!opaque_mm) return 0;
+
+ mm_lock(opaque_mm, MM_LOCK_RW);
+ op = (*opaque_cntr)++;
+ mm_unlock(opaque_mm);
+
+ if (!(entry = add_client(op, &new, r->server))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
+ "Digest: failed to allocate client entry - ignoring "
+ "client");
+ return NULL;
+ }
+
+ return entry;
+}
+#else /* HAVE_SHMEM_MM */
+static client_entry *gen_client(const request_rec *r) { return NULL; }
+#endif /* HAVE_SHMEM_MM */
+
+
+
+/*
+ * MD5-sess code.
+ *
+ * If you want to use algorithm=MD5-sess you must write get_userpw_hash()
+ * yourself (see below). The dummy provided here just returns the hash
+ * from the auth-file, i.e. it is only useful for testing client
+ * implementations of MD5-sess .
+ */
+
+/*
+ * get_userpw_hash() will be called each time a new session needs to be
+ * generated and is expected to return the equivalent of
+ *
+ * ap_md5(r->pool,
+ * ap_pstrcat(r->pool, username, ":", ap_auth_name(r), ":", passwd))
+ *
+ * You must implement this yourself, and will probably consist of code
+ * contacting the password server and retrieving the hash from it.
+ *
+ * TBD: This function should probably be in a seperate source file so that
+ * people need not modify mod_auth_digest.c each time they install a new version
+ * of apache.
+ */
+static const char *get_userpw_hash(const request_rec *r,
+ const digest_header_rec *resp,
+ const digest_config_rec *conf)
+{
+ /* for now, just get it from pwfile */
+ return conf->ha1;
+}
+
+
+static const char *get_session(const request_rec *r,
+ digest_header_rec *resp,
+ const digest_config_rec *conf)
+{
+ const char *ha1 = NULL, *urp;
+
+ /* get ha1 from client list */
+ if (resp->opaque && resp->client)
+ ha1 = resp->client->ha1;
+
+ /* generate new session if necessary */
+ if (ha1 == NULL || ha1[0] == '\0') {
+ urp = get_userpw_hash(r, resp, conf);
+ ha1 = ap_md5(r->pool,
+ (unsigned char *) ap_pstrcat(r->pool, ha1, ":", resp->nonce,
+ ":", resp->cnonce, NULL));
+ if (!resp->client)
+ resp->client = gen_client(r);
+ if (resp->client)
+ memcpy(resp->client->ha1, ha1, 17);
+ }
+
+ return ha1;
+}
+
+
+static void clear_session(const digest_header_rec *resp)
+{
+ if (resp->client)
+ resp->client->ha1[0] = '\0';
+}
+
+
+/*
+ * Authorization challenge generation code (for WWW-Authenticate)
+ */
+
+static const char *guess_domain(pool *p, const char *uri, const char *filename,
+ const char *dir)
+{
+ size_t u_len = strlen(uri), f_len = strlen(filename), d_len = strlen(dir);
+ const char *u, *f;
+
+
+ /* Because of things like mod_alias and mod_rewrite and the fact that
+ * protection is often on a directory basis (not a location basis) it
+ * is hard to determine the uri to put in the domain attribute.
+ *
+ * What we do is the following: first we see if the directory is
+ * a prefix for the uri - if this is the case we assume that therefore
+ * a <Location> directive was protecting this uri and we can use it
+ * for the domain.
+ */
+ if (u_len >= d_len && !memcmp(uri, dir, d_len))
+ return dir;
+
+ /* Now we check for <Files ...>, and if we find one we send back a
+ * dummy uri - this is the only way to specify that the protection
+ * space only covers a single uri.
+ */
+ if (dir[0] != '/')
+ /* This doesn't work for Amaya (ok, it's of arguable validity in
+ * the first place), so just return the file name instead
+ return "http://0.0.0.0/";
+ */
+ return dir;
+
+ /* Next we find the largest common common suffix of the request-uri
+ * and the final file name, ignoring any extensions; this gives us a
+ * hint as to where any rewriting could've occured (assuming that some
+ * prefix of the uri is rewritten, not a suffix).
+ */
+ u = uri + u_len - 1; /* strip any extension */
+ while (u > uri && *u != '/') u--;
+ while (*u && *u != '.') u++;
+ if (*u == '.') u--;
+ if (*u == '/') u--;
+
+ f = filename + f_len - 1; /* strip any extension */
+ while (f > filename && *f != '/') f--;
+ while (*f && *f != '.') f++;
+ if (*f == '.') f--;
+ if (*f == '/') f--;
+
+ while (*f == *u && f > filename && u > uri) u--, f--;
+ f++; u++;
+
+ while (*f && *f != '/') f++, u++; /* suffix must start with / */
+
+ /* Now, if the directory reaches into this common suffix then we can
+ * take the uri with the same reach.
+ */
+ if ((unsigned long) (f-filename) < d_len) {
+ char *tmp = ap_pstrdup(p, uri);
+ tmp[(u-uri)+(d_len-(f-filename))] = '\0';
+ return tmp;
+ }
+
+ return ""; /* give up */
+}
+
+
+static const char *ltox(pool *p, unsigned long num)
+{
+ if (num != 0)
+ return ap_psprintf(p, "%lx", num);
+ else
+ return "";
+}
+
+static void note_digest_auth_failure(request_rec *r,
+ const digest_config_rec *conf,
+ digest_header_rec *resp, int stale)
+{
+ const char *qop, *opaque, *opaque_param, *domain, *nonce;
+ int cnt;
+
+
+ /* Setup qop */
+
+ if (conf->qop_list[0] == NULL)
+ qop = ", qop=\"auth\"";
+ else if (!strcasecmp(conf->qop_list[0], "none"))
+ qop = "";
+ else {
+ qop = ap_pstrcat(r->pool, ", qop=\"", conf->qop_list[0], NULL);
+ for (cnt=1; conf->qop_list[cnt] != NULL; cnt++)
+ qop = ap_pstrcat(r->pool, qop, ",", conf->qop_list[cnt], NULL);
+ qop = ap_pstrcat(r->pool, qop, "\"", NULL);
+ }
+
+ /* MD5-sess stuff */
+
+ if (!stale && !strcasecmp(conf->algorithm, "MD5-sess"))
+ clear_session(resp);
+
+ /* Setup opaque */
+
+ if (resp->opaque == NULL) {
+ /* new client */
+ if ((conf->check_nc || conf->nonce_lifetime == 0
+ || !strcasecmp(conf->algorithm, "MD5-sess"))
+ && (resp->client = gen_client(r)) != NULL)
+ opaque = ltox(r->pool, resp->client->key);
+ else
+ opaque = ""; /* opaque not needed */
+ }
+ else if (resp->client == NULL) {
+ /* client info was gc'd */
+ resp->client = gen_client(r);
+ if (resp->client != NULL) {
+ opaque = ltox(r->pool, resp->client->key);
+ stale = 1;
+ client_list->num_renewed++;
+ }
+ else
+ opaque = ""; /* ??? */
+ }
+ else {
+ opaque = resp->opaque;
+ /* we're generating a new nonce, so reset the nonce-count */
+ resp->client->nonce_count = 0;
+ }
+
+ if (opaque[0])
+ opaque_param = ap_pstrcat(r->pool, ", opaque=\"", opaque, "\"", NULL);
+ else
+ opaque_param = NULL;
+
+ /* Setup nonce */
+
+ nonce = gen_nonce(r->pool, r->request_time, opaque, r->server, conf);
+ if (resp->client && conf->nonce_lifetime == 0)
+ memcpy(resp->client->last_nonce, nonce, NONCE_LEN+1);
+
+ /* setup domain attribute. We want to send this attribute wherever
+ * possible so that the client won't send the Authorization header
+ * unneccessarily (it's usually > 200 bytes!).
+ */
+
+ if (conf->uri_list)
+ domain = conf->uri_list;
+ else {
+ /* They didn't specify any domain, so let's guess at it */
+ domain = guess_domain(r->pool, resp->request_uri->path, r->filename,
+ conf->dir_name);
+ if (domain[0] == '/' && domain[1] == '\0')
+ domain = ""; /* "/" is the default, so no need to send it */
+ else
+ domain = ap_pstrcat(r->pool, ", domain=\"", domain, "\"", NULL);
+ }
+
+ ap_table_mergen(r->err_headers_out,
+ r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
+ ap_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%s\", "
+ "algorithm=%s%s%s%s%s",
+ ap_auth_name(r), nonce, conf->algorithm,
+ opaque_param ? opaque_param : "",
+ domain ? domain : "",
+ stale ? ", stale=true" : "", qop));
+}
+
+
+/*
+ * Authorization header verification code
+ */
+
+static const char *get_hash(request_rec *r, const char *user,
+ const char *realm, const char *auth_pwfile)
+{
+ configfile_t *f;
+ char l[MAX_STRING_LEN];
+ const char *rpw;
+ char *w, *x;
+
+ if (!(f = ap_pcfg_openfile(r->pool, auth_pwfile))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
+ "Digest: Could not open password file: %s", auth_pwfile);
+ return NULL;
+ }
+ while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
+ if ((l[0] == '#') || (!l[0]))
+ continue;
+ rpw = l;
+ w = ap_getword(r->pool, &rpw, ':');
+ x = ap_getword(r->pool, &rpw, ':');
+
+ if (x && w && !strcmp(user, w) && !strcmp(realm, x)) {
+ ap_cfg_closefile(f);
+ return ap_pstrdup(r->pool, rpw);
+ }
+ }
+ ap_cfg_closefile(f);
+ return NULL;
+}
+
+static int check_nc(const request_rec *r, const digest_header_rec *resp,
+ const digest_config_rec *conf)
+{
+ if (conf->check_nc && client_mm) {
+ unsigned long nc;
+
+ const char *snc = resp->nonce_count;
+ char *endptr;
+
+ nc = strtol(snc, &endptr, 16);
+ if (endptr < (snc+strlen(snc)) && !ap_isspace(*endptr)) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: invalid nc %s received - not a number", snc);
+ return !OK;
+ }
+
+ if (!resp->client)
+ return !OK;
+
+ if (nc != resp->client->nonce_count) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, r,
+ "nonce-count check failed: %lu != %lu", nc,
+ resp->client->nonce_count);
+ return !OK;
+ }
+ }
+
+ return OK;
+}
+
+static int check_nonce(request_rec *r, digest_header_rec *resp,
+ const digest_config_rec *conf)
+{
+ double dt;
+ time_rec nonce_time;
+ char tmp, hash[NONCE_HASH_LEN+1];
+
+ if (strlen(resp->nonce) != NONCE_LEN) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: invalid nonce %s received - length is not %d",
+ resp->nonce, NONCE_LEN);
+ note_digest_auth_failure(r, conf, resp, 1);
+ return AUTH_REQUIRED;
+ }
+
+ tmp = resp->nonce[NONCE_TIME_LEN];
+ resp->nonce[NONCE_TIME_LEN] = '\0';
+ ap_base64decode_binary(nonce_time.arr, resp->nonce);
+ gen_nonce_hash(hash, resp->nonce, resp->opaque, r->server, conf);
+ resp->nonce[NONCE_TIME_LEN] = tmp;
+ resp->nonce_time = nonce_time.time;
+
+ if (strcmp(hash, resp->nonce+NONCE_TIME_LEN)) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: invalid nonce %s received - hash is not %s",
+ resp->nonce, hash);
+ note_digest_auth_failure(r, conf, resp, 1);
+ return AUTH_REQUIRED;
+ }
+
+ dt = difftime(r->request_time, nonce_time.time);
+ if (conf->nonce_lifetime > 0 && dt < 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: invalid nonce %s received - user attempted "
+ "time travel", resp->nonce);
+ note_digest_auth_failure(r, conf, resp, 1);
+ return AUTH_REQUIRED;
+ }
+
+ if (conf->nonce_lifetime > 0) {
+ if (dt > conf->nonce_lifetime) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
+ "Digest: user %s: nonce expired - sending new nonce",
+ r->connection->user);
+ note_digest_auth_failure(r, conf, resp, 1);
+ return AUTH_REQUIRED;
+ }
+ }
+ else if (conf->nonce_lifetime == 0 && resp->client) {
+ if (memcmp(resp->client->last_nonce, resp->nonce, NONCE_LEN)) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
+ "Digest: user %s: one-time-nonce mismatch - sending "
+ "new nonce", r->connection->user);
+ note_digest_auth_failure(r, conf, resp, 1);
+ return AUTH_REQUIRED;
+ }
+ }
+ /* else (lifetime < 0) => never expires */
+
+ return OK;
+}
+
+/* The actual MD5 code... whee */
+
+static const char *old_digest(const request_rec *r,
+ const digest_header_rec *resp, const char *ha1)
+{
+ const char *ha2;
+
+ /* rfc-2069 */
+ ha2 = ap_md5(r->pool, (unsigned char *)ap_pstrcat(r->pool, r->method, ":",
+ resp->uri, NULL));
+ return ap_md5(r->pool,
+ (unsigned char *)ap_pstrcat(r->pool, ha1, ":", resp->nonce,
+ ":", ha2, NULL));
+}
+
+static const char *new_digest(const request_rec *r,
+ digest_header_rec *resp,
+ const digest_config_rec *conf)
+{
+ const char *ha1, *ha2, *a2;
+
+ /* draft-ietf-http-authentication-03 */
+ if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess"))
+ ha1 = get_session(r, resp, conf);
+ else
+ ha1 = conf->ha1;
+
+ if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int"))
+ a2 = ap_pstrcat(r->pool, r->method, ":", resp->uri, ":",
+ ap_md5(r->pool, (const unsigned char*) ""), NULL); /* TBD */
+ else
+ a2 = ap_pstrcat(r->pool, r->method, ":", resp->uri, NULL);
+ ha2 = ap_md5(r->pool, (const unsigned char *)a2);
+
+ return ap_md5(r->pool,
+ (unsigned char *)ap_pstrcat(r->pool, ha1, ":", resp->nonce,
+ ":", resp->nonce_count, ":",
+ resp->cnonce, ":",
+ resp->message_qop, ":", ha2,
+ 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 the attributes are correct, if it
+ * really is that user, if the nonce is correct, etc.
+ */
+
+static int authenticate_digest_user(request_rec *r)
+{
+ digest_config_rec *conf;
+ digest_header_rec *resp;
+ request_rec *mainreq;
+ conn_rec *conn = r->connection;
+ const char *t;
+ int res;
+
+
+ /* do we require Digest auth for this URI? */
+
+ if (!(t = ap_auth_type(r)) || strcasecmp(t, "Digest"))
+ return DECLINED;
+
+ if (!ap_auth_name(r)) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: need AuthName: %s", r->uri);
+ return SERVER_ERROR;
+ }
+
+
+ /* get the client response and mark */
+
+ mainreq = r;
+ while (mainreq->main != NULL) mainreq = mainreq->main;
+ while (mainreq->prev != NULL) mainreq = mainreq->prev;
+ resp = (digest_header_rec *) ap_get_module_config(mainreq->request_config,
+ &digest_auth_module);
+ resp->needed_auth = 1;
+
+
+ /* get our conf */
+
+ conf = (digest_config_rec *) ap_get_module_config(r->per_dir_config,
+ &digest_auth_module);
+
+
+ /* check for existence and syntax of Auth header */
+
+ if (resp->auth_hdr_sts != VALID) {
+ if (resp->auth_hdr_sts == NOT_DIGEST)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: client used wrong authentication scheme "
+ "`%s': %s", resp->scheme, r->uri);
+ else if (resp->auth_hdr_sts == INVALID)
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: missing user, realm, nonce, uri, or digest "
+ "in authorization header: %s", r->uri);
+ /* else (resp->auth_hdr_sts == NO_HEADER) */
+ note_digest_auth_failure(r, conf, resp, 0);
+ return AUTH_REQUIRED;
+ }
+
+ r->connection->user = (char *) resp->username;
+ r->connection->ap_auth_type = (char *) "Digest";
+
+
+ /* check the auth attributes */
+
+ if (strcmp(resp->uri, resp->request_uri->path)) {
+ uri_components *r_uri = resp->request_uri, d_uri;
+ ap_parse_uri_components(r->pool, resp->uri, &d_uri);
+
+ if ((d_uri.hostname && d_uri.hostname[0] != '\0'
+ && strcasecmp(d_uri.hostname, r->server->server_hostname))
+ || (d_uri.port_str && d_uri.port != r->server->port)
+ || (!d_uri.port_str && r->server->port != 80)
+ || strcmp(d_uri.path, r_uri->path)
+ || (d_uri.query != r_uri->query
+ && (!d_uri.query || !r_uri->query
+ || strcmp(d_uri.query, r_uri->query)))
+ ) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: uri mismatch - <%s> does not match "
+ "request-uri <%s>", resp->uri,
+ ap_unparse_uri_components(r->pool, r_uri, 0));
+ return BAD_REQUEST;
+ }
+ }
+
+ if (resp->opaque && resp->opaque_num == 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: received invalid opaque - got `%s'",
+ resp->opaque);
+ note_digest_auth_failure(r, conf, resp, 0);
+ return AUTH_REQUIRED;
+ }
+
+ if (strcmp(resp->realm, conf->realm)) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: realm mismatch - got `%s' but expected `%s'",
+ resp->realm, conf->realm);
+ note_digest_auth_failure(r, conf, resp, 0);
+ return AUTH_REQUIRED;
+ }
+
+ if (resp->algorithm != NULL
+ && strcasecmp(resp->algorithm, "MD5")
+ && strcasecmp(resp->algorithm, "MD5-sess")) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: unknown algorithm `%s' received: %s",
+ resp->algorithm, r->uri);
+ note_digest_auth_failure(r, conf, resp, 0);
+ return AUTH_REQUIRED;
+ }
+
+ if (!conf->pwfile)
+ return DECLINED;
+
+ if (!(conf->ha1 = get_hash(r, conn->user, conf->realm, conf->pwfile))) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: user `%s' in realm `%s' not found: %s",
+ conn->user, conf->realm, r->uri);
+ note_digest_auth_failure(r, conf, resp, 0);
+ return AUTH_REQUIRED;
+ }
+
+ if (resp->message_qop == NULL) {
+ /* old (rfc-2069) style digest */
+ if (strcmp(resp->digest, old_digest(r, resp, conf->ha1))) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: user %s: password mismatch: %s", conn->user,
+ r->uri);
+ note_digest_auth_failure(r, conf, resp, 0);
+ return AUTH_REQUIRED;
+ }
+ }
+ else {
+ int match = 0, idx;
+ for (idx=0; conf->qop_list[idx] != NULL; idx++) {
+ if (!strcasecmp(conf->qop_list[idx], resp->message_qop)) {
+ match = 1;
+ break;
+ }
+ }
+
+ if (!match
+ && !(conf->qop_list[0] == NULL
+ && !strcasecmp(resp->message_qop, "auth"))) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: invalid qop `%s' received: %s",
+ resp->message_qop, r->uri);
+ note_digest_auth_failure(r, conf, resp, 0);
+ return AUTH_REQUIRED;
+ }
+
+ if (strcmp(resp->digest, new_digest(r, resp, conf))) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: user %s: password mismatch: %s", conn->user,
+ r->uri);
+ note_digest_auth_failure(r, conf, resp, 0);
+ return AUTH_REQUIRED;
+ }
+ }
+
+ if (check_nc(r, resp, conf) != OK) {
+ note_digest_auth_failure(r, conf, resp, 0);
+ return AUTH_REQUIRED;
+ }
+
+ /* Note: this check is done last so that a "stale=true" can be
+ generated if the nonce is old */
+ if ((res = check_nonce(r, resp, conf)))
+ return res;
+
+ return OK;
+}
+
+
+/*
+ * Checking ID
+ */
+
+static table *groups_for_user(request_rec *r, const char *user,
+ const char *grpfile)
+{
+ configfile_t *f;
+ table *grps = ap_make_table(r->pool, 15);
+ pool *sp;
+ char l[MAX_STRING_LEN];
+ const char *group_name, *ll, *w;
+
+ if (!(f = ap_pcfg_openfile(r->pool, grpfile))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
+ "Digest: Could not open group file: %s", grpfile);
+ return NULL;
+ }
+
+ sp = ap_make_sub_pool(r->pool);
+
+ while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
+ if ((l[0] == '#') || (!l[0]))
+ continue;
+ ll = l;
+ ap_clear_pool(sp);
+
+ group_name = ap_getword(sp, &ll, ':');
+
+ while (ll[0]) {
+ w = ap_getword_conf(sp, &ll);
+ if (!strcmp(w, user)) {
+ ap_table_setn(grps, ap_pstrdup(r->pool, group_name), "in");
+ break;
+ }
+ }
+ }
+
+ ap_cfg_closefile(f);
+ ap_destroy_pool(sp);
+ return grps;
+}
+
+
+static int digest_check_auth(request_rec *r)
+{
+ const digest_config_rec *conf =
+ (digest_config_rec *) ap_get_module_config(r->per_dir_config,
+ &digest_auth_module);
+ const char *user = r->connection->user;
+ int m = r->method_number;
+ int method_restricted = 0;
+ register int x;
+ const char *t, *w;
+ table *grpstatus;
+ const array_header *reqs_arr;
+ require_line *reqs;
+
+ if (!(t = ap_auth_type(r)) || strcasecmp(t, "Digest"))
+ return DECLINED;
+
+ reqs_arr = ap_requires(r);
+ /* If there is no "requires" directive, then any user will do.
+ */
+ if (!reqs_arr)
+ return OK;
+ reqs = (require_line *) reqs_arr->elts;
+
+ if (conf->grpfile)
+ grpstatus = groups_for_user(r, user, conf->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 = ap_getword_white(r->pool, &t);
+ if (!strcasecmp(w, "valid-user"))
+ return OK;
+ else if (!strcasecmp(w, "user")) {
+ while (t[0]) {
+ w = ap_getword_conf(r->pool, &t);
+ if (!strcmp(user, w))
+ return OK;
+ }
+ }
+ else if (!strcasecmp(w, "group")) {
+ if (!grpstatus)
+ return DECLINED;
+
+ while (t[0]) {
+ w = ap_getword_conf(r->pool, &t);
+ if (ap_table_get(grpstatus, w))
+ return OK;
+ }
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: access to %s failed, reason: unknown require "
+ "directive \"%s\"", r->uri, reqs[x].requirement);
+ return DECLINED;
+ }
+ }
+
+ if (!method_restricted)
+ return OK;
+
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Digest: access to %s failed, reason: user %s not allowed access",
+ r->uri, user);
+
+ note_digest_auth_failure(r, conf,
+ (digest_header_rec *) ap_get_module_config(r->request_config,
+ &digest_auth_module),
+ 0);
+ return AUTH_REQUIRED;
+}
+
+
+/*
+ * Authorization-Info header code
+ */
+
+#ifdef SEND_DIGEST
+static const char *hdr(const table *tbl, const char *name)
+{
+ const char *val = ap_table_get(tbl, name);
+ if (val)
+ return val;
+ else
+ return "";
+}
+#endif
+
+static int add_auth_info(request_rec *r)
+{
+ const digest_config_rec *conf =
+ (digest_config_rec *) ap_get_module_config(r->per_dir_config,
+ &digest_auth_module);
+ digest_header_rec *resp =
+ (digest_header_rec *) ap_get_module_config(r->request_config,
+ &digest_auth_module);
+ const char *ai = NULL, *digest = NULL, *nextnonce = "";
+
+ if (resp == NULL || !resp->needed_auth || conf == NULL)
+ return OK;
+
+
+ /* rfc-2069 digest
+ */
+ if (resp->message_qop == NULL) {
+ /* old client, so calc rfc-2069 digest */
+
+#ifdef SEND_DIGEST
+ /* most of this totally bogus because the handlers don't set the
+ * headers until the final handler phase (I wonder why this phase
+ * is called fixup when there's almost nothing you can fix up...)
+ *
+ * Because it's basically impossible to get this right (e.g. the
+ * Content-length is never set yet when we get here, and we can't
+ * calc the entity hash) it's best to just leave this #def'd out.
+ */
+ char *entity_info =
+ ap_md5(r->pool,
+ (unsigned char *) ap_pstrcat(r->pool,
+ ap_unparse_uri_components(r->pool,
+ resp->request_uri, 0), ":",
+ r->content_type ? r->content_type : ap_default_type(r), ":",
+ hdr(r->headers_out, "Content-Length"), ":",
+ r->content_encoding ? r->content_encoding : "", ":",
+ hdr(r->headers_out, "Last-Modified"), ":",
+ r->no_cache && !ap_table_get(r->headers_out, "Expires") ?
+ ap_gm_timestr_822(r->pool, r->request_time) :
+ hdr(r->headers_out, "Expires"),
+ NULL));
+ digest =
+ ap_md5(r->pool,
+ (unsigned char *)ap_pstrcat(r->pool, conf->ha1, ":",
+ resp->nonce, ":",
+ r->method, ":",
+ ap_gm_timestr_822(r->pool, r->request_time), ":",
+ entity_info, ":",
+ ap_md5(r->pool, (unsigned char *) ""), /* H(entity) - TBD */
+ NULL));
+#endif
+ }
+
+
+ /* setup nextnonce
+ */
+ if (conf->nonce_lifetime > 0) {
+ /* send nextnonce if current nonce will expire in less than 30 secs */
+ if (difftime(r->request_time, resp->nonce_time) > (conf->nonce_lifetime-NEXTNONCE_DELTA)) {
+ nextnonce = ap_pstrcat(r->pool, ", nextnonce=\"",
+ gen_nonce(r->pool, r->request_time,
+ resp->opaque, r->server, conf),
+ "\"", NULL);
+ resp->client->nonce_count = 0;
+ }
+ }
+ else if (conf->nonce_lifetime == 0 && resp->client) {
+ const char *nonce = gen_nonce(r->pool, 0, resp->opaque, r->server,
+ conf);
+ nextnonce = ap_pstrcat(r->pool, ", nextnonce=\"", nonce, "\"", NULL);
+ memcpy(resp->client->last_nonce, nonce, NONCE_LEN+1);
+ }
+ /* else nonce never expires, hence no nextnonce */
+
+
+ /* do rfc-2069 digest
+ */
+ if (conf->qop_list[0] && !strcasecmp(conf->qop_list[0], "none")
+ && resp->message_qop == NULL) {
+ /* use only RFC-2069 format */
+ if (digest)
+ ai = ap_pstrcat(r->pool, "digest=\"", digest, "\"", nextnonce,NULL);
+ else
+ ai = nextnonce;
+ }
+ else {
+ const char *resp_dig, *ha1, *a2, *ha2;
+
+ /* calculate rspauth attribute
+ */
+ if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess"))
+ ha1 = get_session(r, resp, conf);
+ else
+ ha1 = conf->ha1;
+
+ if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int"))
+ a2 = ap_pstrcat(r->pool, ":", resp->uri, ":",
+ ap_md5(r->pool, (const unsigned char *) ""), NULL); /* TBD */
+ else
+ a2 = ap_pstrcat(r->pool, ":", resp->uri, NULL);
+ ha2 = ap_md5(r->pool, (const unsigned char *)a2);
+
+ resp_dig = ap_md5(r->pool,
+ (unsigned char *)ap_pstrcat(r->pool, ha1, ":",
+ resp->nonce, ":",
+ resp->nonce_count, ":",
+ resp->cnonce, ":",
+ resp->message_qop ?
+ resp->message_qop : "",
+ ":", ha2, NULL));
+
+ /* assemble Authentication-Info header
+ */
+ ai = ap_pstrcat(r->pool,
+ "rspauth=\"", resp_dig, "\"",
+ nextnonce,
+ resp->cnonce ? ", cnonce=\"" : "",
+ resp->cnonce ? ap_escape_quotes(r->pool, resp->cnonce) :
+ "",
+ resp->cnonce ? "\"" : "",
+ resp->nonce_count ? ", nc=" : "",
+ resp->nonce_count ? resp->nonce_count : "",
+ resp->message_qop ? ", qop=" : "",
+ resp->message_qop ? resp->message_qop : "",
+ digest ? "digest=\"" : "",
+ digest ? digest : "",
+ digest ? "\"" : "",
+ NULL);
+ }
+
+ if (ai && ai[0])
+ ap_table_mergen(r->headers_out,
+ r->proxyreq ? "Proxy-Authentication-Info" :
+ "Authentication-Info",
+ ai);
+ return OK;
+}
+
+
+module MODULE_VAR_EXPORT digest_auth_module =
+{
+ STANDARD_MODULE_STUFF,
+ initialize_module, /* 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 */
+ add_auth_info, /* fixups */
+ NULL, /* logger */
+ NULL, /* header parser */
+ NULL, /* child_init */
+ NULL, /* child_exit */
+ update_nonce_count /* post read-request */
+};
+
diff --git a/usr.sbin/httpd/src/modules/proxy/Makefile.OS2 b/usr.sbin/httpd/src/modules/proxy/Makefile.OS2
new file mode 100644
index 00000000000..260f0050809
--- /dev/null
+++ b/usr.sbin/httpd/src/modules/proxy/Makefile.OS2
@@ -0,0 +1,6 @@
+# Extra rules for making DLLs for OS/2
+
+%.def : %.c
+ echo "LIBRARY $* INITINSTANCE" > $@
+ echo "EXPORTS" >> $@
+ grep "^module .*=" $< | sed "s/module .* \(.*\) =/ \1/" >> $@
diff --git a/usr.sbin/httpd/src/modules/standard/Makefile.OS2 b/usr.sbin/httpd/src/modules/standard/Makefile.OS2
new file mode 100644
index 00000000000..49df7d25f97
--- /dev/null
+++ b/usr.sbin/httpd/src/modules/standard/Makefile.OS2
@@ -0,0 +1,115 @@
+# Extra rules for making DLLs for OS/2
+
+define mkdll
+$(LD_SHLIB) $(LDFLAGS_SHLIB) -o $* $(<:%.c=%.o) $(LIBS_SHLIB) $(LIBS1) $(<:%.o=%.def) && \
+emxbind -b -q -s -h0 -d$(<:%.o=%.def) $* && \
+rm $*
+endef
+
+
+%.def : %.c
+ echo "LIBRARY $* INITINSTANCE" > $@
+ echo "EXPORTS" >> $@
+ grep "^module .*=" $< | sed "s/module.* \(.*\) =.*/ \1/" >> $@
+
+access.dll: mod_access.o mod_access.def
+ $(mkdll)
+
+actions.dll: mod_actions.o mod_actions.def
+ $(mkdll)
+
+alias.dll: mod_alias.o mod_alias.def
+ $(mkdll)
+
+asis.dll: mod_asis.o mod_asis.def
+ $(mkdll)
+
+auth.dll: mod_auth.o mod_auth.def
+ $(mkdll)
+
+auth_ano.dll: mod_auth_anon.o mod_auth_anon.def
+ $(mkdll)
+
+auth_db.dll: mod_auth_db.o mod_auth_db.def
+ $(mkdll)
+
+auth_dbm.dll: mod_auth_dbm.o mod_auth_dbm.def
+ $(mkdll)
+
+autoinde.dll: mod_autoindex.o mod_autoindex.def
+ $(mkdll)
+
+cern_met.dll: mod_cern_meta.o mod_cern_meta.def
+ $(mkdll)
+
+cgi.dll: mod_cgi.o mod_cgi.def
+ $(mkdll)
+
+digest.dll: mod_digest.o mod_digest.def
+ $(mkdll)
+
+dir.dll: mod_dir.o mod_dir.def
+ $(mkdll)
+
+env.dll: mod_env.o mod_env.def
+ $(mkdll)
+
+expires.dll: mod_expires.o mod_expires.def
+ $(mkdll)
+
+headers.dll: mod_headers.o mod_headers.def
+ $(mkdll)
+
+imap.dll: mod_imap.o mod_imap.def
+ $(mkdll)
+
+include.dll: mod_include.o mod_include.def
+ $(mkdll)
+
+info.dll: mod_info.o mod_info.def
+ $(mkdll)
+
+log_agen.dll: mod_log_agent.o mod_log_agent.def
+ $(mkdll)
+
+log_conf.dll: mod_log_config.o mod_log_config.def
+ $(mkdll)
+
+log_refe.dll: mod_log_referer.o mod_log_referer.def
+ $(mkdll)
+
+mime.dll: mod_mime.o mod_mime.def
+ $(mkdll)
+
+mime_mag.dll: mod_mime_magic.o mod_mime_magic.def
+ $(mkdll)
+
+negotiat.dll: mod_negotiation.o mod_negotiation.def
+ $(mkdll)
+
+rewrite.dll: mod_rewrite.o mod_rewrite.def
+ $(mkdll)
+
+setenvif.dll: mod_setenvif.o mod_setenvif.def
+ $(mkdll)
+
+so.dll: mod_so.o mod_so.def
+ $(mkdll)
+
+speling.dll: mod_speling.o mod_speling.def
+ $(mkdll)
+
+status.dll: mod_status.o mod_status.def
+ $(mkdll)
+
+unique_i.dll: mod_unique_id.o mod_unique_id.def
+ $(mkdll)
+
+userdir.dll: mod_userdir.o mod_userdir.def
+ $(mkdll)
+
+usertrac.dll: mod_usertrack.o mod_usertrack.def
+ $(mkdll)
+
+vhost_al.dll: mod_vhost_alias.o mod_vhost_alias.def
+ $(mkdll)
diff --git a/usr.sbin/httpd/src/modules/standard/mod_vhost_alias.c b/usr.sbin/httpd/src/modules/standard/mod_vhost_alias.c
new file mode 100644
index 00000000000..65cc5a2ef41
--- /dev/null
+++ b/usr.sbin/httpd/src/modules/standard/mod_vhost_alias.c
@@ -0,0 +1,482 @@
+/* ====================================================================
+ * Copyright (c) 1995-1999 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. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * 6. 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_vhost_alias.c: support for dynamically configured mass virtual hosting
+ *
+ * Copyright (c) 1998-1999 Demon Internet Ltd.
+ *
+ * This software was submitted by Demon Internet to the Apache Group
+ * in May 1999. Future revisions and derivatives of this source code
+ * must acknowledge Demon Internet as the original contributor of
+ * this module. All other licensing and usage conditions are those
+ * of the Apache Group.
+ *
+ * Originally written by Tony Finch <fanf@demon.net> <dot@dotat.at>.
+ *
+ * Implementation ideas were taken from mod_alias.c. The overall
+ * concept is derived from the OVERRIDE_DOC_ROOT/OVERRIDE_CGIDIR
+ * patch to Apache 1.3b3 and a similar feature in Demon's thttpd,
+ * both written by James Grinter <jrg@blodwen.demon.co.uk>.
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+
+
+module MODULE_VAR_EXPORT vhost_alias_module;
+
+
+/*
+ * basic configuration things
+ * we abbreviate "mod_vhost_alias" to "mva" for shorter names
+ */
+
+typedef enum {
+ VHOST_ALIAS_UNSET, VHOST_ALIAS_NONE, VHOST_ALIAS_NAME, VHOST_ALIAS_IP
+} mva_mode_e;
+
+/*
+ * Per-server module config record.
+ */
+typedef struct mva_sconf_t {
+ char *doc_root;
+ char *cgi_root;
+ mva_mode_e doc_root_mode;
+ mva_mode_e cgi_root_mode;
+} mva_sconf_t;
+
+static void *mva_create_server_config(pool *p, server_rec *s)
+{
+ mva_sconf_t *conf;
+
+ conf = (mva_sconf_t *) ap_pcalloc(p, sizeof(mva_sconf_t));
+ conf->doc_root = NULL;
+ conf->cgi_root = NULL;
+ conf->doc_root_mode = VHOST_ALIAS_UNSET;
+ conf->cgi_root_mode = VHOST_ALIAS_UNSET;
+ return conf;
+}
+
+static void *mva_merge_server_config(pool *p, void *parentv, void *childv)
+{
+ mva_sconf_t *parent = (mva_sconf_t *) parentv;
+ mva_sconf_t *child = (mva_sconf_t *) childv;
+ mva_sconf_t *conf;
+
+ conf = (mva_sconf_t *) ap_pcalloc(p, sizeof(*conf));
+ if (child->doc_root_mode == VHOST_ALIAS_UNSET) {
+ conf->doc_root_mode = parent->doc_root_mode;
+ conf->doc_root = parent->doc_root;
+ }
+ else {
+ conf->doc_root_mode = child->doc_root_mode;
+ conf->doc_root = child->doc_root;
+ }
+ if (child->cgi_root_mode == VHOST_ALIAS_UNSET) {
+ conf->cgi_root_mode = parent->cgi_root_mode;
+ conf->cgi_root = parent->cgi_root;
+ }
+ else {
+ conf->cgi_root_mode = child->cgi_root_mode;
+ conf->cgi_root = child->cgi_root;
+ }
+ return conf;
+}
+
+
+/*
+ * These are just here to tell us what vhost_alias_set should do.
+ * We don't put anything into them; we just use the cell addresses.
+ */
+static int vhost_alias_set_doc_root_ip,
+ vhost_alias_set_cgi_root_ip,
+ vhost_alias_set_doc_root_name,
+ vhost_alias_set_cgi_root_name;
+
+static const char *vhost_alias_set(cmd_parms *cmd, void *dummy, char *map)
+{
+ mva_sconf_t *conf;
+ mva_mode_e mode, *pmode;
+ char **pmap;
+ char *p;
+
+ conf = (mva_sconf_t *) ap_get_module_config(cmd->server->module_config,
+ &vhost_alias_module);
+ /* there ought to be a better way of doing this */
+ if (&vhost_alias_set_doc_root_ip == cmd->info) {
+ mode = VHOST_ALIAS_IP;
+ pmap = &conf->doc_root;
+ pmode = &conf->doc_root_mode;
+ }
+ else if (&vhost_alias_set_cgi_root_ip == cmd->info) {
+ mode = VHOST_ALIAS_IP;
+ pmap = &conf->cgi_root;
+ pmode = &conf->cgi_root_mode;
+ }
+ else if (&vhost_alias_set_doc_root_name == cmd->info) {
+ mode = VHOST_ALIAS_NAME;
+ pmap = &conf->doc_root;
+ pmode = &conf->doc_root_mode;
+ }
+ else if (&vhost_alias_set_cgi_root_name == cmd->info) {
+ mode = VHOST_ALIAS_NAME;
+ pmap = &conf->cgi_root;
+ pmode = &conf->cgi_root_mode;
+ }
+ else {
+ return "INTERNAL ERROR: unknown command info";
+ }
+
+ if (*map != '/') {
+ if (strcasecmp(map, "none")) {
+ return "format string must start with '/' or be 'none'";
+ }
+ *pmap = NULL;
+ *pmode = VHOST_ALIAS_NONE;
+ return NULL;
+ }
+
+ /* sanity check */
+ p = map;
+ while (*p != '\0') {
+ if (*p++ != '%') {
+ continue;
+ }
+ /* we just found a '%' */
+ if (*p == 'p' || *p == '%') {
+ ++p;
+ continue;
+ }
+ /* optional dash */
+ if (*p == '-') {
+ ++p;
+ }
+ /* digit N */
+ if (ap_isdigit(*p)) {
+ ++p;
+ }
+ else {
+ return "syntax error in format string";
+ }
+ /* optional plus */
+ if (*p == '+') {
+ ++p;
+ }
+ /* do we end here? */
+ if (*p != '.') {
+ continue;
+ }
+ ++p;
+ /* optional dash */
+ if (*p == '-') {
+ ++p;
+ }
+ /* digit M */
+ if (ap_isdigit(*p)) {
+ ++p;
+ }
+ else {
+ return "syntax error in format string";
+ }
+ /* optional plus */
+ if (*p == '+') {
+ ++p;
+ }
+ }
+ *pmap = map;
+ *pmode = mode;
+ return NULL;
+}
+
+static const command_rec mva_commands[] =
+{
+ {"VirtualScriptAlias", vhost_alias_set, &vhost_alias_set_cgi_root_name,
+ RSRC_CONF, TAKE1, "how to create a ScriptAlias based on the host"},
+ {"VirtualDocumentRoot", vhost_alias_set, &vhost_alias_set_doc_root_name,
+ RSRC_CONF, TAKE1, "how to create the DocumentRoot based on the host"},
+ {"VirtualScriptAliasIP", vhost_alias_set, &vhost_alias_set_cgi_root_ip,
+ RSRC_CONF, TAKE1, "how to create a ScriptAlias based on the host"},
+ {"VirtualDocumentRootIP", vhost_alias_set, &vhost_alias_set_doc_root_ip,
+ RSRC_CONF, TAKE1, "how to create the DocumentRoot based on the host"},
+ { NULL }
+};
+
+
+/*
+ * This really wants to be a nested function
+ * but C is too feeble to support them.
+ */
+static ap_inline void vhost_alias_checkspace(request_rec *r, char *buf,
+ char **pdest, int size)
+{
+ /* XXX: what if size > HUGE_STRING_LEN? */
+ if (*pdest + size > buf + HUGE_STRING_LEN) {
+ **pdest = '\0';
+ if (r->filename) {
+ r->filename = ap_pstrcat(r->pool, r->filename, buf, NULL);
+ }
+ else {
+ r->filename = ap_pstrdup(r->pool, buf);
+ }
+ *pdest = buf;
+ }
+}
+
+static void vhost_alias_interpolate(request_rec *r, const char *name,
+ const char *map, const char *uri)
+{
+ /* 0..9 9..0 */
+ enum { MAXDOTS = 19 };
+ const char *dots[MAXDOTS+1];
+ int ndots;
+
+ char buf[HUGE_STRING_LEN];
+ char *dest, last;
+
+ int N, M, Np, Mp, Nd, Md;
+ const char *start, *end;
+
+ const char *p;
+
+ ndots = 0;
+ dots[ndots++] = name-1; /* slightly naughty */
+ for (p = name; *p; ++p){
+ if (*p == '.' && ndots < MAXDOTS) {
+ dots[ndots++] = p;
+ }
+ }
+ dots[ndots] = p;
+
+ r->filename = NULL;
+
+ dest = buf;
+ last = '\0';
+ while (*map) {
+ if (*map != '%') {
+ /* normal characters */
+ vhost_alias_checkspace(r, buf, &dest, 1);
+ last = *dest++ = *map++;
+ continue;
+ }
+ /* we are in a format specifier */
+ ++map;
+ /* can't be a slash */
+ last = '\0';
+ /* %% -> % */
+ if (*map == '%') {
+ ++map;
+ vhost_alias_checkspace(r, buf, &dest, 1);
+ *dest++ = '%';
+ continue;
+ }
+ /* port number */
+ if (*map == 'p') {
+ ++map;
+ /* no. of decimal digits in a short plus one */
+ vhost_alias_checkspace(r, buf, &dest, 7);
+ dest += ap_snprintf(dest, 7, "%d", ap_get_server_port(r));
+ continue;
+ }
+ /* deal with %-N+.-M+ -- syntax is already checked */
+ N = M = 0; /* value */
+ Np = Mp = 0; /* is there a plus? */
+ Nd = Md = 0; /* is there a dash? */
+ if (*map == '-') ++map, Nd = 1;
+ N = *map++ - '0';
+ if (*map == '+') ++map, Np = 1;
+ if (*map == '.') {
+ ++map;
+ if (*map == '-') {
+ ++map, Md = 1;
+ }
+ M = *map++ - '0';
+ if (*map == '+') {
+ ++map, Mp = 1;
+ }
+ }
+ /* note that N and M are one-based indices, not zero-based */
+ start = dots[0]+1; /* ptr to the first character */
+ end = dots[ndots]; /* ptr to the character after the last one */
+ if (N != 0) {
+ if (N > ndots) {
+ start = "_";
+ end = start+1;
+ }
+ else if (!Nd) {
+ start = dots[N-1]+1;
+ if (!Np) {
+ end = dots[N];
+ }
+ }
+ else {
+ if (!Np) {
+ start = dots[ndots-N]+1;
+ }
+ end = dots[ndots-N+1];
+ }
+ }
+ if (M != 0) {
+ if (M > end - start) {
+ start = "_";
+ end = start+1;
+ }
+ else if (!Md) {
+ start = start+M-1;
+ if (!Mp) {
+ end = start+1;
+ }
+ }
+ else {
+ if (!Mp) {
+ start = end-M;
+ }
+ end = end-M+1;
+ }
+ }
+ vhost_alias_checkspace(r, buf, &dest, end - start);
+ for (p = start; p < end; ++p) {
+ *dest++ = ap_tolower(*p);
+ }
+ }
+ *dest = '\0';
+ /* no double slashes */
+ if (last == '/') {
+ ++uri;
+ }
+ if (r->filename) {
+ r->filename = ap_pstrcat(r->pool, r->filename, buf, uri, NULL);
+ }
+ else {
+ r->filename = ap_pstrcat(r->pool, buf, uri, NULL);
+ }
+}
+
+static int mva_translate(request_rec *r)
+{
+ mva_sconf_t *conf;
+ const char *name, *map, *uri;
+ mva_mode_e mode;
+ int cgi;
+
+ conf = (mva_sconf_t *) ap_get_module_config(r->server->module_config,
+ &vhost_alias_module);
+ if (!strncmp(r->uri, "/cgi-bin/", 9)) {
+ mode = conf->cgi_root_mode;
+ map = conf->cgi_root;
+ uri = r->uri + 8;
+ /*
+ * can't force cgi immediately because we might not handle this
+ * call if the mode is wrong
+ */
+ cgi = 1;
+ }
+ else if (r->uri[0] == '/') {
+ mode = conf->doc_root_mode;
+ map = conf->doc_root;
+ uri = r->uri;
+ cgi = 0;
+ }
+ else {
+ return DECLINED;
+ }
+
+ if (mode == VHOST_ALIAS_NAME) {
+ name = ap_get_server_name(r);
+ }
+ else if (mode == VHOST_ALIAS_IP) {
+ name = r->connection->local_ip;
+ }
+ else {
+ return DECLINED;
+ }
+
+ vhost_alias_interpolate(r, name, map, uri);
+
+ if (cgi) {
+ /* see is_scriptaliased() in mod_cgi */
+ r->handler = "cgi-script";
+ ap_table_setn(r->notes, "alias-forced-type", r->handler);
+ }
+
+ return OK;
+}
+
+
+module MODULE_VAR_EXPORT vhost_alias_module =
+{
+ STANDARD_MODULE_STUFF,
+ NULL, /* initializer */
+ NULL, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ mva_create_server_config, /* server config */
+ mva_merge_server_config, /* merge server configs */
+ mva_commands, /* command table */
+ NULL, /* handlers */
+ mva_translate, /* filename translation */
+ NULL, /* check_user_id */
+ NULL, /* check auth */
+ NULL, /* check access */
+ NULL, /* type_checker */
+ NULL, /* fixups */
+ NULL, /* logger */
+ NULL, /* header parser */
+ NULL, /* child_init */
+ NULL, /* child_exit */
+ NULL /* post read-request */
+};
diff --git a/usr.sbin/httpd/src/os/tpf/cgetop.c b/usr.sbin/httpd/src/os/tpf/cgetop.c
new file mode 100644
index 00000000000..90ffbce5f45
--- /dev/null
+++ b/usr.sbin/httpd/src/os/tpf/cgetop.c
@@ -0,0 +1,151 @@
+/**********************************************************************/
+/* */
+/* Copyright (c) 1987, 1993, 1994 */
+/* The Regents of the University of California. All rights reserved. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above */
+/* copyright notice, this list of conditions and the following */
+/* disclaimer in the documentation and/or other materials provided */
+/* with the distribution. */
+/* 3. All advertising materials mentioning features or use of this */
+/* software must display the following acknowledgement: */
+/* This product includes software developed by the University of */
+/* California, Berkeley and its contributors. */
+/* 4. Neither the name of the University nor the names of its */
+/* contributors may be used to endorse or promote products derived */
+/* from this software without specific prior written permission. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''*/
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS */
+/* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND*/
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/* */
+/**********************************************************************/
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 8.2 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __CGETOP_
+extern char *optarg;
+extern int opterr, optind, optopt;
+int getopt (int, char * const *, const char *);
+char *group_from_gid (unsigned long, int);
+char *user_from_uid (unsigned long, int);
+extern int optreset;
+#endif
+
+int opterr = 1, /* if error message should be */
+ /* printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with */
+ /* option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/**********************************************************************/
+/* */
+/* getopt -- */
+/* Parse argc/argv argument vector. */
+/* */
+/**********************************************************************/
+int
+getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const *nargv;
+ const char *ostr;
+{
+ /* removed -- BSD2TPF -- crt0 does not create __progname on TPF */
+ /* extern char *__progname; */
+ /* end of removed -- BSD2TPF */
+
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ /* added -- BSD2TPF -- emulate BSD crt0 function to set __progname */
+ char empty = '\0';
+ char *__progname = &empty;
+ if (nargv[0]) {
+ if ((__progname = strrchr(nargv[0], '/')) == NULL) {
+ __progname = nargv[0];
+ }
+ else {
+ ++__progname;
+ }
+ }
+ /* end of added -- BSD2TPF */
+
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return (EOF);
+ }
+ if (place[1] && *++place == '-') {
+ /* found "--" */
+ ++optind;
+ place = EMSG;
+ return (EOF);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /* if the user didn't */
+ /* specify '-' as an option, */
+ /* assume it means EOF. */
+ if (optopt == (int)'-')
+ return (EOF);
+ if (!*place)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", __progname, optopt);
+ return (BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ __progname, optopt);
+ return (BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* dump back option letter */
+} \ No newline at end of file
diff --git a/usr.sbin/httpd/src/os/win32/apache.ico b/usr.sbin/httpd/src/os/win32/apache.ico
new file mode 100644
index 00000000000..161bcf7841c
--- /dev/null
+++ b/usr.sbin/httpd/src/os/win32/apache.ico
Binary files differ
diff --git a/usr.sbin/httpd/src/os/win32/apache.rc b/usr.sbin/httpd/src/os/win32/apache.rc
new file mode 100644
index 00000000000..6dde63f9501
--- /dev/null
+++ b/usr.sbin/httpd/src/os/win32/apache.rc
@@ -0,0 +1,84 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winresrc.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_APACHE ICON DISCARDABLE "apache.ico"
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""winresrc.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/usr.sbin/httpd/src/os/win32/resource.h b/usr.sbin/httpd/src/os/win32/resource.h
new file mode 100644
index 00000000000..820bb6aaaff
--- /dev/null
+++ b/usr.sbin/httpd/src/os/win32/resource.h
@@ -0,0 +1,17 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Apache.rc
+//
+#define IDI_APACHE 101
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/usr.sbin/httpd/src/support/README b/usr.sbin/httpd/src/support/README
new file mode 100644
index 00000000000..80e9cafde0a
--- /dev/null
+++ b/usr.sbin/httpd/src/support/README
@@ -0,0 +1,62 @@
+Support files:
+
+ab
+ ABuse your server with this benchmarker. Rudimentary
+ command line testing tool.
+
+apachectl
+ Apache run-time Control script. To facilitate the
+ administrator and/or your rc.d scripts to control the
+ functioning of the Apache httpd daemon.
+
+apxs
+ APache eXtenSion tool. Eases building and installing
+ DSO style modules.
+
+dbmmanage
+ Create and update user authentication files in the faster
+ DBM format used by mod_auth_db.
+
+htdigest
+ Create and update user authentication files used in
+ DIGEST authentification. See mod_auth_digest.
+
+htpasswd
+ Create and update user authentication files used in
+ BASIC authentification. I.e. the htpasswd files.
+ See mod_auth.
+
+httpd.8
+ General apache man page.
+
+log_server_status
+ This script is designed to be run at a frequent interval by something
+ like cron. It connects to the server and downloads the status
+ information. It reformats the information to a single line and logs
+ it to a file.
+
+logresolve
+ resolve hostnames for IP-adresses in Apache logfiles
+
+phf_abuse_log.cgi
+ This script can be used to detect people trying to abuse an ancient
+ and long plugged security hole which existed in a CGI script distributed
+ with Apache 1.0.3 and earlier versions.
+
+rotatelogs
+ rotate Apache logs without having to kill the server.
+
+split-logfile
+ This script will take a combined virtual hosts access
+ log file and break its contents into separate files.
+
+suexec
+ Switch User For Exec. Used internally by apache,
+ see the document `Apache suEXEC Support'
+ under http://www.apache.org/docs/suexec.html .
+
+SHA1
+ This directory includes some utilities to allow Apache 1.3.6 to
+ recognize passwords in SHA1 format, as used by Netscape web
+ servers. It is not installed by default.
+
diff --git a/usr.sbin/httpd/src/support/SHA1/README.sha1 b/usr.sbin/httpd/src/support/SHA1/README.sha1
new file mode 100644
index 00000000000..3998e1fdd91
--- /dev/null
+++ b/usr.sbin/httpd/src/support/SHA1/README.sha1
@@ -0,0 +1,34 @@
+This directory includes some utilities to allow Apache 1.3.6 to
+recognize passwords in SHA1 format, as used by Netscape web servers.
+
+From Netscape's admin interface, export the password database to an
+ldif file and then use convert.pl in this distribution to generate
+apache style password files.
+
+Note: SHA1 support is useful for migration purposes, but is less
+ secure than Apache's password format, since Apache's (MD5)
+ password format uses a random eight character salt to generate
+ one of many possible hashes for the same password. Netscape
+ uses plain SHA1 without a salt, so the same password
+ will always generate the same hash, making it easier
+ to break since the search space is smaller.
+
+This code was contributed by Clinton Wong <clintdw@netcom.com>.
+
+README.sha1
+ this file
+
+convert-sha1.pl
+ takes an ldif dump from Netscape's web server on
+ standard in, outputs apache htpasswd format on standard out.
+
+ Usage: convert.pl < ldif > passwords
+
+htpasswd-sha1.pl
+ perl script to generate entries in apache htpasswd format.
+
+ Usage: htpasswd-sha1.pl some_user some_password
+
+ldif-sha1.example
+ sample ldif dump with one sha1 password and one crypt password.
+
diff --git a/usr.sbin/httpd/src/support/SHA1/convert-sha1.pl b/usr.sbin/httpd/src/support/SHA1/convert-sha1.pl
new file mode 100644
index 00000000000..35228022a08
--- /dev/null
+++ b/usr.sbin/httpd/src/support/SHA1/convert-sha1.pl
@@ -0,0 +1,36 @@
+#!/usr/bin/perl -w
+use strict;
+
+# This is public domain code. Do whatever you want with it.
+# It was originally included in Clinton Wong's Apache 1.3.6 SHA1/ldif
+# patch distribution as sample code for converting accounts from
+# ldif format (as used by Netscape web servers) to Apache password format.
+
+my $uid='';
+my $passwd='';
+
+while (my $line = <>) {
+ chomp $line;
+ if ( $line =~ /uid:\s*(.+)/) { $uid = $1 }
+ if ( $line =~ /userpassword:\s*(\{\w+\}.+)/) {
+ $passwd = $1;
+ $passwd =~ s/^\{crypt\}//i; # Apache stores crypt without a magic string
+ }
+
+ if (length($line)==0) {
+
+ if (length $uid and length $passwd) {
+ print $uid, ':', $passwd, "\n";
+ } # output if we have something to print
+
+ $uid = '';
+ $passwd = '';
+
+ } # if newline
+} # while something to read
+
+# handle last entry if there isn't a newline before EOF
+ if (length $uid and length $passwd) {
+ print $uid, ':', $passwd, "\n";
+}
+
diff --git a/usr.sbin/httpd/src/support/SHA1/htpasswd-sha1.pl b/usr.sbin/httpd/src/support/SHA1/htpasswd-sha1.pl
new file mode 100644
index 00000000000..ad624d1101f
--- /dev/null
+++ b/usr.sbin/httpd/src/support/SHA1/htpasswd-sha1.pl
@@ -0,0 +1,22 @@
+#!/usr/bin/perl -w
+use strict;
+#
+# Utility which takes a username and password
+# on the command line and generates a username
+# sha1-encrytped password on the stdout.
+#
+# Typical useage:
+# ./htpasswd-sha1.pl dirkx MySecret >> sha1-passwd
+#
+# This is public domain code. Do whatever you want with it.
+# It was originally included in Clinton Wong's Apache 1.3.6 SHA1/ldif
+# patch distribution as sample code for generating entries for
+# Apache password files using SHA1.
+
+use MIME::Base64; # http://www.cpan.org/modules/by-module/MIME/
+use Digest::SHA1; # http://www.cpan.org/modules/by-module/MD5/
+
+if ($#ARGV!=1) { die "Usage $0: user password\n" }
+
+print $ARGV[0], ':{SHA}', encode_base64( Digest::SHA1::sha1($ARGV[1]) );
+
diff --git a/usr.sbin/httpd/src/support/SHA1/ldif-sha1.example b/usr.sbin/httpd/src/support/SHA1/ldif-sha1.example
new file mode 100644
index 00000000000..b8fe917eaf3
--- /dev/null
+++ b/usr.sbin/httpd/src/support/SHA1/ldif-sha1.example
@@ -0,0 +1,19 @@
+dn: cn=someuser
+cn: someuser
+sn: someuser
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: someuser
+userpassword: {SHA}GvF+c3IdvgxAARuC7Uuxp9vjzik=
+
+dn: cn=anotheruser
+cn: anotheruser
+sn: anotheruser
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: anotheruser
+userpassword: {crypt}eFnp.4sz5XnH6
diff --git a/usr.sbin/httpd/src/support/ab.8 b/usr.sbin/httpd/src/support/ab.8
new file mode 100644
index 00000000000..871c457797a
--- /dev/null
+++ b/usr.sbin/httpd/src/support/ab.8
@@ -0,0 +1,210 @@
+.TH ab 1 "March 1998"
+.\" $Id: ab.8,v 1.1 1999/09/29 06:30:07 beck Exp $
+.\" Copyright (c) 1998-1999 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. Products derived from this software may not be called "Apache"
+.\" nor may "Apache" appear in their names without prior written
+.\" permission of the Apache Group.
+.\"
+.\" 6. 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/>.
+.SH NAME
+ab \- Apache HTTP server benchmarking tool
+.SH SYNOPSIS
+.B ab
+[
+.B \-k
+] [
+.BI \-n " requests"
+] [
+.BI \-t " timelimit"
+] [
+.BI \-c " concurrency"
+] [
+.BI \-p " POST file"
+] [
+.BI \-A " Authenticate username:password"
+] [
+.BI \-P " Proxy Authenticate username:password"
+] [
+.BI \-H " Custom header"
+] [
+.BI \-C " Cookie name=value"
+] [
+.BI \-T " content-type"
+] [
+.BI \-v " verbosity"
+]
+] [
+.BI \-w " output HTML"
+]
+] [
+.BI \-x " <table> attributes"
+]
+] [
+.BI \-y " <tr> attributes"
+]
+] [
+.BI \-z " <td> attributes"
+]
+.I [http://]hostname[:port]/path
+
+.B ab
+[
+.B \-V
+] [
+.B \-h
+]
+.PP
+.SH DESCRIPTION
+.B ab
+is a tool for benchmarking your Apache HyperText Transfer Protocol (HTTP)
+server. It is designed to give you an impression on how performant is your
+current Apache installation. This especially shows you how much requests per
+time your Apache installation is capable to serve.
+.PP
+.SH OPTIONS
+.TP 12
+.B \-k
+Enable the HTTP KeepAlive feature, i.e. perform multiple requests within one
+HTTP session instead. Default is no KeepAlive.
+.TP 12
+.BI \-n " requests"
+Number of requests to perform for the benchmarking session. The default is to
+just perform one single request which usually leads to not very representative
+benchmarking results.
+.TP 12
+.BI \-t " timelimit"
+Seconds to max. spend for benchmarking. This implies
+a
+.B \-n
+.B 50000
+internally. Use this to benchmark the server within a fixed total amount of
+time. Per default there is no timelimit.
+.TP 12
+.BI \-c " concurrency"
+Number of multiple requests per time to perform.
+Default is one request per time.
+
+.TP 12
+.BI \-p " POST file"
+File containing data to POST.
+
+.TP 12
+.BI \-A " Authorization username:password"
+Supply BASIC Authentification credentials to the server. The username
+and password are separated by a single ':' and send on the wire uuencoded.
+The string is send regardless of wether the server needs it; (i.e. has
+send an 401. Authentifcation needed).
+
+.TP 12
+.BI \-p " Proxy-Authorization username:password"
+Supply BASIC Authentification credentials to a proxy en-route. The username
+and password are separated by a single ':' and send on the wire uuencoded.
+The string is send regardless of wether the proxy needs it; (i.e. has
+send an 407 Proxy authentifcation needed).
+
+.TP 12
+.BI \-C " Cookie name=value"
+Add a 'Cookie:' line to the request. The argument is typically in the form
+of a 'name=value' pair. This field is repeatable.
+
+.TP 12
+.BI \-p " Header string"
+Postfix extra headers to the request. The argument is typically in the form
+of a valid header line; containing a colon separated field value pair. (i.e.
+'Accept-Encoding: zip/zop;8bit').
+
+.TP 12
+.BI \-T " content-type"
+Content-type header to use for POST data.
+
+.TP 12
+.B \-v
+Set verbosity level - 4 and above prints information on headers, 3 and
+above prints response codes (404, 200, etc.), 2 and above prints
+warnings and info.
+
+.TP 12
+.BI \-w
+Print out results in HTML tables. Default table is two columns wide,
+with a white background.
+.TP 12
+.BI \-x " attributes"
+String to use as attributes for <table>. Attributes are inserted
+<table
+.B here
+>
+.TP 12
+.BI \-y " attributes"
+String to use as attributes for <tr>.
+.TP 12
+.BI \-z " attributes"
+String to use as attributes for <td>.
+.TP 12
+.B \-V
+Display version number and exit.
+.TP 12
+.B \-h
+Display usage information.
+.PD
+.SH BUGS
+There are various statically declared buffers of fixed length. Combined
+with the lazy parsing of the command line arguments, the response headers
+from the server and other external inputs this might bite you.
+.P
+It does not implement HTTP/1.x fully; only accepts some 'expected' forms
+of responses. The rather heavy use of
+.BR strstr(3)
+shows up top in profile,
+which might indicate a performance problem; i.e. you would measure the
+.BR ab
+performance rather than the server's.
+
+.SH SEE ALSO
+.BR httpd(8)
+.
diff --git a/usr.sbin/httpd/src/support/apachectl.8 b/usr.sbin/httpd/src/support/apachectl.8
new file mode 100644
index 00000000000..72300eb98b2
--- /dev/null
+++ b/usr.sbin/httpd/src/support/apachectl.8
@@ -0,0 +1,133 @@
+.TH apachectl 1 "September 1997"
+.\" Copyright (c) 1997-1999 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. Products derived from this software may not be called "Apache"
+.\" nor may "Apache" appear in their names without prior written
+.\" permission of the Apache Group.
+.\"
+.\" 6. 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/>.
+.SH NAME
+apachectl \- Apache HTTP server control interface
+.SH SYNOPSIS
+.B apachectl
+\fIcommand\fP [...]
+.SH DESCRIPTION
+.B apachectl
+is a front end to the Apache HyperText Transfer Protocol (HTTP)
+server. It is designed to help the administrator control the
+functioning of the Apache
+.B httpd
+daemon.
+.PP
+.B NOTE:
+If your Apache installation uses non-standard paths, you will need to
+edit the
+.B apachectl
+script to set the appropriate paths to your PID file and your
+.B httpd
+binary. See the comments in the script for details.
+.PP
+The
+.B apachectl
+script returns a 0 exit value on success, and >0 if an error
+occurs. For more details, view the comments in the script.
+.PP
+Full documentation for Apache is available at
+.B http://www.apache.org/
+.
+.SH OPTIONS
+The \fIcommand\fP can be any one or more of the following options:
+.TP 12
+.BI start
+Start the Apache daemon. Gives an error if it is already running.
+.TP
+.BI stop
+Stops the Apache daemon.
+.TP
+.BI restart
+Restarts the Apache daemon by sending it a SIGHUP. If the daemon
+is not running, it is started.
+This command automatically checks the configuration files via
+.BI configtest
+before initiating the restart to make sure Apache doesn't die.
+.TP
+.BI fullstatus
+Displays a full status report from
+.B mod_status.
+For this to work, you need to have mod_status enabled on your server
+and a text-based browser such as \fIlynx\fP available on your system. The
+URL used to access the status report can be set by editing the
+.B STATUSURL
+variable in the script.
+.TP
+.BI status
+Displays a brief status report. Similar to the fullstatus option,
+except that the list of requests currently being served is omitted.
+.TP
+.BI graceful
+Gracefully restarts the Apache daemon by sending it a SIGUSR1. If
+the daemon is not running, it is started. This differs from a
+normal restart in that currently open connections are not aborted.
+A side effect is that old log files will not be closed immediately.
+This means that if used in a log rotation script, a substantial delay may be
+necessary to ensure that the old log files are closed before processing them.
+This command automatically checks the configuration files via
+.BI configtest
+before initiating the restart to make sure Apache doesn't die.
+.TP
+.BI configtest
+Run a configuration file syntax test. It parses the configuration
+files and either reports
+.B "Syntax Ok"
+or detailed information about the particular syntax error.
+.TP
+.BI help
+Displays a short help message.
+.SH SEE ALSO
+.BR httpd(8)
+.
diff --git a/usr.sbin/httpd/src/support/htdigest.dsp b/usr.sbin/httpd/src/support/htdigest.dsp
new file mode 100644
index 00000000000..f00f87e7e74
--- /dev/null
+++ b/usr.sbin/httpd/src/support/htdigest.dsp
@@ -0,0 +1,103 @@
+# Microsoft Developer Studio Project File - Name="htdigest" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=htdigest - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "htdigest.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htdigest.mak" CFG="htdigest - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htdigest - Win32 Release" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE "htdigest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "htdigest - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "htdigest"
+# PROP BASE Intermediate_Dir "htdigest"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"release/htdigest.exe"
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "htdigest - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "htdiges0"
+# PROP BASE Intermediate_Dir "htdiges0"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"debug/htdigest.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "htdigest - Win32 Release"
+# Name "htdigest - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\ap\ap_cpystrn.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ap\ap_getpass.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ap\ap_md5c.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\htdigest.c
+# End Source File
+# End Target
+# End Project
diff --git a/usr.sbin/httpd/src/support/htdigest.mak b/usr.sbin/httpd/src/support/htdigest.mak
new file mode 100644
index 00000000000..0f048e7d397
--- /dev/null
+++ b/usr.sbin/httpd/src/support/htdigest.mak
@@ -0,0 +1,297 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on htdigest.dsp
+!IF "$(CFG)" == ""
+CFG=htdigest - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to htdigest - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "htdigest - Win32 Release" && "$(CFG)" !=\
+ "htdigest - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htdigest.mak" CFG="htdigest - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htdigest - Win32 Release" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE "htdigest - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "htdigest - Win32 Release"
+
+OUTDIR=.
+INTDIR=.
+# Begin Custom Macros
+OutDir=.
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\release\htdigest.exe"
+
+!ELSE
+
+ALL : "$(OUTDIR)\release\htdigest.exe"
+
+!ENDIF
+
+CLEAN :
+ -@erase "$(INTDIR)\ap_cpystrn.obj"
+ -@erase "$(INTDIR)\ap_getpass.obj"
+ -@erase "$(INTDIR)\ap_md5c.obj"
+ -@erase "$(INTDIR)\htdigest.obj"
+ -@erase "$(INTDIR)\vc50.idb"
+ -@erase "$(OUTDIR)\release\htdigest.exe"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D\
+ "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\htdigest.pch" /YX /FD /c
+CPP_OBJS=.
+CPP_SBRS=.
+
+.c{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdigest.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:console /incremental:no\
+ /pdb:"$(OUTDIR)\htdigest.pdb" /machine:I386\
+ /out:"$(OUTDIR)\release\htdigest.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\ap_cpystrn.obj" \
+ "$(INTDIR)\ap_getpass.obj" \
+ "$(INTDIR)\ap_md5c.obj" \
+ "$(INTDIR)\htdigest.obj"
+
+"$(OUTDIR)\release\htdigest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "htdigest - Win32 Debug"
+
+OUTDIR=.
+INTDIR=.
+# Begin Custom Macros
+OutDir=.
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\debug\htdigest.exe"
+
+!ELSE
+
+ALL : "$(OUTDIR)\debug\htdigest.exe"
+
+!ENDIF
+
+CLEAN :
+ -@erase "$(INTDIR)\ap_cpystrn.obj"
+ -@erase "$(INTDIR)\ap_getpass.obj"
+ -@erase "$(INTDIR)\ap_md5c.obj"
+ -@erase "$(INTDIR)\htdigest.obj"
+ -@erase "$(INTDIR)\vc50.idb"
+ -@erase "$(INTDIR)\vc50.pdb"
+ -@erase "$(OUTDIR)\debug\htdigest.exe"
+ -@erase "$(OUTDIR)\debug\htdigest.ilk"
+ -@erase "$(OUTDIR)\htdigest.pdb"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /I "..\include" /D "WIN32" /D\
+ "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\htdigest.pch" /YX /FD /c
+CPP_OBJS=.
+CPP_SBRS=.
+
+.c{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdigest.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:console /incremental:yes\
+ /pdb:"$(OUTDIR)\htdigest.pdb" /debug /machine:I386\
+ /out:"$(OUTDIR)\debug\htdigest.exe" /pdbtype:sept
+LINK32_OBJS= \
+ "$(INTDIR)\ap_cpystrn.obj" \
+ "$(INTDIR)\ap_getpass.obj" \
+ "$(INTDIR)\ap_md5c.obj" \
+ "$(INTDIR)\htdigest.obj"
+
+"$(OUTDIR)\debug\htdigest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(CFG)" == "htdigest - Win32 Release" || "$(CFG)" ==\
+ "htdigest - Win32 Debug"
+SOURCE=..\ap\ap_cpystrn.c
+DEP_CPP_AP_CP=\
+ "..\include\alloc.h"\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\buff.h"\
+ "..\include\hsregex.h"\
+ "..\include\httpd.h"\
+ "..\include\util_uri.h"\
+ "..\os\win32\os.h"\
+ "..\os\win32\readdir.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_CP=\
+ "..\include\ap_config_auto.h"\
+ "..\include\ebcdic.h"\
+ "..\include\os.h"\
+ "..\include\sfio.h"\
+
+
+"$(INTDIR)\ap_cpystrn.obj" : $(SOURCE) $(DEP_CPP_AP_CP) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\ap\ap_getpass.c
+DEP_CPP_AP_GE=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_GE=\
+ "..\include\ap_config_auto.h"\
+ "..\include\os.h"\
+
+
+"$(INTDIR)\ap_getpass.obj" : $(SOURCE) $(DEP_CPP_AP_GE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\ap\ap_md5c.c
+DEP_CPP_AP_MD=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_md5.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_MD=\
+ "..\ap\ebcdic.h"\
+ "..\include\ap_config_auto.h"\
+ "..\include\os.h"\
+
+
+"$(INTDIR)\ap_md5c.obj" : $(SOURCE) $(DEP_CPP_AP_MD) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\htdigest.c
+DEP_CPP_HTDIG=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_md5.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_HTDIG=\
+ "..\include\ap_config_auto.h"\
+ "..\include\os.h"\
+
+
+"$(INTDIR)\htdigest.obj" : $(SOURCE) $(DEP_CPP_HTDIG) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/usr.sbin/httpd/src/support/htpasswd.dsp b/usr.sbin/httpd/src/support/htpasswd.dsp
new file mode 100644
index 00000000000..7949d7f7e82
--- /dev/null
+++ b/usr.sbin/httpd/src/support/htpasswd.dsp
@@ -0,0 +1,119 @@
+# Microsoft Developer Studio Project File - Name="htpasswd" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=htpasswd - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "htpasswd.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htpasswd.mak" CFG="htpasswd - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htpasswd - Win32 Release" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE "htpasswd - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "htpasswd - Win32 Release"
+# Name "htpasswd - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\ap\ap_cpystrn.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ap\ap_getpass.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ap\ap_md5c.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ap\ap_snprintf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ap\ap_sha1.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ap\ap_checkpass.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\ap\ap_base64.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\htpasswd.c
+# End Source File
+# End Target
+# End Project
diff --git a/usr.sbin/httpd/src/support/htpasswd.mak b/usr.sbin/httpd/src/support/htpasswd.mak
new file mode 100644
index 00000000000..fa69fcd3503
--- /dev/null
+++ b/usr.sbin/httpd/src/support/htpasswd.mak
@@ -0,0 +1,550 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on htpasswd.dsp
+!IF "$(CFG)" == ""
+CFG=htpasswd - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to htpasswd - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "htpasswd - Win32 Release" && "$(CFG)" !=\
+ "htpasswd - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "htpasswd.mak" CFG="htpasswd - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "htpasswd - Win32 Release" (based on\
+ "Win32 (x86) Console Application")
+!MESSAGE "htpasswd - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htpasswd.exe"
+
+!ELSE
+
+ALL : "$(OUTDIR)\htpasswd.exe"
+
+!ENDIF
+
+CLEAN :
+ -@erase "$(INTDIR)\ap_cpystrn.obj"
+ -@erase "$(INTDIR)\ap_getpass.obj"
+ -@erase "$(INTDIR)\ap_md5c.obj"
+ -@erase "$(INTDIR)\ap_snprintf.obj"
+ -@erase "$(INTDIR)\ap_sha1.obj"
+ -@erase "$(INTDIR)\ap_checkpass.obj"
+ -@erase "$(INTDIR)\ap_base64.obj"
+ -@erase "$(INTDIR)\htpasswd.obj"
+ -@erase "$(INTDIR)\vc50.idb"
+ -@erase "$(OUTDIR)\htpasswd.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "..\include" /D "NDEBUG" /D "WIN32" /D\
+ "_CONSOLE" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN" /Fp"$(INTDIR)\htpasswd.pch" /YX\
+ /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+CPP_OBJS=.\Release/
+CPP_SBRS=.
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htpasswd.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ws2_32.lib /nologo /subsystem:console /incremental:no\
+ /pdb:"$(OUTDIR)\htpasswd.pdb" /machine:I386 /out:"$(OUTDIR)\htpasswd.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\ap_cpystrn.obj" \
+ "$(INTDIR)\ap_getpass.obj" \
+ "$(INTDIR)\ap_md5c.obj" \
+ "$(INTDIR)\ap_snprintf.obj" \
+ "$(INTDIR)\ap_sha1.obj" \
+ "$(INTDIR)\ap_checkpass.obj" \
+ "$(INTDIR)\ap_base64.obj" \
+ "$(INTDIR)\htpasswd.obj"
+
+"$(OUTDIR)\htpasswd.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\htpasswd.exe"
+
+!ELSE
+
+ALL : "$(OUTDIR)\htpasswd.exe"
+
+!ENDIF
+
+CLEAN :
+ -@erase "$(INTDIR)\ap_cpystrn.obj"
+ -@erase "$(INTDIR)\ap_getpass.obj"
+ -@erase "$(INTDIR)\ap_md5c.obj"
+ -@erase "$(INTDIR)\ap_snprintf.obj"
+ -@erase "$(INTDIR)\ap_sha1.obj"
+ -@erase "$(INTDIR)\ap_checkpass.obj"
+ -@erase "$(INTDIR)\ap_base64.obj"
+ -@erase "$(INTDIR)\htpasswd.obj"
+ -@erase "$(INTDIR)\vc50.idb"
+ -@erase "$(INTDIR)\vc50.pdb"
+ -@erase "$(OUTDIR)\htpasswd.exe"
+ -@erase "$(OUTDIR)\htpasswd.ilk"
+ -@erase "$(OUTDIR)\htpasswd.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /I "..\include" /D "_DEBUG" /D\
+ "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN"\
+ /Fp"$(INTDIR)\htpasswd.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=.
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\htpasswd.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ws2_32.lib /nologo /subsystem:console /incremental:yes\
+ /pdb:"$(OUTDIR)\htpasswd.pdb" /debug /machine:I386\
+ /out:"$(OUTDIR)\htpasswd.exe" /pdbtype:sept
+LINK32_OBJS= \
+ "$(INTDIR)\ap_cpystrn.obj" \
+ "$(INTDIR)\ap_getpass.obj" \
+ "$(INTDIR)\ap_md5c.obj" \
+ "$(INTDIR)\ap_snprintf.obj" \
+ "$(INTDIR)\ap_sha1.obj" \
+ "$(INTDIR)\ap_checkpass.obj" \
+ "$(INTDIR)\ap_base64.obj" \
+ "$(INTDIR)\htpasswd.obj"
+
+"$(OUTDIR)\htpasswd.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(CFG)" == "htpasswd - Win32 Release" || "$(CFG)" ==\
+ "htpasswd - Win32 Debug"
+SOURCE=..\ap\ap_cpystrn.c
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+DEP_CPP_AP_CP=\
+ "..\include\alloc.h"\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\buff.h"\
+ "..\include\hsregex.h"\
+ "..\include\httpd.h"\
+ "..\include\util_uri.h"\
+ "..\os\win32\os.h"\
+ "..\os\win32\readdir.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_CP=\
+ "..\include\ap_config_auto.h"\
+ "..\include\ebcdic.h"\
+ "..\include\os.h"\
+ "..\include\sfio.h"\
+
+
+"$(INTDIR)\ap_cpystrn.obj" : $(SOURCE) $(DEP_CPP_AP_CP) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+DEP_CPP_AP_CP=\
+ "..\include\alloc.h"\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\buff.h"\
+ "..\include\hsregex.h"\
+ "..\include\httpd.h"\
+ "..\include\util_uri.h"\
+ "..\os\win32\os.h"\
+ "..\os\win32\readdir.h"\
+
+
+"$(INTDIR)\ap_cpystrn.obj" : $(SOURCE) $(DEP_CPP_AP_CP) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ap\ap_getpass.c
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+DEP_CPP_AP_GE=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_GE=\
+ "..\include\ap_config_auto.h"\
+ "..\include\os.h"\
+
+
+"$(INTDIR)\ap_getpass.obj" : $(SOURCE) $(DEP_CPP_AP_GE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+DEP_CPP_AP_GE=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+
+
+"$(INTDIR)\ap_getpass.obj" : $(SOURCE) $(DEP_CPP_AP_GE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ap\ap_md5c.c
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+DEP_CPP_AP_MD=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_md5.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_MD=\
+ "..\ap\ebcdic.h"\
+ "..\include\ap_config_auto.h"\
+ "..\include\os.h"\
+
+
+"$(INTDIR)\ap_md5c.obj" : $(SOURCE) $(DEP_CPP_AP_MD) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+DEP_CPP_AP_MD=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_md5.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+
+
+"$(INTDIR)\ap_md5c.obj" : $(SOURCE) $(DEP_CPP_AP_MD) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ap\ap_snprintf.c
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+DEP_CPP_AP_SN=\
+ "..\include\alloc.h"\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\buff.h"\
+ "..\include\hsregex.h"\
+ "..\include\httpd.h"\
+ "..\include\util_uri.h"\
+ "..\os\win32\os.h"\
+ "..\os\win32\readdir.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_SN=\
+ "..\include\ap_config_auto.h"\
+ "..\include\ebcdic.h"\
+ "..\include\os.h"\
+ "..\include\sfio.h"\
+
+
+"$(INTDIR)\ap_snprintf.obj" : $(SOURCE) $(DEP_CPP_AP_SN) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+DEP_CPP_AP_SN=\
+ "..\include\alloc.h"\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\buff.h"\
+ "..\include\hsregex.h"\
+ "..\include\httpd.h"\
+ "..\include\util_uri.h"\
+ "..\os\win32\os.h"\
+ "..\os\win32\readdir.h"\
+
+
+"$(INTDIR)\ap_snprintf.obj" : $(SOURCE) $(DEP_CPP_AP_SN) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ap\ap_sha1.c
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+DEP_CPP_AP_SH=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_sha1.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_SH=\
+ "..\ap\ebcdic.h"\
+ "..\include\ap_config_auto.h"\
+ "..\include\os.h"\
+
+
+"$(INTDIR)\ap_sha1.obj" : $(SOURCE) $(DEP_CPP_AP_SH) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+DEP_CPP_AP_SH=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_sha1.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+
+
+"$(INTDIR)\ap_sha1.obj" : $(SOURCE) $(DEP_CPP_AP_SH) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ap\ap_checkpass.c
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+DEP_CPP_AP_CH=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_CH=\
+ "..\ap\ebcdic.h"\
+ "..\include\ap_config_auto.h"\
+ "..\include\os.h"\
+
+
+"$(INTDIR)\ap_checkpass.obj" : $(SOURCE) $(DEP_CPP_AP_CH) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+DEP_CPP_AP_CH=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+
+
+"$(INTDIR)\ap_checkpass.obj" : $(SOURCE) $(DEP_CPP_AP_CH) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=..\ap\ap_base64.c
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+DEP_CPP_AP_BA=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_AP_BA=\
+ "..\ap\ebcdic.h"\
+ "..\include\ap_config_auto.h"\
+ "..\include\os.h"\
+
+
+"$(INTDIR)\ap_base64.obj" : $(SOURCE) $(DEP_CPP_AP_BA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+DEP_CPP_AP_BA=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\os.h"\
+
+
+"$(INTDIR)\ap_base64.obj" : $(SOURCE) $(DEP_CPP_AP_BA) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\htpasswd.c
+
+!IF "$(CFG)" == "htpasswd - Win32 Release"
+
+DEP_CPP_HTPAS=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_md5.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\getopt.h"\
+ "..\os\win32\os.h"\
+ {$(INCLUDE)}"sys\stat.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_HTPAS=\
+ "..\include\ap_config_auto.h"\
+ "..\include\os.h"\
+
+
+"$(INTDIR)\htpasswd.obj" : $(SOURCE) $(DEP_CPP_HTPAS) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug"
+
+DEP_CPP_HTPAS=\
+ "..\include\ap.h"\
+ "..\include\ap_config.h"\
+ "..\include\ap_ctype.h"\
+ "..\include\ap_md5.h"\
+ "..\include\ap_mmn.h"\
+ "..\include\hsregex.h"\
+ "..\os\win32\getopt.h"\
+ "..\os\win32\os.h"\
+
+
+"$(INTDIR)\htpasswd.obj" : $(SOURCE) $(DEP_CPP_HTPAS) "$(INTDIR)"
+
+
+!ENDIF
+
+
+!ENDIF
+