diff options
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/ssl')
39 files changed, 21888 insertions, 0 deletions
diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/.deps b/rubbos/app/httpd-2.0.64/modules/ssl/.deps new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/.deps diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/Makefile b/rubbos/app/httpd-2.0.64/modules/ssl/Makefile new file mode 100644 index 00000000..b624d817 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/Makefile @@ -0,0 +1,43 @@ +top_srcdir = /bottlenecks/rubbos/app/httpd-2.0.64 +top_builddir = /bottlenecks/rubbos/app/httpd-2.0.64 +srcdir = /bottlenecks/rubbos/app/httpd-2.0.64/modules/ssl +builddir = /bottlenecks/rubbos/app/httpd-2.0.64/modules/ssl +VPATH = /bottlenecks/rubbos/app/httpd-2.0.64/modules/ssl +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (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.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# standard stuff +# + +include $(top_srcdir)/build/special.mk + +# +# developer stuff +# (we really don't expect end users to use these targets!) +# + +ssl_expr_scan.c: $(top_srcdir)/modules/ssl/ssl_expr_scan.l ssl_expr_parse.h + flex -Pssl_expr_yy -s -B $(top_srcdir)/modules/ssl/ssl_expr_scan.l + sed -e '/$$Header:/d' <lex.ssl_expr_yy.c >ssl_expr_scan.c && rm -f lex.ssl_expr_yy.c + +ssl_expr_parse.c ssl_expr_parse.h: $(top_srcdir)/modules/ssl/ssl_expr_parse.y + yacc -d $(top_srcdir)/modules/ssl/ssl_expr_parse.y + sed -e 's;yy;ssl_expr_yy;g' \ + -e '/#if defined(c_plusplus) || defined(__cplusplus)/,/#endif/d' \ + <y.tab.c >ssl_expr_parse.c && rm -f y.tab.c + sed -e 's;yy;ssl_expr_yy;g' \ + <y.tab.h >ssl_expr_parse.h && rm -f y.tab.h + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/Makefile.in b/rubbos/app/httpd-2.0.64/modules/ssl/Makefile.in new file mode 100644 index 00000000..a5153f3a --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/Makefile.in @@ -0,0 +1,38 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (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.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# standard stuff +# + +include $(top_srcdir)/build/special.mk + +# +# developer stuff +# (we really don't expect end users to use these targets!) +# + +ssl_expr_scan.c: $(top_srcdir)/modules/ssl/ssl_expr_scan.l ssl_expr_parse.h + flex -Pssl_expr_yy -s -B $(top_srcdir)/modules/ssl/ssl_expr_scan.l + sed -e '/$$Header:/d' <lex.ssl_expr_yy.c >ssl_expr_scan.c && rm -f lex.ssl_expr_yy.c + +ssl_expr_parse.c ssl_expr_parse.h: $(top_srcdir)/modules/ssl/ssl_expr_parse.y + yacc -d $(top_srcdir)/modules/ssl/ssl_expr_parse.y + sed -e 's;yy;ssl_expr_yy;g' \ + -e '/#if defined(c_plusplus) || defined(__cplusplus)/,/#endif/d' \ + <y.tab.c >ssl_expr_parse.c && rm -f y.tab.c + sed -e 's;yy;ssl_expr_yy;g' \ + <y.tab.h >ssl_expr_parse.h && rm -f y.tab.h + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/README b/rubbos/app/httpd-2.0.64/modules/ssl/README new file mode 100644 index 00000000..b24af26f --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/README @@ -0,0 +1,129 @@ +SYNOPSIS + + This Apache module provides strong cryptography for the Apache 2.0 webserver + via the Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS + v1) protocols by the help of the SSL/TLS implementation library OpenSSL which + is based on SSLeay from Eric A. Young and Tim J. Hudson. + + The mod_ssl package was created in April 1998 by Ralf S. Engelschall + and was originally derived from software developed by Ben Laurie for + use in the Apache-SSL HTTP server project. The mod_ssl implementation + for Apache 1.3 continues to be supported by the modssl project + <http://www.modssl.org/>. + +SOURCES + + See the top-level LAYOUT file in httpd-2.0 for file descriptions. + + The source files are written in clean ANSI C and pass the ``gcc -O -g + -ggdb3 -Wall -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes + -Wmissing-declarations -Wnested-externs -Winline'' compiler test + (assuming `gcc' is GCC 2.95.2 or newer) without any complains. When + you make changes or additions make sure the source still passes this + compiler test. + +FUNCTIONS + + Inside the source code you will be confronted with the following types of + functions which can be identified by their prefixes: + + ap_xxxx() ............... Apache API function + ssl_xxxx() .............. mod_ssl function + SSL_xxxx() .............. OpenSSL function (SSL library) + OpenSSL_xxxx() .......... OpenSSL function (SSL library) + X509_xxxx() ............. OpenSSL function (Crypto library) + PEM_xxxx() .............. OpenSSL function (Crypto library) + EVP_xxxx() .............. OpenSSL function (Crypto library) + RSA_xxxx() .............. OpenSSL function (Crypto library) + +DATA STRUCTURES + + Inside the source code you will be confronted with the following + data structures: + + server_rec .............. Apache (Virtual) Server + conn_rec ................ Apache Connection + request_rec ............. Apache Request + SSLModConfig ............ mod_ssl (Global) Module Configuration + SSLSrvConfig ............ mod_ssl (Virtual) Server Configuration + SSLDirConfig ............ mod_ssl Directory Configuration + SSLConnConfig ........... mod_ssl Connection Configuration + SSLFilterRec ............ mod_ssl Filter Context + SSL_CTX ................. OpenSSL Context + SSL_METHOD .............. OpenSSL Protocol Method + SSL_CIPHER .............. OpenSSL Cipher + SSL_SESSION ............. OpenSSL Session + SSL ..................... OpenSSL Connection + BIO ..................... OpenSSL Connection Buffer + + For an overview how these are related and chained together have a look at the + page in README.dsov.{fig,ps}. It contains overview diagrams for those data + structures. It's designed for DIN A4 paper size, but you can easily generate + a smaller version inside XFig by specifing a magnification on the Export + panel. + +EXPERIMENTAL CODE + + Experimental code is always encapsulated as following: + + | #ifdef SSL_EXPERIMENTAL_xxxx + | ... + | #endif + + This way it is only compiled in when this define is enabled with + the APACI --enable-rule=SSL_EXPERIMENTAL option and as long as the + C pre-processor variable SSL_EXPERIMENTAL_xxxx_IGNORE is _NOT_ + defined (via CFLAGS). Or in other words: SSL_EXPERIMENTAL enables all + SSL_EXPERIMENTAL_xxxx variables, except if SSL_EXPERIMENTAL_xxxx_IGNORE + is already defined. Currently the following features are experimental: + + o SSL_EXPERIMENTAL_ENGINE + The ability to support the new forthcoming OpenSSL ENGINE stuff. + Until this development branch of OpenSSL is merged into the main + stream, you have to use openssl-engine-0.9.x.tar.gz for this. + mod_ssl automatically recognizes this OpenSSL variant and then can + activate external crypto devices through SSLCryptoDevice directive. + +INCOMPATIBILITIES + + The following intentional incompatibilities exist between mod_ssl 2.x + from Apache 1.3 and this mod_ssl version for Apache 2.0: + + o The complete EAPI-based SSL_VENDOR stuff was removed. + o The complete EAPI-based SSL_COMPAT stuff was removed. + o The <IfDefine> variable MOD_SSL is no longer provided automatically + +MAJOR CHANGES + + For a complete history of changes for Apache 2.0 mod_ssl, see the + CHANGES file in the top-level httpd-2.0 directory. The following + is a condensed summary of the major changes were made between + mod_ssl 2.x from Apache 1.3 and this mod_ssl version for Apache 2.0: + + o The DBM based session cache is now based on APR's DBM API only. + o The shared memory based session cache is now based on APR's APIs. + o SSL I/O is now implemented in terms of filters rather than BUFF + o Eliminated ap_global_ctx. Storing Persistant information in + process_rec->pool->user_data. The ssl_pphrase_Handle_CB() and + ssl_config_global_* () functions have an extra parameter now - + "server_rec *" - which is used to retrieve the SSLModConfigRec. + o Properly support restarts, allowing mod_ssl to be added to a server + that is already running and to change server certs/keys on restart + o Various performance enhancements + o proxy support is no longer an "extension", much of the mod_ssl core + was re-written (ssl_engine_{init,kernel,config}.c) to be generic so + it could be re-used in proxy mode. + - the optional function ssl_proxy_enable is provide for mod_proxy + to enable proxy support + - proxy support now requires 'SSLProxyEngine on' to be configured + - proxy now supports SSLProxyCARevocation{Path,File} in addition to + the original SSLProxy* directives + o per-directory SSLCACertificate{File,Path} is now thread-safe but + requires SSL_set_cert_store patch to OpenSSL + o RSA sslc is supported via ssl_toolkit_compat.h + o the ssl_engine_{ds,ext}.c source files are obsolete and no longer + exist + +TODO + + See the top-level STATUS file in httpd-2.0 for current efforts and goals. diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/README.dsov.fig b/rubbos/app/httpd-2.0.64/modules/ssl/README.dsov.fig new file mode 100644 index 00000000..d8d03db2 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/README.dsov.fig @@ -0,0 +1,346 @@ +#FIG 3.2 +Landscape +Center +Metric +Letter +100.00 +Single +-2 +1200 2 +0 32 #616561 +0 33 #b6b2b6 +0 34 #f7f3f7 +0 35 #cfcfcf +0 36 #ffffff +6 6345 2835 7155 3150 +6 6345 2970 7110 3150 +4 0 0 200 0 20 8 0.0000 4 120 585 6345 3105 "ssl_module")\001 +-6 +4 0 0 200 0 20 8 0.0000 4 120 660 6345 2970 ap_ctx_get(...,\001 +-6 +6 10800 2610 12240 3060 +4 0 0 200 0 20 8 0.0000 4 120 1170 10800 2745 ap_get_module_config(...\001 +4 0 0 200 0 20 8 0.0000 4 120 795 10800 2880 ->per_dir_config,\001 +4 0 0 200 0 20 8 0.0000 4 120 585 10800 3015 &ssl_module)\001 +-6 +6 7920 4770 9135 4995 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 9135 4995 7920 4995 7920 4770 9135 4770 9135 4995 +4 0 0 100 0 18 12 0.0000 4 180 1065 8010 4950 request_rec\001 +-6 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 6975 3330 7425 2520 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 7200 4230 9450 2520 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 7875 4905 7200 5220 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 6750 5130 6750 4545 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 6705 5445 7155 6120 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 7875 4815 7200 4590 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 9585 2565 11475 4230 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 10170 5130 11835 4545 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 7920 6075 9855 5400 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 9990 5445 10935 5625 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 10215 5310 10935 5310 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 11925 4590 11925 5085 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 9810 5490 9810 6840 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 9945 5445 10935 6030 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 8865 4725 10800 2565 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 675 6075 5850 6075 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 675 6525 675 6075 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 5850 6075 5850 6525 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 900 5625 5625 5625 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 1125 5175 5400 5175 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 1350 4725 5175 4725 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 1575 4275 4950 4275 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 1800 3825 4725 3825 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 2025 3375 4500 3375 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 2250 2925 4275 2925 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 2475 2475 4050 2475 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 2700 2025 3825 2025 +2 1 0 3 0 34 200 0 20 0.000 0 0 -1 0 0 2 + 2925 1575 3600 1575 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 900 6075 900 5625 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 1125 6525 1125 5175 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 1350 5175 1350 4725 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 1575 4725 1575 4275 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 1800 6525 1800 3825 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2025 3825 2025 3375 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2250 3375 2250 2925 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2475 2925 2475 2475 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 5625 5625 5625 6075 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 5400 5175 5400 6525 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 5175 4725 5175 5175 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 4950 4275 4950 4725 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 4725 3825 4725 6525 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 4500 3375 4500 3825 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 4275 2925 4275 3375 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 4050 2475 4050 2925 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2700 6525 2700 2025 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 3825 2025 3825 6525 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 0 1.00 60.00 120.00 + 3600 1575 3600 2025 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2925 2025 2925 1575 +2 1 0 4 0 0 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 4.00 60.00 120.00 + 540 6525 6300 6525 +2 3 0 1 7 7 800 0 20 0.000 0 0 -1 0 0 9 + 675 6525 5850 6525 5850 6075 5625 6075 5625 5625 900 5625 + 900 6075 675 6075 675 6525 +2 3 0 1 34 34 700 0 20 0.000 0 0 -1 0 0 13 + 1125 6525 5355 6525 5400 5175 5175 5175 5175 4725 4950 4725 + 4950 4275 1575 4275 1575 4725 1350 4725 1350 5175 1125 5175 + 1125 6525 +2 3 0 1 35 35 500 0 20 0.000 0 0 -1 0 0 17 + 1800 6525 4725 6525 4725 3825 4500 3825 4500 3375 4275 3375 + 4275 2925 4050 2925 4050 2475 2475 2475 2475 2925 2250 2925 + 2250 3375 2025 3375 2025 3825 1800 3825 1800 6525 +2 3 0 1 33 33 400 0 20 0.000 0 0 -1 0 0 9 + 2700 6525 3825 6525 3825 2025 3600 2025 3600 1575 2925 1575 + 2925 2025 2700 2025 2700 6525 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 1 2 + 2 0 1.00 60.00 120.00 + 2 0 1.00 60.00 120.00 + 2700 6750 3825 6750 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 1 2 + 2 0 1.00 60.00 120.00 + 2 0 1.00 60.00 120.00 + 1125 7200 5400 7200 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 1 2 + 2 0 1.00 60.00 120.00 + 2 0 1.00 60.00 120.00 + 1800 6975 4725 6975 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 1 2 + 2 0 1.00 60.00 120.00 + 2 0 1.00 60.00 120.00 + 675 7425 5850 7425 +2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 + 675 6570 675 7650 +2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 + 1125 6570 1125 7650 +2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 + 1800 6570 1800 7650 +2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 + 2700 6570 2700 7650 +2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 + 3825 6570 3825 7650 +2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 + 4725 6570 4725 7650 +2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 + 5400 6570 5400 7650 +2 1 2 1 0 34 200 0 20 3.000 0 1 -1 0 0 2 + 5850 6570 5850 7650 +2 4 0 2 0 7 100 0 -1 0.000 0 0 20 0 0 5 + 12600 8550 450 8550 450 225 12600 225 12600 8550 +2 4 0 1 0 34 200 0 20 0.000 0 0 20 0 0 5 + 12600 1350 450 1350 450 225 12600 225 12600 1350 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 10170 2475 8775 2475 8775 2250 10170 2250 10170 2475 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 11925 2475 10575 2475 10575 2250 11925 2250 11925 2475 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 12375 4500 11430 4500 11430 4275 12375 4275 12375 4500 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 12375 5400 10980 5400 10980 5175 12375 5175 12375 5400 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 10170 5400 9675 5400 9675 5175 10170 5175 10170 5400 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 7875 6300 7200 6300 7200 6075 7875 6075 7875 6300 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 8190 2475 6750 2475 6750 2250 8190 2250 8190 2475 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 7605 3600 6300 3600 6300 3375 7605 3375 7605 3600 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 7335 4500 6300 4500 6300 4275 7335 4275 7335 4500 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 7200 5400 6300 5400 6300 5175 7200 5175 7200 5400 +2 1 0 6 7 7 600 0 -1 0.000 0 0 -1 0 0 2 + 9450 4500 6075 1935 +2 1 0 6 7 7 600 0 -1 0.000 0 0 4 0 0 2 + 9450 4500 12465 2205 +2 1 0 6 7 7 600 0 -1 0.000 0 0 4 0 0 2 + 9450 4500 9450 7785 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 9630 5310 7245 5310 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 11385 4365 7380 4365 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 12240 5805 10980 5805 10980 5580 12240 5580 12240 5805 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 12375 6210 10980 6210 10980 5985 12375 5985 12375 6210 +2 1 0 1 0 34 200 0 20 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 11205 6885 9900 5445 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 12285 7155 10530 7155 10530 6930 12285 6930 12285 7155 +2 4 0 1 35 35 200 0 20 0.000 0 0 4 0 0 5 + 10170 7155 9630 7155 9630 6930 10170 6930 10170 7155 +2 1 0 6 7 7 600 0 -1 0.000 0 0 4 0 0 2 + 12510 6435 9450 6435 +2 1 0 1 0 34 300 0 20 0.000 0 0 7 1 0 4 + 1 1 1.00 60.00 120.00 + 12375 4455 12510 4635 12510 6210 11970 6885 +2 1 2 1 0 34 200 0 20 1.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 9850 5143 9175 4918 +3 1 0 1 34 34 800 0 20 0.000 0 0 0 41 + 7380 1710 6390 2115 5535 2115 6075 3015 5670 3465 6165 3915 + 5715 4410 6030 5040 6030 5310 6480 5715 6390 6255 6975 6300 + 7065 6975 7965 6750 8100 7560 8955 7290 9360 7740 9720 7560 + 10755 8145 12060 8280 12375 7650 12420 7200 12510 7065 12330 6660 + 12510 6390 12420 5940 12375 5400 12510 5220 12510 4725 12600 4275 + 12375 3645 12105 3240 12150 2745 12375 2700 12330 1980 11790 1575 + 11250 1935 10125 1485 8955 2070 7785 1620 7695 1575 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 +4 0 0 100 0 0 12 0.0000 4 180 1440 10575 675 Ralf S. Engelschall\001 +4 0 0 100 0 18 20 0.0000 4 270 3840 4275 675 Apache+mod_ssl+OpenSSL\001 +4 0 0 100 0 0 10 0.0000 4 135 1320 10575 855 rse@engelschall.com\001 +4 0 0 100 0 0 10 0.0000 4 135 1410 10575 1035 www.engelschall.com\001 +4 0 0 100 0 0 12 0.0000 4 135 870 900 675 Version 1.3\001 +4 0 0 100 0 0 12 0.0000 4 180 1035 900 855 12-Apr-1999\001 +4 0 0 200 0 20 8 0.0000 4 60 390 6210 4680 ->server\001 +4 0 0 200 0 20 8 0.0000 4 120 855 8280 6120 ap_ctx_get(...,"ssl")\001 +4 0 0 200 0 20 8 0.0000 4 120 1170 7740 2700 ap_get_module_config(...\001 +4 0 0 200 0 20 8 0.0000 4 120 810 7740 2835 ->module_config,\001 +4 0 0 200 0 20 8 0.0000 4 120 585 7740 2970 &ssl_module)\001 +4 0 0 100 0 18 20 0.0000 4 270 1200 9000 8100 Chaining\001 +4 0 0 100 0 18 20 0.0000 4 210 1095 2745 8100 Lifetime\001 +4 0 0 100 0 18 12 0.0000 4 180 1215 810 6255 ap_global_ctx\001 +4 0 0 100 0 18 12 0.0000 4 180 1305 990 5805 SSLModConfig\001 +4 0 0 100 0 18 12 0.0000 4 180 840 4050 4455 SSL_CTX\001 +4 0 0 100 0 18 12 0.0000 4 150 975 4455 5355 server_rec\001 +4 0 0 100 0 18 12 0.0000 4 180 1260 3870 4905 SSLSrvConfig\001 +4 0 0 100 0 18 12 0.0000 4 135 480 1845 4005 BUFF\001 +4 0 0 100 0 18 12 0.0000 4 150 810 2070 3555 conn_rec\001 +4 0 0 100 0 18 12 0.0000 4 135 345 2295 3105 BIO\001 +4 0 0 100 0 18 12 0.0000 4 135 375 2565 2655 SSL\001 +4 0 0 100 0 18 12 0.0000 4 180 1185 3645 1620 SSLDirConfig\001 +4 0 0 100 0 18 12 0.0000 4 180 1065 3915 2070 request_rec\001 +4 0 0 200 0 0 8 0.0000 4 120 1440 900 7560 Startup, Runtime, Shutdown\001 +4 0 0 200 0 0 8 0.0000 4 105 975 1350 7335 Configuration Time\001 +4 0 0 200 0 0 8 0.0000 4 90 1050 2025 7110 Connection Duration\001 +4 0 0 200 0 0 8 0.0000 4 120 885 2835 6885 Request Duration\001 +4 0 0 200 0 18 20 0.0000 4 195 90 6345 6795 t\001 +4 0 0 200 0 20 8 0.0000 4 90 345 7110 5985 ->client\001 +4 0 0 100 0 18 12 0.0000 4 180 1305 6795 2430 SSLModConfig\001 +4 0 0 100 0 18 12 0.0000 4 180 1260 8865 2430 SSLSrvConfig\001 +4 0 0 100 0 18 12 0.0000 4 180 1215 6345 3555 ap_global_ctx\001 +4 0 0 100 0 18 12 0.0000 4 150 975 6345 4455 server_rec\001 +4 0 0 100 0 18 12 0.0000 4 150 810 6345 5355 conn_rec\001 +4 0 0 100 0 18 12 0.0000 4 135 375 9720 5355 SSL\001 +4 0 0 100 0 18 12 0.0000 4 180 1185 10665 2430 SSLDirConfig\001 +4 0 0 100 0 18 12 0.0000 4 135 480 7290 6255 BUFF\001 +4 0 0 100 0 18 12 0.0000 4 180 1305 11025 5355 SSL_METHOD\001 +4 0 0 100 0 18 12 0.0000 4 180 840 11475 4455 SSL_CTX\001 +4 0 0 100 0 18 24 0.0000 4 285 4365 3915 1080 Data Structure Overview\001 +4 0 0 200 0 20 8 0.0000 4 90 615 7065 5085 ->connection\001 +4 0 0 200 0 20 8 0.0000 4 60 390 7065 4770 ->server\001 +4 0 0 200 0 20 8 0.0000 4 120 960 8010 5445 SSL_get_app_data()\001 +4 0 0 200 0 20 8 0.0000 4 120 510 10530 4050 ->pSSLCtx\001 +4 0 0 200 0 20 8 0.0000 4 120 1215 7875 4275 SSL_CTX_get_app_data()\001 +4 0 0 200 0 20 8 0.0000 4 120 1155 10305 5535 SSL_get_current_cipher()\001 +4 0 0 100 0 18 12 0.0000 4 180 1170 11025 5760 SSL_CIPHER\001 +4 0 0 100 0 18 12 0.0000 4 180 1350 10980 6165 SSL_SESSION\001 +4 0 0 200 0 20 8 0.0000 4 120 840 10440 5940 SSL_get_session()\001 +4 0 0 100 0 18 12 0.0000 4 180 1665 10575 7110 X509_STORE_CTX\001 +4 0 0 100 0 18 12 0.0000 4 135 345 9720 7110 BIO\001 +4 0 0 200 0 20 8 0.0000 4 120 840 9540 7335 SSL_get_{r,w}bio()\001 +4 0 0 100 0 18 20 0.0000 4 270 1170 8730 3465 mod_ssl\001 +4 0 0 100 0 18 20 0.0000 4 270 1050 8145 6750 Apache\001 +4 0 0 200 0 20 8 0.0000 4 120 945 10125 4680 SSL_get_SSL_CTX()\001 +4 0 0 200 0 20 8 0.0000 4 120 1170 10350 5175 SSL_get_SSL_METHOD()\001 +4 0 0 200 0 20 8 0.0000 4 90 465 11745 4770 ->method\001 +4 0 0 200 0 20 8 0.0000 4 120 1665 9945 6480 X509_STORE_CTX_get_app_data()\001 +4 0 0 200 0 20 8 0.0000 4 120 1215 10980 6705 SSL_CTX_get_cert_store()\001 +4 0 0 200 0 20 8 0.0000 4 120 1020 8280 5130 SSL_get_app_data2()\001 +4 0 0 100 0 18 20 0.0000 4 270 1290 10710 7605 OpenSSL\001 +4 0 0 100 0 18 12 0.0000 4 180 720 10710 7785 [Crypto]\001 +4 0 0 100 0 18 20 0.0000 4 270 1290 10935 3645 OpenSSL\001 +4 0 0 100 0 18 12 0.0000 4 180 495 10935 3825 [SSL]\001 diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/README.dsov.ps b/rubbos/app/httpd-2.0.64/modules/ssl/README.dsov.ps new file mode 100644 index 00000000..def19dbe --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/README.dsov.ps @@ -0,0 +1,1138 @@ +%!PS-Adobe-2.0 +%%Title: README.dsov.ps +%%Creator: fig2dev Version 3.2 Patchlevel 1 +%%CreationDate: Mon Apr 12 17:09:11 1999 +%%For: rse@en1.engelschall.com (Ralf S. Engelschall) +%%Orientation: Landscape +%%BoundingBox: 59 37 553 755 +%%Pages: 1 +%%BeginSetup +%%IncludeFeature: *PageSize Letter +%%EndSetup +%%Magnification: 0.9340 +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def +/col32 {0.380 0.396 0.380 srgb} bind def +/col33 {0.714 0.698 0.714 srgb} bind def +/col34 {0.969 0.953 0.969 srgb} bind def +/col35 {0.812 0.812 0.812 srgb} bind def +/col36 {1.000 1.000 1.000 srgb} bind def + +end +save +48.0 12.0 translate + 90 rotate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/reencdict 12 dict def /ReEncode { reencdict begin +/newcodesandnames exch def /newfontname exch def /basefontname exch def +/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def +basefontdict { exch dup /FID ne { dup /Encoding eq +{ exch dup length array copy newfont 3 1 roll put } +{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall +newfont /FontName newfontname put newcodesandnames aload pop +128 1 255 { newfont /Encoding get exch /.notdef put } for +newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat +newfontname newfont definefont pop end } def +/isovec [ +8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde +8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis +8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron +8#220 /dotlessi 8#230 /oe 8#231 /OE +8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling +8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis +8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot +8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus +8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph +8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine +8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf +8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute +8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring +8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute +8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute +8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve +8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply +8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex +8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave +8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring +8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute +8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute +8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve +8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide +8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex +8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def +/Times-Roman /Times-Roman-iso isovec ReEncode +/Helvetica-Bold /Helvetica-Bold-iso isovec ReEncode +/Helvetica-Narrow /Helvetica-Narrow-iso isovec ReEncode +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +10 setmiterlimit +n -1000 9572 m -1000 -1000 l 13622 -1000 l 13622 9572 l cp clip + 0.05883 0.05883 sc +%%Page: 1 1 +% Polyline +7.500 slw +n 6413 2048 m 6380 2054 l 6348 2061 l 6315 2067 l 6283 2073 l 6250 2079 l + 6217 2084 l 6185 2090 l 6152 2095 l 6120 2101 l 6088 2107 l + 6057 2113 l 6027 2120 l 5998 2126 l 5970 2134 l 5943 2141 l + 5918 2149 l 5894 2158 l 5873 2167 l 5853 2177 l 5835 2187 l + 5819 2198 l 5805 2210 l 5793 2222 l 5782 2235 l 5774 2250 l + 5768 2265 l 5763 2281 l 5760 2299 l 5759 2318 l 5759 2339 l + 5761 2360 l 5764 2383 l 5768 2408 l 5774 2433 l 5780 2460 l + 5788 2488 l 5797 2516 l 5806 2546 l 5815 2575 l 5825 2606 l + 5836 2636 l 5846 2666 l 5856 2696 l 5866 2726 l 5875 2755 l + 5884 2784 l 5892 2812 l 5899 2839 l 5905 2866 l 5910 2891 l + 5915 2916 l 5918 2940 l 5919 2968 l 5920 2995 l 5919 3022 l + 5916 3048 l 5912 3075 l 5908 3101 l 5902 3127 l 5895 3153 l + 5887 3179 l 5880 3205 l 5871 3230 l 5863 3254 l 5855 3278 l + 5848 3302 l 5841 3324 l 5834 3346 l 5829 3367 l 5824 3388 l + 5821 3408 l 5819 3427 l 5819 3446 l 5820 3465 l 5823 3484 l + 5827 3503 l 5833 3522 l 5840 3542 l 5848 3562 l 5858 3582 l + 5868 3603 l 5880 3625 l 5891 3647 l 5904 3669 l 5916 3691 l + 5929 3713 l 5941 3736 l 5953 3758 l 5964 3779 l 5974 3801 l + 5983 3822 l 5991 3843 l 5997 3863 l 6002 3883 l 6006 3903 l + 6008 3923 l 6008 3942 l 6006 3962 l 6003 3983 l 5998 4004 l + 5992 4025 l 5985 4048 l 5977 4070 l 5968 4094 l 5958 4118 l + 5947 4142 l 5936 4167 l 5925 4192 l 5913 4216 l 5902 4241 l + 5892 4266 l 5882 4291 l 5872 4315 l 5864 4339 l 5857 4362 l + 5851 4386 l 5846 4409 l 5843 4433 l 5840 4456 l 5840 4480 l + 5840 4505 l 5842 4530 l 5845 4556 l 5849 4582 l 5854 4609 l + 5860 4636 l 5867 4664 l 5875 4692 l 5883 4720 l 5892 4747 l + 5901 4774 l 5910 4801 l 5920 4827 l 5929 4852 l 5938 4875 l + 5947 4898 l 5955 4920 l 5963 4941 l 5971 4961 l 5978 4980 l + 5985 5002 l 5992 5024 l 5999 5046 l 6005 5067 l 6010 5088 l + 6016 5109 l 6022 5129 l 6027 5150 l 6033 5170 l 6039 5190 l + 6045 5209 l 6052 5228 l 6059 5246 l 6067 5264 l 6075 5281 l + 6084 5298 l 6094 5315 l 6105 5333 l 6115 5347 l 6125 5361 l + 6137 5376 l 6149 5392 l 6162 5408 l 6176 5425 l 6191 5443 l + 6206 5461 l 6221 5480 l 6237 5499 l 6253 5519 l 6269 5539 l + 6284 5559 l 6299 5579 l 6313 5599 l 6327 5619 l 6340 5639 l + 6352 5659 l 6363 5679 l 6373 5698 l 6382 5718 l 6390 5738 l + 6398 5759 l 6404 5782 l 6410 5805 l 6415 5828 l 6420 5852 l + 6424 5877 l 6428 5902 l 6431 5927 l 6435 5952 l 6438 5977 l + 6442 6001 l 6446 6025 l 6450 6048 l 6455 6069 l 6461 6090 l + 6467 6109 l 6474 6127 l 6483 6143 l 6492 6159 l 6503 6173 l + 6515 6185 l 6528 6197 l 6543 6209 l 6560 6220 l 6578 6230 l + 6598 6240 l 6619 6250 l 6641 6260 l 6663 6270 l 6687 6281 l + 6710 6291 l 6733 6302 l 6757 6312 l 6779 6324 l 6801 6335 l + 6821 6348 l 6841 6361 l 6859 6374 l 6876 6389 l 6893 6405 l + 6906 6421 l 6919 6437 l 6932 6455 l 6944 6475 l 6955 6495 l + 6967 6516 l 6979 6538 l 6991 6561 l 7003 6584 l 7015 6608 l + 7027 6631 l 7040 6654 l 7053 6677 l 7067 6699 l 7081 6720 l + 7096 6739 l 7111 6758 l 7127 6774 l 7144 6789 l 7161 6803 l + 7180 6815 l 7200 6825 l 7220 6833 l 7240 6840 l 7263 6845 l + 7286 6850 l 7311 6854 l 7338 6857 l 7365 6859 l 7394 6861 l + 7424 6862 l 7454 6864 l 7485 6865 l 7516 6866 l 7547 6867 l + 7578 6868 l 7609 6870 l 7639 6872 l 7668 6875 l 7696 6879 l + 7723 6883 l 7748 6889 l 7773 6895 l 7795 6903 l 7817 6912 l + 7838 6923 l 7857 6934 l 7875 6948 l 7892 6963 l 7909 6980 l + 7926 6998 l 7941 7017 l 7957 7038 l 7972 7060 l 7987 7083 l + 8002 7106 l 8017 7130 l 8031 7154 l 8046 7178 l 8061 7202 l + 8075 7225 l 8090 7247 l 8105 7269 l 8120 7289 l 8135 7308 l + 8151 7326 l 8167 7342 l 8184 7356 l 8202 7369 l 8220 7380 l + 8239 7390 l 8260 7397 l 8282 7404 l 8305 7409 l 8330 7413 l + 8356 7416 l 8383 7418 l 8412 7420 l 8441 7420 l 8471 7419 l + 8502 7418 l 8534 7417 l 8565 7415 l 8597 7413 l 8629 7411 l + 8660 7409 l 8690 7407 l 8720 7405 l 8749 7404 l 8777 7404 l + 8804 7404 l 8830 7405 l 8856 7407 l 8880 7410 l 8906 7414 l + 8931 7420 l 8956 7427 l 8981 7435 l 9005 7444 l 9029 7455 l + 9053 7466 l 9077 7478 l 9100 7491 l 9123 7504 l 9146 7517 l + 9168 7531 l 9190 7544 l 9210 7557 l 9230 7570 l 9250 7582 l + 9268 7593 l 9286 7604 l 9304 7613 l 9320 7621 l 9336 7629 l + 9353 7635 l 9370 7641 l 9388 7645 l 9406 7648 l 9425 7650 l + 9444 7652 l 9464 7653 l 9485 7653 l 9508 7653 l 9531 7653 l + 9555 7653 l 9579 7653 l 9605 7654 l 9631 7655 l 9658 7656 l + 9685 7659 l 9713 7662 l 9742 7666 l 9771 7672 l 9801 7679 l + 9833 7688 l 9853 7694 l 9874 7700 l 9895 7708 l 9918 7716 l + 9941 7725 l 9966 7734 l 9991 7745 l 10017 7755 l 10045 7767 l + 10073 7779 l 10102 7791 l 10132 7804 l 10163 7818 l 10194 7831 l + 10227 7845 l 10259 7860 l 10293 7874 l 10326 7889 l 10360 7903 l + 10394 7918 l 10429 7932 l 10463 7947 l 10497 7961 l 10531 7974 l + 10565 7988 l 10599 8001 l 10633 8013 l 10667 8025 l 10700 8037 l + 10733 8049 l 10767 8059 l 10800 8070 l 10834 8080 l 10868 8090 l + 10902 8099 l 10937 8108 l 10973 8117 l 11009 8125 l 11045 8133 l + 11083 8141 l 11120 8148 l 11158 8155 l 11197 8161 l 11236 8167 l + 11275 8172 l 11313 8177 l 11352 8181 l 11391 8184 l 11429 8187 l + 11467 8190 l 11504 8191 l 11540 8192 l 11576 8192 l 11610 8192 l + 11644 8191 l 11676 8189 l 11707 8187 l 11738 8184 l 11767 8180 l + 11794 8176 l 11821 8171 l 11847 8165 l 11871 8159 l 11895 8153 l + 11923 8143 l 11950 8133 l 11976 8122 l 12001 8109 l 12025 8096 l + 12048 8081 l 12071 8065 l 12092 8048 l 12113 8031 l 12133 8012 l + 12153 7992 l 12171 7972 l 12188 7951 l 12205 7930 l 12220 7909 l + 12235 7887 l 12248 7865 l 12260 7843 l 12272 7822 l 12282 7800 l + 12292 7779 l 12301 7759 l 12309 7739 l 12316 7719 l 12323 7699 l + 12330 7680 l 12338 7655 l 12345 7631 l 12352 7607 l 12359 7582 l + 12365 7558 l 12371 7533 l 12377 7508 l 12382 7484 l 12388 7460 l + 12392 7436 l 12397 7414 l 12401 7391 l 12405 7370 l 12409 7350 l + 12412 7331 l 12415 7313 l 12418 7297 l 12421 7281 l 12424 7266 l + 12428 7253 l 12432 7234 l 12437 7216 l 12442 7199 l 12446 7183 l + 12451 7166 l 12456 7150 l 12460 7134 l 12463 7117 l 12466 7101 l + 12468 7086 l 12469 7070 l 12469 7054 l 12467 7037 l 12465 7020 l + 12462 7006 l 12459 6991 l 12455 6975 l 12450 6958 l 12445 6940 l + 12440 6921 l 12434 6901 l 12428 6880 l 12422 6859 l 12416 6838 l + 12411 6817 l 12406 6796 l 12401 6776 l 12397 6756 l 12394 6736 l + 12392 6718 l 12390 6700 l 12390 6683 l 12390 6665 l 12392 6649 l + 12394 6631 l 12397 6614 l 12401 6597 l 12406 6579 l 12411 6561 l + 12416 6542 l 12422 6524 l 12428 6505 l 12434 6487 l 12440 6468 l + 12445 6450 l 12450 6432 l 12455 6414 l 12459 6396 l 12462 6378 l + 12465 6360 l 12467 6343 l 12468 6326 l 12469 6308 l 12469 6289 l + 12468 6269 l 12468 6249 l 12466 6227 l 12464 6205 l 12462 6182 l + 12460 6159 l 12457 6135 l 12454 6111 l 12451 6087 l 12447 6063 l + 12444 6040 l 12441 6016 l 12437 5993 l 12434 5970 l 12431 5948 l + 12428 5925 l 12424 5902 l 12421 5879 l 12419 5855 l 12416 5831 l + 12413 5806 l 12411 5781 l 12408 5755 l 12406 5729 l 12404 5702 l + 12403 5676 l 12401 5651 l 12400 5625 l 12400 5601 l 12399 5578 l + 12399 5555 l 12400 5534 l 12401 5514 l 12402 5495 l 12403 5477 l + 12405 5460 l 12408 5440 l 12411 5421 l 12416 5402 l 12420 5384 l + 12426 5365 l 12431 5347 l 12437 5329 l 12444 5311 l 12450 5293 l + 12456 5275 l 12462 5258 l 12468 5240 l 12474 5222 l 12479 5205 l + 12483 5186 l 12488 5168 l 12490 5152 l 12493 5135 l 12496 5117 l + 12498 5099 l 12500 5079 l 12502 5058 l 12504 5036 l 12506 5014 l + 12507 4990 l 12509 4966 l 12510 4942 l 12512 4918 l 12513 4893 l + 12515 4869 l 12516 4845 l 12518 4822 l 12520 4799 l 12521 4776 l + 12523 4754 l 12525 4733 l 12527 4713 l 12529 4693 l 12531 4673 l + 12534 4653 l 12536 4632 l 12539 4610 l 12541 4588 l 12543 4566 l + 12546 4543 l 12548 4520 l 12550 4497 l 12552 4473 l 12553 4450 l + 12554 4426 l 12555 4403 l 12555 4380 l 12555 4357 l 12555 4334 l + 12554 4312 l 12552 4290 l 12550 4267 l 12548 4245 l 12545 4224 l + 12541 4203 l 12537 4181 l 12533 4159 l 12528 4136 l 12523 4112 l + 12517 4088 l 12510 4064 l 12503 4038 l 12496 4013 l 12488 3987 l + 12479 3961 l 12471 3935 l 12462 3909 l 12452 3884 l 12443 3859 l + 12434 3835 l 12424 3811 l 12415 3788 l 12405 3766 l 12396 3744 l + 12386 3723 l 12377 3702 l 12368 3683 l 12357 3661 l 12347 3640 l + 12336 3619 l 12325 3598 l 12314 3576 l 12303 3555 l 12291 3533 l + 12280 3511 l 12269 3489 l 12257 3467 l 12246 3446 l 12235 3424 l + 12225 3402 l 12215 3381 l 12206 3360 l 12197 3340 l 12189 3320 l + 12181 3301 l 12174 3281 l 12168 3262 l 12162 3244 l 12158 3225 l + 12153 3204 l 12149 3183 l 12145 3162 l 12142 3139 l 12140 3117 l + 12138 3094 l 12137 3071 l 12137 3047 l 12138 3024 l 12139 3001 l + 12141 2978 l 12143 2956 l 12146 2935 l 12150 2915 l 12154 2896 l + 12158 2879 l 12163 2862 l 12168 2847 l 12174 2833 l 12180 2820 l + 12188 2805 l 12197 2792 l 12206 2779 l 12216 2766 l 12227 2754 l + 12238 2742 l 12249 2730 l 12260 2717 l 12272 2704 l 12282 2691 l + 12292 2676 l 12302 2661 l 12310 2645 l 12318 2627 l 12324 2608 l + 12330 2588 l 12334 2571 l 12336 2553 l 12339 2534 l 12341 2513 l + 12342 2491 l 12343 2467 l 12343 2442 l 12342 2416 l 12340 2389 l + 12338 2360 l 12335 2332 l 12331 2303 l 12326 2273 l 12320 2244 l + 12314 2215 l 12307 2187 l 12299 2159 l 12290 2132 l 12280 2106 l + 12270 2081 l 12259 2056 l 12248 2033 l 12236 2011 l 12224 1990 l + 12210 1970 l 12196 1949 l 12181 1929 l 12164 1910 l 12147 1890 l + 12129 1871 l 12110 1853 l 12090 1835 l 12070 1818 l 12049 1802 l + 12027 1787 l 12005 1773 l 11983 1761 l 11961 1749 l 11939 1739 l + 11917 1730 l 11895 1722 l 11874 1716 l 11852 1710 l 11831 1707 l + 11811 1704 l 11790 1703 l 11769 1702 l 11748 1703 l 11727 1705 l + 11706 1708 l 11683 1711 l 11660 1716 l 11636 1721 l 11612 1727 l + 11587 1733 l 11560 1740 l 11534 1747 l 11506 1754 l 11479 1761 l + 11450 1768 l 11422 1774 l 11393 1780 l 11364 1786 l 11334 1791 l + 11305 1795 l 11275 1798 l 11245 1800 l 11215 1801 l 11184 1801 l + 11153 1800 l 11128 1798 l 11104 1796 l 11078 1793 l 11052 1790 l + 11025 1785 l 10997 1781 l 10968 1776 l 10939 1770 l 10908 1764 l + 10877 1758 l 10844 1751 l 10811 1744 l 10778 1737 l 10743 1730 l + 10708 1722 l 10673 1715 l 10637 1708 l 10601 1701 l 10565 1695 l + 10530 1688 l 10494 1682 l 10458 1677 l 10422 1672 l 10387 1668 l + 10352 1664 l 10318 1661 l 10284 1658 l 10250 1657 l 10216 1656 l + 10183 1655 l 10150 1656 l 10118 1658 l 10087 1660 l 10055 1663 l + 10024 1666 l 9992 1671 l 9960 1676 l 9927 1682 l 9894 1688 l + 9861 1695 l 9827 1703 l 9792 1711 l 9757 1720 l 9721 1729 l + 9685 1738 l 9649 1748 l 9613 1757 l 9576 1767 l 9539 1778 l + 9502 1788 l 9465 1798 l 9429 1807 l 9392 1817 l 9356 1826 l + 9320 1835 l 9285 1844 l 9250 1852 l 9216 1860 l 9182 1867 l + 9148 1873 l 9115 1879 l 9082 1884 l 9050 1889 l 9018 1892 l + 8987 1895 l 8955 1898 l 8919 1899 l 8883 1900 l 8847 1899 l + 8811 1898 l 8774 1896 l 8737 1893 l 8699 1889 l 8661 1884 l + 8623 1878 l 8585 1872 l 8546 1865 l 8508 1857 l 8470 1849 l + 8432 1840 l 8395 1830 l 8358 1821 l 8322 1811 l 8287 1801 l + 8254 1790 l 8221 1780 l 8189 1770 l 8159 1760 l 8130 1750 l + 8102 1740 l 8076 1730 l 8051 1721 l 8028 1712 l 8006 1703 l + 7985 1695 l 7965 1688 l 7931 1674 l 7899 1662 l 7871 1650 l + 7844 1640 l 7820 1631 l 7798 1623 l 7778 1617 l 7760 1611 l + 7743 1607 l 7728 1603 l 7715 1601 l 7702 1600 l 7691 1600 l + 7680 1601 l 7669 1603 l 7658 1605 l 7648 1607 l 7638 1610 l + 7627 1613 l 7615 1617 l 7601 1621 l 7587 1626 l 7571 1632 l + 7554 1638 l 7536 1645 l 7517 1653 l 7496 1661 l 7474 1670 l + 7452 1679 l 7428 1689 l 7403 1699 l 7378 1709 l 7352 1720 l + 7325 1731 l 7297 1743 l 7268 1755 l 7247 1763 l 7226 1772 l + 7204 1781 l 7182 1790 l 7158 1800 l 7133 1810 l 7108 1820 l + 7081 1831 l 7053 1842 l 7025 1853 l 6996 1864 l 6966 1875 l + 6935 1886 l 6904 1898 l 6873 1909 l 6841 1921 l 6809 1932 l + 6776 1943 l 6744 1954 l 6712 1964 l 6680 1974 l 6649 1984 l + 6618 1994 l 6587 2003 l 6557 2011 l 6527 2019 l 6498 2027 l + 6469 2034 l 6441 2041 l cp gs col34 1.00 shd ef gr gs col34 s gr +% Polyline +n 675 6525 m 5850 6525 l 5850 6075 l 5625 6075 l 5625 5625 l 900 5625 l + 900 6075 l 675 6075 l cp gs col7 1.00 shd ef gr gs col7 s gr +% Polyline +n 1125 6525 m 5355 6525 l 5400 5175 l 5175 5175 l 5175 4725 l 4950 4725 l + 4950 4275 l 1575 4275 l 1575 4725 l 1350 4725 l 1350 5175 l + 1125 5175 l cp gs col34 1.00 shd ef gr gs col34 s gr +% Polyline +75.000 slw +n 9450 4500 m 12465 2205 l gs col7 s gr +% Polyline +n 9450 4500 m 9450 7785 l gs col7 s gr +% Polyline +n 9450 4500 m 6075 1935 l gs col7 s gr +% Polyline +n 12510 6435 m 9450 6435 l gs col7 s gr +% Polyline +7.500 slw +n 1800 6525 m 4725 6525 l 4725 3825 l 4500 3825 l 4500 3375 l 4275 3375 l + 4275 2925 l 4050 2925 l 4050 2475 l 2475 2475 l 2475 2925 l + 2250 2925 l 2250 3375 l 2025 3375 l 2025 3825 l 1800 3825 l + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 2700 6525 m 3825 6525 l 3825 2025 l 3600 2025 l 3600 1575 l 2925 1575 l + 2925 2025 l 2700 2025 l cp gs col33 1.00 shd ef gr gs col33 s gr +% Polyline +gs clippath +12068 6810 m 11970 6885 l 12022 6773 l 11937 6878 l 11984 6915 l cp +clip +n 12375 4455 m 12510 4635 l 12510 6210 l 11970 6885 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 12068 6810 m 11970 6885 l 12022 6773 l 12045 6791 l 12068 6810 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +7113 6004 m 7155 6120 l 7063 6037 l 7138 6149 l 7188 6116 l cp +clip +n 6705 5445 m 7155 6120 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 7113 6004 m 7155 6120 l 7063 6037 l 7088 6020 l 7113 6004 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +7304 4656 m 7200 4590 l 7323 4599 l 7195 4557 l 7176 4614 l cp +clip +n 7875 4815 m 7200 4590 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 7304 4656 m 7200 4590 l 7323 4599 l 7314 4628 l 7304 4656 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11405 4128 m 11475 4230 l 11365 4173 l 11466 4262 l 11506 4217 l cp +clip +n 9585 2565 m 11475 4230 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 11405 4128 m 11475 4230 l 11365 4173 l 11385 4151 l 11405 4128 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11712 4556 m 11835 4545 l 11732 4613 l 11859 4568 l 11839 4512 l cp +clip +n 10170 5130 m 11835 4545 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 11712 4556 m 11835 4545 l 11732 4613 l 11722 4585 l 11712 4556 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +9732 5411 m 9855 5400 l 9752 5468 l 9879 5423 l 9859 5367 l cp +clip +n 7920 6075 m 9855 5400 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 9732 5411 m 9855 5400 l 9752 5468 l 9742 5440 l 9732 5411 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +10823 5573 m 10935 5625 l 10812 5632 l 10944 5657 l 10955 5598 l cp +clip +n 9990 5445 m 10935 5625 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 10823 5573 m 10935 5625 l 10812 5632 l 10817 5603 l 10823 5573 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +10815 5280 m 10935 5310 l 10815 5340 l 10950 5340 l 10950 5280 l cp +clip +n 10215 5310 m 10935 5310 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 10815 5280 m 10935 5310 l 10815 5340 l 10815 5310 l 10815 5280 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11955 4965 m 11925 5085 l 11895 4965 l 11895 5100 l 11955 5100 l cp +clip +n 11925 4590 m 11925 5085 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 11955 4965 m 11925 5085 l 11895 4965 l 11925 4965 l 11955 4965 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +9840 6720 m 9810 6840 l 9780 6720 l 9780 6855 l 9840 6855 l cp +clip +n 9810 5490 m 9810 6840 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 9840 6720 m 9810 6840 l 9780 6720 l 9810 6720 l 9840 6720 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +10847 5943 m 10935 6030 l 10816 5995 l 10933 6063 l 10963 6012 l cp +clip +n 9945 5445 m 10935 6030 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 10847 5943 m 10935 6030 l 10816 5995 l 10832 5969 l 10847 5943 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +10698 2634 m 10800 2565 l 10742 2674 l 10832 2574 l 10788 2534 l cp +clip +n 8865 4725 m 10800 2565 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 10698 2634 m 10800 2565 l 10742 2674 l 10720 2654 l 10698 2634 l cp gs 0.00 setgray ef gr col0 s +% Polyline +30.000 slw +n 675 6075 m 5850 6075 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +7.500 slw + [15 15] 15 sd +gs clippath +645 6195 m 675 6075 l 705 6195 l 705 6060 l 645 6060 l cp +clip +n 675 6525 m 675 6075 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 645 6195 m 675 6075 l 705 6195 l 675 6195 l 645 6195 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +5880 6405 m 5850 6525 l 5820 6405 l 5820 6540 l 5880 6540 l cp +clip +n 5850 6075 m 5850 6525 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 5880 6405 m 5850 6525 l 5820 6405 l 5850 6405 l 5880 6405 l cp gs col7 1.00 shd ef gr col0 s +% Polyline +30.000 slw +n 900 5625 m 5625 5625 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 1125 5175 m 5400 5175 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 1350 4725 m 5175 4725 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 1575 4275 m 4950 4275 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 1800 3825 m 4725 3825 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 2025 3375 m 4500 3375 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 2250 2925 m 4275 2925 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 2475 2475 m 4050 2475 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 2700 2025 m 3825 2025 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 2925 1575 m 3600 1575 l gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +7.500 slw + [15 15] 15 sd +gs clippath +870 5745 m 900 5625 l 930 5745 l 930 5610 l 870 5610 l cp +clip +n 900 6075 m 900 5625 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 870 5745 m 900 5625 l 930 5745 l 900 5745 l 870 5745 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +1095 5295 m 1125 5175 l 1155 5295 l 1155 5160 l 1095 5160 l cp +clip +n 1125 6525 m 1125 5175 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 1095 5295 m 1125 5175 l 1155 5295 l 1125 5295 l 1095 5295 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +1320 4845 m 1350 4725 l 1380 4845 l 1380 4710 l 1320 4710 l cp +clip +n 1350 5175 m 1350 4725 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 1320 4845 m 1350 4725 l 1380 4845 l 1350 4845 l 1320 4845 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +1545 4395 m 1575 4275 l 1605 4395 l 1605 4260 l 1545 4260 l cp +clip +n 1575 4725 m 1575 4275 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 1545 4395 m 1575 4275 l 1605 4395 l 1575 4395 l 1545 4395 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +1770 3945 m 1800 3825 l 1830 3945 l 1830 3810 l 1770 3810 l cp +clip +n 1800 6525 m 1800 3825 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 1770 3945 m 1800 3825 l 1830 3945 l 1800 3945 l 1770 3945 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +1995 3495 m 2025 3375 l 2055 3495 l 2055 3360 l 1995 3360 l cp +clip +n 2025 3825 m 2025 3375 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 1995 3495 m 2025 3375 l 2055 3495 l 2025 3495 l 1995 3495 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +2220 3045 m 2250 2925 l 2280 3045 l 2280 2910 l 2220 2910 l cp +clip +n 2250 3375 m 2250 2925 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 2220 3045 m 2250 2925 l 2280 3045 l 2250 3045 l 2220 3045 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +2445 2595 m 2475 2475 l 2505 2595 l 2505 2460 l 2445 2460 l cp +clip +n 2475 2925 m 2475 2475 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 2445 2595 m 2475 2475 l 2505 2595 l 2475 2595 l 2445 2595 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +5655 5955 m 5625 6075 l 5595 5955 l 5595 6090 l 5655 6090 l cp +clip +n 5625 5625 m 5625 6075 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 5655 5955 m 5625 6075 l 5595 5955 l 5625 5955 l 5655 5955 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +5430 6405 m 5400 6525 l 5370 6405 l 5370 6540 l 5430 6540 l cp +clip +n 5400 5175 m 5400 6525 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 5430 6405 m 5400 6525 l 5370 6405 l 5400 6405 l 5430 6405 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +5205 5055 m 5175 5175 l 5145 5055 l 5145 5190 l 5205 5190 l cp +clip +n 5175 4725 m 5175 5175 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 5205 5055 m 5175 5175 l 5145 5055 l 5175 5055 l 5205 5055 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +4980 4605 m 4950 4725 l 4920 4605 l 4920 4740 l 4980 4740 l cp +clip +n 4950 4275 m 4950 4725 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 4980 4605 m 4950 4725 l 4920 4605 l 4950 4605 l 4980 4605 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +4755 6405 m 4725 6525 l 4695 6405 l 4695 6540 l 4755 6540 l cp +clip +n 4725 3825 m 4725 6525 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 4755 6405 m 4725 6525 l 4695 6405 l 4725 6405 l 4755 6405 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +4530 3705 m 4500 3825 l 4470 3705 l 4470 3840 l 4530 3840 l cp +clip +n 4500 3375 m 4500 3825 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 4530 3705 m 4500 3825 l 4470 3705 l 4500 3705 l 4530 3705 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +4305 3255 m 4275 3375 l 4245 3255 l 4245 3390 l 4305 3390 l cp +clip +n 4275 2925 m 4275 3375 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 4305 3255 m 4275 3375 l 4245 3255 l 4275 3255 l 4305 3255 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +4080 2805 m 4050 2925 l 4020 2805 l 4020 2940 l 4080 2940 l cp +clip +n 4050 2475 m 4050 2925 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 4080 2805 m 4050 2925 l 4020 2805 l 4050 2805 l 4080 2805 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +2670 2145 m 2700 2025 l 2730 2145 l 2730 2010 l 2670 2010 l cp +clip +n 2700 6525 m 2700 2025 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 2670 2145 m 2700 2025 l 2730 2145 l 2700 2145 l 2670 2145 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +3855 6405 m 3825 6525 l 3795 6405 l 3795 6540 l 3855 6540 l cp +clip +n 3825 2025 m 3825 6525 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 3855 6405 m 3825 6525 l 3795 6405 l 3825 6405 l 3855 6405 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +3630 1905 m 3600 2025 l 3570 1905 l 3570 2040 l 3630 2040 l cp +clip +n 3600 1575 m 3600 2025 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 3630 1905 m 3600 2025 l 3570 1905 l 3600 1905 l 3630 1905 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +2895 1695 m 2925 1575 l 2955 1695 l 2955 1560 l 2895 1560 l cp +clip +n 2925 2025 m 2925 1575 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 2895 1695 m 2925 1575 l 2955 1695 l 2925 1695 l 2895 1695 l cp gs 0.00 setgray ef gr col0 s +% Polyline +45.000 slw +gs clippath +6087 6495 m 6207 6525 l 6087 6555 l 6360 6555 l 6360 6495 l cp +clip +n 540 6525 m 6300 6525 l gs 0.00 setgray ef gr gs col0 s gr gr + +% arrowhead +n 6087 6495 m 6207 6525 l 6087 6555 l 6087 6525 l 6087 6495 l cp gs 0.00 setgray ef gr col0 s +% Polyline +7.500 slw +gs clippath +3681 6720 m 3825 6750 l 3681 6780 l 3840 6780 l 3840 6720 l cp +2844 6780 m 2700 6750 l 2844 6720 l 2685 6720 l 2685 6780 l cp +clip +n 2700 6750 m 3825 6750 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 2844 6780 m 2700 6750 l 2844 6720 l 2820 6750 l 2844 6780 l cp gs col7 1.00 shd ef gr col0 s +% arrowhead +n 3681 6720 m 3825 6750 l 3681 6780 l 3705 6750 l 3681 6720 l cp gs col7 1.00 shd ef gr col0 s +% Polyline +gs clippath +5256 7170 m 5400 7200 l 5256 7230 l 5415 7230 l 5415 7170 l cp +1269 7230 m 1125 7200 l 1269 7170 l 1110 7170 l 1110 7230 l cp +clip +n 1125 7200 m 5400 7200 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 1269 7230 m 1125 7200 l 1269 7170 l 1245 7200 l 1269 7230 l cp gs col7 1.00 shd ef gr col0 s +% arrowhead +n 5256 7170 m 5400 7200 l 5256 7230 l 5280 7200 l 5256 7170 l cp gs col7 1.00 shd ef gr col0 s +% Polyline +gs clippath +4581 6945 m 4725 6975 l 4581 7005 l 4740 7005 l 4740 6945 l cp +1944 7005 m 1800 6975 l 1944 6945 l 1785 6945 l 1785 7005 l cp +clip +n 1800 6975 m 4725 6975 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 1944 7005 m 1800 6975 l 1944 6945 l 1920 6975 l 1944 7005 l cp gs col7 1.00 shd ef gr col0 s +% arrowhead +n 4581 6945 m 4725 6975 l 4581 7005 l 4605 6975 l 4581 6945 l cp gs col7 1.00 shd ef gr col0 s +% Polyline +gs clippath +5706 7395 m 5850 7425 l 5706 7455 l 5865 7455 l 5865 7395 l cp +819 7455 m 675 7425 l 819 7395 l 660 7395 l 660 7455 l cp +clip +n 675 7425 m 5850 7425 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 819 7455 m 675 7425 l 819 7395 l 795 7425 l 819 7455 l cp gs col7 1.00 shd ef gr col0 s +% arrowhead +n 5706 7395 m 5850 7425 l 5706 7455 l 5730 7425 l 5706 7395 l cp gs col7 1.00 shd ef gr col0 s +% Polyline +1 slc + [15 45] 45 sd +n 675 6570 m 675 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 1125 6570 m 1125 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 1800 6570 m 1800 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 2700 6570 m 2700 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 3825 6570 m 3825 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 4725 6570 m 4725 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 5400 6570 m 5400 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd +% Polyline + [15 45] 45 sd +n 5850 6570 m 5850 7650 l gs col34 1.00 shd ef gr gs col0 s gr [] 0 sd +% Polyline +0 slc +n 750 225 m 450 225 450 1050 300 arcto 4 {pop} repeat + 450 1350 12300 1350 300 arcto 4 {pop} repeat + 12600 1350 12600 525 300 arcto 4 {pop} repeat + 12600 225 750 225 300 arcto 4 {pop} repeat + cp gs col34 1.00 shd ef gr gs col0 s gr +% Polyline +n 8835 2250 m 8775 2250 8775 2415 60 arcto 4 {pop} repeat + 8775 2475 10110 2475 60 arcto 4 {pop} repeat + 10170 2475 10170 2310 60 arcto 4 {pop} repeat + 10170 2250 8835 2250 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 10635 2250 m 10575 2250 10575 2415 60 arcto 4 {pop} repeat + 10575 2475 11865 2475 60 arcto 4 {pop} repeat + 11925 2475 11925 2310 60 arcto 4 {pop} repeat + 11925 2250 10635 2250 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 11490 4275 m 11430 4275 11430 4440 60 arcto 4 {pop} repeat + 11430 4500 12315 4500 60 arcto 4 {pop} repeat + 12375 4500 12375 4335 60 arcto 4 {pop} repeat + 12375 4275 11490 4275 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 11040 5175 m 10980 5175 10980 5340 60 arcto 4 {pop} repeat + 10980 5400 12315 5400 60 arcto 4 {pop} repeat + 12375 5400 12375 5235 60 arcto 4 {pop} repeat + 12375 5175 11040 5175 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 9735 5175 m 9675 5175 9675 5340 60 arcto 4 {pop} repeat + 9675 5400 10110 5400 60 arcto 4 {pop} repeat + 10170 5400 10170 5235 60 arcto 4 {pop} repeat + 10170 5175 9735 5175 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 7260 6075 m 7200 6075 7200 6240 60 arcto 4 {pop} repeat + 7200 6300 7815 6300 60 arcto 4 {pop} repeat + 7875 6300 7875 6135 60 arcto 4 {pop} repeat + 7875 6075 7260 6075 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 6810 2250 m 6750 2250 6750 2415 60 arcto 4 {pop} repeat + 6750 2475 8130 2475 60 arcto 4 {pop} repeat + 8190 2475 8190 2310 60 arcto 4 {pop} repeat + 8190 2250 6810 2250 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 6360 3375 m 6300 3375 6300 3540 60 arcto 4 {pop} repeat + 6300 3600 7545 3600 60 arcto 4 {pop} repeat + 7605 3600 7605 3435 60 arcto 4 {pop} repeat + 7605 3375 6360 3375 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 6360 4275 m 6300 4275 6300 4440 60 arcto 4 {pop} repeat + 6300 4500 7275 4500 60 arcto 4 {pop} repeat + 7335 4500 7335 4335 60 arcto 4 {pop} repeat + 7335 4275 6360 4275 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 6360 5175 m 6300 5175 6300 5340 60 arcto 4 {pop} repeat + 6300 5400 7140 5400 60 arcto 4 {pop} repeat + 7200 5400 7200 5235 60 arcto 4 {pop} repeat + 7200 5175 6360 5175 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +gs clippath +7365 5340 m 7245 5310 l 7365 5280 l 7230 5280 l 7230 5340 l cp +clip +n 9630 5310 m 7245 5310 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 7365 5340 m 7245 5310 l 7365 5280 l 7365 5310 l 7365 5340 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +7500 4395 m 7380 4365 l 7500 4335 l 7365 4335 l 7365 4395 l cp +clip +n 11385 4365 m 7380 4365 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 7500 4395 m 7380 4365 l 7500 4335 l 7500 4365 l 7500 4395 l cp gs 0.00 setgray ef gr col0 s +% Polyline +n 11040 5580 m 10980 5580 10980 5745 60 arcto 4 {pop} repeat + 10980 5805 12180 5805 60 arcto 4 {pop} repeat + 12240 5805 12240 5640 60 arcto 4 {pop} repeat + 12240 5580 11040 5580 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 11040 5985 m 10980 5985 10980 6150 60 arcto 4 {pop} repeat + 10980 6210 12315 6210 60 arcto 4 {pop} repeat + 12375 6210 12375 6045 60 arcto 4 {pop} repeat + 12375 5985 11040 5985 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +gs clippath +9958 5554 m 9900 5445 l 10003 5514 l 9912 5414 l 9868 5454 l cp +clip +n 11205 6885 m 9900 5445 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 9958 5554 m 9900 5445 l 10003 5514 l 9981 5534 l 9958 5554 l cp gs 0.00 setgray ef gr col0 s +% Polyline +n 10590 6930 m 10530 6930 10530 7095 60 arcto 4 {pop} repeat + 10530 7155 12225 7155 60 arcto 4 {pop} repeat + 12285 7155 12285 6990 60 arcto 4 {pop} repeat + 12285 6930 10590 6930 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +n 9690 6930 m 9630 6930 9630 7095 60 arcto 4 {pop} repeat + 9630 7155 10110 7155 60 arcto 4 {pop} repeat + 10170 7155 10170 6990 60 arcto 4 {pop} repeat + 10170 6930 9690 6930 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +/Times-Roman-iso ff 120.00 scf sf +900 7560 m +gs 1 -1 sc (Startup, Runtime, Shutdown) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +6345 2970 m +gs 1 -1 sc (ap_ctx_get\(...,) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +10800 2745 m +gs 1 -1 sc (ap_get_module_config\(...) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +10800 2880 m +gs 1 -1 sc (->per_dir_config,) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +10800 3015 m +gs 1 -1 sc (&ssl_module\)) col0 sh gr +% Polyline +n 7980 4770 m 7920 4770 7920 4935 60 arcto 4 {pop} repeat + 7920 4995 9075 4995 60 arcto 4 {pop} repeat + 9135 4995 9135 4830 60 arcto 4 {pop} repeat + 9135 4770 7980 4770 60 arcto 4 {pop} repeat + cp gs col35 1.00 shd ef gr gs col35 s gr +% Polyline +gs clippath +7340 2610 m 7425 2520 l 7393 2639 l 7459 2521 l 7406 2492 l cp +clip +n 6975 3330 m 7425 2520 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 7340 2610 m 7425 2520 l 7393 2639 l 7367 2625 l 7340 2610 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +9336 2569 m 9450 2520 l 9373 2616 l 9480 2535 l 9444 2487 l cp +clip +n 7200 4230 m 9450 2520 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 9336 2569 m 9450 2520 l 9373 2616 l 9354 2593 l 9336 2569 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +7321 5196 m 7200 5220 l 7296 5142 l 7174 5199 l 7199 5254 l cp +clip +n 7875 4905 m 7200 5220 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 7321 5196 m 7200 5220 l 7296 5142 l 7309 5169 l 7321 5196 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +6720 4665 m 6750 4545 l 6780 4665 l 6780 4530 l 6720 4530 l cp +clip +n 6750 5130 m 6750 4545 l gs col34 1.00 shd ef gr gs col0 s gr gr + +% arrowhead +n 6720 4665 m 6750 4545 l 6780 4665 l 6750 4665 l 6720 4665 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [15 15] 15 sd +gs clippath +9279 4984 m 9175 4918 l 9298 4927 l 9170 4885 l 9151 4942 l cp +clip +n 9850 5143 m 9175 4918 l gs col34 1.00 shd ef gr gs col0 s gr gr + [] 0 sd +% arrowhead +n 9279 4984 m 9175 4918 l 9298 4927 l 9289 4956 l 9279 4984 l cp gs 0.00 setgray ef gr col0 s +/Helvetica-Narrow-iso ff 120.00 scf sf +6210 4680 m +gs 1 -1 sc (->server) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +8280 6120 m +gs 1 -1 sc (ap_ctx_get\(...,"ssl"\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +7740 2700 m +gs 1 -1 sc (ap_get_module_config\(...) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +7740 2835 m +gs 1 -1 sc (->module_config,) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +7740 2970 m +gs 1 -1 sc (&ssl_module\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +6345 3105 m +gs 1 -1 sc ("ssl_module"\)) col0 sh gr +/Times-Roman-iso ff 120.00 scf sf +1350 7335 m +gs 1 -1 sc (Configuration Time) col0 sh gr +/Times-Roman-iso ff 120.00 scf sf +2025 7110 m +gs 1 -1 sc (Connection Duration) col0 sh gr +/Times-Roman-iso ff 120.00 scf sf +2835 6885 m +gs 1 -1 sc (Request Duration) col0 sh gr +/Helvetica-Bold-iso ff 300.00 scf sf +6345 6795 m +gs 1 -1 sc (t) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +7110 5985 m +gs 1 -1 sc (->client) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +7065 5085 m +gs 1 -1 sc (->connection) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +7065 4770 m +gs 1 -1 sc (->server) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +8010 5445 m +gs 1 -1 sc (SSL_get_app_data\(\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +10530 4050 m +gs 1 -1 sc (->pSSLCtx) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +7875 4275 m +gs 1 -1 sc (SSL_CTX_get_app_data\(\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +10305 5535 m +gs 1 -1 sc (SSL_get_current_cipher\(\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +10440 5940 m +gs 1 -1 sc (SSL_get_session\(\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +9540 7335 m +gs 1 -1 sc (SSL_get_{r,w}bio\(\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +10125 4680 m +gs 1 -1 sc (SSL_get_SSL_CTX\(\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +10350 5175 m +gs 1 -1 sc (SSL_get_SSL_METHOD\(\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +11745 4770 m +gs 1 -1 sc (->method) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +9945 6480 m +gs 1 -1 sc (X509_STORE_CTX_get_app_data\(\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +10980 6705 m +gs 1 -1 sc (SSL_CTX_get_cert_store\(\)) col0 sh gr +/Helvetica-Narrow-iso ff 120.00 scf sf +8280 5130 m +gs 1 -1 sc (SSL_get_app_data2\(\)) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +3645 1620 m +gs 1 -1 sc (SSLDirConfig) col0 sh gr +/Helvetica-Bold-iso ff 300.00 scf sf +10935 3645 m +gs 1 -1 sc (OpenSSL) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +10935 3825 m +gs 1 -1 sc ([SSL]) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +11025 5760 m +gs 1 -1 sc (SSL_CIPHER) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +10980 6165 m +gs 1 -1 sc (SSL_SESSION) col0 sh gr +/Helvetica-Bold-iso ff 300.00 scf sf +10710 7605 m +gs 1 -1 sc (OpenSSL) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +10575 7110 m +gs 1 -1 sc (X509_STORE_CTX) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +6795 2430 m +gs 1 -1 sc (SSLModConfig) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +8865 2430 m +gs 1 -1 sc (SSLSrvConfig) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +6345 3555 m +gs 1 -1 sc (ap_global_ctx) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +6345 4455 m +gs 1 -1 sc (server_rec) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +6345 5355 m +gs 1 -1 sc (conn_rec) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +9720 5355 m +gs 1 -1 sc (SSL) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +10665 2430 m +gs 1 -1 sc (SSLDirConfig) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +7290 6255 m +gs 1 -1 sc (BUFF) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +11025 5355 m +gs 1 -1 sc (SSL_METHOD) col0 sh gr +% Polyline +15.000 slw +n 750 225 m 450 225 450 8250 300 arcto 4 {pop} repeat + 450 8550 12300 8550 300 arcto 4 {pop} repeat + 12600 8550 12600 525 300 arcto 4 {pop} repeat + 12600 225 750 225 300 arcto 4 {pop} repeat + cp gs col0 s gr +/Helvetica-Bold-iso ff 180.00 scf sf +11475 4455 m +gs 1 -1 sc (SSL_CTX) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +8010 4950 m +gs 1 -1 sc (request_rec) col0 sh gr +/Times-Roman-iso ff 180.00 scf sf +10575 675 m +gs 1 -1 sc (Ralf S. Engelschall) col0 sh gr +/Helvetica-Bold-iso ff 300.00 scf sf +4275 675 m +gs 1 -1 sc (Apache+mod_ssl+OpenSSL) col0 sh gr +/Times-Roman-iso ff 150.00 scf sf +10575 855 m +gs 1 -1 sc (rse@engelschall.com) col0 sh gr +/Times-Roman-iso ff 150.00 scf sf +10575 1035 m +gs 1 -1 sc (www.engelschall.com) col0 sh gr +/Times-Roman-iso ff 180.00 scf sf +900 675 m +gs 1 -1 sc (Version 1.3) col0 sh gr +/Times-Roman-iso ff 180.00 scf sf +900 855 m +gs 1 -1 sc (12-Apr-1999) col0 sh gr +/Helvetica-Bold-iso ff 360.00 scf sf +3915 1080 m +gs 1 -1 sc (Data Structure Overview) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +9720 7110 m +gs 1 -1 sc (BIO) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +10710 7785 m +gs 1 -1 sc ([Crypto]) col0 sh gr +/Helvetica-Bold-iso ff 300.00 scf sf +8730 3465 m +gs 1 -1 sc (mod_ssl) col0 sh gr +/Helvetica-Bold-iso ff 300.00 scf sf +8145 6750 m +gs 1 -1 sc (Apache) col0 sh gr +/Helvetica-Bold-iso ff 300.00 scf sf +9000 8100 m +gs 1 -1 sc (Chaining) col0 sh gr +/Helvetica-Bold-iso ff 300.00 scf sf +2745 8100 m +gs 1 -1 sc (Lifetime) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +810 6255 m +gs 1 -1 sc (ap_global_ctx) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +990 5805 m +gs 1 -1 sc (SSLModConfig) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +4050 4455 m +gs 1 -1 sc (SSL_CTX) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +4455 5355 m +gs 1 -1 sc (server_rec) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +3870 4905 m +gs 1 -1 sc (SSLSrvConfig) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +1845 4005 m +gs 1 -1 sc (BUFF) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +2070 3555 m +gs 1 -1 sc (conn_rec) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +2295 3105 m +gs 1 -1 sc (BIO) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +2565 2655 m +gs 1 -1 sc (SSL) col0 sh gr +/Helvetica-Bold-iso ff 180.00 scf sf +3915 2070 m +gs 1 -1 sc (request_rec) col0 sh gr +$F2psEnd +rs +showpage diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/config.m4 b/rubbos/app/httpd-2.0.64/modules/ssl/config.m4 new file mode 100644 index 00000000..8cb4b42e --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/config.m4 @@ -0,0 +1,54 @@ +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl # start of module specific part +APACHE_MODPATH_INIT(ssl) + +dnl # list of module object files +ssl_objs="dnl +mod_ssl.lo dnl +ssl_engine_config.lo dnl +ssl_engine_dh.lo dnl +ssl_engine_init.lo dnl +ssl_engine_io.lo dnl +ssl_engine_kernel.lo dnl +ssl_engine_log.lo dnl +ssl_engine_mutex.lo dnl +ssl_engine_pphrase.lo dnl +ssl_engine_rand.lo dnl +ssl_engine_vars.lo dnl +ssl_expr.lo dnl +ssl_expr_eval.lo dnl +ssl_expr_parse.lo dnl +ssl_expr_scan.lo dnl +ssl_scache.lo dnl +ssl_scache_dbm.lo dnl +ssl_scache_shmcb.lo dnl +ssl_scache_shmht.lo dnl +ssl_util.lo dnl +ssl_util_ssl.lo dnl +ssl_util_table.lo dnl +" +dnl # hook module into the Autoconf mechanism (--enable-ssl option) +APACHE_MODULE(ssl, [SSL/TLS support (mod_ssl)], $ssl_objs, , no, [ + APACHE_CHECK_SSL_TOOLKIT + APR_SETVAR(MOD_SSL_LDADD, [\$(SSL_LIBS)]) + AC_CHECK_FUNCS(SSL_set_state) + AC_CHECK_FUNCS(SSL_set_cert_store) +]) + +dnl # end of module specific part +APACHE_MODPATH_FINISH + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/mod_ssl.c b/rubbos/app/httpd-2.0.64/modules/ssl/mod_ssl.c new file mode 100644 index 00000000..dd22ec9a --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/mod_ssl.c @@ -0,0 +1,428 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * mod_ssl.c + * Apache API interface structures + */ + +#include "mod_ssl.h" +#include "util_md5.h" +#include <assert.h> + +/* + * the table of configuration directives we provide + */ + +#define SSL_CMD_ALL(name, args, desc) \ + AP_INIT_##args("SSL"#name, ssl_cmd_SSL##name, \ + NULL, RSRC_CONF|OR_AUTHCFG, desc), + +#define SSL_CMD_SRV(name, args, desc) \ + AP_INIT_##args("SSL"#name, ssl_cmd_SSL##name, \ + NULL, RSRC_CONF, desc), + +#define SSL_CMD_DIR(name, type, args, desc) \ + AP_INIT_##args("SSL"#name, ssl_cmd_SSL##name, \ + NULL, OR_##type, desc), + +#define AP_END_CMD { NULL } + +const char ssl_valid_ssl_mutex_string[] = + "Valid SSLMutex mechanisms are: `none', `default'" +#if APR_HAS_FLOCK_SERIALIZE + ", `flock:/path/to/file'" +#endif +#if APR_HAS_FCNTL_SERIALIZE + ", `fcntl:/path/to/file'" +#endif +#if APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM) + ", `sysvsem'" +#endif +#if APR_HAS_POSIXSEM_SERIALIZE + ", `posixsem'" +#endif +#if APR_HAS_PROC_PTHREAD_SERIALIZE + ", `pthread'" +#endif +#if APR_HAS_FLOCK_SERIALIZE || APR_HAS_FCNTL_SERIALIZE + ", `file:/path/to/file'" +#endif +#if (APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM)) || APR_HAS_POSIXSEM_SERIALIZE + ", `sem'" +#endif + " "; + +static const command_rec ssl_config_cmds[] = { + /* + * Global (main-server) context configuration directives + */ + SSL_CMD_SRV(Mutex, TAKE1, ssl_valid_ssl_mutex_string) + SSL_CMD_SRV(PassPhraseDialog, TAKE1, + "SSL dialog mechanism for the pass phrase query " + "(`builtin', `|/path/to/pipe_program`, " + "or `exec:/path/to/cgi_program')") + SSL_CMD_SRV(SessionCache, TAKE1, + "SSL Session Cache storage " + "(`none', `dbm:/path/to/file')") +#ifdef SSL_EXPERIMENTAL_ENGINE + SSL_CMD_SRV(CryptoDevice, TAKE1, + "SSL external Crypto Device usage " + "(`builtin', `...')") +#endif + SSL_CMD_SRV(RandomSeed, TAKE23, + "SSL Pseudo Random Number Generator (PRNG) seeding source " + "(`startup|connect builtin|file:/path|exec:/path [bytes]')") + + /* + * Per-server context configuration directives + */ + SSL_CMD_SRV(Engine, FLAG, + "SSL switch for the protocol engine " + "(`on', `off')") + SSL_CMD_ALL(CipherSuite, TAKE1, + "Colon-delimited list of permitted SSL Ciphers " + "(`XXX:...:XXX' - see manual)") + SSL_CMD_SRV(CertificateFile, TAKE1, + "SSL Server Certificate file " + "(`/path/to/file' - PEM or DER encoded)") + SSL_CMD_SRV(CertificateKeyFile, TAKE1, + "SSL Server Private Key file " + "(`/path/to/file' - PEM or DER encoded)") + SSL_CMD_SRV(CertificateChainFile, TAKE1, + "SSL Server CA Certificate Chain file " + "(`/path/to/file' - PEM encoded)") + SSL_CMD_ALL(CACertificatePath, TAKE1, + "SSL CA Certificate path " + "(`/path/to/dir' - contains PEM encoded files)") + SSL_CMD_ALL(CACertificateFile, TAKE1, + "SSL CA Certificate file " + "(`/path/to/file' - PEM encoded)") + SSL_CMD_SRV(CARevocationPath, TAKE1, + "SSL CA Certificate Revocation List (CRL) path " + "(`/path/to/dir' - contains PEM encoded files)") + SSL_CMD_SRV(CARevocationFile, TAKE1, + "SSL CA Certificate Revocation List (CRL) file " + "(`/path/to/file' - PEM encoded)") + SSL_CMD_ALL(VerifyClient, TAKE1, + "SSL Client verify type " + "(`none', `optional', `require', `optional_no_ca')") + SSL_CMD_ALL(VerifyDepth, TAKE1, + "SSL Client verify depth " + "(`N' - number of intermediate certificates)") + SSL_CMD_SRV(SessionCacheTimeout, TAKE1, + "SSL Session Cache object lifetime " + "(`N' - number of seconds)") + SSL_CMD_SRV(Protocol, RAW_ARGS, + "Enable or disable various SSL protocols" + "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)") + SSL_CMD_ALL(UserName, TAKE1, + "Set user name to SSL variable value") + SSL_CMD_SRV(InsecureRenegotiation, FLAG, + "Enable support for insecure renegotiation") + + /* + * Proxy configuration for remote SSL connections + */ + SSL_CMD_SRV(ProxyEngine, FLAG, + "SSL switch for the proxy protocol engine " + "(`on', `off')") + SSL_CMD_SRV(ProxyProtocol, RAW_ARGS, + "SSL Proxy: enable or disable SSL protocol flavors " + "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)") + SSL_CMD_SRV(ProxyCipherSuite, TAKE1, + "SSL Proxy: colon-delimited list of permitted SSL ciphers " + "(`XXX:...:XXX' - see manual)") + SSL_CMD_SRV(ProxyVerify, TAKE1, + "SSL Proxy: whether to verify the remote certificate " + "(`on' or `off')") + SSL_CMD_SRV(ProxyVerifyDepth, TAKE1, + "SSL Proxy: maximum certificate verification depth " + "(`N' - number of intermediate certificates)") + SSL_CMD_SRV(ProxyCACertificateFile, TAKE1, + "SSL Proxy: file containing server certificates " + "(`/path/to/file' - PEM encoded certificates)") + SSL_CMD_SRV(ProxyCACertificatePath, TAKE1, + "SSL Proxy: directory containing server certificates " + "(`/path/to/dir' - contains PEM encoded certificates)") + SSL_CMD_SRV(ProxyCARevocationPath, TAKE1, + "SSL Proxy: CA Certificate Revocation List (CRL) path " + "(`/path/to/dir' - contains PEM encoded files)") + SSL_CMD_SRV(ProxyCARevocationFile, TAKE1, + "SSL Proxy: CA Certificate Revocation List (CRL) file " + "(`/path/to/file' - PEM encoded)") + SSL_CMD_SRV(ProxyMachineCertificateFile, TAKE1, + "SSL Proxy: file containing client certificates " + "(`/path/to/file' - PEM encoded certificates)") + SSL_CMD_SRV(ProxyMachineCertificatePath, TAKE1, + "SSL Proxy: directory containing client certificates " + "(`/path/to/dir' - contains PEM encoded certificates)") + + /* + * Per-directory context configuration directives + */ + SSL_CMD_DIR(Options, OPTIONS, RAW_ARGS, + "Set one or more options to configure the SSL engine" + "(`[+-]option[=value] ...' - see manual)") + SSL_CMD_DIR(RequireSSL, AUTHCFG, NO_ARGS, + "Require the SSL protocol for the per-directory context " + "(no arguments)") + SSL_CMD_DIR(Require, AUTHCFG, RAW_ARGS, + "Require a boolean expression to evaluate to true for granting access" + "(arbitrary complex boolean expression - see manual)") + + /* Deprecated directives. */ + AP_INIT_RAW_ARGS("SSLLog", ap_set_deprecated, NULL, OR_ALL, + "SSLLog directive is no longer supported - use ErrorLog."), + AP_INIT_RAW_ARGS("SSLLogLevel", ap_set_deprecated, NULL, OR_ALL, + "SSLLogLevel directive is no longer supported - use LogLevel."), + + AP_END_CMD +}; + +/* + * the various processing hooks + */ + +static int ssl_hook_pre_config(apr_pool_t *pconf, + apr_pool_t *plog, + apr_pool_t *ptemp) +{ + /* Preregister the malloc callbacks so cmds can make library calls */ + CRYPTO_malloc_init(); + + /* Register us to handle mod_log_config %c/%x variables */ + ssl_var_log_config_register(pconf); +#if 0 /* XXX */ + /* XXX: Register us to handle mod_status extensions that don't exist yet */ + ssl_scache_status_register(pconf); +#endif /* -0- */ + + return OK; +} + +static SSLConnRec *ssl_init_connection_ctx(conn_rec *c) +{ + SSLConnRec *sslconn = myConnConfig(c); + + if (sslconn) { + return sslconn; + } + + sslconn = apr_pcalloc(c->pool, sizeof(*sslconn)); + + myConnConfigSet(c, sslconn); + + return sslconn; +} + +int ssl_proxy_enable(conn_rec *c) +{ + SSLSrvConfigRec *sc = mySrvConfig(c->base_server); + + SSLConnRec *sslconn = ssl_init_connection_ctx(c); + + if (!sc->proxy_enabled) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, + "SSL Proxy requested for %s but not enabled " + "[Hint: SSLProxyEngine]", sc->vhost_id); + + return 0; + } + + sslconn->is_proxy = 1; + sslconn->disabled = 0; + + return 1; +} + +int ssl_engine_disable(conn_rec *c) +{ + SSLSrvConfigRec *sc = mySrvConfig(c->base_server); + + SSLConnRec *sslconn; + + if (!sc->enabled) { + return 0; + } + + sslconn = ssl_init_connection_ctx(c); + + sslconn->disabled = 1; + + return 1; +} + +static int ssl_hook_pre_connection(conn_rec *c, void *csd) +{ + SSLSrvConfigRec *sc = mySrvConfig(c->base_server); + SSL *ssl; + SSLConnRec *sslconn = myConnConfig(c); + char *vhost_md5; + modssl_ctx_t *mctx; + + /* + * Immediately stop processing if SSL is disabled for this connection + */ + if (!(sc && (sc->enabled || + (sslconn && sslconn->is_proxy)))) + { + return DECLINED; + } + + /* + * Create SSL context + */ + if (!sslconn) { + sslconn = ssl_init_connection_ctx(c); + } + + if (sslconn->disabled) { + return DECLINED; + } + + /* + * Remember the connection information for + * later access inside callback functions + */ + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, + "Connection to child %ld established " + "(server %s, client %s)", c->id, sc->vhost_id, + c->remote_ip ? c->remote_ip : "unknown"); + + /* + * Seed the Pseudo Random Number Generator (PRNG) + */ + ssl_rand_seed(c->base_server, c->pool, SSL_RSCTX_CONNECT, ""); + + mctx = sslconn->is_proxy ? sc->proxy : sc->server; + + /* + * Create a new SSL connection with the configured server SSL context and + * attach this to the socket. Additionally we register this attachment + * so we can detach later. + */ + if (!(ssl = SSL_new(mctx->ssl_ctx))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, + "Unable to create a new SSL connection from the SSL " + "context"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, c->base_server); + + c->aborted = 1; + + return DECLINED; /* XXX */ + } + + vhost_md5 = ap_md5_binary(c->pool, (unsigned char *)sc->vhost_id, + sc->vhost_id_len); + + if (!SSL_set_session_id_context(ssl, (unsigned char *)vhost_md5, + MD5_DIGESTSIZE*2)) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server, + "Unable to set session id context to `%s'", vhost_md5); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, c->base_server); + + c->aborted = 1; + + return DECLINED; /* XXX */ + } + + SSL_set_app_data(ssl, c); + SSL_set_app_data2(ssl, NULL); /* will be request_rec */ + + sslconn->ssl = ssl; + + /* + * Configure callbacks for SSL connection + */ + SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA); + SSL_set_tmp_dh_callback(ssl, ssl_callback_TmpDH); + + SSL_set_verify_result(ssl, X509_V_OK); + + ssl_io_filter_init(c, ssl); + + return APR_SUCCESS; +} + +static const char *ssl_hook_http_method(const request_rec *r) +{ + SSLSrvConfigRec *sc = mySrvConfig(r->server); + + if (sc->enabled == FALSE) { + return NULL; + } + + return "https"; +} + +static apr_port_t ssl_hook_default_port(const request_rec *r) +{ + SSLSrvConfigRec *sc = mySrvConfig(r->server); + + if (sc->enabled == FALSE) { + return 0; + } + + return 443; +} + +/* + * the module registration phase + */ + +static void ssl_register_hooks(apr_pool_t *p) +{ + /* ssl_hook_ReadReq needs to use the BrowserMatch settings so must + * run after mod_setenvif's post_read_request hook. */ + static const char *pre_prr[] = { "mod_setenvif.c", NULL }; + + ssl_io_filter_register(p); + + ap_hook_pre_connection(ssl_hook_pre_connection,NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_post_config (ssl_init_Module, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_http_method (ssl_hook_http_method, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_default_port (ssl_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_pre_config (ssl_hook_pre_config, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_child_init (ssl_init_Child, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_check_user_id (ssl_hook_UserCheck, NULL,NULL, APR_HOOK_FIRST); + ap_hook_fixups (ssl_hook_Fixup, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_access_checker(ssl_hook_Access, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_auth_checker (ssl_hook_Auth, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_post_read_request(ssl_hook_ReadReq, pre_prr,NULL, APR_HOOK_MIDDLE); + + ssl_var_register(); + + APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); + APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); +} + +module AP_MODULE_DECLARE_DATA ssl_module = { + STANDARD20_MODULE_STUFF, + ssl_config_perdir_create, /* create per-dir config structures */ + ssl_config_perdir_merge, /* merge per-dir config structures */ + ssl_config_server_create, /* create per-server config structures */ + ssl_config_server_merge, /* merge per-server config structures */ + ssl_config_cmds, /* table of configuration directives */ + ssl_register_hooks /* register hooks */ +}; diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/mod_ssl.dsp b/rubbos/app/httpd-2.0.64/modules/ssl/mod_ssl.dsp new file mode 100644 index 00000000..cf3df14e --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/mod_ssl.dsp @@ -0,0 +1,328 @@ +# Microsoft Developer Studio Project File - Name="mod_ssl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=mod_ssl - Win32 Release +!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 "mod_ssl.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 "mod_ssl.mak" CFG="mod_ssl - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mod_ssl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mod_ssl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mod_ssl - 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 /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/openssl/inc32/openssl" /I "../../srclib/openssl/inc32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_SSL_SET_STATE=1" /Fd"Release\mod_ssl_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 /nologo /subsystem:windows /dll /out:"Release/mod_ssl.so" /base:@..\..\os\win32\BaseAddr.ref,mod_ssl.so +# ADD LINK32 kernel32.lib user32.lib wsock32.lib ws2_32.lib advapi32.lib gdi32.lib ssleay32.lib libeay32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Release/mod_ssl.so" /libpath:"../../srclib/openssl/out32dll" /libpath:"../../srclib/openssl/out32" /base:@..\..\os\win32\BaseAddr.ref,mod_ssl.so /opt:ref + +!ELSEIF "$(CFG)" == "mod_ssl - 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 /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/openssl/inc32/openssl" /I "../../srclib/openssl/inc32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_SSL_SET_STATE=1" /Fd"Debug\mod_ssl_src" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_ssl.so" /base:@..\..\os\win32\BaseAddr.ref,mod_ssl.so +# ADD LINK32 kernel32.lib user32.lib wsock32.lib ws2_32.lib advapi32.lib gdi32.lib ssleay32.lib libeay32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_ssl.so" /libpath:"../../srclib/openssl/out32dll.dbg" /libpath:"../../srclib/openssl/out32.dbg" /base:@..\..\os\win32\BaseAddr.ref,mod_ssl.so + +!ENDIF + +# Begin Target + +# Name "mod_ssl - Win32 Release" +# Name "mod_ssl - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "*.c" +# Begin Source File + +SOURCE=.\mod_ssl.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_config.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_dh.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_init.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_io.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_kernel.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_log.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_mutex.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_pphrase.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_rand.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_engine_vars.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_expr.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_expr_eval.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_expr_parse.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_expr_scan.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_scache.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_scache_dbm.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_scache_shmcb.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_scache_shmht.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_util.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_util_ssl.c +# End Source File +# Begin Source File + +SOURCE=.\ssl_util_table.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "*.h" +# Begin Source File + +SOURCE=.\mod_ssl.h +# End Source File +# Begin Source File + +SOURCE=.\ssl_expr.h +# End Source File +# Begin Source File + +SOURCE=.\ssl_expr_parse.h +# End Source File +# Begin Source File + +SOURCE=.\ssl_toolkit_compat.h +# End Source File +# Begin Source File + +SOURCE=.\ssl_util_ssl.h +# End Source File +# Begin Source File + +SOURCE=.\ssl_util_table.h +# End Source File +# End Group +# Begin Group "Generated Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ssl_expr_parse.y + +!IF "$(CFG)" == "mod_ssl - Win32 Release" + +# Begin Custom Build - Generating ssl_expr_parse.c/.h from ssl_expr_parse.y +InputPath=.\ssl_expr_parse.y + +BuildCmds= \ + bison -y -d ssl_expr_parse.y \ + sed -e "s;yy;ssl_expr_yy;g" -e "/#if defined(c_plusplus) || defined(__cplusplus)/,/#endif/d" <y.tab.c >ssl_expr_parse.c \ + del y.tab.c \ + sed -e "s;yy;ssl_expr_yy;g" <y.tab.h >ssl_expr_parse.h \ + del y.tab.h \ + + +"ssl_expr_parse.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"ssl_expr_parse.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ELSEIF "$(CFG)" == "mod_ssl - Win32 Debug" + +# Begin Custom Build - Generating ssl_expr_parse.c/.h from ssl_expr_parse.y +InputPath=.\ssl_expr_parse.y + +BuildCmds= \ + bison -y -d ssl_expr_parse.y \ + sed -e "s;yy;ssl_expr_yy;g" -e "/#if defined(c_plusplus) || defined(__cplusplus)/,/#endif/d" <y.tab.c >ssl_expr_parse.c \ + del y.tab.c \ + sed -e "s;yy;ssl_expr_yy;g" <y.tab.h >ssl_expr_parse.h \ + del y.tab.h \ + + +"ssl_expr_parse.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"ssl_expr_parse.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\ssl_expr_scan.l + +!IF "$(CFG)" == "mod_ssl - Win32 Release" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build - Generating ssl_expr_scan.c from ssl_expr_scan.l +InputPath=.\ssl_expr_scan.l + +"ssl_expr_scan.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + flex -Pssl_expr_yy -s -B ssl_expr_scan.l + sed -e "/$$Header:/d" <lex.ssl_expr_yy.c >ssl_expr_scan.c + del lex.ssl_expr_yy.c + +# End Custom Build + +!ELSEIF "$(CFG)" == "mod_ssl - Win32 Debug" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build - Generating ssl_expr_scan.c from ssl_expr_scan.l +InputPath=.\ssl_expr_scan.l + +"ssl_expr_scan.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + flex -Pssl_expr_yy -s -B ssl_expr_scan.l + sed -e "/$$Header:/d" <lex.ssl_expr_yy.c >ssl_expr_scan.c + del lex.ssl_expr_yy.c + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=.\mod_ssl.rc +# End Source File +# Begin Source File + +SOURCE=..\..\build\win32\win32ver.awk + +!IF "$(CFG)" == "mod_ssl - Win32 Release" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build - Creating Version Resource +InputPath=..\..\build\win32\win32ver.awk + +".\mod_ssl.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + awk -f ../../build/win32/win32ver.awk mod_ssl.so "ssl_module for Apache" ../../include/ap_release.h > .\mod_ssl.rc + +# End Custom Build + +!ELSEIF "$(CFG)" == "mod_ssl - Win32 Debug" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build - Creating Version Resource +InputPath=..\..\build\win32\win32ver.awk + +".\mod_ssl.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + awk -f ../../build/win32/win32ver.awk mod_ssl.so "ssl_module for Apache" ../../include/ap_release.h > .\mod_ssl.rc + +# End Custom Build + +!ENDIF + +# End Source File +# End Target +# End Project diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/mod_ssl.h b/rubbos/app/httpd-2.0.64/modules/ssl/mod_ssl.h new file mode 100644 index 00000000..6f69c26f --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/mod_ssl.h @@ -0,0 +1,724 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * mod_ssl.h + * Global header + */ + /* ``The Apache Group: a collection + of talented individuals who are + trying to perfect the art of + never finishing something.'' + -- Rob Hartill */ +#ifndef __MOD_SSL_H__ +#define __MOD_SSL_H__ + +/* + * Optionally enable the experimental stuff, but allow the user to + * override the decision which experimental parts are included by using + * CFLAGS="-DSSL_EXPERIMENTAL_xxxx_IGNORE". + */ +#ifdef SSL_EXPERIMENTAL +#ifdef SSL_ENGINE +#ifndef SSL_EXPERIMENTAL_ENGINE_IGNORE +#define SSL_EXPERIMENTAL_ENGINE +#endif +#endif +#endif /* SSL_EXPERIMENTAL */ + +/* + * Power up our brain... + */ + +/* Apache headers */ +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_main.h" +#include "http_connection.h" +#include "http_request.h" +#include "http_protocol.h" +#include "util_script.h" +#include "util_filter.h" +#include "mpm.h" +#include "apr.h" +#include "apr_strings.h" +#define APR_WANT_STRFUNC +#include "apr_want.h" +#include "apr_tables.h" +#include "apr_lib.h" +#include "apr_fnmatch.h" +#include "apr_strings.h" +#include "apr_dbm.h" +#include "apr_rmm.h" +#include "apr_shm.h" +#include "apr_global_mutex.h" +#include "apr_optional.h" + +#define MOD_SSL_VERSION AP_SERVER_BASEREVISION + +#ifdef HAVE_SSLC + +#include <bio.h> +#include <ssl.h> +#include <err.h> +#include <x509.h> +#include <pem.h> +#include <evp.h> +#include <objects.h> +#include <sslc.h> + +#else /* !HAVE_SSLC (implicit HAVE_OPENSSL) */ + +#include <ssl.h> +#include <err.h> +#include <x509.h> +#include <pem.h> +#include <crypto.h> +#include <evp.h> +#include <rand.h> +#ifdef SSL_EXPERIMENTAL_ENGINE +#include <engine.h> +#endif +#ifdef HAVE_SSL_X509V3_H +#include <x509v3.h> +#endif + +#endif /* !HAVE_SSLC (implicit HAVE_OPENSSL) */ + + +/* mod_ssl headers */ +#include "ssl_toolkit_compat.h" +#include "ssl_expr.h" +#include "ssl_util_ssl.h" +#include "ssl_util_table.h" + +/* The #ifdef macros are only defined AFTER including the above + * therefore we cannot include these system files at the top :-( + */ +#if APR_HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* needed for STDIN_FILENO et.al., at least on FreeBSD */ +#endif + +/* + * Provide reasonable default for some defines + */ +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (!FALSE) +#endif +#ifndef PFALSE +#define PFALSE ((void *)FALSE) +#endif +#ifndef PTRUE +#define PTRUE ((void *)TRUE) +#endif +#ifndef UNSET +#define UNSET (-1) +#endif +#ifndef NUL +#define NUL '\0' +#endif +#ifndef RAND_MAX +#include <limits.h> +#define RAND_MAX INT_MAX +#endif + +/* + * Provide reasonable defines for some types + */ +#ifndef BOOL +#define BOOL unsigned int +#endif +#ifndef UCHAR +#define UCHAR unsigned char +#endif + +/* + * Provide useful shorthands + */ +#define strEQ(s1,s2) (strcmp(s1,s2) == 0) +#define strNE(s1,s2) (strcmp(s1,s2) != 0) +#define strEQn(s1,s2,n) (strncmp(s1,s2,n) == 0) +#define strNEn(s1,s2,n) (strncmp(s1,s2,n) != 0) + +#define strcEQ(s1,s2) (strcasecmp(s1,s2) == 0) +#define strcNE(s1,s2) (strcasecmp(s1,s2) != 0) +#define strcEQn(s1,s2,n) (strncasecmp(s1,s2,n) == 0) +#define strcNEn(s1,s2,n) (strncasecmp(s1,s2,n) != 0) + +#define strIsEmpty(s) (s == NULL || s[0] == NUL) + +#define myConnConfig(c) \ +(SSLConnRec *)ap_get_module_config(c->conn_config, &ssl_module) +#define myCtxConfig(sslconn, sc) (sslconn->is_proxy ? sc->proxy : sc->server) +#define myConnConfigSet(c, val) \ +ap_set_module_config(c->conn_config, &ssl_module, val) +#define mySrvConfig(srv) (SSLSrvConfigRec *)ap_get_module_config(srv->module_config, &ssl_module) +#define myDirConfig(req) (SSLDirConfigRec *)ap_get_module_config(req->per_dir_config, &ssl_module) +#define myModConfig(srv) (mySrvConfig((srv)))->mc + +#define myCtxVarSet(mc,num,val) mc->rCtx.pV##num = val +#define myCtxVarGet(mc,num,type) (type)(mc->rCtx.pV##num) + +/* + * Defaults for the configuration + */ +#ifndef SSL_SESSION_CACHE_TIMEOUT +#define SSL_SESSION_CACHE_TIMEOUT 300 +#endif + +/* + * Support for MM library + */ +#define SSL_MM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) + +/* + * Support for DBM library + */ +#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) + +#if !defined(SSL_DBM_FILE_SUFFIX_DIR) && !defined(SSL_DBM_FILE_SUFFIX_PAG) +#if defined(DBM_SUFFIX) +#define SSL_DBM_FILE_SUFFIX_DIR DBM_SUFFIX +#define SSL_DBM_FILE_SUFFIX_PAG DBM_SUFFIX +#elif defined(__FreeBSD__) || (defined(DB_LOCK) && defined(DB_SHMEM)) +#define SSL_DBM_FILE_SUFFIX_DIR ".db" +#define SSL_DBM_FILE_SUFFIX_PAG ".db" +#else +#define SSL_DBM_FILE_SUFFIX_DIR ".dir" +#define SSL_DBM_FILE_SUFFIX_PAG ".pag" +#endif +#endif + +/* + * Define the certificate algorithm types + */ + +typedef int ssl_algo_t; + +#define SSL_ALGO_UNKNOWN (0) +#define SSL_ALGO_RSA (1<<0) +#define SSL_ALGO_DSA (1<<1) +#define SSL_ALGO_ALL (SSL_ALGO_RSA|SSL_ALGO_DSA) + +#define SSL_AIDX_RSA (0) +#define SSL_AIDX_DSA (1) +#define SSL_AIDX_MAX (2) + + +/* + * Define IDs for the temporary RSA keys and DH params + */ + +#define SSL_TMP_KEY_RSA_512 (0) +#define SSL_TMP_KEY_RSA_1024 (1) +#define SSL_TMP_KEY_DH_512 (2) +#define SSL_TMP_KEY_DH_1024 (3) +#define SSL_TMP_KEY_MAX (4) + +/* + * Define the SSL options + */ +#define SSL_OPT_NONE (0) +#define SSL_OPT_RELSET (1<<0) +#define SSL_OPT_STDENVVARS (1<<1) +#define SSL_OPT_COMPATENVVARS (1<<2) +#define SSL_OPT_EXPORTCERTDATA (1<<3) +#define SSL_OPT_FAKEBASICAUTH (1<<4) +#define SSL_OPT_STRICTREQUIRE (1<<5) +#define SSL_OPT_OPTRENEGOTIATE (1<<6) +#define SSL_OPT_ALL (SSL_OPT_STDENVVARS|SSL_OPT_COMPATENVVAR|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE) +typedef int ssl_opt_t; + +/* + * Define the SSL Protocol options + */ +#define SSL_PROTOCOL_NONE (0) +#define SSL_PROTOCOL_SSLV2 (1<<0) +#define SSL_PROTOCOL_SSLV3 (1<<1) +#define SSL_PROTOCOL_TLSV1 (1<<2) +#define SSL_PROTOCOL_ALL (SSL_PROTOCOL_SSLV2|SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1) +typedef int ssl_proto_t; + +/* + * Define the SSL verify levels + */ +typedef enum { + SSL_CVERIFY_UNSET = UNSET, + SSL_CVERIFY_NONE = 0, + SSL_CVERIFY_OPTIONAL = 1, + SSL_CVERIFY_REQUIRE = 2, + SSL_CVERIFY_OPTIONAL_NO_CA = 3 +} ssl_verify_t; + +#define SSL_VERIFY_PEER_STRICT \ + (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + +#ifndef X509_V_ERR_CERT_UNTRUSTED +#define X509_V_ERR_CERT_UNTRUSTED 27 +#endif + +#define ssl_verify_error_is_optional(errnum) \ + ((errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) \ + || (errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \ + || (errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) \ + || (errnum == X509_V_ERR_CERT_UNTRUSTED) \ + || (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)) + +/* + * Define the SSL pass phrase dialog types + */ +typedef enum { + SSL_PPTYPE_UNSET = UNSET, + SSL_PPTYPE_BUILTIN = 0, + SSL_PPTYPE_FILTER = 1, + SSL_PPTYPE_PIPE = 2 +} ssl_pphrase_t; + +/* + * Define the Path Checking modes + */ +#define SSL_PCM_EXISTS 1 +#define SSL_PCM_ISREG 2 +#define SSL_PCM_ISDIR 4 +#define SSL_PCM_ISNONZERO 8 +typedef unsigned int ssl_pathcheck_t; + +/* + * Define the SSL session cache modes and structures + */ +typedef enum { + SSL_SCMODE_UNSET = UNSET, + SSL_SCMODE_NONE = 0, + SSL_SCMODE_DBM = 1, + SSL_SCMODE_SHMHT = 2, + SSL_SCMODE_SHMCB = 3 +} ssl_scmode_t; + +/* + * Define the SSL mutex modes + */ +typedef enum { + SSL_MUTEXMODE_UNSET = UNSET, + SSL_MUTEXMODE_NONE = 0, + SSL_MUTEXMODE_USED = 1 +} ssl_mutexmode_t; + +/* + * Define the SSL requirement structure + */ +typedef struct { + char *cpExpr; + ssl_expr *mpExpr; +} ssl_require_t; + +/* + * Define the SSL random number generator seeding source + */ +typedef enum { + SSL_RSCTX_STARTUP = 1, + SSL_RSCTX_CONNECT = 2 +} ssl_rsctx_t; +typedef enum { + SSL_RSSRC_BUILTIN = 1, + SSL_RSSRC_FILE = 2, + SSL_RSSRC_EXEC = 3, + SSL_RSSRC_EGD = 4 +} ssl_rssrc_t; +typedef struct { + ssl_rsctx_t nCtx; + ssl_rssrc_t nSrc; + char *cpPath; + int nBytes; +} ssl_randseed_t; + +/* + * Define the structure of an ASN.1 anything + */ +typedef struct { + long int nData; + unsigned char *cpData; + apr_time_t source_mtime; +} ssl_asn1_t; + +/* + * Define the mod_ssl per-module configuration structure + * (i.e. the global configuration for each httpd process) + */ + +typedef enum { + SSL_SHUTDOWN_TYPE_UNSET, + SSL_SHUTDOWN_TYPE_STANDARD, + SSL_SHUTDOWN_TYPE_UNCLEAN, + SSL_SHUTDOWN_TYPE_ACCURATE +} ssl_shutdown_type_e; + +typedef struct { + SSL *ssl; + const char *client_dn; + X509 *client_cert; + ssl_shutdown_type_e shutdown_type; + const char *verify_info; + const char *verify_error; + int verify_depth; + int is_proxy; + int disabled; + int non_ssl_request; + + /* Track the handshake/renegotiation state for the connection so + * that all client-initiated renegotiations can be rejected, as a + * partial fix for CVE-2009-3555. */ + enum { + RENEG_INIT = 0, /* Before initial handshake */ + RENEG_REJECT, /* After initial handshake; any client-initiated + * renegotiation should be rejected */ + RENEG_ALLOW, /* A server-initated renegotiation is taking + * place (as dictated by configuration) */ + RENEG_ABORT /* Renegotiation initiated by client, abort the + * connection */ + } reneg_state; +} SSLConnRec; + +typedef struct { + pid_t pid; + apr_pool_t *pPool; + BOOL bFixed; + int nSessionCacheMode; + char *szSessionCacheDataFile; + int nSessionCacheDataSize; + apr_shm_t *pSessionCacheDataMM; + apr_rmm_t *pSessionCacheDataRMM; + apr_table_t *tSessionCacheDataTable; + ssl_mutexmode_t nMutexMode; + apr_lockmech_e nMutexMech; + const char *szMutexFile; + apr_global_mutex_t *pMutex; + apr_array_header_t *aRandSeed; + apr_hash_t *tVHostKeys; + void *pTmpKeys[SSL_TMP_KEY_MAX]; + apr_hash_t *tPublicCert; + apr_hash_t *tPrivateKey; +#ifdef SSL_EXPERIMENTAL_ENGINE + char *szCryptoDevice; +#endif + struct { + void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10; + } rCtx; +} SSLModConfigRec; + +/* public cert/private key */ +typedef struct { + /* + * server only has 1-2 certs/keys + * 1 RSA and/or 1 DSA + */ + const char *cert_files[SSL_AIDX_MAX]; + const char *key_files[SSL_AIDX_MAX]; + X509 *certs[SSL_AIDX_MAX]; + EVP_PKEY *keys[SSL_AIDX_MAX]; +} modssl_pk_server_t; + +typedef struct { + /* proxy can have any number of cert/key pairs */ + const char *cert_file; + const char *cert_path; + STACK_OF(X509_INFO) *certs; +} modssl_pk_proxy_t; + +/* stuff related to authentication that can also be per-dir */ +typedef struct { + /* known/trusted CAs */ + const char *ca_cert_path; + const char *ca_cert_file; + + const char *cipher_suite; + + /* for client or downstream server authentication */ + int verify_depth; + ssl_verify_t verify_mode; +} modssl_auth_ctx_t; + +typedef struct SSLSrvConfigRec SSLSrvConfigRec; + +typedef struct { + SSLSrvConfigRec *sc; /* pointer back to server config */ + SSL_CTX *ssl_ctx; + + /* we are one or the other */ + modssl_pk_server_t *pks; + modssl_pk_proxy_t *pkp; + + ssl_proto_t protocol; + + /* config for handling encrypted keys */ + ssl_pphrase_t pphrase_dialog_type; + const char *pphrase_dialog_path; + + const char *cert_chain; + + /* certificate revocation list */ + const char *crl_path; + const char *crl_file; + X509_STORE *crl; + + modssl_auth_ctx_t auth; +} modssl_ctx_t; + +struct SSLSrvConfigRec { + SSLModConfigRec *mc; + BOOL enabled; + BOOL proxy_enabled; + const char *vhost_id; + int vhost_id_len; + int session_cache_timeout; + BOOL insecure_reneg; + modssl_ctx_t *server; + modssl_ctx_t *proxy; +}; + +/* + * Define the mod_ssl per-directory configuration structure + * (i.e. the local configuration for all <Directory> + * and .htaccess contexts) + */ +typedef struct { + BOOL bSSLRequired; + apr_array_header_t *aRequirement; + ssl_opt_t nOptions; + ssl_opt_t nOptionsAdd; + ssl_opt_t nOptionsDel; + const char *szCipherSuite; + ssl_verify_t nVerifyClient; + int nVerifyDepth; + const char *szCACertificatePath; + const char *szCACertificateFile; + const char *szUserName; +} SSLDirConfigRec; + +/* + * function prototypes + */ + +/* API glue structures */ +extern module AP_MODULE_DECLARE_DATA ssl_module; + +/* "global" stuff */ +extern const char ssl_valid_ssl_mutex_string[]; + +/* configuration handling */ +SSLModConfigRec *ssl_config_global_create(server_rec *); +void ssl_config_global_fix(SSLModConfigRec *); +BOOL ssl_config_global_isfixed(SSLModConfigRec *); +void *ssl_config_server_create(apr_pool_t *, server_rec *); +void *ssl_config_server_merge(apr_pool_t *, void *, void *); +void *ssl_config_perdir_create(apr_pool_t *, char *); +void *ssl_config_perdir_merge(apr_pool_t *, void *, void *); +const char *ssl_cmd_SSLMutex(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLPassPhraseDialog(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCryptoDevice(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLRandomSeed(cmd_parms *, void *, const char *, const char *, const char *); +const char *ssl_cmd_SSLEngine(cmd_parms *, void *, int); +const char *ssl_cmd_SSLCipherSuite(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCertificateFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCACertificatePath(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCACertificateFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCARevocationPath(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCARevocationFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLVerifyClient(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLVerifyDepth(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLSessionCache(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLSessionCacheTimeout(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProtocol(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLOptions(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLRequireSSL(cmd_parms *, void *); +const char *ssl_cmd_SSLRequire(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLUserName(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLInsecureRenegotiation(cmd_parms *cmd, void *dcfg, int flag); + +const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag); +const char *ssl_cmd_SSLProxyProtocol(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyVerify(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, void *, const char *); + +/* module initialization */ +int ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *); +void ssl_init_Engine(server_rec *, apr_pool_t *); +void ssl_init_ConfigureServer(server_rec *, apr_pool_t *, apr_pool_t *, SSLSrvConfigRec *); +void ssl_init_CheckServers(server_rec *, apr_pool_t *); +STACK_OF(X509_NAME) + *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *); +void ssl_init_Child(apr_pool_t *, server_rec *); +apr_status_t ssl_init_ModuleKill(void *data); + +/* Apache API hooks */ +int ssl_hook_Auth(request_rec *); +int ssl_hook_UserCheck(request_rec *); +int ssl_hook_Access(request_rec *); +int ssl_hook_Fixup(request_rec *); +int ssl_hook_ReadReq(request_rec *); + +/* OpenSSL callbacks */ +RSA *ssl_callback_TmpRSA(SSL *, int, int); +DH *ssl_callback_TmpDH(SSL *, int, int); +int ssl_callback_SSLVerify(int, X509_STORE_CTX *); +int ssl_callback_SSLVerify_CRL(int, X509_STORE_CTX *, conn_rec *); +int ssl_callback_proxy_cert(SSL *ssl, MODSSL_CLIENT_CERT_CB_ARG_TYPE **x509, EVP_PKEY **pkey); +int ssl_callback_NewSessionCacheEntry(SSL *, SSL_SESSION *); +SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *, unsigned char *, int, int *); +void ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *); +void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE, int, int); + +/* Session Cache Support */ +void ssl_scache_init(server_rec *, apr_pool_t *); +#if 0 /* XXX */ +void ssl_scache_status_register(apr_pool_t *p); +#endif +void ssl_scache_kill(server_rec *); +BOOL ssl_scache_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *); +SSL_SESSION *ssl_scache_retrieve(server_rec *, UCHAR *, int); +void ssl_scache_remove(server_rec *, UCHAR *, int); +void ssl_scache_expire(server_rec *); +void ssl_scache_status(server_rec *, apr_pool_t *, void (*)(char *, void *), void *); +char *ssl_scache_id2sz(UCHAR *, int); +void ssl_scache_dbm_init(server_rec *, apr_pool_t *); +void ssl_scache_dbm_kill(server_rec *); +BOOL ssl_scache_dbm_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *); +SSL_SESSION *ssl_scache_dbm_retrieve(server_rec *, UCHAR *, int); +void ssl_scache_dbm_remove(server_rec *, UCHAR *, int); +void ssl_scache_dbm_expire(server_rec *); +void ssl_scache_dbm_status(server_rec *, apr_pool_t *, void (*)(char *, void *), void *); + +void ssl_scache_shmht_init(server_rec *, apr_pool_t *); +void ssl_scache_shmht_kill(server_rec *); +BOOL ssl_scache_shmht_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *); +SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *, UCHAR *, int); +void ssl_scache_shmht_remove(server_rec *, UCHAR *, int); +void ssl_scache_shmht_expire(server_rec *); +void ssl_scache_shmht_status(server_rec *, apr_pool_t *, void (*)(char *, void *), void *); + +void ssl_scache_shmcb_init(server_rec *, apr_pool_t *); +void ssl_scache_shmcb_kill(server_rec *); +BOOL ssl_scache_shmcb_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *); +SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *, UCHAR *, int); +void ssl_scache_shmcb_remove(server_rec *, UCHAR *, int); +void ssl_scache_shmcb_expire(server_rec *); +void ssl_scache_shmcb_status(server_rec *, apr_pool_t *, void (*)(char *, void *), void *); + +/* Pass Phrase Support */ +void ssl_pphrase_Handle(server_rec *, apr_pool_t *); + +/* Diffie-Hellman Parameter Support */ +DH *ssl_dh_GetTmpParam(int); +DH *ssl_dh_GetParamFromFile(char *); + +unsigned char *ssl_asn1_table_set(apr_hash_t *table, + const char *key, + long int length); + +ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table, + const char *key); + +void ssl_asn1_table_unset(apr_hash_t *table, + const char *key); + +const char *ssl_asn1_keystr(int keytype); + +const char *ssl_asn1_table_keyfmt(apr_pool_t *p, + const char *id, + int keytype); +/* Mutex Support */ +int ssl_mutex_init(server_rec *, apr_pool_t *); +int ssl_mutex_reinit(server_rec *, apr_pool_t *); +int ssl_mutex_on(server_rec *); +int ssl_mutex_off(server_rec *); + +/* Logfile Support */ +void ssl_die(void); +void ssl_log_ssl_error(const char *, int, int, server_rec *); + +/* Variables */ +void ssl_var_register(void); +char *ssl_var_lookup(apr_pool_t *, server_rec *, conn_rec *, request_rec *, char *); +void ssl_var_log_config_register(apr_pool_t *p); + +APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup, + (apr_pool_t *, server_rec *, + conn_rec *, request_rec *, + char *)); + +/* An optional function which returns non-zero if the given connection + * is using SSL/TLS. */ +APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); + +/* Proxy Support */ +int ssl_proxy_enable(conn_rec *c); +int ssl_engine_disable(conn_rec *c); + +APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); + +APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); + +/* I/O */ +void ssl_io_filter_init(conn_rec *, SSL *); +void ssl_io_filter_register(apr_pool_t *); +long ssl_io_data_cb(BIO *, int, MODSSL_BIO_CB_ARG_TYPE *, int, long, long); + +/* ssl_io_buffer_fill fills the setaside buffering of the HTTP request + * to allow an SSL renegotiation to take place. */ +int ssl_io_buffer_fill(request_rec *r); + +/* PRNG */ +int ssl_rand_seed(server_rec *, apr_pool_t *, ssl_rsctx_t, char *); + +/* Utility Functions */ +char *ssl_util_vhostid(apr_pool_t *, server_rec *); +void ssl_util_strupper(char *); +void ssl_util_uuencode(char *, const char *, BOOL); +void ssl_util_uuencode_binary(unsigned char *, const unsigned char *, int, BOOL); +apr_file_t *ssl_util_ppopen(server_rec *, apr_pool_t *, const char *, + const char * const *); +void ssl_util_ppclose(server_rec *, apr_pool_t *, apr_file_t *); +char *ssl_util_readfilter(server_rec *, apr_pool_t *, const char *, + const char * const *); +BOOL ssl_util_path_check(ssl_pathcheck_t, const char *, apr_pool_t *); +ssl_algo_t ssl_util_algotypeof(X509 *, EVP_PKEY *); +char *ssl_util_algotypestr(ssl_algo_t); +char *ssl_util_ptxtsub(apr_pool_t *, const char *, const char *, char *); +void ssl_util_thread_setup(apr_pool_t *); + +#define APR_SHM_MAXSIZE (64 * 1024 * 1024) +#endif /* __MOD_SSL_H__ */ diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/modules.mk b/rubbos/app/httpd-2.0.64/modules/ssl/modules.mk new file mode 100644 index 00000000..ceb52a1b --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/modules.mk @@ -0,0 +1,3 @@ +DISTCLEAN_TARGETS = modules.mk +static = +shared = diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_config.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_config.c new file mode 100644 index 00000000..f597d2a4 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_config.c @@ -0,0 +1,1420 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_config.c + * Apache Configuration Directives + */ + /* ``Damned if you do, + damned if you don't.'' + -- Unknown */ +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** Support for Global Configuration +** _________________________________________________________________ +*/ + +#define SSL_MOD_CONFIG_KEY "ssl_module" + +SSLModConfigRec *ssl_config_global_create(server_rec *s) +{ + apr_pool_t *pool = s->process->pool; + SSLModConfigRec *mc; + void *vmc; + + apr_pool_userdata_get(&vmc, SSL_MOD_CONFIG_KEY, pool); + if (vmc) { + return vmc; /* reused for lifetime of the server */ + } + + /* + * allocate an own subpool which survives server restarts + */ + mc = (SSLModConfigRec *)apr_palloc(pool, sizeof(*mc)); + mc->pPool = pool; + mc->bFixed = FALSE; + + /* + * initialize per-module configuration + */ + mc->nSessionCacheMode = SSL_SCMODE_UNSET; + mc->szSessionCacheDataFile = NULL; + mc->nSessionCacheDataSize = 0; + mc->pSessionCacheDataMM = NULL; + mc->pSessionCacheDataRMM = NULL; + mc->tSessionCacheDataTable = NULL; + mc->nMutexMode = SSL_MUTEXMODE_UNSET; + mc->nMutexMech = APR_LOCK_DEFAULT; + mc->szMutexFile = NULL; + mc->pMutex = NULL; + mc->aRandSeed = apr_array_make(pool, 4, + sizeof(ssl_randseed_t)); + mc->tVHostKeys = apr_hash_make(pool); + mc->tPrivateKey = apr_hash_make(pool); + mc->tPublicCert = apr_hash_make(pool); +#ifdef SSL_EXPERIMENTAL_ENGINE + mc->szCryptoDevice = NULL; +#endif + + memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys)); + + apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY, + apr_pool_cleanup_null, + pool); + + return mc; +} + +void ssl_config_global_fix(SSLModConfigRec *mc) +{ + mc->bFixed = TRUE; +} + +BOOL ssl_config_global_isfixed(SSLModConfigRec *mc) +{ + return mc->bFixed; +} + +/* _________________________________________________________________ +** +** Configuration handling +** _________________________________________________________________ +*/ + +static void modssl_ctx_init(modssl_ctx_t *mctx) +{ + mctx->sc = NULL; /* set during module init */ + + mctx->ssl_ctx = NULL; /* set during module init */ + + mctx->pks = NULL; + mctx->pkp = NULL; + + mctx->protocol = SSL_PROTOCOL_ALL; + + mctx->pphrase_dialog_type = SSL_PPTYPE_UNSET; + mctx->pphrase_dialog_path = NULL; + + mctx->cert_chain = NULL; + + mctx->crl_path = NULL; + mctx->crl_file = NULL; + mctx->crl = NULL; /* set during module init */ + + mctx->auth.ca_cert_path = NULL; + mctx->auth.ca_cert_file = NULL; + mctx->auth.cipher_suite = NULL; + mctx->auth.verify_depth = UNSET; + mctx->auth.verify_mode = SSL_CVERIFY_UNSET; +} + +static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc, + apr_pool_t *p) +{ + modssl_ctx_t *mctx; + + mctx = sc->proxy = apr_palloc(p, sizeof(*sc->proxy)); + + modssl_ctx_init(mctx); + + mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp)); + + mctx->pkp->cert_file = NULL; + mctx->pkp->cert_path = NULL; + mctx->pkp->certs = NULL; +} + +static void modssl_ctx_init_server(SSLSrvConfigRec *sc, + apr_pool_t *p) +{ + modssl_ctx_t *mctx; + + mctx = sc->server = apr_palloc(p, sizeof(*sc->server)); + + modssl_ctx_init(mctx); + + mctx->pks = apr_palloc(p, sizeof(*mctx->pks)); + + memset((void*)mctx->pks->cert_files, 0, sizeof(mctx->pks->cert_files)); + + memset((void*)mctx->pks->key_files, 0, sizeof(mctx->pks->key_files)); + + /* certs/keys are set during module init */ + + memset(mctx->pks->certs, 0, sizeof(mctx->pks->certs)); + + memset(mctx->pks->keys, 0, sizeof(mctx->pks->keys)); +} + +static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) +{ + SSLSrvConfigRec *sc = apr_palloc(p, sizeof(*sc)); + + sc->mc = NULL; + sc->enabled = UNSET; + sc->proxy_enabled = UNSET; + sc->vhost_id = NULL; /* set during module init */ + sc->vhost_id_len = 0; /* set during module init */ + sc->session_cache_timeout = UNSET; + sc->insecure_reneg = UNSET; + + modssl_ctx_init_proxy(sc, p); + + modssl_ctx_init_server(sc, p); + + return sc; +} + +/* + * Create per-server SSL configuration + */ +void *ssl_config_server_create(apr_pool_t *p, server_rec *s) +{ + SSLSrvConfigRec *sc = ssl_config_server_new(p); + + sc->mc = ssl_config_global_create(s); + + return sc; +} + +#define cfgMerge(el,unset) mrg->el = (add->el == (unset)) ? base->el : add->el +#define cfgMergeArray(el) mrg->el = apr_array_append(p, add->el, base->el) +#define cfgMergeString(el) cfgMerge(el, NULL) +#define cfgMergeBool(el) cfgMerge(el, UNSET) +#define cfgMergeInt(el) cfgMerge(el, UNSET) + +static void modssl_ctx_cfg_merge(modssl_ctx_t *base, + modssl_ctx_t *add, + modssl_ctx_t *mrg) +{ + cfgMerge(protocol, SSL_PROTOCOL_ALL); + + cfgMerge(pphrase_dialog_type, SSL_PPTYPE_UNSET); + cfgMergeString(pphrase_dialog_path); + + cfgMergeString(cert_chain); + + cfgMerge(crl_path, NULL); + cfgMerge(crl_file, NULL); + + cfgMergeString(auth.ca_cert_path); + cfgMergeString(auth.ca_cert_file); + cfgMergeString(auth.cipher_suite); + cfgMergeInt(auth.verify_depth); + cfgMerge(auth.verify_mode, SSL_CVERIFY_UNSET); +} + +static void modssl_ctx_cfg_merge_proxy(modssl_ctx_t *base, + modssl_ctx_t *add, + modssl_ctx_t *mrg) +{ + modssl_ctx_cfg_merge(base, add, mrg); + + cfgMergeString(pkp->cert_file); + cfgMergeString(pkp->cert_path); +} + +static void modssl_ctx_cfg_merge_server(modssl_ctx_t *base, + modssl_ctx_t *add, + modssl_ctx_t *mrg) +{ + int i; + + modssl_ctx_cfg_merge(base, add, mrg); + + for (i = 0; i < SSL_AIDX_MAX; i++) { + cfgMergeString(pks->cert_files[i]); + cfgMergeString(pks->key_files[i]); + } +} + +/* + * Merge per-server SSL configurations + */ +void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) +{ + SSLSrvConfigRec *base = (SSLSrvConfigRec *)basev; + SSLSrvConfigRec *add = (SSLSrvConfigRec *)addv; + SSLSrvConfigRec *mrg = ssl_config_server_new(p); + + cfgMerge(mc, NULL); + cfgMergeBool(enabled); + cfgMergeBool(proxy_enabled); + cfgMergeInt(session_cache_timeout); + cfgMergeBool(insecure_reneg); + + modssl_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy); + + modssl_ctx_cfg_merge_server(base->server, add->server, mrg->server); + + return mrg; +} + +/* + * Create per-directory SSL configuration + */ +void *ssl_config_perdir_create(apr_pool_t *p, char *dir) +{ + SSLDirConfigRec *dc = apr_palloc(p, sizeof(*dc)); + + dc->bSSLRequired = FALSE; + dc->aRequirement = apr_array_make(p, 4, sizeof(ssl_require_t)); + dc->nOptions = SSL_OPT_NONE|SSL_OPT_RELSET; + dc->nOptionsAdd = SSL_OPT_NONE; + dc->nOptionsDel = SSL_OPT_NONE; + + dc->szCipherSuite = NULL; + dc->nVerifyClient = SSL_CVERIFY_UNSET; + dc->nVerifyDepth = UNSET; + + dc->szCACertificatePath = NULL; + dc->szCACertificateFile = NULL; + dc->szUserName = NULL; + + return dc; +} + +/* + * Merge per-directory SSL configurations + */ +void *ssl_config_perdir_merge(apr_pool_t *p, void *basev, void *addv) +{ + SSLDirConfigRec *base = (SSLDirConfigRec *)basev; + SSLDirConfigRec *add = (SSLDirConfigRec *)addv; + SSLDirConfigRec *mrg = (SSLDirConfigRec *)apr_palloc(p, sizeof(*mrg)); + + cfgMerge(bSSLRequired, FALSE); + cfgMergeArray(aRequirement); + + if (add->nOptions & SSL_OPT_RELSET) { + mrg->nOptionsAdd = + (base->nOptionsAdd & ~(add->nOptionsDel)) | add->nOptionsAdd; + mrg->nOptionsDel = + (base->nOptionsDel & ~(add->nOptionsAdd)) | add->nOptionsDel; + mrg->nOptions = + (base->nOptions & ~(mrg->nOptionsDel)) | mrg->nOptionsAdd; + } + else { + mrg->nOptions = add->nOptions; + mrg->nOptionsAdd = add->nOptionsAdd; + mrg->nOptionsDel = add->nOptionsDel; + } + + cfgMergeString(szCipherSuite); + cfgMerge(nVerifyClient, SSL_CVERIFY_UNSET); + cfgMergeInt(nVerifyDepth); + + cfgMergeString(szCACertificatePath); + cfgMergeString(szCACertificateFile); + cfgMergeString(szUserName); + + return mrg; +} + +/* + * Configuration functions for particular directives + */ + +const char *ssl_cmd_SSLMutex(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + const char *err; + SSLModConfigRec *mc = myModConfig(cmd->server); + + if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; + } + + if (ssl_config_global_isfixed(mc)) { + return NULL; + } + + if (strcEQ(arg, "none") || strcEQ(arg, "no")) { + mc->nMutexMode = SSL_MUTEXMODE_NONE; + } + /* NOTE: previously, 'yes' implied 'sem' */ + else if (strcEQ(arg, "default") || strcEQ(arg, "yes")) { + mc->nMutexMode = SSL_MUTEXMODE_USED; + mc->nMutexMech = APR_LOCK_DEFAULT; + mc->szMutexFile = NULL; /* APR determines temporary filename */ + } +#if APR_HAS_FLOCK_SERIALIZE + else if (strlen(arg) > 6 && strcEQn(arg, "flock:", 6)) { + const char *file = ap_server_root_relative(cmd->pool, arg+6); + if (!file) { + return apr_pstrcat(cmd->pool, "Invalid SSLMutex flock: path ", + arg+6, NULL); + } + mc->nMutexMode = SSL_MUTEXMODE_USED; + mc->nMutexMech = APR_LOCK_FLOCK; + mc->szMutexFile = apr_psprintf(mc->pPool, "%s.%lu", + file, (unsigned long)getpid()); + } +#endif +#if APR_HAS_FCNTL_SERIALIZE + else if (strlen(arg) > 6 && strcEQn(arg, "fcntl:", 6)) { + const char *file = ap_server_root_relative(cmd->pool, arg+6); + if (!file) { + return apr_pstrcat(cmd->pool, "Invalid SSLMutex fcntl: path ", + arg+6, NULL); + } + mc->nMutexMode = SSL_MUTEXMODE_USED; + mc->nMutexMech = APR_LOCK_FCNTL; + mc->szMutexFile = apr_psprintf(mc->pPool, "%s.%lu", + file, (unsigned long)getpid()); + } +#endif +#if APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM) + else if (strcEQ(arg, "sysvsem")) { + mc->nMutexMode = SSL_MUTEXMODE_USED; + mc->nMutexMech = APR_LOCK_SYSVSEM; + mc->szMutexFile = NULL; /* APR determines temporary filename */ + } +#endif +#if APR_HAS_POSIXSEM_SERIALIZE + else if (strcEQ(arg, "posixsem")) { + mc->nMutexMode = SSL_MUTEXMODE_USED; + mc->nMutexMech = APR_LOCK_POSIXSEM; + mc->szMutexFile = NULL; /* APR determines temporary filename */ + } +#endif +#if APR_HAS_PROC_PTHREAD_SERIALIZE + else if (strcEQ(arg, "pthread")) { + mc->nMutexMode = SSL_MUTEXMODE_USED; + mc->nMutexMech = APR_LOCK_PROC_PTHREAD; + mc->szMutexFile = NULL; /* APR determines temporary filename */ + } +#endif +#if APR_HAS_FLOCK_SERIALIZE || APR_HAS_FCNTL_SERIALIZE + else if (strlen(arg) > 5 && strcEQn(arg, "file:", 5)) { + const char *file = ap_server_root_relative(cmd->pool, arg+5); + if (!file) { + return apr_pstrcat(cmd->pool, "Invalid SSLMutex file: path ", + arg+5, NULL); + } + mc->nMutexMode = SSL_MUTEXMODE_USED; +#if APR_HAS_FLOCK_SERIALIZE + mc->nMutexMech = APR_LOCK_FLOCK; +#endif +#if APR_HAS_FCNTL_SERIALIZE + mc->nMutexMech = APR_LOCK_FCNTL; +#endif + mc->szMutexFile = + apr_psprintf(mc->pPool, "%s.%lu", + file, (unsigned long)getpid()); + } +#endif +#if (APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM)) || APR_HAS_POSIXSEM_SERIALIZE + else if (strcEQ(arg, "sem")) { + mc->nMutexMode = SSL_MUTEXMODE_USED; +#if APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM) + mc->nMutexMech = APR_LOCK_SYSVSEM; +#endif +#if APR_HAS_POSIXSEM_SERIALIZE + mc->nMutexMech = APR_LOCK_POSIXSEM; +#endif + mc->szMutexFile = NULL; /* APR determines temporary filename */ + } +#endif + else { + return apr_pstrcat(cmd->pool, "Invalid SSLMutex argument ", + arg, " (", ssl_valid_ssl_mutex_string, ")", NULL); + } + + return NULL; +} + +const char *ssl_cmd_SSLPassPhraseDialog(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + int arglen = strlen(arg); + + if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; + } + + if (strcEQ(arg, "builtin")) { + sc->server->pphrase_dialog_type = SSL_PPTYPE_BUILTIN; + sc->server->pphrase_dialog_path = NULL; + } + else if ((arglen > 5) && strEQn(arg, "exec:", 5)) { + sc->server->pphrase_dialog_type = SSL_PPTYPE_FILTER; + /* ### This is broken, exec: may contain args, no? */ + sc->server->pphrase_dialog_path = + ap_server_root_relative(cmd->pool, arg+5); + if (!sc->server->pphrase_dialog_path) { + return apr_pstrcat(cmd->pool, + "Invalid SSLPassPhraseDialog exec: path ", + arg+5, NULL); + } + if (!ssl_util_path_check(SSL_PCM_EXISTS, + sc->server->pphrase_dialog_path, + cmd->pool)) + { + return apr_pstrcat(cmd->pool, + "SSLPassPhraseDialog: file '", + sc->server->pphrase_dialog_path, + "' does not exist", NULL); + } + + } + else if ((arglen > 1) && (arg[0] == '|')) { + sc->server->pphrase_dialog_type = SSL_PPTYPE_PIPE; + sc->server->pphrase_dialog_path = arg + 1; + } + else { + return "SSLPassPhraseDialog: Invalid argument"; + } + + return NULL; +} + +#ifdef SSL_EXPERIMENTAL_ENGINE +const char *ssl_cmd_SSLCryptoDevice(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLModConfigRec *mc = myModConfig(cmd->server); + const char *err; + ENGINE *e; +#if SSL_LIBRARY_VERSION >= 0x00907000 + static int loaded_engines = FALSE; + + /* early loading to make sure the engines are already + available for ENGINE_by_id() above... */ + if (!loaded_engines) { + ENGINE_load_builtin_engines(); + loaded_engines = TRUE; + } +#endif + if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; + } + + if (strcEQ(arg, "builtin")) { + mc->szCryptoDevice = NULL; + } + else if ((e = ENGINE_by_id(arg))) { + mc->szCryptoDevice = arg; + ENGINE_free(e); + } + else { + return "SSLCryptoDevice: Invalid argument"; + } + + return NULL; +} +#endif + +const char *ssl_cmd_SSLRandomSeed(cmd_parms *cmd, + void *dcfg, + const char *arg1, + const char *arg2, + const char *arg3) +{ + SSLModConfigRec *mc = myModConfig(cmd->server); + const char *err; + ssl_randseed_t *seed; + int arg2len = strlen(arg2); + + if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; + } + + if (ssl_config_global_isfixed(mc)) { + return NULL; + } + + seed = apr_array_push(mc->aRandSeed); + + if (strcEQ(arg1, "startup")) { + seed->nCtx = SSL_RSCTX_STARTUP; + } + else if (strcEQ(arg1, "connect")) { + seed->nCtx = SSL_RSCTX_CONNECT; + } + else { + return apr_pstrcat(cmd->pool, "SSLRandomSeed: " + "invalid context: `", arg1, "'", + NULL); + } + + if ((arg2len > 5) && strEQn(arg2, "file:", 5)) { + seed->nSrc = SSL_RSSRC_FILE; + seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5); + } + else if ((arg2len > 5) && strEQn(arg2, "exec:", 5)) { + seed->nSrc = SSL_RSSRC_EXEC; + seed->cpPath = ap_server_root_relative(mc->pPool, arg2+5); + } + else if ((arg2len > 4) && strEQn(arg2, "egd:", 4)) { +#ifdef HAVE_SSL_RAND_EGD + seed->nSrc = SSL_RSSRC_EGD; + seed->cpPath = ap_server_root_relative(mc->pPool, arg2+4); +#else + return "egd not supported with this SSL toolkit"; +#endif + } + else if (strcEQ(arg2, "builtin")) { + seed->nSrc = SSL_RSSRC_BUILTIN; + seed->cpPath = NULL; + } + else { + seed->nSrc = SSL_RSSRC_FILE; + seed->cpPath = ap_server_root_relative(mc->pPool, arg2); + } + + if (seed->nSrc != SSL_RSSRC_BUILTIN) { + if (!seed->cpPath) { + return apr_pstrcat(cmd->pool, + "Invalid SSLRandomSeed path ", + arg2, NULL); + } + if (!ssl_util_path_check(SSL_PCM_EXISTS, seed->cpPath, cmd->pool)) { + return apr_pstrcat(cmd->pool, + "SSLRandomSeed: source path '", + seed->cpPath, "' does not exist", NULL); + } + } + + if (!arg3) { + seed->nBytes = 0; /* read whole file */ + } + else { + if (seed->nSrc == SSL_RSSRC_BUILTIN) { + return "SSLRandomSeed: byte specification not " + "allowed for builtin seed source"; + } + + seed->nBytes = atoi(arg3); + + if (seed->nBytes < 0) { + return "SSLRandomSeed: invalid number of bytes specified"; + } + } + + return NULL; +} + +const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, int flag) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + sc->enabled = flag ? TRUE : FALSE; + + return NULL; +} + +const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + + if (cmd->path) { + dc->szCipherSuite = arg; + } + else { + sc->server->auth.cipher_suite = arg; + } + + return NULL; +} + +#define SSL_FLAGS_CHECK_FILE \ + (SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO) + +#define SSL_FLAGS_CHECK_DIR \ + (SSL_PCM_EXISTS|SSL_PCM_ISDIR) + +static const char *ssl_cmd_check_file(cmd_parms *parms, + const char **file) +{ + const char *filepath = ap_server_root_relative(parms->pool, *file); + + if (!filepath) { + return apr_pstrcat(parms->pool, parms->cmd->name, + ": Invalid file path ", *file, NULL); + } + *file = filepath; + + if (ssl_util_path_check(SSL_FLAGS_CHECK_FILE, *file, parms->pool)) { + return NULL; + } + + return apr_pstrcat(parms->pool, parms->cmd->name, + ": file '", *file, + "' does not exist or is empty", NULL); + +} + +const char *ssl_cmd_SSLInsecureRenegotiation(cmd_parms *cmd, void *dcfg, int flag) +{ +#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + sc->insecure_reneg = flag?TRUE:FALSE; + return NULL; +#else + return "The SSLInsecureRenegotiation directive is not available " + "with this SSL library"; +#endif +} + + +static const char *ssl_cmd_check_dir(cmd_parms *parms, + const char **dir) +{ + const char *dirpath = ap_server_root_relative(parms->pool, *dir); + + if (!dirpath) { + return apr_pstrcat(parms->pool, parms->cmd->name, + ": Invalid dir path ", *dir, NULL); + } + *dir = dirpath; + + if (ssl_util_path_check(SSL_FLAGS_CHECK_DIR, *dir, parms->pool)) { + return NULL; + } + + return apr_pstrcat(parms->pool, parms->cmd->name, + ": directory '", *dir, + "' does not exist", NULL); + +} + +#define SSL_AIDX_CERTS 1 +#define SSL_AIDX_KEYS 2 + +static const char *ssl_cmd_check_aidx_max(cmd_parms *parms, + const char *arg, + int idx) +{ + SSLSrvConfigRec *sc = mySrvConfig(parms->server); + const char *err, *desc=NULL, **files=NULL; + int i; + + if ((err = ssl_cmd_check_file(parms, &arg))) { + return err; + } + + switch (idx) { + case SSL_AIDX_CERTS: + desc = "certificates"; + files = sc->server->pks->cert_files; + break; + case SSL_AIDX_KEYS: + desc = "private keys"; + files = sc->server->pks->key_files; + break; + } + + for (i = 0; i < SSL_AIDX_MAX; i++) { + if (!files[i]) { + files[i] = arg; + return NULL; + } + } + + return apr_psprintf(parms->pool, + "%s: only up to %d " + "different %s per virtual host allowed", + parms->cmd->name, SSL_AIDX_MAX, desc); +} + +const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + + const char *err; + + if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_CERTS))) { + return err; + } + + return NULL; +} + +const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + const char *err; + + if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_KEYS))) { + return err; + } + + return NULL; +} + +const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + + sc->server->cert_chain = arg; + + return NULL; +} + +#define NO_PER_DIR_SSL_CA \ + "Your ssl library does not have support for per-directory CA" + +#ifdef HAVE_SSL_SET_CERT_STORE +# define MODSSL_HAVE_SSL_SET_CERT_STORE 1 +#else +# define MODSSL_HAVE_SSL_SET_CERT_STORE 0 +#endif + +#define MODSSL_SET_CA(f) \ + if (cmd->path) \ + if (MODSSL_HAVE_SSL_SET_CERT_STORE) \ + dc->f = arg; \ + else \ + return NO_PER_DIR_SSL_CA; \ + else \ + sc->f = arg \ + +const char *ssl_cmd_SSLCACertificatePath(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + /*SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;*/ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_dir(cmd, &arg))) { + return err; + } + + /* XXX: bring back per-dir */ + sc->server->auth.ca_cert_path = arg; + + return NULL; +} + +const char *ssl_cmd_SSLCACertificateFile(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + /*SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;*/ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + + /* XXX: bring back per-dir */ + sc->server->auth.ca_cert_file = arg; + + return NULL; +} + +const char *ssl_cmd_SSLCARevocationPath(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_dir(cmd, &arg))) { + return err; + } + + sc->server->crl_path = arg; + + return NULL; +} + +const char *ssl_cmd_SSLCARevocationFile(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + + sc->server->crl_file = arg; + + return NULL; +} + +static const char *ssl_cmd_verify_parse(cmd_parms *parms, + const char *arg, + ssl_verify_t *id) +{ + if (strcEQ(arg, "none") || strcEQ(arg, "off")) { + *id = SSL_CVERIFY_NONE; + } + else if (strcEQ(arg, "optional")) { + *id = SSL_CVERIFY_OPTIONAL; + } + else if (strcEQ(arg, "require") || strcEQ(arg, "on")) { + *id = SSL_CVERIFY_REQUIRE; + } + else if (strcEQ(arg, "optional_no_ca")) { + *id = SSL_CVERIFY_OPTIONAL_NO_CA; + } + else { + return apr_pstrcat(parms->temp_pool, parms->cmd->name, + ": Invalid argument '", arg, "'", + NULL); + } + + return NULL; +} + +const char *ssl_cmd_SSLVerifyClient(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + ssl_verify_t mode; + const char *err; + + if ((err = ssl_cmd_verify_parse(cmd, arg, &mode))) { + return err; + } + + if (cmd->path) { + dc->nVerifyClient = mode; + } + else { + sc->server->auth.verify_mode = mode; + } + + return NULL; +} + +static const char *ssl_cmd_verify_depth_parse(cmd_parms *parms, + const char *arg, + int *depth) +{ + if ((*depth = atoi(arg)) >= 0) { + return NULL; + } + + return apr_pstrcat(parms->temp_pool, parms->cmd->name, + ": Invalid argument '", arg, "'", + NULL); +} + +const char *ssl_cmd_SSLVerifyDepth(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + int depth; + const char *err; + + if ((err = ssl_cmd_verify_depth_parse(cmd, arg, &depth))) { + return err; + } + + if (cmd->path) { + dc->nVerifyDepth = depth; + } + else { + sc->server->auth.verify_depth = depth; + } + + return NULL; +} + +#define MODSSL_NO_SHARED_MEMORY_ERROR \ + "SSLSessionCache: shared memory cache not useable on this platform" + +const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLModConfigRec *mc = myModConfig(cmd->server); + const char *err, *colon; + char *cp, *cp2; + int arglen = strlen(arg); + + if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { + return err; + } + + if (ssl_config_global_isfixed(mc)) { + return NULL; + } + + if (strcEQ(arg, "none")) { + mc->nSessionCacheMode = SSL_SCMODE_NONE; + mc->szSessionCacheDataFile = NULL; + } + else if ((arglen > 4) && strcEQn(arg, "dbm:", 4)) { + mc->nSessionCacheMode = SSL_SCMODE_DBM; + mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, arg+4); + if (!mc->szSessionCacheDataFile) { + return apr_psprintf(cmd->pool, + "SSLSessionCache: Invalid cache file path %s", + arg+4); + } + } + else if ((arglen > 6) && strcEQn(arg, "shmht:", 6)) { +#if !APR_HAS_SHARED_MEMORY + return MODSSL_NO_SHARED_MEMORY_ERROR; +#endif + mc->nSessionCacheMode = SSL_SCMODE_SHMHT; + colon = ap_strchr_c(arg, ':'); + mc->szSessionCacheDataFile = + ap_server_root_relative(mc->pPool, colon+1); + if (!mc->szSessionCacheDataFile) { + return apr_psprintf(cmd->pool, + "SSLSessionCache: Invalid cache file path %s", + colon+1); + } + mc->tSessionCacheDataTable = NULL; + mc->nSessionCacheDataSize = 1024*512; /* 512KB */ + + if ((cp = strchr(mc->szSessionCacheDataFile, '('))) { + *cp++ = NUL; + + if (!(cp2 = strchr(cp, ')'))) { + return "SSLSessionCache: Invalid argument: " + "no closing parenthesis"; + } + + *cp2 = NUL; + + mc->nSessionCacheDataSize = atoi(cp); + + if (mc->nSessionCacheDataSize < 8192) { + return "SSLSessionCache: Invalid argument: " + "size has to be >= 8192 bytes"; + } + + if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) { + return apr_psprintf(cmd->pool, + "SSLSessionCache: Invalid argument: " + "size has to be < %d bytes on this " + "platform", APR_SHM_MAXSIZE); + } + } + } + else if (((arglen > 4) && strcEQn(arg, "shm:", 4)) || + ((arglen > 6) && strcEQn(arg, "shmcb:", 6))) { +#if !APR_HAS_SHARED_MEMORY + return MODSSL_NO_SHARED_MEMORY_ERROR; +#endif + mc->nSessionCacheMode = SSL_SCMODE_SHMCB; + colon = ap_strchr_c(arg, ':'); + mc->szSessionCacheDataFile = + ap_server_root_relative(mc->pPool, colon+1); + if (!mc->szSessionCacheDataFile) { + return apr_psprintf(cmd->pool, + "SSLSessionCache: Invalid cache file path %s", + colon+1); + } + mc->tSessionCacheDataTable = NULL; + mc->nSessionCacheDataSize = 1024*512; /* 512KB */ + + if ((cp = strchr(mc->szSessionCacheDataFile, '('))) { + *cp++ = NUL; + + if (!(cp2 = strchr(cp, ')'))) { + return "SSLSessionCache: Invalid argument: " + "no closing parenthesis"; + } + + *cp2 = NUL; + + mc->nSessionCacheDataSize = atoi(cp); + + if (mc->nSessionCacheDataSize < 8192) { + return "SSLSessionCache: Invalid argument: " + "size has to be >= 8192 bytes"; + + } + + if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) { + return apr_psprintf(cmd->pool, + "SSLSessionCache: Invalid argument: " + "size has to be < %d bytes on this " + "platform", APR_SHM_MAXSIZE); + + } + } + } + else { + return "SSLSessionCache: Invalid argument"; + } + + return NULL; +} + +const char *ssl_cmd_SSLSessionCacheTimeout(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + sc->session_cache_timeout = atoi(arg); + + if (sc->session_cache_timeout < 0) { + return "SSLSessionCacheTimeout: Invalid argument"; + } + + return NULL; +} + +const char *ssl_cmd_SSLOptions(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + ssl_opt_t opt; + int first = TRUE; + char action, *w; + + while (*arg) { + w = ap_getword_conf(cmd->pool, &arg); + action = NUL; + + if ((*w == '+') || (*w == '-')) { + action = *(w++); + } + else if (first) { + dc->nOptions = SSL_OPT_NONE; + first = FALSE; + } + + if (strcEQ(w, "StdEnvVars")) { + opt = SSL_OPT_STDENVVARS; + } + else if (strcEQ(w, "CompatEnvVars")) { + opt = SSL_OPT_COMPATENVVARS; + } + else if (strcEQ(w, "ExportCertData")) { + opt = SSL_OPT_EXPORTCERTDATA; + } + else if (strcEQ(w, "FakeBasicAuth")) { + opt = SSL_OPT_FAKEBASICAUTH; + } + else if (strcEQ(w, "StrictRequire")) { + opt = SSL_OPT_STRICTREQUIRE; + } + else if (strcEQ(w, "OptRenegotiate")) { + opt = SSL_OPT_OPTRENEGOTIATE; + } + else { + return apr_pstrcat(cmd->pool, + "SSLOptions: Illegal option '", w, "'", + NULL); + } + + if (action == '-') { + dc->nOptionsAdd &= ~opt; + dc->nOptionsDel |= opt; + dc->nOptions &= ~opt; + } + else if (action == '+') { + dc->nOptionsAdd |= opt; + dc->nOptionsDel &= ~opt; + dc->nOptions |= opt; + } + else { + dc->nOptions = opt; + dc->nOptionsAdd = opt; + dc->nOptionsDel = SSL_OPT_NONE; + } + } + + return NULL; +} + +const char *ssl_cmd_SSLRequireSSL(cmd_parms *cmd, void *dcfg) +{ + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + + dc->bSSLRequired = TRUE; + + return NULL; +} + +const char *ssl_cmd_SSLRequire(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + ssl_expr *expr; + ssl_require_t *require; + + if (!(expr = ssl_expr_comp(cmd->pool, (char *)arg))) { + return apr_pstrcat(cmd->pool, "SSLRequire: ", + ssl_expr_get_error(), NULL); + } + + require = apr_array_push(dc->aRequirement); + require->cpExpr = apr_pstrdup(cmd->pool, arg); + require->mpExpr = expr; + + return NULL; +} + +static const char *ssl_cmd_protocol_parse(cmd_parms *parms, + const char *arg, + ssl_proto_t *options) +{ + ssl_proto_t thisopt; + + *options = SSL_PROTOCOL_NONE; + + while (*arg) { + char *w = ap_getword_conf(parms->temp_pool, &arg); + char action = '\0'; + + if ((*w == '+') || (*w == '-')) { + action = *(w++); + } + + if (strcEQ(w, "SSLv2")) { + thisopt = SSL_PROTOCOL_SSLV2; + } + else if (strcEQ(w, "SSLv3")) { + thisopt = SSL_PROTOCOL_SSLV3; + } + else if (strcEQ(w, "TLSv1")) { + thisopt = SSL_PROTOCOL_TLSV1; + } + else if (strcEQ(w, "all")) { + thisopt = SSL_PROTOCOL_ALL; + } + else { + return apr_pstrcat(parms->temp_pool, + parms->cmd->name, + ": Illegal protocol '", + w, "'", NULL); + } + + if (action == '-') { + *options &= ~thisopt; + } + else if (action == '+') { + *options |= thisopt; + } + else { + *options = thisopt; + } + } + + return NULL; +} + +const char *ssl_cmd_SSLProtocol(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + return ssl_cmd_protocol_parse(cmd, arg, &sc->server->protocol); +} + +const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + sc->proxy_enabled = flag ? TRUE : FALSE; + + return NULL; +} + +const char *ssl_cmd_SSLProxyProtocol(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + return ssl_cmd_protocol_parse(cmd, arg, &sc->proxy->protocol); +} + +const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + + sc->proxy->auth.cipher_suite = arg; + + return NULL; +} + +const char *ssl_cmd_SSLProxyVerify(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + ssl_verify_t mode; + const char *err; + + if ((err = ssl_cmd_verify_parse(cmd, arg, &mode))) { + return err; + } + + sc->proxy->auth.verify_mode = mode; + + return NULL; +} + +const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + int depth; + const char *err; + + if ((err = ssl_cmd_verify_depth_parse(cmd, arg, &depth))) { + return err; + } + + sc->proxy->auth.verify_depth = depth; + + return NULL; +} + +const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + + sc->proxy->auth.ca_cert_file = arg; + + return NULL; +} + +const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_dir(cmd, &arg))) { + return err; + } + + sc->proxy->auth.ca_cert_path = arg; + + return NULL; +} + +const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_dir(cmd, &arg))) { + return err; + } + + sc->proxy->crl_path = arg; + + return NULL; +} + +const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + + sc->proxy->crl_file = arg; + + return NULL; +} + +const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + + sc->proxy->pkp->cert_file = arg; + + return NULL; +} + +const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_dir(cmd, &arg))) { + return err; + } + + sc->proxy->pkp->cert_path = arg; + + return NULL; +} + + +const char *ssl_cmd_SSLUserName(cmd_parms *cmd, void *dcfg, + const char *arg) +{ + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + dc->szUserName = arg; + return NULL; +} diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_dh.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_dh.c new file mode 100644 index 00000000..ec66f050 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_dh.c @@ -0,0 +1,207 @@ +#if 0 +=pod +#endif +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_dh.c + * Diffie-Hellman Built-in Temporary Parameters + */ + +#include "mod_ssl.h" + +/* ----BEGIN GENERATED SECTION-------- */ + +/* +** Diffie-Hellman-Parameters: (512 bit) +** prime: +** 00:d4:bc:d5:24:06:f6:9b:35:99:4b:88:de:5d:b8: +** 96:82:c8:15:7f:62:d8:f3:36:33:ee:57:72:f1:1f: +** 05:ab:22:d6:b5:14:5b:9f:24:1e:5a:cc:31:ff:09: +** 0a:4b:c7:11:48:97:6f:76:79:50:94:e7:1e:79:03: +** 52:9f:5a:82:4b +** generator: 2 (0x2) +** Diffie-Hellman-Parameters: (1024 bit) +** prime: +** 00:e6:96:9d:3d:49:5b:e3:2c:7c:f1:80:c3:bd:d4: +** 79:8e:91:b7:81:82:51:bb:05:5e:2a:20:64:90:4a: +** 79:a7:70:fa:15:a2:59:cb:d5:23:a6:a6:ef:09:c4: +** 30:48:d5:a2:2f:97:1f:3c:20:12:9b:48:00:0e:6e: +** dd:06:1c:bc:05:3e:37:1d:79:4e:53:27:df:61:1e: +** bb:be:1b:ac:9b:5c:60:44:cf:02:3d:76:e0:5e:ea: +** 9b:ad:99:1b:13:a6:3c:97:4e:9e:f1:83:9e:b5:db: +** 12:51:36:f7:26:2e:56:a8:87:15:38:df:d8:23:c6: +** 50:50:85:e2:1f:0d:d5:c8:6b +** generator: 2 (0x2) +*/ + +static unsigned char dh512_p[] = +{ + 0xD4, 0xBC, 0xD5, 0x24, 0x06, 0xF6, 0x9B, 0x35, 0x99, 0x4B, 0x88, 0xDE, + 0x5D, 0xB8, 0x96, 0x82, 0xC8, 0x15, 0x7F, 0x62, 0xD8, 0xF3, 0x36, 0x33, + 0xEE, 0x57, 0x72, 0xF1, 0x1F, 0x05, 0xAB, 0x22, 0xD6, 0xB5, 0x14, 0x5B, + 0x9F, 0x24, 0x1E, 0x5A, 0xCC, 0x31, 0xFF, 0x09, 0x0A, 0x4B, 0xC7, 0x11, + 0x48, 0x97, 0x6F, 0x76, 0x79, 0x50, 0x94, 0xE7, 0x1E, 0x79, 0x03, 0x52, + 0x9F, 0x5A, 0x82, 0x4B, +}; +static unsigned char dh512_g[] = +{ + 0x02, +}; + +static DH *get_dh512(void) +{ + return modssl_dh_configure(dh512_p, sizeof(dh512_p), + dh512_g, sizeof(dh512_g)); +} + +static unsigned char dh1024_p[] = +{ + 0xE6, 0x96, 0x9D, 0x3D, 0x49, 0x5B, 0xE3, 0x2C, 0x7C, 0xF1, 0x80, 0xC3, + 0xBD, 0xD4, 0x79, 0x8E, 0x91, 0xB7, 0x81, 0x82, 0x51, 0xBB, 0x05, 0x5E, + 0x2A, 0x20, 0x64, 0x90, 0x4A, 0x79, 0xA7, 0x70, 0xFA, 0x15, 0xA2, 0x59, + 0xCB, 0xD5, 0x23, 0xA6, 0xA6, 0xEF, 0x09, 0xC4, 0x30, 0x48, 0xD5, 0xA2, + 0x2F, 0x97, 0x1F, 0x3C, 0x20, 0x12, 0x9B, 0x48, 0x00, 0x0E, 0x6E, 0xDD, + 0x06, 0x1C, 0xBC, 0x05, 0x3E, 0x37, 0x1D, 0x79, 0x4E, 0x53, 0x27, 0xDF, + 0x61, 0x1E, 0xBB, 0xBE, 0x1B, 0xAC, 0x9B, 0x5C, 0x60, 0x44, 0xCF, 0x02, + 0x3D, 0x76, 0xE0, 0x5E, 0xEA, 0x9B, 0xAD, 0x99, 0x1B, 0x13, 0xA6, 0x3C, + 0x97, 0x4E, 0x9E, 0xF1, 0x83, 0x9E, 0xB5, 0xDB, 0x12, 0x51, 0x36, 0xF7, + 0x26, 0x2E, 0x56, 0xA8, 0x87, 0x15, 0x38, 0xDF, 0xD8, 0x23, 0xC6, 0x50, + 0x50, 0x85, 0xE2, 0x1F, 0x0D, 0xD5, 0xC8, 0x6B, +}; +static unsigned char dh1024_g[] = +{ + 0x02, +}; + +static DH *get_dh1024(void) +{ + return modssl_dh_configure(dh1024_p, sizeof(dh1024_p), + dh1024_g, sizeof(dh1024_g)); +} +/* ----END GENERATED SECTION---------- */ + +DH *ssl_dh_GetTmpParam(int nKeyLen) +{ + DH *dh; + + if (nKeyLen == 512) + dh = get_dh512(); + else if (nKeyLen == 1024) + dh = get_dh1024(); + else + dh = get_dh1024(); + return dh; +} + +DH *ssl_dh_GetParamFromFile(char *file) +{ + DH *dh = NULL; + BIO *bio; + + if ((bio = BIO_new_file(file, "r")) == NULL) + return NULL; +#if SSL_LIBRARY_VERSION < 0x00904000 + dh = PEM_read_bio_DHparams(bio, NULL, NULL); +#else + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); +#endif + BIO_free(bio); + return (dh); +} + +/* +=cut +## +## Embedded Perl script for generating the temporary DH parameters +## + +require 5.003; +use strict; + +# configuration +my $file = $0; +my $begin = '----BEGIN GENERATED SECTION--------'; +my $end = '----END GENERATED SECTION----------'; + +# read ourself and keep a backup +open(FP, "<$file") || die; +my $source = ''; +$source .= $_ while (<FP>); +close(FP); +open(FP, ">$file.bak") || die; +print FP $source; +close(FP); + +# generate the DH parameters +print "1. Generate 512 and 1024 bit Diffie-Hellman parameters (p, g)\n"; +my $rand = ''; +foreach $file (qw(/var/log/messages /var/adm/messages + /kernel /vmunix /vmlinuz /etc/hosts /etc/resolv.conf)) { + if (-f $file) { + $rand = $file if ($rand eq ''); + $rand .= ":$file" if ($rand ne ''); + } +} +$rand = "-rand $rand" if ($rand ne ''); +system("openssl gendh $rand -out dh512.pem 512"); +system("openssl gendh $rand -out dh1024.pem 1024"); + +# generate DH param info +my $dhinfo = ''; +open(FP, "openssl dh -noout -text -in dh512.pem |") || die; +$dhinfo .= $_ while (<FP>); +close(FP); +open(FP, "openssl dh -noout -text -in dh1024.pem |") || die; +$dhinfo .= $_ while (<FP>); +close(FP); +$dhinfo =~ s|^|** |mg; +$dhinfo = "\n\/\*\n$dhinfo\*\/\n\n"; + +# generate C source from DH params +my $dhsource = ''; +open(FP, "openssl dh -noout -C -in dh512.pem | indent | expand |") || die; +$dhsource .= $_ while (<FP>); +close(FP); +open(FP, "openssl dh -noout -C -in dh1024.pem | indent | expand |") || die; +$dhsource .= $_ while (<FP>); +close(FP); +$dhsource =~ s|(DH\s+\*get_dh)|static $1|sg; + +# generate output +my $o = $dhinfo . $dhsource; + +# insert the generated code at the target location +$source =~ s|(\/\* $begin.+?\n).*\n(.*?\/\* $end)|$1$o$2|s; + +# and update the source on disk +print "Updating file `$file'\n"; +open(FP, ">$file") || die; +print FP $source; +close(FP); + +# cleanup +unlink("dh512.pem"); +unlink("dh1024.pem"); + +=pod +*/ diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_init.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_init.c new file mode 100644 index 00000000..92c3395d --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_init.c @@ -0,0 +1,1243 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_init.c + * Initialization of Servers + */ + /* ``Recursive, adj.; + see Recursive.'' + -- Unknown */ +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** Module Initialization +** _________________________________________________________________ +*/ + + +static void ssl_add_version_components(apr_pool_t *p, + server_rec *s) +{ + char *modver = ssl_var_lookup(p, s, NULL, NULL, "SSL_VERSION_INTERFACE"); + char *libver = ssl_var_lookup(p, s, NULL, NULL, "SSL_VERSION_LIBRARY"); + char *incver = ssl_var_lookup(p, s, NULL, NULL, + "SSL_VERSION_LIBRARY_INTERFACE"); + + ap_add_version_component(p, modver); + ap_add_version_component(p, libver); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "%s compiled against Server: %s, Library: %s", + modver, AP_SERVER_BASEVERSION, incver); +} + + +/* + * Initialize SSL library + */ +static void ssl_init_SSLLibrary(server_rec *s) +{ + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Init: Initializing %s library", SSL_LIBRARY_NAME); + + SSL_load_error_strings(); + SSL_library_init(); + OpenSSL_add_all_algorithms(); /* Required for eg SHA256 client certs */ +} + +/* + * Handle the Temporary RSA Keys and DH Params + */ + +#define MODSSL_TMP_KEY_FREE(mc, type, idx) \ + if (mc->pTmpKeys[idx]) { \ + type##_free((type *)mc->pTmpKeys[idx]); \ + mc->pTmpKeys[idx] = NULL; \ + } + +#define MODSSL_TMP_KEYS_FREE(mc, type) \ + MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_512); \ + MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_1024) + +static void ssl_tmp_keys_free(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + + MODSSL_TMP_KEYS_FREE(mc, RSA); + MODSSL_TMP_KEYS_FREE(mc, DH); +} + +static int ssl_tmp_key_init_rsa(server_rec *s, + int bits, int idx) +{ + SSLModConfigRec *mc = myModConfig(s); + + if (!(mc->pTmpKeys[idx] = + RSA_generate_key(bits, RSA_F4, NULL, NULL))) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Failed to generate temporary " + "%d bit RSA private key", bits); + return !OK; + } + + return OK; +} + +static int ssl_tmp_key_init_dh(server_rec *s, + int bits, int idx) +{ + SSLModConfigRec *mc = myModConfig(s); + + if (!(mc->pTmpKeys[idx] = + ssl_dh_GetTmpParam(bits))) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Failed to generate temporary " + "%d bit DH parameters", bits); + return !OK; + } + + return OK; +} + +#define MODSSL_TMP_KEY_INIT_RSA(s, bits) \ + ssl_tmp_key_init_rsa(s, bits, SSL_TMP_KEY_RSA_##bits) + +#define MODSSL_TMP_KEY_INIT_DH(s, bits) \ + ssl_tmp_key_init_dh(s, bits, SSL_TMP_KEY_DH_##bits) + +static int ssl_tmp_keys_init(server_rec *s) +{ + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Init: Generating temporary RSA private keys (512/1024 bits)"); + + if (MODSSL_TMP_KEY_INIT_RSA(s, 512) || + MODSSL_TMP_KEY_INIT_RSA(s, 1024)) { + return !OK; + } + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Init: Generating temporary DH parameters (512/1024 bits)"); + + if (MODSSL_TMP_KEY_INIT_DH(s, 512) || + MODSSL_TMP_KEY_INIT_DH(s, 1024)) { + return !OK; + } + + return OK; +} + +/* + * Per-module initialization + */ +int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, + server_rec *base_server) +{ + SSLModConfigRec *mc = myModConfig(base_server); + SSLSrvConfigRec *sc; + server_rec *s; + + /* + * Let us cleanup on restarts and exists + */ + apr_pool_cleanup_register(p, base_server, + ssl_init_ModuleKill, + apr_pool_cleanup_null); + + /* + * Any init round fixes the global config + */ + ssl_config_global_create(base_server); /* just to avoid problems */ + ssl_config_global_fix(mc); + + /* + * try to fix the configuration and open the dedicated SSL + * logfile as early as possible + */ + for (s = base_server; s; s = s->next) { + sc = mySrvConfig(s); + + if (sc->server) { + sc->server->sc = sc; + } + + if (sc->proxy) { + sc->proxy->sc = sc; + } + + /* + * Create the server host:port string because we need it a lot + */ + sc->vhost_id = ssl_util_vhostid(p, s); + sc->vhost_id_len = strlen(sc->vhost_id); + + /* Fix up stuff that may not have been set */ + if (sc->enabled == UNSET) { + sc->enabled = FALSE; + } + + if (sc->proxy_enabled == UNSET) { + sc->proxy_enabled = FALSE; + } + + if (sc->session_cache_timeout == UNSET) { + sc->session_cache_timeout = SSL_SESSION_CACHE_TIMEOUT; + } + + if (sc->server->pphrase_dialog_type == SSL_PPTYPE_UNSET) { + sc->server->pphrase_dialog_type = SSL_PPTYPE_BUILTIN; + } + + } + +#if APR_HAS_THREADS + ssl_util_thread_setup(p); +#endif + + /* + * SSL external crypto device ("engine") support + */ +#ifdef SSL_EXPERIMENTAL_ENGINE + ssl_init_Engine(base_server, p); +#endif + + ssl_init_SSLLibrary(base_server); + + /* + * Seed the Pseudo Random Number Generator (PRNG) + * only need ptemp here; nothing inside allocated from the pool + * needs to live once we return from ssl_rand_seed(). + */ + ssl_rand_seed(base_server, ptemp, SSL_RSCTX_STARTUP, "Init: "); + + /* + * read server private keys/public certs into memory. + * decrypting any encrypted keys via configured SSLPassPhraseDialogs + * anything that needs to live longer than ptemp needs to also survive + * restarts, in which case they'll live inside s->process->pool. + */ + ssl_pphrase_Handle(base_server, ptemp); + + if (ssl_tmp_keys_init(base_server)) { + return !OK; + } + + /* + * initialize the mutex handling + */ + if (!ssl_mutex_init(base_server, p)) { + return HTTP_INTERNAL_SERVER_ERROR; + } + + /* + * initialize session caching + */ + ssl_scache_init(base_server, p); + + /* + * initialize servers + */ + ap_log_error(APLOG_MARK, APLOG_INFO, 0, base_server, + "Init: Initializing (virtual) servers for SSL"); + + for (s = base_server; s; s = s->next) { + sc = mySrvConfig(s); + /* + * Either now skip this server when SSL is disabled for + * it or give out some information about what we're + * configuring. + */ + + /* + * Read the server certificate and key + */ + ssl_init_ConfigureServer(s, p, ptemp, sc); + } + + /* + * Configuration consistency checks + */ + ssl_init_CheckServers(base_server, ptemp); + + /* + * Announce mod_ssl and SSL library in HTTP Server field + * as ``mod_ssl/X.X.X OpenSSL/X.X.X'' + */ + ssl_add_version_components(p, base_server); + + SSL_init_app_data2_idx(); /* for SSL_get_app_data2() at request time */ + + return OK; +} + +/* + * Support for external a Crypto Device ("engine"), usually + * a hardware accellerator card for crypto operations. + */ +#ifdef SSL_EXPERIMENTAL_ENGINE +void ssl_init_Engine(server_rec *s, apr_pool_t *p) +{ + SSLModConfigRec *mc = myModConfig(s); + ENGINE *e; + + if (mc->szCryptoDevice) { + if (!(e = ENGINE_by_id(mc->szCryptoDevice))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Failed to load Crypto Device API `%s'", + mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + + if (strEQ(mc->szCryptoDevice, "chil")) { + ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0); + } + + if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Failed to enable Crypto Device API `%s'", + mc->szCryptoDevice); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + + ENGINE_free(e); + } +} +#endif + +static void ssl_init_server_check(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + /* + * check for important parameters and the + * possibility that the user forgot to set them. + */ + if (!mctx->pks->cert_files[0]) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "No SSL Certificate set [hint: SSLCertificateFile]"); + ssl_die(); + } + + /* + * Check for problematic re-initializations + */ + if (mctx->pks->certs[SSL_AIDX_RSA] || + mctx->pks->certs[SSL_AIDX_DSA]) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Illegal attempt to re-initialise SSL for server " + "(theoretically shouldn't happen!)"); + ssl_die(); + } +} + +static void ssl_init_ctx_protocol(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + SSL_CTX *ctx = NULL; + SSL_METHOD *method = NULL; + char *cp; + int protocol = mctx->protocol; + SSLSrvConfigRec *sc = mySrvConfig(s); + + /* + * Create the new per-server SSL context + */ + if (protocol == SSL_PROTOCOL_NONE) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "No SSL protocols available [hint: SSLProtocol]"); + ssl_die(); + } + + cp = apr_pstrcat(p, + (protocol & SSL_PROTOCOL_SSLV2 ? "SSLv2, " : ""), + (protocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""), + (protocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : ""), + NULL); + cp[strlen(cp)-2] = NUL; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Creating new SSL context (protocols: %s)", cp); + + if (protocol == SSL_PROTOCOL_SSLV2) { + method = mctx->pkp ? + SSLv2_client_method() : /* proxy */ + SSLv2_server_method(); /* server */ + ctx = SSL_CTX_new(method); /* only SSLv2 is left */ + } + else { + method = mctx->pkp ? + SSLv23_client_method() : /* proxy */ + SSLv23_server_method(); /* server */ + ctx = SSL_CTX_new(method); /* be more flexible */ + } + + mctx->ssl_ctx = ctx; + + SSL_CTX_set_options(ctx, SSL_OP_ALL); + + if (!(protocol & SSL_PROTOCOL_SSLV2)) { + SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); + } + + if (!(protocol & SSL_PROTOCOL_SSLV3)) { + SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3); + } + + if (!(protocol & SSL_PROTOCOL_TLSV1)) { + SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1); + } + +#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION + if (sc->insecure_reneg == TRUE) { + SSL_CTX_set_options(ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); + } +#endif + + SSL_CTX_set_app_data(ctx, s); + + /* + * Configure additional context ingredients + */ + SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); + +#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + /* + * Disallow a session from being resumed during a renegotiation, + * so that an acceptable cipher suite can be negotiated. + */ + SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); +#endif +} + +static void ssl_init_ctx_session_cache(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + SSL_CTX *ctx = mctx->ssl_ctx; + SSLModConfigRec *mc = myModConfig(s); + long cache_mode = SSL_SESS_CACHE_OFF; + + if (mc->nSessionCacheMode != SSL_SCMODE_NONE) { + /* SSL_SESS_CACHE_NO_INTERNAL will force OpenSSL + * to ignore process local-caching and + * to always get/set/delete sessions using mod_ssl's callbacks. + */ + cache_mode = SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL; + } + + SSL_CTX_set_session_cache_mode(ctx, cache_mode); + + SSL_CTX_sess_set_new_cb(ctx, ssl_callback_NewSessionCacheEntry); + SSL_CTX_sess_set_get_cb(ctx, ssl_callback_GetSessionCacheEntry); + SSL_CTX_sess_set_remove_cb(ctx, ssl_callback_DelSessionCacheEntry); +} + +static void ssl_init_ctx_callbacks(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + SSL_CTX *ctx = mctx->ssl_ctx; + + SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA); + SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); + + SSL_CTX_set_info_callback(ctx, ssl_callback_Info); +} + +static void ssl_init_ctx_verify(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + SSL_CTX *ctx = mctx->ssl_ctx; + + int verify = SSL_VERIFY_NONE; + STACK_OF(X509_NAME) *ca_list; + + if (mctx->auth.verify_mode == SSL_CVERIFY_UNSET) { + mctx->auth.verify_mode = SSL_CVERIFY_NONE; + } + + if (mctx->auth.verify_depth == UNSET) { + mctx->auth.verify_depth = 1; + } + + /* + * Configure callbacks for SSL context + */ + if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) { + verify |= SSL_VERIFY_PEER_STRICT; + } + + if ((mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL) || + (mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA)) + { + verify |= SSL_VERIFY_PEER; + } + + SSL_CTX_set_verify(ctx, verify, ssl_callback_SSLVerify); + + /* + * Configure Client Authentication details + */ + if (mctx->auth.ca_cert_file || mctx->auth.ca_cert_path) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Configuring client authentication"); + + if (!SSL_CTX_load_verify_locations(ctx, + MODSSL_PCHAR_CAST mctx->auth.ca_cert_file, + MODSSL_PCHAR_CAST mctx->auth.ca_cert_path)) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to configure verify locations " + "for client authentication"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + + ca_list = ssl_init_FindCAList(s, ptemp, + mctx->auth.ca_cert_file, + mctx->auth.ca_cert_path); + if (!ca_list) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to determine list of available " + "CA certificates for client authentication"); + ssl_die(); + } + + SSL_CTX_set_client_CA_list(ctx, (STACK *)ca_list); + } + + /* + * Give a warning when no CAs were configured but client authentication + * should take place. This cannot work. + */ + if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) { + ca_list = (STACK_OF(X509_NAME) *)SSL_CTX_get_client_CA_list(ctx); + + if (sk_X509_NAME_num(ca_list) == 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "Init: Oops, you want to request client " + "authentication, but no CAs are known for " + "verification!? [Hint: SSLCACertificate*]"); + } + } +} + +static void ssl_init_ctx_cipher_suite(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + SSL_CTX *ctx = mctx->ssl_ctx; + const char *suite = mctx->auth.cipher_suite; + + /* + * Configure SSL Cipher Suite + */ + if (!suite) { + return; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Configuring permitted SSL ciphers [%s]", + suite); + + if (!SSL_CTX_set_cipher_list(ctx, MODSSL_PCHAR_CAST suite)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to configure permitted SSL ciphers"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } +} + +static void ssl_init_ctx_crl(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + /* + * Configure Certificate Revocation List (CRL) Details + */ + + if (!(mctx->crl_file || mctx->crl_path)) { + return; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Configuring certificate revocation facility"); + + mctx->crl = + SSL_X509_STORE_create((char *)mctx->crl_file, + (char *)mctx->crl_path); + + if (!mctx->crl) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to configure X.509 CRL storage " + "for certificate revocation"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } +} + +static void ssl_init_ctx_cert_chain(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + BOOL skip_first = FALSE; + int i, n; + const char *chain = mctx->cert_chain; + + /* + * Optionally configure extra server certificate chain certificates. + * This is usually done by OpenSSL automatically when one of the + * server cert issuers are found under SSLCACertificatePath or in + * SSLCACertificateFile. But because these are intended for client + * authentication it can conflict. For instance when you use a + * Global ID server certificate you've to send out the intermediate + * CA certificate, too. When you would just configure this with + * SSLCACertificateFile and also use client authentication mod_ssl + * would accept all clients also issued by this CA. Obviously this + * isn't what we want in this situation. So this feature here exists + * to allow one to explicity configure CA certificates which are + * used only for the server certificate chain. + */ + if (!chain) { + return; + } + + for (i = 0; (i < SSL_AIDX_MAX) && mctx->pks->cert_files[i]; i++) { + if (strEQ(mctx->pks->cert_files[i], chain)) { + skip_first = TRUE; + break; + } + } + + n = SSL_CTX_use_certificate_chain(mctx->ssl_ctx, + (char *)chain, + skip_first, NULL); + if (n < 0) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Failed to configure CA certificate chain!"); + ssl_die(); + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Configuring server certificate chain " + "(%d CA certificate%s)", + n, n == 1 ? "" : "s"); +} + +static void ssl_init_ctx(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + ssl_init_ctx_protocol(s, p, ptemp, mctx); + + ssl_init_ctx_session_cache(s, p, ptemp, mctx); + + ssl_init_ctx_callbacks(s, p, ptemp, mctx); + + ssl_init_ctx_verify(s, p, ptemp, mctx); + + ssl_init_ctx_cipher_suite(s, p, ptemp, mctx); + + ssl_init_ctx_crl(s, p, ptemp, mctx); + + if (mctx->pks) { + /* XXX: proxy support? */ + ssl_init_ctx_cert_chain(s, p, ptemp, mctx); + } +} + +static int ssl_server_import_cert(server_rec *s, + modssl_ctx_t *mctx, + const char *id, + int idx) +{ + SSLModConfigRec *mc = myModConfig(s); + ssl_asn1_t *asn1; + MODSSL_D2I_X509_CONST unsigned char *ptr; + const char *type = ssl_asn1_keystr(idx); + X509 *cert; + + if (!(asn1 = ssl_asn1_table_get(mc->tPublicCert, id))) { + return FALSE; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Configuring %s server certificate", type); + + ptr = asn1->cpData; + if (!(cert = d2i_X509(NULL, &ptr, asn1->nData))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to import %s server certificate", type); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + + if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) <= 0) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to configure %s server certificate", type); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + + mctx->pks->certs[idx] = cert; + + return TRUE; +} + +static int ssl_server_import_key(server_rec *s, + modssl_ctx_t *mctx, + const char *id, + int idx) +{ + SSLModConfigRec *mc = myModConfig(s); + ssl_asn1_t *asn1; + MODSSL_D2I_PrivateKey_CONST unsigned char *ptr; + const char *type = ssl_asn1_keystr(idx); + int pkey_type = (idx == SSL_AIDX_RSA) ? EVP_PKEY_RSA : EVP_PKEY_DSA; + EVP_PKEY *pkey; + + if (!(asn1 = ssl_asn1_table_get(mc->tPrivateKey, id))) { + return FALSE; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Configuring %s server private key", type); + + ptr = asn1->cpData; + if (!(pkey = d2i_PrivateKey(pkey_type, NULL, &ptr, asn1->nData))) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to import %s server private key", type); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + + if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) <= 0) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Unable to configure %s server private key", type); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + + /* + * XXX: wonder if this is still needed, this is old todo doc. + * (see http://www.psy.uq.edu.au/~ftp/Crypto/ssleay/TODO.html) + */ + if ((pkey_type == EVP_PKEY_DSA) && mctx->pks->certs[idx]) { + EVP_PKEY *pubkey = X509_get_pubkey(mctx->pks->certs[idx]); + + if (pubkey && EVP_PKEY_missing_parameters(pubkey)) { + EVP_PKEY_copy_parameters(pubkey, pkey); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Copying DSA parameters from private key to certificate"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + EVP_PKEY_free(pubkey); + } + } + + mctx->pks->keys[idx] = pkey; + + return TRUE; +} + +static void ssl_check_public_cert(server_rec *s, + apr_pool_t *ptemp, + X509 *cert, + int type) +{ + int is_ca, pathlen; + char *cn; + + if (!cert) { + return; + } + + /* + * Some information about the certificate(s) + */ + + if (SSL_X509_isSGC(cert)) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "%s server certificate enables " + "Server Gated Cryptography (SGC)", + ssl_asn1_keystr(type)); + } + + if (SSL_X509_getBC(cert, &is_ca, &pathlen)) { + if (is_ca) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "%s server certificate is a CA certificate " + "(BasicConstraints: CA == TRUE !?)", + ssl_asn1_keystr(type)); + } + + if (pathlen > 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "%s server certificate is not a leaf certificate " + "(BasicConstraints: pathlen == %d > 0 !?)", + ssl_asn1_keystr(type), pathlen); + } + } + + if (SSL_X509_getCN(ptemp, cert, &cn)) { + int fnm_flags = FNM_PERIOD|FNM_CASE_BLIND; + + if (apr_fnmatch_test(cn) && + (apr_fnmatch(cn, s->server_hostname, + fnm_flags) == FNM_NOMATCH)) + { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "%s server certificate wildcard CommonName (CN) `%s' " + "does NOT match server name!?", + ssl_asn1_keystr(type), cn); + } + else if (strNE(s->server_hostname, cn)) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "%s server certificate CommonName (CN) `%s' " + "does NOT match server name!?", + ssl_asn1_keystr(type), cn); + } + } +} + +static void ssl_init_server_certs(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + const char *rsa_id, *dsa_id; + const char *vhost_id = mctx->sc->vhost_id; + int i; + int have_rsa, have_dsa; + + rsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_RSA); + dsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_DSA); + + have_rsa = ssl_server_import_cert(s, mctx, rsa_id, SSL_AIDX_RSA); + have_dsa = ssl_server_import_cert(s, mctx, dsa_id, SSL_AIDX_DSA); + + if (!(have_rsa || have_dsa)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Oops, no RSA or DSA server certificate found?!"); + ssl_die(); + } + + for (i = 0; i < SSL_AIDX_MAX; i++) { + ssl_check_public_cert(s, ptemp, mctx->pks->certs[i], i); + } + + have_rsa = ssl_server_import_key(s, mctx, rsa_id, SSL_AIDX_RSA); + have_dsa = ssl_server_import_key(s, mctx, dsa_id, SSL_AIDX_DSA); + + if (!(have_rsa || have_dsa)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Oops, no RSA or DSA server private key found?!"); + ssl_die(); + } +} + +static void ssl_init_proxy_certs(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + int n, ncerts = 0; + STACK_OF(X509_INFO) *sk; + modssl_pk_proxy_t *pkp = mctx->pkp; + + SSL_CTX_set_client_cert_cb(mctx->ssl_ctx, + ssl_callback_proxy_cert); + + if (!(pkp->cert_file || pkp->cert_path)) { + return; + } + + sk = sk_X509_INFO_new_null(); + + if (pkp->cert_file) { + SSL_X509_INFO_load_file(ptemp, sk, pkp->cert_file); + } + + if (pkp->cert_path) { + SSL_X509_INFO_load_path(ptemp, sk, pkp->cert_path); + } + + if ((ncerts = sk_X509_INFO_num(sk)) <= 0) { + sk_X509_INFO_free(sk); + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "no client certs found for SSL proxy"); + return; + } + + /* Check that all client certs have got certificates and private + * keys. */ + for (n = 0; n < ncerts; n++) { + X509_INFO *inf = sk_X509_INFO_value(sk, n); + + if (!inf->x509 || !inf->x_pkey) { + sk_X509_INFO_free(sk); + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, + "incomplete client cert configured for SSL proxy " + "(missing or encrypted private key?)"); + ssl_die(); + return; + } + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "loaded %d client certs for SSL proxy", + ncerts); + pkp->certs = sk; +} + +static void ssl_init_proxy_ctx(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + SSLSrvConfigRec *sc) +{ + ssl_init_ctx(s, p, ptemp, sc->proxy); + + ssl_init_proxy_certs(s, p, ptemp, sc->proxy); +} + +static void ssl_init_server_ctx(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + SSLSrvConfigRec *sc) +{ + ssl_init_server_check(s, p, ptemp, sc->server); + + ssl_init_ctx(s, p, ptemp, sc->server); + + ssl_init_server_certs(s, p, ptemp, sc->server); +} + +/* + * Configure a particular server + */ +void ssl_init_ConfigureServer(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + SSLSrvConfigRec *sc) +{ + if (sc->enabled) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Configuring server for SSL protocol"); + ssl_init_server_ctx(s, p, ptemp, sc); + } + + if (sc->proxy_enabled) { + ssl_init_proxy_ctx(s, p, ptemp, sc); + } +} + +void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) +{ + server_rec *s, *ps; + SSLSrvConfigRec *sc; + apr_hash_t *table; + const char *key; + apr_ssize_t klen; + + BOOL conflict = FALSE; + + /* + * Give out warnings when a server has HTTPS configured + * for the HTTP port or vice versa + */ + for (s = base_server; s; s = s->next) { + sc = mySrvConfig(s); + + if (sc->enabled && (s->port == DEFAULT_HTTP_PORT)) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, + base_server, + "Init: (%s) You configured HTTPS(%d) " + "on the standard HTTP(%d) port!", + ssl_util_vhostid(p, s), + DEFAULT_HTTPS_PORT, DEFAULT_HTTP_PORT); + } + + if (!sc->enabled && (s->port == DEFAULT_HTTPS_PORT)) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, + base_server, + "Init: (%s) You configured HTTP(%d) " + "on the standard HTTPS(%d) port!", + ssl_util_vhostid(p, s), + DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT); + } + } + + /* + * Give out warnings when more than one SSL-aware virtual server uses the + * same IP:port. This doesn't work because mod_ssl then will always use + * just the certificate/keys of one virtual host (which one cannot be said + * easily - but that doesn't matter here). + */ + table = apr_hash_make(p); + + for (s = base_server; s; s = s->next) { + sc = mySrvConfig(s); + + if (!(sc->enabled && s->addrs)) { + continue; + } + + key = apr_psprintf(p, "%pA:%u", + &s->addrs->host_addr, s->addrs->host_port); + klen = strlen(key); + + if ((ps = (server_rec *)apr_hash_get(table, key, klen))) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, + base_server, + "Init: SSL server IP/port conflict: " + "%s (%s:%d) vs. %s (%s:%d)", + ssl_util_vhostid(p, s), + (s->defn_name ? s->defn_name : "unknown"), + s->defn_line_number, + ssl_util_vhostid(p, ps), + (ps->defn_name ? ps->defn_name : "unknown"), + ps->defn_line_number); + conflict = TRUE; + continue; + } + + apr_hash_set(table, key, klen, s); + } + + if (conflict) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, + "Init: You should not use name-based " + "virtual hosts in conjunction with SSL!!"); + } +} + +#ifdef SSLC_VERSION_NUMBER +static int ssl_init_FindCAList_X509NameCmp(char **a, char **b) +{ + return(X509_NAME_cmp((void*)*a, (void*)*b)); +} +#else +static int ssl_init_FindCAList_X509NameCmp(X509_NAME **a, X509_NAME **b) +{ + return(X509_NAME_cmp(*a, *b)); +} +#endif + +static void ssl_init_PushCAList(STACK_OF(X509_NAME) *ca_list, + server_rec *s, const char *file) +{ + int n; + STACK_OF(X509_NAME) *sk; + + sk = (STACK_OF(X509_NAME) *) + SSL_load_client_CA_file(MODSSL_PCHAR_CAST file); + + if (!sk) { + return; + } + + for (n = 0; n < sk_X509_NAME_num(sk); n++) { + char name_buf[256]; + X509_NAME *name = sk_X509_NAME_value(sk, n); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "CA certificate: %s", + X509_NAME_oneline(name, name_buf, sizeof(name_buf))); + + /* + * note that SSL_load_client_CA_file() checks for duplicates, + * but since we call it multiple times when reading a directory + * we must also check for duplicates ourselves. + */ + + if (sk_X509_NAME_find(ca_list, name) < 0) { + /* this will be freed when ca_list is */ + sk_X509_NAME_push(ca_list, name); + } + else { + /* need to free this ourselves, else it will leak */ + X509_NAME_free(name); + } + } + + sk_X509_NAME_free(sk); +} + +STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, + apr_pool_t *ptemp, + const char *ca_file, + const char *ca_path) +{ + STACK_OF(X509_NAME) *ca_list; + + /* + * Start with a empty stack/list where new + * entries get added in sorted order. + */ + ca_list = sk_X509_NAME_new(ssl_init_FindCAList_X509NameCmp); + + /* + * Process CA certificate bundle file + */ + if (ca_file) { + ssl_init_PushCAList(ca_list, s, ca_file); + } + + /* + * Process CA certificate path files + */ + if (ca_path) { + apr_dir_t *dir; + apr_finfo_t direntry; + apr_int32_t finfo_flags = APR_FINFO_TYPE|APR_FINFO_NAME; + apr_status_t rv; + + if ((rv = apr_dir_open(&dir, ca_path, ptemp)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Failed to open SSLCACertificatePath `%s'", + ca_path); + ssl_die(); + } + + while ((apr_dir_read(&direntry, finfo_flags, dir)) == APR_SUCCESS) { + const char *file; + if (direntry.filetype == APR_DIR) { + continue; /* don't try to load directories */ + } + file = apr_pstrcat(ptemp, ca_path, "/", direntry.name, NULL); + ssl_init_PushCAList(ca_list, s, file); + } + + apr_dir_close(dir); + } + + /* + * Cleanup + */ + sk_X509_NAME_set_cmp_func(ca_list, NULL); + + return ca_list; +} + +void ssl_init_Child(apr_pool_t *p, server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + mc->pid = getpid(); /* only call getpid() once per-process */ + + /* XXX: there should be an ap_srand() function */ + srand((unsigned int)time(NULL)); + + /* open the mutex lockfile */ + ssl_mutex_reinit(s, p); +} + +#define MODSSL_CFG_ITEM_FREE(func, item) \ + if (item) { \ + func(item); \ + item = NULL; \ + } + +static void ssl_init_ctx_cleanup(modssl_ctx_t *mctx) +{ + MODSSL_CFG_ITEM_FREE(X509_STORE_free, mctx->crl); + + MODSSL_CFG_ITEM_FREE(SSL_CTX_free, mctx->ssl_ctx); +} + +static void ssl_init_ctx_cleanup_proxy(modssl_ctx_t *mctx) +{ + ssl_init_ctx_cleanup(mctx); + + if (mctx->pkp->certs) { + sk_X509_INFO_pop_free(mctx->pkp->certs, X509_INFO_free); + } +} + +static void ssl_init_ctx_cleanup_server(modssl_ctx_t *mctx) +{ + int i; + + ssl_init_ctx_cleanup(mctx); + + for (i=0; i < SSL_AIDX_MAX; i++) { + MODSSL_CFG_ITEM_FREE(X509_free, + mctx->pks->certs[i]); + + MODSSL_CFG_ITEM_FREE(EVP_PKEY_free, + mctx->pks->keys[i]); + } +} + +apr_status_t ssl_init_ModuleKill(void *data) +{ + SSLSrvConfigRec *sc; + server_rec *base_server = (server_rec *)data; + server_rec *s; + + /* + * Drop the session cache and mutex + */ + ssl_scache_kill(base_server); + + /* + * Destroy the temporary keys and params + */ + ssl_tmp_keys_free(base_server); + + /* + * Free the non-pool allocated structures + * in the per-server configurations + */ + for (s = base_server; s; s = s->next) { + sc = mySrvConfig(s); + + ssl_init_ctx_cleanup_proxy(sc->proxy); + + ssl_init_ctx_cleanup_server(sc->server); + } + + /* + * Try to kill the internals of the SSL library. + */ + ERR_remove_state(0); + EVP_cleanup(); + + return APR_SUCCESS; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c new file mode 100644 index 00000000..c5fe6b8c --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c @@ -0,0 +1,1746 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_io.c + * I/O Functions + */ + /* ``MY HACK: This universe. + Just one little problem: + core keeps dumping.'' + -- Unknown */ +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** I/O Hooks +** _________________________________________________________________ +*/ + +/* This file is designed to be the bridge between OpenSSL and httpd. + * However, we really don't expect anyone (let alone ourselves) to + * remember what is in this file. So, first, a quick overview. + * + * In this file, you will find: + * - ssl_io_filter_input (Apache input filter) + * - ssl_io_filter_output (Apache output filter) + * + * - bio_filter_in_* (OpenSSL input filter) + * - bio_filter_out_* (OpenSSL output filter) + * + * The input chain is roughly: + * + * ssl_io_filter_input->ssl_io_input_read->SSL_read->... + * ...->bio_filter_in_read->ap_get_brigade/next-httpd-filter + * + * In mortal terminology, we do the following: + * - Receive a request for data to the SSL input filter + * - Call a helper function once we know we should perform a read + * - Call OpenSSL's SSL_read() + * - SSL_read() will then call bio_filter_in_read + * - bio_filter_in_read will then try to fetch data from the next httpd filter + * - bio_filter_in_read will flatten that data and return it to SSL_read + * - SSL_read will then decrypt the data + * - ssl_io_input_read will then receive decrypted data as a char* and + * ensure that there were no read errors + * - The char* is placed in a brigade and returned + * + * Since connection-level input filters in httpd need to be able to + * handle AP_MODE_GETLINE calls (namely identifying LF-terminated strings), + * ssl_io_input_getline which will handle this special case. + * + * Due to AP_MODE_GETLINE and AP_MODE_SPECULATIVE, we may sometimes have + * 'leftover' decoded data which must be setaside for the next read. That + * is currently handled by the char_buffer_{read|write} functions. So, + * ssl_io_input_read may be able to fulfill reads without invoking + * SSL_read(). + * + * Note that the filter context of ssl_io_filter_input and bio_filter_in_* + * are shared as bio_filter_in_ctx_t. + * + * Note that the filter is by choice limited to reading at most + * AP_IOBUFSIZE (8192 bytes) per call. + * + */ + +/* this custom BIO allows us to hook SSL_write directly into + * an apr_bucket_brigade and use transient buckets with the SSL + * malloc-ed buffer, rather than copying into a mem BIO. + * also allows us to pass the brigade as data is being written + * rather than buffering up the entire response in the mem BIO. + * + * when SSL needs to flush (e.g. SSL_accept()), it will call BIO_flush() + * which will trigger a call to bio_filter_out_ctrl() -> bio_filter_out_flush(). + * so we only need to flush the output ourselves if we receive an + * EOS or FLUSH bucket. this was not possible with the mem BIO where we + * had to flush all over the place not really knowing when it was required + * to do so. + */ + +typedef struct { + SSL *pssl; + BIO *pbioRead; + BIO *pbioWrite; + ap_filter_t *pInputFilter; + ap_filter_t *pOutputFilter; + int nobuffer; /* non-zero to prevent buffering */ + SSLConnRec *config; +} ssl_filter_ctx_t; + +typedef struct { + ssl_filter_ctx_t *filter_ctx; + conn_rec *c; + apr_bucket_brigade *bb; + apr_size_t length; + char buffer[AP_IOBUFSIZE]; + apr_size_t blen; + apr_status_t rc; +} bio_filter_out_ctx_t; + +static bio_filter_out_ctx_t *bio_filter_out_ctx_new(ssl_filter_ctx_t *filter_ctx, + conn_rec *c) +{ + bio_filter_out_ctx_t *outctx = apr_palloc(c->pool, sizeof(*outctx)); + + outctx->filter_ctx = filter_ctx; + outctx->c = c; + outctx->bb = apr_brigade_create(c->pool, c->bucket_alloc); + outctx->blen = 0; + outctx->length = 0; + + return outctx; +} + +static int bio_filter_out_flush(BIO *bio) +{ + bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr); + apr_bucket *e; + + if (!(outctx->blen || outctx->length)) { + outctx->rc = APR_SUCCESS; + return 1; + } + + if (outctx->blen) { + e = apr_bucket_transient_create(outctx->buffer, outctx->blen, + outctx->bb->bucket_alloc); + /* we filled this buffer first so add it to the + * head of the brigade + */ + APR_BRIGADE_INSERT_HEAD(outctx->bb, e); + outctx->blen = 0; + } + + outctx->length = 0; + e = apr_bucket_flush_create(outctx->bb->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(outctx->bb, e); + + outctx->rc = ap_pass_brigade(outctx->filter_ctx->pOutputFilter->next, + outctx->bb); + /* Fail if the connection was reset: */ + if (outctx->rc == APR_SUCCESS && outctx->c->aborted) { + outctx->rc = APR_ECONNRESET; + } + return (outctx->rc == APR_SUCCESS) ? 1 : -1; +} + +static int bio_filter_create(BIO *bio) +{ + bio->shutdown = 1; + bio->init = 1; + bio->num = -1; + bio->ptr = NULL; + + return 1; +} + +static int bio_filter_destroy(BIO *bio) +{ + if (bio == NULL) { + return 0; + } + + /* nothing to free here. + * apache will destroy the bucket brigade for us + */ + return 1; +} + +static int bio_filter_out_read(BIO *bio, char *out, int outl) +{ + /* this is never called */ + return -1; +} + +static int bio_filter_out_write(BIO *bio, const char *in, int inl) +{ + bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr); + + /* Abort early if the client has initiated a renegotiation. */ + if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) { + outctx->rc = APR_ECONNABORTED; + return -1; + } + + /* when handshaking we'll have a small number of bytes. + * max size SSL will pass us here is about 16k. + * (16413 bytes to be exact) + */ + BIO_clear_retry_flags(bio); + + if (!outctx->length && (inl + outctx->blen < sizeof(outctx->buffer)) && + !outctx->filter_ctx->nobuffer) { + /* the first two SSL_writes (of 1024 and 261 bytes) + * need to be in the same packet (vec[0].iov_base) + */ + /* XXX: could use apr_brigade_write() to make code look cleaner + * but this way we avoid the malloc(APR_BUCKET_BUFF_SIZE) + * and free() of it later + */ + memcpy(&outctx->buffer[outctx->blen], in, inl); + outctx->blen += inl; + } + else { + /* pass along the encrypted data + * need to flush since we're using SSL's malloc-ed buffer + * which will be overwritten once we leave here + */ + apr_bucket *bucket = apr_bucket_transient_create(in, inl, + outctx->bb->bucket_alloc); + + outctx->length += inl; + APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket); + + if (bio_filter_out_flush(bio) < 0) { + return -1; + } + } + + return inl; +} + +static long bio_filter_out_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + long ret = 1; + char **pptr; + + bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr); + + switch (cmd) { + case BIO_CTRL_RESET: + outctx->blen = outctx->length = 0; + break; + case BIO_CTRL_EOF: + ret = (long)((outctx->blen + outctx->length) == 0); + break; + case BIO_C_SET_BUF_MEM_EOF_RETURN: + outctx->blen = outctx->length = (apr_size_t)num; + break; + case BIO_CTRL_INFO: + ret = (long)(outctx->blen + outctx->length); + if (ptr) { + pptr = (char **)ptr; + *pptr = (char *)&(outctx->buffer[0]); + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)bio->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + break; + case BIO_CTRL_WPENDING: + ret = 0L; + break; + case BIO_CTRL_PENDING: + ret = (long)(outctx->blen + outctx->length); + break; + case BIO_CTRL_FLUSH: + ret = bio_filter_out_flush(bio); + break; + case BIO_CTRL_DUP: + ret = 1; + break; + /* N/A */ + case BIO_C_SET_BUF_MEM: + case BIO_C_GET_BUF_MEM_PTR: + /* we don't care */ + case BIO_CTRL_PUSH: + case BIO_CTRL_POP: + default: + ret = 0; + break; + } + + return ret; +} + +static int bio_filter_out_gets(BIO *bio, char *buf, int size) +{ + /* this is never called */ + return -1; +} + +static int bio_filter_out_puts(BIO *bio, const char *str) +{ + /* this is never called */ + return -1; +} + +static BIO_METHOD bio_filter_out_method = { + BIO_TYPE_MEM, + "APR output filter", + bio_filter_out_write, + bio_filter_out_read, /* read is never called */ + bio_filter_out_puts, /* puts is never called */ + bio_filter_out_gets, /* gets is never called */ + bio_filter_out_ctrl, + bio_filter_create, + bio_filter_destroy, +#ifdef OPENSSL_VERSION_NUMBER + NULL /* sslc does not have the callback_ctrl field */ +#endif +}; + +typedef struct { + int length; + char *value; +} char_buffer_t; + +typedef struct { + SSL *ssl; + BIO *bio_out; + ap_filter_t *f; + apr_status_t rc; + ap_input_mode_t mode; + apr_read_type_e block; + apr_bucket_brigade *bb; + char_buffer_t cbuf; + apr_pool_t *pool; + char buffer[AP_IOBUFSIZE]; + ssl_filter_ctx_t *filter_ctx; +} bio_filter_in_ctx_t; + +/* + * this char_buffer api might seem silly, but we don't need to copy + * any of this data and we need to remember the length. + */ + +/* Copy up to INL bytes from the char_buffer BUFFER into IN. Note + * that due to the strange way this API is designed/used, the + * char_buffer object is used to cache a segment of inctx->buffer, and + * then this function called to copy (part of) that segment to the + * beginning of inctx->buffer. So the segments to copy cannot be + * presumed to be non-overlapping, and memmove must be used. */ +static int char_buffer_read(char_buffer_t *buffer, char *in, int inl) +{ + if (!buffer->length) { + return 0; + } + + if (buffer->length > inl) { + /* we have have enough to fill the caller's buffer */ + memmove(in, buffer->value, inl); + buffer->value += inl; + buffer->length -= inl; + } + else { + /* swallow remainder of the buffer */ + memmove(in, buffer->value, buffer->length); + inl = buffer->length; + buffer->value = NULL; + buffer->length = 0; + } + + return inl; +} + +static int char_buffer_write(char_buffer_t *buffer, char *in, int inl) +{ + buffer->value = in; + buffer->length = inl; + return inl; +} + +/* This function will read from a brigade and discard the read buckets as it + * proceeds. It will read at most *len bytes. + */ +static apr_status_t brigade_consume(apr_bucket_brigade *bb, + apr_read_type_e block, + char *c, apr_size_t *len) +{ + apr_size_t actual = 0; + apr_status_t status = APR_SUCCESS; + + while (!APR_BRIGADE_EMPTY(bb)) { + apr_bucket *b = APR_BRIGADE_FIRST(bb); + const char *str; + apr_size_t str_len; + apr_size_t consume; + + /* Justin points out this is an http-ism that might + * not fit if brigade_consume is added to APR. Perhaps + * apr_bucket_read(eos_bucket) should return APR_EOF? + * Then this becomes mainline instead of a one-off. + */ + if (APR_BUCKET_IS_EOS(b)) { + status = APR_EOF; + break; + } + + /* The reason I'm not offering brigade_consume yet + * across to apr-util is that the following call + * illustrates how borked that API really is. For + * this sort of case (caller provided buffer) it + * would be much more trivial for apr_bucket_consume + * to do all the work that follows, based on the + * particular characteristics of the bucket we are + * consuming here. + */ + status = apr_bucket_read(b, &str, &str_len, block); + + if (status != APR_SUCCESS) { + if (APR_STATUS_IS_EOF(status)) { + /* This stream bucket was consumed */ + apr_bucket_delete(b); + continue; + } + break; + } + + if (str_len > 0) { + /* Do not block once some data has been consumed */ + block = APR_NONBLOCK_READ; + + /* Assure we don't overflow. */ + consume = (str_len + actual > *len) ? *len - actual : str_len; + + memcpy(c, str, consume); + + c += consume; + actual += consume; + + if (consume >= b->length) { + /* This physical bucket was consumed */ + apr_bucket_delete(b); + } + else { + /* Only part of this physical bucket was consumed */ + b->start += consume; + b->length -= consume; + } + } + else if (b->length == 0) { + apr_bucket_delete(b); + } + + /* This could probably be actual == *len, but be safe from stray + * photons. */ + if (actual >= *len) { + break; + } + } + + *len = actual; + return status; +} + +/* + * this is the function called by SSL_read() + */ +static int bio_filter_in_read(BIO *bio, char *in, int inlen) +{ + apr_size_t inl = inlen; + bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr); + apr_read_type_e block = inctx->block; + SSLConnRec *sslconn = myConnConfig(inctx->f->c); + + inctx->rc = APR_SUCCESS; + + /* OpenSSL catches this case, so should we. */ + if (!in) + return 0; + + /* Abort early if the client has initiated a renegotiation. */ + if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) { + inctx->rc = APR_ECONNABORTED; + return -1; + } + + /* XXX: flush here only required for SSLv2; + * OpenSSL calls BIO_flush() at the appropriate times for + * the other protocols. + */ + if ((SSL_version(inctx->ssl) == SSL2_VERSION) || sslconn->is_proxy) { + if (bio_filter_out_flush(inctx->bio_out) < 0) { + bio_filter_out_ctx_t *outctx = + (bio_filter_out_ctx_t *)(inctx->bio_out->ptr); + inctx->rc = outctx->rc; + return -1; + } + } + + BIO_clear_retry_flags(bio); + + if (!inctx->bb) { + inctx->rc = APR_EOF; + return -1; + } + + if (APR_BRIGADE_EMPTY(inctx->bb)) { + + inctx->rc = ap_get_brigade(inctx->f->next, inctx->bb, + AP_MODE_READBYTES, block, + inl); + + /* Not a problem, there was simply no data ready yet. + */ + if (APR_STATUS_IS_EAGAIN(inctx->rc) || APR_STATUS_IS_EINTR(inctx->rc) + || (inctx->rc == APR_SUCCESS && APR_BRIGADE_EMPTY(inctx->bb))) { + BIO_set_retry_read(bio); + return 0; + } + + if (inctx->rc != APR_SUCCESS) { + /* Unexpected errors discard the brigade */ + apr_brigade_cleanup(inctx->bb); + inctx->bb = NULL; + return -1; + } + } + + inctx->rc = brigade_consume(inctx->bb, block, in, &inl); + + if (inctx->rc == APR_SUCCESS) { + return (int)inl; + } + + if (APR_STATUS_IS_EAGAIN(inctx->rc) + || APR_STATUS_IS_EINTR(inctx->rc)) { + BIO_set_retry_read(bio); + return (int)inl; + } + + /* Unexpected errors and APR_EOF clean out the brigade. + * Subsequent calls will return APR_EOF. + */ + apr_brigade_cleanup(inctx->bb); + inctx->bb = NULL; + + if (APR_STATUS_IS_EOF(inctx->rc) && inl) { + /* Provide the results of this read pass, + * without resetting the BIO retry_read flag + */ + return (int)inl; + } + + return -1; +} + + +static BIO_METHOD bio_filter_in_method = { + BIO_TYPE_MEM, + "APR input filter", + NULL, /* write is never called */ + bio_filter_in_read, + NULL, /* puts is never called */ + NULL, /* gets is never called */ + NULL, /* ctrl is never called */ + bio_filter_create, + bio_filter_destroy, +#ifdef OPENSSL_VERSION_NUMBER + NULL /* sslc does not have the callback_ctrl field */ +#endif +}; + + +static apr_status_t ssl_io_input_read(bio_filter_in_ctx_t *inctx, + char *buf, + apr_size_t *len) +{ + apr_size_t wanted = *len; + apr_size_t bytes = 0; + int rc; + + *len = 0; + + /* If we have something leftover from last time, try that first. */ + if ((bytes = char_buffer_read(&inctx->cbuf, buf, wanted))) { + *len = bytes; + if (inctx->mode == AP_MODE_SPECULATIVE) { + /* We want to rollback this read. */ + if (inctx->cbuf.length > 0) { + inctx->cbuf.value -= bytes; + inctx->cbuf.length += bytes; + } else { + char_buffer_write(&inctx->cbuf, buf, (int)bytes); + } + return APR_SUCCESS; + } + /* This could probably be *len == wanted, but be safe from stray + * photons. + */ + if (*len >= wanted) { + return APR_SUCCESS; + } + if (inctx->mode == AP_MODE_GETLINE) { + if (memchr(buf, APR_ASCII_LF, *len)) { + return APR_SUCCESS; + } + } + else { + /* Down to a nonblock pattern as we have some data already + */ + inctx->block = APR_NONBLOCK_READ; + } + } + + while (1) { + + if (!inctx->filter_ctx->pssl) { + /* Ensure a non-zero error code is returned */ + if (inctx->rc == APR_SUCCESS) { + inctx->rc = APR_EGENERAL; + } + break; + } + + /* SSL_read may not read because we haven't taken enough data + * from the stack. This is where we want to consider all of + * the blocking and SPECULATIVE semantics + */ + rc = SSL_read(inctx->filter_ctx->pssl, buf + bytes, wanted - bytes); + + if (rc > 0) { + *len += rc; + if (inctx->mode == AP_MODE_SPECULATIVE) { + /* We want to rollback this read. */ + char_buffer_write(&inctx->cbuf, buf, rc); + } + return inctx->rc; + } + else if (rc == 0) { + /* If EAGAIN, we will loop given a blocking read, + * otherwise consider ourselves at EOF. + */ + if (APR_STATUS_IS_EAGAIN(inctx->rc) + || APR_STATUS_IS_EINTR(inctx->rc)) { + /* Already read something, return APR_SUCCESS instead. + * On win32 in particular, but perhaps on other kernels, + * a blocking call isn't 'always' blocking. + */ + if (*len > 0) { + inctx->rc = APR_SUCCESS; + break; + } + if (inctx->block == APR_NONBLOCK_READ) { + break; + } + } + else { + if (*len > 0) { + inctx->rc = APR_SUCCESS; + } + else { + inctx->rc = APR_EOF; + } + break; + } + } + else /* (rc < 0) */ { + int ssl_err = SSL_get_error(inctx->filter_ctx->pssl, rc); + conn_rec *c = (conn_rec*)SSL_get_app_data(inctx->filter_ctx->pssl); + + if (ssl_err == SSL_ERROR_WANT_READ) { + /* + * If OpenSSL wants to read more, and we were nonblocking, + * report as an EAGAIN. Otherwise loop, pulling more + * data from network filter. + * + * (This is usually the case when the client forces an SSL + * renegotation which is handled implicitly by OpenSSL.) + */ + inctx->rc = APR_EAGAIN; + + if (*len > 0) { + inctx->rc = APR_SUCCESS; + break; + } + if (inctx->block == APR_NONBLOCK_READ) { + break; + } + continue; /* Blocking and nothing yet? Try again. */ + } + else if (ssl_err == SSL_ERROR_SYSCALL) { + if (APR_STATUS_IS_EAGAIN(inctx->rc) + || APR_STATUS_IS_EINTR(inctx->rc)) { + /* Already read something, return APR_SUCCESS instead. */ + if (*len > 0) { + inctx->rc = APR_SUCCESS; + break; + } + if (inctx->block == APR_NONBLOCK_READ) { + break; + } + continue; /* Blocking and nothing yet? Try again. */ + } + else { + ap_log_error(APLOG_MARK, APLOG_INFO, inctx->rc, c->base_server, + "SSL input filter read failed."); + } + } + else /* if (ssl_err == SSL_ERROR_SSL) */ { + /* + * Log SSL errors and any unexpected conditions. + */ + ap_log_error(APLOG_MARK, APLOG_INFO, inctx->rc, c->base_server, + "SSL library error %d reading data", ssl_err); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); + + } + if (inctx->rc == APR_SUCCESS) { + inctx->rc = APR_EGENERAL; + } + break; + } + } + return inctx->rc; +} + +static apr_status_t ssl_io_input_getline(bio_filter_in_ctx_t *inctx, + char *buf, + apr_size_t *len) +{ + const char *pos = NULL; + apr_status_t status; + apr_size_t tmplen = *len, buflen = *len, offset = 0; + + *len = 0; + + /* + * in most cases we get all the headers on the first SSL_read. + * however, in certain cases SSL_read will only get a partial + * chunk of the headers, so we try to read until LF is seen. + */ + + while (tmplen > 0) { + status = ssl_io_input_read(inctx, buf + offset, &tmplen); + + if (status != APR_SUCCESS) { + return status; + } + + *len += tmplen; + + if ((pos = memchr(buf, APR_ASCII_LF, *len))) { + break; + } + + offset += tmplen; + tmplen = buflen - offset; + } + + if (pos) { + char *value; + int length; + apr_size_t bytes = pos - buf; + + bytes += 1; + value = buf + bytes; + length = *len - bytes; + + char_buffer_write(&inctx->cbuf, value, length); + + *len = bytes; + } + + return APR_SUCCESS; +} + + +static apr_status_t ssl_filter_write(ap_filter_t *f, + const char *data, + apr_size_t len) +{ + ssl_filter_ctx_t *filter_ctx = f->ctx; + bio_filter_out_ctx_t *outctx; + int res; + + /* write SSL */ + if (filter_ctx->pssl == NULL) { + return APR_EGENERAL; + } + + outctx = (bio_filter_out_ctx_t *)filter_ctx->pbioWrite->ptr; + res = SSL_write(filter_ctx->pssl, (unsigned char *)data, len); + + if (res < 0) { + int ssl_err = SSL_get_error(filter_ctx->pssl, res); + conn_rec *c = (conn_rec*)SSL_get_app_data(outctx->filter_ctx->pssl); + + if (ssl_err == SSL_ERROR_WANT_WRITE) { + /* + * If OpenSSL wants to write more, and we were nonblocking, + * report as an EAGAIN. Otherwise loop, pushing more + * data at the network filter. + * + * (This is usually the case when the client forces an SSL + * renegotation which is handled implicitly by OpenSSL.) + */ + outctx->rc = APR_EAGAIN; + } + else if (ssl_err == SSL_ERROR_SYSCALL) { + ap_log_error(APLOG_MARK, APLOG_INFO, outctx->rc, c->base_server, + "SSL output filter write failed."); + } + else /* if (ssl_err == SSL_ERROR_SSL) */ { + /* + * Log SSL errors + */ + ap_log_error(APLOG_MARK, APLOG_INFO, outctx->rc, c->base_server, + "SSL library error %d writing data", ssl_err); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); + } + if (outctx->rc == APR_SUCCESS) { + outctx->rc = APR_EGENERAL; + } + } + else if ((apr_size_t)res != len) { + conn_rec *c = f->c; + char *reason = "reason unknown"; + + /* XXX: probably a better way to determine this */ + if (SSL_total_renegotiations(filter_ctx->pssl)) { + reason = "likely due to failed renegotiation"; + } + + ap_log_error(APLOG_MARK, APLOG_INFO, outctx->rc, c->base_server, + "failed to write %d of %d bytes (%s)", + len - (apr_size_t)res, len, reason); + + outctx->rc = APR_EGENERAL; + } + return outctx->rc; +} + +/* Just use a simple request. Any request will work for this, because + * we use a flag in the conn_rec->conn_vector now. The fake request just + * gets the request back to the Apache core so that a response can be sent. + * + * To avoid calling back for more data from the socket, use an HTTP/0.9 + * request, and tack on an EOS bucket. + */ +#define HTTP_ON_HTTPS_PORT \ + "GET /" CRLF + +#define HTTP_ON_HTTPS_PORT_BUCKET(alloc) \ + apr_bucket_immortal_create(HTTP_ON_HTTPS_PORT, \ + sizeof(HTTP_ON_HTTPS_PORT) - 1, \ + alloc) + +static void ssl_io_filter_disable(SSLConnRec *sslconn, ap_filter_t *f) +{ + bio_filter_in_ctx_t *inctx = f->ctx; + SSL_free(inctx->ssl); + sslconn->ssl = NULL; + inctx->ssl = NULL; + inctx->filter_ctx->pssl = NULL; +} + +static apr_status_t ssl_io_filter_error(ap_filter_t *f, + apr_bucket_brigade *bb, + apr_status_t status) +{ + SSLConnRec *sslconn = myConnConfig(f->c); + apr_bucket *bucket; + + switch (status) { + case HTTP_BAD_REQUEST: + /* log the situation */ + ap_log_error(APLOG_MARK, APLOG_INFO, 0, + f->c->base_server, + "SSL handshake failed: HTTP spoken on HTTPS port; " + "trying to send HTML error page"); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, f->c->base_server); + + sslconn->non_ssl_request = 1; + ssl_io_filter_disable(sslconn, f); + + /* fake the request line */ + bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc); + break; + + default: + return status; + } + + APR_BRIGADE_INSERT_TAIL(bb, bucket); + bucket = apr_bucket_eos_create(f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, bucket); + + return APR_SUCCESS; +} + +static const char ssl_io_filter[] = "SSL/TLS Filter"; +static const char ssl_io_buffer[] = "SSL/TLS Buffer"; + +/* + * Close the SSL part of the socket connection + * (called immediately _before_ the socket is closed) + * or called with + */ +static apr_status_t ssl_filter_io_shutdown(ssl_filter_ctx_t *filter_ctx, + conn_rec *c, + int abortive) +{ + SSL *ssl = filter_ctx->pssl; + const char *type = ""; + SSLConnRec *sslconn = myConnConfig(c); + int shutdown_type; + + if (!ssl) { + return APR_SUCCESS; + } + + /* + * Now close the SSL layer of the connection. We've to take + * the TLSv1 standard into account here: + * + * | 7.2.1. Closure alerts + * | + * | The client and the server must share knowledge that the connection is + * | ending in order to avoid a truncation attack. Either party may + * | initiate the exchange of closing messages. + * | + * | close_notify + * | This message notifies the recipient that the sender will not send + * | any more messages on this connection. The session becomes + * | unresumable if any connection is terminated without proper + * | close_notify messages with level equal to warning. + * | + * | Either party may initiate a close by sending a close_notify alert. + * | Any data received after a closure alert is ignored. + * | + * | Each party is required to send a close_notify alert before closing + * | the write side of the connection. It is required that the other party + * | respond with a close_notify alert of its own and close down the + * | connection immediately, discarding any pending writes. It is not + * | required for the initiator of the close to wait for the responding + * | close_notify alert before closing the read side of the connection. + * + * This means we've to send a close notify message, but haven't to wait + * for the close notify of the client. Actually we cannot wait for the + * close notify of the client because some clients (including Netscape + * 4.x) don't send one, so we would hang. + */ + + /* + * exchange close notify messages, but allow the user + * to force the type of handshake via SetEnvIf directive + */ + if (abortive) { + shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN; + type = "abortive"; + } + else switch (sslconn->shutdown_type) { + case SSL_SHUTDOWN_TYPE_UNCLEAN: + /* perform no close notify handshake at all + (violates the SSL/TLS standard!) */ + shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN; + type = "unclean"; + break; + case SSL_SHUTDOWN_TYPE_ACCURATE: + /* send close notify and wait for clients close notify + (standard compliant, but usually causes connection hangs) */ + shutdown_type = 0; + type = "accurate"; + break; + default: + /* + * case SSL_SHUTDOWN_TYPE_UNSET: + * case SSL_SHUTDOWN_TYPE_STANDARD: + */ + /* send close notify, but don't wait for clients close notify + (standard compliant and safe, so it's the DEFAULT!) */ + shutdown_type = SSL_RECEIVED_SHUTDOWN; + type = "standard"; + break; + } + + SSL_set_shutdown(ssl, shutdown_type); + SSL_smart_shutdown(ssl); + + /* and finally log the fact that we've closed the connection */ + if (c->base_server->loglevel >= APLOG_INFO) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, + "Connection to child %ld closed with %s shutdown" + "(server %s, client %s)", + c->id, type, + ssl_util_vhostid(c->pool, c->base_server), + c->remote_ip ? c->remote_ip : "unknown"); + } + + /* deallocate the SSL connection */ + if (sslconn->client_cert) { + X509_free(sslconn->client_cert); + sslconn->client_cert = NULL; + } + SSL_free(ssl); + sslconn->ssl = NULL; + filter_ctx->pssl = NULL; /* so filters know we've been shutdown */ + + if (abortive) { + /* prevent any further I/O */ + c->aborted = 1; + } + + return APR_SUCCESS; +} + +static apr_status_t ssl_io_filter_cleanup(void *data) +{ + ssl_filter_ctx_t *filter_ctx = data; + + if (filter_ctx->pssl) { + conn_rec *c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl); + SSLConnRec *sslconn = myConnConfig(c); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, + "SSL connection destroyed without being closed"); + + SSL_free(filter_ctx->pssl); + sslconn->ssl = filter_ctx->pssl = NULL; + } + + return APR_SUCCESS; +} + +/* + * The hook is NOT registered with ap_hook_process_connection. Instead, it is + * called manually from the churn () before it tries to read any data. + * There is some problem if I accept conn_rec *. Still investigating.. + * Adv. if conn_rec * can be accepted is we can hook this function using the + * ap_hook_process_connection hook. + */ +static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx) +{ + conn_rec *c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl); + SSLConnRec *sslconn = myConnConfig(c); + SSLSrvConfigRec *sc = mySrvConfig(c->base_server); + X509 *cert; + int n; + int ssl_err; + long verify_result; + + if (SSL_is_init_finished(filter_ctx->pssl)) { + return APR_SUCCESS; + } + + if (sslconn->is_proxy) { + if ((n = SSL_connect(filter_ctx->pssl)) <= 0) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, + c->base_server, + "SSL Proxy connect failed"); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); + return ssl_filter_io_shutdown(filter_ctx, c, 1); + } + + return APR_SUCCESS; + } + + if ((n = SSL_accept(filter_ctx->pssl)) <= 0) { + bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *) + (filter_ctx->pbioRead->ptr); + bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *) + (filter_ctx->pbioWrite->ptr); + apr_status_t rc = inctx->rc ? inctx->rc : outctx->rc ; + ssl_err = SSL_get_error(filter_ctx->pssl, n); + + if (ssl_err == SSL_ERROR_ZERO_RETURN) { + /* + * The case where the connection was closed before any data + * was transferred. That's not a real error and can occur + * sporadically with some clients. + */ + ap_log_error(APLOG_MARK, APLOG_INFO, rc, + c->base_server, + "SSL handshake stopped: connection was closed"); + } + else if (ssl_err == SSL_ERROR_WANT_READ) { + /* + * This is in addition to what was present earlier. It is + * borrowed from openssl_state_machine.c [mod_tls]. + * TBD. + */ + outctx->rc = APR_EAGAIN; + return SSL_ERROR_WANT_READ; + } + else if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL && + ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) { + /* + * The case where OpenSSL has recognized a HTTP request: + * This means the client speaks plain HTTP on our HTTPS port. + * ssl_io_filter_error will disable the ssl filters when it + * sees this status code. + */ + return HTTP_BAD_REQUEST; + } + else if (ssl_err == SSL_ERROR_SYSCALL) { + ap_log_error(APLOG_MARK, APLOG_INFO, rc, c->base_server, + "SSL handshake interrupted by system " + "[Hint: Stop button pressed in browser?!]"); + } + else /* if (ssl_err == SSL_ERROR_SSL) */ { + /* + * Log SSL errors and any unexpected conditions. + */ + ap_log_error(APLOG_MARK, APLOG_INFO, rc, c->base_server, + "SSL library error %d in handshake " + "(server %s, client %s)", ssl_err, + ssl_util_vhostid(c->pool, c->base_server), + c->remote_ip ? c->remote_ip : "unknown"); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); + + } + if (inctx->rc == APR_SUCCESS) { + inctx->rc = APR_EGENERAL; + } + + return ssl_filter_io_shutdown(filter_ctx, c, 1); + } + + /* + * Check for failed client authentication + */ + verify_result = SSL_get_verify_result(filter_ctx->pssl); + + if ((verify_result != X509_V_OK) || + sslconn->verify_error) + { + if (ssl_verify_error_is_optional(verify_result) && + (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA)) + { + /* leaving this log message as an error for the moment, + * according to the mod_ssl docs: + * "level optional_no_ca is actually against the idea + * of authentication (but can be used to establish + * SSL test pages, etc.)" + * optional_no_ca doesn't appear to work as advertised + * in 1.x + */ + ap_log_error(APLOG_MARK, APLOG_INFO, 0, + c->base_server, + "SSL client authentication failed, " + "accepting certificate based on " + "\"SSLVerifyClient optional_no_ca\" " + "configuration"); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); + } + else { + const char *error = sslconn->verify_error ? + sslconn->verify_error : + X509_verify_cert_error_string(verify_result); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, + c->base_server, + "SSL client authentication failed: %s", + error ? error : "unknown"); + ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); + + return ssl_filter_io_shutdown(filter_ctx, c, 1); + } + } + + /* + * Remember the peer certificate's DN + */ + if ((cert = SSL_get_peer_certificate(filter_ctx->pssl))) { + if (sslconn->client_cert) { + X509_free(sslconn->client_cert); + } + sslconn->client_cert = cert; + sslconn->client_dn = NULL; + } + + /* + * Make really sure that when a peer certificate + * is required we really got one... (be paranoid) + */ + if ((sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE) && + !sslconn->client_cert) + { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, + "No acceptable peer certificate available"); + + return ssl_filter_io_shutdown(filter_ctx, c, 1); + } + + return APR_SUCCESS; +} + +static apr_status_t ssl_io_filter_input(ap_filter_t *f, + apr_bucket_brigade *bb, + ap_input_mode_t mode, + apr_read_type_e block, + apr_off_t readbytes) +{ + apr_status_t status; + bio_filter_in_ctx_t *inctx = f->ctx; + + apr_size_t len = sizeof(inctx->buffer); + int is_init = (mode == AP_MODE_INIT); + + if (f->c->aborted) { + /* XXX: Ok, if we aborted, we ARE at the EOS. We also have + * aborted. This 'double protection' is probably redundant, + * but also effective against just about anything. + */ + apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, bucket); + return APR_ECONNABORTED; + } + + if (!inctx->ssl) { + return ap_get_brigade(f->next, bb, mode, block, readbytes); + } + + /* XXX: we don't currently support anything other than these modes. */ + if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE && + mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) { + return APR_ENOTIMPL; + } + + inctx->mode = mode; + inctx->block = block; + + /* XXX: we could actually move ssl_io_filter_connect to an + * ap_hook_process_connection but would still need to call it for + * AP_MODE_INIT for protocols that may upgrade the connection + * rather than have SSLEngine On configured. + */ + if ((status = ssl_io_filter_connect(inctx->filter_ctx)) != APR_SUCCESS) { + return ssl_io_filter_error(f, bb, status); + } + + if (is_init) { + /* protocol module needs to handshake before sending + * data to client (e.g. NNTP or FTP) + */ + return APR_SUCCESS; + } + + if (inctx->mode == AP_MODE_READBYTES || + inctx->mode == AP_MODE_SPECULATIVE) { + /* Protected from truncation, readbytes < MAX_SIZE_T + * FIXME: No, it's *not* protected. -- jre */ + if (readbytes < len) { + len = (apr_size_t)readbytes; + } + status = ssl_io_input_read(inctx, inctx->buffer, &len); + } + else if (inctx->mode == AP_MODE_GETLINE) { + status = ssl_io_input_getline(inctx, inctx->buffer, &len); + } + else { + /* We have no idea what you are talking about, so return an error. */ + status = APR_ENOTIMPL; + } + + /* It is possible for mod_ssl's BIO to be used outside of the + * direct control of mod_ssl's input or output filter -- notably, + * when mod_ssl initiates a renegotiation. Switching the BIO mode + * back to "blocking" here ensures such operations don't fail with + * SSL_ERROR_WANT_READ. */ + inctx->block = APR_BLOCK_READ; + + /* Handle custom errors. */ + if (status != APR_SUCCESS) { + return ssl_io_filter_error(f, bb, status); + } + + /* Create a transient bucket out of the decrypted data. */ + if (len > 0) { + apr_bucket *bucket = + apr_bucket_transient_create(inctx->buffer, len, f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, bucket); + } + + return APR_SUCCESS; +} + +static apr_status_t ssl_io_filter_output(ap_filter_t *f, + apr_bucket_brigade *bb) +{ + apr_status_t status = APR_SUCCESS; + ssl_filter_ctx_t *filter_ctx = f->ctx; + bio_filter_in_ctx_t *inctx; + bio_filter_out_ctx_t *outctx; + apr_read_type_e rblock = APR_NONBLOCK_READ; + + if (f->c->aborted) { + apr_brigade_cleanup(bb); + return APR_ECONNABORTED; + } + + if (!filter_ctx->pssl) { + /* ssl_filter_io_shutdown was called */ + return ap_pass_brigade(f->next, bb); + } + + inctx = (bio_filter_in_ctx_t *)filter_ctx->pbioRead->ptr; + outctx = (bio_filter_out_ctx_t *)filter_ctx->pbioWrite->ptr; + + /* When we are the writer, we must initialize the inctx + * mode so that we block for any required ssl input, because + * output filtering is always nonblocking. + */ + inctx->mode = AP_MODE_READBYTES; + inctx->block = APR_BLOCK_READ; + + if ((status = ssl_io_filter_connect(filter_ctx)) != APR_SUCCESS) { + return ssl_io_filter_error(f, bb, status); + } + + while (!APR_BRIGADE_EMPTY(bb)) { + apr_bucket *bucket = APR_BRIGADE_FIRST(bb); + + /* If it is a flush or EOS, we need to pass this down. + * These types do not require translation by OpenSSL. + */ + if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) { + if (bio_filter_out_flush(filter_ctx->pbioWrite) < 0) { + status = outctx->rc; + break; + } + + if (APR_BUCKET_IS_EOS(bucket)) { + /* + * By definition, nothing can come after EOS. + * which also means we can pass the rest of this brigade + * without creating a new one since it only contains the + * EOS bucket. + */ + + if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { + return status; + } + break; + } + else { + /* bio_filter_out_flush() already passed down a flush bucket + * if there was any data to be flushed. + */ + apr_bucket_delete(bucket); + } + } + else if (AP_BUCKET_IS_EOC(bucket)) { + /* The special "EOC" bucket means a shutdown is needed; + * - turn off buffering in bio_filter_out_write + * - issue the SSL_shutdown + */ + filter_ctx->nobuffer = 1; + status = ssl_filter_io_shutdown(filter_ctx, f->c, 0); + if (status != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_INFO, status, NULL, + "SSL filter error shutting down I/O"); + } + if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { + return status; + } + break; + } + else { + /* filter output */ + const char *data; + apr_size_t len; + + status = apr_bucket_read(bucket, &data, &len, rblock); + + if (APR_STATUS_IS_EAGAIN(status)) { + /* No data available: flush... */ + if (bio_filter_out_flush(filter_ctx->pbioWrite) < 0) { + status = outctx->rc; + break; + } + rblock = APR_BLOCK_READ; + continue; /* and try again with a blocking read. */ + } + + rblock = APR_NONBLOCK_READ; + + if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) { + break; + } + + status = ssl_filter_write(f, data, len); + apr_bucket_delete(bucket); + + if (status != APR_SUCCESS) { + break; + } + } + } + + return status; +} + +/* 128K maximum buffer size by default. */ +#ifndef SSL_MAX_IO_BUFFER +#define SSL_MAX_IO_BUFFER (128 * 1024) +#endif + +struct modssl_buffer_ctx { + apr_bucket_brigade *bb; + apr_pool_t *pool; +}; + +int ssl_io_buffer_fill(request_rec *r) +{ + conn_rec *c = r->connection; + struct modssl_buffer_ctx *ctx; + apr_bucket_brigade *tempb; + apr_off_t total = 0; /* total length buffered */ + int eos = 0; /* non-zero once EOS is seen */ + + /* Create the context which will be passed to the input filter; + * containing a setaside pool and a brigade which constrain the + * lifetime of the buffered data. */ + ctx = apr_palloc(r->pool, sizeof *ctx); + apr_pool_create(&ctx->pool, r->pool); + ctx->bb = apr_brigade_create(ctx->pool, c->bucket_alloc); + + /* ... and a temporary brigade. */ + tempb = apr_brigade_create(r->pool, c->bucket_alloc); + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "filling buffer"); + + do { + apr_status_t rv; + apr_bucket *e, *next; + + /* The request body is read from the protocol-level input + * filters; the buffering filter will reinject it from that + * level, allowing content/resource filters to run later, if + * necessary. */ + + rv = ap_get_brigade(r->proto_input_filters, tempb, AP_MODE_READBYTES, + APR_BLOCK_READ, 8192); + if (rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "could not read request body for SSL buffer"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + /* Iterate through the returned brigade: setaside each bucket + * into the context's pool and move it into the brigade. */ + for (e = APR_BRIGADE_FIRST(tempb); + e != APR_BRIGADE_SENTINEL(tempb) && !eos; e = next) { + const char *data; + apr_size_t len; + + next = APR_BUCKET_NEXT(e); + + if (APR_BUCKET_IS_EOS(e)) { + eos = 1; + } else if (!APR_BUCKET_IS_METADATA(e)) { + rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "could not read bucket for SSL buffer"); + return HTTP_INTERNAL_SERVER_ERROR; + } + total += len; + } + + rv = apr_bucket_setaside(e, ctx->pool); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "could not setaside bucket for SSL buffer"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + APR_BUCKET_REMOVE(e); + APR_BRIGADE_INSERT_TAIL(ctx->bb, e); + } + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "total of %" APR_OFF_T_FMT " bytes in buffer, eos=%d", + total, eos); + + /* Fail if this exceeds the maximum buffer size. */ + if (total > SSL_MAX_IO_BUFFER) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "request body exceeds maximum size for SSL buffer"); + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + + } while (!eos); + + apr_brigade_destroy(tempb); + + /* Insert the filter which will supply the buffered data. */ + ap_add_input_filter(ssl_io_buffer, ctx, r, c); + + return 0; +} + +/* This input filter supplies the buffered request body to the caller + * from the brigade stored in f->ctx. */ +static apr_status_t ssl_io_filter_buffer(ap_filter_t *f, + apr_bucket_brigade *bb, + ap_input_mode_t mode, + apr_read_type_e block, + apr_off_t bytes) +{ + struct modssl_buffer_ctx *ctx = f->ctx; + apr_status_t rv; + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, + "read from buffered SSL brigade, mode %d, " + "%" APR_OFF_T_FMT " bytes", + mode, bytes); + + if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) { + return APR_ENOTIMPL; + } + + if (mode == AP_MODE_READBYTES) { + apr_bucket *e; + + /* Partition the buffered brigade. */ + rv = apr_brigade_partition(ctx->bb, bytes, &e); + if (rv && rv != APR_INCOMPLETE) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, + "could not partition buffered SSL brigade"); + ap_remove_input_filter(f); + return rv; + } + + /* If the buffered brigade contains less then the requested + * length, just pass it all back. */ + if (rv == APR_INCOMPLETE) { + APR_BRIGADE_CONCAT(bb, ctx->bb); + } else { + apr_bucket *d = APR_BRIGADE_FIRST(ctx->bb); + + e = APR_BUCKET_PREV(e); + + /* Unsplice the partitioned segment and move it into the + * passed-in brigade; no convenient way to do this with + * the APR_BRIGADE_* macros. */ + APR_RING_UNSPLICE(d, e, link); + APR_RING_SPLICE_HEAD(&bb->list, d, e, apr_bucket, link); + + APR_BRIGADE_CHECK_CONSISTENCY(bb); + APR_BRIGADE_CHECK_CONSISTENCY(ctx->bb); + } + } + else { + /* Split a line into the passed-in brigade. */ + rv = apr_brigade_split_line(bb, ctx->bb, mode, bytes); + + if (rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, + "could not split line from buffered SSL brigade"); + ap_remove_input_filter(f); + return rv; + } + } + + if (APR_BRIGADE_EMPTY(ctx->bb)) { + apr_bucket *e = APR_BRIGADE_LAST(bb); + + /* Ensure that the brigade is terminated by an EOS if the + * buffered request body has been entirely consumed. */ + if (e == APR_BRIGADE_SENTINEL(bb) || !APR_BUCKET_IS_EOS(e)) { + e = apr_bucket_eos_create(f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, e); + } + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, + "buffered SSL brigade now exhausted; removing filter"); + ap_remove_input_filter(f); + } + + return APR_SUCCESS; +} + +static void ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_rec *c, + SSL *ssl) +{ + bio_filter_in_ctx_t *inctx; + + inctx = apr_palloc(c->pool, sizeof(*inctx)); + + filter_ctx->pInputFilter = ap_add_input_filter(ssl_io_filter, inctx, NULL, c); + + filter_ctx->pbioRead = BIO_new(&bio_filter_in_method); + filter_ctx->pbioRead->ptr = (void *)inctx; + + inctx->ssl = ssl; + inctx->bio_out = filter_ctx->pbioWrite; + inctx->f = filter_ctx->pInputFilter; + inctx->rc = APR_SUCCESS; + inctx->mode = AP_MODE_READBYTES; + inctx->cbuf.length = 0; + inctx->bb = apr_brigade_create(c->pool, c->bucket_alloc); + inctx->block = APR_BLOCK_READ; + inctx->pool = c->pool; + inctx->filter_ctx = filter_ctx; +} + +void ssl_io_filter_init(conn_rec *c, SSL *ssl) +{ + ssl_filter_ctx_t *filter_ctx; + + filter_ctx = apr_palloc(c->pool, sizeof(ssl_filter_ctx_t)); + + filter_ctx->config = myConnConfig(c); + + filter_ctx->nobuffer = 0; + filter_ctx->pOutputFilter = ap_add_output_filter(ssl_io_filter, + filter_ctx, NULL, c); + + filter_ctx->pbioWrite = BIO_new(&bio_filter_out_method); + filter_ctx->pbioWrite->ptr = (void *)bio_filter_out_ctx_new(filter_ctx, c); + + ssl_io_input_add_filter(filter_ctx, c, ssl); + + SSL_set_bio(ssl, filter_ctx->pbioRead, filter_ctx->pbioWrite); + filter_ctx->pssl = ssl; + + apr_pool_cleanup_register(c->pool, (void*)filter_ctx, + ssl_io_filter_cleanup, apr_pool_cleanup_null); + + if (c->base_server->loglevel >= APLOG_DEBUG) { + BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb); + BIO_set_callback_arg(SSL_get_rbio(ssl), (void *)ssl); + } + + return; +} + +void ssl_io_filter_register(apr_pool_t *p) +{ + ap_register_input_filter (ssl_io_filter, ssl_io_filter_input, NULL, AP_FTYPE_CONNECTION + 5); + ap_register_output_filter (ssl_io_filter, ssl_io_filter_output, NULL, AP_FTYPE_CONNECTION + 5); + + ap_register_input_filter (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL - 1); + + return; +} + +/* _________________________________________________________________ +** +** I/O Data Debugging +** _________________________________________________________________ +*/ + +#define DUMP_WIDTH 16 + +static void ssl_io_data_dump(server_rec *srvr, + MODSSL_BIO_CB_ARG_TYPE *s, + long len) +{ + char buf[256]; + char tmp[64]; + int i, j, rows, trunc; + unsigned char ch; + + trunc = 0; + for(; (len > 0) && ((s[len-1] == ' ') || (s[len-1] == '\0')); len--) + trunc++; + rows = (len / DUMP_WIDTH); + if ((rows * DUMP_WIDTH) < len) + rows++; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, + "+-------------------------------------------------------------------------+"); + for(i = 0 ; i< rows; i++) { + apr_snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH); + apr_cpystrn(buf, tmp, sizeof(buf)); + for (j = 0; j < DUMP_WIDTH; j++) { + if (((i * DUMP_WIDTH) + j) >= len) + apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); + else { + ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff; + apr_snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' '); + apr_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf)); + } + } + apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); + for (j = 0; j < DUMP_WIDTH; j++) { + if (((i * DUMP_WIDTH) + j) >= len) + apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); + else { + ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff; + apr_snprintf(tmp, sizeof(tmp), "%c", ((ch >= ' ') && (ch <= '~')) ? ch : '.'); + apr_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf)); + } + } + apr_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf)); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, + "%s", buf); + } + if (trunc > 0) + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, + "| %04ld - <SPACES/NULS>", len + trunc); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, + "+-------------------------------------------------------------------------+"); + return; +} + +long ssl_io_data_cb(BIO *bio, int cmd, + MODSSL_BIO_CB_ARG_TYPE *argp, + int argi, long argl, long rc) +{ + SSL *ssl; + conn_rec *c; + server_rec *s; + + if ((ssl = (SSL *)BIO_get_callback_arg(bio)) == NULL) + return rc; + if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL) + return rc; + s = c->base_server; + + if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN) + || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) { + if (rc >= 0) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: %s %ld/%d bytes %s BIO#%pp [mem: %pp] %s", + SSL_LIBRARY_NAME, + (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"), + rc, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "to" : "from"), + bio, argp, + (argp != NULL ? "(BIO dump follows)" : "(Oops, no memory buffer?)")); + if (argp != NULL) + ssl_io_data_dump(s, argp, rc); + } + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: I/O error, %d bytes expected to %s on BIO#%pp [mem: %pp]", + SSL_LIBRARY_NAME, argi, + (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"), + bio, argp); + } + } + return rc; +} diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_kernel.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_kernel.c new file mode 100644 index 00000000..60133f7c --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_kernel.c @@ -0,0 +1,1876 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_kernel.c + * The SSL engine kernel + */ + /* ``It took me fifteen years to discover + I had no talent for programming, but + I couldn't give it up because by that + time I was too famous.'' + -- Unknown */ +#include "mod_ssl.h" + +static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn); + +/* Perform a speculative (and non-blocking) read from the connection + * filters for the given request, to determine whether there is any + * pending data to read. Return non-zero if there is, else zero. */ +static int has_buffered_data(request_rec *r) +{ + apr_bucket_brigade *bb; + apr_off_t len; + apr_status_t rv; + int result; + + bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + + rv = ap_get_brigade(r->connection->input_filters, bb, AP_MODE_SPECULATIVE, + APR_NONBLOCK_READ, 1); + result = rv == APR_SUCCESS + && apr_brigade_length(bb, 1, &len) == APR_SUCCESS + && len > 0; + + apr_brigade_destroy(bb); + + return result; +} + +/* + * Post Read Request Handler + */ +int ssl_hook_ReadReq(request_rec *r) +{ + SSLConnRec *sslconn = myConnConfig(r->connection); + SSL *ssl; + + if (!sslconn) { + return DECLINED; + } + + if (sslconn->non_ssl_request) { + const char *errmsg; + char *thisurl; + char *thisport = ""; + int port = ap_get_server_port(r); + + if (!ap_is_default_port(port, r)) { + thisport = apr_psprintf(r->pool, ":%u", port); + } + + thisurl = ap_escape_html(r->pool, + apr_psprintf(r->pool, "https://%s%s/", + ap_get_server_name(r), + thisport)); + + errmsg = apr_psprintf(r->pool, + "Reason: You're speaking plain HTTP " + "to an SSL-enabled server port.<br />\n" + "Instead use the HTTPS scheme to access " + "this URL, please.<br />\n" + "<blockquote>Hint: " + "<a href=\"%s\"><b>%s</b></a></blockquote>", + thisurl, thisurl); + + apr_table_setn(r->notes, "error-notes", errmsg); + + /* Now that we have caught this error, forget it. we are done + * with using SSL on this request. + */ + sslconn->non_ssl_request = 0; + + + return HTTP_BAD_REQUEST; + } + + /* + * Get the SSL connection structure and perform the + * delayed interlinking from SSL back to request_rec + */ + ssl = sslconn->ssl; + if (!ssl) { + return DECLINED; + } + SSL_set_app_data2(ssl, r); + + /* + * Log information about incoming HTTPS requests + */ + if (r->server->loglevel >= APLOG_INFO && ap_is_initial_req(r)) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, + "%s HTTPS request received for child %ld (server %s)", + (r->connection->keepalives <= 0 ? + "Initial (No.1)" : + apr_psprintf(r->pool, "Subsequent (No.%d)", + r->connection->keepalives+1)), + r->connection->id, + ssl_util_vhostid(r->pool, r->server)); + } + + /* SetEnvIf ssl-*-shutdown flags can only be per-server, + * so they won't change across keepalive requests + */ + if (sslconn->shutdown_type == SSL_SHUTDOWN_TYPE_UNSET) { + ssl_configure_env(r, sslconn); + } + + return DECLINED; +} + +/* + * Move SetEnvIf information from request_rec to conn_rec/BUFF + * to allow the close connection handler to use them. + */ + +static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn) +{ + int i; + const apr_array_header_t *arr = apr_table_elts(r->subprocess_env); + const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts; + + sslconn->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD; + + for (i = 0; i < arr->nelts; i++) { + const char *key = elts[i].key; + + switch (*key) { + case 's': + /* being case-sensitive here. + * and not checking for the -shutdown since these are the only + * SetEnvIf "flags" we support + */ + if (!strncmp(key+1, "sl-", 3)) { + key += 4; + if (!strncmp(key, "unclean", 7)) { + sslconn->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN; + } + else if (!strncmp(key, "accurate", 8)) { + sslconn->shutdown_type = SSL_SHUTDOWN_TYPE_ACCURATE; + } + return; /* should only ever be one ssl-*-shutdown */ + } + break; + } + } +} + +/* + * Access Handler + */ +int ssl_hook_Access(request_rec *r) +{ + SSLDirConfigRec *dc = myDirConfig(r); + SSLSrvConfigRec *sc = mySrvConfig(r->server); + SSLConnRec *sslconn = myConnConfig(r->connection); + SSL *ssl = sslconn ? sslconn->ssl : NULL; + SSL_CTX *ctx = NULL; + apr_array_header_t *requires; + ssl_require_t *ssl_requires; + char *cp; + int ok, i; + BOOL renegotiate = FALSE, renegotiate_quick = FALSE; + X509 *cert; + X509 *peercert; + X509_STORE *cert_store = NULL; + X509_STORE_CTX cert_store_ctx; + STACK_OF(SSL_CIPHER) *cipher_list_old = NULL, *cipher_list = NULL; + SSL_CIPHER *cipher = NULL; + int depth, verify_old, verify, n; + + if (ssl) { + ctx = SSL_get_SSL_CTX(ssl); + } + + /* + * Support for SSLRequireSSL directive + */ + if (dc->bSSLRequired && !ssl) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "access to %s failed, reason: %s", + r->filename, "SSL connection required"); + + /* remember forbidden access for strict require option */ + apr_table_setn(r->notes, "ssl-access-forbidden", "1"); + + return HTTP_FORBIDDEN; + } + + /* + * Check to see whether SSL is in use; if it's not, then no + * further access control checks are relevant. (the test for + * sc->enabled is probably strictly unnecessary) + */ + if (!sc->enabled || !ssl) { + return DECLINED; + } + + /* + * Support for per-directory reconfigured SSL connection parameters. + * + * This is implemented by forcing an SSL renegotiation with the + * reconfigured parameter suite. But Apache's internal API processing + * makes our life very hard here, because when internal sub-requests occur + * we nevertheless should avoid multiple unnecessary SSL handshakes (they + * require extra network I/O and especially time to perform). + * + * But the optimization for filtering out the unnecessary handshakes isn't + * obvious and trivial. Especially because while Apache is in its + * sub-request processing the client could force additional handshakes, + * too. And these take place perhaps without our notice. So the only + * possibility is to explicitly _ask_ OpenSSL whether the renegotiation + * has to be performed or not. It has to performed when some parameters + * which were previously known (by us) are not those we've now + * reconfigured (as known by OpenSSL) or (in optimized way) at least when + * the reconfigured parameter suite is stronger (more restrictions) than + * the currently active one. + */ + + /* + * Override of SSLCipherSuite + * + * We provide two options here: + * + * o The paranoid and default approach where we force a renegotiation when + * the cipher suite changed in _any_ way (which is straight-forward but + * often forces renegotiations too often and is perhaps not what the + * user actually wanted). + * + * o The optimized and still secure way where we force a renegotiation + * only if the currently active cipher is no longer contained in the + * reconfigured/new cipher suite. Any other changes are not important + * because it's the servers choice to select a cipher from the ones the + * client supports. So as long as the current cipher is still in the new + * cipher suite we're happy. Because we can assume we would have + * selected it again even when other (better) ciphers exists now in the + * new cipher suite. This approach is fine because the user explicitly + * has to enable this via ``SSLOptions +OptRenegotiate''. So we do no + * implicit optimizations. + */ + if (dc->szCipherSuite) { + /* remember old state */ + + if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) { + cipher = SSL_get_current_cipher(ssl); + } + else { + cipher_list_old = (STACK_OF(SSL_CIPHER) *)SSL_get_ciphers(ssl); + + if (cipher_list_old) { + cipher_list_old = sk_SSL_CIPHER_dup(cipher_list_old); + } + } + + /* configure new state */ + if (!modssl_set_cipher_list(ssl, dc->szCipherSuite)) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, + r->server, + "Unable to reconfigure (per-directory) " + "permitted SSL ciphers"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); + + if (cipher_list_old) { + sk_SSL_CIPHER_free(cipher_list_old); + } + + return HTTP_FORBIDDEN; + } + + /* determine whether a renegotiation has to be forced */ + cipher_list = (STACK_OF(SSL_CIPHER) *)SSL_get_ciphers(ssl); + + if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) { + /* optimized way */ + if ((!cipher && cipher_list) || + (cipher && !cipher_list)) + { + renegotiate = TRUE; + } + else if (cipher && cipher_list && + (sk_SSL_CIPHER_find(cipher_list, cipher) < 0)) + { + renegotiate = TRUE; + } + } + else { + /* paranoid way */ + if ((!cipher_list_old && cipher_list) || + (cipher_list_old && !cipher_list)) + { + renegotiate = TRUE; + } + else if (cipher_list_old && cipher_list) { + for (n = 0; + !renegotiate && (n < sk_SSL_CIPHER_num(cipher_list)); + n++) + { + SSL_CIPHER *value = sk_SSL_CIPHER_value(cipher_list, n); + + if (sk_SSL_CIPHER_find(cipher_list_old, value) < 0) { + renegotiate = TRUE; + } + } + + for (n = 0; + !renegotiate && (n < sk_SSL_CIPHER_num(cipher_list_old)); + n++) + { + SSL_CIPHER *value = sk_SSL_CIPHER_value(cipher_list_old, n); + + if (sk_SSL_CIPHER_find(cipher_list, value) < 0) { + renegotiate = TRUE; + } + } + } + } + + /* cleanup */ + if (cipher_list_old) { + sk_SSL_CIPHER_free(cipher_list_old); + } + + /* tracing */ + if (renegotiate) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Reconfigured cipher suite will force renegotiation"); + } + } + + /* + * override of SSLVerifyDepth + * + * The depth checks are handled by us manually inside the verify callback + * function and not by OpenSSL internally (and our function is aware of + * both the per-server and per-directory contexts). So we cannot ask + * OpenSSL about the currently verify depth. Instead we remember it in our + * ap_ctx attached to the SSL* of OpenSSL. We've to force the + * renegotiation if the reconfigured/new verify depth is less than the + * currently active/remembered verify depth (because this means more + * restriction on the certificate chain). + */ + if (dc->nVerifyDepth != UNSET) { + /* XXX: doesnt look like sslconn->verify_depth is actually used */ + if (!(n = sslconn->verify_depth)) { + sslconn->verify_depth = n = sc->server->auth.verify_depth; + } + + /* determine whether a renegotiation has to be forced */ + if (dc->nVerifyDepth < n) { + renegotiate = TRUE; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Reduced client verification depth will force " + "renegotiation"); + } + } + + /* + * override of SSLVerifyClient + * + * We force a renegotiation if the reconfigured/new verify type is + * stronger than the currently active verify type. + * + * The order is: none << optional_no_ca << optional << require + * + * Additionally the following optimization is possible here: When the + * currently active verify type is "none" but a client certificate is + * already known/present, it's enough to manually force a client + * verification but at least skip the I/O-intensive renegotation + * handshake. + */ + if (dc->nVerifyClient != SSL_CVERIFY_UNSET) { + /* remember old state */ + verify_old = SSL_get_verify_mode(ssl); + /* configure new state */ + verify = SSL_VERIFY_NONE; + + if (dc->nVerifyClient == SSL_CVERIFY_REQUIRE) { + verify |= SSL_VERIFY_PEER_STRICT; + } + + if ((dc->nVerifyClient == SSL_CVERIFY_OPTIONAL) || + (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA)) + { + verify |= SSL_VERIFY_PEER; + } + + modssl_set_verify(ssl, verify, ssl_callback_SSLVerify); + SSL_set_verify_result(ssl, X509_V_OK); + + /* determine whether we've to force a renegotiation */ + if (!renegotiate && verify != verify_old) { + if (((verify_old == SSL_VERIFY_NONE) && + (verify != SSL_VERIFY_NONE)) || + + (!(verify_old & SSL_VERIFY_PEER) && + (verify & SSL_VERIFY_PEER)) || + + (!(verify_old & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) && + (verify & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) + { + renegotiate = TRUE; + /* optimization */ + + if ((dc->nOptions & SSL_OPT_OPTRENEGOTIATE) && + (verify_old == SSL_VERIFY_NONE) && + ((peercert = SSL_get_peer_certificate(ssl)) != NULL)) + { + renegotiate_quick = TRUE; + X509_free(peercert); + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, + r->server, + "Changed client verification type will force " + "%srenegotiation", + renegotiate_quick ? "quick " : ""); + } + } + } + + /* + * override SSLCACertificateFile & SSLCACertificatePath + * This is only enabled if the SSL_set_cert_store() function + * is available in the ssl library. the 1.x based mod_ssl + * used SSL_CTX_set_cert_store which is not thread safe. + */ + +#ifdef HAVE_SSL_SET_CERT_STORE + /* + * check if per-dir and per-server config field are not the same. + * if f is defined in per-dir and not defined in per-server + * or f is defined in both but not the equal ... + */ +#define MODSSL_CFG_NE(f) \ + (dc->f && (!sc->f || (sc->f && strNE(dc->f, sc->f)))) + +#define MODSSL_CFG_CA(f) \ + (dc->f ? dc->f : sc->f) + + if (MODSSL_CFG_NE(szCACertificateFile) || + MODSSL_CFG_NE(szCACertificatePath)) + { + STACK_OF(X509_NAME) *ca_list; + const char *ca_file = MODSSL_CFG_CA(szCACertificateFile); + const char *ca_path = MODSSL_CFG_CA(szCACertificatePath); + + cert_store = X509_STORE_new(); + + if (!X509_STORE_load_locations(cert_store, ca_file, ca_path)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Unable to reconfigure verify locations " + "for client authentication"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); + + X509_STORE_free(cert_store); + + return HTTP_FORBIDDEN; + } + + /* SSL_free will free cert_store */ + SSL_set_cert_store(ssl, cert_store); + + if (!(ca_list = ssl_init_FindCAList(r->server, r->pool, + ca_file, ca_path))) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Unable to determine list of available " + "CA certificates for client authentication"); + + return HTTP_FORBIDDEN; + } + + SSL_set_client_CA_list(ssl, ca_list); + renegotiate = TRUE; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Changed client verification locations will force " + "renegotiation"); + } +#endif /* HAVE_SSL_SET_CERT_STORE */ + + /* If a renegotiation is now required for this location, and the + * request includes a message body (and the client has not + * requested a "100 Continue" response), then the client will be + * streaming the request body over the wire already. In that + * case, it is not possible to stop and perform a new SSL + * handshake immediately; once the SSL library moves to the + * "accept" state, it will reject the SSL packets which the client + * is sending for the request body. + * + * To allow authentication to complete in this auth hook, the + * solution used here is to fill a (bounded) buffer with the + * request body, and then to reinject that request body later. + */ + if (renegotiate && !renegotiate_quick + && (apr_table_get(r->headers_in, "transfer-encoding") + || (apr_table_get(r->headers_in, "content-length") + && strcmp(apr_table_get(r->headers_in, "content-length"), "0"))) + && !r->expecting_100) { + int rv; + + /* Fill the I/O buffer with the request body if possible. */ + rv = ssl_io_buffer_fill(r); + + if (rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "could not buffer message body to allow " + "SSL renegotiation to proceed"); + return rv; + } + } + + /* + * now do the renegotiation if anything was actually reconfigured + */ + if (renegotiate) { + /* + * Now we force the SSL renegotation by sending the Hello Request + * message to the client. Here we have to do a workaround: Actually + * OpenSSL returns immediately after sending the Hello Request (the + * intent AFAIK is because the SSL/TLS protocol says it's not a must + * that the client replies to a Hello Request). But because we insist + * on a reply (anything else is an error for us) we have to go to the + * ACCEPT state manually. Using SSL_set_accept_state() doesn't work + * here because it resets too much of the connection. So we set the + * state explicitly and continue the handshake manually. + */ + ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, + "Requesting connection re-negotiation"); + + if (renegotiate_quick) { + STACK_OF(X509) *cert_stack; + + /* perform just a manual re-verification of the peer */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "Performing quick renegotiation: " + "just re-verifying the peer"); + + cert_stack = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl); + + cert = SSL_get_peer_certificate(ssl); + + if (!cert_stack && cert) { + /* client cert is in the session cache, but there is + * no chain, since ssl3_get_client_certificate() + * sk_X509_shift-ed the peer cert out of the chain. + * we put it back here for the purpose of quick_renegotiation. + */ + cert_stack = sk_new_null(); + sk_X509_push(cert_stack, MODSSL_PCHAR_CAST cert); + } + + if (!cert_stack || (sk_X509_num(cert_stack) == 0)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Cannot find peer certificate chain"); + + return HTTP_FORBIDDEN; + } + + if (!(cert_store || + (cert_store = SSL_CTX_get_cert_store(ctx)))) + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Cannot find certificate storage"); + + return HTTP_FORBIDDEN; + } + + if (!cert) { + cert = sk_X509_value(cert_stack, 0); + } + + X509_STORE_CTX_init(&cert_store_ctx, cert_store, cert, cert_stack); + depth = SSL_get_verify_depth(ssl); + + if (depth >= 0) { + X509_STORE_CTX_set_depth(&cert_store_ctx, depth); + } + + X509_STORE_CTX_set_ex_data(&cert_store_ctx, + SSL_get_ex_data_X509_STORE_CTX_idx(), + (char *)ssl); + + if (!modssl_X509_verify_cert(&cert_store_ctx)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Re-negotiation verification step failed"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); + } + + SSL_set_verify_result(ssl, cert_store_ctx.error); + X509_STORE_CTX_cleanup(&cert_store_ctx); + + if (cert_stack != SSL_get_peer_cert_chain(ssl)) { + /* we created this ourselves, so free it */ + sk_X509_pop_free(cert_stack, X509_free); + } + } + else { + request_rec *id = r->main ? r->main : r; + + /* Additional mitigation for CVE-2009-3555: At this point, + * before renegotiating, an (entire) request has been read + * from the connection. An attacker may have sent further + * data to "prefix" any subsequent request by the victim's + * client after the renegotiation; this data may already + * have been read and buffered. Forcing a connection + * closure after the response ensures such data will be + * discarded. Legimately pipelined HTTP requests will be + * retried anyway with this approach. */ + if (has_buffered_data(r)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "insecure SSL re-negotiation required, but " + "a pipelined request is present; keepalive " + "disabled"); + r->connection->keepalive = AP_CONN_CLOSE; + } + + /* Perform a full renegotiation. */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Performing full renegotiation: complete handshake " + "protocol (%s support secure renegotiation)", +#if defined(SSL_get_secure_renegotiation_support) + SSL_get_secure_renegotiation_support(ssl) ? + "client does" : "client does not" +#else + "server does not" +#endif + ); + + SSL_set_session_id_context(ssl, + (unsigned char *)&id, + sizeof(id)); + + /* Toggle the renegotiation state to allow the new + * handshake to proceed. */ + sslconn->reneg_state = RENEG_ALLOW; + + SSL_renegotiate(ssl); + SSL_do_handshake(ssl); + + if (SSL_get_state(ssl) != SSL_ST_OK) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Re-negotiation request failed"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server); + + r->connection->aborted = 1; + return HTTP_FORBIDDEN; + } + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, + "Awaiting re-negotiation handshake"); + + SSL_set_state(ssl, SSL_ST_ACCEPT); + SSL_do_handshake(ssl); + + sslconn->reneg_state = RENEG_REJECT; + + if (SSL_get_state(ssl) != SSL_ST_OK) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Re-negotiation handshake failed: " + "Not accepted by client!?"); + + r->connection->aborted = 1; + return HTTP_FORBIDDEN; + } + } + + /* + * Remember the peer certificate's DN + */ + if ((cert = SSL_get_peer_certificate(ssl))) { + if (sslconn->client_cert) { + X509_free(sslconn->client_cert); + } + sslconn->client_cert = cert; + sslconn->client_dn = NULL; + } + + /* + * Finally check for acceptable renegotiation results + */ + if (dc->nVerifyClient != SSL_CVERIFY_NONE) { + BOOL do_verify = (dc->nVerifyClient == SSL_CVERIFY_REQUIRE); + + if (do_verify && (SSL_get_verify_result(ssl) != X509_V_OK)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Re-negotiation handshake failed: " + "Client verification failed"); + + return HTTP_FORBIDDEN; + } + + if (do_verify) { + if ((peercert = SSL_get_peer_certificate(ssl)) == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "Re-negotiation handshake failed: " + "Client certificate missing"); + + return HTTP_FORBIDDEN; + } + + X509_free(peercert); + } + } + + /* + * Also check that SSLCipherSuite has been enforced as expected. + */ + if (cipher_list) { + cipher = SSL_get_current_cipher(ssl); + if (sk_SSL_CIPHER_find(cipher_list, cipher) < 0) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "SSL cipher suite not renegotiated: " + "access to %s denied using cipher %s", + r->filename, + SSL_CIPHER_get_name(cipher)); + return HTTP_FORBIDDEN; + } + } + } + + /* If we're trying to have the user name set from a client + * certificate then we need to set it here. This should be safe as + * the user name probably isn't important from an auth checking point + * of view as the certificate supplied acts in that capacity. + * However, if FakeAuth is being used then this isn't the case so + * we need to postpone setting the username until later. + */ + if ((dc->nOptions & SSL_OPT_FAKEBASICAUTH) == 0 && dc->szUserName) { + char *val = ssl_var_lookup(r->pool, r->server, r->connection, + r, (char *)dc->szUserName); + if (val && val[0]) + r->user = val; + } + + /* + * Check SSLRequire boolean expressions + */ + requires = dc->aRequirement; + ssl_requires = (ssl_require_t *)requires->elts; + + for (i = 0; i < requires->nelts; i++) { + ssl_require_t *req = &ssl_requires[i]; + ok = ssl_expr_exec(r, req->mpExpr); + + if (ok < 0) { + cp = apr_psprintf(r->pool, + "Failed to execute " + "SSL requirement expression: %s", + ssl_expr_get_error()); + + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "access to %s failed, reason: %s", + r->filename, cp); + + /* remember forbidden access for strict require option */ + apr_table_setn(r->notes, "ssl-access-forbidden", "1"); + + return HTTP_FORBIDDEN; + } + + if (ok != 1) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, + "Access to %s denied for %s " + "(requirement expression not fulfilled)", + r->filename, r->connection->remote_ip); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, + "Failed expression: %s", req->cpExpr); + + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "access to %s failed, reason: %s", + r->filename, + "SSL requirement expression not fulfilled " + "(see SSL logfile for more details)"); + + /* remember forbidden access for strict require option */ + apr_table_setn(r->notes, "ssl-access-forbidden", "1"); + + return HTTP_FORBIDDEN; + } + } + + /* + * Else access is granted from our point of view (except vendor + * handlers override). But we have to return DECLINED here instead + * of OK, because mod_auth and other modules still might want to + * deny access. + */ + + return DECLINED; +} + +/* + * Authentication Handler: + * Fake a Basic authentication from the X509 client certificate. + * + * This must be run fairly early on to prevent a real authentication from + * occuring, in particular it must be run before anything else that + * authenticates a user. This means that the Module statement for this + * module should be LAST in the Configuration file. + */ +int ssl_hook_UserCheck(request_rec *r) +{ + SSLConnRec *sslconn = myConnConfig(r->connection); + SSLSrvConfigRec *sc = mySrvConfig(r->server); + SSLDirConfigRec *dc = myDirConfig(r); + char *clientdn; + const char *auth_line, *username, *password; + + /* + * Additionally forbid access (again) + * when strict require option is used. + */ + if ((dc->nOptions & SSL_OPT_STRICTREQUIRE) && + (apr_table_get(r->notes, "ssl-access-forbidden"))) + { + return HTTP_FORBIDDEN; + } + + /* + * We decline when we are in a subrequest. The Authorization header + * would already be present if it was added in the main request. + */ + if (!ap_is_initial_req(r)) { + return DECLINED; + } + + /* + * Make sure the user is not able to fake the client certificate + * based authentication by just entering an X.509 Subject DN + * ("/XX=YYY/XX=YYY/..") as the username and "password" as the + * password. + */ + if ((auth_line = apr_table_get(r->headers_in, "Authorization"))) { + if (strcEQ(ap_getword(r->pool, &auth_line, ' '), "Basic")) { + while ((*auth_line == ' ') || (*auth_line == '\t')) { + auth_line++; + } + + auth_line = ap_pbase64decode(r->pool, auth_line); + username = ap_getword_nulls(r->pool, &auth_line, ':'); + password = auth_line; + + if ((username[0] == '/') && strEQ(password, "password")) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Encountered FakeBasicAuth spoof: %s", username); + return HTTP_FORBIDDEN; + } + } + } + + /* + * We decline operation in various situations... + * - SSLOptions +FakeBasicAuth not configured + * - r->user already authenticated + * - ssl not enabled + * - client did not present a certificate + */ + if (!(sc->enabled && sslconn && sslconn->ssl && sslconn->client_cert) || + !(dc->nOptions & SSL_OPT_FAKEBASICAUTH) || r->user) + { + return DECLINED; + } + + if (!sslconn->client_dn) { + X509_NAME *name = X509_get_subject_name(sslconn->client_cert); + char *cp = X509_NAME_oneline(name, NULL, 0); + sslconn->client_dn = apr_pstrdup(r->connection->pool, cp); + modssl_free(cp); + } + + clientdn = (char *)sslconn->client_dn; + + /* + * Fake a password - which one would be immaterial, as, it seems, an empty + * password in the users file would match ALL incoming passwords, if only + * we were using the standard crypt library routine. Unfortunately, OpenSSL + * "fixes" a "bug" in crypt and thus prevents blank passwords from + * working. (IMHO what they really fix is a bug in the users of the code + * - failing to program correctly for shadow passwords). We need, + * therefore, to provide a password. This password can be matched by + * adding the string "xxj31ZMTZzkVA" as the password in the user file. + * This is just the crypted variant of the word "password" ;-) + */ + auth_line = apr_pstrcat(r->pool, "Basic ", + ap_pbase64encode(r->pool, + apr_pstrcat(r->pool, clientdn, + ":password", NULL)), + NULL); + apr_table_set(r->headers_in, "Authorization", auth_line); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, + "Faking HTTP Basic Auth header: \"Authorization: %s\"", + auth_line); + + return DECLINED; +} + +/* authorization phase */ +int ssl_hook_Auth(request_rec *r) +{ + SSLDirConfigRec *dc = myDirConfig(r); + + /* + * Additionally forbid access (again) + * when strict require option is used. + */ + if ((dc->nOptions & SSL_OPT_STRICTREQUIRE) && + (apr_table_get(r->notes, "ssl-access-forbidden"))) + { + return HTTP_FORBIDDEN; + } + + return DECLINED; +} + +/* + * Fixup Handler + */ + +static const char *ssl_hook_Fixup_vars[] = { + "SSL_VERSION_INTERFACE", + "SSL_VERSION_LIBRARY", + "SSL_PROTOCOL", + "SSL_SECURE_RENEG", + "SSL_CIPHER", + "SSL_CIPHER_EXPORT", + "SSL_CIPHER_USEKEYSIZE", + "SSL_CIPHER_ALGKEYSIZE", + "SSL_CLIENT_VERIFY", + "SSL_CLIENT_M_VERSION", + "SSL_CLIENT_M_SERIAL", + "SSL_CLIENT_V_START", + "SSL_CLIENT_V_END", + "SSL_CLIENT_S_DN", + "SSL_CLIENT_S_DN_C", + "SSL_CLIENT_S_DN_ST", + "SSL_CLIENT_S_DN_L", + "SSL_CLIENT_S_DN_O", + "SSL_CLIENT_S_DN_OU", + "SSL_CLIENT_S_DN_CN", + "SSL_CLIENT_S_DN_T", + "SSL_CLIENT_S_DN_I", + "SSL_CLIENT_S_DN_G", + "SSL_CLIENT_S_DN_S", + "SSL_CLIENT_S_DN_D", + "SSL_CLIENT_S_DN_UID", + "SSL_CLIENT_S_DN_Email", + "SSL_CLIENT_I_DN", + "SSL_CLIENT_I_DN_C", + "SSL_CLIENT_I_DN_ST", + "SSL_CLIENT_I_DN_L", + "SSL_CLIENT_I_DN_O", + "SSL_CLIENT_I_DN_OU", + "SSL_CLIENT_I_DN_CN", + "SSL_CLIENT_I_DN_T", + "SSL_CLIENT_I_DN_I", + "SSL_CLIENT_I_DN_G", + "SSL_CLIENT_I_DN_S", + "SSL_CLIENT_I_DN_D", + "SSL_CLIENT_I_DN_UID", + "SSL_CLIENT_I_DN_Email", + "SSL_CLIENT_A_KEY", + "SSL_CLIENT_A_SIG", + "SSL_SERVER_M_VERSION", + "SSL_SERVER_M_SERIAL", + "SSL_SERVER_V_START", + "SSL_SERVER_V_END", + "SSL_SERVER_S_DN", + "SSL_SERVER_S_DN_C", + "SSL_SERVER_S_DN_ST", + "SSL_SERVER_S_DN_L", + "SSL_SERVER_S_DN_O", + "SSL_SERVER_S_DN_OU", + "SSL_SERVER_S_DN_CN", + "SSL_SERVER_S_DN_T", + "SSL_SERVER_S_DN_I", + "SSL_SERVER_S_DN_G", + "SSL_SERVER_S_DN_S", + "SSL_SERVER_S_DN_D", + "SSL_SERVER_S_DN_UID", + "SSL_SERVER_S_DN_Email", + "SSL_SERVER_I_DN", + "SSL_SERVER_I_DN_C", + "SSL_SERVER_I_DN_ST", + "SSL_SERVER_I_DN_L", + "SSL_SERVER_I_DN_O", + "SSL_SERVER_I_DN_OU", + "SSL_SERVER_I_DN_CN", + "SSL_SERVER_I_DN_T", + "SSL_SERVER_I_DN_I", + "SSL_SERVER_I_DN_G", + "SSL_SERVER_I_DN_S", + "SSL_SERVER_I_DN_D", + "SSL_SERVER_I_DN_UID", + "SSL_SERVER_I_DN_Email", + "SSL_SERVER_A_KEY", + "SSL_SERVER_A_SIG", + "SSL_SESSION_ID", + NULL +}; + +int ssl_hook_Fixup(request_rec *r) +{ + SSLConnRec *sslconn = myConnConfig(r->connection); + SSLSrvConfigRec *sc = mySrvConfig(r->server); + SSLDirConfigRec *dc = myDirConfig(r); + apr_table_t *env = r->subprocess_env; + char *var, *val = ""; + STACK_OF(X509) *peer_certs; + SSL *ssl; + int i; + + /* + * Check to see if SSL is on + */ + if (!(sc->enabled && sslconn && (ssl = sslconn->ssl))) { + return DECLINED; + } + + /* + * Annotate the SSI/CGI environment with standard SSL information + */ + /* the always present HTTPS (=HTTP over SSL) flag! */ + apr_table_setn(env, "HTTPS", "on"); + + /* standard SSL environment variables */ + if (dc->nOptions & SSL_OPT_STDENVVARS) { + for (i = 0; ssl_hook_Fixup_vars[i]; i++) { + var = (char *)ssl_hook_Fixup_vars[i]; + val = ssl_var_lookup(r->pool, r->server, r->connection, r, var); + if (!strIsEmpty(val)) { + apr_table_setn(env, var, val); + } + } + } + + /* + * On-demand bloat up the SSI/CGI environment with certificate data + */ + if (dc->nOptions & SSL_OPT_EXPORTCERTDATA) { + val = ssl_var_lookup(r->pool, r->server, r->connection, + r, "SSL_SERVER_CERT"); + + apr_table_setn(env, "SSL_SERVER_CERT", val); + + val = ssl_var_lookup(r->pool, r->server, r->connection, + r, "SSL_CLIENT_CERT"); + + apr_table_setn(env, "SSL_CLIENT_CERT", val); + + if ((peer_certs = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl))) { + for (i = 0; i < sk_X509_num(peer_certs); i++) { + var = apr_psprintf(r->pool, "SSL_CLIENT_CERT_CHAIN_%d", i); + val = ssl_var_lookup(r->pool, r->server, r->connection, + r, var); + if (val) { + apr_table_setn(env, var, val); + } + } + } + } + + +#ifdef SSL_get_secure_renegotiation_support + apr_table_setn(r->notes, "ssl-secure-reneg", + SSL_get_secure_renegotiation_support(ssl) ? "1" : "0"); +#endif + + return DECLINED; +} + +/* _________________________________________________________________ +** +** OpenSSL Callback Functions +** _________________________________________________________________ +*/ + +/* + * Handle out temporary RSA private keys on demand + * + * The background of this as the TLSv1 standard explains it: + * + * | D.1. Temporary RSA keys + * | + * | US Export restrictions limit RSA keys used for encryption to 512 + * | bits, but do not place any limit on lengths of RSA keys used for + * | signing operations. Certificates often need to be larger than 512 + * | bits, since 512-bit RSA keys are not secure enough for high-value + * | transactions or for applications requiring long-term security. Some + * | certificates are also designated signing-only, in which case they + * | cannot be used for key exchange. + * | + * | When the public key in the certificate cannot be used for encryption, + * | the server signs a temporary RSA key, which is then exchanged. In + * | exportable applications, the temporary RSA key should be the maximum + * | allowable length (i.e., 512 bits). Because 512-bit RSA keys are + * | relatively insecure, they should be changed often. For typical + * | electronic commerce applications, it is suggested that keys be + * | changed daily or every 500 transactions, and more often if possible. + * | Note that while it is acceptable to use the same temporary key for + * | multiple transactions, it must be signed each time it is used. + * | + * | RSA key generation is a time-consuming process. In many cases, a + * | low-priority process can be assigned the task of key generation. + * | Whenever a new key is completed, the existing temporary key can be + * | replaced with the new one. + * + * XXX: base on comment above, if thread support is enabled, + * we should spawn a low-priority thread to generate new keys + * on the fly. + * + * So we generated 512 and 1024 bit temporary keys on startup + * which we now just hand out on demand.... + */ + +RSA *ssl_callback_TmpRSA(SSL *ssl, int export, int keylen) +{ + conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); + SSLModConfigRec *mc = myModConfig(c->base_server); + int idx; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, + "handing out temporary %d bit RSA key", keylen); + + /* doesn't matter if export flag is on, + * we won't be asked for keylen > 512 in that case. + * if we are asked for a keylen > 1024, it is too expensive + * to generate on the fly. + * XXX: any reason not to generate 2048 bit keys at startup? + */ + + switch (keylen) { + case 512: + idx = SSL_TMP_KEY_RSA_512; + break; + + case 1024: + default: + idx = SSL_TMP_KEY_RSA_1024; + } + + return (RSA *)mc->pTmpKeys[idx]; +} + +/* + * Hand out the already generated DH parameters... + */ +DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen) +{ + conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); + SSLModConfigRec *mc = myModConfig(c->base_server); + int idx; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, + "handing out temporary %d bit DH key", keylen); + + switch (keylen) { + case 512: + idx = SSL_TMP_KEY_DH_512; + break; + + case 1024: + default: + idx = SSL_TMP_KEY_DH_1024; + } + + return (DH *)mc->pTmpKeys[idx]; +} + +/* + * This OpenSSL callback function is called when OpenSSL + * does client authentication and verifies the certificate chain. + */ +int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx) +{ + /* Get Apache context back through OpenSSL context */ + SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl); + server_rec *s = conn->base_server; + request_rec *r = (request_rec *)SSL_get_app_data2(ssl); + + SSLSrvConfigRec *sc = mySrvConfig(s); + SSLDirConfigRec *dc = r ? myDirConfig(r) : NULL; + SSLConnRec *sslconn = myConnConfig(conn); + modssl_ctx_t *mctx = myCtxConfig(sslconn, sc); + + /* Get verify ingredients */ + int errnum = X509_STORE_CTX_get_error(ctx); + int errdepth = X509_STORE_CTX_get_error_depth(ctx); + int depth, verify; + + /* + * Log verification information + */ + if (s->loglevel >= APLOG_DEBUG) { + X509 *cert = X509_STORE_CTX_get_current_cert(ctx); + char *sname = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); + char *iname = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Certificate Verification: " + "depth: %d, subject: %s, issuer: %s", + errdepth, + sname ? sname : "-unknown-", + iname ? iname : "-unknown-"); + + if (sname) { + modssl_free(sname); + } + + if (iname) { + modssl_free(iname); + } + } + + /* + * Check for optionally acceptable non-verifiable issuer situation + */ + if (dc && (dc->nVerifyClient != SSL_CVERIFY_UNSET)) { + verify = dc->nVerifyClient; + } + else { + verify = mctx->auth.verify_mode; + } + + if (verify == SSL_CVERIFY_NONE) { + /* + * SSLProxyVerify is either not configured or set to "none". + * (this callback doesn't happen in the server context if SSLVerify + * is not configured or set to "none") + */ + return TRUE; + } + + if (ssl_verify_error_is_optional(errnum) && + (verify == SSL_CVERIFY_OPTIONAL_NO_CA)) + { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Certificate Verification: Verifiable Issuer is " + "configured as optional, therefore we're accepting " + "the certificate"); + + sslconn->verify_info = "GENEROUS"; + ok = TRUE; + } + + /* + * Additionally perform CRL-based revocation checks + */ + if (ok) { + if (!(ok = ssl_callback_SSLVerify_CRL(ok, ctx, conn))) { + errnum = X509_STORE_CTX_get_error(ctx); + } + } + + /* + * If we already know it's not ok, log the real reason + */ + if (!ok) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Certificate Verification: Error (%d): %s", + errnum, X509_verify_cert_error_string(errnum)); + + if (sslconn->client_cert) { + X509_free(sslconn->client_cert); + sslconn->client_cert = NULL; + } + sslconn->client_dn = NULL; + sslconn->verify_error = X509_verify_cert_error_string(errnum); + } + + /* + * Finally check the depth of the certificate verification + */ + if (dc && (dc->nVerifyDepth != UNSET)) { + depth = dc->nVerifyDepth; + } + else { + depth = mctx->auth.verify_depth; + } + + if (errdepth > depth) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Certificate Verification: Certificate Chain too long " + "(chain has %d certificates, but maximum allowed are " + "only %d)", + errdepth, depth); + + errnum = X509_V_ERR_CERT_CHAIN_TOO_LONG; + sslconn->verify_error = X509_verify_cert_error_string(errnum); + + ok = FALSE; + } + + /* + * And finally signal OpenSSL the (perhaps changed) state + */ + return ok; +} + +int ssl_callback_SSLVerify_CRL(int ok, X509_STORE_CTX *ctx, conn_rec *c) +{ + server_rec *s = c->base_server; + SSLSrvConfigRec *sc = mySrvConfig(s); + SSLConnRec *sslconn = myConnConfig(c); + modssl_ctx_t *mctx = myCtxConfig(sslconn, sc); + X509_OBJECT obj; + X509_NAME *subject, *issuer; + X509 *cert; + X509_CRL *crl; + EVP_PKEY *pubkey; + int i, n, rc; + + /* + * Unless a revocation store for CRLs was created we + * cannot do any CRL-based verification, of course. + */ + if (!mctx->crl) { + return ok; + } + + /* + * Determine certificate ingredients in advance + */ + cert = X509_STORE_CTX_get_current_cert(ctx); + subject = X509_get_subject_name(cert); + issuer = X509_get_issuer_name(cert); + + /* + * OpenSSL provides the general mechanism to deal with CRLs but does not + * use them automatically when verifying certificates, so we do it + * explicitly here. We will check the CRL for the currently checked + * certificate, if there is such a CRL in the store. + * + * We come through this procedure for each certificate in the certificate + * chain, starting with the root-CA's certificate. At each step we've to + * both verify the signature on the CRL (to make sure it's a valid CRL) + * and it's revocation list (to make sure the current certificate isn't + * revoked). But because to check the signature on the CRL we need the + * public key of the issuing CA certificate (which was already processed + * one round before), we've a little problem. But we can both solve it and + * at the same time optimize the processing by using the following + * verification scheme (idea and code snippets borrowed from the GLOBUS + * project): + * + * 1. We'll check the signature of a CRL in each step when we find a CRL + * through the _subject_ name of the current certificate. This CRL + * itself will be needed the first time in the next round, of course. + * But we do the signature processing one round before this where the + * public key of the CA is available. + * + * 2. We'll check the revocation list of a CRL in each step when + * we find a CRL through the _issuer_ name of the current certificate. + * This CRLs signature was then already verified one round before. + * + * This verification scheme allows a CA to revoke its own certificate as + * well, of course. + */ + + /* + * Try to retrieve a CRL corresponding to the _subject_ of + * the current certificate in order to verify it's integrity. + */ + memset((char *)&obj, 0, sizeof(obj)); + rc = SSL_X509_STORE_lookup(mctx->crl, + X509_LU_CRL, subject, &obj); + crl = obj.data.crl; + + if ((rc > 0) && crl) { + /* + * Log information about CRL + * (A little bit complicated because of ASN.1 and BIOs...) + */ + if (s->loglevel >= APLOG_DEBUG) { + char buff[512]; /* should be plenty */ + BIO *bio = BIO_new(BIO_s_mem()); + + BIO_printf(bio, "CA CRL: Issuer: "); + X509_NAME_print(bio, issuer, 0); + + BIO_printf(bio, ", lastUpdate: "); + ASN1_UTCTIME_print(bio, X509_CRL_get_lastUpdate(crl)); + + BIO_printf(bio, ", nextUpdate: "); + ASN1_UTCTIME_print(bio, X509_CRL_get_nextUpdate(crl)); + + n = BIO_read(bio, buff, sizeof(buff) - 1); + buff[n] = '\0'; + + BIO_free(bio); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, buff); + } + + /* + * Verify the signature on this CRL + */ + pubkey = X509_get_pubkey(cert); + rc = X509_CRL_verify(crl, pubkey); +#ifdef OPENSSL_VERSION_NUMBER + /* Only refcounted in OpenSSL */ + if (pubkey) + EVP_PKEY_free(pubkey); +#endif + if (rc <= 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "Invalid signature on CRL"); + + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); + X509_OBJECT_free_contents(&obj); + return FALSE; + } + + /* + * Check date of CRL to make sure it's not expired + */ + i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)); + + if (i == 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "Found CRL has invalid nextUpdate field"); + + X509_STORE_CTX_set_error(ctx, + X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); + X509_OBJECT_free_contents(&obj); + + return FALSE; + } + + if (i < 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "Found CRL is expired - " + "revoking all certificates until you get updated CRL"); + + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED); + X509_OBJECT_free_contents(&obj); + + return FALSE; + } + + X509_OBJECT_free_contents(&obj); + } + + /* + * Try to retrieve a CRL corresponding to the _issuer_ of + * the current certificate in order to check for revocation. + */ + memset((char *)&obj, 0, sizeof(obj)); + rc = SSL_X509_STORE_lookup(mctx->crl, + X509_LU_CRL, issuer, &obj); + + crl = obj.data.crl; + if ((rc > 0) && crl) { + /* + * Check if the current certificate is revoked by this CRL + */ + n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); + + for (i = 0; i < n; i++) { + X509_REVOKED *revoked = + sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); + + ASN1_INTEGER *sn = X509_REVOKED_get_serialNumber(revoked); + + if (!ASN1_INTEGER_cmp(sn, X509_get_serialNumber(cert))) { + if (s->loglevel >= APLOG_DEBUG) { + char *cp = X509_NAME_oneline(issuer, NULL, 0); + long serial = ASN1_INTEGER_get(sn); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Certificate with serial %ld (0x%lX) " + "revoked per CRL from issuer %s", + serial, serial, cp); + modssl_free(cp); + } + + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED); + X509_OBJECT_free_contents(&obj); + + return FALSE; + } + } + + X509_OBJECT_free_contents(&obj); + } + + return ok; +} + +#define SSLPROXY_CERT_CB_LOG_FMT \ + "Proxy client certificate callback: (%s) " + +static void modssl_proxy_info_log(server_rec *s, + X509_INFO *info, + const char *msg) +{ + SSLSrvConfigRec *sc = mySrvConfig(s); + char name_buf[256]; + X509_NAME *name; + char *dn; + + if (s->loglevel < APLOG_DEBUG) { + return; + } + + name = X509_get_subject_name(info->x509); + dn = X509_NAME_oneline(name, name_buf, sizeof(name_buf)); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + SSLPROXY_CERT_CB_LOG_FMT "%s, sending %s", + sc->vhost_id, msg, dn ? dn : "-uknown-"); +} + +/* + * caller will decrement the cert and key reference + * so we need to increment here to prevent them from + * being freed. + */ +#define modssl_set_cert_info(info, cert, pkey) \ + *cert = info->x509; \ + X509_reference_inc(*cert); \ + *pkey = info->x_pkey->dec_pkey; \ + EVP_PKEY_reference_inc(*pkey) + +int ssl_callback_proxy_cert(SSL *ssl, MODSSL_CLIENT_CERT_CB_ARG_TYPE **x509, EVP_PKEY **pkey) +{ + conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); + server_rec *s = c->base_server; + SSLSrvConfigRec *sc = mySrvConfig(s); + X509_NAME *ca_name, *issuer; + X509_INFO *info; + STACK_OF(X509_NAME) *ca_list; + STACK_OF(X509_INFO) *certs = sc->proxy->pkp->certs; + int i, j; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + SSLPROXY_CERT_CB_LOG_FMT "entered", + sc->vhost_id); + + if (!certs || (sk_X509_INFO_num(certs) <= 0)) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + SSLPROXY_CERT_CB_LOG_FMT + "downstream server wanted client certificate " + "but none are configured", sc->vhost_id); + return FALSE; + } + + ca_list = SSL_get_client_CA_list(ssl); + + if (!ca_list || (sk_X509_NAME_num(ca_list) <= 0)) { + /* + * downstream server didn't send us a list of acceptable CA certs, + * so we send the first client cert in the list. + */ + info = sk_X509_INFO_value(certs, 0); + + modssl_proxy_info_log(s, info, "no acceptable CA list"); + + modssl_set_cert_info(info, x509, pkey); + + return TRUE; + } + + for (i = 0; i < sk_X509_NAME_num(ca_list); i++) { + ca_name = sk_X509_NAME_value(ca_list, i); + + for (j = 0; j < sk_X509_INFO_num(certs); j++) { + info = sk_X509_INFO_value(certs, j); + issuer = X509_get_issuer_name(info->x509); + + if (X509_NAME_cmp(issuer, ca_name) == 0) { + modssl_proxy_info_log(s, info, "found acceptable cert"); + + modssl_set_cert_info(info, x509, pkey); + + return TRUE; + } + } + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + SSLPROXY_CERT_CB_LOG_FMT + "no client certificate found!?", sc->vhost_id); + + return FALSE; +} + +static void ssl_session_log(server_rec *s, + const char *request, + unsigned char *id, + unsigned int idlen, + const char *status, + const char *result, + long timeout) +{ + char buf[SSL_SESSION_ID_STRING_LEN]; + char timeout_str[56] = {'\0'}; + + if (s->loglevel < APLOG_DEBUG) { + return; + } + + if (timeout) { + apr_snprintf(timeout_str, sizeof(timeout_str), + "timeout=%lds ", (timeout - time(NULL))); + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Inter-Process Session Cache: " + "request=%s status=%s id=%s %s(session %s)", + request, status, + SSL_SESSION_id2sz(id, idlen, buf, sizeof(buf)), + timeout_str, result); +} + +/* + * This callback function is executed by OpenSSL whenever a new SSL_SESSION is + * added to the internal OpenSSL session cache. We use this hook to spread the + * SSL_SESSION also to the inter-process disk-cache to make share it with our + * other Apache pre-forked server processes. + */ +int ssl_callback_NewSessionCacheEntry(SSL *ssl, SSL_SESSION *session) +{ + /* Get Apache context back through OpenSSL context */ + conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl); + server_rec *s = conn->base_server; + SSLSrvConfigRec *sc = mySrvConfig(s); + long timeout = sc->session_cache_timeout; + BOOL rc; + unsigned char *id; + unsigned int idlen; + + /* + * Set the timeout also for the internal OpenSSL cache, because this way + * our inter-process cache is consulted only when it's really necessary. + */ + SSL_set_timeout(session, timeout); + + /* + * Store the SSL_SESSION in the inter-process cache with the + * same expire time, so it expires automatically there, too. + */ + id = SSL_SESSION_get_session_id(session); + idlen = SSL_SESSION_get_session_id_length(session); + + timeout += modssl_session_get_time(session); + + rc = ssl_scache_store(s, id, idlen, timeout, session); + + ssl_session_log(s, "SET", id, idlen, + rc == TRUE ? "OK" : "BAD", + "caching", timeout); + + /* + * return 0 which means to OpenSSL that the session is still + * valid and was not freed by us with SSL_SESSION_free(). + */ + return 0; +} + +/* + * This callback function is executed by OpenSSL whenever a + * SSL_SESSION is looked up in the internal OpenSSL cache and it + * was not found. We use this to lookup the SSL_SESSION in the + * inter-process disk-cache where it was perhaps stored by one + * of our other Apache pre-forked server processes. + */ +SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *ssl, + unsigned char *id, + int idlen, int *do_copy) +{ + /* Get Apache context back through OpenSSL context */ + conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl); + server_rec *s = conn->base_server; + SSL_SESSION *session; + + /* + * Try to retrieve the SSL_SESSION from the inter-process cache + */ + session = ssl_scache_retrieve(s, id, idlen); + + ssl_session_log(s, "GET", id, idlen, + session ? "FOUND" : "MISSED", + session ? "reuse" : "renewal", 0); + + /* + * Return NULL or the retrieved SSL_SESSION. But indicate (by + * setting do_copy to 0) that the reference count on the + * SSL_SESSION should not be incremented by the SSL library, + * because we will no longer hold a reference to it ourself. + */ + *do_copy = 0; + + return session; +} + +/* + * This callback function is executed by OpenSSL whenever a + * SSL_SESSION is removed from the the internal OpenSSL cache. + * We use this to remove the SSL_SESSION in the inter-process + * disk-cache, too. + */ +void ssl_callback_DelSessionCacheEntry(SSL_CTX *ctx, + SSL_SESSION *session) +{ + server_rec *s; + SSLSrvConfigRec *sc; + unsigned char *id; + unsigned int idlen; + + /* + * Get Apache context back through OpenSSL context + */ + if (!(s = (server_rec *)SSL_CTX_get_app_data(ctx))) { + return; /* on server shutdown Apache is already gone */ + } + + sc = mySrvConfig(s); + + /* + * Remove the SSL_SESSION from the inter-process cache + */ + id = SSL_SESSION_get_session_id(session); + idlen = SSL_SESSION_get_session_id_length(session); + + ssl_scache_remove(s, id, idlen); + + ssl_session_log(s, "REM", id, idlen, + "OK", "dead", 0); + + return; +} + +/* Dump debugginfo trace to the log file. */ +static void log_tracing_state(MODSSL_INFO_CB_ARG_TYPE ssl, conn_rec *c, + server_rec *s, int where, int rc) +{ + /* + * create the various trace messages + */ + if (where & SSL_CB_HANDSHAKE_START) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: Handshake: start", SSL_LIBRARY_NAME); + } + else if (where & SSL_CB_HANDSHAKE_DONE) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: Handshake: done", SSL_LIBRARY_NAME); + } + else if (where & SSL_CB_LOOP) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: Loop: %s", + SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); + } + else if (where & SSL_CB_READ) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: Read: %s", + SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); + } + else if (where & SSL_CB_WRITE) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: Write: %s", + SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); + } + else if (where & SSL_CB_ALERT) { + char *str = (where & SSL_CB_READ) ? "read" : "write"; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: Alert: %s:%s:%s", + SSL_LIBRARY_NAME, str, + SSL_alert_type_string_long(rc), + SSL_alert_desc_string_long(rc)); + } + else if (where & SSL_CB_EXIT) { + if (rc == 0) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: Exit: failed in %s", + SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); + } + else if (rc < 0) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "%s: Exit: error in %s", + SSL_LIBRARY_NAME, SSL_state_string_long(ssl)); + } + } + + /* + * Because SSL renegotations can happen at any time (not only after + * SSL_accept()), the best way to log the current connection details is + * right after a finished handshake. + */ + if (where & SSL_CB_HANDSHAKE_DONE) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Connection: Client IP: %s, Protocol: %s, " + "Cipher: %s (%s/%s bits)", + ssl_var_lookup(NULL, s, c, NULL, "REMOTE_ADDR"), + ssl_var_lookup(NULL, s, c, NULL, "SSL_PROTOCOL"), + ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER"), + ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER_USEKEYSIZE"), + ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER_ALGKEYSIZE")); + } +} + +/* + * This callback function is executed while OpenSSL processes the SSL + * handshake and does SSL record layer stuff. It's used to trap + * client-initiated renegotiations, and for dumping everything to the + * log. + */ +void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc) +{ + conn_rec *c; + server_rec *s; + SSLConnRec *scr; + + /* Retrieve the conn_rec and the associated SSLConnRec. */ + if ((c = (conn_rec *)SSL_get_app_data((SSL *)ssl)) == NULL) { + return; + } + + if ((scr = myConnConfig(c)) == NULL) { + return; + } + + /* If the reneg state is to reject renegotiations, check the SSL + * state machine and move to ABORT if a Client Hello is being + * read. */ + if ((where & SSL_CB_ACCEPT_LOOP) && scr->reneg_state == RENEG_REJECT) { + int state = SSL_get_state((SSL *)ssl); + + if (state == SSL3_ST_SR_CLNT_HELLO_A + || state == SSL23_ST_SR_CLNT_HELLO_A) { + scr->reneg_state = RENEG_ABORT; + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, + "rejecting client initiated renegotiation"); + } + } + /* If the first handshake is complete, change state to reject any + * subsequent client-initated renegotiation. */ + else if ((where & SSL_CB_HANDSHAKE_DONE) && scr->reneg_state == RENEG_INIT) { + scr->reneg_state = RENEG_REJECT; + } + + s = c->base_server; + if (s && s->loglevel >= APLOG_DEBUG) { + log_tracing_state(ssl, c, s, where, rc); + } +} diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_log.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_log.c new file mode 100644 index 00000000..5ca1b6c0 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_log.c @@ -0,0 +1,101 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_log.c + * Logging Facility + */ + /* ``The difference between a computer + industry job and open-source software + hacking is about 30 hours a week.'' + -- Ralf S. Engelschall */ +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** Logfile Support +** _________________________________________________________________ +*/ + +static const struct { + const char *cpPattern; + const char *cpAnnotation; +} ssl_log_annotate[] = { + { "*envelope*bad*decrypt*", "wrong pass phrase!?" }, + { "*CLIENT_HELLO*unknown*protocol*", "speaking not SSL to HTTPS port!?" }, + { "*CLIENT_HELLO*http*request*", "speaking HTTP to HTTPS port!?" }, + { "*SSL3_READ_BYTES:sslv3*alert*bad*certificate*", "Subject CN in certificate not server name or identical to CA!?" }, + { "*self signed certificate in certificate chain*", "Client certificate signed by CA not known to server?" }, + { "*peer did not return a certificate*", "No CAs known to server for verification?" }, + { "*no shared cipher*", "Too restrictive SSLCipherSuite or using DSA server certificate?" }, + { "*no start line*", "Bad file contents or format - or even just a forgotten SSLCertificateKeyFile?" }, + { "*bad password read*", "You entered an incorrect pass phrase!?" }, + { "*bad mac decode*", "Browser still remembered details of a re-created server certificate?" }, + { NULL, NULL } +}; + +static const char *ssl_log_annotation(const char *error) +{ + int i = 0; + + while (ssl_log_annotate[i].cpPattern != NULL + && ap_strcmp_match(error, ssl_log_annotate[i].cpPattern) != 0) + i++; + + return ssl_log_annotate[i].cpAnnotation; +} + +void ssl_die(void) +{ + /* + * This is used for fatal errors and here + * it is common module practice to really + * exit from the complete program. + */ + exit(1); +} + +/* + * Prints the SSL library error information. + */ +void ssl_log_ssl_error(const char *file, int line, int level, server_rec *s) +{ + unsigned long e; + + while ((e = ERR_get_error())) { + const char *annotation; + char err[256]; + + ERR_error_string_n(e, err, sizeof err); + annotation = ssl_log_annotation(err); + + if (annotation) { + ap_log_error(file, line, level, 0, s, + "SSL Library Error: %lu %s %s", + e, err, annotation); + } + else { + ap_log_error(file, line, level, 0, s, + "SSL Library Error: %lu %s", + e, err); + } + } +} diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_mutex.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_mutex.c new file mode 100644 index 00000000..1e65f4fe --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_mutex.c @@ -0,0 +1,120 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_mutex.c + * Semaphore for Mutual Exclusion + */ + /* ``Real programmers confuse + Christmas and Halloween + because DEC 25 = OCT 31.'' + -- Unknown */ + +#include "mod_ssl.h" +#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) +#include "unixd.h" +#define MOD_SSL_SET_MUTEX_PERMS /* XXX Apache should define something */ +#endif + +int ssl_mutex_init(server_rec *s, apr_pool_t *p) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_status_t rv; + + if (mc->nMutexMode == SSL_MUTEXMODE_NONE) + return TRUE; + + if ((rv = apr_global_mutex_create(&mc->pMutex, mc->szMutexFile, + mc->nMutexMech, p)) != APR_SUCCESS) { + if (mc->szMutexFile) + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot create SSLMutex with file `%s'", + mc->szMutexFile); + else + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot create SSLMutex"); + return FALSE; + } + +#ifdef MOD_SSL_SET_MUTEX_PERMS + rv = unixd_set_global_mutex_perms(mc->pMutex); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Could not set permissions on ssl_mutex; check User " + "and Group directives"); + return FALSE; + } +#endif + return TRUE; +} + +int ssl_mutex_reinit(server_rec *s, apr_pool_t *p) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_status_t rv; + + if (mc->nMutexMode == SSL_MUTEXMODE_NONE) + return TRUE; + + if ((rv = apr_global_mutex_child_init(&mc->pMutex, + mc->szMutexFile, p)) != APR_SUCCESS) { + if (mc->szMutexFile) + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot reinit SSLMutex with file `%s'", + mc->szMutexFile); + else + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, + "Cannot reinit SSLMutex"); + return FALSE; + } + return TRUE; +} + +int ssl_mutex_on(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_status_t rv; + + if (mc->nMutexMode == SSL_MUTEXMODE_NONE) + return TRUE; + if ((rv = apr_global_mutex_lock(mc->pMutex)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, + "Failed to acquire global mutex lock"); + return FALSE; + } + return TRUE; +} + +int ssl_mutex_off(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_status_t rv; + + if (mc->nMutexMode == SSL_MUTEXMODE_NONE) + return TRUE; + if ((rv = apr_global_mutex_unlock(mc->pMutex)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, + "Failed to release global mutex lock"); + return FALSE; + } + return TRUE; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_pphrase.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_pphrase.c new file mode 100644 index 00000000..1ca3f32f --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_pphrase.c @@ -0,0 +1,789 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_pphrase.c + * Pass Phrase Dialog + */ + /* ``Treat your password like your + toothbrush. Don't let anybody + else use it, and get a new one + every six months.'' + -- Clifford Stoll */ +#include "mod_ssl.h" + +/* + * Return true if the named file exists and is readable + */ + +static apr_status_t exists_and_readable(char *fname, apr_pool_t *pool, apr_time_t *mtime) +{ + apr_status_t stat; + apr_finfo_t sbuf; + apr_file_t *fd; + + if ((stat = apr_stat(&sbuf, fname, APR_FINFO_MIN, pool)) != APR_SUCCESS) + return stat; + + if (sbuf.filetype != APR_REG) + return APR_EGENERAL; + + if ((stat = apr_file_open(&fd, fname, APR_READ, 0, pool)) != APR_SUCCESS) + return stat; + + if (mtime) { + *mtime = sbuf.mtime; + } + + apr_file_close(fd); + return APR_SUCCESS; +} + +/* + * reuse vhost keys for asn1 tables where keys are allocated out + * of s->process->pool to prevent "leaking" each time we format + * a vhost key. since the key is stored in a table with lifetime + * of s->process->pool, the key needs to have the same lifetime. + * + * XXX: probably seems silly to use a hash table with keys and values + * being the same, but it is easier than doing a linear search + * and will make it easier to remove keys if needed in the future. + * also have the problem with apr_array_header_t that if we + * underestimate the number of vhost keys when we apr_array_make(), + * the array will get resized when we push past the initial number + * of elts. this resizing in the s->process->pool means "leaking" + * since apr_array_push() will apr_alloc arr->nalloc * 2 elts, + * leaving the original arr->elts to waste. + */ +static char *asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p, + char *id, char *an) +{ + /* 'p' pool used here is cleared on restarts (or sooner) */ + char *key = apr_psprintf(p, "%s:%s", id, an); + void *keyptr = apr_hash_get(mc->tVHostKeys, key, + APR_HASH_KEY_STRING); + + if (!keyptr) { + /* make a copy out of s->process->pool */ + keyptr = apr_pstrdup(mc->pPool, key); + apr_hash_set(mc->tVHostKeys, keyptr, + APR_HASH_KEY_STRING, keyptr); + } + + return (char *)keyptr; +} + +/* _________________________________________________________________ +** +** Pass Phrase and Private Key Handling +** _________________________________________________________________ +*/ + +#define BUILTIN_DIALOG_BACKOFF 2 +#define BUILTIN_DIALOG_RETRIES 5 + +static apr_file_t *writetty = NULL; +static apr_file_t *readtty = NULL; + +/* + * sslc has a nasty flaw where its + * PEM_read_bio_PrivateKey does not take a callback arg. + */ +static server_rec *ssl_pphrase_server_rec = NULL; + +#ifdef SSLC_VERSION_NUMBER +int ssl_pphrase_Handle_CB(char *, int, int); +#else +int ssl_pphrase_Handle_CB(char *, int, int, void *); +#endif + +static char *pphrase_array_get(apr_array_header_t *arr, int idx) +{ + if ((idx < 0) || (idx >= arr->nelts)) { + return NULL; + } + + return ((char **)arr->elts)[idx]; +} + +static void pphrase_array_clear(apr_array_header_t *arr) +{ + if (arr->nelts > 0) { + memset(arr->elts, 0, arr->elt_size * arr->nelts); + } + arr->nelts = 0; +} + +void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) +{ + SSLModConfigRec *mc = myModConfig(s); + SSLSrvConfigRec *sc; + server_rec *pServ; + char *cpVHostID; + char szPath[MAX_STRING_LEN]; + EVP_PKEY *pPrivateKey; + ssl_asn1_t *asn1; + unsigned char *ucp; + long int length; + X509 *pX509Cert; + BOOL bReadable; + apr_array_header_t *aPassPhrase; + int nPassPhrase; + int nPassPhraseCur; + char *cpPassPhraseCur; + int nPassPhraseRetry; + int nPassPhraseDialog; + int nPassPhraseDialogCur; + BOOL bPassPhraseDialogOnce; + char **cpp; + int i, j; + ssl_algo_t algoCert, algoKey, at; + char *an; + char *cp; + apr_time_t pkey_mtime = 0; + int isterm = 1; + apr_status_t rv; + /* + * Start with a fresh pass phrase array + */ + aPassPhrase = apr_array_make(p, 2, sizeof(char *)); + nPassPhrase = 0; + nPassPhraseDialog = 0; + + /* + * Walk through all configured servers + */ + for (pServ = s; pServ != NULL; pServ = pServ->next) { + sc = mySrvConfig(pServ); + + if (!sc->enabled) + continue; + + cpVHostID = ssl_util_vhostid(p, pServ); + ap_log_error(APLOG_MARK, APLOG_INFO, 0, pServ, + "Loading certificate & private key of SSL-aware server"); + + /* + * Read in server certificate(s): This is the easy part + * because this file isn't encrypted in any way. + */ + if (sc->server->pks->cert_files[0] == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, pServ, + "Server should be SSL-aware but has no certificate " + "configured [Hint: SSLCertificateFile]"); + ssl_die(); + } + algoCert = SSL_ALGO_UNKNOWN; + algoKey = SSL_ALGO_UNKNOWN; + for (i = 0, j = 0; i < SSL_AIDX_MAX && sc->server->pks->cert_files[i] != NULL; i++) { + + apr_cpystrn(szPath, sc->server->pks->cert_files[i], sizeof(szPath)); + if ((rv = exists_and_readable(szPath, p, NULL)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Init: Can't open server certificate file %s", + szPath); + ssl_die(); + } + if ((pX509Cert = SSL_read_X509(szPath, NULL, NULL)) == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Unable to read server certificate from file %s", szPath); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + + /* + * check algorithm type of certificate and make + * sure only one certificate per type is used. + */ + at = ssl_util_algotypeof(pX509Cert, NULL); + an = ssl_util_algotypestr(at); + if (algoCert & at) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Multiple %s server certificates not " + "allowed", an); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + algoCert |= at; + + /* + * Insert the certificate into global module configuration to let it + * survive the processing between the 1st Apache API init round (where + * we operate here) and the 2nd Apache init round (where the + * certificate is actually used to configure mod_ssl's per-server + * configuration structures). + */ + cp = asn1_table_vhost_key(mc, p, cpVHostID, an); + length = i2d_X509(pX509Cert, NULL); + ucp = ssl_asn1_table_set(mc->tPublicCert, cp, length); + (void)i2d_X509(pX509Cert, &ucp); /* 2nd arg increments */ + + /* + * Free the X509 structure + */ + X509_free(pX509Cert); + + /* + * Read in the private key: This is the non-trivial part, because the + * key is typically encrypted, so a pass phrase dialog has to be used + * to request it from the user (or it has to be alternatively gathered + * from a dialog program). The important point here is that ISPs + * usually have hundrets of virtual servers configured and a lot of + * them use SSL, so really we have to minimize the pass phrase + * dialogs. + * + * The idea is this: When N virtual hosts are configured and all of + * them use encrypted private keys with different pass phrases, we + * have no chance and have to pop up N pass phrase dialogs. But + * usually the admin is clever enough and uses the same pass phrase + * for more private key files (typically he even uses one single pass + * phrase for all). When this is the case we can minimize the dialogs + * by trying to re-use already known/entered pass phrases. + */ + if (sc->server->pks->key_files[j] != NULL) + apr_cpystrn(szPath, sc->server->pks->key_files[j++], sizeof(szPath)); + + /* + * Try to read the private key file with the help of + * the callback function which serves the pass + * phrases to OpenSSL + */ + myCtxVarSet(mc, 1, pServ); + myCtxVarSet(mc, 2, p); + myCtxVarSet(mc, 3, aPassPhrase); + myCtxVarSet(mc, 4, &nPassPhraseCur); + myCtxVarSet(mc, 5, &cpPassPhraseCur); + myCtxVarSet(mc, 6, cpVHostID); + myCtxVarSet(mc, 7, an); + myCtxVarSet(mc, 8, &nPassPhraseDialog); + myCtxVarSet(mc, 9, &nPassPhraseDialogCur); + myCtxVarSet(mc, 10, &bPassPhraseDialogOnce); + + nPassPhraseCur = 0; + nPassPhraseRetry = 0; + nPassPhraseDialogCur = 0; + bPassPhraseDialogOnce = TRUE; + + pPrivateKey = NULL; + + for (;;) { + /* + * Try to read the private key file with the help of + * the callback function which serves the pass + * phrases to OpenSSL + */ + if ((rv = exists_and_readable(szPath, p, + &pkey_mtime)) != APR_SUCCESS ) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Init: Can't open server private key file " + "%s",szPath); + ssl_die(); + } + + /* + * if the private key is encrypted and SSLPassPhraseDialog + * is configured to "builtin" it isn't possible to prompt for + * a password after httpd has detached from the tty. + * in this case if we already have a private key and the + * file name/mtime hasn't changed, then reuse the existing key. + * we also reuse existing private keys that were encrypted for + * exec: and pipe: dialogs to minimize chances to snoop the + * password. that and pipe: dialogs might prompt the user + * for password, which on win32 for example could happen 4 + * times at startup. twice for each child and twice within + * each since apache "restarts itself" on startup. + * of course this will not work for the builtin dialog if + * the server was started without LoadModule ssl_module + * configured, then restarted with it configured. + * but we fall through with a chance of success if the key + * is not encrypted or can be handled via exec or pipe dialog. + * and in the case of fallthrough, pkey_mtime and isatty() + * are used to give a better idea as to what failed. + */ + if (pkey_mtime) { + int i; + + for (i=0; i < SSL_AIDX_MAX; i++) { + const char *key_id = + ssl_asn1_table_keyfmt(p, cpVHostID, i); + ssl_asn1_t *asn1 = + ssl_asn1_table_get(mc->tPrivateKey, key_id); + + if (asn1 && (asn1->source_mtime == pkey_mtime)) { + ap_log_error(APLOG_MARK, APLOG_INFO, + 0, pServ, + "%s reusing existing " + "%s private key on restart", + cpVHostID, ssl_asn1_keystr(i)); + return; + } + } + } + + cpPassPhraseCur = NULL; + ssl_pphrase_server_rec = s; /* to make up for sslc flaw */ + + /* Ensure that the error stack is empty; some SSL + * functions will fail spuriously if the error stack + * is not empty. */ + ERR_clear_error(); + + bReadable = ((pPrivateKey = SSL_read_PrivateKey(szPath, NULL, + ssl_pphrase_Handle_CB, s)) != NULL ? TRUE : FALSE); + + /* + * when the private key file now was readable, + * it's fine and we go out of the loop + */ + if (bReadable) + break; + + /* + * when we have more remembered pass phrases + * try to reuse these first. + */ + if (nPassPhraseCur < nPassPhrase) { + nPassPhraseCur++; + continue; + } + + /* + * else it's not readable and we have no more + * remembered pass phrases. Then this has to mean + * that the callback function popped up the dialog + * but a wrong pass phrase was entered. We give the + * user (but not the dialog program) a few more + * chances... + */ +#ifndef WIN32 + if ((sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN + || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) +#else + if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE +#endif + && cpPassPhraseCur != NULL + && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) { + apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect " + "(%d more retr%s permitted).\n", + (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry), + (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry) == 1 ? "y" : "ies"); + nPassPhraseRetry++; + if (nPassPhraseRetry > BUILTIN_DIALOG_BACKOFF) + apr_sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF) + * 5 * APR_USEC_PER_SEC); + continue; + } +#ifdef WIN32 + if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: SSLPassPhraseDialog builtin is not " + "supported on Win32 (key file " + "%s)", szPath); + ssl_die(); + } +#endif /* WIN32 */ + + /* + * Ok, anything else now means a fatal error. + */ + if (cpPassPhraseCur == NULL) { + if (nPassPhraseDialogCur && pkey_mtime && + !(isterm = isatty(fileno(stdout)))) /* XXX: apr_isatty() */ + { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, + pServ, + "Init: Unable to read pass phrase " + "[Hint: key introduced or changed " + "before restart?]"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, pServ); + } + else { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, + pServ, "Init: Private key not found"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, pServ); + } + if (writetty) { + apr_file_printf(writetty, "Apache:mod_ssl:Error: Private key not found.\n"); + apr_file_printf(writetty, "**Stopped\n"); + } + } + else { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, + pServ, "Init: Pass phrase incorrect"); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, pServ); + + if (writetty) { + apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect.\n"); + apr_file_printf(writetty, "**Stopped\n"); + } + } + ssl_die(); + } + + if (pPrivateKey == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Unable to read server private key from " + "file %s [Hint: Perhaps it is in a separate file? " + " See SSLCertificateKeyFile]", szPath); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + + /* + * check algorithm type of private key and make + * sure only one private key per type is used. + */ + at = ssl_util_algotypeof(NULL, pPrivateKey); + an = ssl_util_algotypestr(at); + if (algoKey & at) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Multiple %s server private keys not " + "allowed", an); + ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); + ssl_die(); + } + algoKey |= at; + + /* + * Log the type of reading + */ + if (nPassPhraseDialogCur == 0) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, pServ, + "unencrypted %s private key - pass phrase not " + "required", an); + } + else { + if (cpPassPhraseCur != NULL) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, + pServ, + "encrypted %s private key - pass phrase " + "requested", an); + } + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, + pServ, + "encrypted %s private key - pass phrase" + " reused", an); + } + } + + /* + * Ok, when we have one more pass phrase store it + */ + if (cpPassPhraseCur != NULL) { + cpp = (char **)apr_array_push(aPassPhrase); + *cpp = cpPassPhraseCur; + nPassPhrase++; + } + + /* + * Insert private key into the global module configuration + * (we convert it to a stand-alone DER byte sequence + * because the SSL library uses static variables inside a + * RSA structure which do not survive DSO reloads!) + */ + cp = asn1_table_vhost_key(mc, p, cpVHostID, an); + length = i2d_PrivateKey(pPrivateKey, NULL); + ucp = ssl_asn1_table_set(mc->tPrivateKey, cp, length); + (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */ + + if (nPassPhraseDialogCur != 0) { + /* remember mtime of encrypted keys */ + asn1 = ssl_asn1_table_get(mc->tPrivateKey, cp); + asn1->source_mtime = pkey_mtime; + } + + /* + * Free the private key structure + */ + EVP_PKEY_free(pPrivateKey); + } + } + + /* + * Let the user know when we're successful. + */ + if (nPassPhraseDialog > 0) { + sc = mySrvConfig(s); + if (writetty) { + apr_file_printf(writetty, "\n"); + apr_file_printf(writetty, "Ok: Pass Phrase Dialog successful.\n"); + } + } + + /* + * Wipe out the used memory from the + * pass phrase array and then deallocate it + */ + if (aPassPhrase->nelts) { + pphrase_array_clear(aPassPhrase); + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Init: Wiped out the queried pass phrases from memory"); + } + + /* Close the pipes if they were opened + */ + if (readtty) { + apr_file_close(readtty); + apr_file_close(writetty); + readtty = writetty = NULL; + } + return; +} + +static apr_status_t ssl_pipe_child_create(apr_pool_t *p, const char *progname) +{ + /* Child process code for 'ErrorLog "|..."'; + * may want a common framework for this, since I expect it will + * be common for other foo-loggers to want this sort of thing... + */ + apr_status_t rc; + apr_procattr_t *procattr; + apr_proc_t *procnew; + + if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS) && + ((rc = apr_procattr_io_set(procattr, + APR_FULL_BLOCK, + APR_FULL_BLOCK, + APR_NO_PIPE)) == APR_SUCCESS)) { + char **args; + const char *pname; + + apr_tokenize_to_argv(progname, &args, p); + pname = apr_pstrdup(p, args[0]); + procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew)); + rc = apr_proc_create(procnew, pname, (const char * const *)args, + NULL, procattr, p); + if (rc == APR_SUCCESS) { + /* XXX: not sure if we aught to... + * apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); + */ + writetty = procnew->in; + readtty = procnew->out; + } + } + + return rc; +} + +static int pipe_get_passwd_cb(char *buf, int length, char *prompt, int verify) +{ + apr_status_t rc; + char *p; + + apr_file_puts(prompt, writetty); + + buf[0]='\0'; + rc = apr_file_gets(buf, length, readtty); + apr_file_puts(APR_EOL_STR, writetty); + + if (rc != APR_SUCCESS || apr_file_eof(readtty)) { + memset(buf, 0, length); + return 1; /* failure */ + } + if ((p = strchr(buf, '\n')) != NULL) { + *p = '\0'; + } +#ifdef WIN32 + /* XXX: apr_sometest */ + if ((p = strchr(buf, '\r')) != NULL) { + *p = '\0'; + } +#endif + return 0; +} + +#ifdef SSLC_VERSION_NUMBER +int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify) +{ + void *srv = ssl_pphrase_server_rec; +#else +int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) +{ +#endif + SSLModConfigRec *mc; + server_rec *s; + apr_pool_t *p; + apr_array_header_t *aPassPhrase; + SSLSrvConfigRec *sc; + int *pnPassPhraseCur; + char **cppPassPhraseCur; + char *cpVHostID; + char *cpAlgoType; + int *pnPassPhraseDialog; + int *pnPassPhraseDialogCur; + BOOL *pbPassPhraseDialogOnce; + char *cpp; + int len = -1; + + mc = myModConfig((server_rec *)srv); + + /* + * Reconnect to the context of ssl_phrase_Handle() + */ + s = myCtxVarGet(mc, 1, server_rec *); + p = myCtxVarGet(mc, 2, apr_pool_t *); + aPassPhrase = myCtxVarGet(mc, 3, apr_array_header_t *); + pnPassPhraseCur = myCtxVarGet(mc, 4, int *); + cppPassPhraseCur = myCtxVarGet(mc, 5, char **); + cpVHostID = myCtxVarGet(mc, 6, char *); + cpAlgoType = myCtxVarGet(mc, 7, char *); + pnPassPhraseDialog = myCtxVarGet(mc, 8, int *); + pnPassPhraseDialogCur = myCtxVarGet(mc, 9, int *); + pbPassPhraseDialogOnce = myCtxVarGet(mc, 10, BOOL *); + sc = mySrvConfig(s); + + (*pnPassPhraseDialog)++; + (*pnPassPhraseDialogCur)++; + + /* + * When remembered pass phrases are available use them... + */ + if ((cpp = pphrase_array_get(aPassPhrase, *pnPassPhraseCur)) != NULL) { + apr_cpystrn(buf, cpp, bufsize); + len = strlen(buf); + return len; + } + + /* + * Builtin or Pipe dialog + */ + if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN + || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) { + char *prompt; + int i; + + if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) { + if (!readtty) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Init: Creating pass phrase dialog pipe child " + "'%s'", sc->server->pphrase_dialog_path); + if (ssl_pipe_child_create(p, sc->server->pphrase_dialog_path) + != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Init: Failed to create pass phrase pipe '%s'", + sc->server->pphrase_dialog_path); + PEMerr(PEM_F_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); + memset(buf, 0, (unsigned int)bufsize); + return (-1); + } + } + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Init: Requesting pass phrase via piped dialog"); + } + else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */ +#ifdef WIN32 + PEMerr(PEM_F_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); + memset(buf, 0, (unsigned int)bufsize); + return (-1); +#else + /* + * stderr has already been redirected to the error_log. + * rather than attempting to temporarily rehook it to the terminal, + * we print the prompt to stdout before EVP_read_pw_string turns + * off tty echo + */ + apr_file_open_stdout(&writetty, p); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Init: Requesting pass phrase via builtin terminal " + "dialog"); +#endif + } + + /* + * The first time display a header to inform the user about what + * program he actually speaks to, which module is responsible for + * this terminal dialog and why to the hell he has to enter + * something... + */ + if (*pnPassPhraseDialog == 1) { + apr_file_printf(writetty, "%s mod_ssl/%s (Pass Phrase Dialog)\n", + AP_SERVER_BASEVERSION, MOD_SSL_VERSION); + apr_file_printf(writetty, "Some of your private key files are encrypted for security reasons.\n"); + apr_file_printf(writetty, "In order to read them you have to provide us with the pass phrases.\n"); + } + if (*pbPassPhraseDialogOnce) { + *pbPassPhraseDialogOnce = FALSE; + apr_file_printf(writetty, "\n"); + apr_file_printf(writetty, "Server %s (%s)\n", cpVHostID, cpAlgoType); + } + + /* + * Emulate the OpenSSL internal pass phrase dialog + * (see crypto/pem/pem_lib.c:def_callback() for details) + */ + prompt = "Enter pass phrase:"; + + for (;;) { + apr_file_puts(prompt, writetty); + if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) { + i = pipe_get_passwd_cb(buf, bufsize, "", FALSE); + } + else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */ + i = EVP_read_pw_string(buf, bufsize, "", FALSE); + } + if (i != 0) { + PEMerr(PEM_F_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); + memset(buf, 0, (unsigned int)bufsize); + return (-1); + } + len = strlen(buf); + if (len < 1) + apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase empty (needs to be at least 1 character).\n"); + else + break; + } + } + + /* + * Filter program + */ + else if (sc->server->pphrase_dialog_type == SSL_PPTYPE_FILTER) { + const char *cmd = sc->server->pphrase_dialog_path; + const char **argv = apr_palloc(p, sizeof(char *) * 4); + char *result; + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Init: Requesting pass phrase from dialog filter " + "program (%s)", cmd); + + argv[0] = cmd; + argv[1] = cpVHostID; + argv[2] = cpAlgoType; + argv[3] = NULL; + + result = ssl_util_readfilter(s, p, cmd, argv); + apr_cpystrn(buf, result, bufsize); + len = strlen(buf); + } + + /* + * Ok, we now have the pass phrase, so give it back + */ + *cppPassPhraseCur = apr_pstrdup(p, buf); + + /* + * And return it's length to OpenSSL... + */ + return (len); +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_rand.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_rand.c new file mode 100644 index 00000000..b640e3f9 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_rand.c @@ -0,0 +1,179 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_rand.c + * Random Number Generator Seeding + */ + /* ``The generation of random + numbers is too important + to be left to chance.'' */ + +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** Support for better seeding of SSL library's RNG +** _________________________________________________________________ +*/ + +static int ssl_rand_choosenum(int, int); +static int ssl_rand_feedfp(apr_pool_t *, apr_file_t *, int); + +int ssl_rand_seed(server_rec *s, apr_pool_t *p, ssl_rsctx_t nCtx, char *prefix) +{ + SSLModConfigRec *mc; + apr_array_header_t *apRandSeed; + ssl_randseed_t *pRandSeeds; + ssl_randseed_t *pRandSeed; + unsigned char stackdata[256]; + int nReq, nDone; + apr_file_t *fp; + int i, n, l; + + mc = myModConfig(s); + nReq = 0; + nDone = 0; + apRandSeed = mc->aRandSeed; + pRandSeeds = (ssl_randseed_t *)apRandSeed->elts; + for (i = 0; i < apRandSeed->nelts; i++) { + pRandSeed = &pRandSeeds[i]; + if (pRandSeed->nCtx == nCtx) { + nReq += pRandSeed->nBytes; + if (pRandSeed->nSrc == SSL_RSSRC_FILE) { + /* + * seed in contents of an external file + */ + if (apr_file_open(&fp, pRandSeed->cpPath, + APR_READ, APR_OS_DEFAULT, p) != APR_SUCCESS) + continue; + nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes); + apr_file_close(fp); + } + else if (pRandSeed->nSrc == SSL_RSSRC_EXEC) { + const char *cmd = pRandSeed->cpPath; + const char **argv = apr_palloc(p, sizeof(char *) * 3); + /* + * seed in contents generated by an external program + */ + argv[0] = cmd; + argv[1] = apr_itoa(p, pRandSeed->nBytes); + argv[2] = NULL; + + if ((fp = ssl_util_ppopen(s, p, cmd, argv)) == NULL) + continue; + nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes); + ssl_util_ppclose(s, p, fp); + } +#ifdef HAVE_SSL_RAND_EGD + else if (pRandSeed->nSrc == SSL_RSSRC_EGD) { + /* + * seed in contents provided by the external + * Entropy Gathering Daemon (EGD) + */ + if ((n = RAND_egd(pRandSeed->cpPath)) == -1) + continue; + nDone += n; + } +#endif + else if (pRandSeed->nSrc == SSL_RSSRC_BUILTIN) { + struct { + time_t t; + pid_t pid; + } my_seed; + + /* + * seed in the current time (usually just 4 bytes) + */ + my_seed.t = time(NULL); + + /* + * seed in the current process id (usually just 4 bytes) + */ + my_seed.pid = mc->pid; + + l = sizeof(my_seed); + RAND_seed((unsigned char *)&my_seed, l); + nDone += l; + + /* + * seed in some current state of the run-time stack (128 bytes) + */ + n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1); + RAND_seed(stackdata+n, 128); + nDone += 128; + + } + } + } + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "%sSeeding PRNG with %d bytes of entropy", prefix, nDone); + + if (RAND_status() == 0) + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "%sPRNG still contains insufficient entropy!", prefix); + + return nDone; +} + +#define BUFSIZE 8192 + +static int ssl_rand_feedfp(apr_pool_t *p, apr_file_t *fp, int nReq) +{ + apr_size_t nDone; + unsigned char caBuf[BUFSIZE]; + apr_size_t nBuf; + apr_size_t nRead; + apr_size_t nTodo; + + nDone = 0; + nRead = BUFSIZE; + nTodo = nReq; + while (1) { + if (nReq > 0) + nRead = (nTodo < BUFSIZE ? nTodo : BUFSIZE); + nBuf = nRead; + if (apr_file_read(fp, caBuf, &nBuf) != APR_SUCCESS) + break; + RAND_seed(caBuf, nBuf); + nDone += nBuf; + if (nReq > 0) { + nTodo -= nBuf; + if (nTodo <= 0) + break; + } + } + return nDone; +} + +static int ssl_rand_choosenum(int l, int h) +{ + int i; + char buf[50]; + + apr_snprintf(buf, sizeof(buf), "%.0f", + (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l))); + i = atoi(buf)+1; + if (i < l) i = l; + if (i > h) i = h; + return i; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_vars.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_vars.c new file mode 100644 index 00000000..661e99d8 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_vars.c @@ -0,0 +1,687 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_engine_vars.c + * Variable Lookup Facility + */ + /* ``Those of you who think they + know everything are very annoying + to those of us who do.'' + -- Unknown */ +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** Variable Lookup +** _________________________________________________________________ +*/ + +static char *ssl_var_lookup_header(apr_pool_t *p, request_rec *r, const char *name); +static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var); +static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var); +static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var); +static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm); +static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs); +static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var); +static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs); +static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c); +static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, conn_rec *c, char *var); +static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize); +static char *ssl_var_lookup_ssl_version(apr_pool_t *pp, apr_pool_t *p, char *var); + +static int ssl_is_https(conn_rec *c) +{ + SSLConnRec *sslconn = myConnConfig(c); + return sslconn && sslconn->ssl; +} + +void ssl_var_register(void) +{ + APR_REGISTER_OPTIONAL_FN(ssl_is_https); + APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); + return; +} + +/* This function must remain safe to use for a non-SSL connection. */ +char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var) +{ + SSLModConfigRec *mc = myModConfig(s); + char *result; + BOOL resdup; + apr_time_exp_t tm; + + result = NULL; + resdup = TRUE; + + /* + * When no pool is given try to find one + */ + if (p == NULL) { + if (r != NULL) + p = r->pool; + else if (c != NULL) + p = c->pool; + else + p = mc->pPool; + } + + /* + * Request dependent stuff + */ + if (r != NULL) { + if (strcEQ(var, "HTTP_USER_AGENT")) + result = ssl_var_lookup_header(p, r, "User-Agent"); + else if (strcEQ(var, "HTTP_REFERER")) + result = ssl_var_lookup_header(p, r, "Referer"); + else if (strcEQ(var, "HTTP_COOKIE")) + result = ssl_var_lookup_header(p, r, "Cookie"); + else if (strcEQ(var, "HTTP_FORWARDED")) + result = ssl_var_lookup_header(p, r, "Forwarded"); + else if (strcEQ(var, "HTTP_HOST")) + result = ssl_var_lookup_header(p, r, "Host"); + else if (strcEQ(var, "HTTP_PROXY_CONNECTION")) + result = ssl_var_lookup_header(p, r, "Proxy-Connection"); + else if (strcEQ(var, "HTTP_ACCEPT")) + result = ssl_var_lookup_header(p, r, "Accept"); + else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5)) + /* all other headers from which we are still not know about */ + result = ssl_var_lookup_header(p, r, var+5); + else if (strcEQ(var, "THE_REQUEST")) + result = r->the_request; + else if (strcEQ(var, "REQUEST_METHOD")) + result = (char *)(r->method); + else if (strcEQ(var, "REQUEST_SCHEME")) + result = (char *)ap_http_method(r); + else if (strcEQ(var, "REQUEST_URI")) + result = r->uri; + else if (strcEQ(var, "SCRIPT_FILENAME") || + strcEQ(var, "REQUEST_FILENAME")) + result = r->filename; + else if (strcEQ(var, "PATH_INFO")) + result = r->path_info; + else if (strcEQ(var, "QUERY_STRING")) + result = r->args; + else if (strcEQ(var, "REMOTE_HOST")) + result = (char *)ap_get_remote_host(r->connection, + r->per_dir_config, REMOTE_NAME, NULL); + else if (strcEQ(var, "REMOTE_IDENT")) + result = (char *)ap_get_remote_logname(r); + else if (strcEQ(var, "IS_SUBREQ")) + result = (r->main != NULL ? "true" : "false"); + else if (strcEQ(var, "DOCUMENT_ROOT")) + result = (char *)ap_document_root(r); + else if (strcEQ(var, "SERVER_ADMIN")) + result = r->server->server_admin; + else if (strcEQ(var, "SERVER_NAME")) + result = (char *)ap_get_server_name(r); + else if (strcEQ(var, "SERVER_PORT")) + result = apr_psprintf(p, "%u", ap_get_server_port(r)); + else if (strcEQ(var, "SERVER_PROTOCOL")) + result = r->protocol; + } + + /* + * Connection stuff + */ + if (result == NULL && c != NULL) { + SSLConnRec *sslconn = myConnConfig(c); + if (strcEQ(var, "REMOTE_ADDR")) + result = c->remote_ip; + else if (strcEQ(var, "REMOTE_USER")) + result = r->user; + else if (strcEQ(var, "AUTH_TYPE")) + result = r->ap_auth_type; + else if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) + && sslconn && sslconn->ssl) + result = ssl_var_lookup_ssl(p, c, var+4); + else if (strcEQ(var, "HTTPS")) { + if (sslconn && sslconn->ssl) + result = "on"; + else + result = "off"; + } + } + + /* + * Totally independent stuff + */ + if (result == NULL) { + if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12)) + result = ssl_var_lookup_ssl_version(s->process->pool, p, var+12); + else if (strcEQ(var, "SERVER_SOFTWARE")) + result = (char *)ap_get_server_version(); + else if (strcEQ(var, "API_VERSION")) { + result = apr_psprintf(p, "%d", MODULE_MAGIC_NUMBER); + resdup = FALSE; + } + else if (strcEQ(var, "TIME_YEAR")) { + apr_time_exp_lt(&tm, apr_time_now()); + result = apr_psprintf(p, "%02d%02d", + (tm.tm_year / 100) + 19, tm.tm_year % 100); + resdup = FALSE; + } +#define MKTIMESTR(format, tmfield) \ + apr_time_exp_lt(&tm, apr_time_now()); \ + result = apr_psprintf(p, format, tm.tmfield); \ + resdup = FALSE; + else if (strcEQ(var, "TIME_MON")) { + MKTIMESTR("%02d", tm_mon+1) + } + else if (strcEQ(var, "TIME_DAY")) { + MKTIMESTR("%02d", tm_mday) + } + else if (strcEQ(var, "TIME_HOUR")) { + MKTIMESTR("%02d", tm_hour) + } + else if (strcEQ(var, "TIME_MIN")) { + MKTIMESTR("%02d", tm_min) + } + else if (strcEQ(var, "TIME_SEC")) { + MKTIMESTR("%02d", tm_sec) + } + else if (strcEQ(var, "TIME_WDAY")) { + MKTIMESTR("%d", tm_wday) + } + else if (strcEQ(var, "TIME")) { + apr_time_exp_lt(&tm, apr_time_now()); + result = apr_psprintf(p, + "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19, + (tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + resdup = FALSE; + } + /* all other env-variables from the parent Apache process */ + else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) { + result = (char *)apr_table_get(r->notes, var+4); + if (result == NULL) + result = (char *)apr_table_get(r->subprocess_env, var+4); + if (result == NULL) + result = getenv(var+4); + } + } + + if (result != NULL && resdup) + result = apr_pstrdup(p, result); + if (result == NULL) + result = ""; + return result; +} + +static char *ssl_var_lookup_header(apr_pool_t *p, request_rec *r, const char *name) +{ + char *hdr = NULL; + + if ((hdr = (char *)apr_table_get(r->headers_in, name)) != NULL) + hdr = apr_pstrdup(p, hdr); + return hdr; +} + +static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var) +{ + SSLConnRec *sslconn = myConnConfig(c); + char *result; + X509 *xs; + STACK_OF(X509) *sk; + SSL *ssl; + + result = NULL; + + ssl = sslconn->ssl; + if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) { + result = ssl_var_lookup_ssl_version(c->base_server->process->pool, + p, var+8); + } + else if (ssl != NULL && strcEQ(var, "PROTOCOL")) { + result = (char *)SSL_get_version(ssl); + } + else if (ssl != NULL && strcEQ(var, "SESSION_ID")) { + char buf[SSL_SESSION_ID_STRING_LEN]; + SSL_SESSION *pSession = SSL_get_session(ssl); + if (pSession) { + result = apr_pstrdup(p, SSL_SESSION_id2sz( + SSL_SESSION_get_session_id(pSession), + SSL_SESSION_get_session_id_length(pSession), + buf, sizeof(buf))); + } + } + else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) { + result = ssl_var_lookup_ssl_cipher(p, c, var+6); + } + else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) { + sk = SSL_get_peer_cert_chain(ssl); + result = ssl_var_lookup_ssl_cert_chain(p, sk, var+18); + } + else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) { + result = ssl_var_lookup_ssl_cert_verify(p, c); + } + else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) { + if ((xs = SSL_get_peer_certificate(ssl)) != NULL) { + result = ssl_var_lookup_ssl_cert(p, xs, var+7); + X509_free(xs); + } + } + else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) { + if ((xs = SSL_get_certificate(ssl)) != NULL) + result = ssl_var_lookup_ssl_cert(p, xs, var+7); + } + else if (ssl != NULL && strcEQ(var, "SECURE_RENEG")) { + int flag = 0; +#ifdef SSL_get_secure_renegotiation_support + flag = SSL_get_secure_renegotiation_support(ssl); +#endif + result = apr_pstrdup(p, flag ? "true" : "false"); + } + + return result; +} + +static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var) +{ + char *result; + BOOL resdup; + X509_NAME *xsname; + int nid; + char *cp; + + result = NULL; + resdup = TRUE; + + if (strcEQ(var, "M_VERSION")) { + result = apr_psprintf(p, "%lu", X509_get_version(xs)+1); + resdup = FALSE; + } + else if (strcEQ(var, "M_SERIAL")) { + result = ssl_var_lookup_ssl_cert_serial(p, xs); + } + else if (strcEQ(var, "V_START")) { + result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs)); + } + else if (strcEQ(var, "V_END")) { + result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs)); + } + else if (strcEQ(var, "S_DN")) { + xsname = X509_get_subject_name(xs); + cp = X509_NAME_oneline(xsname, NULL, 0); + result = apr_pstrdup(p, cp); + modssl_free(cp); + resdup = FALSE; + } + else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) { + xsname = X509_get_subject_name(xs); + result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); + resdup = FALSE; + } + else if (strcEQ(var, "I_DN")) { + xsname = X509_get_issuer_name(xs); + cp = X509_NAME_oneline(xsname, NULL, 0); + result = apr_pstrdup(p, cp); + modssl_free(cp); + resdup = FALSE; + } + else if (strlen(var) > 5 && strcEQn(var, "I_DN_", 5)) { + xsname = X509_get_issuer_name(xs); + result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); + resdup = FALSE; + } + else if (strcEQ(var, "A_SIG")) { + nid = OBJ_obj2nid((ASN1_OBJECT *)X509_get_signature_algorithm(xs)); + result = apr_pstrdup(p, + (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); + resdup = FALSE; + } + else if (strcEQ(var, "A_KEY")) { + nid = OBJ_obj2nid((ASN1_OBJECT *)X509_get_key_algorithm(xs)); + result = apr_pstrdup(p, + (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); + resdup = FALSE; + } + else if (strcEQ(var, "CERT")) { + result = ssl_var_lookup_ssl_cert_PEM(p, xs); + } + + if (result != NULL && resdup) + result = apr_pstrdup(p, result); + return result; +} + +static const struct { + char *name; + int nid; +} ssl_var_lookup_ssl_cert_dn_rec[] = { + { "C", NID_countryName }, + { "ST", NID_stateOrProvinceName }, /* officially (RFC2156) */ + { "SP", NID_stateOrProvinceName }, /* compatibility (SSLeay) */ + { "L", NID_localityName }, + { "O", NID_organizationName }, + { "OU", NID_organizationalUnitName }, + { "CN", NID_commonName }, + { "T", NID_title }, + { "I", NID_initials }, + { "G", NID_givenName }, + { "S", NID_surname }, + { "D", NID_description }, +/* This has been removed in OpenSSL 0.9.8-dev. */ +#ifdef NID_uniqueIdentifier + { "UID", NID_uniqueIdentifier }, +#endif + { "Email", NID_pkcs9_emailAddress }, + { NULL, 0 } +}; + +static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var) +{ + char *result; + X509_NAME_ENTRY *xsne; + int i, j, n; + unsigned char *data_ptr; + int data_len; + + result = NULL; + + for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) { + if (strEQ(var, ssl_var_lookup_ssl_cert_dn_rec[i].name)) { + for (j = 0; j < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *) + X509_NAME_get_entries(xsname)); + j++) { + xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *) + X509_NAME_get_entries(xsname), j); + + n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); + data_ptr = X509_NAME_ENTRY_get_data_ptr(xsne); + data_len = X509_NAME_ENTRY_get_data_len(xsne); + + if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid) { + result = apr_palloc(p, data_len+1); + apr_cpystrn(result, (char *)data_ptr, data_len+1); +#ifdef CHARSET_EBCDIC + ascii2ebcdic(result, result, xsne->value->length); +#endif /* CHARSET_EBCDIC */ + result[data_len] = NUL; + break; + } + } + break; + } + } + return result; +} + +static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm) +{ + char *result; + BIO* bio; + int n; + + if ((bio = BIO_new(BIO_s_mem())) == NULL) + return NULL; + ASN1_UTCTIME_print(bio, tm); + n = BIO_pending(bio); + result = apr_pcalloc(p, n+1); + n = BIO_read(bio, result, n); + result[n] = NUL; + BIO_free(bio); + return result; +} + +static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs) +{ + char *result; + BIO *bio; + int n; + + if ((bio = BIO_new(BIO_s_mem())) == NULL) + return NULL; + i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs)); + n = BIO_pending(bio); + result = apr_pcalloc(p, n+1); + n = BIO_read(bio, result, n); + result[n] = NUL; + BIO_free(bio); + return result; +} + +static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var) +{ + char *result; + X509 *xs; + int n; + + result = NULL; + + if (strspn(var, "0123456789") == strlen(var)) { + n = atoi(var); + if (n < sk_X509_num(sk)) { + xs = sk_X509_value(sk, n); + result = ssl_var_lookup_ssl_cert_PEM(p, xs); + } + } + + return result; +} + +static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs) +{ + char *result; + BIO *bio; + int n; + + if ((bio = BIO_new(BIO_s_mem())) == NULL) + return NULL; + PEM_write_bio_X509(bio, xs); + n = BIO_pending(bio); + result = apr_pcalloc(p, n+1); + n = BIO_read(bio, result, n); + result[n] = NUL; + BIO_free(bio); + return result; +} + +static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c) +{ + SSLConnRec *sslconn = myConnConfig(c); + char *result; + long vrc; + const char *verr; + const char *vinfo; + SSL *ssl; + X509 *xs; + + result = NULL; + ssl = sslconn->ssl; + verr = sslconn->verify_error; + vinfo = sslconn->verify_info; + vrc = SSL_get_verify_result(ssl); + xs = SSL_get_peer_certificate(ssl); + + if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs == NULL) + /* no client verification done at all */ + result = "NONE"; + else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL) + /* client verification done successful */ + result = "SUCCESS"; + else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS")) + /* client verification done in generous way */ + result = "GENEROUS"; + else + /* client verification failed */ + result = apr_psprintf(p, "FAILED:%s", verr); + + if (xs) + X509_free(xs); + return result; +} + +static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, conn_rec *c, char *var) +{ + SSLConnRec *sslconn = myConnConfig(c); + char *result; + BOOL resdup; + int usekeysize, algkeysize; + SSL *ssl; + + result = NULL; + resdup = TRUE; + + ssl = sslconn->ssl; + ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize); + + if (ssl && strEQ(var, "")) { + SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); + result = (cipher != NULL ? (char *)SSL_CIPHER_get_name(cipher) : NULL); + } + else if (strcEQ(var, "_EXPORT")) + result = (usekeysize < 56 ? "true" : "false"); + else if (strcEQ(var, "_USEKEYSIZE")) { + result = apr_psprintf(p, "%d", usekeysize); + resdup = FALSE; + } + else if (strcEQ(var, "_ALGKEYSIZE")) { + result = apr_psprintf(p, "%d", algkeysize); + resdup = FALSE; + } + + if (result != NULL && resdup) + result = apr_pstrdup(p, result); + return result; +} + +static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize) +{ + SSL_CIPHER *cipher; + + *usekeysize = 0; + *algkeysize = 0; + if (ssl != NULL) + if ((cipher = SSL_get_current_cipher(ssl)) != NULL) + *usekeysize = SSL_CIPHER_get_bits(cipher, algkeysize); + return; +} + +static char *ssl_var_lookup_ssl_version(apr_pool_t *pp, apr_pool_t *p, char *var) +{ + static char interface[] = "mod_ssl/" MOD_SSL_VERSION; + static char library_interface[] = SSL_LIBRARY_TEXT; + static char *library = NULL; + char *result; + + if (!library) { + char *cp, *cp2; + library = apr_pstrdup(pp, SSL_LIBRARY_DYNTEXT); + if ((cp = strchr(library, ' ')) != NULL) { + *cp = '/'; + if ((cp2 = strchr(cp, ' ')) != NULL) + *cp2 = NUL; + } + if ((cp = strchr(library_interface, ' ')) != NULL) { + *cp = '/'; + if ((cp2 = strchr(cp, ' ')) != NULL) + *cp2 = NUL; + } + } + + if (strEQ(var, "INTERFACE")) { + result = apr_pstrdup(p, interface); + } + else if (strEQ(var, "LIBRARY_INTERFACE")) { + result = apr_pstrdup(p, library_interface); + } + else if (strEQ(var, "LIBRARY")) { + result = apr_pstrdup(p, library); + } + else { + result = NULL; + } + return result; +} + + +/* _________________________________________________________________ +** +** SSL Extension to mod_log_config +** _________________________________________________________________ +*/ + +#include "../../modules/loggers/mod_log_config.h" + +static const char *ssl_var_log_handler_c(request_rec *r, char *a); +static const char *ssl_var_log_handler_x(request_rec *r, char *a); + +/* + * register us for the mod_log_config function registering phase + * to establish %{...}c and to be able to expand %{...}x variables. + */ +void ssl_var_log_config_register(apr_pool_t *p) +{ + static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register; + + log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); + + if (log_pfn_register) { + log_pfn_register(p, "c", ssl_var_log_handler_c, 0); + log_pfn_register(p, "x", ssl_var_log_handler_x, 0); + } + return; +} + +/* + * implement the %{..}c log function + * (we are the only function) + */ +static const char *ssl_var_log_handler_c(request_rec *r, char *a) +{ + SSLConnRec *sslconn = myConnConfig(r->connection); + char *result; + + if (sslconn == NULL || sslconn->ssl == NULL) + return NULL; + result = NULL; + if (strEQ(a, "version")) + result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_PROTOCOL"); + else if (strEQ(a, "cipher")) + result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER"); + else if (strEQ(a, "subjectdn") || strEQ(a, "clientcert")) + result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN"); + else if (strEQ(a, "issuerdn") || strEQ(a, "cacert")) + result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN"); + else if (strEQ(a, "errcode")) + result = "-"; + else if (strEQ(a, "errstr")) + result = (char *)sslconn->verify_error; + if (result != NULL && result[0] == NUL) + result = NULL; + return result; +} + +/* + * extend the implementation of the %{..}x log function + * (there can be more functions) + */ +static const char *ssl_var_log_handler_x(request_rec *r, char *a) +{ + char *result; + + result = ssl_var_lookup(r->pool, r->server, r->connection, r, a); + if (result != NULL && result[0] == NUL) + result = NULL; + return result; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr.c new file mode 100644 index 00000000..19e3d757 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr.c @@ -0,0 +1,82 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_expr.c + * Expression Handling + */ + /* ``It is hard to fly with + the eagles when you work + with the turkeys.'' + -- Unknown */ +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** Expression Handling +** _________________________________________________________________ +*/ + +ssl_expr_info_type ssl_expr_info; +char *ssl_expr_error; + +ssl_expr *ssl_expr_comp(apr_pool_t *p, char *expr) +{ + ssl_expr_info.pool = p; + ssl_expr_info.inputbuf = expr; + ssl_expr_info.inputlen = strlen(expr); + ssl_expr_info.inputptr = ssl_expr_info.inputbuf; + ssl_expr_info.expr = FALSE; + + ssl_expr_error = NULL; + if (ssl_expr_yyparse()) + return NULL; + return ssl_expr_info.expr; +} + +char *ssl_expr_get_error(void) +{ + if (ssl_expr_error == NULL) + return ""; + return ssl_expr_error; +} + +ssl_expr *ssl_expr_make(ssl_expr_node_op op, void *a1, void *a2) +{ + ssl_expr *node; + + node = (ssl_expr *)apr_palloc(ssl_expr_info.pool, sizeof(ssl_expr)); + node->node_op = op; + node->node_arg1 = (char *)a1; + node->node_arg2 = (char *)a2; + return node; +} + +int ssl_expr_exec(request_rec *r, ssl_expr *expr) +{ + BOOL rc; + + rc = ssl_expr_eval(r, expr); + if (ssl_expr_error != NULL) + return (-1); + else + return (rc ? 1 : 0); +} diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr.h b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr.h new file mode 100644 index 00000000..20b9fbdb --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr.h @@ -0,0 +1,104 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_expr.h + * Expression Handling (Header) + */ + /* ``May all your PUSHes be POPed.'' */ + +#ifndef __SSL_EXPR_H__ +#define __SSL_EXPR_H__ + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE !FALSE +#endif + +#ifndef YY_NULL +#define YY_NULL 0 +#endif + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef BOOL +#define BOOL unsigned int +#endif + +#ifndef NULL +#define NULL (void *)0 +#endif + +#ifndef NUL +#define NUL '\0' +#endif + +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif + +typedef enum { + op_NOP, op_ListElement, + op_True, op_False, op_Not, op_Or, op_And, op_Comp, + op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE, op_IN, op_REG, op_NRE, + op_Digit, op_String, op_Regex, op_Var, op_Func +} ssl_expr_node_op; + +typedef struct { + ssl_expr_node_op node_op; + void *node_arg1; + void *node_arg2; + apr_pool_t *p; +} ssl_expr_node; + +typedef ssl_expr_node ssl_expr; + +typedef struct { + apr_pool_t *pool; + char *inputbuf; + int inputlen; + char *inputptr; + ssl_expr *expr; +} ssl_expr_info_type; + +extern ssl_expr_info_type ssl_expr_info; +extern char *ssl_expr_error; + +#define yylval ssl_expr_yylval +#define yyerror ssl_expr_yyerror +#define yyinput ssl_expr_yyinput + +extern int ssl_expr_yyparse(void); +extern int ssl_expr_yyerror(char *); +extern int ssl_expr_yylex(void); + +extern ssl_expr *ssl_expr_comp(apr_pool_t *, char *); +extern int ssl_expr_exec(request_rec *, ssl_expr *); +extern char *ssl_expr_get_error(void); +extern ssl_expr *ssl_expr_make(ssl_expr_node_op, void *, void *); +extern BOOL ssl_expr_eval(request_rec *, ssl_expr *); + +#endif /* __SSL_EXPR_H__ */ diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_eval.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_eval.c new file mode 100644 index 00000000..30adeefc --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_eval.c @@ -0,0 +1,254 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_expr_eval.c + * Expression Evaluation + */ + /* ``Make love, + not software!'' + -- Unknown */ +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** Expression Evaluation +** _________________________________________________________________ +*/ + +static BOOL ssl_expr_eval_comp(request_rec *, ssl_expr *); +static char *ssl_expr_eval_word(request_rec *, ssl_expr *); +static char *ssl_expr_eval_func_file(request_rec *, char *); +static int ssl_expr_eval_strcmplex(char *, char *); + +BOOL ssl_expr_eval(request_rec *r, ssl_expr *node) +{ + switch (node->node_op) { + case op_True: { + return TRUE; + } + case op_False: { + return FALSE; + } + case op_Not: { + ssl_expr *e = (ssl_expr *)node->node_arg1; + return (!ssl_expr_eval(r, e)); + } + case op_Or: { + ssl_expr *e1 = (ssl_expr *)node->node_arg1; + ssl_expr *e2 = (ssl_expr *)node->node_arg2; + return (ssl_expr_eval(r, e1) || ssl_expr_eval(r, e2)); + } + case op_And: { + ssl_expr *e1 = (ssl_expr *)node->node_arg1; + ssl_expr *e2 = (ssl_expr *)node->node_arg2; + return (ssl_expr_eval(r, e1) && ssl_expr_eval(r, e2)); + } + case op_Comp: { + ssl_expr *e = (ssl_expr *)node->node_arg1; + return ssl_expr_eval_comp(r, e); + } + default: { + ssl_expr_error = "Internal evaluation error: Unknown expression node"; + return FALSE; + } + } +} + +static BOOL ssl_expr_eval_comp(request_rec *r, ssl_expr *node) +{ + switch (node->node_op) { + case op_EQ: { + ssl_expr *e1 = (ssl_expr *)node->node_arg1; + ssl_expr *e2 = (ssl_expr *)node->node_arg2; + return (strcmp(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) == 0); + } + case op_NE: { + ssl_expr *e1 = (ssl_expr *)node->node_arg1; + ssl_expr *e2 = (ssl_expr *)node->node_arg2; + return (strcmp(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) != 0); + } + case op_LT: { + ssl_expr *e1 = (ssl_expr *)node->node_arg1; + ssl_expr *e2 = (ssl_expr *)node->node_arg2; + return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) < 0); + } + case op_LE: { + ssl_expr *e1 = (ssl_expr *)node->node_arg1; + ssl_expr *e2 = (ssl_expr *)node->node_arg2; + return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) <= 0); + } + case op_GT: { + ssl_expr *e1 = (ssl_expr *)node->node_arg1; + ssl_expr *e2 = (ssl_expr *)node->node_arg2; + return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) > 0); + } + case op_GE: { + ssl_expr *e1 = (ssl_expr *)node->node_arg1; + ssl_expr *e2 = (ssl_expr *)node->node_arg2; + return (ssl_expr_eval_strcmplex(ssl_expr_eval_word(r, e1), ssl_expr_eval_word(r, e2)) >= 0); + } + case op_IN: { + ssl_expr *e1 = (ssl_expr *)node->node_arg1; + ssl_expr *e2 = (ssl_expr *)node->node_arg2; + ssl_expr *e3; + char *w1 = ssl_expr_eval_word(r, e1); + BOOL found = FALSE; + do { + e3 = (ssl_expr *)e2->node_arg1; + e2 = (ssl_expr *)e2->node_arg2; + if (strcmp(w1, ssl_expr_eval_word(r, e3)) == 0) { + found = TRUE; + break; + } + } while (e2 != NULL); + return found; + } + case op_REG: { + ssl_expr *e1; + ssl_expr *e2; + char *word; + regex_t *regex; + + e1 = (ssl_expr *)node->node_arg1; + e2 = (ssl_expr *)node->node_arg2; + word = ssl_expr_eval_word(r, e1); + regex = (regex_t *)(e2->node_arg1); + return (ap_regexec(regex, word, 0, NULL, 0) == 0); + } + case op_NRE: { + ssl_expr *e1; + ssl_expr *e2; + char *word; + regex_t *regex; + + e1 = (ssl_expr *)node->node_arg1; + e2 = (ssl_expr *)node->node_arg2; + word = ssl_expr_eval_word(r, e1); + regex = (regex_t *)(e2->node_arg1); + return !(ap_regexec(regex, word, 0, NULL, 0) == 0); + } + default: { + ssl_expr_error = "Internal evaluation error: Unknown expression node"; + return FALSE; + } + } +} + +static char *ssl_expr_eval_word(request_rec *r, ssl_expr *node) +{ + switch (node->node_op) { + case op_Digit: { + char *string = (char *)node->node_arg1; + return string; + } + case op_String: { + char *string = (char *)node->node_arg1; + return string; + } + case op_Var: { + char *var = (char *)node->node_arg1; + char *val = ssl_var_lookup(r->pool, r->server, r->connection, r, var); + return (val == NULL ? "" : val); + } + case op_Func: { + char *name = (char *)node->node_arg1; + ssl_expr *args = (ssl_expr *)node->node_arg2; + if (strEQ(name, "file")) + return ssl_expr_eval_func_file(r, (char *)(args->node_arg1)); + else { + ssl_expr_error = "Internal evaluation error: Unknown function name"; + return ""; + } + } + default: { + ssl_expr_error = "Internal evaluation error: Unknown expression node"; + return FALSE; + } + } +} + +static char *ssl_expr_eval_func_file(request_rec *r, char *filename) +{ + apr_file_t *fp; + char *buf; + apr_off_t offset; + apr_size_t len; + apr_finfo_t finfo; + + if (apr_file_open(&fp, filename, APR_READ|APR_BUFFERED, + APR_OS_DEFAULT, r->pool) != APR_SUCCESS) { + ssl_expr_error = "Cannot open file"; + return ""; + } + apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); + if ((finfo.size + 1) != ((apr_size_t)finfo.size + 1)) { + ssl_expr_error = "Huge file cannot be read"; + apr_file_close(fp); + return ""; + } + len = (apr_size_t)finfo.size; + if (len == 0) { + buf = (char *)apr_palloc(r->pool, sizeof(char) * 1); + *buf = NUL; + } + else { + if ((buf = (char *)apr_palloc(r->pool, sizeof(char)*(len+1))) == NULL) { + ssl_expr_error = "Cannot allocate memory"; + apr_file_close(fp); + return ""; + } + offset = 0; + apr_file_seek(fp, APR_SET, &offset); + if (apr_file_read(fp, buf, &len) != APR_SUCCESS) { + ssl_expr_error = "Cannot read from file"; + apr_file_close(fp); + return ""; + } + buf[len] = NUL; + } + apr_file_close(fp); + return buf; +} + +/* a variant of strcmp(3) which works correctly also for number strings */ +static int ssl_expr_eval_strcmplex(char *cpNum1, char *cpNum2) +{ + int i, n1, n2; + + if (cpNum1 == NULL) + return -1; + if (cpNum2 == NULL) + return +1; + n1 = strlen(cpNum1); + n2 = strlen(cpNum2); + if (n1 > n2) + return 1; + if (n1 < n2) + return -1; + for (i = 0; i < n1; i++) { + if (cpNum1[i] > cpNum2[i]) + return 1; + if (cpNum1[i] < cpNum2[i]) + return -1; + } + return 0; +} diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_parse.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_parse.c new file mode 100644 index 00000000..6f3f990e --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_parse.c @@ -0,0 +1,1081 @@ + +/* A Bison parser, made from ssl_expr_parse.y + by GNU Bison version 1.28 */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define T_TRUE 257 +#define T_FALSE 258 +#define T_DIGIT 259 +#define T_ID 260 +#define T_STRING 261 +#define T_REGEX 262 +#define T_REGEX_I 263 +#define T_FUNC_FILE 264 +#define T_OP_EQ 265 +#define T_OP_NE 266 +#define T_OP_LT 267 +#define T_OP_LE 268 +#define T_OP_GT 269 +#define T_OP_GE 270 +#define T_OP_REG 271 +#define T_OP_NRE 272 +#define T_OP_IN 273 +#define T_OP_OR 274 +#define T_OP_AND 275 +#define T_OP_NOT 276 + +#line 68 "ssl_expr_parse.y" + +#include "mod_ssl.h" + +#line 72 "ssl_expr_parse.y" +typedef union { + char *cpVal; + ssl_expr *exVal; +} YYSTYPE; +#include <stdio.h> + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 53 +#define YYFLAG -32768 +#define YYNTBASE 29 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 276 ? ssl_expr_yytranslate[x] : 36) + +static const char ssl_expr_yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 28, 2, 2, 23, + 24, 2, 2, 27, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 25, 2, 26, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22 +}; + +#if YYDEBUG != 0 +static const short ssl_expr_yyprhs[] = { 0, + 0, 2, 4, 6, 9, 13, 17, 19, 23, 27, + 31, 35, 39, 43, 47, 53, 57, 61, 63, 67, + 69, 71, 76, 78, 80, 82 +}; + +static const short ssl_expr_yyrhs[] = { 30, + 0, 3, 0, 4, 0, 22, 30, 0, 30, 20, + 30, 0, 30, 21, 30, 0, 31, 0, 23, 30, + 24, 0, 33, 11, 33, 0, 33, 12, 33, 0, + 33, 13, 33, 0, 33, 14, 33, 0, 33, 15, + 33, 0, 33, 16, 33, 0, 33, 19, 25, 32, + 26, 0, 33, 17, 34, 0, 33, 18, 34, 0, + 33, 0, 32, 27, 33, 0, 5, 0, 7, 0, + 28, 25, 6, 26, 0, 35, 0, 8, 0, 9, + 0, 10, 23, 7, 24, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short ssl_expr_yyrline[] = { 0, + 115, 118, 119, 120, 121, 122, 123, 124, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 138, 139, 142, + 143, 144, 145, 148, 158, 170 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const ssl_expr_yytname[] = { "$","error","$undefined.","T_TRUE", +"T_FALSE","T_DIGIT","T_ID","T_STRING","T_REGEX","T_REGEX_I","T_FUNC_FILE","T_OP_EQ", +"T_OP_NE","T_OP_LT","T_OP_LE","T_OP_GT","T_OP_GE","T_OP_REG","T_OP_NRE","T_OP_IN", +"T_OP_OR","T_OP_AND","T_OP_NOT","'('","')'","'{'","'}'","','","'%'","root","expr", +"comparison","words","word","regex","funccall", NULL +}; +#endif + +static const short ssl_expr_yyr1[] = { 0, + 29, 30, 30, 30, 30, 30, 30, 30, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 32, 32, 33, + 33, 33, 33, 34, 34, 35 +}; + +static const short ssl_expr_yyr2[] = { 0, + 1, 1, 1, 2, 3, 3, 1, 3, 3, 3, + 3, 3, 3, 3, 5, 3, 3, 1, 3, 1, + 1, 4, 1, 1, 1, 4 +}; + +static const short ssl_expr_yydefact[] = { 0, + 2, 3, 20, 21, 0, 0, 0, 0, 1, 7, + 0, 23, 0, 4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, + 5, 6, 9, 10, 11, 12, 13, 14, 24, 25, + 16, 17, 0, 26, 22, 0, 18, 15, 0, 19, + 0, 0, 0 +}; + +static const short ssl_expr_yydefgoto[] = { 51, + 9, 10, 46, 11, 41, 12 +}; + +static const short ssl_expr_yypact[] = { 3, +-32768,-32768,-32768,-32768, -11, 3, 3, -10, 0,-32768, + 22,-32768, 16,-32768, -2, 23, 3, 3, 4, 4, + 4, 4, 4, 4, 34, 34, 21, 24,-32768, 25, + 26,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768, 4,-32768,-32768, 18,-32768,-32768, 4,-32768, + 49, 50,-32768 +}; + +static const short ssl_expr_yypgoto[] = {-32768, + 10,-32768,-32768, -19, 27,-32768 +}; + + +#define YYLAST 53 + + +static const short ssl_expr_yytable[] = { 33, + 34, 35, 36, 37, 38, 1, 2, 3, 3, 4, + 4, 13, 5, 5, 16, 14, 15, 17, 18, 17, + 18, 29, 28, 47, 6, 7, 31, 32, 30, 50, + 8, 8, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 39, 40, 48, 49, 43, 18, 44, 52, 53, + 45, 0, 42 +}; + +static const short ssl_expr_yycheck[] = { 19, + 20, 21, 22, 23, 24, 3, 4, 5, 5, 7, + 7, 23, 10, 10, 25, 6, 7, 20, 21, 20, + 21, 24, 7, 43, 22, 23, 17, 18, 6, 49, + 28, 28, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 8, 9, 26, 27, 25, 21, 24, 0, 0, + 26, -1, 26 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/local/share/bison.simple" +/* This file comes from bison-1.28. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +#ifndef YYSTACK_USE_ALLOCA +#ifdef alloca +#define YYSTACK_USE_ALLOCA +#else /* alloca not defined */ +#ifdef __GNUC__ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) +#define YYSTACK_USE_ALLOCA +#include <alloca.h> +#else /* not sparc */ +/* We think this test detects Watcom and Microsoft C. */ +/* This used to test MSDOS, but that is a bad idea + since that symbol is in the user namespace. */ +#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) +#if 0 /* No need for malloc.h, which pollutes the namespace; + instead, just don't use alloca. */ +#include <malloc.h> +#endif +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +/* I don't know what this was needed for, but it pollutes the namespace. + So I turned it off. rms, 2 May 1997. */ +/* #include <malloc.h> */ +#pragma alloca +#define YYSTACK_USE_ALLOCA +#else /* not MSDOS, or __TURBOC__, or _AIX */ +#if 0 +#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, + and on HPUX 10. Eventually we can turn this on. */ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#endif /* __hpux */ +#endif +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc */ +#endif /* not GNU C */ +#endif /* alloca not defined */ +#endif /* YYSTACK_USE_ALLOCA not defined */ + +#ifdef YYSTACK_USE_ALLOCA +#define YYSTACK_ALLOC alloca +#else +#define YYSTACK_ALLOC malloc +#endif + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define ssl_expr_yyerrok (ssl_expr_yyerrstatus = 0) +#define ssl_expr_yyclearin (ssl_expr_yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto ssl_expr_yyacceptlab +#define YYABORT goto ssl_expr_yyabortlab +#define YYERROR goto ssl_expr_yyerrlab1 +/* Like YYERROR except do call ssl_expr_yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto ssl_expr_yyerrlab +#define YYRECOVERING() (!!ssl_expr_yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (ssl_expr_yychar == YYEMPTY && ssl_expr_yylen == 1) \ + { ssl_expr_yychar = (token), ssl_expr_yylval = (value); \ + ssl_expr_yychar1 = YYTRANSLATE (ssl_expr_yychar); \ + YYPOPSTACK; \ + goto ssl_expr_yybackup; \ + } \ + else \ + { ssl_expr_yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX ssl_expr_yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX ssl_expr_yylex(&ssl_expr_yylval, &ssl_expr_yylloc, YYLEX_PARAM) +#else +#define YYLEX ssl_expr_yylex(&ssl_expr_yylval, &ssl_expr_yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX ssl_expr_yylex(&ssl_expr_yylval, YYLEX_PARAM) +#else +#define YYLEX ssl_expr_yylex(&ssl_expr_yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int ssl_expr_yychar; /* the lookahead symbol */ +YYSTYPE ssl_expr_yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE ssl_expr_yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int ssl_expr_yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int ssl_expr_yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Define __ssl_expr_yy_memcpy. Note that the size argument + should be passed with type unsigned int, because that is what the non-GCC + definitions require. With GCC, __builtin_memcpy takes an arg + of type size_t, but it can handle unsigned int. */ + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __ssl_expr_yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__ssl_expr_yy_memcpy (to, from, count) + char *to; + char *from; + unsigned int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__ssl_expr_yy_memcpy (char *to, char *from, unsigned int count) +{ + register char *t = to; + register char *f = from; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 217 "/usr/local/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into ssl_expr_yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +#ifdef YYPARSE_PARAM +int ssl_expr_yyparse (void *); +#else +int ssl_expr_yyparse (void); +#endif +#endif + +int +ssl_expr_yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int ssl_expr_yystate; + register int ssl_expr_yyn; + register short *ssl_expr_yyssp; + register YYSTYPE *ssl_expr_yyvsp; + int ssl_expr_yyerrstatus; /* number of tokens to shift before error messages enabled */ + int ssl_expr_yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short ssl_expr_yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE ssl_expr_yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *ssl_expr_yyss = ssl_expr_yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *ssl_expr_yyvs = ssl_expr_yyvsa; /* to allow ssl_expr_yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE ssl_expr_yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *ssl_expr_yyls = ssl_expr_yylsa; + YYLTYPE *ssl_expr_yylsp; + +#define YYPOPSTACK (ssl_expr_yyvsp--, ssl_expr_yyssp--, ssl_expr_yylsp--) +#else +#define YYPOPSTACK (ssl_expr_yyvsp--, ssl_expr_yyssp--) +#endif + + int ssl_expr_yystacksize = YYINITDEPTH; + int ssl_expr_yyfree_stacks = 0; + +#ifdef YYPURE + int ssl_expr_yychar; + YYSTYPE ssl_expr_yylval; + int ssl_expr_yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE ssl_expr_yylloc; +#endif +#endif + + YYSTYPE ssl_expr_yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int ssl_expr_yylen; + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + ssl_expr_yystate = 0; + ssl_expr_yyerrstatus = 0; + ssl_expr_yynerrs = 0; + ssl_expr_yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + ssl_expr_yyssp = ssl_expr_yyss - 1; + ssl_expr_yyvsp = ssl_expr_yyvs; +#ifdef YYLSP_NEEDED + ssl_expr_yylsp = ssl_expr_yyls; +#endif + +/* Push a new state, which is found in ssl_expr_yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +ssl_expr_yynewstate: + + *++ssl_expr_yyssp = ssl_expr_yystate; + + if (ssl_expr_yyssp >= ssl_expr_yyss + ssl_expr_yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *ssl_expr_yyvs1 = ssl_expr_yyvs; + short *ssl_expr_yyss1 = ssl_expr_yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *ssl_expr_yyls1 = ssl_expr_yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = ssl_expr_yyssp - ssl_expr_yyss + 1; + +#ifdef ssl_expr_yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if ssl_expr_yyoverflow is a macro. */ + ssl_expr_yyoverflow("parser stack overflow", + &ssl_expr_yyss1, size * sizeof (*ssl_expr_yyssp), + &ssl_expr_yyvs1, size * sizeof (*ssl_expr_yyvsp), + &ssl_expr_yyls1, size * sizeof (*ssl_expr_yylsp), + &ssl_expr_yystacksize); +#else + ssl_expr_yyoverflow("parser stack overflow", + &ssl_expr_yyss1, size * sizeof (*ssl_expr_yyssp), + &ssl_expr_yyvs1, size * sizeof (*ssl_expr_yyvsp), + &ssl_expr_yystacksize); +#endif + + ssl_expr_yyss = ssl_expr_yyss1; ssl_expr_yyvs = ssl_expr_yyvs1; +#ifdef YYLSP_NEEDED + ssl_expr_yyls = ssl_expr_yyls1; +#endif +#else /* no ssl_expr_yyoverflow */ + /* Extend the stack our own way. */ + if (ssl_expr_yystacksize >= YYMAXDEPTH) + { + ssl_expr_yyerror("parser stack overflow"); + if (ssl_expr_yyfree_stacks) + { + free (ssl_expr_yyss); + free (ssl_expr_yyvs); +#ifdef YYLSP_NEEDED + free (ssl_expr_yyls); +#endif + } + return 2; + } + ssl_expr_yystacksize *= 2; + if (ssl_expr_yystacksize > YYMAXDEPTH) + ssl_expr_yystacksize = YYMAXDEPTH; +#ifndef YYSTACK_USE_ALLOCA + ssl_expr_yyfree_stacks = 1; +#endif + ssl_expr_yyss = (short *) YYSTACK_ALLOC (ssl_expr_yystacksize * sizeof (*ssl_expr_yyssp)); + __ssl_expr_yy_memcpy ((char *)ssl_expr_yyss, (char *)ssl_expr_yyss1, + size * (unsigned int) sizeof (*ssl_expr_yyssp)); + ssl_expr_yyvs = (YYSTYPE *) YYSTACK_ALLOC (ssl_expr_yystacksize * sizeof (*ssl_expr_yyvsp)); + __ssl_expr_yy_memcpy ((char *)ssl_expr_yyvs, (char *)ssl_expr_yyvs1, + size * (unsigned int) sizeof (*ssl_expr_yyvsp)); +#ifdef YYLSP_NEEDED + ssl_expr_yyls = (YYLTYPE *) YYSTACK_ALLOC (ssl_expr_yystacksize * sizeof (*ssl_expr_yylsp)); + __ssl_expr_yy_memcpy ((char *)ssl_expr_yyls, (char *)ssl_expr_yyls1, + size * (unsigned int) sizeof (*ssl_expr_yylsp)); +#endif +#endif /* no ssl_expr_yyoverflow */ + + ssl_expr_yyssp = ssl_expr_yyss + size - 1; + ssl_expr_yyvsp = ssl_expr_yyvs + size - 1; +#ifdef YYLSP_NEEDED + ssl_expr_yylsp = ssl_expr_yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + fprintf(stderr, "Stack size increased to %d\n", ssl_expr_yystacksize); +#endif + + if (ssl_expr_yyssp >= ssl_expr_yyss + ssl_expr_yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + fprintf(stderr, "Entering state %d\n", ssl_expr_yystate); +#endif + + goto ssl_expr_yybackup; + ssl_expr_yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* ssl_expr_yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + ssl_expr_yyn = ssl_expr_yypact[ssl_expr_yystate]; + if (ssl_expr_yyn == YYFLAG) + goto ssl_expr_yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* ssl_expr_yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (ssl_expr_yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + fprintf(stderr, "Reading a token: "); +#endif + ssl_expr_yychar = YYLEX; + } + + /* Convert token to internal form (in ssl_expr_yychar1) for indexing tables with */ + + if (ssl_expr_yychar <= 0) /* This means end of input. */ + { + ssl_expr_yychar1 = 0; + ssl_expr_yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + ssl_expr_yychar1 = YYTRANSLATE(ssl_expr_yychar); + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + { + fprintf (stderr, "Next token is %d (%s", ssl_expr_yychar, ssl_expr_yytname[ssl_expr_yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, ssl_expr_yychar, ssl_expr_yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + ssl_expr_yyn += ssl_expr_yychar1; + if (ssl_expr_yyn < 0 || ssl_expr_yyn > YYLAST || ssl_expr_yycheck[ssl_expr_yyn] != ssl_expr_yychar1) + goto ssl_expr_yydefault; + + ssl_expr_yyn = ssl_expr_yytable[ssl_expr_yyn]; + + /* ssl_expr_yyn is what to do for this token type in this state. + Negative => reduce, -ssl_expr_yyn is rule number. + Positive => shift, ssl_expr_yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (ssl_expr_yyn < 0) + { + if (ssl_expr_yyn == YYFLAG) + goto ssl_expr_yyerrlab; + ssl_expr_yyn = -ssl_expr_yyn; + goto ssl_expr_yyreduce; + } + else if (ssl_expr_yyn == 0) + goto ssl_expr_yyerrlab; + + if (ssl_expr_yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + fprintf(stderr, "Shifting token %d (%s), ", ssl_expr_yychar, ssl_expr_yytname[ssl_expr_yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (ssl_expr_yychar != YYEOF) + ssl_expr_yychar = YYEMPTY; + + *++ssl_expr_yyvsp = ssl_expr_yylval; +#ifdef YYLSP_NEEDED + *++ssl_expr_yylsp = ssl_expr_yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (ssl_expr_yyerrstatus) ssl_expr_yyerrstatus--; + + ssl_expr_yystate = ssl_expr_yyn; + goto ssl_expr_yynewstate; + +/* Do the default action for the current state. */ +ssl_expr_yydefault: + + ssl_expr_yyn = ssl_expr_yydefact[ssl_expr_yystate]; + if (ssl_expr_yyn == 0) + goto ssl_expr_yyerrlab; + +/* Do a reduction. ssl_expr_yyn is the number of a rule to reduce with. */ +ssl_expr_yyreduce: + ssl_expr_yylen = ssl_expr_yyr2[ssl_expr_yyn]; + if (ssl_expr_yylen > 0) + ssl_expr_yyval = ssl_expr_yyvsp[1-ssl_expr_yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + ssl_expr_yyn, ssl_expr_yyrline[ssl_expr_yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = ssl_expr_yyprhs[ssl_expr_yyn]; ssl_expr_yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", ssl_expr_yytname[ssl_expr_yyrhs[i]]); + fprintf (stderr, " -> %s\n", ssl_expr_yytname[ssl_expr_yyr1[ssl_expr_yyn]]); + } +#endif + + + switch (ssl_expr_yyn) { + +case 1: +#line 115 "ssl_expr_parse.y" +{ ssl_expr_info.expr = ssl_expr_yyvsp[0].exVal; ; + break;} +case 2: +#line 118 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_True, NULL, NULL); ; + break;} +case 3: +#line 119 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_False, NULL, NULL); ; + break;} +case 4: +#line 120 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_Not, ssl_expr_yyvsp[0].exVal, NULL); ; + break;} +case 5: +#line 121 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_Or, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 6: +#line 122 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_And, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 7: +#line 123 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_Comp, ssl_expr_yyvsp[0].exVal, NULL); ; + break;} +case 8: +#line 124 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_yyvsp[-1].exVal; ; + break;} +case 9: +#line 127 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_EQ, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 10: +#line 128 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_NE, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 11: +#line 129 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_LT, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 12: +#line 130 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_LE, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 13: +#line 131 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_GT, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 14: +#line 132 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_GE, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 15: +#line 133 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_IN, ssl_expr_yyvsp[-4].exVal, ssl_expr_yyvsp[-1].exVal); ; + break;} +case 16: +#line 134 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_REG, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 17: +#line 135 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_NRE, ssl_expr_yyvsp[-2].exVal, ssl_expr_yyvsp[0].exVal); ; + break;} +case 18: +#line 138 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_ListElement, ssl_expr_yyvsp[0].exVal, NULL); ; + break;} +case 19: +#line 139 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_ListElement, ssl_expr_yyvsp[0].exVal, ssl_expr_yyvsp[-2].exVal); ; + break;} +case 20: +#line 142 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_Digit, ssl_expr_yyvsp[0].cpVal, NULL); ; + break;} +case 21: +#line 143 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_String, ssl_expr_yyvsp[0].cpVal, NULL); ; + break;} +case 22: +#line 144 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_make(op_Var, ssl_expr_yyvsp[-1].cpVal, NULL); ; + break;} +case 23: +#line 145 "ssl_expr_parse.y" +{ ssl_expr_yyval.exVal = ssl_expr_yyvsp[0].exVal; ; + break;} +case 24: +#line 148 "ssl_expr_parse.y" +{ + regex_t *regex; + if ((regex = ap_pregcomp(ssl_expr_info.pool, ssl_expr_yyvsp[0].cpVal, + REG_EXTENDED|REG_NOSUB)) == NULL) { + ssl_expr_error = "Failed to compile regular expression"; + YYERROR; + regex = NULL; + } + ssl_expr_yyval.exVal = ssl_expr_make(op_Regex, regex, NULL); + ; + break;} +case 25: +#line 158 "ssl_expr_parse.y" +{ + regex_t *regex; + if ((regex = ap_pregcomp(ssl_expr_info.pool, ssl_expr_yyvsp[0].cpVal, + REG_EXTENDED|REG_NOSUB|REG_ICASE)) == NULL) { + ssl_expr_error = "Failed to compile regular expression"; + YYERROR; + regex = NULL; + } + ssl_expr_yyval.exVal = ssl_expr_make(op_Regex, regex, NULL); + ; + break;} +case 26: +#line 170 "ssl_expr_parse.y" +{ + ssl_expr *args = ssl_expr_make(op_ListElement, ssl_expr_yyvsp[-1].cpVal, NULL); + ssl_expr_yyval.exVal = ssl_expr_make(op_Func, "file", args); + ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 543 "/usr/local/share/bison.simple" + + ssl_expr_yyvsp -= ssl_expr_yylen; + ssl_expr_yyssp -= ssl_expr_yylen; +#ifdef YYLSP_NEEDED + ssl_expr_yylsp -= ssl_expr_yylen; +#endif + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + { + short *ssp1 = ssl_expr_yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != ssl_expr_yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++ssl_expr_yyvsp = ssl_expr_yyval; + +#ifdef YYLSP_NEEDED + ssl_expr_yylsp++; + if (ssl_expr_yylen == 0) + { + ssl_expr_yylsp->first_line = ssl_expr_yylloc.first_line; + ssl_expr_yylsp->first_column = ssl_expr_yylloc.first_column; + ssl_expr_yylsp->last_line = (ssl_expr_yylsp-1)->last_line; + ssl_expr_yylsp->last_column = (ssl_expr_yylsp-1)->last_column; + ssl_expr_yylsp->text = 0; + } + else + { + ssl_expr_yylsp->last_line = (ssl_expr_yylsp+ssl_expr_yylen-1)->last_line; + ssl_expr_yylsp->last_column = (ssl_expr_yylsp+ssl_expr_yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + ssl_expr_yyn = ssl_expr_yyr1[ssl_expr_yyn]; + + ssl_expr_yystate = ssl_expr_yypgoto[ssl_expr_yyn - YYNTBASE] + *ssl_expr_yyssp; + if (ssl_expr_yystate >= 0 && ssl_expr_yystate <= YYLAST && ssl_expr_yycheck[ssl_expr_yystate] == *ssl_expr_yyssp) + ssl_expr_yystate = ssl_expr_yytable[ssl_expr_yystate]; + else + ssl_expr_yystate = ssl_expr_yydefgoto[ssl_expr_yyn - YYNTBASE]; + + goto ssl_expr_yynewstate; + +ssl_expr_yyerrlab: /* here on detecting error */ + + if (! ssl_expr_yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++ssl_expr_yynerrs; + +#ifdef YYERROR_VERBOSE + ssl_expr_yyn = ssl_expr_yypact[ssl_expr_yystate]; + + if (ssl_expr_yyn > YYFLAG && ssl_expr_yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -ssl_expr_yyn if nec to avoid negative indexes in ssl_expr_yycheck. */ + for (x = (ssl_expr_yyn < 0 ? -ssl_expr_yyn : 0); + x < (sizeof(ssl_expr_yytname) / sizeof(char *)); x++) + if (ssl_expr_yycheck[x + ssl_expr_yyn] == x) + size += strlen(ssl_expr_yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (ssl_expr_yyn < 0 ? -ssl_expr_yyn : 0); + x < (sizeof(ssl_expr_yytname) / sizeof(char *)); x++) + if (ssl_expr_yycheck[x + ssl_expr_yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, ssl_expr_yytname[x]); + strcat(msg, "'"); + count++; + } + } + ssl_expr_yyerror(msg); + free(msg); + } + else + ssl_expr_yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + ssl_expr_yyerror("parse error"); + } + + goto ssl_expr_yyerrlab1; +ssl_expr_yyerrlab1: /* here on error raised explicitly by an action */ + + if (ssl_expr_yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (ssl_expr_yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", ssl_expr_yychar, ssl_expr_yytname[ssl_expr_yychar1]); +#endif + + ssl_expr_yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + ssl_expr_yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto ssl_expr_yyerrhandle; + +ssl_expr_yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + ssl_expr_yyn = ssl_expr_yydefact[ssl_expr_yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (ssl_expr_yyn) goto ssl_expr_yydefault; +#endif + +ssl_expr_yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (ssl_expr_yyssp == ssl_expr_yyss) YYABORT; + ssl_expr_yyvsp--; + ssl_expr_yystate = *--ssl_expr_yyssp; +#ifdef YYLSP_NEEDED + ssl_expr_yylsp--; +#endif + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + { + short *ssp1 = ssl_expr_yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != ssl_expr_yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +ssl_expr_yyerrhandle: + + ssl_expr_yyn = ssl_expr_yypact[ssl_expr_yystate]; + if (ssl_expr_yyn == YYFLAG) + goto ssl_expr_yyerrdefault; + + ssl_expr_yyn += YYTERROR; + if (ssl_expr_yyn < 0 || ssl_expr_yyn > YYLAST || ssl_expr_yycheck[ssl_expr_yyn] != YYTERROR) + goto ssl_expr_yyerrdefault; + + ssl_expr_yyn = ssl_expr_yytable[ssl_expr_yyn]; + if (ssl_expr_yyn < 0) + { + if (ssl_expr_yyn == YYFLAG) + goto ssl_expr_yyerrpop; + ssl_expr_yyn = -ssl_expr_yyn; + goto ssl_expr_yyreduce; + } + else if (ssl_expr_yyn == 0) + goto ssl_expr_yyerrpop; + + if (ssl_expr_yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (ssl_expr_yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++ssl_expr_yyvsp = ssl_expr_yylval; +#ifdef YYLSP_NEEDED + *++ssl_expr_yylsp = ssl_expr_yylloc; +#endif + + ssl_expr_yystate = ssl_expr_yyn; + goto ssl_expr_yynewstate; + + ssl_expr_yyacceptlab: + /* YYACCEPT comes here. */ + if (ssl_expr_yyfree_stacks) + { + free (ssl_expr_yyss); + free (ssl_expr_yyvs); +#ifdef YYLSP_NEEDED + free (ssl_expr_yyls); +#endif + } + return 0; + + ssl_expr_yyabortlab: + /* YYABORT comes here. */ + if (ssl_expr_yyfree_stacks) + { + free (ssl_expr_yyss); + free (ssl_expr_yyvs); +#ifdef YYLSP_NEEDED + free (ssl_expr_yyls); +#endif + } + return 1; +} +#line 176 "ssl_expr_parse.y" + + +int ssl_expr_yyerror(char *s) +{ + ssl_expr_error = s; + return 2; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_parse.h b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_parse.h new file mode 100644 index 00000000..5378e287 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_parse.h @@ -0,0 +1,27 @@ +typedef union { + char *cpVal; + ssl_expr *exVal; +} YYSTYPE; +#define T_TRUE 257 +#define T_FALSE 258 +#define T_DIGIT 259 +#define T_ID 260 +#define T_STRING 261 +#define T_REGEX 262 +#define T_REGEX_I 263 +#define T_FUNC_FILE 264 +#define T_OP_EQ 265 +#define T_OP_NE 266 +#define T_OP_LT 267 +#define T_OP_LE 268 +#define T_OP_GT 269 +#define T_OP_GE 270 +#define T_OP_REG 271 +#define T_OP_NRE 272 +#define T_OP_IN 273 +#define T_OP_OR 274 +#define T_OP_AND 275 +#define T_OP_NOT 276 + + +extern YYSTYPE ssl_expr_yylval; diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_parse.y b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_parse.y new file mode 100644 index 00000000..649e1541 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_parse.y @@ -0,0 +1,148 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | + * | '_ ` _ \ / _ \ / _` | / __/ __| | + * | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL + * |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/ + * |_____| + * ssl_expr_parse.y + * Expression LR(1) Parser + */ + /* ``What you see is all you get.'' + -- Brian Kernighan */ + +/* _________________________________________________________________ +** +** Expression Parser +** _________________________________________________________________ +*/ + +%{ +#include "mod_ssl.h" +%} + +%union { + char *cpVal; + ssl_expr *exVal; +} + +%token T_TRUE +%token T_FALSE + +%token <cpVal> T_DIGIT +%token <cpVal> T_ID +%token <cpVal> T_STRING +%token <cpVal> T_REGEX +%token <cpVal> T_REGEX_I + +%token T_FUNC_FILE + +%token T_OP_EQ +%token T_OP_NE +%token T_OP_LT +%token T_OP_LE +%token T_OP_GT +%token T_OP_GE +%token T_OP_REG +%token T_OP_NRE +%token T_OP_IN + +%token T_OP_OR +%token T_OP_AND +%token T_OP_NOT + +%left T_OP_OR +%left T_OP_AND +%left T_OP_NOT + +%type <exVal> expr +%type <exVal> comparison +%type <exVal> funccall +%type <exVal> regex +%type <exVal> words +%type <exVal> word + +%% + +root : expr { ssl_expr_info.expr = $1; } + ; + +expr : T_TRUE { $$ = ssl_expr_make(op_True, NULL, NULL); } + | T_FALSE { $$ = ssl_expr_make(op_False, NULL, NULL); } + | T_OP_NOT expr { $$ = ssl_expr_make(op_Not, $2, NULL); } + | expr T_OP_OR expr { $$ = ssl_expr_make(op_Or, $1, $3); } + | expr T_OP_AND expr { $$ = ssl_expr_make(op_And, $1, $3); } + | comparison { $$ = ssl_expr_make(op_Comp, $1, NULL); } + | '(' expr ')' { $$ = $2; } + ; + +comparison: word T_OP_EQ word { $$ = ssl_expr_make(op_EQ, $1, $3); } + | word T_OP_NE word { $$ = ssl_expr_make(op_NE, $1, $3); } + | word T_OP_LT word { $$ = ssl_expr_make(op_LT, $1, $3); } + | word T_OP_LE word { $$ = ssl_expr_make(op_LE, $1, $3); } + | word T_OP_GT word { $$ = ssl_expr_make(op_GT, $1, $3); } + | word T_OP_GE word { $$ = ssl_expr_make(op_GE, $1, $3); } + | word T_OP_IN '{' words '}' { $$ = ssl_expr_make(op_IN, $1, $4); } + | word T_OP_REG regex { $$ = ssl_expr_make(op_REG, $1, $3); } + | word T_OP_NRE regex { $$ = ssl_expr_make(op_NRE, $1, $3); } + ; + +words : word { $$ = ssl_expr_make(op_ListElement, $1, NULL); } + | words ',' word { $$ = ssl_expr_make(op_ListElement, $3, $1); } + ; + +word : T_DIGIT { $$ = ssl_expr_make(op_Digit, $1, NULL); } + | T_STRING { $$ = ssl_expr_make(op_String, $1, NULL); } + | '%' '{' T_ID '}' { $$ = ssl_expr_make(op_Var, $3, NULL); } + | funccall { $$ = $1; } + ; + +regex : T_REGEX { + regex_t *regex; + if ((regex = ap_pregcomp(ssl_expr_info.pool, $1, + REG_EXTENDED|REG_NOSUB)) == NULL) { + ssl_expr_error = "Failed to compile regular expression"; + YYERROR; + } + $$ = ssl_expr_make(op_Regex, regex, NULL); + } + | T_REGEX_I { + regex_t *regex; + if ((regex = ap_pregcomp(ssl_expr_info.pool, $1, + REG_EXTENDED|REG_NOSUB|REG_ICASE)) == NULL) { + ssl_expr_error = "Failed to compile regular expression"; + YYERROR; + } + $$ = ssl_expr_make(op_Regex, regex, NULL); + } + ; + +funccall : T_FUNC_FILE '(' T_STRING ')' { + ssl_expr *args = ssl_expr_make(op_ListElement, $3, NULL); + $$ = ssl_expr_make(op_Func, "file", args); + } + ; + +%% + +int yyerror(char *s) +{ + ssl_expr_error = s; + return 2; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_scan.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_scan.c new file mode 100644 index 00000000..12977a3e --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_scan.c @@ -0,0 +1,1969 @@ +#define yy_create_buffer ssl_expr_yy_create_buffer +#define yy_delete_buffer ssl_expr_yy_delete_buffer +#define yy_scan_buffer ssl_expr_yy_scan_buffer +#define yy_scan_string ssl_expr_yy_scan_string +#define yy_scan_bytes ssl_expr_yy_scan_bytes +#define yy_flex_debug ssl_expr_yy_flex_debug +#define yy_init_buffer ssl_expr_yy_init_buffer +#define yy_flush_buffer ssl_expr_yy_flush_buffer +#define yy_load_buffer_state ssl_expr_yy_load_buffer_state +#define yy_switch_to_buffer ssl_expr_yy_switch_to_buffer +#define yyin ssl_expr_yyin +#define yyleng ssl_expr_yyleng +#define yylex ssl_expr_yylex +#define yyout ssl_expr_yyout +#define yyrestart ssl_expr_yyrestart +#define yytext ssl_expr_yytext + +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/striker/cvs2svn/dumps/httpd-2.0/../../httpd-2.0/modules/ssl/ssl_expr_scan.c,v 1.12.2.4 2004/02/09 20:53:20 nd Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <unistd.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ +#pragma warn -rch +#pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + + +#define yywrap() 1 +#define YY_SKIP_YYWRAP +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 46 +#define YY_END_OF_BUFFER 47 +static yyconst short int yy_accept[86] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 47, 45, + 1, 38, 2, 45, 43, 24, 45, 28, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, + 13, 4, 3, 14, 16, 18, 17, 1, 22, 32, + 34, 43, 26, 20, 31, 30, 44, 44, 19, 44, + 44, 29, 27, 39, 25, 23, 15, 15, 21, 44, + 35, 44, 36, 13, 12, 5, 6, 10, 11, 7, + 8, 9, 33, 44, 44, 37, 44, 5, 6, 44, + 40, 41, 5, 42, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 1, 1, 1, 6, 1, 1, + 1, 1, 1, 1, 7, 1, 1, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 7, 1, 10, + 11, 12, 1, 1, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 1, 14, 1, 1, 7, 1, 15, 16, 13, 17, + + 18, 19, 20, 13, 21, 13, 13, 22, 23, 24, + 25, 13, 26, 27, 28, 29, 30, 13, 13, 13, + 13, 13, 1, 31, 1, 32, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[33] = + { 0, + 1, 1, 2, 1, 3, 1, 4, 4, 4, 1, + 1, 1, 4, 3, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 1, 1 + } ; + +static yyconst short int yy_base[93] = + { 0, + 0, 0, 30, 31, 0, 0, 82, 81, 101, 142, + 35, 28, 142, 94, 32, 88, 31, 87, 0, 69, + 66, 28, 28, 67, 29, 63, 30, 63, 62, 57, + 0, 142, 142, 88, 142, 142, 142, 48, 142, 142, + 142, 44, 142, 142, 142, 142, 0, 70, 0, 64, + 63, 0, 0, 0, 0, 0, 142, 0, 0, 55, + 0, 46, 142, 0, 142, 53, 62, 142, 142, 142, + 142, 142, 0, 44, 48, 0, 41, 70, 72, 38, + 0, 0, 74, 0, 142, 117, 121, 125, 50, 129, + 133, 137 + + } ; + +static yyconst short int yy_def[93] = + { 0, + 85, 1, 86, 86, 87, 87, 88, 88, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 89, 89, + 89, 89, 89, 89, 89, 90, 89, 89, 89, 85, + 91, 85, 85, 92, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 85, 89, 89, 89, + 89, 89, 85, 91, 85, 85, 85, 85, 85, 85, + 85, 85, 89, 89, 89, 89, 89, 85, 85, 89, + 89, 89, 85, 89, 0, 85, 85, 85, 85, 85, + 85, 85 + + } ; + +static yyconst short int yy_nxt[175] = + { 0, + 10, 11, 11, 12, 13, 14, 10, 15, 15, 16, + 17, 18, 19, 10, 20, 19, 19, 21, 22, 23, + 24, 25, 26, 27, 28, 19, 19, 19, 29, 19, + 30, 10, 32, 32, 33, 33, 38, 38, 39, 42, + 42, 44, 50, 34, 34, 52, 55, 59, 51, 38, + 38, 42, 42, 47, 60, 84, 53, 56, 82, 40, + 78, 79, 45, 57, 57, 81, 57, 57, 57, 79, + 79, 80, 57, 57, 57, 77, 57, 83, 79, 79, + 79, 79, 79, 76, 75, 74, 73, 63, 62, 61, + 54, 49, 48, 57, 57, 66, 67, 46, 43, 41, + + 85, 37, 37, 68, 85, 85, 69, 85, 85, 85, + 85, 70, 85, 85, 71, 85, 72, 31, 31, 31, + 31, 35, 35, 35, 35, 36, 36, 36, 36, 58, + 85, 58, 58, 64, 85, 85, 64, 65, 65, 65, + 65, 9, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85 + } ; + +static yyconst short int yy_chk[175] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 4, 3, 4, 11, 11, 12, 15, + 15, 17, 22, 3, 4, 23, 25, 27, 22, 38, + 38, 42, 42, 89, 27, 80, 23, 25, 77, 12, + 66, 66, 17, 26, 26, 75, 26, 26, 26, 67, + 67, 74, 26, 26, 26, 62, 26, 78, 78, 79, + 79, 83, 83, 60, 51, 50, 48, 30, 29, 28, + 24, 21, 20, 26, 26, 34, 34, 18, 16, 14, + + 9, 8, 7, 34, 0, 0, 34, 0, 0, 0, + 0, 34, 0, 0, 34, 0, 34, 86, 86, 86, + 86, 87, 87, 87, 87, 88, 88, 88, 88, 90, + 0, 90, 90, 91, 0, 0, 91, 92, 92, 92, + 92, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "ssl_expr_scan.l" +#define INITIAL 0 +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | + * | '_ ` _ \ / _ \ / _` | / __/ __| | + * | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL + * |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/ + * |_____| + * ssl_expr_scan.l + * Expression Scanner + */ +/* ``Killing for peace is +like fucking for virginity.'' +-- Unknown */ +/* _________________________________________________________________ +** +** Expression Scanner +** _________________________________________________________________ +*/ +#line 38 "ssl_expr_scan.l" +#include "mod_ssl.h" + +#include "ssl_expr_parse.h" + +#define YY_NO_UNPUT 1 +int yyinput(char *buf, int max_size); + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + (result = yyinput(buf, max_size)) + +#define MAX_STR_LEN 2048 +/* %option stack */ +#define YY_NEVER_INTERACTIVE 1 +#define str 1 + +#define regex 2 +#define regex_flags 3 + +#line 535 "lex.ssl_expr_yy.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 91 "ssl_expr_scan.l" + + + char caStr[MAX_STR_LEN]; + char *cpStr = NULL; + char caRegex[MAX_STR_LEN]; + char *cpRegex = NULL; + char cRegexDel = NUL; + + /* + * Whitespaces + */ +#line 698 "lex.ssl_expr_yy.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 86 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 85 ); + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 102 "ssl_expr_scan.l" +{ + /* NOP */ +} + YY_BREAK +/* + * C-style strings ("...") + */ +case 2: +YY_RULE_SETUP +#line 109 "ssl_expr_scan.l" +{ + cpStr = caStr; + BEGIN(str); +} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 113 "ssl_expr_scan.l" +{ + BEGIN(INITIAL); + *cpStr = NUL; + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, caStr); + return T_STRING; +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 119 "ssl_expr_scan.l" +{ + yyerror("Unterminated string"); +} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 122 "ssl_expr_scan.l" +{ + int result; + + (void)sscanf(yytext+1, "%o", &result); + if (result > 0xff) + yyerror("Escape sequence out of bound"); + else + *cpStr++ = result; +} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 131 "ssl_expr_scan.l" +{ + yyerror("Bad escape sequence"); +} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 134 "ssl_expr_scan.l" +{ *cpStr++ = '\n'; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 135 "ssl_expr_scan.l" +{ *cpStr++ = '\r'; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 136 "ssl_expr_scan.l" +{ *cpStr++ = '\t'; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 137 "ssl_expr_scan.l" +{ *cpStr++ = '\b'; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 138 "ssl_expr_scan.l" +{ *cpStr++ = '\f'; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 139 "ssl_expr_scan.l" +{ + *cpStr++ = yytext[1]; +} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 142 "ssl_expr_scan.l" +{ + char *cp = yytext; + while (*cp != NUL) + *cpStr++ = *cp++; +} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 147 "ssl_expr_scan.l" +{ + *cpStr++ = yytext[1]; +} + YY_BREAK +/* + * Regular Expression + */ +case 15: +YY_RULE_SETUP +#line 154 "ssl_expr_scan.l" +{ + cRegexDel = yytext[1]; + cpRegex = caRegex; + BEGIN(regex); +} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 159 "ssl_expr_scan.l" +{ + if (yytext[0] == cRegexDel) { + *cpRegex = NUL; + BEGIN(regex_flags); + } + else { + *cpRegex++ = yytext[0]; + } +} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 168 "ssl_expr_scan.l" +{ + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, caRegex); + BEGIN(INITIAL); + return T_REGEX_I; +} + YY_BREAK +case 18: +YY_RULE_SETUP +#line 173 "ssl_expr_scan.l" +{ + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, caRegex); + yyless(0); + BEGIN(INITIAL); + return T_REGEX; +} + YY_BREAK +case YY_STATE_EOF(regex_flags): +#line 179 "ssl_expr_scan.l" +{ + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, caRegex); + BEGIN(INITIAL); + return T_REGEX; +} + YY_BREAK +/* + * Operators + */ +case 19: +YY_RULE_SETUP +#line 188 "ssl_expr_scan.l" +{ return T_OP_EQ; } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 189 "ssl_expr_scan.l" +{ return T_OP_EQ; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 190 "ssl_expr_scan.l" +{ return T_OP_NE; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 191 "ssl_expr_scan.l" +{ return T_OP_NE; } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 192 "ssl_expr_scan.l" +{ return T_OP_LT; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 193 "ssl_expr_scan.l" +{ return T_OP_LT; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 194 "ssl_expr_scan.l" +{ return T_OP_LE; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 195 "ssl_expr_scan.l" +{ return T_OP_LE; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 196 "ssl_expr_scan.l" +{ return T_OP_GT; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 197 "ssl_expr_scan.l" +{ return T_OP_GT; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 198 "ssl_expr_scan.l" +{ return T_OP_GE; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 199 "ssl_expr_scan.l" +{ return T_OP_GE; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 200 "ssl_expr_scan.l" +{ return T_OP_REG; } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 201 "ssl_expr_scan.l" +{ return T_OP_NRE; } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 202 "ssl_expr_scan.l" +{ return T_OP_AND; } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 203 "ssl_expr_scan.l" +{ return T_OP_AND; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 204 "ssl_expr_scan.l" +{ return T_OP_OR; } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 205 "ssl_expr_scan.l" +{ return T_OP_OR; } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 206 "ssl_expr_scan.l" +{ return T_OP_NOT; } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 207 "ssl_expr_scan.l" +{ return T_OP_NOT; } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 208 "ssl_expr_scan.l" +{ return T_OP_IN; } + YY_BREAK +/* + * Functions + */ +case 40: +YY_RULE_SETUP +#line 213 "ssl_expr_scan.l" +{ return T_FUNC_FILE; } + YY_BREAK +/* + * Specials + */ +case 41: +YY_RULE_SETUP +#line 218 "ssl_expr_scan.l" +{ return T_TRUE; } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 219 "ssl_expr_scan.l" +{ return T_FALSE; } + YY_BREAK +/* + * Digits + */ +case 43: +YY_RULE_SETUP +#line 224 "ssl_expr_scan.l" +{ + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, yytext); + return T_DIGIT; +} + YY_BREAK +/* + * Identifiers + */ +case 44: +YY_RULE_SETUP +#line 232 "ssl_expr_scan.l" +{ + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, yytext); + return T_ID; +} + YY_BREAK +/* + * Anything else is returned as is... + */ +case 45: +YY_RULE_SETUP +#line 240 "ssl_expr_scan.l" +{ + return yytext[0]; +} + YY_BREAK +case 46: +YY_RULE_SETUP +#line 244 "ssl_expr_scan.l" +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK +#line 1098 "lex.ssl_expr_yy.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(str): +case YY_STATE_EOF(regex): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 86 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 86 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 85); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 244 "ssl_expr_scan.l" + + +int yyinput(char *buf, int max_size) +{ + int n; + + if ((n = MIN(max_size, ssl_expr_info.inputbuf + + ssl_expr_info.inputlen + - ssl_expr_info.inputptr)) <= 0) + return YY_NULL; + memcpy(buf, ssl_expr_info.inputptr, n); + ssl_expr_info.inputptr += n; + return n; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_scan.l b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_scan.l new file mode 100644 index 00000000..86ba3b49 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_expr_scan.l @@ -0,0 +1,225 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | + * | '_ ` _ \ / _ \ / _` | / __/ __| | + * | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL + * |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/ + * |_____| + * ssl_expr_scan.l + * Expression Scanner + */ + /* ``Killing for peace is + like fucking for virginity.'' + -- Unknown */ + +/* _________________________________________________________________ +** +** Expression Scanner +** _________________________________________________________________ +*/ + +%{ +#include "mod_ssl.h" + +#include "ssl_expr_parse.h" + +#define YY_NO_UNPUT 1 +int yyinput(char *buf, int max_size); + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + (result = yyinput(buf, max_size)) + +#define MAX_STR_LEN 2048 +%} + +%pointer +/* %option stack */ +%option never-interactive +%option noyywrap +%x str +%x regex regex_flags + +%% + + char caStr[MAX_STR_LEN]; + char *cpStr = NULL; + char caRegex[MAX_STR_LEN]; + char *cpRegex = NULL; + char cRegexDel = NUL; + + /* + * Whitespaces + */ +[ \t\n]+ { + /* NOP */ +} + + /* + * C-style strings ("...") + */ +\" { + cpStr = caStr; + BEGIN(str); +} +<str>\" { + BEGIN(INITIAL); + *cpStr = NUL; + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, caStr); + return T_STRING; +} +<str>\n { + yyerror("Unterminated string"); +} +<str>\\[0-7]{1,3} { + int result; + + (void)sscanf(yytext+1, "%o", &result); + if (result > 0xff) + yyerror("Escape sequence out of bound"); + else + *cpStr++ = result; +} +<str>\\[0-9]+ { + yyerror("Bad escape sequence"); +} +<str>\\n { *cpStr++ = '\n'; } +<str>\\r { *cpStr++ = '\r'; } +<str>\\t { *cpStr++ = '\t'; } +<str>\\b { *cpStr++ = '\b'; } +<str>\\f { *cpStr++ = '\f'; } +<str>\\(.|\n) { + *cpStr++ = yytext[1]; +} +<str>[^\\\n\"]+ { + char *cp = yytext; + while (*cp != NUL) + *cpStr++ = *cp++; +} +<str>. { + *cpStr++ = yytext[1]; +} + + /* + * Regular Expression + */ +"m". { + cRegexDel = yytext[1]; + cpRegex = caRegex; + BEGIN(regex); +} +<regex>.|\n { + if (yytext[0] == cRegexDel) { + *cpRegex = NUL; + BEGIN(regex_flags); + } + else { + *cpRegex++ = yytext[0]; + } +} +<regex_flags>i { + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, caRegex); + BEGIN(INITIAL); + return T_REGEX_I; +} +<regex_flags>.|\n { + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, caRegex); + yyless(0); + BEGIN(INITIAL); + return T_REGEX; +} +<regex_flags><<EOF>> { + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, caRegex); + BEGIN(INITIAL); + return T_REGEX; +} + + /* + * Operators + */ +"eq" { return T_OP_EQ; } +"==" { return T_OP_EQ; } +"ne" { return T_OP_NE; } +"!=" { return T_OP_NE; } +"lt" { return T_OP_LT; } +"<" { return T_OP_LT; } +"le" { return T_OP_LE; } +"<=" { return T_OP_LE; } +"gt" { return T_OP_GT; } +">" { return T_OP_GT; } +"ge" { return T_OP_GE; } +">=" { return T_OP_GE; } +"=~" { return T_OP_REG; } +"!~" { return T_OP_NRE; } +"and" { return T_OP_AND; } +"&&" { return T_OP_AND; } +"or" { return T_OP_OR; } +"||" { return T_OP_OR; } +"not" { return T_OP_NOT; } +"!" { return T_OP_NOT; } +"in" { return T_OP_IN; } + + /* + * Functions + */ +"file" { return T_FUNC_FILE; } + + /* + * Specials + */ +"true" { return T_TRUE; } +"false" { return T_FALSE; } + + /* + * Digits + */ +[0-9]+ { + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, yytext); + return T_DIGIT; +} + + /* + * Identifiers + */ +[a-zA-Z][a-zA-Z0-9_:-]* { + yylval.cpVal = apr_pstrdup(ssl_expr_info.pool, yytext); + return T_ID; +} + + /* + * Anything else is returned as is... + */ +.|\n { + return yytext[0]; +} + +%% + +int yyinput(char *buf, int max_size) +{ + int n; + + if ((n = MIN(max_size, ssl_expr_info.inputbuf + + ssl_expr_info.inputlen + - ssl_expr_info.inputptr)) <= 0) + return YY_NULL; + memcpy(buf, ssl_expr_info.inputptr, n); + ssl_expr_info.inputptr += n; + return n; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache.c new file mode 100644 index 00000000..d74b853b --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache.c @@ -0,0 +1,199 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_scache.c + * Session Cache Abstraction + */ + /* ``Open-Source Software: generous + programmers from around the world all + join forces to help you shoot + yourself in the foot for free.'' + -- Unknown */ +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** Session Cache: Common Abstraction Layer +** _________________________________________________________________ +*/ + +void ssl_scache_init(server_rec *s, apr_pool_t *p) +{ + SSLModConfigRec *mc = myModConfig(s); + + /* + * Warn the user that he should use the session cache. + * But we can operate without it, of course. + */ + if (mc->nSessionCacheMode == SSL_SCMODE_UNSET) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "Init: Session Cache is not configured " + "[hint: SSLSessionCache]"); + mc->nSessionCacheMode = SSL_SCMODE_NONE; + return; + } + + if (mc->nSessionCacheMode == SSL_SCMODE_DBM) + ssl_scache_dbm_init(s, p); + else if ((mc->nSessionCacheMode == SSL_SCMODE_SHMHT) || + (mc->nSessionCacheMode == SSL_SCMODE_SHMCB)) { + void *data; + const char *userdata_key = "ssl_scache_init"; + + apr_pool_userdata_get(&data, userdata_key, s->process->pool); + if (!data) { + apr_pool_userdata_set((const void *)1, userdata_key, + apr_pool_cleanup_null, s->process->pool); + return; + } + if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) + ssl_scache_shmht_init(s, p); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) + ssl_scache_shmcb_init(s, p); + } +} + +void ssl_scache_kill(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + + if (mc->nSessionCacheMode == SSL_SCMODE_DBM) + ssl_scache_dbm_kill(s); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) + ssl_scache_shmht_kill(s); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) + ssl_scache_shmcb_kill(s); + return; +} + +BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) +{ + SSLModConfigRec *mc = myModConfig(s); + BOOL rv = FALSE; + + if (mc->nSessionCacheMode == SSL_SCMODE_DBM) + rv = ssl_scache_dbm_store(s, id, idlen, expiry, sess); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) + rv = ssl_scache_shmht_store(s, id, idlen, expiry, sess); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) + rv = ssl_scache_shmcb_store(s, id, idlen, expiry, sess); + return rv; +} + +SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + SSL_SESSION *sess = NULL; + + if (mc->nSessionCacheMode == SSL_SCMODE_DBM) + sess = ssl_scache_dbm_retrieve(s, id, idlen); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) + sess = ssl_scache_shmht_retrieve(s, id, idlen); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) + sess = ssl_scache_shmcb_retrieve(s, id, idlen); + return sess; +} + +void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + + if (mc->nSessionCacheMode == SSL_SCMODE_DBM) + ssl_scache_dbm_remove(s, id, idlen); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) + ssl_scache_shmht_remove(s, id, idlen); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) + ssl_scache_shmcb_remove(s, id, idlen); + return; +} + +void ssl_scache_status(server_rec *s, apr_pool_t *p, void (*func)(char *, void *), void *arg) +{ + SSLModConfigRec *mc = myModConfig(s); + + if (mc->nSessionCacheMode == SSL_SCMODE_DBM) + ssl_scache_dbm_status(s, p, func, arg); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) + ssl_scache_shmht_status(s, p, func, arg); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) + ssl_scache_shmcb_status(s, p, func, arg); + return; +} + +void ssl_scache_expire(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + + if (mc->nSessionCacheMode == SSL_SCMODE_DBM) + ssl_scache_dbm_expire(s); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) + ssl_scache_shmht_expire(s); + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) + ssl_scache_shmcb_expire(s); + return; +} + +/* _________________________________________________________________ +** +** SSL Extension to mod_status +** _________________________________________________________________ +*/ +#if 0 /* NOT YET */ +static void ssl_ext_ms_display(request_rec *, int, int); + +void ssl_scache_status_register(apr_pool_t *p) +{ + /* XXX point mod_status to this update, when it grows the opt fn */ +#if 0 + ap_hook_register("ap::mod_status::display", ssl_ext_ms_display, AP_HOOK_NOCTX); +#endif + return; +} + +static void ssl_ext_ms_display_cb(char *str, void *_r) +{ + request_rec *r = (request_rec *)_r; + if (str != NULL) + ap_rputs(str, r); + return; +} + +static void ssl_ext_ms_display(request_rec *r, int no_table_report, int short_report) +{ + SSLSrvConfigRec *sc = mySrvConfig(r->server); + + if (sc == NULL) + return; + if (short_report) + return; + ap_rputs("<hr>\n", r); + ap_rputs("<table cellspacing=0 cellpadding=0>\n", r); + ap_rputs("<tr><td bgcolor=\"#000000\">\n", r); + ap_rputs("<b><font color=\"#ffffff\" face=\"Arial,Helvetica\">SSL/TLS Session Cache Status:</font></b>\r", r); + ap_rputs("</td></tr>\n", r); + ap_rputs("<tr><td bgcolor=\"#ffffff\">\n", r); + ssl_scache_status(r->server, r->pool, ssl_ext_ms_display_cb, r); + ap_rputs("</td></tr>\n", r); + ap_rputs("</table>\n", r); + return; +} +#endif diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_dbm.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_dbm.c new file mode 100644 index 00000000..10ab9c89 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_dbm.c @@ -0,0 +1,462 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_scache_dbm.c + * Session Cache via DBM + */ + +#include "mod_ssl.h" + +void ssl_scache_dbm_init(server_rec *s, apr_pool_t *p) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_status_t rv; + + /* for the DBM we need the data file */ + if (mc->szSessionCacheDataFile == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "SSLSessionCache required"); + ssl_die(); + } + + /* open it once to create it and to make sure it _can_ be created */ + ssl_mutex_on(s); + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot create SSLSessionCache DBM file `%s'", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + return; + } + apr_dbm_close(dbm); + +#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) + /* + * We have to make sure the Apache child processes have access to + * the DBM file. But because there are brain-dead platforms where we + * cannot exactly determine the suffixes we try all possibilities. + */ + if (geteuid() == 0 /* is superuser */) { + chown(mc->szSessionCacheDataFile, unixd_config.user_id, -1 /* no gid change */); + if (chown(apr_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_DIR, NULL), + unixd_config.user_id, -1) == -1) { + if (chown(apr_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL), + unixd_config.user_id, -1) == -1) + chown(apr_pstrcat(p, mc->szSessionCacheDataFile, ".dir", NULL), + unixd_config.user_id, -1); + } + if (chown(apr_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_PAG, NULL), + unixd_config.user_id, -1) == -1) { + if (chown(apr_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL), + unixd_config.user_id, -1) == -1) + chown(apr_pstrcat(p, mc->szSessionCacheDataFile, ".pag", NULL), + unixd_config.user_id, -1); + } + } +#endif + ssl_mutex_off(s); + ssl_scache_dbm_expire(s); + return; +} + +void ssl_scache_dbm_kill(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_pool_t *p; + + apr_pool_sub_make(&p, mc->pPool, NULL); + if (p != NULL) { + /* the correct way */ + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_DIR, NULL)); + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_PAG, NULL)); + /* the additional ways to be sure */ + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, ".dir", NULL)); + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, ".pag", NULL)); + unlink(apr_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL)); + unlink(mc->szSessionCacheDataFile); + apr_pool_destroy(p); + } + return; +} + +BOOL ssl_scache_dbm_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + UCHAR ucaData[SSL_SESSION_MAX_DER]; + int nData; + UCHAR *ucp; + apr_status_t rv; + + /* streamline session data */ + if ((nData = i2d_SSL_SESSION(sess, NULL)) > sizeof(ucaData)) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "streamline session data size too large: %d > %d", + nData, sizeof(ucaData)); + return FALSE; + } + ucp = ucaData; + i2d_SSL_SESSION(sess, &ucp); + + /* be careful: do not try to store too much bytes in a DBM file! */ +#ifdef PAIRMAX + if ((idlen + nData) >= PAIRMAX) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "data size too large for DBM session cache: %d >= %d", + (idlen + nData), PAIRMAX); + return FALSE; + } +#else + if ((idlen + nData) >= 950 /* at least less than approx. 1KB */) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "data size too large for DBM session cache: %d >= %d", + (idlen + nData), 950); + return FALSE; + } +#endif + + /* create DBM key */ + dbmkey.dptr = (char *)id; + dbmkey.dsize = idlen; + + /* create DBM value */ + dbmval.dsize = sizeof(time_t) + nData; + dbmval.dptr = (char *)malloc(dbmval.dsize); + if (dbmval.dptr == NULL) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "malloc error creating DBM value"); + return FALSE; + } + memcpy((char *)dbmval.dptr, &expiry, sizeof(time_t)); + memcpy((char *)dbmval.dptr+sizeof(time_t), ucaData, nData); + + /* and store it to the DBM file */ + ssl_mutex_on(s); + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot open SSLSessionCache DBM file `%s' for writing " + "(store)", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + free(dbmval.dptr); + return FALSE; + } + if ((rv = apr_dbm_store(dbm, dbmkey, dbmval)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot store SSL session to DBM file `%s'", + mc->szSessionCacheDataFile); + apr_dbm_close(dbm); + ssl_mutex_off(s); + free(dbmval.dptr); + return FALSE; + } + apr_dbm_close(dbm); + ssl_mutex_off(s); + + /* free temporary buffers */ + free(dbmval.dptr); + + /* allow the regular expiring to occur */ + ssl_scache_dbm_expire(s); + + return TRUE; +} + +SSL_SESSION *ssl_scache_dbm_retrieve(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + SSL_SESSION *sess = NULL; + MODSSL_D2I_SSL_SESSION_CONST unsigned char *ucpData; + int nData; + time_t expiry; + time_t now; + apr_status_t rc; + + /* allow the regular expiring to occur */ + ssl_scache_dbm_expire(s); + + /* create DBM key and values */ + dbmkey.dptr = (char *)id; + dbmkey.dsize = idlen; + + /* and fetch it from the DBM file + * XXX: Should we open the dbm against r->pool so the cleanup will + * do the apr_dbm_close? This would make the code a bit cleaner. + */ + ssl_mutex_on(s); + if ((rc = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, + "Cannot open SSLSessionCache DBM file `%s' for reading " + "(fetch)", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + return NULL; + } + rc = apr_dbm_fetch(dbm, dbmkey, &dbmval); + if (rc != APR_SUCCESS) { + apr_dbm_close(dbm); + ssl_mutex_off(s); + return NULL; + } + if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(time_t)) { + apr_dbm_close(dbm); + ssl_mutex_off(s); + return NULL; + } + + /* parse resulting data */ + nData = dbmval.dsize-sizeof(time_t); + ucpData = malloc(nData); + if (ucpData == NULL) { + apr_dbm_close(dbm); + ssl_mutex_off(s); + return NULL; + } + /* Cast needed, ucpData may be const */ + memcpy((unsigned char *)ucpData, + (char *)dbmval.dptr + sizeof(time_t), nData); + memcpy(&expiry, dbmval.dptr, sizeof(time_t)); + + apr_dbm_close(dbm); + ssl_mutex_off(s); + + /* make sure the stuff is still not expired */ + now = time(NULL); + if (expiry <= now) { + ssl_scache_dbm_remove(s, id, idlen); + return NULL; + } + + /* unstreamed SSL_SESSION */ + sess = d2i_SSL_SESSION(NULL, &ucpData, nData); + + return sess; +} + +void ssl_scache_dbm_remove(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_status_t rv; + + /* create DBM key and values */ + dbmkey.dptr = (char *)id; + dbmkey.dsize = idlen; + + /* and delete it from the DBM file */ + ssl_mutex_on(s); + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot open SSLSessionCache DBM file `%s' for writing " + "(delete)", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + return; + } + apr_dbm_delete(dbm, dbmkey); + apr_dbm_close(dbm); + ssl_mutex_off(s); + + return; +} + +void ssl_scache_dbm_expire(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + SSLSrvConfigRec *sc = mySrvConfig(s); + static time_t tLast = 0; + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + apr_pool_t *p; + time_t tExpiresAt; + int nElements = 0; + int nDeleted = 0; + int bDelete; + apr_datum_t *keylist; + int keyidx; + int i; + time_t tNow; + apr_status_t rv; + + /* + * make sure the expiration for still not-accessed session + * cache entries is done only from time to time + */ + tNow = time(NULL); + if (tNow < tLast+sc->session_cache_timeout) + return; + tLast = tNow; + + /* + * Here we have to be very carefully: Not all DBM libraries are + * smart enough to allow one to iterate over the elements and at the + * same time delete expired ones. Some of them get totally crazy + * while others have no problems. So we have to do it the slower but + * more safe way: we first iterate over all elements and remember + * those which have to be expired. Then in a second pass we delete + * all those expired elements. Additionally we reopen the DBM file + * to be really safe in state. + */ + +#define KEYMAX 1024 + + ssl_mutex_on(s); + for (;;) { + /* allocate the key array in a memory sub pool */ + apr_pool_sub_make(&p, mc->pPool, NULL); + if (p == NULL) + break; + if ((keylist = apr_palloc(p, sizeof(dbmkey)*KEYMAX)) == NULL) { + apr_pool_destroy(p); + break; + } + + /* pass 1: scan DBM database */ + keyidx = 0; + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE,SSL_DBM_FILE_MODE, + p)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot open SSLSessionCache DBM file `%s' for " + "scanning", + mc->szSessionCacheDataFile); + apr_pool_destroy(p); + break; + } + apr_dbm_firstkey(dbm, &dbmkey); + while (dbmkey.dptr != NULL) { + nElements++; + bDelete = FALSE; + apr_dbm_fetch(dbm, dbmkey, &dbmval); + if (dbmval.dsize <= sizeof(time_t) || dbmval.dptr == NULL) + bDelete = TRUE; + else { + memcpy(&tExpiresAt, dbmval.dptr, sizeof(time_t)); + if (tExpiresAt <= tNow) + bDelete = TRUE; + } + if (bDelete) { + if ((keylist[keyidx].dptr = apr_palloc(p, dbmkey.dsize)) != NULL) { + memcpy(keylist[keyidx].dptr, dbmkey.dptr, dbmkey.dsize); + keylist[keyidx].dsize = dbmkey.dsize; + keyidx++; + if (keyidx == KEYMAX) + break; + } + } + apr_dbm_nextkey(dbm, &dbmkey); + } + apr_dbm_close(dbm); + + /* pass 2: delete expired elements */ + if (apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE,SSL_DBM_FILE_MODE, p) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot re-open SSLSessionCache DBM file `%s' for " + "expiring", + mc->szSessionCacheDataFile); + apr_pool_destroy(p); + break; + } + for (i = 0; i < keyidx; i++) { + apr_dbm_delete(dbm, keylist[i]); + nDeleted++; + } + apr_dbm_close(dbm); + + /* destroy temporary pool */ + apr_pool_destroy(p); + + if (keyidx < KEYMAX) + break; + } + ssl_mutex_off(s); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Inter-Process Session Cache (DBM) Expiry: " + "old: %d, new: %d, removed: %d", + nElements, nElements-nDeleted, nDeleted); + return; +} + +void ssl_scache_dbm_status(server_rec *s, apr_pool_t *p, void (*func)(char *, void *), void *arg) +{ + SSLModConfigRec *mc = myModConfig(s); + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + int nElem; + int nSize; + int nAverage; + apr_status_t rv; + + nElem = 0; + nSize = 0; + ssl_mutex_on(s); + /* + * XXX - Check what pool is to be used - TBD + */ + if ((rv = apr_dbm_open(&dbm, mc->szSessionCacheDataFile, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, + mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot open SSLSessionCache DBM file `%s' for status " + "retrival", + mc->szSessionCacheDataFile); + ssl_mutex_off(s); + return; + } + /* + * XXX - Check the return value of apr_dbm_firstkey, apr_dbm_fetch - TBD + */ + apr_dbm_firstkey(dbm, &dbmkey); + for ( ; dbmkey.dptr != NULL; apr_dbm_nextkey(dbm, &dbmkey)) { + apr_dbm_fetch(dbm, dbmkey, &dbmval); + if (dbmval.dptr == NULL) + continue; + nElem += 1; + nSize += dbmval.dsize; + } + apr_dbm_close(dbm); + ssl_mutex_off(s); + if (nSize > 0 && nElem > 0) + nAverage = nSize / nElem; + else + nAverage = 0; + func(apr_psprintf(p, "cache type: <b>DBM</b>, maximum size: <b>unlimited</b><br>"), arg); + func(apr_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg); + func(apr_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg); + return; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_shmcb.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_shmcb.c new file mode 100644 index 00000000..cee66bf5 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_shmcb.c @@ -0,0 +1,1362 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_scache_shmcb.c + * Session Cache via Shared Memory (Cyclic Buffer Variant) + */ + +#include "mod_ssl.h" + +/* + * This shared memory based SSL session cache implementation was + * originally written by Geoff Thorpe <geoff@geoffthorpe.net> for C2Net + * Europe as a contribution to Ralf Engelschall's mod_ssl project. + */ + +/* + * The shared-memory segment header can be cast to and from the + * SHMCBHeader type, all other structures need to be initialised by + * utility functions. + * + * The "header" looks like this; + * + * data applying to the overall structure: + * - division_offset (unsigned int): + * how far into the shared memory segment the first division is. + * - division_size (unsigned int): + * how many bytes each division occupies. + * (NB: This includes the queue and the cache) + * - division_mask (unsigned char): + * the "mask" in the next line. Add one to this, + * and that's the number of divisions. + * + * data applying to within each division: + * - queue_size (unsigned int): + * how big each "queue" is. NB: The queue is the first block in each + * division and is followed immediately by the cache itself so so + * there's no cache_offset value. + * + * data applying to within each queue: + * - index_num (unsigned char): + * how many indexes in each cache's queue + * - index_offset (unsigned char): + * how far into the queue the first index is. + * - index_size: + * how big each index is. + * + * data applying to within each cache: + * - cache_data_offset (unsigned int): + * how far into the cache the session-data array is stored. + * - cache_data_size (unsigned int): + * how big each cache's data block is. + * + * statistics data (this will eventually be per-division but right now + * there's only one mutex): + * - stores (unsigned long): + * how many stores have been performed in the cache. + * - expiries (unsigned long): + * how many session have been expired from the cache. + * - scrolled (unsigned long): + * how many sessions have been scrolled out of full cache during a + * "store" operation. This is different to the "removes" stats as + * they are requested by mod_ssl/Apache, these are done because of + * cache logistics. (NB: Also, this value should be deducible from + * the others if my code has no bugs, but I count it anyway - plus + * it helps debugging :-). + * - retrieves_hit (unsigned long): + * how many session-retrieves have succeeded. + * - retrieves_miss (unsigned long): + * how many session-retrieves have failed. + * - removes_hit (unsigned long): + * - removes_miss (unsigned long): + * + * Following immediately after the header is an array of "divisions". + * Each division is simply a "queue" immediately followed by its + * corresponding "cache". Each division handles some pre-defined band + * of sessions by using the "division_mask" in the header. Eg. if + * division_mask=0x1f then there are 32 divisions, the first of which + * will store sessions whose least-significant 5 bits are 0, the second + * stores session whose LS 5 bits equal 1, etc. A queue is an indexing + * structure referring to its corresponding cache. + * + * A "queue" looks like this; + * + * - first_pos (unsigned int): + * the location within the array of indexes where the virtual + * "left-hand-edge" of the cyclic buffer is. + * - pos_count (unsigned int): + * the number of indexes occupied from first_pos onwards. + * + * ...followed by an array of indexes, each of which can be + * memcpy'd to and from an SHMCBIndex, and look like this; + * + * - expires (time_t): + * the time() value at which this session expires. + * - offset (unsigned int): + * the offset within the cache data block where the corresponding + * session is stored. + * - s_id2 (unsigned char): + * the second byte of the session_id, stored as an optimisation to + * reduce the number of d2i_SSL_SESSION calls that are made when doing + * a lookup. + * - removed (unsigned char): + * a byte used to indicate whether a session has been "passively" + * removed. Ie. it is still in the cache but is to be disregarded by + * any "retrieve" operation. + * + * A "cache" looks like this; + * + * - first_pos (unsigned int): + * the location within the data block where the virtual + * "left-hand-edge" of the cyclic buffer is. + * - pos_count (unsigned int): + * the number of bytes used in the data block from first_pos onwards. + * + * ...followed by the data block in which actual DER-encoded SSL + * sessions are stored. + */ + +/* + * Header - can be memcpy'd to and from the front of the shared + * memory segment. NB: The first copy (commented out) has the + * elements in a meaningful order, but due to data-alignment + * braindeadness, the second (uncommented) copy has the types grouped + * so as to decrease "struct-bloat". sigh. + */ +typedef struct { + unsigned long num_stores; + unsigned long num_expiries; + unsigned long num_scrolled; + unsigned long num_retrieves_hit; + unsigned long num_retrieves_miss; + unsigned long num_removes_hit; + unsigned long num_removes_miss; + unsigned int division_offset; + unsigned int division_size; + unsigned int queue_size; + unsigned int cache_data_offset; + unsigned int cache_data_size; + unsigned char division_mask; + unsigned int index_num; + unsigned int index_offset; + unsigned int index_size; +} SHMCBHeader; + +/* + * Index - can be memcpy'd to and from an index inside each + * queue's index array. + */ +typedef struct { + time_t expires; + unsigned int offset; + unsigned char s_id2; + unsigned char removed; +} SHMCBIndex; + +/* + * Queue - must be populated by a call to shmcb_get_division + * and the structure's pointers are used for updating (ie. + * the structure doesn't need any "set" to update values). + */ +typedef struct { + SHMCBHeader *header; + unsigned int *first_pos; + unsigned int *pos_count; + SHMCBIndex *indexes; +} SHMCBQueue; + +/* + * Cache - same comment as for Queue. 'Queue's are in a 1-1 + * correspondance with 'Cache's and are usually carried round + * in a pair, they are only seperated for clarity. + */ +typedef struct { + SHMCBHeader *header; + unsigned int *first_pos; + unsigned int *pos_count; + unsigned char *data; +} SHMCBCache; + +/* + * Forward function prototypes. + */ + +/* Functions for working around data-alignment-picky systems (sparcs, + Irix, etc). These use "memcpy" as a way of foxing these systems into + treating the composite types as byte-arrays rather than higher-level + primitives that it prefers to have 4-(or 8-)byte aligned. I don't + envisage this being a performance issue as a couple of 2 or 4 byte + memcpys can hardly make a dent on the massive memmove operations this + cache technique avoids, nor the overheads of ASN en/decoding. */ +static unsigned int shmcb_get_safe_uint(unsigned int *); +static void shmcb_set_safe_uint_ex(unsigned char *, const unsigned char *); +#define shmcb_set_safe_uint(pdest, src) \ + do { \ + unsigned int tmp_uint = src; \ + shmcb_set_safe_uint_ex((unsigned char *)pdest, \ + (const unsigned char *)(&tmp_uint)); \ + } while(0) +#if 0 /* Unused so far */ +static unsigned long shmcb_get_safe_ulong(unsigned long *); +static void shmcb_set_safe_ulong_ex(unsigned char *, const unsigned char *); +#define shmcb_set_safe_ulong(pdest, src) \ + do { \ + unsigned long tmp_ulong = src; \ + shmcb_set_safe_ulong_ex((unsigned char *)pdest, \ + (const unsigned char *)(&tmp_ulong)); \ + } while(0) +#endif +static time_t shmcb_get_safe_time(time_t *); +static void shmcb_set_safe_time_ex(unsigned char *, const unsigned char *); +#define shmcb_set_safe_time(pdest, src) \ + do { \ + time_t tmp_time = src; \ + shmcb_set_safe_time_ex((unsigned char *)pdest, \ + (const unsigned char *)(&tmp_time)); \ + } while(0) + +/* This is necessary simply so that the size passed to memset() is not a + * compile-time constant, preventing the compiler from optimising it. */ +static void shmcb_safe_clear(void *ptr, size_t size) +{ + memset(ptr, 0, size); +} + +/* Underlying functions for session-caching */ +static BOOL shmcb_init_memory(server_rec *, void *, unsigned int); +static BOOL shmcb_store_session(server_rec *, void *, UCHAR *, int, SSL_SESSION *, time_t); +static SSL_SESSION *shmcb_retrieve_session(server_rec *, void *, UCHAR *, int); +static BOOL shmcb_remove_session(server_rec *, void *, UCHAR *, int); + +/* Utility functions for manipulating the structures */ +static void shmcb_get_header(void *, SHMCBHeader **); +static BOOL shmcb_get_division(SHMCBHeader *, SHMCBQueue *, SHMCBCache *, unsigned int); +static SHMCBIndex *shmcb_get_index(const SHMCBQueue *, unsigned int); +static unsigned int shmcb_expire_division(server_rec *, SHMCBQueue *, SHMCBCache *); +static BOOL shmcb_insert_encoded_session(server_rec *, SHMCBQueue *, SHMCBCache *, unsigned char *, unsigned int, unsigned char *, time_t); +static SSL_SESSION *shmcb_lookup_session_id(server_rec *, SHMCBQueue *, SHMCBCache *, UCHAR *, unsigned int); +static BOOL shmcb_remove_session_id(server_rec *, SHMCBQueue *, SHMCBCache *, UCHAR *, unsigned int); + +/* + * Data-alignment functions (a.k.a. avoidance tactics) + * + * NB: On HPUX (and possibly others) there is a *very* mischievous little + * "optimisation" in the compilers where it will convert the following; + * memcpy(dest_ptr, &source, sizeof(unsigned int)); + * (where dest_ptr is of type (unsigned int *) and source is (unsigned int)) + * into; + * *dest_ptr = source; (or *dest_ptr = *(&source), not sure). + * Either way, it completely destroys the whole point of these _safe_ + * functions, because the assignment operation will fall victim to the + * architecture's byte-alignment dictations, whereas the memcpy (as a + * byte-by-byte copy) should not. sigh. So, if you're wondering about the + * apparently unnecessary conversions to (unsigned char *) in these + * functions, you now have an explanation. Don't just revert them back and + * say "ooh look, it still works" - if you try it on HPUX (well, 32-bit + * HPUX 11.00 at least) you may find it fails with a SIGBUS. :-( + */ + +static unsigned int shmcb_get_safe_uint(unsigned int *ptr) +{ + unsigned int ret; + shmcb_set_safe_uint_ex((unsigned char *)(&ret), + (const unsigned char *)ptr); + return ret; +} + +static void shmcb_set_safe_uint_ex(unsigned char *dest, + const unsigned char *src) +{ + memcpy(dest, src, sizeof(unsigned int)); +} + +#if 0 /* Unused so far */ +static unsigned long shmcb_get_safe_ulong(unsigned long *ptr) +{ + unsigned long ret; + shmcb_set_safe_ulong_ex((unsigned char *)(&ret), + (const unsigned char *)ptr); + return ret; +} + +static void shmcb_set_safe_ulong_ex(unsigned char *dest, + const unsigned char *src) +{ + memcpy(dest, src, sizeof(unsigned long)); +} +#endif + +static time_t shmcb_get_safe_time(time_t * ptr) +{ + time_t ret; + shmcb_set_safe_time_ex((unsigned char *)(&ret), + (const unsigned char *)ptr); + return ret; +} + +static void shmcb_set_safe_time_ex(unsigned char *dest, + const unsigned char *src) +{ + memcpy(dest, src, sizeof(time_t)); +} +/* +** +** High-Level "handlers" as per ssl_scache.c +** +*/ + +void ssl_scache_shmcb_init(server_rec *s, apr_pool_t *p) +{ + SSLModConfigRec *mc = myModConfig(s); + void *shm_segment; + apr_size_t shm_segsize; + apr_status_t rv; + + /* + * Create shared memory segment + */ + if (mc->szSessionCacheDataFile == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "SSLSessionCache required"); + ssl_die(); + } + + /* Use anonymous shm by default, fall back on name-based. */ + rv = apr_shm_create(&(mc->pSessionCacheDataMM), + mc->nSessionCacheDataSize, + NULL, mc->pPool); + + if (APR_STATUS_IS_ENOTIMPL(rv)) { + rv = apr_shm_create(&(mc->pSessionCacheDataMM), + mc->nSessionCacheDataSize, + mc->szSessionCacheDataFile, + mc->pPool); + } + + if (rv != APR_SUCCESS) { + char buf[100]; + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot allocate shared memory: (%d)%s", rv, + apr_strerror(rv, buf, sizeof(buf))); + ssl_die(); + } + shm_segment = apr_shm_baseaddr_get(mc->pSessionCacheDataMM); + shm_segsize = apr_shm_size_get(mc->pSessionCacheDataMM); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "shmcb_init allocated %" APR_SIZE_T_FMT + " bytes of shared memory", + shm_segsize); + if (!shmcb_init_memory(s, shm_segment, shm_segsize)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Failure initialising 'shmcb' shared memory"); + ssl_die(); + } + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Shared memory session cache initialised"); + + /* + * Success ... we hack the memory block into place by cheating for + * now and stealing a member variable the original shared memory + * cache was using. :-) + */ + mc->tSessionCacheDataTable = (table_t *) shm_segment; + return; +} + +void ssl_scache_shmcb_kill(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + + if (mc->pSessionCacheDataMM != NULL) { + apr_shm_destroy(mc->pSessionCacheDataMM); + mc->pSessionCacheDataMM = NULL; + } + return; +} + +BOOL ssl_scache_shmcb_store(server_rec *s, UCHAR *id, int idlen, + time_t timeout, SSL_SESSION * pSession) +{ + SSLModConfigRec *mc = myModConfig(s); + void *shm_segment; + BOOL to_return = FALSE; + + /* We've kludged our pointer into the other cache's member variable. */ + shm_segment = (void *) mc->tSessionCacheDataTable; + ssl_mutex_on(s); + if (!shmcb_store_session(s, shm_segment, id, idlen, pSession, timeout)) + /* in this cache engine, "stores" should never fail. */ + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "'shmcb' code was unable to store a " + "session in the cache."); + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "shmcb_store successful"); + to_return = TRUE; + } + ssl_mutex_off(s); + return to_return; +} + +SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + void *shm_segment; + SSL_SESSION *pSession; + + /* We've kludged our pointer into the other cache's member variable. */ + shm_segment = (void *) mc->tSessionCacheDataTable; + ssl_mutex_on(s); + pSession = shmcb_retrieve_session(s, shm_segment, id, idlen); + ssl_mutex_off(s); + if (pSession) + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "shmcb_retrieve had a hit"); + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "shmcb_retrieve had a miss"); + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Client requested a 'session-resume' but " + "we have no such session."); + } + return pSession; +} + +void ssl_scache_shmcb_remove(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + void *shm_segment; + + /* We've kludged our pointer into the other cache's member variable. */ + shm_segment = (void *) mc->tSessionCacheDataTable; + ssl_mutex_on(s); + shmcb_remove_session(s, shm_segment, id, idlen); + ssl_mutex_off(s); +} + +void ssl_scache_shmcb_expire(server_rec *s) +{ + /* NOP */ + return; +} + +void ssl_scache_shmcb_status(server_rec *s, apr_pool_t *p, + void (*func) (char *, void *), void *arg) +{ + SSLModConfigRec *mc = myModConfig(s); + SHMCBHeader *header; + SHMCBQueue queue; + SHMCBCache cache; + SHMCBIndex *idx; + void *shm_segment; + unsigned int loop, total, cache_total, non_empty_divisions; + int index_pct, cache_pct; + double expiry_total; + time_t average_expiry, now, max_expiry, min_expiry, idxexpiry; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "inside ssl_scache_shmcb_status"); + + /* We've kludged our pointer into the other cache's member variable. */ + shm_segment = (void *) mc->tSessionCacheDataTable; + + /* Get the header structure. */ + shmcb_get_header(shm_segment, &header); + total = cache_total = non_empty_divisions = 0; + average_expiry = max_expiry = min_expiry = 0; + expiry_total = 0; + + /* It may seem strange to grab "now" at this point, but in theory + * we should never have a negative threshold but grabbing "now" after + * the loop (which performs expiries) could allow that chance. */ + now = time(NULL); + for (loop = 0; loop <= header->division_mask; loop++) { + if (shmcb_get_division(header, &queue, &cache, loop)) { + shmcb_expire_division(s, &queue, &cache); + total += shmcb_get_safe_uint(queue.pos_count); + cache_total += shmcb_get_safe_uint(cache.pos_count); + if (shmcb_get_safe_uint(queue.pos_count) > 0) { + idx = shmcb_get_index(&queue, + shmcb_get_safe_uint(queue.first_pos)); + non_empty_divisions++; + idxexpiry = shmcb_get_safe_time(&(idx->expires)); + expiry_total += (double) idxexpiry; + max_expiry = (idxexpiry > max_expiry ? idxexpiry : + max_expiry); + if (min_expiry == 0) + min_expiry = idxexpiry; + else + min_expiry = (idxexpiry < min_expiry ? idxexpiry : + min_expiry); + } + } + } + index_pct = (100 * total) / (header->index_num * (header->division_mask + 1)); + cache_pct = (100 * cache_total) / (header->cache_data_size * (header->division_mask + 1)); + func(apr_psprintf(p, "cache type: <b>SHMCB</b>, shared memory: <b>%d</b> " + "bytes, current sessions: <b>%d</b><br>", + mc->nSessionCacheDataSize, total), arg); + func(apr_psprintf(p, "sub-caches: <b>%d</b>, indexes per sub-cache: " + "<b>%d</b><br>", (int) header->division_mask + 1, + (int) header->index_num), arg); + if (non_empty_divisions != 0) { + average_expiry = (time_t)(expiry_total / (double)non_empty_divisions); + func(apr_psprintf(p, "time left on oldest entries' SSL sessions: "), arg); + if (now < average_expiry) + func(apr_psprintf(p, "avg: <b>%d</b> seconds, (range: %d...%d)<br>", + (int)(average_expiry - now), (int) (min_expiry - now), + (int)(max_expiry - now)), arg); + else + func(apr_psprintf(p, "expiry threshold: <b>Calculation Error!</b>" + "<br>"), arg); + + } + func(apr_psprintf(p, "index usage: <b>%d%%</b>, cache usage: <b>%d%%</b>" + "<br>", index_pct, cache_pct), arg); + func(apr_psprintf(p, "total sessions stored since starting: <b>%lu</b><br>", + header->num_stores), arg); + func(apr_psprintf(p,"total sessions expired since starting: <b>%lu</b><br>", + header->num_expiries), arg); + func(apr_psprintf(p, "total (pre-expiry) sessions scrolled out of the " + "cache: <b>%lu</b><br>", header->num_scrolled), arg); + func(apr_psprintf(p, "total retrieves since starting: <b>%lu</b> hit, " + "<b>%lu</b> miss<br>", header->num_retrieves_hit, + header->num_retrieves_miss), arg); + func(apr_psprintf(p, "total removes since starting: <b>%lu</b> hit, " + "<b>%lu</b> miss<br>", header->num_removes_hit, + header->num_removes_miss), arg); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "leaving shmcb_status"); + return; +} + +/* +** +** Memory manipulation and low-level cache operations +** +*/ + +static BOOL shmcb_init_memory( + server_rec *s, void *shm_mem, + unsigned int shm_mem_size) +{ + SHMCBHeader *header; + SHMCBQueue queue; + SHMCBCache cache; + unsigned int temp, loop, granularity; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "entered shmcb_init_memory()"); + + /* Calculate some sizes... */ + temp = sizeof(SHMCBHeader); + + /* If the segment is ridiculously too small, bail out */ + if (shm_mem_size < (2*temp)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "shared memory segment too small"); + return FALSE; + } + + /* Make temp the amount of memory without the header */ + temp = shm_mem_size - temp; + + /* Work on the basis that you need 10 bytes index for each session + * (approx 150 bytes), which is to divide temp by 160 - and then + * make sure we err on having too index space to burn even when + * the cache is full, which is a lot less stupid than having + * having not enough index space to utilise the whole cache!. */ + temp /= 120; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "for %u bytes, recommending %u indexes", + shm_mem_size, temp); + + /* We should divide these indexes evenly amongst the queues. Try + * to get it so that there are roughly half the number of divisions + * as there are indexes in each division. */ + granularity = 256; + while ((temp / granularity) < (2 * granularity)) + granularity /= 2; + + /* So we have 'granularity' divisions, set 'temp' equal to the + * number of indexes in each division. */ + temp /= granularity; + + /* Too small? Bail ... */ + if (temp < 5) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "shared memory segment too small"); + return FALSE; + } + + /* OK, we're sorted - from here on in, the return should be TRUE */ + header = (SHMCBHeader *)shm_mem; + header->division_mask = (unsigned char)(granularity - 1); + header->division_offset = sizeof(SHMCBHeader); + header->index_num = temp; + header->index_offset = (2 * sizeof(unsigned int)); + header->index_size = sizeof(SHMCBIndex); + header->queue_size = header->index_offset + + (header->index_num * header->index_size); + + /* Now calculate the space for each division */ + temp = shm_mem_size - header->division_offset; + header->division_size = temp / granularity; + + /* Calculate the space left in each division for the cache */ + temp -= header->queue_size; + header->cache_data_offset = (2 * sizeof(unsigned int)); + header->cache_data_size = header->division_size - + header->queue_size - header->cache_data_offset; + + /* Output trace info */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "shmcb_init_memory choices follow"); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "division_mask = 0x%02X", header->division_mask); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "division_offset = %u", header->division_offset); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "division_size = %u", header->division_size); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "queue_size = %u", header->queue_size); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "index_num = %u", header->index_num); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "index_offset = %u", header->index_offset); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "index_size = %u", header->index_size); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "cache_data_offset = %u", header->cache_data_offset); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "cache_data_size = %u", header->cache_data_size); + + /* The header is done, make the caches empty */ + for (loop = 0; loop < granularity; loop++) { + if (!shmcb_get_division(header, &queue, &cache, loop)) + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "shmcb_init_memory, " "internal error"); + shmcb_set_safe_uint(cache.first_pos, 0); + shmcb_set_safe_uint(cache.pos_count, 0); + shmcb_set_safe_uint(queue.first_pos, 0); + shmcb_set_safe_uint(queue.pos_count, 0); + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "leaving shmcb_init_memory()"); + return TRUE; +} + +static BOOL shmcb_store_session( + server_rec *s, void *shm_segment, UCHAR *id, + int idlen, SSL_SESSION * pSession, + time_t timeout) +{ + SHMCBHeader *header; + SHMCBQueue queue; + SHMCBCache cache; + unsigned char masked_index; + unsigned char encoded[SSL_SESSION_MAX_DER]; + unsigned char *ptr_encoded; + unsigned int len_encoded; + time_t expiry_time; + unsigned char *session_id = SSL_SESSION_get_session_id(pSession); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "inside shmcb_store_session"); + + /* Get the header structure, which division this session will fall into etc. */ + shmcb_get_header(shm_segment, &header); + masked_index = session_id[0] & header->division_mask; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "session_id[0]=%u, masked index=%u", + session_id[0], masked_index); + if (!shmcb_get_division(header, &queue, &cache, (unsigned int)masked_index)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "shmcb_store_session internal error"); + return FALSE; + } + + /* Serialise the session, work out how much we're dealing + * with. NB: This check could be removed if we're not paranoid + * or we find some assurance that it will never be necessary. */ + len_encoded = i2d_SSL_SESSION(pSession, NULL); + if (len_encoded > SSL_SESSION_MAX_DER) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "session is too big (%u bytes)", len_encoded); + return FALSE; + } + ptr_encoded = encoded; + len_encoded = i2d_SSL_SESSION(pSession, &ptr_encoded); + expiry_time = timeout; + if (!shmcb_insert_encoded_session(s, &queue, &cache, encoded, + len_encoded, session_id, + expiry_time)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "can't store a session!"); + return FALSE; + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "leaving shmcb_store successfully"); + header->num_stores++; + return TRUE; +} + +static SSL_SESSION *shmcb_retrieve_session( + server_rec *s, void *shm_segment, + UCHAR *id, int idlen) +{ + SHMCBHeader *header; + SHMCBQueue queue; + SHMCBCache cache; + unsigned char masked_index; + SSL_SESSION *pSession; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "inside shmcb_retrieve_session"); + if (idlen < 2) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided " + "(%u bytes)", idlen); + return FALSE; + } + + /* Get the header structure, which division this session lookup + * will come from etc. */ + shmcb_get_header(shm_segment, &header); + masked_index = id[0] & header->division_mask; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "id[0]=%u, masked index=%u", id[0], masked_index); + if (!shmcb_get_division(header, &queue, &cache, (unsigned int) masked_index)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "shmcb_retrieve_session internal error"); + header->num_retrieves_miss++; + return FALSE; + } + + /* Get the session corresponding to the session_id or NULL if it + * doesn't exist (or is flagged as "removed"). */ + pSession = shmcb_lookup_session_id(s, &queue, &cache, id, idlen); + if (pSession) + header->num_retrieves_hit++; + else + header->num_retrieves_miss++; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "leaving shmcb_retrieve_session"); + return pSession; +} + +static BOOL shmcb_remove_session( + server_rec *s, void *shm_segment, + UCHAR *id, int idlen) +{ + SHMCBHeader *header; + SHMCBQueue queue; + SHMCBCache cache; + unsigned char masked_index; + BOOL res; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "inside shmcb_remove_session"); + if (id == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "remove called with NULL session_id!"); + return FALSE; + } + + /* Get the header structure, which division this session remove + * will happen in etc. */ + shmcb_get_header(shm_segment, &header); + masked_index = id[0] & header->division_mask; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "id[0]=%u, masked index=%u", id[0], masked_index); + if (!shmcb_get_division(header, &queue, &cache, (unsigned int)masked_index)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "shmcb_remove_session, internal error"); + header->num_removes_miss++; + return FALSE; + } + res = shmcb_remove_session_id(s, &queue, &cache, id, idlen); + if (res) + header->num_removes_hit++; + else + header->num_removes_miss++; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "leaving shmcb_remove_session"); + return res; +} + + +/* +** +** Weirdo cyclic buffer functions +** +*/ + +/* This gets used in the cyclic "index array" (in the 'Queue's) and + * in the cyclic 'Cache's too ... you provide the "width" of the + * cyclic store, the starting position and how far to move (with + * wrapping if necessary). Basically it's addition modulo buf_size. */ +static unsigned int shmcb_cyclic_increment( + unsigned int buf_size, + unsigned int start_pos, + unsigned int to_add) +{ + start_pos += to_add; + while (start_pos >= buf_size) + start_pos -= buf_size; + return start_pos; +} + +/* Given two positions in a cyclic buffer, calculate the "distance". + * This is to cover the case ("non-trivial") where the 'next' offset + * is to the left of the 'start' offset. NB: This calculates the + * space inclusive of one end-point but not the other. There is an + * ambiguous case (which is why we use the <start_pos,offset> + * coordinate system rather than <start_pos,end_pos> one) when 'start' + * is the same as 'next'. It could indicate the buffer is full or it + * can indicate the buffer is empty ... I choose the latter as it's + * easier and usually necessary to check if the buffer is full anyway + * before doing incremental logic (which is this useful for), but we + * definitely need the empty case handled - in fact it's our starting + * state!! */ +static unsigned int shmcb_cyclic_space( + unsigned int buf_size, + unsigned int start_offset, + unsigned int next_offset) +{ + /* Is it the trivial case? */ + if (start_offset <= next_offset) + return (next_offset - start_offset); /* yes */ + else + return ((buf_size - start_offset) + next_offset); /* no */ +} + +/* A "normal-to-cyclic" memcpy ... this takes a linear block of + * memory and copies it onto a cyclic buffer. The purpose and + * function of this is pretty obvious, you need to cover the case + * that the destination (cyclic) buffer has to wrap round. */ +static void shmcb_cyclic_ntoc_memcpy( + unsigned int buf_size, + unsigned char *data, + unsigned int dest_offset, + unsigned char *src, unsigned int src_len) +{ + /* Cover the case that src_len > buf_size */ + if (src_len > buf_size) + src_len = buf_size; + + /* Can it be copied all in one go? */ + if (dest_offset + src_len < buf_size) + /* yes */ + memcpy(data + dest_offset, src, src_len); + else { + /* no */ + memcpy(data + dest_offset, src, buf_size - dest_offset); + memcpy(data, src + buf_size - dest_offset, + src_len + dest_offset - buf_size); + } + return; +} + +/* A "cyclic-to-normal" memcpy ... given the last function, this + * one's purpose is clear, it copies out of a cyclic buffer handling + * wrapping. */ +static void shmcb_cyclic_cton_memcpy( + unsigned int buf_size, + unsigned char *dest, + unsigned char *data, + unsigned int src_offset, + unsigned int src_len) +{ + /* Cover the case that src_len > buf_size */ + if (src_len > buf_size) + src_len = buf_size; + + /* Can it be copied all in one go? */ + if (src_offset + src_len < buf_size) + /* yes */ + memcpy(dest, data + src_offset, src_len); + else { + /* no */ + memcpy(dest, data + src_offset, buf_size - src_offset); + memcpy(dest + buf_size - src_offset, data, + src_len + src_offset - buf_size); + } + return; +} + +/* Here's the cool hack that makes it all work ... by simply + * making the first collection of bytes *be* our header structure + * (casting it into the C structure), we have the perfect way to + * maintain state in a shared-memory session cache from one call + * (and process) to the next, use the shared memory itself! The + * original mod_ssl shared-memory session cache uses variables + * inside the context, but we simply use that for storing the + * pointer to the shared memory itself. And don't forget, after + * Apache's initialisation, this "header" is constant/read-only + * so we can read it outside any locking. + * <grin> - sometimes I just *love* coding y'know?! */ +static void shmcb_get_header(void *shm_mem, SHMCBHeader **header) +{ + *header = (SHMCBHeader *)shm_mem; + return; +} + +/* This is what populates our "interesting" structures. Given a + * pointer to the header, and an index into the appropriate + * division (this must have already been masked using the + * division_mask by the caller!), we can populate the provided + * SHMCBQueue and SHMCBCache structures with values and + * pointers to the underlying shared memory. Upon returning + * (if not FALSE), the caller can meddle with the pointer + * values and they will map into the shared-memory directly, + * as such there's no need to "free" or "set" the Queue or + * Cache values, they were themselves references to the *real* + * data. */ +static BOOL shmcb_get_division( + SHMCBHeader *header, SHMCBQueue *queue, + SHMCBCache *cache, unsigned int idx) +{ + unsigned char *pQueue; + unsigned char *pCache; + + /* bounds check */ + if (idx > (unsigned int) header->division_mask) + return FALSE; + + /* Locate the blocks of memory storing the corresponding data */ + pQueue = ((unsigned char *) header) + header->division_offset + + (idx * header->division_size); + pCache = pQueue + header->queue_size; + + /* Populate the structures with appropriate pointers */ + queue->first_pos = (unsigned int *) pQueue; + + /* Our structures stay packed, no matter what the system's + * data-alignment regime is. */ + queue->pos_count = (unsigned int *) (pQueue + sizeof(unsigned int)); + queue->indexes = (SHMCBIndex *) (pQueue + (2 * sizeof(unsigned int))); + cache->first_pos = (unsigned int *) pCache; + cache->pos_count = (unsigned int *) (pCache + sizeof(unsigned int)); + cache->data = (unsigned char *) (pCache + (2 * sizeof(unsigned int))); + queue->header = cache->header = header; + + return TRUE; +} + +/* This returns a pointer to the piece of shared memory containing + * a specified 'Index'. SHMCBIndex, like SHMCBHeader, is a fixed + * width non-referencing structure of primitive types that can be + * cast onto the corresponding block of shared memory. Thus, by + * returning a cast pointer to that section of shared memory, the + * caller can read and write values to and from the "structure" and + * they are actually reading and writing the underlying shared + * memory. */ +static SHMCBIndex *shmcb_get_index( + const SHMCBQueue *queue, unsigned int idx) +{ + /* bounds check */ + if (idx > queue->header->index_num) + return NULL; + + /* Return a pointer to the index. NB: I am being horribly pendantic + * here so as to avoid any potential data-alignment assumptions being + * placed on the pointer arithmetic by the compiler (sigh). */ + return (SHMCBIndex *)(((unsigned char *) queue->indexes) + + (idx * sizeof(SHMCBIndex))); +} + +/* This functions rolls expired cache (and index) entries off the front + * of the cyclic buffers in a division. The function returns the number + * of expired sessions. */ +static unsigned int shmcb_expire_division( + server_rec *s, SHMCBQueue *queue, SHMCBCache *cache) +{ + SHMCBIndex *idx; + time_t now; + unsigned int loop, index_num, pos_count, new_pos; + SHMCBHeader *header; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "entering shmcb_expire_division"); + + /* We must calculate num and space ourselves based on expiry times. */ + now = time(NULL); + loop = 0; + new_pos = shmcb_get_safe_uint(queue->first_pos); + + /* Cache useful values */ + header = queue->header; + index_num = header->index_num; + pos_count = shmcb_get_safe_uint(queue->pos_count); + while (loop < pos_count) { + idx = shmcb_get_index(queue, new_pos); + if (shmcb_get_safe_time(&(idx->expires)) > now) + /* it hasn't expired yet, we're done iterating */ + break; + /* This one should be expired too. Shift to the next entry. */ + loop++; + new_pos = shmcb_cyclic_increment(index_num, new_pos, 1); + } + + /* Find the new_offset and make the expiries happen. */ + if (loop > 0) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "will be expiring %u sessions", loop); + /* We calculate the new_offset by "peeking" (or in the + * case it's the last entry, "sneaking" ;-). */ + if (loop == pos_count) { + /* We are expiring everything! This is easy to do... */ + shmcb_set_safe_uint(queue->pos_count, 0); + shmcb_set_safe_uint(cache->pos_count, 0); + } + else { + /* The Queue is easy to adjust */ + shmcb_set_safe_uint(queue->pos_count, + shmcb_get_safe_uint(queue->pos_count) - loop); + shmcb_set_safe_uint(queue->first_pos, new_pos); + /* peek to the start of the next session */ + idx = shmcb_get_index(queue, new_pos); + /* We can use shmcb_cyclic_space because we've guaranteed + * we don't fit the ambiguous full/empty case. */ + shmcb_set_safe_uint(cache->pos_count, + shmcb_get_safe_uint(cache->pos_count) - + shmcb_cyclic_space(header->cache_data_size, + shmcb_get_safe_uint(cache->first_pos), + shmcb_get_safe_uint(&(idx->offset)))); + shmcb_set_safe_uint(cache->first_pos, shmcb_get_safe_uint(&(idx->offset))); + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "we now have %u sessions", + shmcb_get_safe_uint(queue->pos_count)); + } + header->num_expiries += loop; + return loop; +} + +/* Inserts a new encoded session into a queue/cache pair - expiring + * (early or otherwise) any leading sessions as necessary to ensure + * there is room. An error return (FALSE) should only happen in the + * event of surreal values being passed on, or ridiculously small + * cache sizes. NB: For tracing purposes, this function is also given + * the server_rec to allow "ssl_log()". */ +static BOOL shmcb_insert_encoded_session( + server_rec *s, SHMCBQueue * queue, + SHMCBCache * cache, + unsigned char *encoded, + unsigned int encoded_len, + unsigned char *session_id, + time_t expiry_time) +{ + SHMCBHeader *header; + SHMCBIndex *idx = NULL; + unsigned int gap, new_pos, loop, new_offset; + int need; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "entering shmcb_insert_encoded_session, " + "*queue->pos_count = %u", + shmcb_get_safe_uint(queue->pos_count)); + + /* If there's entries to expire, ditch them first thing. */ + shmcb_expire_division(s, queue, cache); + header = cache->header; + gap = header->cache_data_size - shmcb_get_safe_uint(cache->pos_count); + if (gap < encoded_len) { + new_pos = shmcb_get_safe_uint(queue->first_pos); + loop = 0; + need = (int) encoded_len - (int) gap; + while ((need > 0) && (loop + 1 < shmcb_get_safe_uint(queue->pos_count))) { + new_pos = shmcb_cyclic_increment(header->index_num, new_pos, 1); + loop += 1; + idx = shmcb_get_index(queue, new_pos); + need = (int) encoded_len - (int) gap - + shmcb_cyclic_space(header->cache_data_size, + shmcb_get_safe_uint(cache->first_pos), + shmcb_get_safe_uint(&(idx->offset))); + } + if (loop > 0) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "about to scroll %u sessions from %u", + loop, shmcb_get_safe_uint(queue->pos_count)); + /* We are removing "loop" items from the cache. */ + shmcb_set_safe_uint(cache->pos_count, + shmcb_get_safe_uint(cache->pos_count) - + shmcb_cyclic_space(header->cache_data_size, + shmcb_get_safe_uint(cache->first_pos), + shmcb_get_safe_uint(&(idx->offset)))); + shmcb_set_safe_uint(cache->first_pos, shmcb_get_safe_uint(&(idx->offset))); + shmcb_set_safe_uint(queue->pos_count, shmcb_get_safe_uint(queue->pos_count) - loop); + shmcb_set_safe_uint(queue->first_pos, new_pos); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "now only have %u sessions", + shmcb_get_safe_uint(queue->pos_count)); + /* Update the stats!!! */ + header->num_scrolled += loop; + } + } + + /* probably unecessary checks, but I'll leave them until this code + * is verified. */ + if (shmcb_get_safe_uint(cache->pos_count) + encoded_len > + header->cache_data_size) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "shmcb_insert_encoded_session internal error"); + return FALSE; + } + if (shmcb_get_safe_uint(queue->pos_count) == header->index_num) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "shmcb_insert_encoded_session internal error"); + return FALSE; + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "we have %u bytes and %u indexes free - enough", + header->cache_data_size - + shmcb_get_safe_uint(cache->pos_count), header->index_num - + shmcb_get_safe_uint(queue->pos_count)); + + + /* HERE WE ASSUME THAT THE NEW SESSION SHOULD GO ON THE END! I'M NOT + * CHECKING WHETHER IT SHOULD BE GENUINELY "INSERTED" SOMEWHERE. + * + * We either fix that, or find out at a "higher" (read "mod_ssl") + * level whether it is possible to have distinct session caches for + * any attempted tomfoolery to do with different session timeouts. + * Knowing in advance that we can have a cache-wide constant timeout + * would make this stuff *MUCH* more efficient. Mind you, it's very + * efficient right now because I'm ignoring this problem!!! + */ + + /* Increment to the first unused byte */ + new_offset = shmcb_cyclic_increment(header->cache_data_size, + shmcb_get_safe_uint(cache->first_pos), + shmcb_get_safe_uint(cache->pos_count)); + /* Copy the DER-encoded session into place */ + shmcb_cyclic_ntoc_memcpy(header->cache_data_size, cache->data, + new_offset, encoded, encoded_len); + /* Get the new index that this session is stored in. */ + new_pos = shmcb_cyclic_increment(header->index_num, + shmcb_get_safe_uint(queue->first_pos), + shmcb_get_safe_uint(queue->pos_count)); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "storing in index %u, at offset %u", + new_pos, new_offset); + idx = shmcb_get_index(queue, new_pos); + if (idx == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "shmcb_insert_encoded_session internal error"); + return FALSE; + } + shmcb_safe_clear(idx, sizeof(SHMCBIndex)); + shmcb_set_safe_time(&(idx->expires), expiry_time); + shmcb_set_safe_uint(&(idx->offset), new_offset); + + /* idx->removed = (unsigned char)0; */ /* Not needed given the memset above. */ + idx->s_id2 = session_id[1]; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "session_id[0]=%u, idx->s_id2=%u", + session_id[0], session_id[1]); + + /* All that remains is to adjust the cache's and queue's "pos_count"s. */ + shmcb_set_safe_uint(cache->pos_count, + shmcb_get_safe_uint(cache->pos_count) + encoded_len); + shmcb_set_safe_uint(queue->pos_count, + shmcb_get_safe_uint(queue->pos_count) + 1); + + /* And just for good debugging measure ... */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "leaving now with %u bytes in the cache and %u indexes", + shmcb_get_safe_uint(cache->pos_count), + shmcb_get_safe_uint(queue->pos_count)); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "leaving shmcb_insert_encoded_session"); + return TRUE; +} + +/* Performs a lookup into a queue/cache pair for a + * session_id. If found, the session is deserialised + * and returned, otherwise NULL. */ +static SSL_SESSION *shmcb_lookup_session_id( + server_rec *s, SHMCBQueue *queue, + SHMCBCache *cache, UCHAR *id, + unsigned int idlen) +{ + unsigned char tempasn[SSL_SESSION_MAX_DER]; + SHMCBIndex *idx; + SHMCBHeader *header; + SSL_SESSION *pSession = NULL; + unsigned int curr_pos, loop, count; + MODSSL_D2I_SSL_SESSION_CONST unsigned char *ptr; + time_t now; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "entering shmcb_lookup_session_id"); + + /* If there are entries to expire, ditch them first thing. */ + shmcb_expire_division(s, queue, cache); + now = time(NULL); + curr_pos = shmcb_get_safe_uint(queue->first_pos); + count = shmcb_get_safe_uint(queue->pos_count); + header = queue->header; + for (loop = 0; loop < count; loop++) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "loop=%u, count=%u, curr_pos=%u", + loop, count, curr_pos); + idx = shmcb_get_index(queue, curr_pos); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "idx->s_id2=%u, id[1]=%u, offset=%u", + idx->s_id2, id[1], shmcb_get_safe_uint(&(idx->offset))); + /* Only look into the session further if; + * (a) the second byte of the session_id matches, + * (b) the "removed" flag isn't set, + * (c) the session hasn't expired yet. + * We do (c) like this so that it saves us having to + * do natural expiries ... naturally expired sessions + * scroll off the front anyway when the cache is full and + * "rotating", the only real issue that remains is the + * removal or disabling of forcibly killed sessions. */ + if ((idx->s_id2 == id[1]) && !idx->removed && + (shmcb_get_safe_time(&(idx->expires)) > now)) { + unsigned int session_id_length; + unsigned char *session_id; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "at index %u, found possible session match", + curr_pos); + shmcb_cyclic_cton_memcpy(header->cache_data_size, + tempasn, cache->data, + shmcb_get_safe_uint(&(idx->offset)), + SSL_SESSION_MAX_DER); + ptr = tempasn; + pSession = d2i_SSL_SESSION(NULL, &ptr, SSL_SESSION_MAX_DER); + session_id_length = SSL_SESSION_get_session_id_length(pSession); + session_id = SSL_SESSION_get_session_id(pSession); + + if (pSession == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "scach2_lookup_session_id internal error"); + return NULL; + } + if ((session_id_length == idlen) && + (memcmp(session_id, id, idlen) == 0)) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "a match!"); + return pSession; + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "not a match"); + SSL_SESSION_free(pSession); + pSession = NULL; + } + curr_pos = shmcb_cyclic_increment(header->index_num, curr_pos, 1); + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "no matching sessions were found"); + return NULL; +} + +static BOOL shmcb_remove_session_id( + server_rec *s, SHMCBQueue *queue, + SHMCBCache *cache, UCHAR *id, unsigned int idlen) +{ + unsigned char tempasn[SSL_SESSION_MAX_DER]; + SSL_SESSION *pSession = NULL; + SHMCBIndex *idx; + SHMCBHeader *header; + unsigned int curr_pos, loop, count; + MODSSL_D2I_SSL_SESSION_CONST unsigned char *ptr; + BOOL to_return = FALSE; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "entering shmcb_remove_session_id"); + + /* If there's entries to expire, ditch them first thing. */ + /* shmcb_expire_division(s, queue, cache); */ + + /* Regarding the above ... hmmm ... I know my expiry code is slightly + * "faster" than all this remove stuff ... but if the higher level + * code calls a "remove" operation (and this *only* seems to happen + * when it has spotted an expired session before we had a chance to) + * then it should get credit for a remove (stats-wise). Also, in the + * off-chance that the server *requests* a renegotiate and wants to + * wipe the session clean we should give that priority over our own + * routine expiry handling. So I've moved the expiry check to *after* + * this general remove stuff. */ + curr_pos = shmcb_get_safe_uint(queue->first_pos); + count = shmcb_get_safe_uint(queue->pos_count); + header = cache->header; + for (loop = 0; loop < count; loop++) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "loop=%u, count=%u, curr_pos=%u", + loop, count, curr_pos); + idx = shmcb_get_index(queue, curr_pos); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "idx->s_id2=%u, id[1]=%u", idx->s_id2, + id[1]); + /* Only look into the session further if the second byte of the + * session_id matches. */ + if (idx->s_id2 == id[1]) { + unsigned int session_id_length; + unsigned char *session_id; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "at index %u, found possible " + "session match", curr_pos); + shmcb_cyclic_cton_memcpy(header->cache_data_size, + tempasn, cache->data, + shmcb_get_safe_uint(&(idx->offset)), + SSL_SESSION_MAX_DER); + ptr = tempasn; + pSession = d2i_SSL_SESSION(NULL, &ptr, SSL_SESSION_MAX_DER); + if (pSession == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "shmcb_remove_session_id, internal error"); + goto end; + } + session_id_length = SSL_SESSION_get_session_id_length(pSession); + session_id = SSL_SESSION_get_session_id(pSession); + + if ((session_id_length == idlen) + && (memcmp(id, session_id, idlen) == 0)) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "a match!"); + /* Scrub out this session "quietly" */ + idx->removed = (unsigned char) 1; + SSL_SESSION_free(pSession); + to_return = TRUE; + goto end; + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "not a match"); + SSL_SESSION_free(pSession); + pSession = NULL; + } + curr_pos = shmcb_cyclic_increment(header->index_num, curr_pos, 1); + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "no matching sessions were found"); + + /* If there's entries to expire, ditch them now. */ + shmcb_expire_division(s, queue, cache); +end: + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "leaving shmcb_remove_session_id"); + return to_return; +} diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_shmht.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_shmht.c new file mode 100644 index 00000000..28def647 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_scache_shmht.c @@ -0,0 +1,351 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_scache_shmht.c + * Session Cache via Shared Memory (Hash Table Variant) + */ + +#include "mod_ssl.h" + +/* + * Wrapper functions for table library which resemble malloc(3) & Co + * but use the variants from the MM shared memory library. + */ + +static void *ssl_scache_shmht_malloc(void *opt_param, size_t size) +{ + SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); + + apr_rmm_off_t off = apr_rmm_calloc(mc->pSessionCacheDataRMM, size); + return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off); +} + +static void *ssl_scache_shmht_calloc(void *opt_param, + size_t number, size_t size) +{ + SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); + + apr_rmm_off_t off = apr_rmm_calloc(mc->pSessionCacheDataRMM, (number*size)); + + return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off); +} + +static void *ssl_scache_shmht_realloc(void *opt_param, void *ptr, size_t size) +{ + SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); + + apr_rmm_off_t off = apr_rmm_realloc(mc->pSessionCacheDataRMM, ptr, size); + return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off); +} + +static void ssl_scache_shmht_free(void *opt_param, void *ptr) +{ + SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); + + apr_rmm_off_t off = apr_rmm_offset_get(mc->pSessionCacheDataRMM, ptr); + apr_rmm_free(mc->pSessionCacheDataRMM, off); + return; +} + +/* + * Now the actual session cache implementation + * based on a hash table inside a shared memory segment. + */ + +void ssl_scache_shmht_init(server_rec *s, apr_pool_t *p) +{ + SSLModConfigRec *mc = myModConfig(s); + table_t *ta; + int ta_errno; + apr_size_t avail; + int n; + apr_status_t rv; + + /* + * Create shared memory segment + */ + if (mc->szSessionCacheDataFile == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "SSLSessionCache required"); + ssl_die(); + } + + if ((rv = apr_shm_create(&(mc->pSessionCacheDataMM), + mc->nSessionCacheDataSize, + mc->szSessionCacheDataFile, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot allocate shared memory"); + ssl_die(); + } + + if ((rv = apr_rmm_init(&(mc->pSessionCacheDataRMM), NULL, + apr_shm_baseaddr_get(mc->pSessionCacheDataMM), + mc->nSessionCacheDataSize, mc->pPool)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "Cannot initialize rmm"); + ssl_die(); + } + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "initialize MM %pp RMM %pp", + mc->pSessionCacheDataMM, mc->pSessionCacheDataRMM); + + /* + * Create hash table in shared memory segment + */ + avail = mc->nSessionCacheDataSize; + n = (avail/2) / 1024; + n = n < 10 ? 10 : n; + + /* + * Passing server_rec as opt_param to table_alloc so that we can do + * logging if required ssl_util_table. Otherwise, mc is sufficient. + */ + if ((ta = table_alloc(n, &ta_errno, + ssl_scache_shmht_malloc, + ssl_scache_shmht_calloc, + ssl_scache_shmht_realloc, + ssl_scache_shmht_free, s )) == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot allocate hash table in shared memory: %s", + table_strerror(ta_errno)); + ssl_die(); + } + + table_attr(ta, TABLE_FLAG_AUTO_ADJUST|TABLE_FLAG_ADJUST_DOWN); + table_set_data_alignment(ta, sizeof(char *)); + table_clear(ta); + mc->tSessionCacheDataTable = ta; + + /* + * Log the done work + */ + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Init: Created hash-table (%d buckets) " + "in shared memory (%" APR_SIZE_T_FMT + " bytes) for SSL session cache", + n, avail); + return; +} + +void ssl_scache_shmht_kill(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + + if (mc->pSessionCacheDataRMM != NULL) { + apr_rmm_destroy(mc->pSessionCacheDataRMM); + mc->pSessionCacheDataRMM = NULL; + } + + if (mc->pSessionCacheDataMM != NULL) { + apr_shm_destroy(mc->pSessionCacheDataMM); + mc->pSessionCacheDataMM = NULL; + } + return; +} + +BOOL ssl_scache_shmht_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) +{ + SSLModConfigRec *mc = myModConfig(s); + void *vp; + UCHAR ucaData[SSL_SESSION_MAX_DER]; + int nData; + UCHAR *ucp; + + /* streamline session data */ + if ((nData = i2d_SSL_SESSION(sess, NULL)) > sizeof(ucaData)) + return FALSE; + ucp = ucaData; + i2d_SSL_SESSION(sess, &ucp); + + ssl_mutex_on(s); + if (table_insert_kd(mc->tSessionCacheDataTable, + id, idlen, NULL, sizeof(time_t)+nData, + NULL, &vp, 1) != TABLE_ERROR_NONE) { + ssl_mutex_off(s); + return FALSE; + } + memcpy(vp, &expiry, sizeof(time_t)); + memcpy((char *)vp+sizeof(time_t), ucaData, nData); + ssl_mutex_off(s); + + /* allow the regular expiring to occur */ + ssl_scache_shmht_expire(s); + + return TRUE; +} + +SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + void *vp; + SSL_SESSION *sess = NULL; + MODSSL_D2I_SSL_SESSION_CONST UCHAR *ucpData; + int nData; + time_t expiry; + time_t now; + int n; + + /* allow the regular expiring to occur */ + ssl_scache_shmht_expire(s); + + /* lookup key in table */ + ssl_mutex_on(s); + if (table_retrieve(mc->tSessionCacheDataTable, + id, idlen, &vp, &n) != TABLE_ERROR_NONE) { + ssl_mutex_off(s); + return NULL; + } + + /* copy over the information to the SCI */ + nData = n-sizeof(time_t); + ucpData = (UCHAR *)malloc(nData); + if (ucpData == NULL) { + ssl_mutex_off(s); + return NULL; + } + memcpy(&expiry, vp, sizeof(time_t)); + memcpy((void *)ucpData, (char *)vp+sizeof(time_t), nData); + ssl_mutex_off(s); + + /* make sure the stuff is still not expired */ + now = time(NULL); + if (expiry <= now) { + ssl_scache_shmht_remove(s, id, idlen); + return NULL; + } + + /* unstreamed SSL_SESSION */ + sess = d2i_SSL_SESSION(NULL, &ucpData, nData); + + return sess; +} + +void ssl_scache_shmht_remove(server_rec *s, UCHAR *id, int idlen) +{ + SSLModConfigRec *mc = myModConfig(s); + + /* remove value under key in table */ + ssl_mutex_on(s); + table_delete(mc->tSessionCacheDataTable, id, idlen, NULL, NULL); + ssl_mutex_off(s); + return; +} + +void ssl_scache_shmht_expire(server_rec *s) +{ + SSLModConfigRec *mc = myModConfig(s); + SSLSrvConfigRec *sc = mySrvConfig(s); + static time_t tLast = 0; + table_linear_t iterator; + time_t tExpiresAt; + void *vpKey; + void *vpKeyThis; + void *vpData; + int nKey; + int nKeyThis; + int nData; + int nElements = 0; + int nDeleted = 0; + int bDelete; + int rc; + time_t tNow; + + /* + * make sure the expiration for still not-accessed session + * cache entries is done only from time to time + */ + tNow = time(NULL); + if (tNow < tLast+sc->session_cache_timeout) + return; + tLast = tNow; + + ssl_mutex_on(s); + if (table_first_r(mc->tSessionCacheDataTable, &iterator, + &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) { + do { + bDelete = FALSE; + nElements++; + if (nData < sizeof(time_t) || vpData == NULL) + bDelete = TRUE; + else { + memcpy(&tExpiresAt, vpData, sizeof(time_t)); + /* + * XXX : Force the record to be cleaned up. TBD (Madhu) + * tExpiresAt = tNow; + */ + if (tExpiresAt <= tNow) + bDelete = TRUE; + } + vpKeyThis = vpKey; + nKeyThis = nKey; + rc = table_next_r(mc->tSessionCacheDataTable, &iterator, + &vpKey, &nKey, &vpData, &nData); + if (bDelete) { + table_delete(mc->tSessionCacheDataTable, + vpKeyThis, nKeyThis, NULL, NULL); + nDeleted++; + } + } while (rc == TABLE_ERROR_NONE); + /* (vpKeyThis != vpKey) && (nKeyThis != nKey) */ + } + ssl_mutex_off(s); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Inter-Process Session Cache (SHMHT) Expiry: " + "old: %d, new: %d, removed: %d", + nElements, nElements-nDeleted, nDeleted); + return; +} + +void ssl_scache_shmht_status(server_rec *s, apr_pool_t *p, void (*func)(char *, void *), void *arg) +{ + SSLModConfigRec *mc = myModConfig(s); + void *vpKey; + void *vpData; + int nKey; + int nData; + int nElem; + int nSize; + int nAverage; + + nElem = 0; + nSize = 0; + ssl_mutex_on(s); + if (table_first(mc->tSessionCacheDataTable, + &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) { + do { + if (vpKey == NULL || vpData == NULL) + continue; + nElem += 1; + nSize += nData; + } while (table_next(mc->tSessionCacheDataTable, + &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE); + } + ssl_mutex_off(s); + if (nSize > 0 && nElem > 0) + nAverage = nSize / nElem; + else + nAverage = 0; + func(apr_psprintf(p, "cache type: <b>SHMHT</b>, maximum size: <b>%d</b> bytes<br>", mc->nSessionCacheDataSize), arg); + func(apr_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg); + func(apr_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg); + return; +} diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_toolkit_compat.h b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_toolkit_compat.h new file mode 100644 index 00000000..72772150 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_toolkit_compat.h @@ -0,0 +1,239 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SSL_TOOLKIT_COMPAT_H +#define SSL_TOOLKIT_COMPAT_H + +/* + * this header file provides a compatiblity layer + * between OpenSSL and RSA sslc + */ + +#ifdef OPENSSL_VERSION_NUMBER + +/* + * rsa sslc uses incomplete types for most structures + * so we macroize for OpenSSL those which cannot be dereferenced + * using the same sames as the sslc functions + */ + +#define EVP_PKEY_key_type(k) (EVP_PKEY_type(k->type)) + +#define X509_NAME_get_entries(xs) (xs->entries) +#define X509_REVOKED_get_serialNumber(xs) (xs->serialNumber) + +#define X509_get_signature_algorithm(xs) (xs->cert_info->signature->algorithm) +#define X509_get_key_algorithm(xs) (xs->cert_info->key->algor->algorithm) + +#define X509_NAME_ENTRY_get_data_ptr(xs) (xs->value->data) +#define X509_NAME_ENTRY_get_data_len(xs) (xs->value->length) + +#define SSL_CTX_get_extra_certs(ctx) (ctx->extra_certs) +#define SSL_CTX_set_extra_certs(ctx,value) {ctx->extra_certs = value;} + +#define SSL_CIPHER_get_name(s) (s->name) +#define SSL_CIPHER_get_valid(s) (s->valid) + +#define SSL_SESSION_get_session_id(s) (s->session_id) +#define SSL_SESSION_get_session_id_length(s) (s->session_id_length) + +/* + * Support for retrieving/overriding states + */ +#ifndef SSL_get_state +#define SSL_get_state(ssl) SSL_state(ssl) +#endif + +#define SSL_set_state(ssl,val) (ssl)->state = val + +#define MODSSL_BIO_CB_ARG_TYPE const char +#define MODSSL_CRYPTO_CB_ARG_TYPE const char +#if (OPENSSL_VERSION_NUMBER < 0x00907000) +#define MODSSL_INFO_CB_ARG_TYPE SSL* +#else +#define MODSSL_INFO_CB_ARG_TYPE const SSL* +#endif +#define MODSSL_CLIENT_CERT_CB_ARG_TYPE X509 +#define MODSSL_PCHAR_CAST + +/* ...shifting sands of openssl... */ +#if (OPENSSL_VERSION_NUMBER >= 0x0090707f) +# define MODSSL_D2I_SSL_SESSION_CONST const +#else +# define MODSSL_D2I_SSL_SESSION_CONST +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x00908000) +# define MODSSL_D2I_PrivateKey_CONST const +# define MODSSL_D2I_X509_CONST const +#else +# define MODSSL_D2I_PrivateKey_CONST +# define MODSSL_D2I_X509_CONST +#endif + +#define modssl_X509_verify_cert X509_verify_cert + +typedef int (modssl_read_bio_cb_fn)(char*,int,int,void*); + +#if (OPENSSL_VERSION_NUMBER < 0x00904000) +#define modssl_PEM_read_bio_X509(b, x, cb, arg) PEM_read_bio_X509(b, x, cb) +#else +#define modssl_PEM_read_bio_X509(b, x, cb, arg) PEM_read_bio_X509(b, x, cb, arg) +#endif + +#define modssl_PEM_X509_INFO_read_bio PEM_X509_INFO_read_bio + +#define modssl_PEM_read_bio_PrivateKey PEM_read_bio_PrivateKey + +#define modssl_set_cipher_list SSL_set_cipher_list + +#define modssl_free OPENSSL_free + +#define EVP_PKEY_reference_inc(pkey) \ + CRYPTO_add(&((pkey)->references), +1, CRYPTO_LOCK_X509_PKEY) + +#define X509_reference_inc(cert) \ + CRYPTO_add(&((cert)->references), +1, CRYPTO_LOCK_X509) + +#define HAVE_SSL_RAND_EGD /* since 9.5.1 */ + +#ifdef HAVE_SSL_X509V3_H +#define HAVE_SSL_X509V3_EXT_d2i +#endif + +#ifndef PEM_F_DEF_CALLBACK +#ifdef PEM_F_PEM_DEF_CALLBACK +/* In OpenSSL 0.9.8 PEM_F_DEF_CALLBACK was renamed */ +#define PEM_F_DEF_CALLBACK PEM_F_PEM_DEF_CALLBACK +#endif +#endif + +#elif defined (SSLC_VERSION_NUMBER) /* RSA */ + +/* sslc does not support this function, OpenSSL has since 9.5.1 */ +#define RAND_status() 1 + +/* sslc names this function a bit differently */ +#define CRYPTO_num_locks() CRYPTO_get_num_locks() + +#ifndef STACK_OF +#define STACK_OF(type) STACK +#endif + +#define MODSSL_BIO_CB_ARG_TYPE char +#define MODSSL_CRYPTO_CB_ARG_TYPE char +#define MODSSL_INFO_CB_ARG_TYPE SSL* +#define MODSSL_CLIENT_CERT_CB_ARG_TYPE void +#define MODSSL_PCHAR_CAST (char *) +#define MODSSL_D2I_SSL_SESSION_CONST +#define MODSSL_D2I_PrivateKey_CONST +#define MODSSL_D2I_X509_CONST + +typedef int (modssl_read_bio_cb_fn)(char*,int,int); + +#define modssl_X509_verify_cert(c) X509_verify_cert(c, NULL) + +#define modssl_PEM_read_bio_X509(b, x, cb, arg) \ + PEM_read_bio_X509(b, x, cb) + +#define modssl_PEM_X509_INFO_read_bio(b, x, cb, arg)\ + PEM_X509_INFO_read_bio(b, x, cb) + +#define modssl_PEM_read_bio_PrivateKey(b, k, cb, arg) \ + PEM_read_bio_PrivateKey(b, k, cb) + +#ifndef HAVE_SSL_SET_STATE +#define SSL_set_state(ssl, state) /* XXX: should throw an error */ +#endif + +#define modssl_set_cipher_list(ssl, l) \ + SSL_set_cipher_list(ssl, (char *)l) + +#define modssl_free free + +#ifndef PEM_F_DEF_CALLBACK +#define PEM_F_DEF_CALLBACK PEM_F_DEF_CB +#endif + +#if SSLC_VERSION_NUMBER < 0x2000 + +#define X509_STORE_CTX_set_depth(st, d) +#define X509_CRL_get_lastUpdate(x) ((x)->crl->lastUpdate) +#define X509_CRL_get_nextUpdate(x) ((x)->crl->nextUpdate) +#define X509_CRL_get_REVOKED(x) ((x)->crl->revoked) +#define X509_REVOKED_get_serialNumber(xs) (xs->serialNumber) + +#define modssl_set_verify(ssl, verify, cb) \ + SSL_set_verify(ssl, verify) + +#define NO_SSL_X509V3_H + +#else /* SSLC_VERSION_NUMBER >= 0x2000 */ + +#define CRYPTO_malloc_init R_malloc_init + +#define EVP_cleanup() + +#endif /* SSLC_VERSION_NUMBER >= 0x2000 */ + +typedef void (*modssl_popfree_fn)(char *data); + +#define sk_SSL_CIPHER_dup sk_dup +#define sk_SSL_CIPHER_find(st, data) sk_find(st, (void *)data) +#define sk_SSL_CIPHER_free sk_free +#define sk_SSL_CIPHER_num sk_num +#define sk_SSL_CIPHER_value (SSL_CIPHER *)sk_value +#define sk_X509_num sk_num +#define sk_X509_push sk_push +#define sk_X509_pop_free(st, free) sk_pop_free((STACK*)(st), (modssl_popfree_fn)(free)) +#define sk_X509_value (X509 *)sk_value +#define sk_X509_INFO_free sk_free +#define sk_X509_INFO_pop_free(st, free) sk_pop_free((STACK*)(st), (modssl_popfree_fn)(free)) +#define sk_X509_INFO_num sk_num +#define sk_X509_INFO_new_null sk_new_null +#define sk_X509_INFO_value (X509_INFO *)sk_value +#define sk_X509_NAME_find(st, data) sk_find(st, (void *)data) +#define sk_X509_NAME_free sk_free +#define sk_X509_NAME_new sk_new +#define sk_X509_NAME_num sk_num +#define sk_X509_NAME_push(st, data) sk_push(st, (void *)data) +#define sk_X509_NAME_value (X509_NAME *)sk_value +#define sk_X509_NAME_ENTRY_num sk_num +#define sk_X509_NAME_ENTRY_value (X509_NAME_ENTRY *)sk_value +#define sk_X509_NAME_set_cmp_func sk_set_cmp_func +#define sk_X509_REVOKED_num sk_num +#define sk_X509_REVOKED_value (X509_REVOKED *)sk_value + +#else /* ! OPENSSL_VERSION_NUMBER && ! SSLC_VERSION_NUMBER */ + +#error "Unrecognized SSL Toolkit!" + +#endif /* ! OPENSSL_VERSION_NUMBER && ! SSLC_VERSION_NUMBER */ + +#ifndef modssl_set_verify +#define modssl_set_verify(ssl, verify, cb) \ + SSL_set_verify(ssl, verify, cb) +#endif + +#ifndef NO_SSL_X509V3_H +#define HAVE_SSL_X509V3_H +#endif + +#ifndef SSL_SESS_CACHE_NO_INTERNAL +#define SSL_SESS_CACHE_NO_INTERNAL SSL_SESS_CACHE_NO_INTERNAL_LOOKUP +#endif + +#endif /* SSL_TOOLKIT_COMPAT_H */ diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util.c new file mode 100644 index 00000000..f1319547 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util.c @@ -0,0 +1,449 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_util.c + * Utility Functions + */ + /* ``Every day of my life + I am forced to add another + name to the list of people + who piss me off!'' + -- Calvin */ + +#include "mod_ssl.h" +#include "ap_mpm.h" +#include "apr_thread_mutex.h" + +/* _________________________________________________________________ +** +** Utility Functions +** _________________________________________________________________ +*/ + +char *ssl_util_vhostid(apr_pool_t *p, server_rec *s) +{ + char *id; + SSLSrvConfigRec *sc; + char *host; + apr_port_t port; + + host = s->server_hostname; + if (s->port != 0) + port = s->port; + else { + sc = mySrvConfig(s); + if (sc->enabled) + port = DEFAULT_HTTPS_PORT; + else + port = DEFAULT_HTTP_PORT; + } + id = apr_psprintf(p, "%s:%lu", host, (unsigned long)port); + return id; +} + +void ssl_util_strupper(char *s) +{ + for (; *s; ++s) + *s = apr_toupper(*s); + return; +} + +static const char ssl_util_uuencode_six2pr[64+1] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +void ssl_util_uuencode(char *szTo, const char *szFrom, BOOL bPad) +{ + ssl_util_uuencode_binary((unsigned char *)szTo, + (const unsigned char *)szFrom, + strlen(szFrom), bPad); +} + +void ssl_util_uuencode_binary(unsigned char *szTo, + const unsigned char *szFrom, + int nLength, BOOL bPad) +{ + const unsigned char *s; + int nPad = 0; + + for (s = szFrom; nLength > 0; s += 3) { + *szTo++ = ssl_util_uuencode_six2pr[s[0] >> 2]; + *szTo++ = ssl_util_uuencode_six2pr[(s[0] << 4 | s[1] >> 4) & 0x3f]; + if (--nLength == 0) { + nPad = 2; + break; + } + *szTo++ = ssl_util_uuencode_six2pr[(s[1] << 2 | s[2] >> 6) & 0x3f]; + if (--nLength == 0) { + nPad = 1; + break; + } + *szTo++ = ssl_util_uuencode_six2pr[s[2] & 0x3f]; + --nLength; + } + while(bPad && nPad--) { + *szTo++ = NUL; + } + *szTo = NUL; + return; +} + +apr_file_t *ssl_util_ppopen(server_rec *s, apr_pool_t *p, const char *cmd, + const char * const *argv) +{ + apr_procattr_t *procattr; + apr_proc_t *proc; + + if (apr_procattr_create(&procattr, p) != APR_SUCCESS) + return NULL; + if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK, + APR_FULL_BLOCK) != APR_SUCCESS) + return NULL; + if (apr_procattr_dir_set(procattr, + ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS) + return NULL; + if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS) + return NULL; + if ((proc = (apr_proc_t *)apr_pcalloc(p, sizeof(apr_proc_t))) == NULL) + return NULL; + if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS) + return NULL; + return proc->out; +} + +void ssl_util_ppclose(server_rec *s, apr_pool_t *p, apr_file_t *fp) +{ + apr_file_close(fp); + return; +} + +/* + * Run a filter program and read the first line of its stdout output + */ +char *ssl_util_readfilter(server_rec *s, apr_pool_t *p, const char *cmd, + const char * const *argv) +{ + static char buf[MAX_STRING_LEN]; + apr_file_t *fp; + apr_size_t nbytes = 1; + char c; + int k; + + if ((fp = ssl_util_ppopen(s, p, cmd, argv)) == NULL) + return NULL; + /* XXX: we are reading 1 byte at a time here */ + for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS + && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) { + if (c == '\n' || c == '\r') + break; + buf[k++] = c; + } + buf[k] = NUL; + ssl_util_ppclose(s, p, fp); + + return buf; +} + +BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p) +{ + apr_finfo_t finfo; + + if (path == NULL) + return FALSE; + if (pcm & SSL_PCM_EXISTS && apr_stat(&finfo, path, + APR_FINFO_TYPE|APR_FINFO_SIZE, p) != 0) + return FALSE; + if (pcm & SSL_PCM_ISREG && finfo.filetype != APR_REG) + return FALSE; + if (pcm & SSL_PCM_ISDIR && finfo.filetype != APR_DIR) + return FALSE; + if (pcm & SSL_PCM_ISNONZERO && finfo.size <= 0) + return FALSE; + return TRUE; +} + +ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey) +{ + ssl_algo_t t; + + t = SSL_ALGO_UNKNOWN; + if (pCert != NULL) + pKey = X509_get_pubkey(pCert); + if (pKey != NULL) { + switch (EVP_PKEY_key_type(pKey)) { + case EVP_PKEY_RSA: + t = SSL_ALGO_RSA; + break; + case EVP_PKEY_DSA: + t = SSL_ALGO_DSA; + break; + default: + break; + } + } + return t; +} + +char *ssl_util_algotypestr(ssl_algo_t t) +{ + char *cp; + + cp = "UNKNOWN"; + switch (t) { + case SSL_ALGO_RSA: + cp = "RSA"; + break; + case SSL_ALGO_DSA: + cp = "DSA"; + break; + default: + break; + } + return cp; +} + +char *ssl_util_ptxtsub(apr_pool_t *p, const char *cpLine, + const char *cpMatch, char *cpSubst) +{ +#define MAX_PTXTSUB 100 + char *cppMatch[MAX_PTXTSUB]; + char *cpResult; + int nResult; + int nLine; + int nSubst; + int nMatch; + char *cpI; + char *cpO; + char *cp; + int i; + + /* + * Pass 1: find substitution locations and calculate sizes + */ + nLine = strlen(cpLine); + nMatch = strlen(cpMatch); + nSubst = strlen(cpSubst); + for (cpI = (char *)cpLine, i = 0, nResult = 0; + cpI < cpLine+nLine && i < MAX_PTXTSUB; ) { + if ((cp = strstr(cpI, cpMatch)) != NULL) { + cppMatch[i++] = cp; + nResult += ((cp-cpI)+nSubst); + cpI = (cp+nMatch); + } + else { + nResult += strlen(cpI); + break; + } + } + cppMatch[i] = NULL; + if (i == 0) + return NULL; + + /* + * Pass 2: allocate memory and assemble result + */ + cpResult = apr_pcalloc(p, nResult+1); + for (cpI = (char *)cpLine, cpO = cpResult, i = 0; + cppMatch[i] != NULL; + i++) { + apr_cpystrn(cpO, cpI, cppMatch[i]-cpI+1); + cpO += (cppMatch[i]-cpI); + apr_cpystrn(cpO, cpSubst, nSubst+1); + cpO += nSubst; + cpI = (cppMatch[i]+nMatch); + } + apr_cpystrn(cpO, cpI, cpResult+nResult-cpO+1); + + return cpResult; +} + +/* + * certain key and cert data needs to survive restarts, + * which are stored in the user data table of s->process->pool. + * to prevent "leaking" of this data, we use malloc/free + * rather than apr_palloc and these wrappers to help make sure + * we do not leak the malloc-ed data. + */ +unsigned char *ssl_asn1_table_set(apr_hash_t *table, + const char *key, + long int length) +{ + apr_ssize_t klen = strlen(key); + ssl_asn1_t *asn1 = apr_hash_get(table, key, klen); + + /* + * if a value for this key already exists, + * reuse as much of the already malloc-ed data + * as possible. + */ + if (asn1) { + if (asn1->nData != length) { + free(asn1->cpData); /* XXX: realloc? */ + asn1->cpData = NULL; + } + } + else { + asn1 = malloc(sizeof(*asn1)); + asn1->source_mtime = 0; /* used as a note for encrypted private keys */ + asn1->cpData = NULL; + } + + asn1->nData = length; + if (!asn1->cpData) { + asn1->cpData = malloc(length); + } + + apr_hash_set(table, key, klen, asn1); + + return asn1->cpData; /* caller will assign a value to this */ +} + +ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table, + const char *key) +{ + return (ssl_asn1_t *)apr_hash_get(table, key, APR_HASH_KEY_STRING); +} + +void ssl_asn1_table_unset(apr_hash_t *table, + const char *key) +{ + apr_ssize_t klen = strlen(key); + ssl_asn1_t *asn1 = apr_hash_get(table, key, klen); + + if (!asn1) { + return; + } + + if (asn1->cpData) { + free(asn1->cpData); + } + free(asn1); + + apr_hash_set(table, key, klen, NULL); +} + +static const char *ssl_asn1_key_types[] = {"RSA", "DSA"}; + +const char *ssl_asn1_keystr(int keytype) +{ + if (keytype >= SSL_AIDX_MAX) { + return NULL; + } + + return ssl_asn1_key_types[keytype]; +} + +const char *ssl_asn1_table_keyfmt(apr_pool_t *p, + const char *id, + int keytype) +{ + const char *keystr = ssl_asn1_keystr(keytype); + + return apr_pstrcat(p, id, ":", keystr, NULL); +} + + +#if APR_HAS_THREADS +/* + * To ensure thread-safetyness in OpenSSL - work in progress + */ + +static apr_thread_mutex_t **lock_cs; +static int lock_num_locks; + +#ifdef SSLC_VERSION_NUMBER +#if SSLC_VERSION_NUMBER >= 0x2000 +static int ssl_util_thr_lock(int mode, int type, + const char *file, int line) +#else +static void ssl_util_thr_lock(int mode, int type, + const char *file, int line) +#endif +#else +static void ssl_util_thr_lock(int mode, int type, + const char *file, int line) +#endif +{ + if (type < lock_num_locks) { + if (mode & CRYPTO_LOCK) { + apr_thread_mutex_lock(lock_cs[type]); + } + else { + apr_thread_mutex_unlock(lock_cs[type]); + } +#ifdef SSLC_VERSION_NUMBER +#if SSLC_VERSION_NUMBER >= 0x2000 + return 1; + } + else { + return -1; +#endif +#endif + } +} + +static unsigned long ssl_util_thr_id(void) +{ + /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread + * id is a structure twice that big. Use the TCB pointer instead as a + * unique unsigned long. + */ +#ifdef __MVS__ + struct PSA { + char unmapped[540]; + unsigned long PSATOLD; + } *psaptr = 0; + + return psaptr->PSATOLD; +#else + return (unsigned long) apr_os_thread_current(); +#endif +} + +static apr_status_t ssl_util_thread_cleanup(void *data) +{ + CRYPTO_set_locking_callback(NULL); + CRYPTO_set_id_callback(NULL); + + /* Let the registered mutex cleanups do their own thing + */ + return APR_SUCCESS; +} + +void ssl_util_thread_setup(apr_pool_t *p) +{ + int i; + + lock_num_locks = CRYPTO_num_locks(); + lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs)); + + for (i = 0; i < lock_num_locks; i++) { + apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p); + } + + CRYPTO_set_id_callback(ssl_util_thr_id); + + CRYPTO_set_locking_callback(ssl_util_thr_lock); + + apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup, + apr_pool_cleanup_null); +} +#endif diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_ssl.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_ssl.c new file mode 100644 index 00000000..857bc304 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_ssl.c @@ -0,0 +1,574 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_util_ssl.c + * Additional Utility Functions for OpenSSL + */ + +#include "mod_ssl.h" + +/* _________________________________________________________________ +** +** Additional High-Level Functions for OpenSSL +** _________________________________________________________________ +*/ + +/* we initialize this index at startup time + * and never write to it at request time, + * so this static is thread safe. + * also note that OpenSSL increments at static variable when + * SSL_get_ex_new_index() is called, so we _must_ do this at startup. + */ +static int SSL_app_data2_idx = -1; + +void SSL_init_app_data2_idx(void) +{ + int i; + + if (SSL_app_data2_idx > -1) { + return; + } + + /* we _do_ need to call this twice */ + for (i=0; i<=1; i++) { + SSL_app_data2_idx = + SSL_get_ex_new_index(0, + "Second Application Data for SSL", + NULL, NULL, NULL); + } +} + +void *SSL_get_app_data2(SSL *ssl) +{ + return (void *)SSL_get_ex_data(ssl, SSL_app_data2_idx); +} + +void SSL_set_app_data2(SSL *ssl, void *arg) +{ + SSL_set_ex_data(ssl, SSL_app_data2_idx, (char *)arg); + return; +} + +/* _________________________________________________________________ +** +** High-Level Certificate / Private Key Loading +** _________________________________________________________________ +*/ + +X509 *SSL_read_X509(char* filename, X509 **x509, modssl_read_bio_cb_fn *cb) +{ + X509 *rc; + BIO *bioS; + BIO *bioF; + + /* 1. try PEM (= DER+Base64+headers) */ + if ((bioS=BIO_new_file(filename, "r")) == NULL) + return NULL; + rc = modssl_PEM_read_bio_X509 (bioS, x509, cb, NULL); + BIO_free(bioS); + + if (rc == NULL) { + /* 2. try DER+Base64 */ + if ((bioS=BIO_new_file(filename, "r")) == NULL) + return NULL; + + if ((bioF = BIO_new(BIO_f_base64())) == NULL) { + BIO_free(bioS); + return NULL; + } + bioS = BIO_push(bioF, bioS); + rc = d2i_X509_bio(bioS, NULL); + BIO_free_all(bioS); + + if (rc == NULL) { + /* 3. try plain DER */ + if ((bioS=BIO_new_file(filename, "r")) == NULL) + return NULL; + rc = d2i_X509_bio(bioS, NULL); + BIO_free(bioS); + } + } + if (rc != NULL && x509 != NULL) { + if (*x509 != NULL) + X509_free(*x509); + *x509 = rc; + } + return rc; +} + +#if SSL_LIBRARY_VERSION <= 0x00904100 +static EVP_PKEY *d2i_PrivateKey_bio(BIO *bio, EVP_PKEY **key) +{ + return ((EVP_PKEY *)ASN1_d2i_bio( + (char *(*)())EVP_PKEY_new, + (char *(*)())d2i_PrivateKey, + (bio), (unsigned char **)(key))); +} +#endif + +EVP_PKEY *SSL_read_PrivateKey(char* filename, EVP_PKEY **key, modssl_read_bio_cb_fn *cb, void *s) +{ + EVP_PKEY *rc; + BIO *bioS; + BIO *bioF; + + /* 1. try PEM (= DER+Base64+headers) */ + if ((bioS=BIO_new_file(filename, "r")) == NULL) + return NULL; + rc = modssl_PEM_read_bio_PrivateKey(bioS, key, cb, s); + BIO_free(bioS); + + if (rc == NULL) { + /* 2. try DER+Base64 */ + if ((bioS = BIO_new_file(filename, "r")) == NULL) + return NULL; + + if ((bioF = BIO_new(BIO_f_base64())) == NULL) { + BIO_free(bioS); + return NULL; + } + bioS = BIO_push(bioF, bioS); + rc = d2i_PrivateKey_bio(bioS, NULL); + BIO_free_all(bioS); + + if (rc == NULL) { + /* 3. try plain DER */ + if ((bioS = BIO_new_file(filename, "r")) == NULL) + return NULL; + rc = d2i_PrivateKey_bio(bioS, NULL); + BIO_free(bioS); + } + } + if (rc != NULL && key != NULL) { + if (*key != NULL) + EVP_PKEY_free(*key); + *key = rc; + } + return rc; +} + +/* _________________________________________________________________ +** +** Smart shutdown +** _________________________________________________________________ +*/ + +int SSL_smart_shutdown(SSL *ssl) +{ + int i; + int rc; + + /* + * Repeat the calls, because SSL_shutdown internally dispatches through a + * little state machine. Usually only one or two interation should be + * needed, so we restrict the total number of restrictions in order to + * avoid process hangs in case the client played bad with the socket + * connection and OpenSSL cannot recognize it. + */ + rc = 0; + for (i = 0; i < 4 /* max 2x pending + 2x data = 4 */; i++) { + if ((rc = SSL_shutdown(ssl))) + break; + } + return rc; +} + +/* _________________________________________________________________ +** +** Certificate Revocation List (CRL) Storage +** _________________________________________________________________ +*/ + +X509_STORE *SSL_X509_STORE_create(char *cpFile, char *cpPath) +{ + X509_STORE *pStore; + X509_LOOKUP *pLookup; + + if (cpFile == NULL && cpPath == NULL) + return NULL; + if ((pStore = X509_STORE_new()) == NULL) + return NULL; + if (cpFile != NULL) { + pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_file()); + if (pLookup == NULL) { + X509_STORE_free(pStore); + return NULL; + } + X509_LOOKUP_load_file(pLookup, cpFile, X509_FILETYPE_PEM); + } + if (cpPath != NULL) { + pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_hash_dir()); + if (pLookup == NULL) { + X509_STORE_free(pStore); + return NULL; + } + X509_LOOKUP_add_dir(pLookup, cpPath, X509_FILETYPE_PEM); + } + return pStore; +} + +int SSL_X509_STORE_lookup(X509_STORE *pStore, int nType, + X509_NAME *pName, X509_OBJECT *pObj) +{ + X509_STORE_CTX pStoreCtx; + int rc; + + X509_STORE_CTX_init(&pStoreCtx, pStore, NULL, NULL); + rc = X509_STORE_get_by_subject(&pStoreCtx, nType, pName, pObj); + X509_STORE_CTX_cleanup(&pStoreCtx); + return rc; +} + +/* _________________________________________________________________ +** +** Cipher Suite Spec String Creation +** _________________________________________________________________ +*/ + +char *SSL_make_ciphersuite(apr_pool_t *p, SSL *ssl) +{ + STACK_OF(SSL_CIPHER) *sk; + SSL_CIPHER *c; + int i; + int l; + char *cpCipherSuite; + char *cp; + + if (ssl == NULL) + return ""; + if ((sk = (STACK_OF(SSL_CIPHER) *)SSL_get_ciphers(ssl)) == NULL) + return ""; + l = 0; + for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { + c = sk_SSL_CIPHER_value(sk, i); + l += strlen(SSL_CIPHER_get_name(c))+2+1; + } + if (l == 0) + return ""; + cpCipherSuite = (char *)apr_palloc(p, l+1); + cp = cpCipherSuite; + for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { + c = sk_SSL_CIPHER_value(sk, i); + l = strlen(SSL_CIPHER_get_name(c)); + memcpy(cp, SSL_CIPHER_get_name(c), l); + cp += l; + *cp++ = '/'; + *cp++ = (SSL_CIPHER_get_valid(c) == 1 ? '1' : '0'); + *cp++ = ':'; + } + *(cp-1) = NUL; + return cpCipherSuite; +} + +/* _________________________________________________________________ +** +** Certificate Checks +** _________________________________________________________________ +*/ + +/* check whether cert contains extended key usage with a SGC tag */ +BOOL SSL_X509_isSGC(X509 *cert) +{ +#ifdef HAVE_SSL_X509V3_EXT_d2i + X509_EXTENSION *ext; + int ext_nid; + STACK *sk; + BOOL is_sgc; + int idx; + int i; + + is_sgc = FALSE; + idx = X509_get_ext_by_NID(cert, NID_ext_key_usage, -1); + if (idx >= 0) { + ext = X509_get_ext(cert, idx); + if ((sk = (STACK *)X509V3_EXT_d2i(ext)) != NULL) { + for (i = 0; i < sk_num(sk); i++) { + ext_nid = OBJ_obj2nid((ASN1_OBJECT *)sk_value(sk, i)); + if (ext_nid == NID_ms_sgc || ext_nid == NID_ns_sgc) { + is_sgc = TRUE; + break; + } + } + } + } + return is_sgc; +#else + return FALSE; +#endif +} + +/* retrieve basic constraints ingredients */ +BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen) +{ +#ifdef HAVE_SSL_X509V3_EXT_d2i + X509_EXTENSION *ext; + BASIC_CONSTRAINTS *bc; + int idx; + BIGNUM *bn = NULL; + char *cp; + + if ((idx = X509_get_ext_by_NID(cert, NID_basic_constraints, -1)) < 0) + return FALSE; + ext = X509_get_ext(cert, idx); + if (ext == NULL) + return FALSE; + if ((bc = (BASIC_CONSTRAINTS *)X509V3_EXT_d2i(ext)) == NULL) + return FALSE; + *ca = bc->ca; + *pathlen = -1 /* unlimited */; + if (bc->pathlen != NULL) { + if ((bn = ASN1_INTEGER_to_BN(bc->pathlen, NULL)) == NULL) + return FALSE; + if ((cp = BN_bn2dec(bn)) == NULL) + return FALSE; + *pathlen = atoi(cp); + free(cp); + BN_free(bn); + } + BASIC_CONSTRAINTS_free(bc); + return TRUE; +#else + return FALSE; +#endif +} + +/* retrieve subject CommonName of certificate */ +BOOL SSL_X509_getCN(apr_pool_t *p, X509 *xs, char **cppCN) +{ + X509_NAME *xsn; + X509_NAME_ENTRY *xsne; + int i, nid; + unsigned char *data_ptr; + int data_len; + + xsn = X509_get_subject_name(xs); + for (i = 0; i < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *) + X509_NAME_get_entries(xsn)); i++) { + xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *) + X509_NAME_get_entries(xsn), i); + nid = OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); + if (nid == NID_commonName) { + data_ptr = X509_NAME_ENTRY_get_data_ptr(xsne); + data_len = X509_NAME_ENTRY_get_data_len(xsne); + *cppCN = apr_palloc(p, data_len+1); + apr_cpystrn(*cppCN, (char *)data_ptr, data_len+1); + (*cppCN)[data_len] = NUL; +#ifdef CHARSET_EBCDIC + ascii2ebcdic(*cppCN, *cppCN, strlen(*cppCN)); +#endif + return TRUE; + } + } + return FALSE; +} + +/* _________________________________________________________________ +** +** Low-Level CA Certificate Loading +** _________________________________________________________________ +*/ + +BOOL SSL_X509_INFO_load_file(apr_pool_t *ptemp, + STACK_OF(X509_INFO) *sk, + const char *filename) +{ + BIO *in; + + if (!(in = BIO_new(BIO_s_file()))) { + return FALSE; + } + + if (BIO_read_filename(in, MODSSL_PCHAR_CAST filename) <= 0) { + BIO_free(in); + return FALSE; + } + + ERR_clear_error(); + + modssl_PEM_X509_INFO_read_bio(in, sk, NULL, NULL); + + BIO_free(in); + + return TRUE; +} + +BOOL SSL_X509_INFO_load_path(apr_pool_t *ptemp, + STACK_OF(X509_INFO) *sk, + const char *pathname) +{ + /* XXX: this dir read code is exactly the same as that in + * ssl_engine_init.c, only the call to handle the fullname is different, + * should fold the duplication. + */ + apr_dir_t *dir; + apr_finfo_t dirent; + apr_int32_t finfo_flags = APR_FINFO_TYPE|APR_FINFO_NAME; + const char *fullname; + BOOL ok = FALSE; + + if (apr_dir_open(&dir, pathname, ptemp) != APR_SUCCESS) { + return FALSE; + } + + while ((apr_dir_read(&dirent, finfo_flags, dir)) == APR_SUCCESS) { + if (dirent.filetype == APR_DIR) { + continue; /* don't try to load directories */ + } + + fullname = apr_pstrcat(ptemp, + pathname, "/", dirent.name, + NULL); + + if (SSL_X509_INFO_load_file(ptemp, sk, fullname)) { + ok = TRUE; + } + } + + apr_dir_close(dir); + + return ok; +} + +/* _________________________________________________________________ +** +** Extra Server Certificate Chain Support +** _________________________________________________________________ +*/ + +/* + * Read a file that optionally contains the server certificate in PEM + * format, possibly followed by a sequence of CA certificates that + * should be sent to the peer in the SSL Certificate message. + */ +int SSL_CTX_use_certificate_chain( + SSL_CTX *ctx, char *file, int skipfirst, modssl_read_bio_cb_fn *cb) +{ + BIO *bio; + X509 *x509; + unsigned long err; + int n; + STACK *extra_certs; + + if ((bio = BIO_new(BIO_s_file_internal())) == NULL) + return -1; + if (BIO_read_filename(bio, file) <= 0) { + BIO_free(bio); + return -1; + } + /* optionally skip a leading server certificate */ + if (skipfirst) { + if ((x509 = modssl_PEM_read_bio_X509(bio, NULL, cb, NULL)) == NULL) { + BIO_free(bio); + return -1; + } + X509_free(x509); + } + /* free a perhaps already configured extra chain */ + extra_certs=SSL_CTX_get_extra_certs(ctx); + if (extra_certs != NULL) { + sk_X509_pop_free((STACK_OF(X509) *)extra_certs, X509_free); + SSL_CTX_set_extra_certs(ctx,NULL); + } + /* create new extra chain by loading the certs */ + n = 0; + while ((x509 = modssl_PEM_read_bio_X509(bio, NULL, cb, NULL)) != NULL) { + if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) { + X509_free(x509); + BIO_free(bio); + return -1; + } + n++; + } + /* Make sure that only the error is just an EOF */ + if ((err = ERR_peek_error()) > 0) { + if (!( ERR_GET_LIB(err) == ERR_LIB_PEM + && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { + BIO_free(bio); + return -1; + } + while (ERR_get_error() > 0) ; + } + BIO_free(bio); + return n; +} + +/* _________________________________________________________________ +** +** Session Stuff +** _________________________________________________________________ +*/ + +char *SSL_SESSION_id2sz(unsigned char *id, int idlen, + char *str, int strsize) +{ + char *cp; + int n; + + cp = str; + for (n = 0; n < idlen && n < SSL_MAX_SSL_SESSION_ID_LENGTH; n++) { + apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]); + cp += 2; + } + *cp = NUL; + return str; +} + +/* sslc+OpenSSL compat */ + +int modssl_session_get_time(SSL_SESSION *session) +{ +#ifdef OPENSSL_VERSION_NUMBER + return SSL_SESSION_get_time(session); +#else /* assume sslc */ + CRYPTO_TIME_T ct; + SSL_SESSION_get_time(session, &ct); + return CRYPTO_time_to_int(&ct); +#endif +} + +#ifndef SSLC_VERSION_NUMBER +#define SSLC_VERSION_NUMBER 0x0000 +#endif + +DH *modssl_dh_configure(unsigned char *p, int plen, + unsigned char *g, int glen) +{ + DH *dh; + + if (!(dh = DH_new())) { + return NULL; + } + +#if defined(OPENSSL_VERSION_NUMBER) || (SSLC_VERSION_NUMBER < 0x2000) + dh->p = BN_bin2bn(p, plen, NULL); + dh->g = BN_bin2bn(g, glen, NULL); + if (!(dh->p && dh->g)) { + DH_free(dh); + return NULL; + } +#else + R_EITEMS_add(dh->data, PK_TYPE_DH, PK_DH_P, 0, p, plen, R_EITEMS_PF_COPY); + R_EITEMS_add(dh->data, PK_TYPE_DH, PK_DH_G, 0, g, glen, R_EITEMS_PF_COPY); +#endif + + return dh; +} diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_ssl.h b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_ssl.h new file mode 100644 index 00000000..d5c48f16 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_ssl.h @@ -0,0 +1,93 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_util_ssl.h + * Additional Utility Functions for OpenSSL + */ + +#ifndef __SSL_UTIL_SSL_H__ +#define __SSL_UTIL_SSL_H__ + +/* + * Determine SSL library version number + */ +#define SSL_NIBBLE(x,n) ((x >> (n * 4)) & 0xF) + +#ifdef OPENSSL_VERSION_NUMBER +#define SSL_LIBRARY_VERSION OPENSSL_VERSION_NUMBER +#define SSL_LIBRARY_NAME "OpenSSL" +#define SSL_LIBRARY_TEXT OPENSSL_VERSION_TEXT +#define SSL_LIBRARY_DYNTEXT SSLeay_version(SSLEAY_VERSION) +#elif defined(SSLC_VERSION_NUMBER) +#define SSL_LIBRARY_VERSION SSLC_VERSION_NUMBER +#define SSL_LIBRARY_NAME "SSL-C" +#define SSL_LIBRARY_TEXT { 'S', 'S', 'L', '-', 'C', ' ', \ + '0' + SSL_NIBBLE(SSLC_VERSION_NUMBER,3), '.', \ + '0' + SSL_NIBBLE(SSLC_VERSION_NUMBER,2), '.', \ + '0' + SSL_NIBBLE(SSLC_VERSION_NUMBER,1), '.', \ + '0' + SSL_NIBBLE(SSLC_VERSION_NUMBER,0), 0 } +#define SSL_LIBRARY_DYNTEXT SSLC_library_info(SSLC_INFO_VERSION) +#elif !defined(SSL_LIBRARY_VERSION) +#define SSL_LIBRARY_VERSION 0x0000 +#define SSL_LIBRARY_NAME "OtherSSL" +#define SSL_LIBRARY_TEXT "OtherSSL 0.0.0 00 XXX 0000" +#define SSL_LIBRARY_DYNTEXT "OtherSSL 0.0.0 00 XXX 0000" +#endif + +/* + * Maximum length of a DER encoded session. + * FIXME: There is no define in OpenSSL, but OpenSSL uses 1024*10, + * so this value should be ok. Although we have no warm feeling. + */ +#define SSL_SESSION_MAX_DER 1024*10 + +/* max length for SSL_SESSION_id2sz */ +#define SSL_SESSION_ID_STRING_LEN \ + ((SSL_MAX_SSL_SESSION_ID_LENGTH + 1) * 2) + +/* + * Additional Functions + */ +void SSL_init_app_data2_idx(void); +void *SSL_get_app_data2(SSL *); +void SSL_set_app_data2(SSL *, void *); +X509 *SSL_read_X509(char *, X509 **, modssl_read_bio_cb_fn *); +EVP_PKEY *SSL_read_PrivateKey(char *, EVP_PKEY **, modssl_read_bio_cb_fn *, void *); +int SSL_smart_shutdown(SSL *ssl); +X509_STORE *SSL_X509_STORE_create(char *, char *); +int SSL_X509_STORE_lookup(X509_STORE *, int, X509_NAME *, X509_OBJECT *); +char *SSL_make_ciphersuite(apr_pool_t *, SSL *); +BOOL SSL_X509_isSGC(X509 *); +BOOL SSL_X509_getBC(X509 *, int *, int *); +BOOL SSL_X509_getCN(apr_pool_t *, X509 *, char **); +BOOL SSL_X509_INFO_load_file(apr_pool_t *, STACK_OF(X509_INFO) *, const char *); +BOOL SSL_X509_INFO_load_path(apr_pool_t *, STACK_OF(X509_INFO) *, const char *); +int SSL_CTX_use_certificate_chain(SSL_CTX *, char *, int, modssl_read_bio_cb_fn *); +char *SSL_SESSION_id2sz(unsigned char *, int, char *, int); + +/* util functions for OpenSSL+sslc compat */ +int modssl_session_get_time(SSL_SESSION *session); + +DH *modssl_dh_configure(unsigned char *p, int plen, + unsigned char *g, int glen); + +#endif /* __SSL_UTIL_SSL_H__ */ diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_table.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_table.c new file mode 100644 index 00000000..5eb98ec8 --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_table.c @@ -0,0 +1,2518 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_util_table.c + * High Performance Hash Table Functions + */ + +/* + * Generic hash table handler + * Table 4.1.0 July-28-1998 + * + * This library is a generic open hash table with buckets and + * linked lists. It is pretty high performance. Each element + * has a key and a data. The user indexes on the key to find the + * data. + * + * Copyright 1998 by Gray Watson <gray@letters.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose and without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, + * and that the name of Gray Watson not be used in advertising or + * publicity pertaining to distribution of the document or software + * without specific, written prior permission. + * + * Gray Watson makes no representations about the suitability of the + * software described herein for any purpose. It is provided "as is" + * without express or implied warranty. + * + * Modified in March 1999 by Ralf S. Engelschall <rse@engelschall.com> + * for use in the mod_ssl project: + * o merged table_loc.h header into table.c + * o removed fillproto-comments from table.h + * o removed mmap() support because it's too unportable + * o added support for MM library via ta_{malloc,calloc,realloc,free} + */ + +#include <stdlib.h> +#include <string.h> + +/* forward definitions for table.h */ +typedef struct table_st table_t; +typedef struct table_entry_st table_entry_t; + +#define TABLE_PRIVATE +#include "ssl_util_table.h" +#include "mod_ssl.h" + +/****************************** local defines ******************************/ + +#ifndef BITSPERBYTE +#define BITSPERBYTE 8 +#endif +#ifndef BITS +#define BITS(type) (BITSPERBYTE * (int)sizeof(type)) +#endif + +#define TABLE_MAGIC 0xBADF00D /* very magic magicness */ +#define LINEAR_MAGIC 0xAD00D00 /* magic value for linear struct */ +#define DEFAULT_SIZE 1024 /* default table size */ +#define MAX_ALIGNMENT 128 /* max alignment value */ +#define MAX_SORT_SPLITS 128 /* qsort can handle 2^128 entries */ + +/* returns 1 when we should grow or shrink the table */ +#define SHOULD_TABLE_GROW(tab) ((tab)->ta_entry_n > (tab)->ta_bucket_n * 2) +#define SHOULD_TABLE_SHRINK(tab) ((tab)->ta_entry_n < (tab)->ta_bucket_n / 2) + +/* + * void HASH_MIX + * + * DESCRIPTION: + * + * Mix 3 32-bit values reversibly. For every delta with one or two bits + * set, and the deltas of all three high bits or all three low bits, + * whether the original value of a,b,c is almost all zero or is + * uniformly distributed. + * + * If HASH_MIX() is run forward or backward, at least 32 bits in a,b,c + * have at least 1/4 probability of changing. If mix() is run + * forward, every bit of c will change between 1/3 and 2/3 of the + * time. (Well, 22/100 and 78/100 for some 2-bit deltas.) + * + * HASH_MIX() takes 36 machine instructions, but only 18 cycles on a + * superscalar machine (like a Pentium or a Sparc). No faster mixer + * seems to work, that's the result of my brute-force search. There + * were about 2^68 hashes to choose from. I only tested about a + * billion of those. + */ +#define HASH_MIX(a, b, c) \ + do { \ + a -= b; a -= c; a ^= (c >> 13); \ + b -= c; b -= a; b ^= (a << 8); \ + c -= a; c -= b; c ^= (b >> 13); \ + a -= b; a -= c; a ^= (c >> 12); \ + b -= c; b -= a; b ^= (a << 16); \ + c -= a; c -= b; c ^= (b >> 5); \ + a -= b; a -= c; a ^= (c >> 3); \ + b -= c; b -= a; b ^= (a << 10); \ + c -= a; c -= b; c ^= (b >> 15); \ + } while(0) + +#define TABLE_POINTER(table, type, pnt) (pnt) + +/* + * Macros to get at the key and the data pointers + */ +#define ENTRY_KEY_BUF(entry_p) ((entry_p)->te_key_buf) +#define ENTRY_DATA_BUF(tab_p, entry_p) \ + (ENTRY_KEY_BUF(entry_p) + (entry_p)->te_key_size) + +/* + * Table structures... + */ + +/* + * HACK: this should be equiv as the table_entry_t without the key_buf + * char. We use this with the ENTRY_SIZE() macro above which solves + * the problem with the lack of the [0] GNU hack. We use the + * table_entry_t structure to better map the memory and make things + * faster. + */ +typedef struct table_shell_st { + unsigned int te_key_size; /* size of data */ + unsigned int te_data_size; /* size of data */ + struct table_shell_st *te_next_p; /* pointer to next in the list */ + /* NOTE: this does not have the te_key_buf field here */ +} table_shell_t; + +/* + * Elements in the bucket linked-lists. The key[1] is the start of + * the key with the rest of the key and all of the data information + * packed in memory directly after the end of this structure. + * + * NOTE: if this structure is changed, the table_shell_t must be changed + * to match. + */ +struct table_entry_st { + unsigned int te_key_size; /* size of data */ + unsigned int te_data_size; /* size of data */ + struct table_entry_st *te_next_p; /* pointer to next in the list */ + unsigned char te_key_buf[1]; /* 1st byte of key buf */ +}; + +/* external structure for debuggers be able to see void */ +typedef table_entry_t table_entry_ext_t; + +/* main table structure */ +struct table_st { + unsigned int ta_magic; /* magic number */ + unsigned int ta_flags; /* table's flags defined in table.h */ + unsigned int ta_bucket_n; /* num of buckets, should be 2^X */ + unsigned int ta_entry_n; /* num of entries in all buckets */ + unsigned int ta_data_align; /* data alignment value */ + table_entry_t **ta_buckets; /* array of linked lists */ + table_linear_t ta_linear; /* linear tracking */ + unsigned long ta_file_size; /* size of on-disk space */ + void *(*ta_malloc)(void *opt_param, size_t size); + void *(*ta_calloc)(void *opt_param, size_t number, size_t size); + void *(*ta_realloc)(void *opt_param, void *ptr, size_t size); + void (*ta_free)(void *opt_param, void *ptr); + void *opt_param; +}; + +/* external table structure for debuggers */ +typedef table_t table_ext_t; + +/* local comparison functions */ +typedef int (*compare_t) (const void *element1_p, const void *element2_p, + table_compare_t user_compare, + const table_t * table_p); + +/* + * to map error to string + */ +typedef struct { + int es_error; /* error number */ + char *es_string; /* assocaited string */ +} error_str_t; + +static error_str_t errors[] = +{ + {TABLE_ERROR_NONE, "no error"}, + {TABLE_ERROR_PNT, "invalid table pointer"}, + {TABLE_ERROR_ARG_NULL, "buffer argument is null"}, + {TABLE_ERROR_SIZE, "incorrect size argument"}, + {TABLE_ERROR_OVERWRITE, "key exists and no overwrite"}, + {TABLE_ERROR_NOT_FOUND, "key does not exist"}, + {TABLE_ERROR_ALLOC, "error allocating memory"}, + {TABLE_ERROR_LINEAR, "linear access not in progress"}, + {TABLE_ERROR_OPEN, "could not open file"}, + {TABLE_ERROR_SEEK, "could not seek to position in file"}, + {TABLE_ERROR_READ, "could not read from file"}, + {TABLE_ERROR_WRITE, "could not write to file"}, + {TABLE_ERROR_EMPTY, "table is empty"}, + {TABLE_ERROR_NOT_EMPTY, "table contains data"}, + {TABLE_ERROR_ALIGNMENT, "invalid alignment value"}, + {0} +}; + +#define INVALID_ERROR "invalid error code" + + +/********************** wrappers for system functions ************************/ +static void *sys_malloc(void *param, size_t size) +{ + return malloc(size); +} + +static void *sys_calloc(void *param, size_t size1, size_t size2) +{ + return calloc(size1, size2); +} + +static void *sys_realloc(void *param, void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +static void sys_free(void *param, void *ptr) +{ + free(ptr); +} + +/****************************** local functions ******************************/ + +/* + * static table_entry_t *first_entry + * + * DESCRIPTION: + * + * Return the first entry in the table. It will set the linear + * structure counter to the position of the first entry. + * + * RETURNS: + * + * Success: A pointer to the first entry in the table. + * + * Failure: NULL if there is no first entry. + * + * ARGUMENTS: + * + * table_p - Table whose next entry we are finding. + * + * linear_p - Pointer to a linear structure which we will advance and + * then find the corresponding entry. + */ +static table_entry_t *first_entry(table_t * table_p, + table_linear_t * linear_p) +{ + table_entry_t *entry_p; + unsigned int bucket_c = 0; + + /* look for the first non-empty bucket */ + for (bucket_c = 0; bucket_c < table_p->ta_bucket_n; bucket_c++) { + entry_p = table_p->ta_buckets[bucket_c]; + if (entry_p != NULL) { + if (linear_p != NULL) { + linear_p->tl_bucket_c = bucket_c; + linear_p->tl_entry_c = 0; + } + return TABLE_POINTER(table_p, table_entry_t *, entry_p); + } + } + + return NULL; +} + +/* + * static table_entry_t *next_entry + * + * DESCRIPTION: + * + * Return the next entry in the table which is past the position in + * our linear pointer. It will advance the linear structure counters. + * + * RETURNS: + * + * Success: A pointer to the next entry in the table. + * + * Failure: NULL. + * + * ARGUMENTS: + * + * table_p - Table whose next entry we are finding. + * + * linear_p - Pointer to a linear structure which we will advance and + * then find the corresponding entry. + * + * error_p - Pointer to an integer which when the routine returns will + * contain a table error code. + */ +static table_entry_t *next_entry(table_t * table_p, table_linear_t * linear_p, + int *error_p) +{ + table_entry_t *entry_p; + int entry_c; + + /* can't next if we haven't first-ed */ + if (linear_p == NULL) { + if (error_p != NULL) + *error_p = TABLE_ERROR_LINEAR; + return NULL; + } + + if (linear_p->tl_bucket_c >= table_p->ta_bucket_n) { + /* + * NOTE: this might happen if we delete an item which shortens the + * table bucket numbers. + */ + if (error_p != NULL) + *error_p = TABLE_ERROR_NOT_FOUND; + return NULL; + } + + linear_p->tl_entry_c++; + + /* find the entry which is the nth in the list */ + entry_p = table_p->ta_buckets[linear_p->tl_bucket_c]; + /* NOTE: we swap the order here to be more efficient */ + for (entry_c = linear_p->tl_entry_c; entry_c > 0; entry_c--) { + /* did we reach the end of the list? */ + if (entry_p == NULL) + break; + entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p)->te_next_p; + } + + /* did we find an entry in the current bucket? */ + if (entry_p != NULL) { + if (error_p != NULL) + *error_p = TABLE_ERROR_NONE; + return TABLE_POINTER(table_p, table_entry_t *, entry_p); + } + + /* find the first entry in the next non-empty bucket */ + + linear_p->tl_entry_c = 0; + for (linear_p->tl_bucket_c++; linear_p->tl_bucket_c < table_p->ta_bucket_n; + linear_p->tl_bucket_c++) { + entry_p = table_p->ta_buckets[linear_p->tl_bucket_c]; + if (entry_p != NULL) { + if (error_p != NULL) + *error_p = TABLE_ERROR_NONE; + return TABLE_POINTER(table_p, table_entry_t *, entry_p); + } + } + + if (error_p != NULL) + *error_p = TABLE_ERROR_NOT_FOUND; + return NULL; +} + +/* + * static unsigned int hash + * + * DESCRIPTION: + * + * Hash a variable-length key into a 32-bit value. Every bit of the + * key affects every bit of the return value. Every 1-bit and 2-bit + * delta achieves avalanche. About (6 * len + 35) instructions. The + * best hash table sizes are powers of 2. There is no need to use mod + * (sooo slow!). If you need less than 32 bits, use a bitmask. For + * example, if you need only 10 bits, do h = (h & hashmask(10)); In + * which case, the hash table should have hashsize(10) elements. + * + * By Bob Jenkins, 1996. bob_jenkins@compuserve.com. You may use + * this code any way you wish, private, educational, or commercial. + * It's free. See + * http://ourworld.compuserve.com/homepages/bob_jenkins/evahash.htm + * Use for hash table lookup, or anything where one collision in 2^^32 + * is acceptable. Do NOT use for cryptographic purposes. + * + * RETURNS: + * + * Returns a 32-bit hash value. + * + * ARGUMENTS: + * + * key - Key (the unaligned variable-length array of bytes) that we + * are hashing. + * + * length - Length of the key in bytes. + * + * init_val - Initialization value of the hash if you need to hash a + * number of strings together. For instance, if you are hashing N + * strings (unsigned char **)keys, do it like this: + * + * for (i=0, h=0; i<N; ++i) h = hash( keys[i], len[i], h); + */ +static unsigned int hash(const unsigned char *key, + const unsigned int length, + const unsigned int init_val) +{ + const unsigned char *key_p = key; + unsigned int a, b, c, len; + + /* set up the internal state */ + a = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + b = 0x9e3779b9; + c = init_val; /* the previous hash value */ + + /* handle most of the key */ + for (len = length; len >= 12; len -= 12) { + a += (key_p[0] + + ((unsigned long) key_p[1] << 8) + + ((unsigned long) key_p[2] << 16) + + ((unsigned long) key_p[3] << 24)); + b += (key_p[4] + + ((unsigned long) key_p[5] << 8) + + ((unsigned long) key_p[6] << 16) + + ((unsigned long) key_p[7] << 24)); + c += (key_p[8] + + ((unsigned long) key_p[9] << 8) + + ((unsigned long) key_p[10] << 16) + + ((unsigned long) key_p[11] << 24)); + HASH_MIX(a, b, c); + key_p += 12; + } + + c += length; + + /* all the case statements fall through to the next */ + switch (len) { + case 11: + c += ((unsigned long) key_p[10] << 24); + case 10: + c += ((unsigned long) key_p[9] << 16); + case 9: + c += ((unsigned long) key_p[8] << 8); + /* the first byte of c is reserved for the length */ + case 8: + b += ((unsigned long) key_p[7] << 24); + case 7: + b += ((unsigned long) key_p[6] << 16); + case 6: + b += ((unsigned long) key_p[5] << 8); + case 5: + b += key_p[4]; + case 4: + a += ((unsigned long) key_p[3] << 24); + case 3: + a += ((unsigned long) key_p[2] << 16); + case 2: + a += ((unsigned long) key_p[1] << 8); + case 1: + a += key_p[0]; + /* case 0: nothing left to add */ + } + HASH_MIX(a, b, c); + + return c; +} + +/* + * static int entry_size + * + * DESCRIPTION: + * + * Calculates the appropriate size of an entry to include the key and + * data sizes as well as any associated alignment to the data. + * + * RETURNS: + * + * The associated size of the entry. + * + * ARGUMENTS: + * + * table_p - Table associated with the entries whose size we are + * determining. + * + * key_size - Size of the entry key. + * + * data - Size of the entry data. + */ +static int entry_size(const table_t * table_p, const unsigned int key_size, + const unsigned int data_size) +{ + int size, left; + + /* initial size -- key is already aligned if right after struct */ + size = sizeof(struct table_shell_st) + key_size; + + /* if there is no alignment then it is easy */ + if (table_p->ta_data_align == 0) + return size + data_size; + /* add in our alignement */ + left = size & (table_p->ta_data_align - 1); + if (left > 0) + size += table_p->ta_data_align - left; + /* we add the data size here after the alignment */ + size += data_size; + + return size; +} + +/* + * static unsigned char *entry_data_buf + * + * DESCRIPTION: + * + * Companion to the ENTRY_DATA_BUF macro but this handles any + * associated alignment to the data in the entry. + * + * RETURNS: + * + * Pointer to the data segment of the entry. + * + * ARGUMENTS: + * + * table_p - Table associated with the entry. + * + * entry_p - Entry whose data pointer we are determining. + */ +static unsigned char *entry_data_buf(const table_t * table_p, + const table_entry_t * entry_p) +{ + const unsigned char *buf_p; + int size, pad; + + buf_p = entry_p->te_key_buf + entry_p->te_key_size; + + /* if there is no alignment then it is easy */ + if (table_p->ta_data_align == 0) + return (unsigned char *) buf_p; + /* we need the size of the space before the data */ + size = sizeof(struct table_shell_st) + entry_p->te_key_size; + + /* add in our alignment */ + pad = size & (table_p->ta_data_align - 1); + if (pad > 0) + pad = table_p->ta_data_align - pad; + return (unsigned char *) buf_p + pad; +} + +/******************************* sort routines *******************************/ + +/* + * static int our_compare + * + * DESCRIPTION: + * + * Compare two entries by calling user's compare program or by using + * memcmp. + * + * RETURNS: + * + * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2. + * + * ARGUMENTS: + * + * p1 - First entry pointer to compare. + * + * p2 - Second entry pointer to compare. + * + * compare - User comparison function. Ignored. + * + * table_p - Associated table being ordered. Ignored. + */ +static int local_compare(const void *p1, const void *p2, + table_compare_t compare, const table_t * table_p) +{ + const table_entry_t *const *ent1_p = p1, *const *ent2_p = p2; + int cmp; + unsigned int size; + + /* compare as many bytes as we can */ + size = (*ent1_p)->te_key_size; + if ((*ent2_p)->te_key_size < size) + size = (*ent2_p)->te_key_size; + cmp = memcmp(ENTRY_KEY_BUF(*ent1_p), ENTRY_KEY_BUF(*ent2_p), size); + /* if common-size equal, then if next more bytes, it is larger */ + if (cmp == 0) + cmp = (*ent1_p)->te_key_size - (*ent2_p)->te_key_size; + return cmp; +} + +/* + * static int external_compare + * + * DESCRIPTION: + * + * Compare two entries by calling user's compare program or by using + * memcmp. + * + * RETURNS: + * + * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2. + * + * ARGUMENTS: + * + * p1 - First entry pointer to compare. + * + * p2 - Second entry pointer to compare. + * + * user_compare - User comparison function. + * + * table_p - Associated table being ordered. + */ +static int external_compare(const void *p1, const void *p2, + table_compare_t user_compare, + const table_t * table_p) +{ + const table_entry_t *const *ent1_p = p1, *const *ent2_p = p2; + /* since we know we are not aligned we can use the EXTRY_DATA_BUF macro */ + return user_compare(ENTRY_KEY_BUF(*ent1_p), (*ent1_p)->te_key_size, + ENTRY_DATA_BUF(table_p, *ent1_p), + (*ent1_p)->te_data_size, + ENTRY_KEY_BUF(*ent2_p), (*ent2_p)->te_key_size, + ENTRY_DATA_BUF(table_p, *ent2_p), + (*ent2_p)->te_data_size); +} + +/* + * static int external_compare_align + * + * DESCRIPTION: + * + * Compare two entries by calling user's compare program or by using + * memcmp. Alignment information is necessary. + * + * RETURNS: + * + * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2. + * + * ARGUMENTS: + * + * p1 - First entry pointer to compare. + * + * p2 - Second entry pointer to compare. + * + * user_compare - User comparison function. + * + * table_p - Associated table being ordered. + */ +static int external_compare_align(const void *p1, const void *p2, + table_compare_t user_compare, + const table_t * table_p) +{ + const table_entry_t *const *ent1_p = p1, *const *ent2_p = p2; + /* since we are aligned we have to use the entry_data_buf function */ + return user_compare(ENTRY_KEY_BUF(*ent1_p), (*ent1_p)->te_key_size, + entry_data_buf(table_p, *ent1_p), + (*ent1_p)->te_data_size, + ENTRY_KEY_BUF(*ent2_p), (*ent2_p)->te_key_size, + entry_data_buf(table_p, *ent2_p), + (*ent2_p)->te_data_size); +} + +/* + * static void split + * + * DESCRIPTION: + * + * This sorts an array of longs via the quick sort algorithm (it's + * pretty quick) + * + * RETURNS: + * + * None. + * + * ARGUMENTS: + * + * first_p - Start of the list that we are splitting. + * + * last_p - Last entry in the list that we are splitting. + * + * compare - Comparison function which is handling the actual + * elements. This is either a local function or a function to setup + * the problem element key and data pointers which then hands off to + * the user function. + * + * user_compare - User comparison function. Could be NULL if we are + * just using a local comparison function. + * + * table_p - Associated table being sorted. + */ +static void split(void *first_p, void *last_p, compare_t compare, + table_compare_t user_compare, table_t * table_p) +{ + void *pivot_p, *left_p, *right_p, *left_last_p, *right_first_p; + void *firsts[MAX_SORT_SPLITS], *lasts[MAX_SORT_SPLITS]; + int split_c = 0; + + for (;;) { + + /* no need to split the list if it is < 2 elements */ + while (first_p >= last_p) { + if (split_c == 0) { + /* we are done */ + return; + } + split_c--; + first_p = firsts[split_c]; + last_p = lasts[split_c]; + } + + left_p = first_p; + right_p = last_p; + pivot_p = first_p; + + do { + /* scan from right hand side */ + while (right_p > left_p + && compare(right_p, pivot_p, user_compare, table_p) > 0) + right_p = (char *) right_p - sizeof(table_entry_t *); + /* scan from left hand side */ + while (right_p > left_p + && compare(pivot_p, left_p, user_compare, table_p) >= 0) + left_p = (char *) left_p + sizeof(table_entry_t *); + /* if the pointers haven't met then swap values */ + if (right_p > left_p) { + /* swap_bytes(left_p, right_p) */ + table_entry_t *temp; + + temp = *(table_entry_t **) left_p; + *(table_entry_t **) left_p = *(table_entry_t **) right_p; + *(table_entry_t **) right_p = temp; + } + } while (right_p > left_p); + + /* now we swap the pivot with the right-hand side */ + { + /* swap_bytes(pivot_p, right_p); */ + table_entry_t *temp; + + temp = *(table_entry_t **) pivot_p; + *(table_entry_t **) pivot_p = *(table_entry_t **) right_p; + *(table_entry_t **) right_p = temp; + } + pivot_p = right_p; + + /* save the section to the right of the pivot in our stack */ + right_first_p = (char *) pivot_p + sizeof(table_entry_t *); + left_last_p = (char *) pivot_p - sizeof(table_entry_t *); + + /* do we need to save the righthand side? */ + if (right_first_p < last_p) { + if (split_c >= MAX_SORT_SPLITS) { + /* sanity check here -- we should never get here */ + abort(); + } + firsts[split_c] = right_first_p; + lasts[split_c] = last_p; + split_c++; + } + + /* do the left hand side of the pivot */ + /* first_p = first_p */ + last_p = left_last_p; + } +} + +/*************************** exported routines *******************************/ + +/* + * table_t *table_alloc + * + * DESCRIPTION: + * + * Allocate a new table structure. + * + * RETURNS: + * + * A pointer to the new table structure which must be passed to + * table_free to be deallocated. On error a NULL is returned. + * + * ARGUMENTS: + * + * bucket_n - Number of buckets for the hash table. Our current hash + * value works best with base two numbers. Set to 0 to take the + * library default of 1024. + * + * error_p - Pointer to an integer which, if not NULL, will contain a + * table error code. + * + * malloc_f, realloc_f, free_f - Pointers to malloc(3)-, realloc(3)- + * and free(3)-style functions. + */ +table_t *table_alloc(const unsigned int bucket_n, int *error_p, + void *(*malloc_f)(void *opt_param, size_t size), + void *(*calloc_f)(void *opt_param, size_t number, size_t size), + void *(*realloc_f)(void *opt_param, void *ptr, size_t size), + void (*free_f)(void *opt_param, void *ptr), void *opt_param) +{ + table_t *table_p = NULL; + unsigned int buck_n; + + /* allocate a table structure */ + if (malloc_f != NULL) + table_p = malloc_f(opt_param, sizeof(table_t)); + else + table_p = malloc(sizeof(table_t)); + if (table_p == NULL) { + if (error_p != NULL) + *error_p = TABLE_ERROR_ALLOC; + return NULL; + } + + if (bucket_n > 0) + buck_n = bucket_n; + else + buck_n = DEFAULT_SIZE; + /* allocate the buckets which are NULLed */ + if (calloc_f != NULL) + table_p->ta_buckets = (table_entry_t **)calloc_f(opt_param, buck_n, + sizeof(table_entry_t *)); + else + table_p->ta_buckets = (table_entry_t **)calloc(buck_n, sizeof(table_entry_t *)); + if (table_p->ta_buckets == NULL) { + if (error_p != NULL) + *error_p = TABLE_ERROR_ALLOC; + if (free_f != NULL) + free_f(opt_param, table_p); + else + free(table_p); + return NULL; + } + + /* initialize structure */ + table_p->ta_magic = TABLE_MAGIC; + table_p->ta_flags = 0; + table_p->ta_bucket_n = buck_n; + table_p->ta_entry_n = 0; + table_p->ta_data_align = 0; + table_p->ta_linear.tl_magic = 0; + table_p->ta_linear.tl_bucket_c = 0; + table_p->ta_linear.tl_entry_c = 0; + table_p->ta_file_size = 0; + table_p->ta_malloc = malloc_f != NULL ? malloc_f : sys_malloc; + table_p->ta_calloc = calloc_f != NULL ? calloc_f : sys_calloc; + table_p->ta_realloc = realloc_f != NULL ? realloc_f : sys_realloc; + table_p->ta_free = free_f != NULL ? free_f : sys_free; + table_p->opt_param = opt_param; + + if (error_p != NULL) + *error_p = TABLE_ERROR_NONE; + return table_p; +} + +/* + * int table_attr + * + * DESCRIPTION: + * + * Set the attributes for the table. The available attributes are + * specified at the top of table.h. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Pointer to a table structure which we will be altering. + * + * attr - Attribute(s) that we will be applying to the table. + */ +int table_attr(table_t * table_p, const int attr) +{ + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + table_p->ta_flags = attr; + + return TABLE_ERROR_NONE; +} + +/* + * int table_set_data_alignment + * + * DESCRIPTION: + * + * Set the alignment for the data in the table. For data elements + * sizeof(long) is recommended unless you use smaller data types + * exclusively. + * + * WARNING: This must be done before any data gets put into the table. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Pointer to a table structure which we will be altering. + * + * alignment - Alignment requested for the data. Must be a power of + * 2. Set to 0 for none. + */ +int table_set_data_alignment(table_t * table_p, const int alignment) +{ + int val; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (table_p->ta_entry_n > 0) + return TABLE_ERROR_NOT_EMPTY; + /* defaults */ + if (alignment < 2) + table_p->ta_data_align = 0; + else { + /* verify we have a base 2 number */ + for (val = 2; val < MAX_ALIGNMENT; val *= 2) { + if (val == alignment) + break; + } + if (val >= MAX_ALIGNMENT) + return TABLE_ERROR_ALIGNMENT; + table_p->ta_data_align = alignment; + } + + return TABLE_ERROR_NONE; +} + +/* + * int table_clear + * + * DESCRIPTION: + * + * Clear out and free all elements in a table structure. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer that we will be clearing. + */ +int table_clear(table_t * table_p) +{ + table_entry_t *entry_p, *next_p; + table_entry_t **bucket_p, **bounds_p; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + /* free the table allocation and table structure */ + bounds_p = table_p->ta_buckets + table_p->ta_bucket_n; + for (bucket_p = table_p->ta_buckets; bucket_p < bounds_p; bucket_p++) { + for (entry_p = *bucket_p; entry_p != NULL; entry_p = next_p) { + /* record the next pointer before we free */ + next_p = entry_p->te_next_p; + table_p->ta_free(table_p->opt_param, entry_p); + } + /* clear the bucket entry after we free its entries */ + *bucket_p = NULL; + } + + /* reset table state info */ + table_p->ta_entry_n = 0; + table_p->ta_linear.tl_magic = 0; + table_p->ta_linear.tl_bucket_c = 0; + table_p->ta_linear.tl_entry_c = 0; + + return TABLE_ERROR_NONE; +} + +/* + * int table_free + * + * DESCRIPTION: + * + * Deallocates a table structure. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer that we will be freeing. + */ +int table_free(table_t * table_p) +{ + int ret; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + ret = table_clear(table_p); + + if (table_p->ta_buckets != NULL) + table_p->ta_free(table_p->opt_param, table_p->ta_buckets); + table_p->ta_magic = 0; + table_p->ta_free(table_p->opt_param, table_p); + + return ret; +} + +/* + * int table_insert_kd + * + * DESCRIPTION: + * + * Like table_insert except it passes back a pointer to the key and + * the data buffers after they have been inserted into the table + * structure. + * + * This routine adds a key/data pair both of which are made up of a + * buffer of bytes and an associated size. Both the key and the data + * will be copied into buffers allocated inside the table. If the key + * exists already, the associated data will be replaced if the + * overwrite flag is set, otherwise an error is returned. + * + * NOTE: be very careful changing the values since the table library + * provides the pointers to its memory. The key can _never_ be + * changed otherwise you will not find it again. The data can be + * changed but its length can never be altered unless you delete and + * re-insert it into the table. + * + * WARNING: The pointers to the key and data are not in any specific + * alignment. Accessing the key and/or data as an short, integer, or + * long pointer directly can cause problems. + * + * WARNING: Replacing a data cell (not inserting) will cause the table + * linked list to be temporarily invalid. Care must be taken with + * multiple threaded programs which are relying on the first/next + * linked list to be always valid. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer into which we will be inserting a + * new key/data pair. + * + * key_buf - Buffer of bytes of the key that we are inserting. If you + * are storing an (int) as the key (for example) then key_buf should + * be a (int *). + * + * key_size - Size of the key_buf buffer. If set to < 0 then the + * library will do a strlen of key_buf and add 1 for the '\0'. If you + * are storing an (int) as the key (for example) then key_size should + * be sizeof(int). + * + * data_buf - Buffer of bytes of the data that we are inserting. If + * it is NULL then the library will allocate space for the data in the + * table without copying in any information. If data_buf is NULL and + * data_size is 0 then the library will associate a NULL data pointer + * with the key. If you are storing a (long) as the data (for + * example) then data_buf should be a (long *). + * + * data_size - Size of the data_buf buffer. If set to < 0 then the + * library will do a strlen of data_buf and add 1 for the '\0'. If + * you are storing an (long) as the key (for example) then key_size + * should be sizeof(long). + * + * key_buf_p - Pointer which, if not NULL, will be set to the address + * of the key storage that was allocated in the table. If you are + * storing an (int) as the key (for example) then key_buf_p should be + * (int **) i.e. the address of a (int *). + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that was allocated in the table. If you are + * storing an (long) as the data (for example) then data_buf_p should + * be (long **) i.e. the address of a (long *). + * + * overwrite - Flag which, if set to 1, will allow the overwriting of + * the data in the table with the new data if the key already exists + * in the table. + */ +int table_insert_kd(table_t * table_p, + const void *key_buf, const int key_size, + const void *data_buf, const int data_size, + void **key_buf_p, void **data_buf_p, + const char overwrite_b) +{ + int bucket; + unsigned int ksize, dsize; + table_entry_t *entry_p, *last_p; + void *key_copy_p, *data_copy_p; + + /* check the arguments */ + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (key_buf == NULL) + return TABLE_ERROR_ARG_NULL; + /* data_buf can be null but size must be >= 0, if it isn't null size != 0 */ + if ((data_buf == NULL && data_size < 0) + || (data_buf != NULL && data_size == 0)) + return TABLE_ERROR_SIZE; + /* determine sizes of key and data */ + if (key_size < 0) + ksize = strlen((char *) key_buf) + sizeof(char); + else + ksize = key_size; + if (data_size < 0) + dsize = strlen((char *) data_buf) + sizeof(char); + else + dsize = data_size; + /* get the bucket number via a hash function */ + bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n; + + /* look for the entry in this bucket, only check keys of the same size */ + last_p = NULL; + for (entry_p = table_p->ta_buckets[bucket]; + (entry_p != NULL) && (entry_p->te_next_p != last_p); + last_p = entry_p, entry_p = entry_p->te_next_p) { + if (entry_p->te_key_size == ksize + && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0) + break; + } + + /* did we find it? then we are in replace mode. */ + if (entry_p != NULL) { + + /* can we not overwrite existing data? */ + if (!overwrite_b) { + if (key_buf_p != NULL) + *key_buf_p = ENTRY_KEY_BUF(entry_p); + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + if (table_p->ta_data_align == 0) + *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); + else + *data_buf_p = entry_data_buf(table_p, entry_p); + } + } + return TABLE_ERROR_OVERWRITE; + } + + /* re-alloc entry's data if the new size != the old */ + if (dsize != entry_p->te_data_size) { + + /* + * First we delete it from the list to keep the list whole. + * This properly preserves the linked list in case we have a + * thread marching through the linked list while we are + * inserting. Maybe this is an unnecessary protection but it + * should not harm that much. + */ + if (last_p == NULL) + table_p->ta_buckets[bucket] = entry_p->te_next_p; + else + last_p->te_next_p = entry_p->te_next_p; + /* + * Realloc the structure which may change its pointer. NOTE: + * this may change any previous data_key_p and data_copy_p + * pointers. + */ + entry_p = (table_entry_t *) + table_p->ta_realloc(table_p->opt_param, entry_p, + entry_size(table_p, entry_p->te_key_size, dsize)); + if (entry_p == NULL) + return TABLE_ERROR_ALLOC; + /* add it back to the front of the list */ + entry_p->te_data_size = dsize; + entry_p->te_next_p = table_p->ta_buckets[bucket]; + table_p->ta_buckets[bucket] = entry_p; + } + + /* copy or replace data in storage */ + if (dsize > 0) { + if (table_p->ta_data_align == 0) + data_copy_p = ENTRY_DATA_BUF(table_p, entry_p); + else + data_copy_p = entry_data_buf(table_p, entry_p); + if (data_buf != NULL) + memcpy(data_copy_p, data_buf, dsize); + } + else + data_copy_p = NULL; + if (key_buf_p != NULL) + *key_buf_p = ENTRY_KEY_BUF(entry_p); + if (data_buf_p != NULL) + *data_buf_p = data_copy_p; + /* returning from the section where we were overwriting table data */ + return TABLE_ERROR_NONE; + } + + /* + * It is a new entry. + */ + + /* allocate a new entry */ + entry_p = (table_entry_t *) + table_p->ta_malloc(table_p->opt_param, + entry_size(table_p, ksize, dsize)); + if (entry_p == NULL) + return TABLE_ERROR_ALLOC; + /* copy key into storage */ + entry_p->te_key_size = ksize; + key_copy_p = ENTRY_KEY_BUF(entry_p); + memcpy(key_copy_p, key_buf, ksize); + + /* copy data in */ + entry_p->te_data_size = dsize; + if (dsize > 0) { + if (table_p->ta_data_align == 0) + data_copy_p = ENTRY_DATA_BUF(table_p, entry_p); + else + data_copy_p = entry_data_buf(table_p, entry_p); + if (data_buf != NULL) + memcpy(data_copy_p, data_buf, dsize); + } + else + data_copy_p = NULL; + if (key_buf_p != NULL) + *key_buf_p = key_copy_p; + if (data_buf_p != NULL) + *data_buf_p = data_copy_p; + /* insert into list, no need to append */ + entry_p->te_next_p = table_p->ta_buckets[bucket]; + table_p->ta_buckets[bucket] = entry_p; + + table_p->ta_entry_n++; + + /* do we need auto-adjust? */ + if (table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST + && SHOULD_TABLE_GROW(table_p)) + return table_adjust(table_p, table_p->ta_entry_n); + return TABLE_ERROR_NONE; +} + +/* + * int table_insert + * + * DESCRIPTION: + * + * Exactly the same as table_insert_kd except it does not pass back a + * pointer to the key after they have been inserted into the table + * structure. This is still here for backwards compatibility. + * + * See table_insert_kd for more information. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer into which we will be inserting a + * new key/data pair. + * + * key_buf - Buffer of bytes of the key that we are inserting. If you + * are storing an (int) as the key (for example) then key_buf should + * be a (int *). + * + * key_size - Size of the key_buf buffer. If set to < 0 then the + * library will do a strlen of key_buf and add 1 for the '\0'. If you + * are storing an (int) as the key (for example) then key_size should + * be sizeof(int). + * + * data_buf - Buffer of bytes of the data that we are inserting. If + * it is NULL then the library will allocate space for the data in the + * table without copying in any information. If data_buf is NULL and + * data_size is 0 then the library will associate a NULL data pointer + * with the key. If you are storing a (long) as the data (for + * example) then data_buf should be a (long *). + * + * data_size - Size of the data_buf buffer. If set to < 0 then the + * library will do a strlen of data_buf and add 1 for the '\0'. If + * you are storing an (long) as the key (for example) then key_size + * should be sizeof(long). + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that was allocated in the table. If you are + * storing an (long) as the data (for example) then data_buf_p should + * be (long **) i.e. the address of a (long *). + * + * overwrite - Flag which, if set to 1, will allow the overwriting of + * the data in the table with the new data if the key already exists + * in the table. + */ +int table_insert(table_t * table_p, + const void *key_buf, const int key_size, + const void *data_buf, const int data_size, + void **data_buf_p, const char overwrite_b) +{ + return table_insert_kd(table_p, key_buf, key_size, data_buf, data_size, + NULL, data_buf_p, overwrite_b); +} + +/* + * int table_retrieve + * + * DESCRIPTION: + * + * This routine looks up a key made up of a buffer of bytes and an + * associated size in the table. If found then it returns the + * associated data information. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer into which we will be searching + * for the key. + * + * key_buf - Buffer of bytes of the key that we are searching for. If + * you are looking for an (int) as the key (for example) then key_buf + * should be a (int *). + * + * key_size - Size of the key_buf buffer. If set to < 0 then the + * library will do a strlen of key_buf and add 1 for the '\0'. If you + * are looking for an (int) as the key (for example) then key_size + * should be sizeof(int). + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that was allocated in the table and that is + * associated with the key. If a (long) was stored as the data (for + * example) then data_buf_p should be (long **) i.e. the address of a + * (long *). + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data stored in the table that is associated with + * the key. + */ +int table_retrieve(table_t * table_p, + const void *key_buf, const int key_size, + void **data_buf_p, int *data_size_p) +{ + int bucket; + unsigned int ksize; + table_entry_t *entry_p, **buckets; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (key_buf == NULL) + return TABLE_ERROR_ARG_NULL; + /* find key size */ + if (key_size < 0) + ksize = strlen((char *) key_buf) + sizeof(char); + else + ksize = key_size; + /* get the bucket number via a has function */ + bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n; + + /* look for the entry in this bucket, only check keys of the same size */ + buckets = table_p->ta_buckets; + for (entry_p = buckets[bucket]; + entry_p != NULL; + entry_p = entry_p->te_next_p) { + entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p); + if (entry_p->te_key_size == ksize + && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0) + break; + } + + /* not found? */ + if (entry_p == NULL) + return TABLE_ERROR_NOT_FOUND; + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + if (table_p->ta_data_align == 0) + *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); + else + *data_buf_p = entry_data_buf(table_p, entry_p); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + return TABLE_ERROR_NONE; +} + +/* + * int table_delete + * + * DESCRIPTION: + * + * This routine looks up a key made up of a buffer of bytes and an + * associated size in the table. If found then it will be removed + * from the table. The associated data can be passed back to the user + * if requested. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * NOTE: this could be an allocation error if the library is to return + * the data to the user. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we will be deleteing + * the key. + * + * key_buf - Buffer of bytes of the key that we are searching for to + * delete. If you are deleting an (int) key (for example) then + * key_buf should be a (int *). + * + * key_size - Size of the key_buf buffer. If set to < 0 then the + * library will do a strlen of key_buf and add 1 for the '\0'. If you + * are deleting an (int) key (for example) then key_size should be + * sizeof(int). + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that was allocated in the table and that was + * associated with the key. If a (long) was stored as the data (for + * example) then data_buf_p should be (long **) i.e. the address of a + * (long *). If a pointer is passed in, the caller is responsible for + * freeing it after use. If data_buf_p is NULL then the library will + * free up the data allocation itself. + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data that was stored in the table and that was + * associated with the key. + */ +int table_delete(table_t * table_p, + const void *key_buf, const int key_size, + void **data_buf_p, int *data_size_p) +{ + int bucket; + unsigned int ksize; + unsigned char *data_copy_p; + table_entry_t *entry_p, *last_p; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (key_buf == NULL) + return TABLE_ERROR_ARG_NULL; + /* get the key size */ + if (key_size < 0) + ksize = strlen((char *) key_buf) + sizeof(char); + else + ksize = key_size; + /* find our bucket */ + bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n; + + /* look for the entry in this bucket, only check keys of the same size */ + for (last_p = NULL, entry_p = table_p->ta_buckets[bucket]; entry_p != NULL; + last_p = entry_p, entry_p = entry_p->te_next_p) { + if (entry_p->te_key_size == ksize + && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0) + break; + } + + /* did we find it? */ + if (entry_p == NULL) + return TABLE_ERROR_NOT_FOUND; + /* + * NOTE: we may want to adjust the linear counters here if the entry + * we are deleting is the one we are pointing on or is ahead of the + * one in the bucket list + */ + + /* remove entry from the linked list */ + if (last_p == NULL) + table_p->ta_buckets[bucket] = entry_p->te_next_p; + else + last_p->te_next_p = entry_p->te_next_p; + /* free entry */ + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + /* + * if we were storing it compacted, we now need to malloc some + * space if the user wants the value after the delete. + */ + *data_buf_p = table_p->ta_malloc(table_p->opt_param, + entry_p->te_data_size); + if (*data_buf_p == NULL) + return TABLE_ERROR_ALLOC; + if (table_p->ta_data_align == 0) + data_copy_p = ENTRY_DATA_BUF(table_p, entry_p); + else + data_copy_p = entry_data_buf(table_p, entry_p); + memcpy(*data_buf_p, data_copy_p, entry_p->te_data_size); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + table_p->ta_free(table_p->opt_param, entry_p); + entry_p = NULL; + + table_p->ta_entry_n--; + + /* do we need auto-adjust down? */ + if ((table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST) + && (table_p->ta_flags & TABLE_FLAG_ADJUST_DOWN) + && SHOULD_TABLE_SHRINK(table_p)) + return table_adjust(table_p, table_p->ta_entry_n); + return TABLE_ERROR_NONE; +} + +/* + * int table_delete_first + * + * DESCRIPTION: + * + * This is like the table_delete routines except it deletes the first + * key/data pair in the table instead of an entry corresponding to a + * particular key. The associated key and data information can be + * passed back to the user if requested. This routines is handy to + * clear out a table. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * NOTE: this could be an allocation error if the library is to return + * the data to the user. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we will be deleteing + * the first key. + * + * key_buf_p - Pointer which, if not NULL, will be set to the address + * of the storage of the first key that was allocated in the table. + * If an (int) was stored as the first key (for example) then + * key_buf_p should be (int **) i.e. the address of a (int *). If a + * pointer is passed in, the caller is responsible for freeing it + * after use. If key_buf_p is NULL then the library will free up the + * key allocation itself. + * + * key_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the key that was stored in the table and that was + * associated with the key. + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that was allocated in the table and that was + * associated with the key. If a (long) was stored as the data (for + * example) then data_buf_p should be (long **) i.e. the address of a + * (long *). If a pointer is passed in, the caller is responsible for + * freeing it after use. If data_buf_p is NULL then the library will + * free up the data allocation itself. + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data that was stored in the table and that was + * associated with the key. + */ +int table_delete_first(table_t * table_p, + void **key_buf_p, int *key_size_p, + void **data_buf_p, int *data_size_p) +{ + unsigned char *data_copy_p; + table_entry_t *entry_p; + table_linear_t linear; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + /* take the first entry */ + entry_p = first_entry(table_p, &linear); + if (entry_p == NULL) + return TABLE_ERROR_NOT_FOUND; + /* + * NOTE: we may want to adjust the linear counters here if the entry + * we are deleting is the one we are pointing on or is ahead of the + * one in the bucket list + */ + + /* remove entry from the linked list */ + table_p->ta_buckets[linear.tl_bucket_c] = entry_p->te_next_p; + + /* free entry */ + if (key_buf_p != NULL) { + if (entry_p->te_key_size == 0) + *key_buf_p = NULL; + else { + /* + * if we were storing it compacted, we now need to malloc some + * space if the user wants the value after the delete. + */ + *key_buf_p = table_p->ta_malloc(table_p->opt_param, + entry_p->te_key_size); + if (*key_buf_p == NULL) + return TABLE_ERROR_ALLOC; + memcpy(*key_buf_p, ENTRY_KEY_BUF(entry_p), entry_p->te_key_size); + } + } + if (key_size_p != NULL) + *key_size_p = entry_p->te_key_size; + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + /* + * if we were storing it compacted, we now need to malloc some + * space if the user wants the value after the delete. + */ + *data_buf_p = table_p->ta_malloc(table_p->opt_param, + entry_p->te_data_size); + if (*data_buf_p == NULL) + return TABLE_ERROR_ALLOC; + if (table_p->ta_data_align == 0) + data_copy_p = ENTRY_DATA_BUF(table_p, entry_p); + else + data_copy_p = entry_data_buf(table_p, entry_p); + memcpy(*data_buf_p, data_copy_p, entry_p->te_data_size); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + table_p->ta_free(table_p->opt_param, entry_p); + + table_p->ta_entry_n--; + + /* do we need auto-adjust down? */ + if ((table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST) + && (table_p->ta_flags & TABLE_FLAG_ADJUST_DOWN) + && SHOULD_TABLE_SHRINK(table_p)) + return table_adjust(table_p, table_p->ta_entry_n); + return TABLE_ERROR_NONE; +} + +/* + * int table_info + * + * DESCRIPTION: + * + * Get some information about a table_p structure. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we are getting + * information. + * + * num_buckets_p - Pointer to an integer which, if not NULL, will + * contain the number of buckets in the table. + * + * num_entries_p - Pointer to an integer which, if not NULL, will + * contain the number of entries stored in the table. + */ +int table_info(table_t * table_p, int *num_buckets_p, int *num_entries_p) +{ + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (num_buckets_p != NULL) + *num_buckets_p = table_p->ta_bucket_n; + if (num_entries_p != NULL) + *num_entries_p = table_p->ta_entry_n; + return TABLE_ERROR_NONE; +} + +/* + * int table_adjust + * + * DESCRIPTION: + * + * Set the number of buckets in a table to a certain value. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer of which we are adjusting. + * + * bucket_n - Number buckets to adjust the table to. Set to 0 to + * adjust the table to its number of entries. + */ +int table_adjust(table_t * table_p, const int bucket_n) +{ + table_entry_t *entry_p, *next_p; + table_entry_t **buckets, **bucket_p, **bounds_p; + int bucket; + unsigned int buck_n; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + /* + * NOTE: we walk through the entries and rehash them. If we stored + * the hash value as a full int in the table-entry, all we would + * have to do is remod it. + */ + + /* normalize to the number of entries */ + if (bucket_n == 0) + buck_n = table_p->ta_entry_n; + else + buck_n = bucket_n; + /* we must have at least 1 bucket */ + if (buck_n == 0) + buck_n = 1; + /* make sure we have somethign to do */ + if (buck_n <= table_p->ta_bucket_n) + return TABLE_ERROR_NONE; + /* allocate a new bucket list */ + buckets = (table_entry_t **) + table_p->ta_calloc(table_p->opt_param, + buck_n, sizeof(table_entry_t *)); + if (table_p->ta_buckets == NULL) + return TABLE_ERROR_ALLOC; + /* + * run through each of the items in the current table and rehash + * them into the newest bucket sizes + */ + bounds_p = table_p->ta_buckets + table_p->ta_bucket_n; + for (bucket_p = table_p->ta_buckets; bucket_p < bounds_p; bucket_p++) { + for (entry_p = *bucket_p; entry_p != NULL; entry_p = next_p) { + + /* hash the old data into the new table size */ + bucket = hash(ENTRY_KEY_BUF(entry_p), entry_p->te_key_size, 0) % buck_n; + + /* record the next one now since we overwrite next below */ + next_p = entry_p->te_next_p; + + /* insert into new list, no need to append */ + entry_p->te_next_p = buckets[bucket]; + buckets[bucket] = entry_p; + + /* + * NOTE: we may want to adjust the bucket_c linear entry here to + * keep it current + */ + } + /* remove the old table pointers as we go by */ + *bucket_p = NULL; + } + + /* replace the table buckets with the new ones */ + table_p->ta_free(table_p->opt_param, table_p->ta_buckets); + table_p->ta_buckets = buckets; + table_p->ta_bucket_n = buck_n; + + return TABLE_ERROR_NONE; +} + +/* + * const char *table_strerror + * + * DESCRIPTION: + * + * Return the corresponding string for the error number. + * + * RETURNS: + * + * Success - String equivalient of the error. + * + * Failure - String "invalid error code" + * + * ARGUMENTS: + * + * error - Error number that we are converting. + */ +const char *table_strerror(const int error) +{ + error_str_t *err_p; + + for (err_p = errors; err_p->es_error != 0; err_p++) { + if (err_p->es_error == error) + return err_p->es_string; + } + + return INVALID_ERROR; +} + +/* + * int table_type_size + * + * DESCRIPTION: + * + * Return the size of the internal table type. + * + * RETURNS: + * + * The size of the table_t type. + * + * ARGUMENTS: + * + * None. + */ +int table_type_size(void) +{ + return sizeof(table_t); +} + +/************************* linear access routines ****************************/ + +/* + * int table_first + * + * DESCRIPTION: + * + * Find first element in a table and pass back information about the + * key/data pair. If any of the key/data pointers are NULL then they + * are ignored. + * + * NOTE: This function is not reentrant. More than one thread cannot + * be doing a first and next on the same table at the same time. Use + * the table_first_r version below for this. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we are getting the + * first element. + * + * key_buf_p - Pointer which, if not NULL, will be set to the address + * of the storage of the first key that is allocated in the table. If + * an (int) is stored as the first key (for example) then key_buf_p + * should be (int **) i.e. the address of a (int *). + * + * key_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the key that is stored in the table and that is + * associated with the first key. + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that is allocated in the table and that is + * associated with the first key. If a (long) is stored as the data + * (for example) then data_buf_p should be (long **) i.e. the address + * of a (long *). + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data that is stored in the table and that is + * associated with the first key. + */ +int table_first(table_t * table_p, + void **key_buf_p, int *key_size_p, + void **data_buf_p, int *data_size_p) +{ + table_entry_t *entry_p; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + /* initialize our linear magic number */ + table_p->ta_linear.tl_magic = LINEAR_MAGIC; + + entry_p = first_entry(table_p, &table_p->ta_linear); + if (entry_p == NULL) + return TABLE_ERROR_NOT_FOUND; + if (key_buf_p != NULL) + *key_buf_p = ENTRY_KEY_BUF(entry_p); + if (key_size_p != NULL) + *key_size_p = entry_p->te_key_size; + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + if (table_p->ta_data_align == 0) + *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); + else + *data_buf_p = entry_data_buf(table_p, entry_p); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + return TABLE_ERROR_NONE; +} + +/* + * int table_next + * + * DESCRIPTION: + * + * Find the next element in a table and pass back information about + * the key/data pair. If any of the key/data pointers are NULL then + * they are ignored. + * + * NOTE: This function is not reentrant. More than one thread cannot + * be doing a first and next on the same table at the same time. Use + * the table_next_r version below for this. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we are getting the + * next element. + * + * key_buf_p - Pointer which, if not NULL, will be set to the address + * of the storage of the next key that is allocated in the table. If + * an (int) is stored as the next key (for example) then key_buf_p + * should be (int **) i.e. the address of a (int *). + * + * key_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the key that is stored in the table and that is + * associated with the next key. + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that is allocated in the table and that is + * associated with the next key. If a (long) is stored as the data + * (for example) then data_buf_p should be (long **) i.e. the address + * of a (long *). + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data that is stored in the table and that is + * associated with the next key. + */ +int table_next(table_t * table_p, + void **key_buf_p, int *key_size_p, + void **data_buf_p, int *data_size_p) +{ + table_entry_t *entry_p; + int error; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (table_p->ta_linear.tl_magic != LINEAR_MAGIC) + return TABLE_ERROR_LINEAR; + /* move to the next entry */ + entry_p = next_entry(table_p, &table_p->ta_linear, &error); + if (entry_p == NULL) + return error; + if (key_buf_p != NULL) + *key_buf_p = ENTRY_KEY_BUF(entry_p); + if (key_size_p != NULL) + *key_size_p = entry_p->te_key_size; + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + if (table_p->ta_data_align == 0) + *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); + else + *data_buf_p = entry_data_buf(table_p, entry_p); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + return TABLE_ERROR_NONE; +} + +/* + * int table_this + * + * DESCRIPTION: + * + * Find the current element in a table and pass back information about + * the key/data pair. If any of the key/data pointers are NULL then + * they are ignored. + * + * NOTE: This function is not reentrant. Use the table_current_r + * version below. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we are getting the + * current element. + * + * key_buf_p - Pointer which, if not NULL, will be set to the address + * of the storage of the current key that is allocated in the table. + * If an (int) is stored as the current key (for example) then + * key_buf_p should be (int **) i.e. the address of a (int *). + * + * key_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the key that is stored in the table and that is + * associated with the current key. + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that is allocated in the table and that is + * associated with the current key. If a (long) is stored as the data + * (for example) then data_buf_p should be (long **) i.e. the address + * of a (long *). + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data that is stored in the table and that is + * associated with the current key. + */ +int table_this(table_t * table_p, + void **key_buf_p, int *key_size_p, + void **data_buf_p, int *data_size_p) +{ + table_entry_t *entry_p = NULL; + int entry_c; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (table_p->ta_linear.tl_magic != LINEAR_MAGIC) + return TABLE_ERROR_LINEAR; + /* if we removed an item that shorted the bucket list, we may get this */ + if (table_p->ta_linear.tl_bucket_c >= table_p->ta_bucket_n) { + /* + * NOTE: this might happen if we delete an item which shortens the + * table bucket numbers. + */ + return TABLE_ERROR_NOT_FOUND; + } + + /* find the entry which is the nth in the list */ + entry_p = table_p->ta_buckets[table_p->ta_linear.tl_bucket_c]; + /* NOTE: we swap the order here to be more efficient */ + for (entry_c = table_p->ta_linear.tl_entry_c; entry_c > 0; entry_c--) { + /* did we reach the end of the list? */ + if (entry_p == NULL) + break; + entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p)->te_next_p; + } + + /* is this a NOT_FOUND or a LINEAR error */ + if (entry_p == NULL) + return TABLE_ERROR_NOT_FOUND; + if (key_buf_p != NULL) + *key_buf_p = ENTRY_KEY_BUF(entry_p); + if (key_size_p != NULL) + *key_size_p = entry_p->te_key_size; + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + if (table_p->ta_data_align == 0) + *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); + else + *data_buf_p = entry_data_buf(table_p, entry_p); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + return TABLE_ERROR_NONE; +} + +/* + * int table_first_r + * + * DESCRIPTION: + * + * Reetrant version of the table_first routine above. Find first + * element in a table and pass back information about the key/data + * pair. If any of the key/data pointers are NULL then they are + * ignored. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we are getting the + * first element. + * + * linear_p - Pointer to a table linear structure which is initialized + * here. The same pointer should then be passed to table_next_r + * below. + * + * key_buf_p - Pointer which, if not NULL, will be set to the address + * of the storage of the first key that is allocated in the table. If + * an (int) is stored as the first key (for example) then key_buf_p + * should be (int **) i.e. the address of a (int *). + * + * key_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the key that is stored in the table and that is + * associated with the first key. + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that is allocated in the table and that is + * associated with the first key. If a (long) is stored as the data + * (for example) then data_buf_p should be (long **) i.e. the address + * of a (long *). + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data that is stored in the table and that is + * associated with the first key. + */ +int table_first_r(table_t * table_p, table_linear_t * linear_p, + void **key_buf_p, int *key_size_p, + void **data_buf_p, int *data_size_p) +{ + table_entry_t *entry_p; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (linear_p == NULL) + return TABLE_ERROR_ARG_NULL; + /* initialize our linear magic number */ + linear_p->tl_magic = LINEAR_MAGIC; + + entry_p = first_entry(table_p, linear_p); + if (entry_p == NULL) + return TABLE_ERROR_NOT_FOUND; + if (key_buf_p != NULL) + *key_buf_p = ENTRY_KEY_BUF(entry_p); + if (key_size_p != NULL) + *key_size_p = entry_p->te_key_size; + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + if (table_p->ta_data_align == 0) + *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); + else + *data_buf_p = entry_data_buf(table_p, entry_p); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + return TABLE_ERROR_NONE; +} + +/* + * int table_next_r + * + * DESCRIPTION: + * + * Reetrant version of the table_next routine above. Find next + * element in a table and pass back information about the key/data + * pair. If any of the key/data pointers are NULL then they are + * ignored. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we are getting the + * next element. + * + * linear_p - Pointer to a table linear structure which is incremented + * here. The same pointer must have been passed to table_first_r + * first so that it can be initialized. + * + * key_buf_p - Pointer which, if not NULL, will be set to the address + * of the storage of the next key that is allocated in the table. If + * an (int) is stored as the next key (for example) then key_buf_p + * should be (int **) i.e. the address of a (int *). + * + * key_size_p - Pointer to an integer which, if not NULL will be set + * to the size of the key that is stored in the table and that is + * associated with the next key. + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that is allocated in the table and that is + * associated with the next key. If a (long) is stored as the data + * (for example) then data_buf_p should be (long **) i.e. the address + * of a (long *). + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data that is stored in the table and that is + * associated with the next key. + */ +int table_next_r(table_t * table_p, table_linear_t * linear_p, + void **key_buf_p, int *key_size_p, + void **data_buf_p, int *data_size_p) +{ + table_entry_t *entry_p; + int error; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (linear_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (linear_p->tl_magic != LINEAR_MAGIC) + return TABLE_ERROR_LINEAR; + /* move to the next entry */ + entry_p = next_entry(table_p, linear_p, &error); + if (entry_p == NULL) + return error; + if (key_buf_p != NULL) + *key_buf_p = ENTRY_KEY_BUF(entry_p); + if (key_size_p != NULL) + *key_size_p = entry_p->te_key_size; + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + if (table_p->ta_data_align == 0) + *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); + else + *data_buf_p = entry_data_buf(table_p, entry_p); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + return TABLE_ERROR_NONE; +} + +/* + * int table_this_r + * + * DESCRIPTION: + * + * Reetrant version of the table_this routine above. Find current + * element in a table and pass back information about the key/data + * pair. If any of the key/data pointers are NULL then they are + * ignored. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we are getting the + * current element. + * + * linear_p - Pointer to a table linear structure which is accessed + * here. The same pointer must have been passed to table_first_r + * first so that it can be initialized. + * + * key_buf_p - Pointer which, if not NULL, will be set to the address + * of the storage of the current key that is allocated in the table. + * If an (int) is stored as the current key (for example) then + * key_buf_p should be (int **) i.e. the address of a (int *). + * + * key_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the key that is stored in the table and that is + * associated with the current key. + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage that is allocated in the table and that is + * associated with the current key. If a (long) is stored as the data + * (for example) then data_buf_p should be (long **) i.e. the address + * of a (long *). + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data that is stored in the table and that is + * associated with the current key. + */ +int table_this_r(table_t * table_p, table_linear_t * linear_p, + void **key_buf_p, int *key_size_p, + void **data_buf_p, int *data_size_p) +{ + table_entry_t *entry_p; + int entry_c; + + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (linear_p->tl_magic != LINEAR_MAGIC) + return TABLE_ERROR_LINEAR; + /* if we removed an item that shorted the bucket list, we may get this */ + if (linear_p->tl_bucket_c >= table_p->ta_bucket_n) { + /* + * NOTE: this might happen if we delete an item which shortens the + * table bucket numbers. + */ + return TABLE_ERROR_NOT_FOUND; + } + + /* find the entry which is the nth in the list */ + for (entry_c = linear_p->tl_entry_c, + entry_p = table_p->ta_buckets[linear_p->tl_bucket_c]; + entry_p != NULL && entry_c > 0; + entry_c--, entry_p = TABLE_POINTER(table_p, table_entry_t *, + entry_p)->te_next_p) { + } + + if (entry_p == NULL) + return TABLE_ERROR_NOT_FOUND; + if (key_buf_p != NULL) + *key_buf_p = ENTRY_KEY_BUF(entry_p); + if (key_size_p != NULL) + *key_size_p = entry_p->te_key_size; + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + if (table_p->ta_data_align == 0) + *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); + else + *data_buf_p = entry_data_buf(table_p, entry_p); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + return TABLE_ERROR_NONE; +} + +/******************************** table order ********************************/ + +/* + * table_entry_t *table_order + * + * DESCRIPTION: + * + * Order a table by building an array of table entry pointers and then + * sorting this array using the qsort function. To retrieve the + * sorted entries, you can then use the table_entry routine to access + * each entry in order. + * + * NOTE: This routine is now thread safe in that two table_order calls + * can now happen at the same time, even on the same table. + * + * RETURNS: + * + * An allocated list of entry pointers which must be freed later. + * Returns null on error. + * + * ARGUMENTS: + * + * table_p - Pointer to the table that we are ordering. + * + * compare - Comparison function defined by the user. Its definition + * is at the top of the table.h file. If this is NULL then it will + * order the table my memcmp-ing the keys. + * + * num_entries_p - Pointer to an integer which, if not NULL, will + * contain the number of entries in the returned entry pointer array. + * + * error_p - Pointer to an integer which, if not NULL, will contain a + * table error code. + */ +table_entry_t **table_order(table_t * table_p, table_compare_t compare, + int *num_entries_p, int *error_p) +{ + table_entry_t *entry_p, **entries, **entries_p; + table_linear_t linear; + compare_t comp_func; + int error; + + if (table_p == NULL) { + if (error_p != NULL) + *error_p = TABLE_ERROR_ARG_NULL; + return NULL; + } + if (table_p->ta_magic != TABLE_MAGIC) { + if (error_p != NULL) + *error_p = TABLE_ERROR_PNT; + return NULL; + } + + /* there must be at least 1 element in the table for this to work */ + if (table_p->ta_entry_n == 0) { + if (error_p != NULL) + *error_p = TABLE_ERROR_EMPTY; + return NULL; + } + + entries = (table_entry_t **) + table_p->ta_malloc(table_p->opt_param, + table_p->ta_entry_n *sizeof(table_entry_t *)); + if (entries == NULL) { + if (error_p != NULL) + *error_p = TABLE_ERROR_ALLOC; + return NULL; + } + + /* get a pointer to all entries */ + entry_p = first_entry(table_p, &linear); + if (entry_p == NULL) { + if (error_p != NULL) + *error_p = TABLE_ERROR_NOT_FOUND; + return NULL; + } + + /* add all of the entries to the array */ + for (entries_p = entries; + entry_p != NULL; + entry_p = next_entry(table_p, &linear, &error)) + *entries_p++ = entry_p; + if (error != TABLE_ERROR_NOT_FOUND) { + if (error_p != NULL) + *error_p = error; + return NULL; + } + + if (compare == NULL) { + /* this is regardless of the alignment */ + comp_func = local_compare; + } + else if (table_p->ta_data_align == 0) + comp_func = external_compare; + else + comp_func = external_compare_align; + /* now qsort the entire entries array from first to last element */ + split(entries, entries + table_p->ta_entry_n - 1, comp_func, compare, + table_p); + + if (num_entries_p != NULL) + *num_entries_p = table_p->ta_entry_n; + if (error_p != NULL) + *error_p = TABLE_ERROR_NONE; + return entries; +} + +/* + * int table_entry + * + * DESCRIPTION: + * + * Get information about an element. The element is one from the + * array returned by the table_order function. If any of the key/data + * pointers are NULL then they are ignored. + * + * RETURNS: + * + * Success - TABLE_ERROR_NONE + * + * Failure - Table error code. + * + * ARGUMENTS: + * + * table_p - Table structure pointer from which we are getting the + * element. + * + * entry_p - Pointer to a table entry from the array returned by the + * table_order function. + * + * key_buf_p - Pointer which, if not NULL, will be set to the address + * of the storage of this entry that is allocated in the table. If an + * (int) is stored as this entry (for example) then key_buf_p should + * be (int **) i.e. the address of a (int *). + * + * key_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the key that is stored in the table. + * + * data_buf_p - Pointer which, if not NULL, will be set to the address + * of the data storage of this entry that is allocated in the table. + * If a (long) is stored as this entry data (for example) then + * data_buf_p should be (long **) i.e. the address of a (long *). + * + * data_size_p - Pointer to an integer which, if not NULL, will be set + * to the size of the data that is stored in the table. + */ +int table_entry_info(table_t * table_p, table_entry_t * entry_p, + void **key_buf_p, int *key_size_p, + void **data_buf_p, int *data_size_p) +{ + if (table_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (table_p->ta_magic != TABLE_MAGIC) + return TABLE_ERROR_PNT; + if (entry_p == NULL) + return TABLE_ERROR_ARG_NULL; + if (key_buf_p != NULL) + *key_buf_p = ENTRY_KEY_BUF(entry_p); + if (key_size_p != NULL) + *key_size_p = entry_p->te_key_size; + if (data_buf_p != NULL) { + if (entry_p->te_data_size == 0) + *data_buf_p = NULL; + else { + if (table_p->ta_data_align == 0) + *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); + else + *data_buf_p = entry_data_buf(table_p, entry_p); + } + } + if (data_size_p != NULL) + *data_size_p = entry_p->te_data_size; + return TABLE_ERROR_NONE; +} + diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_table.h b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_table.h new file mode 100644 index 00000000..33438b2f --- /dev/null +++ b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_util_table.h @@ -0,0 +1,152 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_util_table.h + * High Performance Hash Table Header + */ + +/* + * Generic hash table defines + * Table 4.1.0 July-28-1998 + * + * This library is a generic open hash table with buckets and + * linked lists. It is pretty high performance. Each element + * has a key and a data. The user indexes on the key to find the + * data. + * + * Copyright 1998 by Gray Watson <gray@letters.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose and without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, + * and that the name of Gray Watson not be used in advertising or + * publicity pertaining to distribution of the document or software + * without specific, written prior permission. + * + * Gray Watson makes no representations about the suitability of the + * software described herein for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifndef __SSL_UTIL_TABLE_H__ +#define __SSL_UTIL_TABLE_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * To build a "key" in any of the below routines, pass in a pointer to + * the key and its size [i.e. sizeof(int), etc]. With any of the + * "key" or "data" arguments, if their size is < 0, it will do an + * internal strlen of the item and add 1 for the \0. + * + * If you are using firstkey() and nextkey() functions, be careful if, + * after starting your firstkey loop, you use delete or insert, it + * will not crash but may produce interesting results. If you are + * deleting from firstkey to NULL it will work fine. + */ + +/* return types for table functions */ +#define TABLE_ERROR_NONE 1 /* no error from function */ +#define TABLE_ERROR_PNT 2 /* bad table pointer */ +#define TABLE_ERROR_ARG_NULL 3 /* buffer args were null */ +#define TABLE_ERROR_SIZE 4 /* size of data was bad */ +#define TABLE_ERROR_OVERWRITE 5 /* key exists and we cant overwrite */ +#define TABLE_ERROR_NOT_FOUND 6 /* key does not exist */ +#define TABLE_ERROR_ALLOC 7 /* memory allocation error */ +#define TABLE_ERROR_LINEAR 8 /* no linear access started */ +#define TABLE_ERROR_OPEN 9 /* could not open file */ +#define TABLE_ERROR_SEEK 10 /* could not seek to pos in file */ +#define TABLE_ERROR_READ 11 /* could not read from file */ +#define TABLE_ERROR_WRITE 12 /* could not write to file */ +#define TABLE_ERROR_EMPTY 13 /* table is empty */ +#define TABLE_ERROR_NOT_EMPTY 14 /* table contains data */ +#define TABLE_ERROR_ALIGNMENT 15 /* invalid alignment value */ + +/* + * Table flags set with table_attr. + */ + +/* + * Automatically adjust the number of table buckets on the fly. + * Whenever the number of entries gets above some threshold, the + * number of buckets is realloced to a new size and each entry is + * re-hashed. Although this may take some time when it re-hashes, the + * table will perform better over time. + */ +#define TABLE_FLAG_AUTO_ADJUST (1<<0) + +/* + * If the above auto-adjust flag is set, also adjust the number of + * table buckets down as we delete entries. + */ +#define TABLE_FLAG_ADJUST_DOWN (1<<1) + +/* structure to walk through the fields in a linear order */ +typedef struct { + unsigned int tl_magic; /* magic structure to ensure correct init */ + unsigned int tl_bucket_c; /* where in the table buck array we are */ + unsigned int tl_entry_c; /* in the bucket, which entry we are on */ +} table_linear_t; + +typedef int (*table_compare_t)(const void *key1, const int key1_size, + const void *data1, const int data1_size, + const void *key2, const int key2_size, + const void *data2, const int data2_size); + +#ifndef TABLE_PRIVATE +typedef void table_t; +typedef void table_entry_t; +#endif + +/* + * Prototypes + */ +extern table_t *table_alloc(const unsigned int bucket_n, int *error_p, void *(*malloc_f)(void *opt_param, size_t size), void *(*calloc_f)(void *opt_param, size_t number, size_t size), void *(*realloc_f)(void *opt_param, void *ptr, size_t size), void (*free_f)(void *opt_param, void *ptr), void *opt_param); +extern int table_attr(table_t *table_p, const int attr); +extern int table_set_data_alignment(table_t *table_p, const int alignment); +extern int table_clear(table_t *table_p); +extern int table_free(table_t *table_p); +extern int table_insert_kd(table_t *table_p, const void *key_buf, const int key_size, const void *data_buf, const int data_size, void **key_buf_p, void **data_buf_p, const char overwrite_b); +extern int table_insert(table_t *table_p, const void *key_buf, const int key_size, const void *data_buf, const int data_size, void **data_buf_p, const char overwrite_b); +extern int table_retrieve(table_t *table_p, const void *key_buf, const int key_size, void **data_buf_p, int *data_size_p); +extern int table_delete(table_t *table_p, const void *key_buf, const int key_size, void **data_buf_p, int *data_size_p); +extern int table_delete_first(table_t *table_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); +extern int table_info(table_t *table_p, int *num_buckets_p, int *num_entries_p); +extern int table_adjust(table_t *table_p, const int bucket_n); +extern const char *table_strerror(const int error); +extern int table_type_size(void); +extern int table_first(table_t *table_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); +extern int table_next(table_t *table_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); +extern int table_this(table_t *table_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); +extern int table_first_r(table_t *table_p, table_linear_t *linear_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); +extern int table_next_r(table_t *table_p, table_linear_t *linear_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); +extern int table_this_r(table_t *table_p, table_linear_t *linear_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); +extern table_entry_t **table_order(table_t *table_p, table_compare_t compare, int *num_entries_p, int *error_p); +extern int table_entry_info(table_t *table_p, table_entry_t *entry_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SSL_UTIL_TABLE_H__ */ |