summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalf S. Engelschall <rse@apache.org>2001-05-04 21:54:25 +0000
committerRalf S. Engelschall <rse@apache.org>2001-05-04 21:54:25 +0000
commitf83672781de25207442ff908258219de1d103062 (patch)
treeba5717fc9753ff787e05f28007101951087c86eb
parent498c91aa40551ed31ae68b9f0655f0b3ce4a41de (diff)
downloadhttpd-f83672781de25207442ff908258219de1d103062.tar.gz
Initial revision
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88988 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--modules/ssl/Makefile.libdir15
-rw-r--r--modules/ssl/Makefile.tmpl529
-rw-r--r--modules/ssl/Makefile.win32133
-rw-r--r--modules/ssl/README163
-rw-r--r--modules/ssl/README.dsov.fig346
-rw-r--r--modules/ssl/README.dsov.ps1138
-rw-r--r--modules/ssl/libssl.module497
-rw-r--r--modules/ssl/libssl.version1
-rw-r--r--modules/ssl/mod_ssl.c248
-rw-r--r--modules/ssl/mod_ssl.h854
-rw-r--r--modules/ssl/ssl_engine_compat.c511
-rw-r--r--modules/ssl/ssl_engine_config.c1093
-rw-r--r--modules/ssl/ssl_engine_dh.c255
-rw-r--r--modules/ssl/ssl_engine_ds.c195
-rw-r--r--modules/ssl/ssl_engine_ext.c808
-rw-r--r--modules/ssl/ssl_engine_init.c1090
-rw-r--r--modules/ssl/ssl_engine_io.c728
-rw-r--r--modules/ssl/ssl_engine_kernel.c1905
-rw-r--r--modules/ssl/ssl_engine_log.c326
-rw-r--r--modules/ssl/ssl_engine_mutex.c397
-rw-r--r--modules/ssl/ssl_engine_pphrase.c545
-rw-r--r--modules/ssl/ssl_engine_rand.c215
-rw-r--r--modules/ssl/ssl_engine_vars.c615
-rw-r--r--modules/ssl/ssl_expr.c119
-rw-r--r--modules/ssl/ssl_expr.h139
-rw-r--r--modules/ssl/ssl_expr_eval.c282
-rw-r--r--modules/ssl/ssl_expr_parse.c605
-rw-r--r--modules/ssl/ssl_expr_parse.h29
-rw-r--r--modules/ssl/ssl_expr_parse.y186
-rw-r--r--modules/ssl/ssl_expr_scan.c2002
-rw-r--r--modules/ssl/ssl_expr_scan.l261
-rw-r--r--modules/ssl/ssl_scache.c204
-rw-r--r--modules/ssl/ssl_scache_dbm.c440
-rw-r--r--modules/ssl/ssl_scache_shmcb.c1343
-rw-r--r--modules/ssl/ssl_scache_shmht.c347
-rw-r--r--modules/ssl/ssl_util.c437
-rw-r--r--modules/ssl/ssl_util_sdbm.c926
-rw-r--r--modules/ssl/ssl_util_sdbm.h191
-rw-r--r--modules/ssl/ssl_util_ssl.c544
-rw-r--r--modules/ssl/ssl_util_ssl.h115
-rw-r--r--modules/ssl/ssl_util_table.c2868
-rw-r--r--modules/ssl/ssl_util_table.h189
42 files changed, 23834 insertions, 0 deletions
diff --git a/modules/ssl/Makefile.libdir b/modules/ssl/Makefile.libdir
new file mode 100644
index 0000000000..a4a4c32080
--- /dev/null
+++ b/modules/ssl/Makefile.libdir
@@ -0,0 +1,15 @@
+## _ _
+## _ __ ___ ___ __| | ___ ___| | mod_ssl
+## | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+## | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+## |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+## |_____|
+## Makefile.libdir
+## Apache 1.3 Configuration mechanism indicator file
+##
+
+This is a place-holder which indicates to Apache's Configure script that it
+shouldn't provide the default targets when building the Makefile in this
+directory. Instead it'll just prepend all the important variable definitions,
+and copy the Makefile.tmpl onto the end.
+
diff --git a/modules/ssl/Makefile.tmpl b/modules/ssl/Makefile.tmpl
new file mode 100644
index 0000000000..38162731d7
--- /dev/null
+++ b/modules/ssl/Makefile.tmpl
@@ -0,0 +1,529 @@
+## _ _
+## _ __ ___ ___ __| | ___ ___| | mod_ssl
+## | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+## | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+## |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+## |_____|
+## Makefile.tmpl
+## Apache 1.3 Makefile template for SSL module (Unix environment)
+##
+
+## ====================================================================
+## Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+##
+## 1. Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+##
+## 2. Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following
+## disclaimer in the documentation and/or other materials
+## provided with the distribution.
+##
+## 3. All advertising materials mentioning features or use of this
+## software must display the following acknowledgment:
+## "This product includes software developed by
+## Ralf S. Engelschall <rse@engelschall.com> for use in the
+## mod_ssl project (http://www.modssl.org/)."
+##
+## 4. The names "mod_ssl" must not be used to endorse or promote
+## products derived from this software without prior written
+## permission. For written permission, please contact
+## rse@engelschall.com.
+##
+## 5. Products derived from this software may not be called "mod_ssl"
+## nor may "mod_ssl" appear in their names without prior
+## written permission of Ralf S. Engelschall.
+##
+## 6. Redistributions of any form whatsoever must retain the following
+## acknowledgment:
+## "This product includes software developed by
+## Ralf S. Engelschall <rse@engelschall.com> for use in the
+## mod_ssl project (http://www.modssl.org/)."
+##
+## THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+## EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+## HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+## NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+## OF THE POSSIBILITY OF SUCH DAMAGE.
+## ====================================================================
+##
+ #
+ # ``I cannot write a program which is
+ # as popular as one from Larry Wall.
+ # But I can write one which is from me.''
+ # -- RSE
+
+LIB=libssl.$(LIBEXT)
+
+OBJS=\
+ mod_ssl.o\
+ ssl_engine_config.o\
+ ssl_engine_compat.o\
+ ssl_engine_ds.o\
+ ssl_engine_dh.o\
+ ssl_engine_init.o\
+ ssl_engine_kernel.o\
+ ssl_engine_rand.o\
+ ssl_engine_io.o\
+ ssl_engine_log.o\
+ ssl_engine_mutex.o\
+ ssl_engine_pphrase.o\
+ ssl_engine_vars.o\
+ ssl_engine_ext.o\
+ ssl_scache.o\
+ ssl_scache_dbm.o\
+ ssl_scache_shmht.o\
+ ssl_scache_shmcb.o\
+ ssl_expr.o\
+ ssl_expr_scan.o\
+ ssl_expr_parse.o\
+ ssl_expr_eval.o\
+ ssl_util.o\
+ ssl_util_ssl.o\
+ ssl_util_sdbm.o\
+ ssl_util_table.o\
+ $(SSL_VENDOR_OBJS)
+
+OBJS_PIC=\
+ mod_ssl.lo\
+ ssl_engine_config.lo\
+ ssl_engine_compat.lo\
+ ssl_engine_ds.lo\
+ ssl_engine_dh.lo\
+ ssl_engine_init.lo\
+ ssl_engine_kernel.lo\
+ ssl_engine_rand.lo\
+ ssl_engine_io.lo\
+ ssl_engine_log.lo\
+ ssl_engine_mutex.lo\
+ ssl_engine_pphrase.lo\
+ ssl_engine_vars.lo\
+ ssl_engine_ext.lo\
+ ssl_scache.lo\
+ ssl_scache_dbm.lo\
+ ssl_scache_shmht.lo\
+ ssl_scache_shmcb.lo\
+ ssl_expr.lo\
+ ssl_expr_scan.lo\
+ ssl_expr_parse.lo\
+ ssl_expr_eval.lo\
+ ssl_util.lo\
+ ssl_util_ssl.lo\
+ ssl_util_sdbm.lo\
+ ssl_util_table.lo\
+ $(SSL_VENDOR_OBJS_PIC)
+
+##
+## END-USER AREA
+##
+
+all: lib
+
+lib: $(LIB)
+
+libssl.a: $(OBJS)
+ rm -f $@
+ ar cr $@ $(OBJS)
+ $(RANLIB) $@
+
+libssl.so: $(OBJS_PIC)
+ rm -f $@
+ $(LD_SHLIB) $(SSL_LDFLAGS) $(LDFLAGS_SHLIB) -o $@ $(OBJS_PIC) $(SSL_LIBS) $(LIBS_SHLIB)
+
+.SUFFIXES: .o .lo
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(SSL_CFLAGS) $(SSL_VERSION) $<
+
+.c.lo:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(CFLAGS_SHLIB) $(SSL_CFLAGS) $(SSL_VERSION) $< && mv $*.o $*.lo
+
+clean:
+ rm -f $(OBJS) $(OBJS_PIC)
+ rm -f libssl.a libssl.so
+
+realclean: clean
+ rm -f ssl_expr_parse.c ssl_expr_parse.h
+ rm -f ssl_expr_scan.c
+
+distclean: clean
+ -rm -f Makefile
+
+##
+## DEVELOPER AREA
+## We really don't expect end users to use these targets!
+##
+
+ssl_expr_scan.c: ssl_expr_scan.l ssl_expr_parse.h
+ flex -Pssl_expr_yy -s -B 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: ssl_expr_parse.y
+ yacc -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 && 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
+
+nocons:
+ @$(MAKE) $(MFLAGS) $(MFLAGS_STATIC) \
+ SSL_CFLAGS="`echo $(SSL_CFLAGS) |\
+ sed -e 's;-DSSL_CONSERVATIVE;;'`" all
+
+cons:
+ @$(MAKE) $(MFLAGS) $(MFLAGS_STATIC) \
+ SSL_CFLAGS="`echo $(SSL_CFLAGS) |\
+ sed -e 's;-DSSL_CONSERVATIVE;;' \
+ -e 's;^;-DSSL_CONSERVATIVE ;'`" all
+noexp:
+ @$(MAKE) $(MFLAGS) $(MFLAGS_STATIC) \
+ SSL_CFLAGS="`echo $(SSL_CFLAGS) |\
+ sed -e 's;-DSSL_EXPERIMENTAL;;'`" all
+
+exp:
+ @$(MAKE) $(MFLAGS) $(MFLAGS_STATIC) \
+ SSL_CFLAGS="`echo $(SSL_CFLAGS) |\
+ sed -e 's;-DSSL_EXPERIMENTAL;;' \
+ -e 's;^;-DSSL_EXPERIMENTAL ;'`" all
+
+depend:
+ cp Makefile.tmpl Makefile.tmpl.bak \
+ && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.tmpl > Makefile.new \
+ && gcc -MM $(INCLUDES) $(CFLAGS) $(SSL_CFLAGS) *.c >> Makefile.new \
+ && sed -e '1,$$s; $(INCDIR)/; $$(INCDIR)/;g' \
+ -e '1,$$s; $(OSDIR)/; $$(OSDIR)/;g' \
+ -e '1,$$s;^\([a-z0-9_]*\)\.o:;\1.o \1.lo:;g' Makefile.new \
+ > Makefile.tmpl \
+ && rm Makefile.new
+
+##
+## DEPENDENCY AREA
+##
+
+$(OBJS) $(OBJS_PIC): Makefile
+
+# DO NOT REMOVE
+mod_ssl.o mod_ssl.lo: mod_ssl.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_compat.o ssl_engine_compat.lo: ssl_engine_compat.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_config.o ssl_engine_config.lo: ssl_engine_config.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_dh.o ssl_engine_dh.lo: ssl_engine_dh.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_ds.o ssl_engine_ds.lo: ssl_engine_ds.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_ext.o ssl_engine_ext.lo: ssl_engine_ext.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_init.o ssl_engine_init.lo: ssl_engine_init.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_io.o ssl_engine_io.lo: ssl_engine_io.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_kernel.o ssl_engine_kernel.lo: ssl_engine_kernel.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_log.o ssl_engine_log.lo: ssl_engine_log.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_mutex.o ssl_engine_mutex.lo: ssl_engine_mutex.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_pphrase.o ssl_engine_pphrase.lo: ssl_engine_pphrase.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_rand.o ssl_engine_rand.lo: ssl_engine_rand.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_engine_vars.o ssl_engine_vars.lo: ssl_engine_vars.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_expr.o ssl_expr.lo: ssl_expr.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_expr_eval.o ssl_expr_eval.lo: ssl_expr_eval.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_expr_parse.o ssl_expr_parse.lo: ssl_expr_parse.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_expr_scan.o ssl_expr_scan.lo: ssl_expr_scan.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h \
+ ssl_expr_parse.h
+ssl_scache.o ssl_scache.lo: ssl_scache.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_scache_dbm.o ssl_scache_dbm.lo: ssl_scache_dbm.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_scache_shmcb.o ssl_scache_shmcb.lo: ssl_scache_shmcb.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_scache_shmht.o ssl_scache_shmht.lo: ssl_scache_shmht.c mod_ssl.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_util.o ssl_util.lo: ssl_util.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_util_sdbm.o ssl_util_sdbm.lo: ssl_util_sdbm.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_util_ssl.o ssl_util_ssl.lo: ssl_util_ssl.c mod_ssl.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/httpd.h $(INCDIR)/ap_mm.h $(INCDIR)/ap_alloc.h \
+ $(INCDIR)/ap_hook.h $(INCDIR)/ap_ctx.h $(INCDIR)/buff.h \
+ $(INCDIR)/ap.h $(INCDIR)/util_uri.h \
+ $(INCDIR)/http_config.h $(INCDIR)/http_conf_globals.h \
+ $(INCDIR)/http_protocol.h $(INCDIR)/http_request.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_core.h \
+ $(INCDIR)/http_log.h $(INCDIR)/scoreboard.h \
+ $(INCDIR)/util_md5.h $(INCDIR)/ap_md5.h \
+ $(INCDIR)/fnmatch.h ssl_expr.h ssl_util_ssl.h ssl_util_table.h
+ssl_util_table.o ssl_util_table.lo: ssl_util_table.c ssl_util_table.h
diff --git a/modules/ssl/Makefile.win32 b/modules/ssl/Makefile.win32
new file mode 100644
index 0000000000..92781c182f
--- /dev/null
+++ b/modules/ssl/Makefile.win32
@@ -0,0 +1,133 @@
+## _ _
+## _ __ ___ ___ __| | ___ ___| | mod_ssl
+## | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+## | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+## |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+## |_____|
+## Makefile.win32
+## Apache 1.3 Makefile for SSL module (Win32 environment)
+##
+
+##
+## ====================================================================
+## Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+##
+## 1. Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+##
+## 2. Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following
+## disclaimer in the documentation and/or other materials
+## provided with the distribution.
+##
+## 3. All advertising materials mentioning features or use of this
+## software must display the following acknowledgment:
+## "This product includes software developed by
+## Ralf S. Engelschall <rse@engelschall.com> for use in the
+## mod_ssl project (http://www.modssl.org/)."
+##
+## 4. The names "mod_ssl" must not be used to endorse or promote
+## products derived from this software without prior written
+## permission. For written permission, please contact
+## rse@engelschall.com.
+##
+## 5. Products derived from this software may not be called "mod_ssl"
+## nor may "mod_ssl" appear in their names without prior
+## written permission of Ralf S. Engelschall.
+##
+## 6. Redistributions of any form whatsoever must retain the following
+## acknowledgment:
+## "This product includes software developed by
+## Ralf S. Engelschall <rse@engelschall.com> for use in the
+## mod_ssl project (http://www.modssl.org/)."
+##
+## THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+## EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+## HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+## NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+## OF THE POSSIBILITY OF SUCH DAMAGE.
+## ====================================================================
+##
+
+# the following variables are automatically
+# adjusted by the configure.bat script.
+SSL_INC = p:\ssl\work\win32\openssl\include
+SSL_LIB = p:\ssl\work\win32\openssl\lib
+MOD_SSL_VERS_NUM = 000000
+MOD_SSL_VERS_STR = 0.0.0
+
+# build tools and flags
+CC = cl.exe
+CFLAGS = /nologo /c /O2 /MD /W3 /GX /DNDEBUG /DWIN32 /D_WINDOWS /DSHARED_MODULE /DEAPI
+CFLAGS = $(CFLAGS) /DMOD_SSL=$(MOD_SSL_VERS_NUM) /DMOD_SSL_VERSION=\"$(MOD_SSL_VERS_STR)\"
+CFLAGS = $(CFLAGS) /I..\..\include /I..\..\os\win32 /I$(SSL_INC)
+LD = link.exe
+LDFLAGS = /nologo
+RM = del
+
+# name and extension of generated mod_ssl library file
+LIBNAME = mod_ssl
+LIBEXT = so
+LIBFILE = $(LIBNAME).$(LIBEXT)
+
+# mod_ssl object files
+OBJS=\
+ mod_ssl.obj\
+ ssl_engine_config.obj\
+ ssl_engine_compat.obj\
+ ssl_engine_ds.obj\
+ ssl_engine_dh.obj\
+ ssl_engine_init.obj\
+ ssl_engine_kernel.obj\
+ ssl_engine_rand.obj\
+ ssl_engine_io.obj\
+ ssl_engine_log.obj\
+ ssl_engine_mutex.obj\
+ ssl_engine_pphrase.obj\
+ ssl_engine_vars.obj\
+ ssl_engine_ext.obj\
+ ssl_scache.obj\
+ ssl_scache_dbm.obj\
+ ssl_scache_shmcb.obj\
+ ssl_scache_shmht.obj\
+ ssl_expr.obj\
+ ssl_expr_scan.obj\
+ ssl_expr_parse.obj\
+ ssl_expr_eval.obj\
+ ssl_util.obj\
+ ssl_util_ssl.obj\
+ ssl_util_sdbm.obj\
+ ssl_util_table.obj
+
+.c.obj:
+ $(CC) $(CFLAGS) $<
+
+all: $(LIBFILE)
+
+$(LIBNAME).lib: $(OBJS)
+ $(LD) $(LDFLAGS) /lib /out:$@ \
+ $(OBJS)
+
+$(LIBNAME).so: $(OBJS)
+ $(LD) $(LDFLAGS) /dll /out:$@ \
+ $(OBJS) \
+ ..\..\Release\ApacheCore.lib \
+ $(SSL_LIB)\ssleay32.lib \
+ $(SSL_LIB)\libeay32.lib \
+ wsock32.lib gdi32.lib
+
+clean:
+ -$(RM) $(LIBFILE)
+ -$(RM) $(OBJS)
+
diff --git a/modules/ssl/README b/modules/ssl/README
new file mode 100644
index 0000000000..ca9e225bf8
--- /dev/null
+++ b/modules/ssl/README
@@ -0,0 +1,163 @@
+ _ _
+ _ __ ___ ___ __| | ___ ___| |
+ | '_ ` _ \ / _ \ / _` | / __/ __| |
+ | | | | | | (_) | (_| | \__ \__ \ | ``mod_ssl combines the flexibility of
+ |_| |_| |_|\___/ \__,_|___|___/___/_| Apache with the security of OpenSSL.''
+ |_____|
+ mod_ssl ``Ralf Engelschall has released an
+ Apache Interface to OpenSSL excellent module that integrates
+ http://www.modssl.org/ Apache and SSLeay.''
+ Version 2.8 -- Tim J. Hudson
+
+ SYNOPSIS
+
+ This Apache module provides strong cryptography for the Apache 1.3 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.
+
+ SOURCES
+
+ Here is a short overview of the source files:
+
+ Makefile.libdir ......... dummy for Apache config mechanism
+ Makefile.tmpl ........... Makefile template for Unix platform
+ Makefile.win32 .......... Makefile template for Win32 platform
+ libssl.module ........... stub called from the Apache config mechanism
+ libssl.version .......... file containing the mod_ssl version information
+ mod_ssl.c ............... main source file containing API structures
+ mod_ssl.h ............... common header file of mod_ssl
+ ssl_engine_compat.c ..... backward compatibility support
+ ssl_engine_config.c ..... module configuration handling
+ ssl_engine_dh.c ......... DSA/DH support
+ ssl_engine_ds.c ......... data structures
+ ssl_engine_ext.c ........ Extensions to other Apache parts
+ ssl_engine_init.c ....... module initialization
+ ssl_engine_io.c ......... I/O support
+ ssl_engine_kernel.c ..... SSL engine kernel
+ ssl_engine_log.c ........ logfile support
+ ssl_engine_mutex.c ...... mutual exclusion support
+ ssl_engine_pphrase.c .... pass-phrase handling
+ ssl_engine_rand.c ....... PRNG support
+ ssl_engine_vars.c ....... Variable Expansion support
+ ssl_expr.c .............. expression handling main source
+ ssl_expr.h .............. expression handling common header
+ ssl_expr_scan.c ......... expression scanner automaton (pre-generated)
+ ssl_expr_scan.l ......... expression scanner source
+ ssl_expr_parse.c ........ expression parser automaton (pre-generated)
+ ssl_expr_parse.h ........ expression parser header (pre-generated)
+ ssl_expr_parse.y ........ expression parser source
+ ssl_expr_eval.c ......... expression machine evaluation
+ ssl_scache.c ............ session cache abstraction layer
+ ssl_scache_dbm.c ........ session cache via DBM file
+ ssl_scache_shmcb.c ...... session cache via shared memory cyclic buffer
+ ssl_scache_shmht.c ...... session cache via shared memory hash table
+ ssl_util.c .............. utility functions
+ ssl_util_ssl.c .......... the OpenSSL companion source
+ ssl_util_ssl.h .......... the OpenSSL companion header
+ ssl_util_sdbm.c ......... the SDBM library source
+ ssl_util_sdbm.h ......... the SDBM library header
+ ssl_util_table.c ........ the hash table library source
+ ssl_util_table.h ........ the hash table library header
+
+ 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:
+
+ ap_ctx .................. Apache EAPI Context
+ server_rec .............. Apache (Virtual) Server
+ conn_rec ................ Apache Connection
+ BUFF .................... Apache Connection Buffer
+ request_rec ............. Apache Request
+ SSLModConfig ............ mod_ssl (Global) Module Configuration
+ SSLSrvConfig ............ mod_ssl (Virtual) Server Configuration
+ SSLDirConfig ............ mod_ssl Directory Configuration
+ 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_PERDIRCA
+ The ability to use SSLCACertificateFile and SSLCACertificatePath
+ in a per-directory context (.htaccess). This is provided by some nasty
+ reconfiguration hacks until OpenSSL has better support for this. It
+ should work on non-multithreaded platforms (all but Win32).
+
+ o SSL_EXPERIMENTAL_PROXY
+ The ability to use various additional SSLProxyXXX directives in
+ oder to control extended client functionality in the HTTPS proxy
+ code.
+
+ 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.
+
+ VENDOR EXTENSIONS
+
+ Inside the mod_ssl sources you can enable various EAPI vendor hooks
+ (`ap::mod_ssl::vendor::xxxx') by using the APACI --enable-rule=SSL_VENDOR
+ option. These hooks can be used to change or extend mod_ssl by a vendor
+ without patching the source code. Grep for `ap::mod_ssl::vendor::'.
+ Additionally vendors can add their own source code to files named
+ ssl_vendor.c, ssl_vendor_XXX.c, etc. The libssl.module script automatically
+ picks these up under configuration time and mod_ssl under run-time calls the
+ functions `void ssl_vendor_register(void)' and `void
+ ssl_vendor_unregister(void)' inside these objects to bootstrap them.
+
+ An ssl_vendor.c should at least contain the following contents:
+
+ | #include "mod_ssl.h"
+ | void ssl_vendor_register(void) { return; }
+ | void ssl_vendor_unregister(void) { return; }
+
diff --git a/modules/ssl/README.dsov.fig b/modules/ssl/README.dsov.fig
new file mode 100644
index 0000000000..d8d03db247
--- /dev/null
+++ b/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/modules/ssl/README.dsov.ps b/modules/ssl/README.dsov.ps
new file mode 100644
index 0000000000..def19dbecf
--- /dev/null
+++ b/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/modules/ssl/libssl.module b/modules/ssl/libssl.module
new file mode 100644
index 0000000000..72eeabb345
--- /dev/null
+++ b/modules/ssl/libssl.module
@@ -0,0 +1,497 @@
+## _ _
+## _ __ ___ ___ __| | ___ ___| | mod_ssl
+## | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+## | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+## |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+## |_____|
+## libssl.module
+## Apache 1.3 Configuration mechanism module stub
+##
+
+##
+## ====================================================================
+## Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+##
+## 1. Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+##
+## 2. Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following
+## disclaimer in the documentation and/or other materials
+## provided with the distribution.
+##
+## 3. All advertising materials mentioning features or use of this
+## software must display the following acknowledgment:
+## "This product includes software developed by
+## Ralf S. Engelschall <rse@engelschall.com> for use in the
+## mod_ssl project (http://www.modssl.org/)."
+##
+## 4. The names "mod_ssl" must not be used to endorse or promote
+## products derived from this software without prior written
+## permission. For written permission, please contact
+## rse@engelschall.com.
+##
+## 5. Products derived from this software may not be called "mod_ssl"
+## nor may "mod_ssl" appear in their names without prior
+## written permission of Ralf S. Engelschall.
+##
+## 6. Redistributions of any form whatsoever must retain the following
+## acknowledgment:
+## "This product includes software developed by
+## Ralf S. Engelschall <rse@engelschall.com> for use in the
+## mod_ssl project (http://www.modssl.org/)."
+##
+## THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+## EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+## HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+## NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+## STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+## OF THE POSSIBILITY OF SUCH DAMAGE.
+## ====================================================================
+##
+
+ # ``What you are missing, I suppose, is that I'm not
+ # prepared to give equal rights to Ralf on the basis
+ # that he's spent a few hours doing what he thinks is
+ # better than what I've spent the last 4 years on,
+ # and so he isn't prepared to cooperate with me.''
+ # -- Ben Laurie, Apache-SSL author
+
+Name: ssl_module
+ConfigStart
+
+ #
+ # interface to the src/Configure script
+ #
+ my_dir="`echo ${modfile} | sed -e 's:/[^/]*$::'`"
+ my_version="$my_dir/libssl.version"
+ my_outfile="Makefile.config"
+ my_prefix=" +"
+ my_prefixe=" "
+ SSL_CFLAGS=''
+ SSL_LDFLAGS=''
+ SSL_LIBS=''
+
+ #
+ # find a reasonable Bourne Shell for sub-shell calls
+ #
+ SH=sh
+ if [ -f /bin/bash ]; then
+ SH=/bin/bash
+ elif [ -f /bin/sh5 ]; then
+ SH=/bin/sh5
+ elif [ -f /bin/sh ]; then
+ SH=/bin/sh
+ fi
+
+ #
+ # determine mod_ssl author version
+ #
+ A_ID=`cat $my_version | sed -e 's; .*;;'`
+ A_NAME=`echo $A_ID | sed -e 's;/.*;;'`
+ A_VER=`echo $A_ID | sed -e 's;.*/;;'`
+ A_VER_STR=`echo $A_VER | sed -e 's;-.*;;'`
+ case $A_VER_STR in
+ *.*b* )
+ A_VER_HEX=`echo "$A_VER_STR" | sed -e 's/b.*//' | awk -F. '{ printf("%d%02d", $1, $2); }' &&
+ echo "$A_VER_STR" | sed -e 's/.*b//' | awk '{ printf("0%02d", $1); }'`
+ ;;
+ *.*.* )
+ A_VER_HEX=`echo "$A_VER_STR" | awk -F. '{ printf("%d%02d1%02d", $1, $2, $3); }'`
+ ;;
+ esac
+ echo "$my_prefix SSL interface: $A_NAME/$A_VER_STR"
+ SSL_VERSION="-DMOD_SSL_VERSION=\\\"$A_VER_STR\\\""
+
+ #
+ # determine optional mod_ssl product version
+ #
+ if [ ".`egrep '.*/.* .*/.*' $my_version`" != . ]; then
+ P_ID=`cat $my_version | sed -e 's;.* ;;'`
+ P_NAME=`echo $P_ID | sed -e 's;/.*;;'`
+ P_VER=`echo $P_ID | sed -e 's;.*/;;'`
+ P_VER_STR=`echo $P_VER | sed -e 's;-.*;;'`
+ case $P_VER_STR in
+ *.*b* )
+ P_VER_HEX=`echo "$P_VER_STR" | sed -e 's/b.*//' | awk -F. '{ printf("%d%02d", $1, $2); }' &&
+ echo "$P_VER_STR" | sed -e 's/.*b//' | awk '{ printf("0%02d", $1); }'`
+ ;;
+ *.*.* )
+ P_VER_HEX=`echo "$P_VER_STR" | awk -F. '{ printf("%d%02d1%02d", $1, $2, $3); }'`
+ ;;
+ esac
+ echo "$my_prefix SSL product: $P_NAME/$P_VER_STR"
+ SSL_VERSION="$SSL_VERSION -DSSL_PRODUCT_NAME=\\\"$P_NAME\\\""
+ SSL_VERSION="$SSL_VERSION -DSSL_PRODUCT_VERSION=\\\"$P_VER_STR\\\""
+ fi
+
+ #
+ # determine object build type
+ #
+ case $modfile in
+ *.so ) my_buildtype="DSO" ;;
+ * ) my_buildtype="OBJ" ;;
+ esac
+ echo "$my_prefix SSL interface build type: $my_buildtype"
+
+ #
+ # determine SSL rules
+ #
+ if [ ".$APXS_MODE" = .YES ]; then
+ my_rule_SSL_COMPAT=$SSL_COMPAT
+ my_rule_SSL_SDBM=$SSL_SDBM
+ my_rule_SSL_EXPERIMENTAL=$SSL_EXPERIMENTAL
+ my_rule_SSL_CONSERVATIVE=$SSL_CONSERVATIVE
+ my_rule_SSL_VENDOR=$SSL_VENDOR
+ else
+ my_rule_SSL_COMPAT=`$SH helpers/CutRule SSL_COMPAT $file`
+ my_rule_SSL_SDBM=`$SH helpers/CutRule SSL_SDBM $file`
+ my_rule_SSL_EXPERIMENTAL=`$SH helpers/CutRule SSL_EXPERIMENTAL $file`
+ my_rule_SSL_CONSERVATIVE=`$SH helpers/CutRule SSL_CONSERVATIVE $file`
+ my_rule_SSL_VENDOR=`$SH helpers/CutRule SSL_VENDOR $file`
+ fi
+
+ #
+ # determine compatibility mode
+ #
+ if [ ".$my_rule_SSL_COMPAT" = .yes ]; then
+ echo "$my_prefix SSL interface compatibility: enabled"
+ SSL_CFLAGS="$SSL_CFLAGS -DSSL_COMPAT"
+ else
+ echo "$my_prefix SSL interface compatibility: disabled"
+ fi
+
+ #
+ # determine experimental mode
+ #
+ if [ ".$my_rule_SSL_EXPERIMENTAL" = .yes ]; then
+ echo "$my_prefix SSL interface experimental code: enabled"
+ SSL_CFLAGS="$SSL_CFLAGS -DSSL_EXPERIMENTAL"
+ else
+ echo "$my_prefix SSL interface experimental code: disabled"
+ fi
+
+ #
+ # determine conservative mode
+ #
+ if [ ".$my_rule_SSL_CONSERVATIVE" = .yes ]; then
+ echo "$my_prefix SSL interface conservative code: enabled"
+ SSL_CFLAGS="$SSL_CFLAGS -DSSL_CONSERVATIVE"
+ else
+ echo "$my_prefix SSL interface conservative code: disabled"
+ fi
+
+ #
+ # determine vendor mode
+ #
+ SSL_VENDOR_OBJS=''
+ SSL_VENDOR_OBJS_PIC=''
+ if [ ".$my_rule_SSL_VENDOR" = .yes ]; then
+ echo "$my_prefix SSL interface vendor extensions: enabled"
+ SSL_CFLAGS="$SSL_CFLAGS -DSSL_VENDOR"
+ my_src="`cd $my_dir && echo ssl_vendor*.c`"
+ if [ ".$my_src" != . -a ".$my_src" != ".ssl_vendor*.c" ]; then
+ SSL_CFLAGS="$SSL_CFLAGS -DSSL_VENDOR_OBJS"
+ SSL_VENDOR_OBJS="`echo $my_src | sed -e 's;\.c;.o;g'`"
+ SSL_VENDOR_OBJS_PIC="`echo $my_src | sed -e 's;\.c;.lo;g'`"
+ echo "$my_prefix SSL interface vendor objects: $SSL_VENDOR_OBJS"
+ fi
+ else
+ echo "$my_prefix SSL interface vendor extensions: disabled"
+ fi
+
+ #
+ # determine DBM support library
+ # (src/Configure has DBM_LIB predefined for some platforms)
+ #
+ if [ ".$APXS_MODE" != .YES ]; then
+ SSL_DBM_NAME=''
+ # 1. check for predefined DBM lib
+ if [ ".$DBM_LIB" != . ]; then
+ LIBS_ORIG="$LIBS"
+ LIBS="$LIBS $DBM_LIB"
+ if $SH helpers/TestCompile func dbm_open; then
+ SSL_DBM_NAME="Configured DBM ($DBM_LIB)"
+ SSL_DBM_FLAG="$DBM_LIB"
+ fi
+ LIBS="$LIBS_ORIG"
+ fi
+ # 2. check for various vendor DBM libs
+ if [ ".$SSL_DBM_NAME" = . ]; then
+ if $SH helpers/TestCompile func dbm_open; then
+ SSL_DBM_NAME='Vendor DBM (libc)'
+ SSL_DBM_FLAG=''
+ elif $SH helpers/TestCompile lib dbm dbm_open; then
+ SSL_DBM_NAME='Vendor DBM (libdbm)'
+ SSL_DBM_FLAG='-ldbm'
+ elif $SH helpers/TestCompile lib ndbm dbm_open; then
+ SSL_DBM_NAME='Vendor DBM (libndbm)'
+ SSL_DBM_FLAG='-lndbm'
+ fi
+ fi
+ # 3. let the SSL_SDBM rule override decisions
+ if [ ".$my_rule_SSL_SDBM" = .yes ]; then
+ # force us to fallback to SDBM
+ SSL_DBM_NAME=''
+ fi
+ if [ ".$my_rule_SSL_SDBM" = .no ]; then
+ # for us to never use SDBM, but be
+ # careful when no DBM was found at all
+ if [ ".$SSL_DBM_NAME" = . ]; then
+ echo "Error: SDBM is needed, because no custom or vendor DBM library available!" 1>&2
+ echo "Hint: Allow us to choose SDBM by changing the rule SSL_SDBM, please." 1>&2
+ exit 1
+ fi
+ fi
+ # 4. override decision on a few brain-dead platforms
+ if [ ".$my_rule_SSL_SDBM" = .default ]; then
+ case "$OS" in
+ Linux )
+ # force Linux boxes to use builtin SDBM per default because
+ # of too much broken vendor DBM libraries on this platform
+ SSL_DBM_NAME=''
+ ;;
+ esac
+ fi
+ # 5. finally configure the chosen DBM lib
+ if [ ".$SSL_DBM_NAME" != . ]; then
+ echo "$my_prefix SSL interface plugin: $SSL_DBM_NAME"
+ my_dbm_already_used=`echo $LIBS | grep -- " $SSL_DBM_FLAG"`
+ if [ ".$my_buildtype" = .OBJ -a ".$my_dbm_already_used" != . ]; then
+ :
+ else
+ SSL_LIBS="$SSL_LIBS $SSL_DBM_FLAG"
+ fi
+ else
+ echo "$my_prefix SSL interface plugin: Built-in SDBM"
+ SSL_CFLAGS="$SSL_CFLAGS -DSSL_USE_SDBM"
+ fi
+ fi
+
+ #
+ # determine SSL_BASE
+ #
+ if [ ".$SSL_BASE" = . ]; then
+ SSL_BASE=`egrep '^SSL_BASE=' $file | tail -1 | awk -F= '{print $2}'`
+ if [ ".$SSL_BASE" = . ]; then
+ if [ -d /usr/local/ssl ]; then
+ SSL_BASE="/usr/local/ssl"
+ else
+ SSL_BASE="SYSTEM"
+ fi
+ fi
+ fi
+ case $SSL_BASE in
+ SYSTEM ) ;;
+ /* ) ;;
+ * ) SSL_BASE="`cd ../$SSL_BASE; pwd`" ;;
+ esac
+ if [ ".$SSL_BASE" = .SYSTEM ]; then
+ echo "$my_prefix SSL library path: [SYSTEM]"
+ else
+ if [ ! -d "$SSL_BASE" ]; then
+ echo "Error: Cannot find SSL installation in $SSL_BASE" 1>&2
+ echo "Hint: Please provide us with the location of OpenSSL" 1>&2
+ echo " via the environment variable SSL_BASE." 1>&2
+ exit 1
+ fi
+ echo "$my_prefix SSL library path: $SSL_BASE"
+ fi
+
+ #
+ # determine location of OpenSSL binaries
+ # (we still search also for `ssleay' to allow us to
+ # better complain about the actually installed version)
+ #
+ SSL_BINDIR=""
+ if [ ".$SSL_BASE" = .SYSTEM ]; then
+ for name in openssl ssleay; do
+ for p in . `echo $PATH | sed -e 's/:/ /g'`; do
+ if [ -f "$p/$name" ]; then
+ SSL_PROGRAM="$p/$name"
+ SSL_BINDIR="$p"
+ break
+ fi
+ done
+ if [ ".$SSL_BINDIR" != . ]; then
+ break;
+ fi
+ done
+ if [ ".$SSL_BINDIR" = . ]; then
+ echo "Error: Cannot find SSL binaries in $PATH" 1>&2
+ exit 1
+ fi
+ else
+ for name in openssl ssleay; do
+ if [ -f "$SSL_BASE/bin/$name" ]; then
+ SSL_PROGRAM="$SSL_BASE/bin/$name"
+ SSL_BINDIR='$(SSL_BASE)/bin'
+ break;
+ fi
+ if [ -f "$SSL_BASE/apps/$name" ]; then
+ SSL_PROGRAM="$SSL_BASE/apps/$name"
+ SSL_BINDIR='$(SSL_BASE)/apps'
+ break;
+ fi
+ done
+ if [ ".$SSL_BINDIR" = . ]; then
+ echo "Error: Cannot find SSL binaries under $SSL_BASE" 1>&2
+ exit 1
+ fi
+ fi
+
+ #
+ # SSL version
+ #
+ SSL_VERSION_ID="`$SSL_PROGRAM version`"
+ echo "$my_prefix SSL library version: $SSL_VERSION_ID"
+ case $SSL_VERSION_ID in
+ *0.[5678].*|*0.9.[012]* )
+ echo "Error: OpenSSL VERSIONS BELOW 0.9.3 ARE NO LONGER SUPPORTED."
+ echo "Hint: Use OpenSSL version 0.9.3 or higher!"
+ exit 1
+ ;;
+ esac
+
+ #
+ # SSL engine support
+ #
+ case $SSL_VERSION_ID in
+ *0.9.6*engine* | *0.9.6a*engine* | *0.9.[789]* )
+ SSL_CFLAGS="$SSL_CFLAGS -DSSL_ENGINE"
+ ;;
+ esac
+
+ #
+ # determine location of OpenSSL headers
+ #
+ if [ ".$SSL_BASE" = .SYSTEM ]; then
+ SSL_INCDIR=""
+ for p in . /usr/include /usr/include/ssl/ /usr/local/include /usr/local/include/ssl; do
+ if [ -f "$p/openssl/ssl.h" ]; then
+ SSL_INCDIR="$p"
+ break
+ fi
+ done
+ if [ ".$SSL_INCDIR" = . ]; then
+ echo "Error: Cannot find SSL header files in any of the following dirs:" 1>&2
+ echo "Error: . /usr/include /usr/include/ssl/ /usr/local/include /usr/local/include/ssl" 1>&2
+ exit 1
+ fi
+ else
+ if [ -f "$SSL_BASE/include/openssl/ssl.h" ]; then
+ SSL_INCDIR='$(SSL_BASE)/include'
+ else
+ echo "Error: Cannot find SSL header files under $SSL_BASE" 1>&2
+ exit 1
+ fi
+ fi
+ if [ ".$SSL_INCDIR" != "./usr/include" ]; then
+ SSL_CFLAGS="$SSL_CFLAGS -I\$(SSL_INCDIR)"
+ fi
+
+ #
+ # determine location of OpenSSL libraries
+ #
+ if [ ".$SSL_BASE" = .SYSTEM ]; then
+ SSL_LIBDIR=""
+ for p in . /lib /usr/lib /usr/local/lib; do
+ if [ -f "$p/libssl.a" -o -f "$p/libssl.so" ]; then
+ SSL_LIBDIR="$p"
+ my_real_ssl_libdir="$p"
+ break
+ fi
+ done
+ if [ ".$SSL_LIBDIR" = . ]; then
+ echo "Error: Cannot find SSL library files in any of the following dirs:" 1>&2
+ echo "Error: . /lib /usr/lib /usr/local/lib" 1>&2
+ exit 1
+ fi
+ else
+ if [ -f "$SSL_BASE/libssl.a" -o -f "$SSL_BASE/libssl.so" ]; then
+ SSL_LIBDIR='$(SSL_BASE)'
+ my_real_ssl_libdir="$SSL_BASE"
+ elif [ -f "$SSL_BASE/lib/libssl.a" -o -f "$SSL_BASE/lib/libssl.so" ]; then
+ SSL_LIBDIR='$(SSL_BASE)/lib'
+ my_real_ssl_libdir="$SSL_BASE/lib"
+ else
+ echo "Error: Cannot find SSL library files under $SSL_BASE" 1>&2
+ exit 1
+ fi
+ fi
+ SSL_LDFLAGS="$SSL_LDFLAGS -L\$(SSL_LIBDIR)"
+ SSL_LIBS="$SSL_LIBS -lssl -lcrypto"
+
+ #
+ # SSL installation type
+ #
+ case $SSL_BINDIR in
+ */apps ) my_type="source tree only" ;;
+ * ) my_type="installed package" ;;
+ esac
+ case $SSL_BASE in
+ SYSTEM ) my_note="(system-wide)" ;;
+ * ) my_note="(stand-alone)" ;;
+ esac
+ echo "$my_prefix SSL library type: $my_type $my_note"
+
+ #
+ # Special GCC/DSO support
+ #
+ # Under some platforms where GCC is used we have to link the DSO
+ # (libssl.so) explicitly against the GCC library (libgcc) to avoid
+ # problems with missing symbols like __umoddi3, etc.
+ #
+ # Notice: When GCC is installed as "cc" we assume it's really
+ # well incorporated into the system and no hack is
+ # needed (like on FreeBSD, Linux, etc.)
+ #
+ if [ ".$my_buildtype" = .DSO ]; then
+ my_CC=`echo "$CC" | sed -e 's/ .*//'`
+ case $my_CC in
+ gcc|*/gcc|egcs|*/egcs|egcc|*/egcc|pgcc|*/pgcc )
+ gcclibdir="`$CC --print-libgcc-file-name | sed -e 's;/[^/]*$;;'`"
+ SSL_LIBS="$SSL_LIBS -L$gcclibdir -lgcc"
+ ;;
+ esac
+ fi
+
+ #
+ # adjust the Apache build environment
+ #
+ echo "SSL_BASE=$SSL_BASE" >>$my_outfile
+ echo "SSL_BINDIR=$SSL_BINDIR" >>$my_outfile
+ echo "SSL_INCDIR=$SSL_INCDIR" >>$my_outfile
+ echo "SSL_LIBDIR=$SSL_LIBDIR" >>$my_outfile
+ echo "SSL_PROGRAM=$SSL_PROGRAM" >>$my_outfile
+ echo "SSL_VERSION=$SSL_VERSION" >>$my_outfile
+ echo "SSL_CFLAGS=$SSL_CFLAGS" >>$my_outfile
+ echo "SSL_VENDOR_OBJS=$SSL_VENDOR_OBJS" >>$my_outfile
+ echo "SSL_VENDOR_OBJS_PIC=$SSL_VENDOR_OBJS_PIC" >>$my_outfile
+ if [ ".$my_buildtype" = .DSO ]; then
+ # under DSO we link ourself
+ echo "SSL_LIBS=$SSL_LIBS" >>$my_outfile
+ echo "SSL_LDFLAGS=$SSL_LDFLAGS" >>$my_outfile
+ else
+ # else we are linked with httpd
+ LDFLAGS="$LDFLAGS $SSL_LDFLAGS"
+ LIBS="$LIBS $SSL_LIBS"
+ fi
+ CFLAGS="$CFLAGS -DMOD_SSL=$A_VER_HEX"
+ if [ ".$P_ID" != . ]; then
+ CFLAGS="$CFLAGS -DSSL_PRODUCT=$P_VER_HEX"
+ fi
+ RULE_EAPI=yes
+
+ConfigEnd
+
diff --git a/modules/ssl/libssl.version b/modules/ssl/libssl.version
new file mode 100644
index 0000000000..a053095e44
--- /dev/null
+++ b/modules/ssl/libssl.version
@@ -0,0 +1 @@
+mod_ssl/2.8.3-1.3.19
diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c
new file mode 100644
index 0000000000..2d1b5e1b0a
--- /dev/null
+++ b/modules/ssl/mod_ssl.c
@@ -0,0 +1,248 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** mod_ssl.c
+** Apache API interface structures
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``I'll be surprised if
+ others think that what you
+ are doing is honourable.''
+ -- Ben Laurie, Apache-SSL author */
+#include "mod_ssl.h"
+
+/* _________________________________________________________________
+**
+** Apache API glue structures
+** _________________________________________________________________
+*/
+
+/*
+ * identify the module to SCCS `what' and RCS `ident' commands
+ */
+static char const sccsid[] = "@(#) mod_ssl/" MOD_SSL_VERSION " >";
+static char const rcsid[] = "$Id: mod_ssl.c,v 1.1 2001/05/04 21:54:42 rse Exp $";
+
+/*
+ * the table of configuration directives we provide
+ */
+static command_rec ssl_config_cmds[] = {
+ /*
+ * Global (main-server) context configuration directives
+ */
+ AP_SRV_CMD(Mutex, TAKE1,
+ "SSL lock for handling internal mutual exclusions "
+ "(`none', `file:/path/to/file')")
+ AP_SRV_CMD(PassPhraseDialog, TAKE1,
+ "SSL dialog mechanism for the pass phrase query "
+ "(`builtin', `exec:/path/to/program')")
+ AP_SRV_CMD(SessionCache, TAKE1,
+ "SSL Session Cache storage "
+ "(`none', `dbm:/path/to/file')")
+#ifdef SSL_EXPERIMENTAL_ENGINE
+ AP_SRV_CMD(CryptoDevice, TAKE1,
+ "SSL external Crypto Device usage "
+ "(`builtin', `...')")
+#endif
+ AP_SRV_CMD(RandomSeed, TAKE23,
+ "SSL Pseudo Random Number Generator (PRNG) seeding source "
+ "(`startup|connect builtin|file:/path|exec:/path [bytes]')")
+
+ /*
+ * Per-server context configuration directives
+ */
+ AP_SRV_CMD(Engine, FLAG,
+ "SSL switch for the protocol engine "
+ "(`on', `off')")
+ AP_ALL_CMD(CipherSuite, TAKE1,
+ "Colon-delimited list of permitted SSL Ciphers "
+ "(`XXX:...:XXX' - see manual)")
+ AP_SRV_CMD(CertificateFile, TAKE1,
+ "SSL Server Certificate file "
+ "(`/path/to/file' - PEM or DER encoded)")
+ AP_SRV_CMD(CertificateKeyFile, TAKE1,
+ "SSL Server Private Key file "
+ "(`/path/to/file' - PEM or DER encoded)")
+ AP_SRV_CMD(CertificateChainFile, TAKE1,
+ "SSL Server CA Certificate Chain file "
+ "(`/path/to/file' - PEM encoded)")
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ AP_ALL_CMD(CACertificatePath, TAKE1,
+ "SSL CA Certificate path "
+ "(`/path/to/dir' - contains PEM encoded files)")
+ AP_ALL_CMD(CACertificateFile, TAKE1,
+ "SSL CA Certificate file "
+ "(`/path/to/file' - PEM encoded)")
+#else
+ AP_SRV_CMD(CACertificatePath, TAKE1,
+ "SSL CA Certificate path "
+ "(`/path/to/dir' - contains PEM encoded files)")
+ AP_SRV_CMD(CACertificateFile, TAKE1,
+ "SSL CA Certificate file "
+ "(`/path/to/file' - PEM encoded)")
+#endif
+ AP_SRV_CMD(CARevocationPath, TAKE1,
+ "SSL CA Certificate Revocation List (CRL) path "
+ "(`/path/to/dir' - contains PEM encoded files)")
+ AP_SRV_CMD(CARevocationFile, TAKE1,
+ "SSL CA Certificate Revocation List (CRL) file "
+ "(`/path/to/file' - PEM encoded)")
+ AP_ALL_CMD(VerifyClient, TAKE1,
+ "SSL Client verify type "
+ "(`none', `optional', `require', `optional_no_ca')")
+ AP_ALL_CMD(VerifyDepth, TAKE1,
+ "SSL Client verify depth "
+ "(`N' - number of intermediate certificates)")
+ AP_SRV_CMD(SessionCacheTimeout, TAKE1,
+ "SSL Session Cache object lifetime "
+ "(`N' - number of seconds)")
+ AP_SRV_CMD(Log, TAKE1,
+ "SSL logfile for SSL-related messages "
+ "(`/path/to/file', `|/path/to/program')")
+ AP_SRV_CMD(LogLevel, TAKE1,
+ "SSL logfile verbosity level "
+ "(`none', `error', `warn', `info', `debug')")
+ AP_SRV_CMD(Protocol, RAW_ARGS,
+ "Enable or disable various SSL protocols"
+ "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)")
+
+#ifdef SSL_EXPERIMENTAL_PROXY
+ /*
+ * Proxy configuration for remote SSL connections
+ */
+ AP_SRV_CMD(ProxyProtocol, RAW_ARGS,
+ "SSL Proxy: enable or disable SSL protocol flavors "
+ "(`[+-][SSLv2|SSLv3|TLSv1] ...' - see manual)")
+ AP_SRV_CMD(ProxyCipherSuite, TAKE1,
+ "SSL Proxy: colon-delimited list of permitted SSL ciphers "
+ "(`XXX:...:XXX' - see manual)")
+ AP_SRV_CMD(ProxyVerify, FLAG,
+ "SSL Proxy: whether to verify the remote certificate "
+ "(`on' or `off')")
+ AP_SRV_CMD(ProxyVerifyDepth, TAKE1,
+ "SSL Proxy: maximum certificate verification depth "
+ "(`N' - number of intermediate certificates)")
+ AP_SRV_CMD(ProxyCACertificateFile, TAKE1,
+ "SSL Proxy: file containing server certificates "
+ "(`/path/to/file' - PEM encoded certificates)")
+ AP_SRV_CMD(ProxyCACertificatePath, TAKE1,
+ "SSL Proxy: directory containing server certificates "
+ "(`/path/to/dir' - contains PEM encoded certificates)")
+ AP_SRV_CMD(ProxyMachineCertificateFile, TAKE1,
+ "SSL Proxy: file containing client certificates "
+ "(`/path/to/file' - PEM encoded certificates)")
+ AP_SRV_CMD(ProxyMachineCertificatePath, TAKE1,
+ "SSL Proxy: directory containing client certificates "
+ "(`/path/to/dir' - contains PEM encoded certificates)")
+#endif
+
+ /*
+ * Per-directory context configuration directives
+ */
+ AP_DIR_CMD(Options, OPTIONS, RAW_ARGS,
+ "Set one of more options to configure the SSL engine"
+ "(`[+-]option[=value] ...' - see manual)")
+ AP_DIR_CMD(RequireSSL, AUTHCFG, NO_ARGS,
+ "Require the SSL protocol for the per-directory context "
+ "(no arguments)")
+ AP_DIR_CMD(Require, AUTHCFG, RAW_ARGS,
+ "Require a boolean expresion to evaluate to true for granting access"
+ "(arbitrary complex boolean expression - see manual)")
+
+ AP_END_CMD
+};
+
+static const handler_rec ssl_config_handler[] = {
+ { "mod_ssl:content-handler", ssl_hook_Handler },
+ { NULL, NULL }
+};
+
+/*
+ * the main Apache API config structure
+ */
+module MODULE_VAR_EXPORT ssl_module = {
+ STANDARD_MODULE_STUFF,
+
+ /* Standard API (always present) */
+
+ ssl_init_Module, /* module initializer */
+ 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 config file commands */
+ ssl_config_handler, /* [#8] MIME-typed-dispatched handlers */
+ ssl_hook_Translate, /* [#1] URI to filename translation */
+ ssl_hook_Auth, /* [#4] validate user id from request */
+ ssl_hook_UserCheck, /* [#5] check if the user is ok _here_ */
+ ssl_hook_Access, /* [#3] check access by host address */
+ NULL, /* [#6] determine MIME type */
+ ssl_hook_Fixup, /* [#7] pre-run fixups */
+ NULL, /* [#9] log a transaction */
+ NULL, /* [#2] header parser */
+ ssl_init_Child, /* child_init */
+ NULL, /* child_exit */
+ ssl_hook_ReadReq, /* [#0] post read-request */
+
+ /* Extended API (forced to be enabled with mod_ssl) */
+
+ ssl_hook_AddModule, /* after modules was added to core */
+ ssl_hook_RemoveModule, /* before module is removed from core */
+ ssl_hook_RewriteCommand, /* configuration command rewriting */
+ ssl_hook_NewConnection, /* socket connection open */
+ ssl_hook_CloseConnection /* socket connection close */
+};
+
diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h
new file mode 100644
index 0000000000..8731ef9de4
--- /dev/null
+++ b/modules/ssl/mod_ssl.h
@@ -0,0 +1,854 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** mod_ssl.h
+** Global header
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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 1
+
+/*
+ * Check whether Extended API (EAPI) is enabled
+ */
+#ifndef EAPI
+#error "mod_ssl requires Extended API (EAPI)"
+#endif
+
+/*
+ * 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
+#ifndef SSL_EXPERIMENTAL_PERDIRCA_IGNORE
+#define SSL_EXPERIMENTAL_PERDIRCA
+#endif
+#ifndef SSL_EXPERIMENTAL_PROXY_IGNORE
+#define SSL_EXPERIMENTAL_PROXY
+#endif
+#ifdef SSL_ENGINE
+#ifndef SSL_EXPERIMENTAL_ENGINE_IGNORE
+#define SSL_EXPERIMENTAL_ENGINE
+#endif
+#endif
+#endif /* SSL_EXPERIMENTAL */
+
+/*
+ * Power up our brain...
+ */
+
+/* OS headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+#ifdef WIN32
+#include <wincrypt.h>
+#include <winsock2.h>
+#endif
+
+/* OpenSSL headers */
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pem.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#ifdef SSL_EXPERIMENTAL_ENGINE
+#include <openssl/engine.h>
+#endif
+
+/* Apache headers */
+#define CORE_PRIVATE
+#include "ap_config.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_conf_globals.h"
+#include "http_protocol.h"
+#include "http_request.h"
+#include "http_main.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "scoreboard.h"
+#include "util_md5.h"
+#include "fnmatch.h"
+#undef CORE_PRIVATE
+
+/* mod_ssl headers */
+#include "ssl_expr.h"
+#include "ssl_util_ssl.h"
+#include "ssl_util_table.h"
+
+/*
+ * 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 cfgMerge(el,unset) new->el = add->el == unset ? base->el : add->el
+#define cfgMergeArray(el) new->el = ap_append_arrays(p, add->el, base->el)
+#define cfgMergeTable(el) new->el = ap_overlay_tables(p, add->el, base->el)
+#define cfgMergeCtx(el) new->el = ap_ctx_overlay(p, add->el, base->el)
+#define cfgMergeString(el) cfgMerge(el, NULL)
+#define cfgMergeBool(el) cfgMerge(el, UNSET)
+#define cfgMergeInt(el) cfgMerge(el, UNSET)
+
+#define myModConfig() (SSLModConfigRec *)ap_ctx_get(ap_global_ctx, "ssl_module")
+#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 myCtxVarSet(mc,num,val) mc->rCtx.pV##num = val
+#define myCtxVarGet(mc,num,type) (type)(mc->rCtx.pV##num)
+
+#define AP_ALL_CMD(name, args, desc) \
+ { "SSL"#name, ssl_cmd_SSL##name, NULL, RSRC_CONF|OR_AUTHCFG, args, desc },
+#define AP_SRV_CMD(name, args, desc) \
+ { "SSL"#name, ssl_cmd_SSL##name, NULL, RSRC_CONF, args, desc },
+#define AP_DIR_CMD(name, type, args, desc) \
+ { "SSL"#name, ssl_cmd_SSL##name, NULL, OR_##type, args, desc },
+#define AP_END_CMD \
+ { NULL }
+
+/*
+ * SSL Logging
+ */
+#define SSL_LOG_NONE (1<<0)
+#define SSL_LOG_ERROR (1<<1)
+#define SSL_LOG_WARN (1<<2)
+#define SSL_LOG_INFO (1<<3)
+#define SSL_LOG_TRACE (1<<4)
+#define SSL_LOG_DEBUG (1<<5)
+#define SSL_LOG_MASK (SSL_LOG_ERROR|SSL_LOG_WARN|SSL_LOG_INFO|SSL_LOG_TRACE|SSL_LOG_DEBUG)
+
+#define SSL_ADD_NONE (1<<8)
+#define SSL_ADD_ERRNO (1<<9)
+#define SSL_ADD_SSLERR (1<<10)
+#define SSL_NO_TIMESTAMP (1<<11)
+#define SSL_NO_LEVELID (1<<12)
+#define SSL_NO_NEWLINE (1<<13)
+
+/*
+ * Defaults for the configuration
+ */
+#ifndef SSL_SESSION_CACHE_TIMEOUT
+#define SSL_SESSION_CACHE_TIMEOUT 300
+#endif
+
+/*
+ * Support for file locking: Try to determine whether we should use fcntl() or
+ * flock(). Would be better ap_config.h could provide this... :-(
+ */
+#if defined(USE_FCNTL_SERIALIZED_ACCEPT)
+#define SSL_USE_FCNTL 1
+#include <fcntl.h>
+#endif
+#if defined(USE_FLOCK_SERIALIZED_ACCEPT)
+#define SSL_USE_FLOCK 1
+#include <sys/file.h>
+#endif
+#if !defined(SSL_USE_FCNTL) && !defined(SSL_USE_FLOCK)
+#define SSL_USE_FLOCK 1
+#if !defined(MPE) && !defined(WIN32)
+#include <sys/file.h>
+#endif
+#ifndef LOCK_UN
+#undef SSL_USE_FLOCK
+#define SSL_USE_FCNTL 1
+#include <fcntl.h>
+#endif
+#endif
+#ifdef AIX
+#undef SSL_USE_FLOCK
+#define SSL_USE_FCNTL 1
+#include <fcntl.h>
+#endif
+
+/*
+ * Support for Mutex
+ */
+#ifndef WIN32
+#define SSL_MUTEX_LOCK_MODE ( S_IRUSR|S_IWUSR )
+#else
+#define SSL_MUTEX_LOCK_MODE (_S_IREAD|_S_IWRITE )
+#endif
+#if defined(USE_SYSVSEM_SERIALIZED_ACCEPT) ||\
+ (defined(__FreeBSD__) && defined(__FreeBSD_version) &&\
+ __FreeBSD_version >= 300000) ||\
+ (defined(LINUX) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) &&\
+ LINUX >= 2 && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) ||\
+ defined(SOLARIS2) || defined(__hpux) ||\
+ (defined (__digital__) && defined (__unix__))
+#define SSL_CAN_USE_SEM
+#define SSL_HAVE_IPCSEM
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+/*
+ * Some platforms have a `union semun' pre-defined but Single Unix
+ * Specification (SUSv2) says in semctl(2): `If required, it is of
+ * type union semun, which the application program must explicitly
+ * declare'. So we define it always ourself to avoid problems (but under
+ * a different name to avoid a namespace clash).
+ */
+union ssl_ipc_semun {
+ long val;
+ struct semid_ds *buf;
+ unsigned short int *array;
+};
+#endif
+#ifdef WIN32
+#define SSL_CAN_USE_SEM
+#define SSL_HAVE_W32SEM
+#include "multithread.h"
+#include <process.h>
+#endif
+
+/*
+ * Support for MM library
+ */
+#ifndef WIN32
+#define SSL_MM_FILE_MODE ( S_IRUSR|S_IWUSR )
+#else
+#define SSL_MM_FILE_MODE ( _S_IREAD|_S_IWRITE )
+#endif
+
+/*
+ * Support for DBM library
+ */
+#ifndef WIN32
+#define SSL_DBM_FILE_MODE ( S_IRUSR|S_IWUSR )
+#else
+#define SSL_USE_SDBM
+#define SSL_DBM_FILE_MODE ( _S_IREAD|_S_IWRITE )
+#endif
+
+#ifdef SSL_USE_SDBM
+#include "ssl_util_sdbm.h"
+#define ssl_dbm_open sdbm_open
+#define ssl_dbm_close sdbm_close
+#define ssl_dbm_store sdbm_store
+#define ssl_dbm_fetch sdbm_fetch
+#define ssl_dbm_delete sdbm_delete
+#define ssl_dbm_firstkey sdbm_firstkey
+#define ssl_dbm_nextkey sdbm_nextkey
+#define SSL_DBM_FILE_SUFFIX_DIR ".dir"
+#define SSL_DBM_FILE_SUFFIX_PAG ".pag"
+#else /* !SSL_USE_SDBM */
+#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) \
+ && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+#include <db1/ndbm.h>
+#else
+#include <ndbm.h>
+#endif
+#define ssl_dbm_open dbm_open
+#define ssl_dbm_close dbm_close
+#define ssl_dbm_store dbm_store
+#define ssl_dbm_fetch dbm_fetch
+#define ssl_dbm_delete dbm_delete
+#define ssl_dbm_firstkey dbm_firstkey
+#define ssl_dbm_nextkey dbm_nextkey
+#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
+#endif /* !SSL_USE_SDBM */
+
+/*
+ * Check for OpenSSL version
+ */
+#if SSL_LIBRARY_VERSION < 0x00903100
+#error "mod_ssl requires OpenSSL 0.9.3 or higher"
+#endif
+
+/*
+ * The own data structures
+ */
+typedef struct {
+ pool *pPool;
+ pool *pSubPool;
+ array_header *aData;
+} ssl_ds_array;
+
+typedef struct {
+ pool *pPool;
+ pool *pSubPool;
+ array_header *aKey;
+ array_header *aData;
+} ssl_ds_table;
+
+/*
+ * 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_TKP_GEN (0)
+#define SSL_TKP_ALLOC (1)
+#define SSL_TKP_FREE (2)
+
+#define SSL_TKPIDX_RSA512 (0)
+#define SSL_TKPIDX_RSA1024 (1)
+#define SSL_TKPIDX_DH512 (2)
+#define SSL_TKPIDX_DH1024 (3)
+#define SSL_TKPIDX_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 the SSL pass phrase dialog types
+ */
+typedef enum {
+ SSL_PPTYPE_UNSET = UNSET,
+ SSL_PPTYPE_BUILTIN = 0,
+ SSL_PPTYPE_FILTER = 1
+} 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_FILE = 1,
+ SSL_MUTEXMODE_SEM = 2
+} 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
+#if SSL_LIBRARY_VERSION >= 0x00905100
+ ,SSL_RSSRC_EGD = 4
+#endif
+} 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;
+} ssl_asn1_t;
+
+/*
+ * Define the mod_ssl per-module configuration structure
+ * (i.e. the global configuration for each httpd process)
+ */
+
+typedef struct {
+ pool *pPool;
+ BOOL bFixed;
+ int nInitCount;
+ int nSessionCacheMode;
+ char *szSessionCacheDataFile;
+ int nSessionCacheDataSize;
+ AP_MM *pSessionCacheDataMM;
+ table_t *tSessionCacheDataTable;
+ ssl_mutexmode_t nMutexMode;
+ char *szMutexFile;
+ int nMutexFD;
+ int nMutexSEMID;
+ array_header *aRandSeed;
+ ssl_ds_table *tTmpKeys;
+ void *pTmpKeys[SSL_TKPIDX_MAX];
+ ssl_ds_table *tPublicCert;
+ ssl_ds_table *tPrivateKey;
+#ifdef SSL_EXPERIMENTAL_ENGINE
+ char *szCryptoDevice;
+#endif
+ struct {
+ void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10;
+ } rCtx;
+#ifdef SSL_VENDOR
+ ap_ctx *ctx;
+#endif
+} SSLModConfigRec;
+
+/*
+ * Define the mod_ssl per-server configuration structure
+ * (i.e. the configuration for the main server
+ * and all <VirtualHost> contexts)
+ */
+typedef struct {
+ BOOL bEnabled;
+ char *szPublicCertFile[SSL_AIDX_MAX];
+ char *szPrivateKeyFile[SSL_AIDX_MAX];
+ char *szCertificateChain;
+ char *szCACertificatePath;
+ char *szCACertificateFile;
+ char *szLogFile;
+ char *szCipherSuite;
+ FILE *fileLogFile;
+ int nLogLevel;
+ int nVerifyDepth;
+ ssl_verify_t nVerifyClient;
+ X509 *pPublicCert[SSL_AIDX_MAX];
+ EVP_PKEY *pPrivateKey[SSL_AIDX_MAX];
+ SSL_CTX *pSSLCtx;
+ int nSessionCacheTimeout;
+ int nPassPhraseDialogType;
+ char *szPassPhraseDialogPath;
+ ssl_proto_t nProtocol;
+ char *szCARevocationPath;
+ char *szCARevocationFile;
+ X509_STORE *pRevocationStore;
+#ifdef SSL_EXPERIMENTAL_PROXY
+ /* Configuration details for proxy operation */
+ ssl_proto_t nProxyProtocol;
+ int bProxyVerify;
+ int nProxyVerifyDepth;
+ char *szProxyCACertificatePath;
+ char *szProxyCACertificateFile;
+ char *szProxyClientCertificateFile;
+ char *szProxyClientCertificatePath;
+ char *szProxyCipherSuite;
+ SSL_CTX *pSSLProxyCtx;
+ STACK_OF(X509_INFO) *skProxyClientCerts;
+#endif
+#ifdef SSL_VENDOR
+ ap_ctx *ctx;
+#endif
+} SSLSrvConfigRec;
+
+/*
+ * Define the mod_ssl per-directory configuration structure
+ * (i.e. the local configuration for all <Directory>
+ * and .htaccess contexts)
+ */
+typedef struct {
+ BOOL bSSLRequired;
+ array_header *aRequirement;
+ ssl_opt_t nOptions;
+ ssl_opt_t nOptionsAdd;
+ ssl_opt_t nOptionsDel;
+ char *szCipherSuite;
+ ssl_verify_t nVerifyClient;
+ int nVerifyDepth;
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ char *szCACertificatePath;
+ char *szCACertificateFile;
+#endif
+#ifdef SSL_VENDOR
+ ap_ctx *ctx;
+#endif
+} SSLDirConfigRec;
+
+/*
+ * function prototypes
+ */
+
+/* API glue structures */
+extern module MODULE_VAR_EXPORT ssl_module;
+
+/* configuration handling */
+void ssl_config_global_create(void);
+void ssl_config_global_fix(void);
+BOOL ssl_config_global_isfixed(void);
+void *ssl_config_server_create(pool *, server_rec *);
+void *ssl_config_server_merge(pool *, void *, void *);
+void *ssl_config_perdir_create(pool *, char *);
+void *ssl_config_perdir_merge(pool *, void *, void *);
+const char *ssl_cmd_SSLMutex(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLPassPhraseDialog(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLCryptoDevice(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLRandomSeed(cmd_parms *, char *, char *, char *, char *);
+const char *ssl_cmd_SSLEngine(cmd_parms *, char *, int);
+const char *ssl_cmd_SSLCipherSuite(cmd_parms *, SSLDirConfigRec *, char *);
+const char *ssl_cmd_SSLCertificateFile(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLCACertificatePath(cmd_parms *, SSLDirConfigRec *, char *);
+const char *ssl_cmd_SSLCACertificateFile(cmd_parms *, SSLDirConfigRec *, char *);
+const char *ssl_cmd_SSLCARevocationPath(cmd_parms *, SSLDirConfigRec *, char *);
+const char *ssl_cmd_SSLCARevocationFile(cmd_parms *, SSLDirConfigRec *, char *);
+const char *ssl_cmd_SSLVerifyClient(cmd_parms *, SSLDirConfigRec *, char *);
+const char *ssl_cmd_SSLVerifyDepth(cmd_parms *, SSLDirConfigRec *, char *);
+const char *ssl_cmd_SSLSessionCache(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLSessionCacheTimeout(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLLog(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLLogLevel(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLProtocol(cmd_parms *, char *, const char *);
+const char *ssl_cmd_SSLOptions(cmd_parms *, SSLDirConfigRec *, const char *);
+const char *ssl_cmd_SSLRequireSSL(cmd_parms *, SSLDirConfigRec *, char *);
+const char *ssl_cmd_SSLRequire(cmd_parms *, SSLDirConfigRec *, char *);
+#ifdef SSL_EXPERIMENTAL_PROXY
+const char *ssl_cmd_SSLProxyProtocol(cmd_parms *, char *, const char *);
+const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLProxyVerify(cmd_parms *, char *, int);
+const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, char *, char *);
+const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, char *, char *);
+#endif
+
+/* module initialization */
+void ssl_init_Module(server_rec *, pool *);
+void ssl_init_SSLLibrary(void);
+void ssl_init_Engine(server_rec *, pool *);
+void ssl_init_TmpKeysHandle(int, server_rec *, pool *);
+void ssl_init_ConfigureServer(server_rec *, pool *, SSLSrvConfigRec *);
+void ssl_init_CheckServers(server_rec *, pool *);
+STACK_OF(X509_NAME)
+ *ssl_init_FindCAList(server_rec *, pool *, char *, char *);
+void ssl_init_Child(server_rec *, pool *);
+void ssl_init_ChildKill(void *);
+void ssl_init_ModuleKill(void *);
+
+/* Apache API hooks */
+void ssl_hook_AddModule(module *);
+void ssl_hook_RemoveModule(module *);
+char *ssl_hook_RewriteCommand(cmd_parms *, void *, const char *);
+void ssl_hook_NewConnection(conn_rec *);
+void ssl_hook_TimeoutConnection(int);
+void ssl_hook_CloseConnection(conn_rec *);
+int ssl_hook_Translate(request_rec *);
+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 *);
+int ssl_hook_Handler(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 *, server_rec *);
+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_LogTracingState(SSL *, int, int);
+
+/* Session Cache Support */
+void ssl_scache_init(server_rec *, pool *);
+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 *, pool *, void (*)(char *, void *), void *);
+char *ssl_scache_id2sz(UCHAR *, int);
+void ssl_scache_dbm_init(server_rec *, pool *);
+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 *, pool *, void (*)(char *, void *), void *);
+void ssl_scache_shmht_init(server_rec *, pool *);
+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 *, pool *, void (*)(char *, void *), void *);
+void ssl_scache_shmcb_init(server_rec *, pool *);
+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 *, pool *, void (*)(char *, void *), void *);
+
+/* Pass Phrase Support */
+void ssl_pphrase_Handle(server_rec *, pool *);
+int ssl_pphrase_Handle_CB(char *, int, int);
+
+/* Diffie-Hellman Parameter Support */
+DH *ssl_dh_GetTmpParam(int);
+DH *ssl_dh_GetParamFromFile(char *);
+
+/* Data Structures */
+ssl_ds_array *ssl_ds_array_make(pool *, int);
+BOOL ssl_ds_array_isempty(ssl_ds_array *);
+void *ssl_ds_array_push(ssl_ds_array *);
+void *ssl_ds_array_get(ssl_ds_array *, int);
+void ssl_ds_array_wipeout(ssl_ds_array *);
+void ssl_ds_array_kill(ssl_ds_array *);
+ssl_ds_table *ssl_ds_table_make(pool *, int);
+BOOL ssl_ds_table_isempty(ssl_ds_table *);
+void *ssl_ds_table_push(ssl_ds_table *, char *);
+void *ssl_ds_table_get(ssl_ds_table *, char *);
+void ssl_ds_table_wipeout(ssl_ds_table *);
+void ssl_ds_table_kill(ssl_ds_table *);
+
+/* Mutex Support */
+void ssl_mutex_init(server_rec *, pool *);
+void ssl_mutex_reinit(server_rec *, pool *);
+void ssl_mutex_on(server_rec *);
+void ssl_mutex_off(server_rec *);
+void ssl_mutex_kill(server_rec *s);
+void ssl_mutex_file_create(server_rec *, pool *);
+void ssl_mutex_file_open(server_rec *, pool *);
+void ssl_mutex_file_remove(void *);
+BOOL ssl_mutex_file_acquire(void);
+BOOL ssl_mutex_file_release(void);
+void ssl_mutex_sem_create(server_rec *, pool *);
+void ssl_mutex_sem_open(server_rec *, pool *);
+void ssl_mutex_sem_remove(void *);
+BOOL ssl_mutex_sem_acquire(void);
+BOOL ssl_mutex_sem_release(void);
+
+/* Logfile Support */
+void ssl_log_open(server_rec *, server_rec *, pool *);
+BOOL ssl_log_applies(server_rec *, int);
+void ssl_log(server_rec *, int, const char *, ...);
+void ssl_die(void);
+
+/* Variables */
+void ssl_var_register(void);
+void ssl_var_unregister(void);
+char *ssl_var_lookup(pool *, server_rec *, conn_rec *, request_rec *, char *);
+
+/* I/O */
+void ssl_io_register(void);
+void ssl_io_unregister(void);
+long ssl_io_data_cb(BIO *, int, const char *, int, long, long);
+#ifndef SSL_CONSERVATIVE
+void ssl_io_suck(request_rec *, SSL *);
+#endif
+
+/* PRNG */
+int ssl_rand_seed(server_rec *, pool *, ssl_rsctx_t, char *);
+
+/* Extensions */
+void ssl_ext_register(void);
+void ssl_ext_unregister(void);
+
+/* Compatibility */
+#ifdef SSL_COMPAT
+char *ssl_compat_directive(server_rec *, pool *, const char *);
+void ssl_compat_variables(request_rec *);
+#endif
+
+/* Utility Functions */
+char *ssl_util_server_root_relative(pool *, char *, char *);
+char *ssl_util_vhostid(pool *, 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);
+FILE *ssl_util_ppopen(server_rec *, pool *, char *);
+int ssl_util_ppopen_child(void *, child_info *);
+void ssl_util_ppclose(server_rec *, pool *, FILE *);
+char *ssl_util_readfilter(server_rec *, pool *, char *);
+BOOL ssl_util_path_check(ssl_pathcheck_t, char *);
+ssl_algo_t ssl_util_algotypeof(X509 *, EVP_PKEY *);
+char *ssl_util_algotypestr(ssl_algo_t);
+char *ssl_util_ptxtsub(pool *, const char *, const char *, char *);
+void ssl_util_thread_setup(void);
+
+/* Vendor extension support */
+#if defined(SSL_VENDOR) && defined(SSL_VENDOR_OBJS)
+void ssl_vendor_register(void);
+void ssl_vendor_unregister(void);
+#endif
+
+#endif /* MOD_SSL_H */
diff --git a/modules/ssl/ssl_engine_compat.c b/modules/ssl/ssl_engine_compat.c
new file mode 100644
index 0000000000..a9fe50fdfe
--- /dev/null
+++ b/modules/ssl/ssl_engine_compat.c
@@ -0,0 +1,511 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_compat.c
+** Backward Compatibility
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+ /* ``Backward compatibility is for
+ users who don't want to live
+ on the bleeding edge.''
+ -- Unknown */
+#ifdef SSL_COMPAT
+
+#include "mod_ssl.h"
+
+
+/* _________________________________________________________________
+**
+** Backward Compatibility
+** _________________________________________________________________
+*/
+
+/*
+ * The mapping of obsolete directives to official ones...
+ */
+
+static char *ssl_compat_RequireSSL(pool *, const char *, const char *, const char *);
+static char *ssl_compat_SSLSessionLockFile(pool *, const char *, const char *, const char *);
+static char *ssl_compat_SSLCacheDisable(pool *, const char *, const char *, const char *);
+static char *ssl_compat_SSLRequireCipher(pool *, const char *, const char *, const char *);
+static char *ssl_compat_SSLBanCipher(pool *, const char *, const char *, const char *);
+static char *ssl_compat_SSL_SessionDir(pool *, const char *, const char *, const char *);
+static char *ssl_compat_words2list(pool *, const char *);
+
+#define CRM_BEGIN /* nop */
+#define CRM_ENTRY(what,action) { what, action },
+#define CRM_END { NULL, NULL, NULL, NULL, NULL, NULL }
+#define CRM_CMD(cmd) cmd, NULL, NULL
+#define CRM_STR(str) NULL, str, NULL
+#define CRM_PAT(cmd) NULL, NULL, pat
+#define CRM_LOG(msg) msg, NULL, NULL
+#define CRM_SUB(new) NULL, new, NULL
+#define CRM_CAL(fct) NULL, NULL, fct
+
+static struct {
+ char *cpCommand;
+ char *cpSubstring;
+ char *cpPattern;
+ char *cpMessage;
+ char *cpSubst;
+ char *(*fpSubst)(pool *, const char *, const char *, const char *);
+} ssl_cmd_rewrite_map[] = {
+ CRM_BEGIN
+
+ /*
+ * Apache-SSL 1.x & mod_ssl 2.0.x backward compatibility
+ */
+ CRM_ENTRY( CRM_CMD("SSLEnable"), CRM_SUB("SSLEngine on") )
+ CRM_ENTRY( CRM_CMD("SSLDisable"), CRM_SUB("SSLEngine off") )
+ CRM_ENTRY( CRM_CMD("SSLLogFile"), CRM_SUB("SSLLog") )
+ CRM_ENTRY( CRM_CMD("SSLRequiredCiphers"), CRM_SUB("SSLCipherSuite") )
+ CRM_ENTRY( CRM_CMD("SSLRequireCipher"), CRM_CAL(ssl_compat_SSLRequireCipher) )
+ CRM_ENTRY( CRM_CMD("SSLBanCipher"), CRM_CAL(ssl_compat_SSLBanCipher) )
+ CRM_ENTRY( CRM_CMD("SSLFakeBasicAuth"), CRM_SUB("SSLOptions +FakeBasicAuth") )
+ CRM_ENTRY( CRM_CMD("SSLCacheServerPath"), CRM_LOG("Use SSLSessionCache instead") )
+ CRM_ENTRY( CRM_CMD("SSLCacheServerPort"), CRM_LOG("Use SSLSessionCache instead") )
+
+ /*
+ * Apache-SSL 1.x backward compatibility
+ */
+ CRM_ENTRY( CRM_CMD("SSLExportClientCertificates"), CRM_SUB("SSLOptions +ExportCertData") )
+ CRM_ENTRY( CRM_CMD("SSLCacheServerRunDir"), CRM_LOG("Not needed for mod_ssl") )
+
+ /*
+ * Sioux 1.x backward compatibility
+ */
+ CRM_ENTRY( CRM_CMD("SSL_CertFile"), CRM_SUB("SSLCertificateFile") )
+ CRM_ENTRY( CRM_CMD("SSL_KeyFile"), CRM_SUB("SSLCertificateKeyFile") )
+ CRM_ENTRY( CRM_CMD("SSL_CipherSuite"), CRM_SUB("SSLCipherSuite") )
+ CRM_ENTRY( CRM_CMD("SSL_X509VerifyDir"), CRM_SUB("SSLCACertificatePath") )
+ CRM_ENTRY( CRM_CMD("SSL_Log"), CRM_SUB("SSLLogFile") )
+ CRM_ENTRY( CRM_CMD("SSL_Connect"), CRM_SUB("SSLEngine") )
+ CRM_ENTRY( CRM_CMD("SSL_ClientAuth"), CRM_SUB("SSLVerifyClient") )
+ CRM_ENTRY( CRM_CMD("SSL_X509VerifyDepth"), CRM_SUB("SSLVerifyDepth") )
+ CRM_ENTRY( CRM_CMD("SSL_FetchKeyPhraseFrom"), CRM_LOG("Use SSLPassPhraseDialog instead") )
+ CRM_ENTRY( CRM_CMD("SSL_SessionDir"), CRM_CAL(ssl_compat_SSL_SessionDir) )
+ CRM_ENTRY( CRM_CMD("SSL_Require"), CRM_LOG("Use SSLRequire instead (Syntax!)"))
+ CRM_ENTRY( CRM_CMD("SSL_CertFileType"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSL_KeyFileType"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSL_X509VerifyPolicy"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSL_LogX509Attributes"), CRM_LOG("Not supported by mod_ssl") )
+
+ /*
+ * Stronghold 2.x backward compatibility
+ */
+ CRM_ENTRY( CRM_CMD("StrongholdAccelerator"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("StrongholdKey"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("StrongholdLicenseFile"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSLFlag"), CRM_SUB("SSLEngine") )
+ CRM_ENTRY( CRM_CMD("SSLClientCAfile"), CRM_SUB("SSLCACertificateFile") )
+ CRM_ENTRY( CRM_CMD("SSLSessionLockFile"), CRM_CAL(ssl_compat_SSLSessionLockFile) )
+ CRM_ENTRY( CRM_CMD("SSLCacheDisable"), CRM_CAL(ssl_compat_SSLCacheDisable) )
+ CRM_ENTRY( CRM_CMD("RequireSSL"), CRM_CAL(ssl_compat_RequireSSL) )
+ CRM_ENTRY( CRM_CMD("SSLCipherList"), CRM_SUB("SSLCipherSuite") )
+ CRM_ENTRY( CRM_CMD("SSLErrorFile"), CRM_LOG("Not needed for mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSLRoot"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSL_CertificateLogDir"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("AuthCertDir"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSL_Group"), CRM_LOG("Not supported by mod_ssl") )
+#ifndef SSL_EXPERIMENTAL_PROXY
+ CRM_ENTRY( CRM_CMD("SSLProxyMachineCertPath"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSLProxyMachineCertFile"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSLProxyCACertificatePath"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSLProxyCACertificateFile"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSLProxyVerifyDepth"), CRM_LOG("Not supported by mod_ssl") )
+ CRM_ENTRY( CRM_CMD("SSLProxyCipherList"), CRM_LOG("Not supported by mod_ssl") )
+#else
+ CRM_ENTRY( CRM_CMD("SSLProxyCipherList"), CRM_SUB("SSLProxyCipherSuite") )
+#endif
+
+ CRM_END
+};
+
+static char *ssl_compat_RequireSSL(
+ pool *p, const char *oline, const char *cmd, const char *args)
+{
+ char *cp;
+
+ for (cp = (char *)args; ap_isspace(*cp); cp++)
+ ;
+ if (strcEQ(cp, "on"))
+ return "SSLRequireSSL";
+ return "";
+}
+
+static char *ssl_compat_SSLSessionLockFile(
+ pool *p, const char *oline, const char *cmd, const char *args)
+{
+ char *cp;
+
+ for (cp = (char *)args; ap_isspace(*cp); cp++)
+ ;
+ return ap_pstrcat(p, "SSLMutex file:", cp, NULL);
+}
+
+static char *ssl_compat_SSLCacheDisable(
+ pool *p, const char *oline, const char *cmd, const char *args)
+{
+ char *cp;
+
+ for (cp = (char *)args; ap_isspace(*cp); cp++)
+ ;
+ if (strcEQ(cp, "on"))
+ return "SSLSessionCache none";
+ return "";
+}
+
+static char *ssl_compat_SSLRequireCipher(pool *p, const char *oline, const char *cmd, const char *args)
+{
+ return ap_pstrcat(p, "SSLRequire %{SSL_CIPHER} in {",
+ ssl_compat_words2list(p, args),
+ "}", NULL);
+}
+
+static char *ssl_compat_SSLBanCipher(pool *p, const char *oline, const char *cmd, const char *args)
+{
+ return ap_pstrcat(p, "SSLRequire not (%{SSL_CIPHER} in {",
+ ssl_compat_words2list(p, args),
+ "})", NULL);
+}
+
+static char *ssl_compat_SSL_SessionDir(
+ pool *p, const char *oline, const char *cmd, const char *args)
+{
+ char *cp;
+
+ for (cp = (char *)args; ap_isspace(*cp); cp++)
+ ;
+ return ap_pstrcat(p, "SSLSessionCache dir:", cp, NULL);
+}
+
+static char *ssl_compat_words2list(pool *p, const char *oline)
+{
+ char *line;
+ char *cpB;
+ char *cpE;
+ char *cpI;
+ char *cpO;
+ char n;
+
+ /*
+ * Step 1: Determine borders
+ */
+ cpB = (char *)oline;
+ while (*cpB == ' ' || *cpB == '\t')
+ cpB++;
+ cpE = cpB+strlen(cpB);
+ while (cpE > cpB && (*(cpE-1) == ' ' || *(cpE-1) == '\t'))
+ cpE--;
+
+ /*
+ * Step 2: Determine final size and allocate buffer
+ */
+ for (cpI = cpB, n = 1; cpI < cpE; cpI++)
+ if ((*cpI == ' ' || *cpI == '\t') &&
+ (cpI > cpB && *(cpI-1) != ' ' && *(cpI-1) != '\t'))
+ n++;
+ line = ap_palloc(p, (cpE-cpB)+(n*2)+n+1);
+ cpI = cpB;
+ cpO = line;
+ while (cpI < cpE) {
+ if ( (*cpI != ' ' && *cpI != '\t')
+ && ( cpI == cpB
+ || ( cpI > cpB
+ && (*(cpI-1) == ' ' || *(cpI-1) == '\t')))) {
+ *cpO++ = '"';
+ *cpO++ = *cpI++;
+ }
+ else if ( (*cpI == ' ' || *cpI == '\t')
+ && ( cpI > cpB
+ && (*(cpI-1) != ' ' && *(cpI-1) != '\t'))) {
+ *cpO++ = '"';
+ *cpO++ = ',';
+ *cpO++ = *cpI++;
+ }
+ else {
+ *cpO++ = *cpI++;
+ }
+ }
+ if (cpI > cpB && (*(cpI-1) != ' ' && *(cpI-1) != '\t'))
+ *cpO++ = '"';
+ *cpO++ = NUL;
+ return line;
+}
+
+char *ssl_compat_directive(server_rec *s, pool *p, const char *oline)
+{
+ int i;
+ char *line;
+ char *cp;
+ char caCmd[1024];
+ char *cpArgs;
+ int match;
+
+ /*
+ * Skip comment lines
+ */
+ cp = (char *)oline;
+ while ((*cp == ' ' || *cp == '\t' || *cp == '\n') && (*cp != NUL))
+ cp++;
+ if (*cp == '#' || *cp == NUL)
+ return NULL;
+
+ /*
+ * Extract directive name
+ */
+ cp = (char *)oline;
+ for (i = 0; *cp != ' ' && *cp != '\t' && *cp != NUL && i < 1024; )
+ caCmd[i++] = *cp++;
+ caCmd[i] = NUL;
+ cpArgs = cp;
+
+ /*
+ * Apply rewriting map
+ */
+ line = NULL;
+ for (i = 0; !(ssl_cmd_rewrite_map[i].cpCommand == NULL &&
+ ssl_cmd_rewrite_map[i].cpPattern == NULL ); i++) {
+ /*
+ * Matching
+ */
+ match = FALSE;
+ if (ssl_cmd_rewrite_map[i].cpCommand != NULL) {
+ if (strcEQ(ssl_cmd_rewrite_map[i].cpCommand, caCmd))
+ match = TRUE;
+ }
+ else if (ssl_cmd_rewrite_map[i].cpSubstring != NULL) {
+ if (strstr(oline, ssl_cmd_rewrite_map[i].cpSubstring) != NULL)
+ match = TRUE;
+ }
+ else if (ssl_cmd_rewrite_map[i].cpPattern != NULL) {
+ if (ap_fnmatch(ssl_cmd_rewrite_map[i].cpPattern, oline, 0))
+ match = TRUE;
+ }
+
+ /*
+ * Action Processing
+ */
+ if (match) {
+ if (ssl_cmd_rewrite_map[i].cpMessage != NULL) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, s,
+ "mod_ssl:Compat: OBSOLETE '%s' => %s",
+ oline, ssl_cmd_rewrite_map[i].cpMessage);
+ line = "";
+ break;
+ }
+ else if (ssl_cmd_rewrite_map[i].cpSubst != NULL) {
+ if (ssl_cmd_rewrite_map[i].cpCommand != NULL)
+ line = ap_pstrcat(p, ssl_cmd_rewrite_map[i].cpSubst,
+ cpArgs, NULL);
+ else if (ssl_cmd_rewrite_map[i].cpSubstring != NULL)
+ line = ssl_util_ptxtsub(p, oline, ssl_cmd_rewrite_map[i].cpSubstring,
+ ssl_cmd_rewrite_map[i].cpSubst);
+ else
+ line = ssl_cmd_rewrite_map[i].cpSubst;
+ break;
+ }
+ else if (ssl_cmd_rewrite_map[i].fpSubst != NULL) {
+ line = ((char *(*)(pool *, const char *, const char *, const char *))
+ (ssl_cmd_rewrite_map[i].fpSubst))(p, oline, caCmd, cpArgs);
+ break;
+ }
+ }
+ }
+ if (line != NULL && line[0] != NUL)
+ ap_log_error(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, s,
+ "mod_ssl:Compat: MAPPED '%s' => '%s'", oline, line);
+ return line;
+}
+
+/*
+ * The mapping of obsolete environment variables to official ones...
+ */
+
+#define VRM_BEGIN /* nop */
+#define VRM_ENTRY(var,action) { var, action },
+#define VRM_END { NULL, NULL, NULL }
+#define VRM_VAR(old) old
+#define VRM_SUB(new) new, NULL
+#define VRM_LOG(msg) NULL, msg
+
+static struct {
+ char *cpOld;
+ char *cpNew;
+ char *cpMsg;
+} ssl_var_rewrite_map[] = {
+ VRM_BEGIN
+
+ /*
+ * Apache-SSL 1.x, mod_ssl 2.0.x, Sioux 1.x
+ * and Stronghold 2.x backward compatibility
+ */
+ VRM_ENTRY( VRM_VAR("SSL_PROTOCOL_VERSION"), VRM_SUB("SSL_PROTOCOL") )
+ VRM_ENTRY( VRM_VAR("SSLEAY_VERSION"), VRM_SUB("SSL_VERSION_LIBRARY") )
+ VRM_ENTRY( VRM_VAR("HTTPS_SECRETKEYSIZE"), VRM_SUB("SSL_CIPHER_USEKEYSIZE") )
+ VRM_ENTRY( VRM_VAR("HTTPS_KEYSIZE"), VRM_SUB("SSL_CIPHER_ALGKEYSIZE") )
+ VRM_ENTRY( VRM_VAR("HTTPS_CIPHER"), VRM_SUB("SSL_CIPHER") )
+ VRM_ENTRY( VRM_VAR("HTTPS_EXPORT"), VRM_SUB("SSL_CIPHER_EXPORT") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_KEY_SIZE"), VRM_SUB("SSL_CIPHER_ALGKEYSIZE") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_CERTIFICATE"), VRM_SUB("SSL_SERVER_CERT") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_CERT_START"), VRM_SUB("SSL_SERVER_V_START") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_CERT_END"), VRM_SUB("SSL_SERVER_V_END") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_CERT_SERIAL"), VRM_SUB("SSL_SERVER_M_SERIAL") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_SIGNATURE_ALGORITHM"),VRM_SUB("SSL_SERVER_A_SIG") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_DN"), VRM_SUB("SSL_SERVER_S_DN") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_CN"), VRM_SUB("SSL_SERVER_S_DN_CN") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_EMAIL"), VRM_SUB("SSL_SERVER_S_DN_Email") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_O"), VRM_SUB("SSL_SERVER_S_DN_O") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_OU"), VRM_SUB("SSL_SERVER_S_DN_OU") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_C"), VRM_SUB("SSL_SERVER_S_DN_C") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_SP"), VRM_SUB("SSL_SERVER_S_DN_SP") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_L"), VRM_SUB("SSL_SERVER_S_DN_L") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_IDN"), VRM_SUB("SSL_SERVER_I_DN") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_ICN"), VRM_SUB("SSL_SERVER_I_DN_CN") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_IEMAIL"), VRM_SUB("SSL_SERVER_I_DN_Email") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_IO"), VRM_SUB("SSL_SERVER_I_DN_O") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_IOU"), VRM_SUB("SSL_SERVER_I_DN_OU") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_IC"), VRM_SUB("SSL_SERVER_I_DN_C") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_ISP"), VRM_SUB("SSL_SERVER_I_DN_SP") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_IL"), VRM_SUB("SSL_SERVER_I_DN_L") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_CERTIFICATE"), VRM_SUB("SSL_CLIENT_CERT") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_CERT_START"), VRM_SUB("SSL_CLIENT_V_START") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_CERT_END"), VRM_SUB("SSL_CLIENT_V_END") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_CERT_SERIAL"), VRM_SUB("SSL_CLIENT_M_SERIAL") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_SIGNATURE_ALGORITHM"),VRM_SUB("SSL_CLIENT_A_SIG") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_DN"), VRM_SUB("SSL_CLIENT_S_DN") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_CN"), VRM_SUB("SSL_CLIENT_S_DN_CN") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_EMAIL"), VRM_SUB("SSL_CLIENT_S_DN_Email") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_O"), VRM_SUB("SSL_CLIENT_S_DN_O") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_OU"), VRM_SUB("SSL_CLIENT_S_DN_OU") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_C"), VRM_SUB("SSL_CLIENT_S_DN_C") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_SP"), VRM_SUB("SSL_CLIENT_S_DN_SP") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_L"), VRM_SUB("SSL_CLIENT_S_DN_L") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_IDN"), VRM_SUB("SSL_CLIENT_I_DN") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_ICN"), VRM_SUB("SSL_CLIENT_I_DN_CN") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_IEMAIL"), VRM_SUB("SSL_CLIENT_I_DN_Email") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_IO"), VRM_SUB("SSL_CLIENT_I_DN_O") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_IOU"), VRM_SUB("SSL_CLIENT_I_DN_OU") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_IC"), VRM_SUB("SSL_CLIENT_I_DN_C") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_ISP"), VRM_SUB("SSL_CLIENT_I_DN_SP") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_IL"), VRM_SUB("SSL_CLIENT_I_DN_L") )
+ VRM_ENTRY( VRM_VAR("SSL_EXPORT"), VRM_SUB("SSL_CIPHER_EXPORT") )
+ VRM_ENTRY( VRM_VAR("SSL_KEYSIZE"), VRM_SUB("SSL_CIPHER_ALGKEYSIZE") )
+ VRM_ENTRY( VRM_VAR("SSL_SECRETKEYSIZE"), VRM_SUB("SSL_CIPHER_USEKEYSIZE") )
+ VRM_ENTRY( VRM_VAR("SSL_SSLEAY_VERSION"), VRM_SUB("SSL_VERSION_LIBRARY") )
+
+ VRM_ENTRY( VRM_VAR("SSL_STRONG_CRYPTO"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_KEY_EXP"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_KEY_SIZE"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_KEY_ALGORITHM"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_SESSIONDIR"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_CERTIFICATELOGDIR"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_CERTFILE"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_KEYFILE"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_SERVER_KEYFILETYPE"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_KEY_EXP"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_KEY_ALGORITHM"), VRM_LOG("Not supported by mod_ssl") )
+ VRM_ENTRY( VRM_VAR("SSL_CLIENT_KEY_SIZE"), VRM_LOG("Not supported by mod_ssl") )
+
+ VRM_END
+};
+
+void ssl_compat_variables(request_rec *r)
+{
+ char *cpOld;
+ char *cpNew;
+ char *cpMsg;
+ char *cpVal;
+ int i;
+
+ for (i = 0; ssl_var_rewrite_map[i].cpOld != NULL; i++) {
+ cpOld = ssl_var_rewrite_map[i].cpOld;
+ cpMsg = ssl_var_rewrite_map[i].cpMsg;
+ cpNew = ssl_var_rewrite_map[i].cpNew;
+ if (cpNew != NULL) {
+ cpVal = ssl_var_lookup(r->pool, r->server, r->connection, r, cpNew);
+ if (!strIsEmpty(cpVal))
+ ap_table_set(r->subprocess_env, cpOld, cpVal);
+ }
+ else if (cpMsg != NULL) {
+#ifdef SSL_VENDOR
+ /*
+ * something that isn't provided by mod_ssl, so at least
+ * let vendor extensions provide a reasonable value first.
+ */
+ cpVal = NULL;
+ ap_hook_use("ap::mod_ssl::vendor::compat_variables_lookup",
+ AP_HOOK_SIG3(ptr,ptr,ptr),
+ AP_HOOK_DECLINE(NULL),
+ &cpVal, r, cpOld);
+ if (cpVal != NULL) {
+ ap_table_set(r->subprocess_env, cpOld, cpVal);
+ continue;
+ }
+#endif
+
+ /*
+ * we cannot print a message, so we set at least
+ * the variables content to the compat message
+ */
+ ap_table_set(r->subprocess_env, cpOld, cpMsg);
+ }
+ }
+ return;
+}
+
+#endif /* SSL_COMPAT */
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
new file mode 100644
index 0000000000..c47340b223
--- /dev/null
+++ b/modules/ssl/ssl_engine_config.c
@@ -0,0 +1,1093 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_config.c
+** Apache Configuration Directives
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+ /* ``Damned if you do,
+ damned if you don't.''
+ -- Unknown */
+#include "mod_ssl.h"
+
+
+/* _________________________________________________________________
+**
+** Support for Global Configuration
+** _________________________________________________________________
+*/
+
+void ssl_hook_AddModule(module *m)
+{
+ if (m == &ssl_module) {
+ /*
+ * Announce us for the configuration files
+ */
+ ap_add_config_define("MOD_SSL");
+
+ /*
+ * Link ourself into the Apache kernel
+ */
+ ssl_var_register();
+ ssl_ext_register();
+ ssl_io_register();
+#if defined(SSL_VENDOR) && defined(SSL_VENDOR_OBJS)
+ ssl_vendor_register();
+#endif
+ }
+ return;
+}
+
+void ssl_hook_RemoveModule(module *m)
+{
+ if (m == &ssl_module) {
+ /*
+ * Unlink ourself from the Apache kernel
+ */
+ ssl_var_unregister();
+ ssl_ext_unregister();
+ ssl_io_unregister();
+#if defined(SSL_VENDOR) && defined(SSL_VENDOR_OBJS)
+ ssl_vendor_unregister();
+#endif
+ }
+ return;
+}
+
+void ssl_config_global_create(void)
+{
+ pool *pPool;
+ SSLModConfigRec *mc;
+
+ mc = ap_ctx_get(ap_global_ctx, "ssl_module");
+ if (mc == NULL) {
+ /*
+ * allocate an own subpool which survives server restarts
+ */
+ pPool = ap_make_sub_pool(NULL);
+ mc = (SSLModConfigRec *)ap_palloc(pPool, sizeof(SSLModConfigRec));
+ mc->pPool = pPool;
+ mc->bFixed = FALSE;
+
+ /*
+ * initialize per-module configuration
+ */
+ mc->nInitCount = 0;
+ mc->nSessionCacheMode = SSL_SCMODE_UNSET;
+ mc->szSessionCacheDataFile = NULL;
+ mc->nSessionCacheDataSize = 0;
+ mc->pSessionCacheDataMM = NULL;
+ mc->tSessionCacheDataTable = NULL;
+ mc->nMutexMode = SSL_MUTEXMODE_UNSET;
+ mc->szMutexFile = NULL;
+ mc->nMutexFD = -1;
+ mc->nMutexSEMID = -1;
+ mc->aRandSeed = ap_make_array(pPool, 4, sizeof(ssl_randseed_t));
+ mc->tPrivateKey = ssl_ds_table_make(pPool, sizeof(ssl_asn1_t));
+ mc->tPublicCert = ssl_ds_table_make(pPool, sizeof(ssl_asn1_t));
+ mc->tTmpKeys = ssl_ds_table_make(pPool, sizeof(ssl_asn1_t));
+#ifdef SSL_EXPERIMENTAL_ENGINE
+ mc->szCryptoDevice = NULL;
+#endif
+
+ (void)memset(mc->pTmpKeys, 0, SSL_TKPIDX_MAX*sizeof(void *));
+
+#ifdef SSL_VENDOR
+ mc->ctx = ap_ctx_new(pPool);
+ ap_hook_use("ap::mod_ssl::vendor::config_global_create",
+ AP_HOOK_SIG2(void,ptr), AP_HOOK_MODE_ALL, mc);
+#endif
+
+ /*
+ * And push it into Apache's global context
+ */
+ ap_ctx_set(ap_global_ctx, "ssl_module", mc);
+ }
+ return;
+}
+
+void ssl_config_global_fix(void)
+{
+ SSLModConfigRec *mc = myModConfig();
+ mc->bFixed = TRUE;
+ return;
+}
+
+BOOL ssl_config_global_isfixed(void)
+{
+ SSLModConfigRec *mc = myModConfig();
+ return (mc->bFixed);
+}
+
+
+/* _________________________________________________________________
+**
+** Configuration handling
+** _________________________________________________________________
+*/
+
+/*
+ * Create per-server SSL configuration
+ */
+void *ssl_config_server_create(pool *p, server_rec *s)
+{
+ SSLSrvConfigRec *sc;
+
+ ssl_config_global_create();
+
+ sc = ap_palloc(p, sizeof(SSLSrvConfigRec));
+ sc->bEnabled = UNSET;
+ sc->szCACertificatePath = NULL;
+ sc->szCACertificateFile = NULL;
+ sc->szCertificateChain = NULL;
+ sc->szLogFile = NULL;
+ sc->szCipherSuite = NULL;
+ sc->nLogLevel = SSL_LOG_NONE;
+ sc->nVerifyDepth = UNSET;
+ sc->nVerifyClient = SSL_CVERIFY_UNSET;
+ sc->nSessionCacheTimeout = UNSET;
+ sc->nPassPhraseDialogType = SSL_PPTYPE_UNSET;
+ sc->szPassPhraseDialogPath = NULL;
+ sc->nProtocol = SSL_PROTOCOL_ALL;
+ sc->fileLogFile = NULL;
+ sc->pSSLCtx = NULL;
+ sc->szCARevocationPath = NULL;
+ sc->szCARevocationFile = NULL;
+ sc->pRevocationStore = NULL;
+
+#ifdef SSL_EXPERIMENTAL_PROXY
+ sc->nProxyVerifyDepth = UNSET;
+ sc->szProxyCACertificatePath = NULL;
+ sc->szProxyCACertificateFile = NULL;
+ sc->szProxyClientCertificateFile = NULL;
+ sc->szProxyClientCertificatePath = NULL;
+ sc->szProxyCipherSuite = NULL;
+ sc->nProxyProtocol = SSL_PROTOCOL_ALL & ~SSL_PROTOCOL_TLSV1;
+ sc->bProxyVerify = UNSET;
+ sc->pSSLProxyCtx = NULL;
+#endif
+
+ (void)memset(sc->szPublicCertFile, 0, SSL_AIDX_MAX*sizeof(char *));
+ (void)memset(sc->szPrivateKeyFile, 0, SSL_AIDX_MAX*sizeof(char *));
+ (void)memset(sc->pPublicCert, 0, SSL_AIDX_MAX*sizeof(X509 *));
+ (void)memset(sc->pPrivateKey, 0, SSL_AIDX_MAX*sizeof(EVP_PKEY *));
+
+#ifdef SSL_VENDOR
+ sc->ctx = ap_ctx_new(p);
+ ap_hook_use("ap::mod_ssl::vendor::config_server_create",
+ AP_HOOK_SIG4(void,ptr,ptr,ptr), AP_HOOK_MODE_ALL,
+ p, s, sc);
+#endif
+
+ return sc;
+}
+
+/*
+ * Merge per-server SSL configurations
+ */
+void *ssl_config_server_merge(pool *p, void *basev, void *addv)
+{
+ SSLSrvConfigRec *base = (SSLSrvConfigRec *)basev;
+ SSLSrvConfigRec *add = (SSLSrvConfigRec *)addv;
+ SSLSrvConfigRec *new = (SSLSrvConfigRec *)ap_palloc(p, sizeof(SSLSrvConfigRec));
+ int i;
+
+ cfgMergeBool(bEnabled);
+ cfgMergeString(szCACertificatePath);
+ cfgMergeString(szCACertificateFile);
+ cfgMergeString(szCertificateChain);
+ cfgMergeString(szLogFile);
+ cfgMergeString(szCipherSuite);
+ cfgMerge(nLogLevel, SSL_LOG_NONE);
+ cfgMergeInt(nVerifyDepth);
+ cfgMerge(nVerifyClient, SSL_CVERIFY_UNSET);
+ cfgMergeInt(nSessionCacheTimeout);
+ cfgMerge(nPassPhraseDialogType, SSL_PPTYPE_UNSET);
+ cfgMergeString(szPassPhraseDialogPath);
+ cfgMerge(nProtocol, SSL_PROTOCOL_ALL);
+ cfgMerge(fileLogFile, NULL);
+ cfgMerge(pSSLCtx, NULL);
+ cfgMerge(szCARevocationPath, NULL);
+ cfgMerge(szCARevocationFile, NULL);
+ cfgMerge(pRevocationStore, NULL);
+
+ for (i = 0; i < SSL_AIDX_MAX; i++) {
+ cfgMergeString(szPublicCertFile[i]);
+ cfgMergeString(szPrivateKeyFile[i]);
+ cfgMerge(pPublicCert[i], NULL);
+ cfgMerge(pPrivateKey[i], NULL);
+ }
+
+#ifdef SSL_VENDOR
+ cfgMergeCtx(ctx);
+ ap_hook_use("ap::mod_ssl::vendor::config_server_merge",
+ AP_HOOK_SIG5(void,ptr,ptr,ptr,ptr), AP_HOOK_MODE_ALL,
+ p, base, add, new);
+#endif
+
+#ifdef SSL_EXPERIMENTAL_PROXY
+ cfgMergeInt(nProxyVerifyDepth);
+ cfgMergeString(szProxyCACertificatePath);
+ cfgMergeString(szProxyCACertificateFile);
+ cfgMergeString(szProxyClientCertificateFile);
+ cfgMergeString(szProxyClientCertificatePath);
+ cfgMergeString(szProxyCipherSuite);
+ cfgMerge(nProxyProtocol, (SSL_PROTOCOL_ALL & ~SSL_PROTOCOL_TLSV1));
+ cfgMergeBool(bProxyVerify);
+ cfgMerge(pSSLProxyCtx, NULL);
+#endif
+
+ return new;
+}
+
+/*
+ * Create per-directory SSL configuration
+ */
+void *ssl_config_perdir_create(pool *p, char *dir)
+{
+ SSLDirConfigRec *dc = ap_palloc(p, sizeof(SSLDirConfigRec));
+
+ dc->bSSLRequired = FALSE;
+ dc->aRequirement = ap_make_array(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;
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ dc->szCACertificatePath = NULL;
+ dc->szCACertificateFile = NULL;
+#endif
+
+#ifdef SSL_VENDOR
+ dc->ctx = ap_ctx_new(p);
+ ap_hook_use("ap::mod_ssl::vendor::config_perdir_create",
+ AP_HOOK_SIG4(void,ptr,ptr,ptr), AP_HOOK_MODE_ALL,
+ p, dir, dc);
+#endif
+
+ return dc;
+}
+
+/*
+ * Merge per-directory SSL configurations
+ */
+void *ssl_config_perdir_merge(pool *p, void *basev, void *addv)
+{
+ SSLDirConfigRec *base = (SSLDirConfigRec *)basev;
+ SSLDirConfigRec *add = (SSLDirConfigRec *)addv;
+ SSLDirConfigRec *new = (SSLDirConfigRec *)ap_palloc(p,
+ sizeof(SSLDirConfigRec));
+
+ cfgMerge(bSSLRequired, FALSE);
+ cfgMergeArray(aRequirement);
+
+ if (add->nOptions & SSL_OPT_RELSET) {
+ new->nOptionsAdd = (base->nOptionsAdd & ~(add->nOptionsDel)) | add->nOptionsAdd;
+ new->nOptionsDel = (base->nOptionsDel & ~(add->nOptionsAdd)) | add->nOptionsDel;
+ new->nOptions = (base->nOptions & ~(new->nOptionsDel)) | new->nOptionsAdd;
+ }
+ else {
+ new->nOptions = add->nOptions;
+ new->nOptionsAdd = add->nOptionsAdd;
+ new->nOptionsDel = add->nOptionsDel;
+ }
+
+ cfgMergeString(szCipherSuite);
+ cfgMerge(nVerifyClient, SSL_CVERIFY_UNSET);
+ cfgMergeInt(nVerifyDepth);
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ cfgMergeString(szCACertificatePath);
+ cfgMergeString(szCACertificateFile);
+#endif
+
+#ifdef SSL_VENDOR
+ cfgMergeCtx(ctx);
+ ap_hook_use("ap::mod_ssl::vendor::config_perdir_merge",
+ AP_HOOK_SIG5(void,ptr,ptr,ptr,ptr), AP_HOOK_MODE_ALL,
+ p, base, add, new);
+#endif
+
+ return new;
+}
+
+/*
+ * Directive Rewriting
+ */
+
+char *ssl_hook_RewriteCommand(cmd_parms *cmd, void *config, const char *cmd_line)
+{
+#ifdef SSL_COMPAT
+ return ssl_compat_directive(cmd->server, cmd->pool, cmd_line);
+#else
+ return NULL;
+#endif
+}
+
+/*
+ * Configuration functions for particular directives
+ */
+
+const char *ssl_cmd_SSLMutex(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ const char *err;
+ SSLModConfigRec *mc = myModConfig();
+
+ if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL)
+ return err;
+ if (ssl_config_global_isfixed())
+ return NULL;
+ if (strcEQ(arg, "none")) {
+ mc->nMutexMode = SSL_MUTEXMODE_NONE;
+ }
+ else if (strlen(arg) > 5 && strcEQn(arg, "file:", 5)) {
+#ifndef WIN32
+ mc->nMutexMode = SSL_MUTEXMODE_FILE;
+ mc->szMutexFile = ap_psprintf(mc->pPool, "%s.%lu",
+ ssl_util_server_root_relative(cmd->pool, "mutex", arg+5),
+ (unsigned long)getpid());
+#else
+ return "SSLMutex: Lockfiles not available on this platform";
+#endif
+ }
+ else if (strcEQ(arg, "sem")) {
+#ifdef SSL_CAN_USE_SEM
+ mc->nMutexMode = SSL_MUTEXMODE_SEM;
+#else
+ return "SSLMutex: Semaphores not available on this platform";
+#endif
+ }
+ else
+ return "SSLMutex: Invalid argument";
+ return NULL;
+}
+
+const char *ssl_cmd_SSLPassPhraseDialog(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ const char *err;
+
+ if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL)
+ return err;
+ if (strcEQ(arg, "builtin")) {
+ sc->nPassPhraseDialogType = SSL_PPTYPE_BUILTIN;
+ sc->szPassPhraseDialogPath = NULL;
+ }
+ else if (strlen(arg) > 5 && strEQn(arg, "exec:", 5)) {
+ sc->nPassPhraseDialogType = SSL_PPTYPE_FILTER;
+ sc->szPassPhraseDialogPath = ssl_util_server_root_relative(cmd->pool, "dialog", arg+5);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS, sc->szPassPhraseDialogPath))
+ return ap_pstrcat(cmd->pool, "SSLPassPhraseDialog: file '",
+ sc->szPassPhraseDialogPath, "' not exists", NULL);
+ }
+ else
+ return "SSLPassPhraseDialog: Invalid argument";
+ return NULL;
+}
+
+#ifdef SSL_EXPERIMENTAL_ENGINE
+const char *ssl_cmd_SSLCryptoDevice(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLModConfigRec *mc = myModConfig();
+ 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)) != NULL)
+ return err;
+ if (strcEQ(arg, "builtin")) {
+ mc->szCryptoDevice = NULL;
+ }
+ else if ((e = ENGINE_by_id(arg)) != NULL) {
+ mc->szCryptoDevice = arg;
+ ENGINE_free(e);
+ }
+ else
+ return "SSLCryptoDevice: Invalid argument";
+ return NULL;
+}
+#endif
+
+const char *ssl_cmd_SSLRandomSeed(
+ cmd_parms *cmd, char *struct_ptr, char *arg1, char *arg2, char *arg3)
+{
+ SSLModConfigRec *mc = myModConfig();
+ const char *err;
+ ssl_randseed_t *pRS;
+
+ if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL)
+ return err;
+ if (ssl_config_global_isfixed())
+ return NULL;
+ pRS = ap_push_array(mc->aRandSeed);
+ if (strcEQ(arg1, "startup"))
+ pRS->nCtx = SSL_RSCTX_STARTUP;
+ else if (strcEQ(arg1, "connect"))
+ pRS->nCtx = SSL_RSCTX_CONNECT;
+ else
+ return ap_pstrcat(cmd->pool, "SSLRandomSeed: "
+ "invalid context: `", arg1, "'");
+ if (strlen(arg2) > 5 && strEQn(arg2, "file:", 5)) {
+ pRS->nSrc = SSL_RSSRC_FILE;
+ pRS->cpPath = ap_pstrdup(mc->pPool, ssl_util_server_root_relative(cmd->pool, "random", arg2+5));
+ }
+ else if (strlen(arg2) > 5 && strEQn(arg2, "exec:", 5)) {
+ pRS->nSrc = SSL_RSSRC_EXEC;
+ pRS->cpPath = ap_pstrdup(mc->pPool, ssl_util_server_root_relative(cmd->pool, "random", arg2+5));
+ }
+#if SSL_LIBRARY_VERSION >= 0x00905100
+ else if (strlen(arg2) > 4 && strEQn(arg2, "egd:", 4)) {
+ pRS->nSrc = SSL_RSSRC_EGD;
+ pRS->cpPath = ap_pstrdup(mc->pPool, ssl_util_server_root_relative(cmd->pool, "random", arg2+4));
+ }
+#endif
+ else if (strcEQ(arg2, "builtin")) {
+ pRS->nSrc = SSL_RSSRC_BUILTIN;
+ pRS->cpPath = NULL;
+ }
+ else {
+ pRS->nSrc = SSL_RSSRC_FILE;
+ pRS->cpPath = ap_pstrdup(mc->pPool, ssl_util_server_root_relative(cmd->pool, "random", arg2));
+ }
+ if (pRS->nSrc != SSL_RSSRC_BUILTIN)
+ if (!ssl_util_path_check(SSL_PCM_EXISTS, pRS->cpPath))
+ return ap_pstrcat(cmd->pool, "SSLRandomSeed: source path '",
+ pRS->cpPath, "' not exists", NULL);
+ if (arg3 == NULL)
+ pRS->nBytes = 0; /* read whole file */
+ else {
+ if (pRS->nSrc == SSL_RSSRC_BUILTIN)
+ return "SSLRandomSeed: byte specification not "
+ "allowed for builtin seed source";
+ pRS->nBytes = atoi(arg3);
+ if (pRS->nBytes < 0)
+ return "SSLRandomSeed: invalid number of bytes specified";
+ }
+ return NULL;
+}
+
+const char *ssl_cmd_SSLEngine(
+ cmd_parms *cmd, char *struct_ptr, int flag)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ sc->bEnabled = (flag ? TRUE : FALSE);
+ return NULL;
+}
+
+const char *ssl_cmd_SSLCipherSuite(
+ cmd_parms *cmd, SSLDirConfigRec *dc, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ if (cmd->path == NULL || dc == NULL)
+ sc->szCipherSuite = arg;
+ else
+ dc->szCipherSuite = arg;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLCertificateFile(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+ int i;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLCertificateFile: file '",
+ cpPath, "' not exists or empty", NULL);
+ for (i = 0; i < SSL_AIDX_MAX && sc->szPublicCertFile[i] != NULL; i++)
+ ;
+ if (i == SSL_AIDX_MAX)
+ return ap_psprintf(cmd->pool, "SSLCertificateFile: only up to %d "
+ "different certificates per virtual host allowed",
+ SSL_AIDX_MAX);
+ sc->szPublicCertFile[i] = cpPath;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLCertificateKeyFile(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+ int i;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLCertificateKeyFile: file '",
+ cpPath, "' not exists or empty", NULL);
+ for (i = 0; i < SSL_AIDX_MAX && sc->szPrivateKeyFile[i] != NULL; i++)
+ ;
+ if (i == SSL_AIDX_MAX)
+ return ap_psprintf(cmd->pool, "SSLCertificateKeyFile: only up to %d "
+ "different private keys per virtual host allowed",
+ SSL_AIDX_MAX);
+ sc->szPrivateKeyFile[i] = cpPath;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLCertificateChainFile(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLCertificateChainFile: file '",
+ cpPath, "' not exists or empty", NULL);
+ sc->szCertificateChain = cpPath;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLCACertificatePath(
+ cmd_parms *cmd, SSLDirConfigRec *dc, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLCACertificatePath: directory '",
+ cpPath, "' not exists", NULL);
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ if (cmd->path == NULL || dc == NULL)
+ sc->szCACertificatePath = cpPath;
+ else
+ dc->szCACertificatePath = cpPath;
+#else
+ sc->szCACertificatePath = cpPath;
+#endif
+ return NULL;
+}
+
+const char *ssl_cmd_SSLCACertificateFile(
+ cmd_parms *cmd, SSLDirConfigRec *dc, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLCACertificateFile: file '",
+ cpPath, "' not exists or empty", NULL);
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ if (cmd->path == NULL || dc == NULL)
+ sc->szCACertificateFile = cpPath;
+ else
+ dc->szCACertificateFile = cpPath;
+#else
+ sc->szCACertificateFile = cpPath;
+#endif
+ return NULL;
+}
+
+const char *ssl_cmd_SSLCARevocationPath(
+ cmd_parms *cmd, SSLDirConfigRec *dc, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLCARecocationPath: directory '",
+ cpPath, "' not exists", NULL);
+ sc->szCARevocationPath = cpPath;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLCARevocationFile(
+ cmd_parms *cmd, SSLDirConfigRec *dc, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLCARevocationFile: file '",
+ cpPath, "' not exists or empty", NULL);
+ sc->szCARevocationFile = cpPath;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLVerifyClient(
+ cmd_parms *cmd, SSLDirConfigRec *dc, char *level)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ ssl_verify_t id;
+
+ if (strEQ(level, "0") || strcEQ(level, "none"))
+ id = SSL_CVERIFY_NONE;
+ else if (strEQ(level, "1") || strcEQ(level, "optional"))
+ id = SSL_CVERIFY_OPTIONAL;
+ else if (strEQ(level, "2") || strcEQ(level, "require"))
+ id = SSL_CVERIFY_REQUIRE;
+ else if (strEQ(level, "3") || strcEQ(level, "optional_no_ca"))
+ id = SSL_CVERIFY_OPTIONAL_NO_CA;
+ else
+ return "SSLVerifyClient: Invalid argument";
+ if (cmd->path == NULL || dc == NULL)
+ sc->nVerifyClient = id;
+ else
+ dc->nVerifyClient = id;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLVerifyDepth(
+ cmd_parms *cmd, SSLDirConfigRec *dc, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ int d;
+
+ d = atoi(arg);
+ if (d < 0)
+ return "SSLVerifyDepth: Invalid argument";
+ if (cmd->path == NULL || dc == NULL)
+ sc->nVerifyDepth = d;
+ else
+ dc->nVerifyDepth = d;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLSessionCache(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ const char *err;
+ SSLModConfigRec *mc = myModConfig();
+ char *cp, *cp2;
+ int maxsize;
+
+ if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY)) != NULL)
+ return err;
+ if (ssl_config_global_isfixed())
+ return NULL;
+ if (strcEQ(arg, "none")) {
+ mc->nSessionCacheMode = SSL_SCMODE_NONE;
+ mc->szSessionCacheDataFile = NULL;
+ }
+ else if (strlen(arg) > 4 && strcEQn(arg, "dbm:", 4)) {
+ mc->nSessionCacheMode = SSL_SCMODE_DBM;
+ mc->szSessionCacheDataFile = ap_pstrdup(mc->pPool,
+ ssl_util_server_root_relative(cmd->pool, "scache", arg+4));
+ }
+ else if ( (strlen(arg) > 4 && strcEQn(arg, "shm:", 4))
+ || (strlen(arg) > 6 && strcEQn(arg, "shmht:", 6))) {
+ if (!ap_mm_useable())
+ return "SSLSessionCache: shared memory cache not useable on this platform";
+ mc->nSessionCacheMode = SSL_SCMODE_SHMHT;
+ cp = strchr(arg, ':');
+ mc->szSessionCacheDataFile = ap_pstrdup(mc->pPool,
+ ssl_util_server_root_relative(cmd->pool, "scache", cp+1));
+ mc->tSessionCacheDataTable = NULL;
+ mc->nSessionCacheDataSize = 1024*512; /* 512KB */
+ if ((cp = strchr(mc->szSessionCacheDataFile, '(')) != NULL) {
+ *cp++ = NUL;
+ if ((cp2 = strchr(cp, ')')) == NULL)
+ 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";
+ maxsize = ap_mm_core_maxsegsize();
+ if (mc->nSessionCacheDataSize >= maxsize)
+ return ap_psprintf(cmd->pool, "SSLSessionCache: Invalid argument: "
+ "size has to be < %d bytes on this platform", maxsize);
+ }
+ }
+ else if (strlen(arg) > 6 && strcEQn(arg, "shmcb:", 6)) {
+ if (!ap_mm_useable())
+ return "SSLSessionCache: shared memory cache not useable on this platform";
+ mc->nSessionCacheMode = SSL_SCMODE_SHMCB;
+ mc->szSessionCacheDataFile = ap_pstrdup(mc->pPool,
+ ap_server_root_relative(cmd->pool, arg+6));
+ mc->tSessionCacheDataTable = NULL;
+ mc->nSessionCacheDataSize = 1024*512; /* 512KB */
+ if ((cp = strchr(mc->szSessionCacheDataFile, '(')) != NULL) {
+ *cp++ = NUL;
+ if ((cp2 = strchr(cp, ')')) == NULL)
+ 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";
+ maxsize = ap_mm_core_maxsegsize();
+ if (mc->nSessionCacheDataSize >= maxsize)
+ return ap_psprintf(cmd->pool, "SSLSessionCache: Invalid argument: "
+ "size has to be < %d bytes on this platform", maxsize);
+ }
+ }
+ else
+#ifdef SSL_VENDOR
+ if (!ap_hook_use("ap::mod_ssl::vendor::cmd_sslsessioncache",
+ AP_HOOK_SIG4(void,ptr,ptr,ptr), AP_HOOK_MODE_ALL,
+ cmd, arg, mc))
+#endif
+ return "SSLSessionCache: Invalid argument";
+ return NULL;
+}
+
+const char *ssl_cmd_SSLSessionCacheTimeout(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ sc->nSessionCacheTimeout = atoi(arg);
+ if (sc->nSessionCacheTimeout < 0)
+ return "SSLSessionCacheTimeout: Invalid argument";
+ return NULL;
+}
+
+const char *ssl_cmd_SSLLog(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ const char *err;
+
+ if ((err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIRECTORY
+ |NOT_IN_LOCATION|NOT_IN_FILES )) != NULL)
+ return err;
+ sc->szLogFile = arg;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLLogLevel(
+ cmd_parms *cmd, char *struct_ptr, char *level)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ const char *err;
+
+ if ((err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIRECTORY
+ |NOT_IN_LOCATION|NOT_IN_FILES )) != NULL)
+ return err;
+ if (strcEQ(level, "none"))
+ sc->nLogLevel = SSL_LOG_NONE;
+ else if (strcEQ(level, "error"))
+ sc->nLogLevel = SSL_LOG_ERROR;
+ else if (strcEQ(level, "warn"))
+ sc->nLogLevel = SSL_LOG_WARN;
+ else if (strcEQ(level, "info"))
+ sc->nLogLevel = SSL_LOG_INFO;
+ else if (strcEQ(level, "trace"))
+ sc->nLogLevel = SSL_LOG_TRACE;
+ else if (strcEQ(level, "debug"))
+ sc->nLogLevel = SSL_LOG_DEBUG;
+ else
+ return "SSLLogLevel: Invalid argument";
+ return NULL;
+}
+
+const char *ssl_cmd_SSLOptions(
+ cmd_parms *cmd, SSLDirConfigRec *dc, const char *cpLine)
+{
+ ssl_opt_t opt;
+ int first;
+ char action;
+ char *w;
+
+ first = TRUE;
+ while (cpLine[0] != NUL) {
+ w = ap_getword_conf(cmd->pool, &cpLine);
+ 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 ap_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, SSLDirConfigRec *dc, char *cipher)
+{
+ dc->bSSLRequired = TRUE;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLRequire(
+ cmd_parms *cmd, SSLDirConfigRec *dc, char *cpExpr)
+{
+ ssl_expr *mpExpr;
+ ssl_require_t *pReqRec;
+
+ if ((mpExpr = ssl_expr_comp(cmd->pool, cpExpr)) == NULL)
+ return ap_pstrcat(cmd->pool, "SSLRequire: ", ssl_expr_get_error(), NULL);
+ pReqRec = ap_push_array(dc->aRequirement);
+ pReqRec->cpExpr = ap_pstrdup(cmd->pool, cpExpr);
+ pReqRec->mpExpr = mpExpr;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLProtocol(
+ cmd_parms *cmd, char *struct_ptr, const char *opt)
+{
+ SSLSrvConfigRec *sc;
+ ssl_proto_t options, thisopt;
+ char action;
+ char *w;
+
+ sc = mySrvConfig(cmd->server);
+ options = SSL_PROTOCOL_NONE;
+ while (opt[0] != NUL) {
+ w = ap_getword_conf(cmd->pool, &opt);
+
+ action = NUL;
+ 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 ap_pstrcat(cmd->pool, "SSLProtocol: Illegal protocol '", w, "'", NULL);
+
+ if (action == '-')
+ options &= ~thisopt;
+ else if (action == '+')
+ options |= thisopt;
+ else
+ options = thisopt;
+ }
+ sc->nProtocol = options;
+ return NULL;
+}
+
+#ifdef SSL_EXPERIMENTAL_PROXY
+
+const char *ssl_cmd_SSLProxyProtocol(
+ cmd_parms *cmd, char *struct_ptr, const char *opt)
+{
+ SSLSrvConfigRec *sc;
+ ssl_proto_t options, thisopt;
+ char action;
+ char *w;
+
+ sc = mySrvConfig(cmd->server);
+ options = SSL_PROTOCOL_NONE;
+ while (opt[0] != NUL) {
+ w = ap_getword_conf(cmd->pool, &opt);
+
+ action = NUL;
+ 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 ap_pstrcat(cmd->pool, "SSLProxyProtocol: "
+ "Illegal protocol '", w, "'", NULL);
+ if (action == '-')
+ options &= ~thisopt;
+ else if (action == '+')
+ options |= thisopt;
+ else
+ options = thisopt;
+ }
+ sc->nProxyProtocol = options;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLProxyCipherSuite(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ sc->szProxyCipherSuite = arg;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLProxyVerify(
+ cmd_parms *cmd, char *struct_ptr, int flag)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ sc->bProxyVerify = (flag ? TRUE : FALSE);
+ return NULL;
+}
+
+const char *ssl_cmd_SSLProxyVerifyDepth(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ int d;
+
+ d = atoi(arg);
+ if (d < 0)
+ return "SSLProxyVerifyDepth: Invalid argument";
+ sc->nProxyVerifyDepth = d;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLProxyCACertificateFile(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLProxyCACertificateFile: file '",
+ cpPath, "' not exists or empty", NULL);
+ sc->szProxyCACertificateFile = cpPath;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLProxyCACertificatePath(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLProxyCACertificatePath: directory '",
+ cpPath, "' does not exists", NULL);
+ sc->szProxyCACertificatePath = cpPath;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLProxyMachineCertificateFile(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISREG|SSL_PCM_ISNONZERO, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLProxyMachineCertFile: file '",
+ cpPath, "' not exists or empty", NULL);
+ sc->szProxyClientCertificateFile = cpPath;
+ return NULL;
+}
+
+const char *ssl_cmd_SSLProxyMachineCertificatePath(
+ cmd_parms *cmd, char *struct_ptr, char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ char *cpPath;
+
+ cpPath = ssl_util_server_root_relative(cmd->pool, "certkey", arg);
+ if (!ssl_util_path_check(SSL_PCM_EXISTS|SSL_PCM_ISDIR, cpPath))
+ return ap_pstrcat(cmd->pool, "SSLProxyMachineCertPath: directory '",
+ cpPath, "' does not exists", NULL);
+ sc->szProxyClientCertificatePath = cpPath;
+ return NULL;
+}
+
+#endif /* SSL_EXPERIMENTAL_PROXY */
+
diff --git a/modules/ssl/ssl_engine_dh.c b/modules/ssl/ssl_engine_dh.c
new file mode 100644
index 0000000000..84f49e6657
--- /dev/null
+++ b/modules/ssl/ssl_engine_dh.c
@@ -0,0 +1,255 @@
+#if 0
+=pod
+#endif
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_dh.c
+** Diffie-Hellman Built-in Temporary Parameters
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#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()
+{
+ DH *dh;
+
+ if ((dh = DH_new()) == NULL)
+ return (NULL);
+ dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
+ dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return (NULL);
+ return (dh);
+}
+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()
+{
+ DH *dh;
+
+ if ((dh = DH_new()) == NULL)
+ return (NULL);
+ dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
+ dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return (NULL);
+ return (dh);
+}
+/* ----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 -8 |") || die;
+$dhsource .= $_ while (<FP>);
+close(FP);
+open(FP, "openssl dh -noout -C -in dh1024.pem | indent | expand -8 |") || 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/modules/ssl/ssl_engine_ds.c b/modules/ssl/ssl_engine_ds.c
new file mode 100644
index 0000000000..f0f9e00e48
--- /dev/null
+++ b/modules/ssl/ssl_engine_ds.c
@@ -0,0 +1,195 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_ds.c
+** Additional Data Structures
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``If you can't do it in
+ C or assembly language,
+ it isn't worth doing.''
+ -- Unknown */
+#include "mod_ssl.h"
+
+
+/* _________________________________________________________________
+**
+** Data Structures which store _arbitrary_ data
+** _________________________________________________________________
+*/
+
+ssl_ds_array *ssl_ds_array_make(pool *p, int size)
+{
+ ssl_ds_array *a;
+
+ if ((a = (ssl_ds_array *)ap_palloc(p, sizeof(ssl_ds_array))) == NULL)
+ return NULL;
+ a->pPool = p;
+ if ((a->pSubPool = ap_make_sub_pool(p)) == NULL)
+ return NULL;
+ a->aData = ap_make_array(a->pSubPool, 2, size);
+ return a;
+}
+
+BOOL ssl_ds_array_isempty(ssl_ds_array *a)
+{
+ if (a == NULL || a->aData == NULL || a->aData->nelts == 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void *ssl_ds_array_push(ssl_ds_array *a)
+{
+ void *d;
+
+ d = (void *)ap_push_array(a->aData);
+ return d;
+}
+
+void *ssl_ds_array_get(ssl_ds_array *a, int n)
+{
+ void *d;
+
+ if (n < 0 || n >= a->aData->nelts)
+ return NULL;
+ d = (void *)(a->aData->elts+(a->aData->elt_size*n));
+ return d;
+}
+
+void ssl_ds_array_wipeout(ssl_ds_array *a)
+{
+ if (a->aData->nelts > 0)
+ memset(a->aData->elts, 0, a->aData->elt_size*a->aData->nelts);
+ return;
+}
+
+void ssl_ds_array_kill(ssl_ds_array *a)
+{
+ ap_destroy_pool(a->pSubPool);
+ a->pSubPool = NULL;
+ a->aData = NULL;
+ return;
+}
+
+ssl_ds_table *ssl_ds_table_make(pool *p, int size)
+{
+ ssl_ds_table *t;
+
+ if ((t = (ssl_ds_table *)ap_palloc(p, sizeof(ssl_ds_table))) == NULL)
+ return NULL;
+ t->pPool = p;
+ if ((t->pSubPool = ap_make_sub_pool(p)) == NULL)
+ return NULL;
+ t->aKey = ap_make_array(t->pSubPool, 2, MAX_STRING_LEN);
+ t->aData = ap_make_array(t->pSubPool, 2, size);
+ return t;
+}
+
+BOOL ssl_ds_table_isempty(ssl_ds_table *t)
+{
+ if (t == NULL || t->aKey == NULL || t->aKey->nelts == 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void *ssl_ds_table_push(ssl_ds_table *t, char *key)
+{
+ char *k;
+ void *d;
+
+ k = (char *)ap_push_array(t->aKey);
+ d = (void *)ap_push_array(t->aData);
+ ap_cpystrn(k, key, t->aKey->elt_size);
+ return d;
+}
+
+void *ssl_ds_table_get(ssl_ds_table *t, char *key)
+{
+ char *k;
+ void *d;
+ int i;
+
+ d = NULL;
+ for (i = 0; i < t->aKey->nelts; i++) {
+ k = (t->aKey->elts+(t->aKey->elt_size*i));
+ if (strEQ(k, key)) {
+ d = (void *)(t->aData->elts+(t->aData->elt_size*i));
+ break;
+ }
+ }
+ return d;
+}
+
+void ssl_ds_table_wipeout(ssl_ds_table *t)
+{
+ if (t->aKey->nelts > 0) {
+ memset(t->aKey->elts, 0, t->aKey->elt_size*t->aKey->nelts);
+ memset(t->aData->elts, 0, t->aData->elt_size*t->aData->nelts);
+ }
+ return;
+}
+
+void ssl_ds_table_kill(ssl_ds_table *t)
+{
+ ap_destroy_pool(t->pSubPool);
+ t->pSubPool = NULL;
+ t->aKey = NULL;
+ t->aData = NULL;
+ return;
+}
+
diff --git a/modules/ssl/ssl_engine_ext.c b/modules/ssl/ssl_engine_ext.c
new file mode 100644
index 0000000000..81b283ce40
--- /dev/null
+++ b/modules/ssl/ssl_engine_ext.c
@@ -0,0 +1,808 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_ext.c
+** Extensions to other Apache parts
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``Only those who attempt the absurd
+ can achieve the impossible.''
+ -- Unknown */
+#include "mod_ssl.h"
+
+
+/* _________________________________________________________________
+**
+** SSL Extensions
+** _________________________________________________________________
+*/
+
+static void ssl_ext_mlc_register(void);
+static void ssl_ext_mlc_unregister(void);
+static void ssl_ext_mr_register(void);
+static void ssl_ext_mr_unregister(void);
+static void ssl_ext_mp_register(void);
+static void ssl_ext_mp_unregister(void);
+static void ssl_ext_ms_register(void);
+static void ssl_ext_ms_unregister(void);
+
+void ssl_ext_register(void)
+{
+ ssl_ext_mlc_register();
+ ssl_ext_mr_register();
+ ssl_ext_mp_register();
+ ssl_ext_ms_register();
+ return;
+}
+
+void ssl_ext_unregister(void)
+{
+ ssl_ext_mlc_unregister();
+ ssl_ext_mr_unregister();
+ ssl_ext_mp_unregister();
+ ssl_ext_ms_unregister();
+ return;
+}
+
+/* _________________________________________________________________
+**
+** SSL Extension to mod_log_config
+** _________________________________________________________________
+*/
+
+static char *ssl_ext_mlc_log_c(request_rec *r, char *a);
+static char *ssl_ext_mlc_log_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.
+ */
+static void ssl_ext_mlc_register(void)
+{
+ ap_hook_register("ap::mod_log_config::log_c",
+ ssl_ext_mlc_log_c, AP_HOOK_NOCTX);
+ ap_hook_register("ap::mod_log_config::log_x",
+ ssl_ext_mlc_log_x, AP_HOOK_NOCTX);
+ return;
+}
+
+static void ssl_ext_mlc_unregister(void)
+{
+ ap_hook_unregister("ap::mod_log_config::log_c",
+ ssl_ext_mlc_log_c);
+ ap_hook_unregister("ap::mod_log_config::log_x",
+ ssl_ext_mlc_log_x);
+ return;
+}
+
+/*
+ * implement the %{..}c log function
+ * (we are the only function)
+ */
+static char *ssl_ext_mlc_log_c(request_rec *r, char *a)
+{
+ char *result;
+
+ if (ap_ctx_get(r->connection->client->ctx, "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 = ap_ctx_get(r->connection->client->ctx, "ssl::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 char *ssl_ext_mlc_log_x(request_rec *r, char *a)
+{
+ char *result;
+
+ result = NULL;
+ if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL)
+ result = ssl_var_lookup(r->pool, r->server, r->connection, r, a);
+ if (result != NULL && result[0] == NUL)
+ result = NULL;
+ return result;
+}
+
+/* _________________________________________________________________
+**
+** SSL Extension to mod_rewrite
+** _________________________________________________________________
+*/
+
+static char *ssl_ext_mr_lookup_variable(request_rec *r, char *var);
+
+/*
+ * register us for the mod_rewrite lookup_variable() function
+ */
+static void ssl_ext_mr_register(void)
+{
+ ap_hook_register("ap::mod_rewrite::lookup_variable",
+ ssl_ext_mr_lookup_variable, AP_HOOK_NOCTX);
+ return;
+}
+
+static void ssl_ext_mr_unregister(void)
+{
+ ap_hook_unregister("ap::mod_rewrite::lookup_variable",
+ ssl_ext_mr_lookup_variable);
+ return;
+}
+
+static char *ssl_ext_mr_lookup_variable(request_rec *r, char *var)
+{
+ char *val;
+
+ val = ssl_var_lookup(r->pool, r->server, r->connection, r, var);
+ if (val[0] == NUL)
+ val = NULL;
+ return val;
+}
+
+/* _________________________________________________________________
+**
+** SSL Extension to mod_proxy
+** _________________________________________________________________
+*/
+
+static int ssl_ext_mp_canon(request_rec *, char *);
+static int ssl_ext_mp_handler(request_rec *, void *, char *, char *, int, char *);
+static int ssl_ext_mp_set_destport(request_rec *);
+static char *ssl_ext_mp_new_connection(request_rec *, BUFF *, char *);
+static void ssl_ext_mp_close_connection(void *);
+static int ssl_ext_mp_write_host_header(request_rec *, BUFF *, char *, int, char *);
+#ifdef SSL_EXPERIMENTAL_PROXY
+static void ssl_ext_mp_init(server_rec *, pool *);
+static int ssl_ext_mp_verify_cb(int, X509_STORE_CTX *);
+static int ssl_ext_mp_clientcert_cb(SSL *, X509 **, EVP_PKEY **);
+#endif
+
+/*
+ * register us ...
+ */
+static void ssl_ext_mp_register(void)
+{
+#ifdef SSL_EXPERIMENTAL_PROXY
+ ap_hook_register("ap::mod_proxy::init",
+ ssl_ext_mp_init, AP_HOOK_NOCTX);
+#endif
+ ap_hook_register("ap::mod_proxy::canon",
+ ssl_ext_mp_canon, AP_HOOK_NOCTX);
+ ap_hook_register("ap::mod_proxy::handler",
+ ssl_ext_mp_handler, AP_HOOK_NOCTX);
+ ap_hook_register("ap::mod_proxy::http::handler::set_destport",
+ ssl_ext_mp_set_destport, AP_HOOK_NOCTX);
+ ap_hook_register("ap::mod_proxy::http::handler::new_connection",
+ ssl_ext_mp_new_connection, AP_HOOK_NOCTX);
+ ap_hook_register("ap::mod_proxy::http::handler::write_host_header",
+ ssl_ext_mp_write_host_header, AP_HOOK_NOCTX);
+ return;
+}
+
+static void ssl_ext_mp_unregister(void)
+{
+#ifdef SSL_EXPERIMENTAL_PROXY
+ ap_hook_unregister("ap::mod_proxy::init", ssl_ext_mp_init);
+#endif
+ ap_hook_unregister("ap::mod_proxy::canon", ssl_ext_mp_canon);
+ ap_hook_unregister("ap::mod_proxy::handler", ssl_ext_mp_handler);
+ ap_hook_unregister("ap::mod_proxy::http::handler::set_destport",
+ ssl_ext_mp_set_destport);
+ ap_hook_unregister("ap::mod_proxy::http::handler::new_connection",
+ ssl_ext_mp_new_connection);
+ ap_hook_unregister("ap::mod_proxy::http::handler::write_host_header",
+ ssl_ext_mp_write_host_header);
+ return;
+}
+
+/*
+ * SSL proxy initialization
+ */
+#ifdef SSL_EXPERIMENTAL_PROXY
+static void ssl_ext_mp_init(server_rec *s, pool *p)
+{
+ SSLSrvConfigRec *sc;
+ char *cpVHostID;
+ int nVerify;
+ SSL_CTX *ctx;
+ char *cp;
+ STACK_OF(X509_INFO) *sk;
+
+ /*
+ * Initialize each virtual server
+ */
+ ERR_clear_error();
+ for (; s != NULL; s = s->next) {
+ sc = mySrvConfig(s);
+ cpVHostID = ssl_util_vhostid(p, s);
+
+ if (sc->bProxyVerify == UNSET)
+ sc->bProxyVerify = FALSE;
+
+ /*
+ * Create new SSL context and configure callbacks
+ */
+ if (sc->nProxyProtocol == SSL_PROTOCOL_NONE) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) No Proxy SSL protocols available [hint: SSLProxyProtocol]",
+ cpVHostID);
+ ssl_die();
+ }
+ cp = ap_pstrcat(p, (sc->nProxyProtocol & SSL_PROTOCOL_SSLV2 ? "SSLv2, " : ""),
+ (sc->nProxyProtocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""),
+ (sc->nProxyProtocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : ""), NULL);
+ cp[strlen(cp)-2] = NUL;
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Creating new proxy SSL context (protocols: %s)",
+ cpVHostID, cp);
+ if (sc->nProxyProtocol == SSL_PROTOCOL_SSLV2)
+ ctx = SSL_CTX_new(SSLv2_client_method()); /* only SSLv2 is left */
+ else
+ ctx = SSL_CTX_new(SSLv23_client_method()); /* be more flexible */
+ if (ctx == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to create SSL Proxy context", cpVHostID);
+ ssl_die();
+ }
+ sc->pSSLProxyCtx = ctx;
+ SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ if (!(sc->nProxyProtocol & SSL_PROTOCOL_SSLV2))
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+ if (!(sc->nProxyProtocol & SSL_PROTOCOL_SSLV3))
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
+ if (!(sc->nProxyProtocol & SSL_PROTOCOL_TLSV1))
+ SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
+
+ if (sc->szProxyClientCertificateFile || sc->szProxyClientCertificatePath) {
+ sk = sk_X509_INFO_new_null();
+ if (sc->szProxyClientCertificateFile)
+ SSL_load_CrtAndKeyInfo_file(p, sk, sc->szProxyClientCertificateFile);
+ if (sc->szProxyClientCertificatePath)
+ SSL_load_CrtAndKeyInfo_path(p, sk, sc->szProxyClientCertificatePath);
+ ssl_log(s, SSL_LOG_TRACE, "Init: (%s) loaded %d client certs for SSL proxy",
+ cpVHostID, sk_X509_INFO_num(sk));
+ if (sk_X509_INFO_num(sk) > 0) {
+ SSL_CTX_set_client_cert_cb(ctx, ssl_ext_mp_clientcert_cb);
+ sc->skProxyClientCerts = sk;
+ }
+ }
+
+ /*
+ * Calculate OpenSSL verify type for verifying the remote server
+ * certificate. We either verify it against our list of CA's, or don't
+ * bother at all.
+ */
+ nVerify = SSL_VERIFY_NONE;
+ if (sc->bProxyVerify)
+ nVerify |= SSL_VERIFY_PEER;
+ if ( nVerify & SSL_VERIFY_PEER
+ && sc->szProxyCACertificateFile == NULL
+ && sc->szProxyCACertificatePath == NULL) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) SSLProxyVerify set to On but no CA certificates configured",
+ cpVHostID);
+ ssl_die();
+ }
+ if ( nVerify & SSL_VERIFY_NONE
+ && ( sc->szProxyCACertificateFile != NULL
+ || sc->szProxyCACertificatePath != NULL)) {
+ ssl_log(s, SSL_LOG_WARN,
+ "init: (%s) CA certificates configured but ignored because SSLProxyVerify is Off",
+ cpVHostID);
+ }
+ SSL_CTX_set_verify(ctx, nVerify, ssl_ext_mp_verify_cb);
+
+ /*
+ * Enable session caching. We can safely use the same cache
+ * as used for communicating with the other clients.
+ */
+ SSL_CTX_sess_set_new_cb(sc->pSSLProxyCtx, ssl_callback_NewSessionCacheEntry);
+ SSL_CTX_sess_set_get_cb(sc->pSSLProxyCtx, ssl_callback_GetSessionCacheEntry);
+ SSL_CTX_sess_set_remove_cb(sc->pSSLProxyCtx, ssl_callback_DelSessionCacheEntry);
+
+ /*
+ * Configure SSL Cipher Suite
+ */
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Configuring permitted SSL ciphers for SSL proxy", cpVHostID);
+ if (sc->szProxyCipherSuite != NULL) {
+ if (!SSL_CTX_set_cipher_list(sc->pSSLProxyCtx, sc->szProxyCipherSuite)) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure permitted SSL ciphers for SSL Proxy",
+ cpVHostID);
+ ssl_die();
+ }
+ }
+
+ /*
+ * Configure Client Authentication details
+ */
+ if (sc->szProxyCACertificateFile != NULL || sc->szProxyCACertificatePath != NULL) {
+ ssl_log(s, SSL_LOG_DEBUG,
+ "Init: (%s) Configuring client verification locations for SSL Proxy",
+ cpVHostID);
+ if (!SSL_CTX_load_verify_locations(sc->pSSLProxyCtx,
+ sc->szProxyCACertificateFile,
+ sc->szProxyCACertificatePath)) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure SSL verify locations for SSL proxy",
+ cpVHostID);
+ ssl_die();
+ }
+ }
+ }
+ return;
+}
+#endif /* SSL_EXPERIMENTAL_PROXY */
+
+static int ssl_ext_mp_canon(request_rec *r, char *url)
+{
+ int rc;
+
+ if (strcEQn(url, "https:", 6)) {
+ rc = OK;
+ ap_hook_call("ap::mod_proxy::http::canon",
+ &rc, r, url+6, "https", DEFAULT_HTTPS_PORT);
+ return rc;
+ }
+ return DECLINED;
+}
+
+static int ssl_ext_mp_handler(
+ request_rec *r, void *cr, char *url, char *proxyhost, int proxyport, char *protocol)
+{
+ int rc;
+
+ if (strcEQ(protocol, "https")) {
+ ap_ctx_set(r->ctx, "ssl::proxy::enabled", PTRUE);
+ ap_hook_call("ap::mod_proxy::http::handler",
+ &rc, r, cr, url, proxyhost, proxyport);
+ return rc;
+ }
+ else {
+ ap_ctx_set(r->ctx, "ssl::proxy::enabled", PFALSE);
+ }
+ return DECLINED;
+}
+
+static int ssl_ext_mp_set_destport(request_rec *r)
+{
+ if (ap_ctx_get(r->ctx, "ssl::proxy::enabled") == PTRUE)
+ return DEFAULT_HTTPS_PORT;
+ else
+ return DEFAULT_HTTP_PORT;
+}
+
+static char *ssl_ext_mp_new_connection(request_rec *r, BUFF *fb, char *peer)
+{
+#ifndef SSL_EXPERIMENTAL_PROXY
+ SSL_CTX *ssl_ctx;
+#endif
+ SSL *ssl;
+ char *errmsg;
+ int rc;
+ char *cpVHostID;
+ char *cpVHostMD5;
+#ifdef SSL_EXPERIMENTAL_PROXY
+ SSLSrvConfigRec *sc;
+ char *cp;
+#endif
+
+ if (ap_ctx_get(r->ctx, "ssl::proxy::enabled") == PFALSE)
+ return NULL;
+
+ /*
+ * Find context
+ */
+#ifdef SSL_EXPERIMENTAL_PROXY
+ sc = mySrvConfig(r->server);
+#endif
+ cpVHostID = ssl_util_vhostid(r->pool, r->server);
+
+ /*
+ * Create a SSL context and handle
+ */
+#ifdef SSL_EXPERIMENTAL_PROXY
+ ssl = SSL_new(sc->pSSLProxyCtx);
+#else
+ ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+ ssl = SSL_new(ssl_ctx);
+#endif
+ if (ssl == NULL) {
+ errmsg = ap_psprintf(r->pool, "SSL proxy new failed (%s): peer %s: %s",
+ cpVHostID, peer, ERR_reason_error_string(ERR_get_error()));
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ return errmsg;
+ }
+ SSL_clear(ssl);
+ cpVHostMD5 = ap_md5(r->pool, (unsigned char *)cpVHostID);
+ if (!SSL_set_session_id_context(ssl, (unsigned char *)cpVHostMD5, strlen(cpVHostMD5))) {
+ errmsg = ap_psprintf(r->pool, "Unable to set session id context to `%s': peer %s: %s",
+ cpVHostMD5, peer, ERR_reason_error_string(ERR_get_error()));
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ return errmsg;
+ }
+ SSL_set_fd(ssl, fb->fd);
+#ifdef SSL_EXPERIMENTAL_PROXY
+ SSL_set_app_data(ssl, fb->ctx);
+#endif
+ ap_ctx_set(fb->ctx, "ssl", ssl);
+#ifdef SSL_EXPERIMENTAL_PROXY
+ ap_ctx_set(fb->ctx, "ssl::proxy::server_rec", r->server);
+ ap_ctx_set(fb->ctx, "ssl::proxy::peer", peer);
+ ap_ctx_set(fb->ctx, "ssl::proxy::servername", cpVHostID);
+ ap_ctx_set(fb->ctx, "ssl::proxy::verifyerror", NULL);
+#endif
+
+ /*
+ * Give us a chance to gracefully close the connection
+ */
+ ap_register_cleanup(r->pool, (void *)fb,
+ ssl_ext_mp_close_connection, ssl_ext_mp_close_connection);
+
+ /*
+ * Establish the SSL connection
+ */
+ if ((rc = SSL_connect(ssl)) <= 0) {
+#ifdef SSL_EXPERIMENTAL_PROXY
+ if ((cp = (char *)ap_ctx_get(fb->ctx, "ssl::proxy::verifyerror")) != NULL) {
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ return NULL;
+ }
+#endif
+ errmsg = ap_psprintf(r->pool, "SSL proxy connect failed (%s): peer %s: %s",
+ cpVHostID, peer, ERR_reason_error_string(ERR_get_error()));
+ ssl_log(r->server, SSL_LOG_ERROR, errmsg);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ return errmsg;
+ }
+
+ return NULL;
+}
+
+static void ssl_ext_mp_close_connection(void *_fb)
+{
+ BUFF *fb = _fb;
+ SSL *ssl;
+#ifndef SSL_EXPERIMENTAL_PROXY
+ SSL_CTX *ctx;
+#endif
+
+ ssl = ap_ctx_get(fb->ctx, "ssl");
+ if (ssl != NULL) {
+#ifndef SSL_EXPERIMENTAL_PROXY
+ ctx = SSL_get_SSL_CTX(ssl);
+#endif
+ SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+#ifndef SSL_EXPERIMENTAL_PROXY
+ if (ctx != NULL)
+ SSL_CTX_free(ctx);
+#endif
+ }
+ return;
+}
+
+static int ssl_ext_mp_write_host_header(
+ request_rec *r, BUFF *fb, char *host, int port, char *portstr)
+{
+ if (ap_ctx_get(r->ctx, "ssl::proxy::enabled") == PFALSE)
+ return DECLINED;
+
+ if (portstr != NULL && port != DEFAULT_HTTPS_PORT) {
+ ap_bvputs(fb, "Host: ", host, ":", portstr, "\r\n", NULL);
+ return OK;
+ }
+ return DECLINED;
+}
+
+#ifdef SSL_EXPERIMENTAL_PROXY
+
+/*
+ * Callback for client certificate stuff.
+ * If the remote site sent us a SSLv3 list of acceptable CA's then trawl the
+ * table of client certs and send the first one that matches.
+ */
+static int ssl_ext_mp_clientcert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
+{
+ SSLSrvConfigRec *sc;
+ X509_NAME *xnx;
+ X509_NAME *issuer;
+ X509_INFO *xi;
+ char *peer;
+ char *servername;
+ server_rec *s;
+ ap_ctx *pCtx;
+ STACK_OF(X509_NAME) *sk;
+ STACK_OF(X509_INFO) *pcerts;
+ char *cp;
+ int i, j;
+
+ pCtx = (ap_ctx *)SSL_get_app_data(ssl);
+ s = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
+ peer = ap_ctx_get(pCtx, "ssl::proxy::peer");
+ servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
+
+ sc = mySrvConfig(s);
+ pcerts = sc->skProxyClientCerts;
+
+ ssl_log(s, SSL_LOG_DEBUG,
+ "Proxy client certificate callback: (%s) entered", servername);
+
+ if ((pcerts == NULL) || (sk_X509_INFO_num(pcerts) <= 0)) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Proxy client certificate callback: (%s) "
+ "site wanted client certificate but none available",
+ servername);
+ return 0;
+ }
+
+ sk = SSL_get_client_CA_list(ssl);
+
+ if ((sk == NULL) || (sk_X509_NAME_num(sk) <= 0)) {
+ /*
+ * remote site didn't send us a list of acceptable CA certs,
+ * so lets send the first one we came across
+ */
+ xi = sk_X509_INFO_value(pcerts, 0);
+ cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
+ ssl_log(s, SSL_LOG_DEBUG,
+ "SSL Proxy: (%s) no acceptable CA list, sending %s",
+ servername, cp != NULL ? cp : "-unknown-");
+ free(cp);
+ /* export structures to the caller */
+ *x509 = xi->x509;
+ *pkey = xi->x_pkey->dec_pkey;
+ /* prevent OpenSSL freeing these structures */
+ CRYPTO_add(&((*x509)->references), +1, CRYPTO_LOCK_X509_PKEY);
+ CRYPTO_add(&((*pkey)->references), +1, CRYPTO_LOCK_X509_PKEY);
+ return 1;
+ }
+
+ for (i = 0; i < sk_X509_NAME_num(sk); i++) {
+ xnx = sk_X509_NAME_value(sk, i);
+ for (j = 0; j < sk_X509_INFO_num(pcerts); j++) {
+ xi = sk_X509_INFO_value(pcerts,j);
+ issuer = X509_get_issuer_name(xi->x509);
+ if (X509_NAME_cmp(issuer, xnx) == 0) {
+ cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
+ ssl_log(s, SSL_LOG_DEBUG, "SSL Proxy: (%s) sending %s",
+ servername, cp != NULL ? cp : "-unknown-");
+ free(cp);
+ /* export structures to the caller */
+ *x509 = xi->x509;
+ *pkey = xi->x_pkey->dec_pkey;
+ /* prevent OpenSSL freeing these structures */
+ CRYPTO_add(&((*x509)->references), +1, CRYPTO_LOCK_X509_PKEY);
+ CRYPTO_add(&((*pkey)->references), +1, CRYPTO_LOCK_X509_PKEY);
+ return 1;
+ }
+ }
+ }
+ ssl_log(s, SSL_LOG_TRACE,
+ "Proxy client certificate callback: (%s) "
+ "no client certificate found!?", servername);
+ return 0;
+}
+
+/*
+ * This is the verify callback when we are connecting to a remote SSL server
+ * from the proxy. Information is passed in via the SSL "ctx" app_data
+ * mechanism. We pass in an Apache context in this field, which contains
+ * server_rec of the server making the proxy connection from the
+ * "ssl::proxy::server_rec" context.
+ *
+ * The result of the verification is passed back out to SSLERR via the return
+ * value. We also store the error message in the "proxyverifyfailed" context,
+ * so the caller of SSL_connect() can log a detailed error message.
+ */
+static int ssl_ext_mp_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+ SSLSrvConfigRec *sc;
+ X509 *xs;
+ int errnum;
+ int errdepth;
+ char *cp, *cp2;
+ ap_ctx *pCtx;
+ server_rec *s;
+ SSL *ssl;
+ char *peer;
+ char *servername;
+
+ ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx);
+ pCtx = (ap_ctx *)SSL_get_app_data(ssl);
+ s = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
+ peer = ap_ctx_get(pCtx, "ssl::proxy::peer");
+ servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
+ sc = mySrvConfig(s);
+
+ /*
+ * Unless stated otherwise by the configuration, we really don't
+ * care if the verification was okay or not, so lets return now
+ * before we do anything involving memory or time.
+ */
+ if (sc->bProxyVerify == FALSE)
+ return ok;
+
+ /*
+ * Get verify ingredients
+ */
+ xs = X509_STORE_CTX_get_current_cert(ctx);
+ errnum = X509_STORE_CTX_get_error(ctx);
+ errdepth = X509_STORE_CTX_get_error_depth(ctx);
+
+ /*
+ * Log verification information
+ */
+ cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0);
+ cp2 = X509_NAME_oneline(X509_get_issuer_name(xs), NULL, 0);
+ ssl_log(s, SSL_LOG_DEBUG,
+ "SSL Proxy: (%s) Certificate Verification for remote server %s: "
+ "depth: %d, subject: %s, issuer: %s",
+ servername, peer != NULL ? peer : "-unknown-",
+ errdepth, cp != NULL ? cp : "-unknown-",
+ cp2 != NULL ? cp2 : "-unknown");
+ free(cp);
+ free(cp2);
+
+ /*
+ * If we already know it's not ok, log the real reason
+ */
+ if (!ok) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "SSL Proxy: (%s) Certificate Verification failed for %s: "
+ "Error (%d): %s", servername,
+ peer != NULL ? peer : "-unknown-",
+ errnum, X509_verify_cert_error_string(errnum));
+ ap_ctx_set(pCtx, "ssl::proxy::verifyerror",
+ (void *)X509_verify_cert_error_string(errnum));
+ return ok;
+ }
+
+ /*
+ * Check the depth of the certificate chain
+ */
+ if (sc->nProxyVerifyDepth > 0) {
+ if (errdepth > sc->nProxyVerifyDepth) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "SSL Proxy: (%s) Certificate Verification failed for %s: "
+ "Certificate Chain too long "
+ "(chain has %d certificates, but maximum allowed are only %d)",
+ servername, peer, errdepth, sc->nProxyVerifyDepth);
+ ap_ctx_set(pCtx, "ssl::proxy::verifyerror",
+ (void *)X509_verify_cert_error_string(X509_V_ERR_CERT_CHAIN_TOO_LONG));
+ ok = FALSE;
+ }
+ }
+
+ /*
+ * And finally signal OpenSSL the (perhaps changed) state
+ */
+ return (ok);
+}
+
+#endif /* SSL_EXPERIMENTAL_PROXY */
+
+/* _________________________________________________________________
+**
+** SSL Extension to mod_status
+** _________________________________________________________________
+*/
+
+static void ssl_ext_ms_display(request_rec *, int, int);
+
+static void ssl_ext_ms_register(void)
+{
+ ap_hook_register("ap::mod_status::display", ssl_ext_ms_display, AP_HOOK_NOCTX);
+ return;
+}
+
+static void ssl_ext_ms_unregister(void)
+{
+ ap_hook_unregister("ap::mod_status::display", ssl_ext_ms_display);
+ 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;
+}
+
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
new file mode 100644
index 0000000000..6a27c4af4d
--- /dev/null
+++ b/modules/ssl/ssl_engine_init.c
@@ -0,0 +1,1090 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_init.c
+** Initialization of Servers
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/* ====================================================================
+ * Copyright (c) 1995-1999 Ben Laurie. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by Ben Laurie
+ * for use in the Apache-SSL HTTP server project."
+ *
+ * 4. The name "Apache-SSL Server" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Ben Laurie
+ * for use in the Apache-SSL HTTP server project."
+ *
+ * THIS SOFTWARE IS PROVIDED BY BEN LAURIE ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BEN LAURIE OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``Recursive, adj.;
+ see Recursive.''
+ -- Unknown */
+#include "mod_ssl.h"
+
+
+/* _________________________________________________________________
+**
+** Module Initialization
+** _________________________________________________________________
+*/
+
+/*
+ * Per-module initialization
+ */
+void ssl_init_Module(server_rec *s, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+ SSLSrvConfigRec *sc;
+ server_rec *s2;
+ char *cp;
+
+ mc->nInitCount++;
+
+ /*
+ * Let us cleanup on restarts and exists
+ */
+ ap_register_cleanup(p, s, ssl_init_ModuleKill, ssl_init_ChildKill);
+
+ /*
+ * Any init round fixes the global config
+ */
+ ssl_config_global_create(); /* just to avoid problems */
+ ssl_config_global_fix();
+
+ /*
+ * try to fix the configuration and open the dedicated SSL
+ * logfile as early as possible
+ */
+ for (s2 = s; s2 != NULL; s2 = s2->next) {
+ sc = mySrvConfig(s2);
+
+ /* Fix up stuff that may not have been set */
+ if (sc->bEnabled == UNSET)
+ sc->bEnabled = FALSE;
+ if (sc->nVerifyClient == SSL_CVERIFY_UNSET)
+ sc->nVerifyClient = SSL_CVERIFY_NONE;
+ if (sc->nVerifyDepth == UNSET)
+ sc->nVerifyDepth = 1;
+#ifdef SSL_EXPERIMENTAL_PROXY
+ if (sc->nProxyVerifyDepth == UNSET)
+ sc->nProxyVerifyDepth = 1;
+#endif
+ if (sc->nSessionCacheTimeout == UNSET)
+ sc->nSessionCacheTimeout = SSL_SESSION_CACHE_TIMEOUT;
+ if (sc->nPassPhraseDialogType == SSL_PPTYPE_UNSET)
+ sc->nPassPhraseDialogType = SSL_PPTYPE_BUILTIN;
+
+ /* Open the dedicated SSL logfile */
+ ssl_log_open(s, s2, p);
+ }
+
+ /*
+ * Identification
+ */
+ if (mc->nInitCount == 1) {
+ ssl_log(s, SSL_LOG_INFO, "Server: %s, Interface: %s, Library: %s",
+ SERVER_BASEVERSION,
+ ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_INTERFACE"),
+ ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_LIBRARY"));
+#ifdef WIN32
+ ssl_log(s, SSL_LOG_WARN, "You are using mod_ssl under Win32. "
+ "This combination is *NOT* officially supported. "
+ "Use it at your own risk!");
+#endif
+ }
+
+ /*
+ * Initialization round information
+ */
+ if (mc->nInitCount == 1)
+ ssl_log(s, SSL_LOG_INFO, "Init: 1st startup round (still not detached)");
+ else if (mc->nInitCount == 2)
+ ssl_log(s, SSL_LOG_INFO, "Init: 2nd startup round (already detached)");
+ else
+ ssl_log(s, SSL_LOG_INFO, "Init: %d%s restart round (already detached)",
+ mc->nInitCount-2, (mc->nInitCount-2) == 1 ? "st" : "nd");
+
+#ifdef SSL_VENDOR
+ ap_hook_use("ap::mod_ssl::vendor::init_module",
+ AP_HOOK_SIG3(void,ptr,ptr), AP_HOOK_ALL, s, p);
+#endif
+
+ /*
+ * The initialization phase inside the Apache API is totally bogus.
+ * We actually have three non-trivial problems:
+ *
+ * 1. Under Unix the API does a 2-round initialization of modules while
+ * under Win32 it doesn't. This means we have to make sure that at
+ * least the pass phrase dialog doesn't occur twice. We overcome this
+ * problem by using a counter (mc->nInitCount) which has to
+ * survive the init rounds.
+ *
+ * 2. Between the first and the second round Apache detaches from
+ * the terminal under Unix. This means that our pass phrase dialog
+ * _has_ to be done in the first round and _cannot_ be done in the
+ * second round.
+ *
+ * 3. When Dynamic Shared Object (DSO) mechanism is used under Unix the
+ * module segment (code & data) gets unloaded and re-loaded between
+ * the first and the second round. This means no global data survives
+ * between first and the second init round. We overcome this by using
+ * an entry ("ssl_module") inside the ap_global_ctx.
+ *
+ * The situation as a table:
+ *
+ * Unix/static Unix/DSO Win32 Action Required
+ * (-DSHARED_MODULE) (-DWIN32)
+ * ----------- ----------------- --------- -----------------------------------
+ * - load module - -
+ * init init init SSL library init, Pass Phrase Dialog
+ * detach detach - -
+ * - reload module - -
+ * init init - SSL library init, mod_ssl init
+ *
+ * Ok, now try to solve this totally ugly situation...
+ */
+
+#ifdef SHARED_MODULE
+ ssl_log(s, SSL_LOG_INFO, "Init: %snitializing %s library",
+ mc->nInitCount == 1 ? "I" : "Rei", SSL_LIBRARY_NAME);
+ ssl_init_SSLLibrary();
+#else
+ if (mc->nInitCount <= 2) {
+ ssl_log(s, SSL_LOG_INFO, "Init: %snitializing %s library",
+ mc->nInitCount == 1 ? "I" : "Rei", SSL_LIBRARY_NAME);
+ ssl_init_SSLLibrary();
+ }
+#endif
+ if (mc->nInitCount == 1) {
+ ssl_pphrase_Handle(s, p);
+ ssl_init_TmpKeysHandle(SSL_TKP_GEN, s, p);
+#ifndef WIN32
+ return;
+#endif
+ }
+
+ /*
+ * SSL external crypto device ("engine") support
+ */
+#ifdef SSL_EXPERIMENTAL_ENGINE
+ ssl_init_Engine(s, p);
+#endif
+
+ /*
+ * Warn the user that he should use the session cache.
+ * But we can operate without it, of course.
+ */
+ if (mc->nSessionCacheMode == SSL_SCMODE_UNSET) {
+ ssl_log(s, SSL_LOG_WARN,
+ "Init: Session Cache is not configured [hint: SSLSessionCache]");
+ mc->nSessionCacheMode = SSL_SCMODE_NONE;
+ }
+
+ /*
+ * initialize the mutex handling and session caching
+ */
+ ssl_mutex_init(s, p);
+ ssl_scache_init(s, p);
+
+ /*
+ * Seed the Pseudo Random Number Generator (PRNG)
+ */
+ ssl_rand_seed(s, p, SSL_RSCTX_STARTUP, "Init: ");
+
+ /*
+ * allocate the temporary RSA keys and DH params
+ */
+ ssl_init_TmpKeysHandle(SSL_TKP_ALLOC, s, p);
+
+ /*
+ * initialize servers
+ */
+ ssl_log(s, SSL_LOG_INFO, "Init: Initializing (virtual) servers for SSL");
+ for (s2 = s; s2 != NULL; s2 = s2->next) {
+ sc = mySrvConfig(s2);
+ /*
+ * Either now skip this server when SSL is disabled for
+ * it or give out some information about what we're
+ * configuring.
+ */
+ if (!sc->bEnabled)
+ continue;
+ ssl_log(s2, SSL_LOG_INFO,
+ "Init: Configuring server %s for SSL protocol",
+ ssl_util_vhostid(p, s2));
+
+ /*
+ * Read the server certificate and key
+ */
+ ssl_init_ConfigureServer(s2, p, sc);
+ }
+
+ /*
+ * Configuration consistency checks
+ */
+ ssl_init_CheckServers(s, p);
+
+ /*
+ * Announce mod_ssl and SSL library in HTTP Server field
+ * as ``mod_ssl/X.X.X OpenSSL/X.X.X''
+ */
+ if ((cp = ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_PRODUCT")) != NULL && cp[0] != NUL)
+ ap_add_version_component(cp);
+ ap_add_version_component(ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_INTERFACE"));
+ ap_add_version_component(ssl_var_lookup(p, NULL, NULL, NULL, "SSL_VERSION_LIBRARY"));
+
+ return;
+}
+
+/*
+ * Initialize SSL library (also already needed for the pass phrase dialog)
+ */
+void ssl_init_SSLLibrary(void)
+{
+#ifdef WIN32
+ CRYPTO_malloc_init();
+#endif
+ SSL_load_error_strings();
+ SSL_library_init();
+ ssl_util_thread_setup();
+ X509V3_add_standard_extensions();
+ return;
+}
+
+/*
+ * 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, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+ ENGINE *e;
+
+ if (mc->szCryptoDevice != NULL) {
+ if ((e = ENGINE_by_id(mc->szCryptoDevice)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load Crypto Device API `%s'",
+ mc->szCryptoDevice);
+ 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)) {
+ ssl_log(s, SSL_LOG_ERROR, "Init: Failed to enable Crypto Device API `%s'",
+ mc->szCryptoDevice);
+ ssl_die();
+ }
+ ENGINE_free(e);
+ }
+ return;
+}
+#endif
+
+/*
+ * Handle the Temporary RSA Keys and DH Params
+ */
+void ssl_init_TmpKeysHandle(int action, server_rec *s, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+ ssl_asn1_t *asn1;
+ unsigned char *ucp;
+ RSA *rsa;
+ DH *dh;
+
+ /* Generate Keys and Params */
+ if (action == SSL_TKP_GEN) {
+
+ /* seed PRNG */
+ ssl_rand_seed(s, p, SSL_RSCTX_STARTUP, "Init: ");
+
+ /* generate 512 bit RSA key */
+ ssl_log(s, SSL_LOG_INFO, "Init: Generating temporary RSA private keys (512/1024 bits)");
+ if ((rsa = RSA_generate_key(512, RSA_F4, NULL, NULL)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Failed to generate temporary 512 bit RSA private key");
+ ssl_die();
+ }
+ asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tTmpKeys, "RSA:512");
+ asn1->nData = i2d_RSAPrivateKey(rsa, NULL);
+ asn1->cpData = ap_palloc(mc->pPool, asn1->nData);
+ ucp = asn1->cpData; i2d_RSAPrivateKey(rsa, &ucp); /* 2nd arg increments */
+ RSA_free(rsa);
+
+ /* generate 1024 bit RSA key */
+ if ((rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Failed to generate temporary 1024 bit RSA private key");
+ ssl_die();
+ }
+ asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tTmpKeys, "RSA:1024");
+ asn1->nData = i2d_RSAPrivateKey(rsa, NULL);
+ asn1->cpData = ap_palloc(mc->pPool, asn1->nData);
+ ucp = asn1->cpData; i2d_RSAPrivateKey(rsa, &ucp); /* 2nd arg increments */
+ RSA_free(rsa);
+
+ ssl_log(s, SSL_LOG_INFO, "Init: Configuring temporary DH parameters (512/1024 bits)");
+
+ /* import 512 bit DH param */
+ if ((dh = ssl_dh_GetTmpParam(512)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR, "Init: Failed to import temporary 512 bit DH parameters");
+ ssl_die();
+ }
+ asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tTmpKeys, "DH:512");
+ asn1->nData = i2d_DHparams(dh, NULL);
+ asn1->cpData = ap_palloc(mc->pPool, asn1->nData);
+ ucp = asn1->cpData; i2d_DHparams(dh, &ucp); /* 2nd arg increments */
+ /* no need to free dh, it's static */
+
+ /* import 1024 bit DH param */
+ if ((dh = ssl_dh_GetTmpParam(1024)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR, "Init: Failed to import temporary 1024 bit DH parameters");
+ ssl_die();
+ }
+ asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tTmpKeys, "DH:1024");
+ asn1->nData = i2d_DHparams(dh, NULL);
+ asn1->cpData = ap_palloc(mc->pPool, asn1->nData);
+ ucp = asn1->cpData; i2d_DHparams(dh, &ucp); /* 2nd arg increments */
+ /* no need to free dh, it's static */
+ }
+
+ /* Allocate Keys and Params */
+ else if (action == SSL_TKP_ALLOC) {
+
+ ssl_log(s, SSL_LOG_INFO, "Init: Configuring temporary RSA private keys (512/1024 bits)");
+
+ /* allocate 512 bit RSA key */
+ if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tTmpKeys, "RSA:512")) != NULL) {
+ ucp = asn1->cpData;
+ if ((mc->pTmpKeys[SSL_TKPIDX_RSA512] =
+#if SSL_LIBRARY_VERSION >= 0x00907000
+ (void *)d2i_RSAPrivateKey(NULL, (const unsigned char **)&ucp, asn1->nData)) == NULL) {
+#else
+ (void *)d2i_RSAPrivateKey(NULL, &ucp, asn1->nData)) == NULL) {
+#endif
+ ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load temporary 512 bit RSA private key");
+ ssl_die();
+ }
+ }
+
+ /* allocate 1024 bit RSA key */
+ if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tTmpKeys, "RSA:1024")) != NULL) {
+ ucp = asn1->cpData;
+ if ((mc->pTmpKeys[SSL_TKPIDX_RSA1024] =
+#if SSL_LIBRARY_VERSION >= 0x00907000
+ (void *)d2i_RSAPrivateKey(NULL, (const unsigned char **)&ucp, asn1->nData)) == NULL) {
+#else
+ (void *)d2i_RSAPrivateKey(NULL, &ucp, asn1->nData)) == NULL) {
+#endif
+ ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load temporary 1024 bit RSA private key");
+ ssl_die();
+ }
+ }
+
+ ssl_log(s, SSL_LOG_INFO, "Init: Configuring temporary DH parameters (512/1024 bits)");
+
+ /* allocate 512 bit DH param */
+ if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tTmpKeys, "DH:512")) != NULL) {
+ ucp = asn1->cpData;
+ if ((mc->pTmpKeys[SSL_TKPIDX_DH512] =
+#if SSL_LIBRARY_VERSION >= 0x00907000
+ (void *)d2i_DHparams(NULL, (const unsigned char **)&ucp, asn1->nData)) == NULL) {
+#else
+ (void *)d2i_DHparams(NULL, &ucp, asn1->nData)) == NULL) {
+#endif
+ ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load temporary 512 bit DH parameters");
+ ssl_die();
+ }
+ }
+
+ /* allocate 1024 bit DH param */
+ if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tTmpKeys, "DH:1024")) != NULL) {
+ ucp = asn1->cpData;
+ if ((mc->pTmpKeys[SSL_TKPIDX_DH1024] =
+#if SSL_LIBRARY_VERSION >= 0x00907000
+ (void *)d2i_DHparams(NULL, (const unsigned char **)&ucp, asn1->nData)) == NULL) {
+#else
+ (void *)d2i_DHparams(NULL, &ucp, asn1->nData)) == NULL) {
+#endif
+ ssl_log(s, SSL_LOG_ERROR, "Init: Failed to load temporary 1024 bit DH parameters");
+ ssl_die();
+ }
+ }
+ }
+
+ /* Free Keys and Params */
+ else if (action == SSL_TKP_FREE) {
+ if (mc->pTmpKeys[SSL_TKPIDX_RSA512] != NULL) {
+ RSA_free((RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA512]);
+ mc->pTmpKeys[SSL_TKPIDX_RSA512] = NULL;
+ }
+ if (mc->pTmpKeys[SSL_TKPIDX_RSA1024] != NULL) {
+ RSA_free((RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA1024]);
+ mc->pTmpKeys[SSL_TKPIDX_RSA1024] = NULL;
+ }
+ if (mc->pTmpKeys[SSL_TKPIDX_DH512] != NULL) {
+ DH_free((DH *)mc->pTmpKeys[SSL_TKPIDX_DH512]);
+ mc->pTmpKeys[SSL_TKPIDX_DH512] = NULL;
+ }
+ if (mc->pTmpKeys[SSL_TKPIDX_DH1024] != NULL) {
+ DH_free((DH *)mc->pTmpKeys[SSL_TKPIDX_DH1024]);
+ mc->pTmpKeys[SSL_TKPIDX_DH1024] = NULL;
+ }
+ }
+ return;
+}
+
+/*
+ * Configure a particular server
+ */
+void ssl_init_ConfigureServer(server_rec *s, pool *p, SSLSrvConfigRec *sc)
+{
+ SSLModConfigRec *mc = myModConfig();
+ int nVerify;
+ char *cpVHostID;
+ EVP_PKEY *pKey;
+ SSL_CTX *ctx;
+ STACK_OF(X509_NAME) *skCAList;
+ ssl_asn1_t *asn1;
+ unsigned char *ucp;
+ char *cp;
+ BOOL ok;
+ BOOL bSkipFirst;
+ int isca, pathlen;
+ int i, n;
+
+ /*
+ * Create the server host:port string because we need it a lot
+ */
+ cpVHostID = ssl_util_vhostid(p, s);
+
+ /*
+ * Now check for important parameters and the
+ * possibility that the user forgot to set them.
+ */
+ if (sc->szPublicCertFile[0] == NULL) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) No SSL Certificate set [hint: SSLCertificateFile]",
+ cpVHostID);
+ ssl_die();
+ }
+
+ /*
+ * Check for problematic re-initializations
+ */
+ if (sc->pPublicCert[SSL_AIDX_RSA] != NULL ||
+ sc->pPublicCert[SSL_AIDX_DSA] != NULL ) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) Illegal attempt to re-initialise SSL for server "
+ "(theoretically shouldn't happen!)", cpVHostID);
+ ssl_die();
+ }
+
+ /*
+ * Create the new per-server SSL context
+ */
+ if (sc->nProtocol == SSL_PROTOCOL_NONE) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) No SSL protocols available [hint: SSLProtocol]",
+ cpVHostID);
+ ssl_die();
+ }
+ cp = ap_pstrcat(p, (sc->nProtocol & SSL_PROTOCOL_SSLV2 ? "SSLv2, " : ""),
+ (sc->nProtocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""),
+ (sc->nProtocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : ""), NULL);
+ cp[strlen(cp)-2] = NUL;
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Creating new SSL context (protocols: %s)", cpVHostID, cp);
+ if (sc->nProtocol == SSL_PROTOCOL_SSLV2)
+ ctx = SSL_CTX_new(SSLv2_server_method()); /* only SSLv2 is left */
+ else
+ ctx = SSL_CTX_new(SSLv23_server_method()); /* be more flexible */
+ SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ if (!(sc->nProtocol & SSL_PROTOCOL_SSLV2))
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+ if (!(sc->nProtocol & SSL_PROTOCOL_SSLV3))
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
+ if (!(sc->nProtocol & SSL_PROTOCOL_TLSV1))
+ SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
+ SSL_CTX_set_app_data(ctx, s);
+ sc->pSSLCtx = ctx;
+
+ /*
+ * Configure additional context ingredients
+ */
+ SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
+ if (mc->nSessionCacheMode == SSL_SCMODE_NONE)
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+ else
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
+
+ /*
+ * Configure callbacks for SSL context
+ */
+ nVerify = SSL_VERIFY_NONE;
+ if (sc->nVerifyClient == SSL_CVERIFY_REQUIRE)
+ nVerify |= SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ if ( (sc->nVerifyClient == SSL_CVERIFY_OPTIONAL)
+ || (sc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA) )
+ nVerify |= SSL_VERIFY_PEER;
+ SSL_CTX_set_verify(ctx, nVerify, ssl_callback_SSLVerify);
+ 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);
+ 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_LogTracingState);
+
+ /*
+ * Configure SSL Cipher Suite
+ */
+ if (sc->szCipherSuite != NULL) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Configuring permitted SSL ciphers [%s]",
+ cpVHostID, sc->szCipherSuite);
+ if (!SSL_CTX_set_cipher_list(ctx, sc->szCipherSuite)) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure permitted SSL ciphers",
+ cpVHostID);
+ ssl_die();
+ }
+ }
+
+ /*
+ * Configure Client Authentication details
+ */
+ if (sc->szCACertificateFile != NULL || sc->szCACertificatePath != NULL) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Configuring client authentication", cpVHostID);
+ if (!SSL_CTX_load_verify_locations(ctx,
+ sc->szCACertificateFile,
+ sc->szCACertificatePath)) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure verify locations "
+ "for client authentication", cpVHostID);
+ ssl_die();
+ }
+ if ((skCAList = ssl_init_FindCAList(s, p, sc->szCACertificateFile,
+ sc->szCACertificatePath)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) Unable to determine list of available "
+ "CA certificates for client authentication", cpVHostID);
+ ssl_die();
+ }
+ SSL_CTX_set_client_CA_list(sc->pSSLCtx, skCAList);
+ }
+
+ /*
+ * Configure Certificate Revocation List (CRL) Details
+ */
+ if (sc->szCARevocationFile != NULL || sc->szCARevocationPath != NULL) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Configuring certificate revocation facility", cpVHostID);
+ if ((sc->pRevocationStore =
+ SSL_X509_STORE_create(sc->szCARevocationFile,
+ sc->szCARevocationPath)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure X.509 CRL storage "
+ "for certificate revocation", cpVHostID);
+ ssl_die();
+ }
+ }
+
+ /*
+ * Give a warning when no CAs were configured but client authentication
+ * should take place. This cannot work.
+ */
+ if (sc->nVerifyClient == SSL_CVERIFY_REQUIRE) {
+ skCAList = SSL_CTX_get_client_CA_list(ctx);
+ if (sk_X509_NAME_num(skCAList) == 0)
+ ssl_log(s, SSL_LOG_WARN,
+ "Init: Ops, you want to request client authentication, "
+ "but no CAs are known for verification!? "
+ "[Hint: SSLCACertificate*]");
+ }
+
+ /*
+ * Configure server certificate(s)
+ */
+ ok = FALSE;
+ cp = ap_psprintf(p, "%s:RSA", cpVHostID);
+ if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tPublicCert, cp)) != NULL) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Configuring RSA server certificate", cpVHostID);
+ ucp = asn1->cpData;
+ if ((sc->pPublicCert[SSL_AIDX_RSA] = d2i_X509(NULL, &ucp, asn1->nData)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to import RSA server certificate",
+ cpVHostID);
+ ssl_die();
+ }
+ if (SSL_CTX_use_certificate(ctx, sc->pPublicCert[SSL_AIDX_RSA]) <= 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure RSA server certificate",
+ cpVHostID);
+ ssl_die();
+ }
+ ok = TRUE;
+ }
+ cp = ap_psprintf(p, "%s:DSA", cpVHostID);
+ if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tPublicCert, cp)) != NULL) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Configuring DSA server certificate", cpVHostID);
+ ucp = asn1->cpData;
+ if ((sc->pPublicCert[SSL_AIDX_DSA] = d2i_X509(NULL, &ucp, asn1->nData)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to import DSA server certificate",
+ cpVHostID);
+ ssl_die();
+ }
+ if (SSL_CTX_use_certificate(ctx, sc->pPublicCert[SSL_AIDX_DSA]) <= 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure DSA server certificate",
+ cpVHostID);
+ ssl_die();
+ }
+ ok = TRUE;
+ }
+ if (!ok) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) Ops, no RSA or DSA server certificate found?!", cpVHostID);
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) You have to perform a *full* server restart when you added or removed a certificate and/or key file", cpVHostID);
+ ssl_die();
+ }
+
+ /*
+ * Some information about the certificate(s)
+ */
+ for (i = 0; i < SSL_AIDX_MAX; i++) {
+ if (sc->pPublicCert[i] != NULL) {
+ if (SSL_X509_isSGC(sc->pPublicCert[i])) {
+ ssl_log(s, SSL_LOG_INFO,
+ "Init: (%s) %s server certificate enables "
+ "Server Gated Cryptography (SGC)",
+ cpVHostID, (i == SSL_AIDX_RSA ? "RSA" : "DSA"));
+ }
+ if (SSL_X509_getBC(sc->pPublicCert[i], &isca, &pathlen)) {
+ if (isca)
+ ssl_log(s, SSL_LOG_WARN,
+ "Init: (%s) %s server certificate is a CA certificate "
+ "(BasicConstraints: CA == TRUE !?)",
+ cpVHostID, (i == SSL_AIDX_RSA ? "RSA" : "DSA"));
+ if (pathlen > 0)
+ ssl_log(s, SSL_LOG_WARN,
+ "Init: (%s) %s server certificate is not a leaf certificate "
+ "(BasicConstraints: pathlen == %d > 0 !?)",
+ cpVHostID, (i == SSL_AIDX_RSA ? "RSA" : "DSA"), pathlen);
+ }
+ if (SSL_X509_getCN(p, sc->pPublicCert[i], &cp)) {
+ if (ap_is_fnmatch(cp) &&
+ !ap_fnmatch(cp, s->server_hostname, FNM_PERIOD|FNM_CASE_BLIND)) {
+ ssl_log(s, SSL_LOG_WARN,
+ "Init: (%s) %s server certificate wildcard CommonName (CN) `%s' "
+ "does NOT match server name!?", cpVHostID,
+ (i == SSL_AIDX_RSA ? "RSA" : "DSA"), cp);
+ }
+ else if (strNE(s->server_hostname, cp)) {
+ ssl_log(s, SSL_LOG_WARN,
+ "Init: (%s) %s server certificate CommonName (CN) `%s' "
+ "does NOT match server name!?", cpVHostID,
+ (i == SSL_AIDX_RSA ? "RSA" : "DSA"), cp);
+ }
+ }
+ }
+ }
+
+ /*
+ * Configure server private key(s)
+ */
+ ok = FALSE;
+ cp = ap_psprintf(p, "%s:RSA", cpVHostID);
+ if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tPrivateKey, cp)) != NULL) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Configuring RSA server private key", cpVHostID);
+ ucp = asn1->cpData;
+ if ((sc->pPrivateKey[SSL_AIDX_RSA] =
+ d2i_PrivateKey(EVP_PKEY_RSA, NULL, &ucp, asn1->nData)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to import RSA server private key",
+ cpVHostID);
+ ssl_die();
+ }
+ if (SSL_CTX_use_PrivateKey(ctx, sc->pPrivateKey[SSL_AIDX_RSA]) <= 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure RSA server private key",
+ cpVHostID);
+ ssl_die();
+ }
+ ok = TRUE;
+ }
+ cp = ap_psprintf(p, "%s:DSA", cpVHostID);
+ if ((asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tPrivateKey, cp)) != NULL) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Configuring DSA server private key", cpVHostID);
+ ucp = asn1->cpData;
+ if ((sc->pPrivateKey[SSL_AIDX_DSA] =
+ d2i_PrivateKey(EVP_PKEY_DSA, NULL, &ucp, asn1->nData)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to import DSA server private key",
+ cpVHostID);
+ ssl_die();
+ }
+ if (SSL_CTX_use_PrivateKey(ctx, sc->pPrivateKey[SSL_AIDX_DSA]) <= 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure DSA server private key",
+ cpVHostID);
+ ssl_die();
+ }
+ ok = TRUE;
+ }
+ if (!ok) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) Ops, no RSA or DSA server private key found?!", cpVHostID);
+ ssl_die();
+ }
+
+ /*
+ * Optionally copy DSA parameters for certificate from private key
+ * (see http://www.psy.uq.edu.au/~ftp/Crypto/ssleay/TODO.html)
+ */
+ if ( sc->pPublicCert[SSL_AIDX_DSA] != NULL
+ && sc->pPrivateKey[SSL_AIDX_DSA] != NULL) {
+ pKey = X509_get_pubkey(sc->pPublicCert[SSL_AIDX_DSA]);
+ if ( pKey != NULL
+ && EVP_PKEY_type(pKey->type) == EVP_PKEY_DSA
+ && EVP_PKEY_missing_parameters(pKey))
+ EVP_PKEY_copy_parameters(pKey, sc->pPrivateKey[SSL_AIDX_DSA]);
+ }
+
+ /*
+ * 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 (sc->szCertificateChain != NULL) {
+ bSkipFirst = FALSE;
+ for (i = 0; i < SSL_AIDX_MAX && sc->szPublicCertFile[i] != NULL; i++) {
+ if (strEQ(sc->szPublicCertFile[i], sc->szCertificateChain)) {
+ bSkipFirst = TRUE;
+ break;
+ }
+ }
+ if ((n = SSL_CTX_use_certificate_chain(ctx, sc->szCertificateChain,
+ bSkipFirst, NULL)) < 0) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) Failed to configure CA certificate chain!", cpVHostID);
+ ssl_die();
+ }
+ ssl_log(s, SSL_LOG_TRACE, "Init: (%s) Configuring "
+ "server certificate chain (%d CA certificate%s)", cpVHostID,
+ n, n == 1 ? "" : "s");
+ }
+
+#ifdef SSL_VENDOR
+ ap_hook_use("ap::mod_ssl::vendor::configure_server",
+ AP_HOOK_SIG4(void,ptr,ptr,ptr), AP_HOOK_ALL,
+ s, p, sc);
+#endif
+
+ return;
+}
+
+void ssl_init_CheckServers(server_rec *sm, pool *p)
+{
+ server_rec *s;
+ server_rec **ps;
+ SSLSrvConfigRec *sc;
+ ssl_ds_table *t;
+ pool *sp;
+ char *key;
+ BOOL bConflict;
+
+ /*
+ * Give out warnings when a server has HTTPS configured
+ * for the HTTP port or vice versa
+ */
+ for (s = sm; s != NULL; s = s->next) {
+ sc = mySrvConfig(s);
+ if (sc->bEnabled && s->port == DEFAULT_HTTP_PORT)
+ ssl_log(sm, SSL_LOG_WARN,
+ "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->bEnabled && s->port == DEFAULT_HTTPS_PORT)
+ ssl_log(sm, SSL_LOG_WARN,
+ "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).
+ */
+ sp = ap_make_sub_pool(p);
+ t = ssl_ds_table_make(sp, sizeof(server_rec *));
+ bConflict = FALSE;
+ for (s = sm; s != NULL; s = s->next) {
+ sc = mySrvConfig(s);
+ if (!sc->bEnabled)
+ continue;
+ key = ap_psprintf(sp, "%pA:%u", &s->addrs->host_addr, s->addrs->host_port);
+ ps = ssl_ds_table_get(t, key);
+ if (ps != NULL) {
+ ssl_log(sm, SSL_LOG_WARN,
+ "Init: SSL server IP/port conflict: %s (%s:%d) vs. %s (%s:%d)",
+ ssl_util_vhostid(p, s),
+ (s->defn_name != NULL ? s->defn_name : "unknown"),
+ s->defn_line_number,
+ ssl_util_vhostid(p, *ps),
+ ((*ps)->defn_name != NULL ? (*ps)->defn_name : "unknown"),
+ (*ps)->defn_line_number);
+ bConflict = TRUE;
+ continue;
+ }
+ ps = ssl_ds_table_push(t, key);
+ *ps = s;
+ }
+ ssl_ds_table_kill(t);
+ ap_destroy_pool(sp);
+ if (bConflict)
+ ssl_log(sm, SSL_LOG_WARN,
+ "Init: You should not use name-based virtual hosts in conjunction with SSL!!");
+
+ return;
+}
+
+static int ssl_init_FindCAList_X509NameCmp(X509_NAME **a, X509_NAME **b)
+{
+ return(X509_NAME_cmp(*a, *b));
+}
+
+STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, pool *pp, char *cpCAfile, char *cpCApath)
+{
+ STACK_OF(X509_NAME) *skCAList;
+ STACK_OF(X509_NAME) *sk;
+ DIR *dir;
+ struct DIR_TYPE *direntry;
+ char *cp;
+ pool *p;
+ int n;
+
+ /*
+ * Use a subpool so we don't bloat up the server pool which
+ * is remains in memory for the complete operation time of
+ * the server.
+ */
+ p = ap_make_sub_pool(pp);
+
+ /*
+ * Start with a empty stack/list where new
+ * entries get added in sorted order.
+ */
+ skCAList = sk_X509_NAME_new(ssl_init_FindCAList_X509NameCmp);
+
+ /*
+ * Process CA certificate bundle file
+ */
+ if (cpCAfile != NULL) {
+ sk = SSL_load_client_CA_file(cpCAfile);
+ for(n = 0; sk != NULL && n < sk_X509_NAME_num(sk); n++) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "CA certificate: %s",
+ X509_NAME_oneline(sk_X509_NAME_value(sk, n), NULL, 0));
+ if (sk_X509_NAME_find(skCAList, sk_X509_NAME_value(sk, n)) < 0)
+ sk_X509_NAME_push(skCAList, sk_X509_NAME_value(sk, n));
+ }
+ }
+
+ /*
+ * Process CA certificate path files
+ */
+ if (cpCApath != NULL) {
+ dir = ap_popendir(p, cpCApath);
+ while ((direntry = readdir(dir)) != NULL) {
+ cp = ap_pstrcat(p, cpCApath, "/", direntry->d_name, NULL);
+ sk = SSL_load_client_CA_file(cp);
+ for(n = 0; sk != NULL && n < sk_X509_NAME_num(sk); n++) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "CA certificate: %s",
+ X509_NAME_oneline(sk_X509_NAME_value(sk, n), NULL, 0));
+ if (sk_X509_NAME_find(skCAList, sk_X509_NAME_value(sk, n)) < 0)
+ sk_X509_NAME_push(skCAList, sk_X509_NAME_value(sk, n));
+ }
+ }
+ ap_pclosedir(p, dir);
+ }
+
+ /*
+ * Cleanup
+ */
+ sk_X509_NAME_set_cmp_func(skCAList, NULL);
+ ap_destroy_pool(p);
+
+ return skCAList;
+}
+
+void ssl_init_Child(server_rec *s, pool *p)
+{
+ /* open the mutex lockfile */
+ ssl_mutex_reinit(s, p);
+ return;
+}
+
+void ssl_init_ChildKill(void *data)
+{
+ /* currently nothing to do */
+ return;
+}
+
+void ssl_init_ModuleKill(void *data)
+{
+ SSLSrvConfigRec *sc;
+ server_rec *s = (server_rec *)data;
+
+ /*
+ * Drop the session cache and mutex
+ */
+ ssl_scache_kill(s);
+ ssl_mutex_kill(s);
+
+ /*
+ * Destroy the temporary keys and params
+ */
+ ssl_init_TmpKeysHandle(SSL_TKP_FREE, s, NULL);
+
+ /*
+ * Free the non-pool allocated structures
+ * in the per-server configurations
+ */
+ for (; s != NULL; s = s->next) {
+ sc = mySrvConfig(s);
+ if (sc->pPublicCert[SSL_AIDX_RSA] != NULL) {
+ X509_free(sc->pPublicCert[SSL_AIDX_RSA]);
+ sc->pPublicCert[SSL_AIDX_RSA] = NULL;
+ }
+ if (sc->pPublicCert[SSL_AIDX_DSA] != NULL) {
+ X509_free(sc->pPublicCert[SSL_AIDX_DSA]);
+ sc->pPublicCert[SSL_AIDX_DSA] = NULL;
+ }
+ if (sc->pPrivateKey[SSL_AIDX_RSA] != NULL) {
+ EVP_PKEY_free(sc->pPrivateKey[SSL_AIDX_RSA]);
+ sc->pPrivateKey[SSL_AIDX_RSA] = NULL;
+ }
+ if (sc->pPrivateKey[SSL_AIDX_DSA] != NULL) {
+ EVP_PKEY_free(sc->pPrivateKey[SSL_AIDX_DSA]);
+ sc->pPrivateKey[SSL_AIDX_DSA] = NULL;
+ }
+ if (sc->pSSLCtx != NULL) {
+ SSL_CTX_free(sc->pSSLCtx);
+ sc->pSSLCtx = NULL;
+ }
+ }
+
+ /*
+ * Try to kill the internals of the SSL library.
+ */
+#ifdef SHARED_MODULE
+ ERR_free_strings();
+ ERR_remove_state(0);
+ EVP_cleanup();
+#endif
+
+ return;
+}
+
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
new file mode 100644
index 0000000000..4ba1574ca8
--- /dev/null
+++ b/modules/ssl/ssl_engine_io.c
@@ -0,0 +1,728 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_io.c
+** I/O Functions
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``MY HACK: This universe.
+ Just one little problem:
+ core keeps dumping.''
+ -- Unknown */
+#include "mod_ssl.h"
+
+/* _________________________________________________________________
+**
+** I/O Request Body Sucking and Re-Injection
+** _________________________________________________________________
+*/
+
+#ifndef SSL_CONSERVATIVE
+
+/*
+ * Background:
+ *
+ * 1. When the client sends a HTTP/HTTPS request, Apache's core code
+ * reads only the request line ("METHOD /path HTTP/x.y") and the
+ * attached MIME headers ("Foo: bar") up to the terminating line ("CR
+ * LF"). An attached request body (for instance the data of a POST
+ * method) is _NOT_ read. Instead it is read by mod_cgi's content
+ * handler and directly passed to the CGI script.
+ *
+ * 2. mod_ssl supports per-directory re-configuration of SSL parameters.
+ * This is implemented by performing an SSL renegotiation of the
+ * re-configured parameters after the request is read, but before the
+ * response is sent. In more detail: the renegotiation happens after the
+ * request line and MIME headers were read, but _before_ the attached
+ * request body is read. The reason simply is that in the HTTP protocol
+ * usually there is no acknowledgment step between the headers and the
+ * body (there is the 100-continue feature and the chunking facility
+ * only), so Apache has no API hook for this step.
+ *
+ * 3. the problem now occurs when the client sends a POST request for
+ * URL /foo via HTTPS the server and the server has SSL parameters
+ * re-configured on a per-URL basis for /foo. Then mod_ssl has to
+ * perform an SSL renegotiation after the request was read and before
+ * the response is sent. But the problem is the pending POST body data
+ * in the receive buffer of SSL (which Apache still has not read - it's
+ * pending until mod_cgi sucks it in). When mod_ssl now tries to perform
+ * the renegotiation the pending data leads to an I/O error.
+ *
+ * Solution Idea:
+ *
+ * There are only two solutions: Either to simply state that POST
+ * requests to URLs with SSL re-configurations are not allowed, or to
+ * renegotiate really after the _complete_ request (i.e. including
+ * the POST body) was read. Obviously the latter would be preferred,
+ * but it cannot be done easily inside Apache, because as already
+ * mentioned, there is no API step between the body reading and the body
+ * processing. And even when we mod_ssl would hook directly into the
+ * loop of mod_cgi, we wouldn't solve the problem for other handlers, of
+ * course. So the only general solution is to suck in the pending data
+ * of the request body from the OpenSSL BIO into the Apache BUFF. Then
+ * the renegotiation can be done and after this step Apache can proceed
+ * processing the request as before.
+ *
+ * Solution Implementation:
+ *
+ * We cannot simply suck in the data via an SSL_read-based loop because of
+ * HTTP chunking. Instead we _have_ to use the Apache API for this step which
+ * is aware of HTTP chunking. So the trick is to suck in the pending request
+ * data via the Apache API (which uses Apache's BUFF code and in the
+ * background mod_ssl's I/O glue code) and re-inject it later into the Apache
+ * BUFF code again. This way the data flows twice through the Apache BUFF, of
+ * course. But this way the solution doesn't depend on any Apache specifics
+ * and is fully transparent to Apache modules.
+ */
+
+struct ssl_io_suck_st {
+ BOOL active;
+ char *bufptr;
+ int buflen;
+ char *pendptr;
+ int pendlen;
+};
+
+/* prepare request_rec structure for input sucking */
+static void ssl_io_suck_start(request_rec *r)
+{
+ struct ssl_io_suck_st *ss;
+
+ ss = ap_ctx_get(r->ctx, "ssl::io::suck");
+ if (ss == NULL) {
+ ss = ap_palloc(r->pool, sizeof(struct ssl_io_suck_st));
+ ap_ctx_set(r->ctx, "ssl::io::suck", ss);
+ ss->buflen = 8192;
+ ss->bufptr = ap_palloc(r->pool, ss->buflen);
+ }
+ ss->pendptr = ss->bufptr;
+ ss->pendlen = 0;
+ ss->active = FALSE;
+ return;
+}
+
+/* record a sucked input chunk */
+static void ssl_io_suck_record(request_rec *r, char *buf, int len)
+{
+ struct ssl_io_suck_st *ss;
+
+ if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
+ return;
+ if (((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) < len) {
+ /* "expand" buffer: actually we cannot really expand the buffer
+ here, because Apache's pool system doesn't support expanding chunks
+ of memory. Instead we have to either reuse processed data or
+ allocate a new chunk of memory in advance if we really need more
+ memory. */
+ int newlen;
+ char *newptr;
+
+ if (( (ss->pendptr - ss->bufptr)
+ + ((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) ) >= len) {
+ /* make memory available by reusing already processed data */
+ memmove(ss->bufptr, ss->pendptr, ss->pendlen);
+ ss->pendptr = ss->bufptr;
+ }
+ else {
+ /* too bad, we have to allocate a new larger buffer */
+ newlen = (ss->buflen * 2) + len;
+ newptr = ap_palloc(r->pool, newlen);
+ ss->bufptr = newptr;
+ ss->buflen = newlen;
+ memcpy(ss->bufptr, ss->pendptr, ss->pendlen);
+ ss->pendptr = ss->bufptr;
+ }
+ }
+ memcpy(ss->pendptr+ss->pendlen, buf, len);
+ ss->pendlen += len;
+ return;
+}
+
+/* finish request_rec after input sucking */
+static void ssl_io_suck_end(request_rec *r)
+{
+ struct ssl_io_suck_st *ss;
+
+ if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
+ return;
+ ss->active = TRUE;
+ r->read_body = REQUEST_NO_BODY;
+ r->read_length = 0;
+ r->read_chunked = 0;
+ r->remaining = 0;
+ ap_bsetflag(r->connection->client, B_CHUNK, 0);
+ return;
+}
+
+void ssl_io_suck(request_rec *r, SSL *ssl)
+{
+ int rc;
+ int len;
+ char *buf;
+ int buflen;
+ char c;
+ int sucked;
+
+ if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) == OK) {
+ if (ap_should_client_block(r)) {
+
+ /* read client request block through Apache API */
+ buflen = HUGE_STRING_LEN;
+ buf = ap_palloc(r->pool, buflen);
+ ap_hard_timeout("SSL I/O request body pre-sucking", r);
+ sucked = 0;
+ ssl_io_suck_start(r);
+ while ((len = ap_get_client_block(r, buf, buflen)) > 0) {
+ ssl_io_suck_record(r, buf, len);
+ sucked += len;
+ }
+ ssl_io_suck_end(r);
+ ap_kill_timeout(r);
+
+ /* suck trailing data (usually CR LF) which
+ is still in the Apache BUFF layer */
+ while (ap_bpeekc(r->connection->client) != EOF) {
+ c = ap_bgetc(r->connection->client);
+ ssl_io_suck_record(r, &c, 1);
+ sucked++;
+ }
+
+ ssl_log(r->server, SSL_LOG_TRACE,
+ "I/O: sucked %d bytes of input data from SSL/TLS I/O layer "
+ "for delayed injection into Apache I/O layer", sucked);
+ }
+ }
+ return;
+}
+
+/* the SSL_read replacement routine which knows about the suck buffer */
+static int ssl_io_suck_read(SSL *ssl, char *buf, int len)
+{
+ ap_ctx *actx;
+ struct ssl_io_suck_st *ss;
+ request_rec *r = NULL;
+ int rv;
+
+ actx = (ap_ctx *)SSL_get_app_data2(ssl);
+ if (actx != NULL)
+ r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec");
+
+ rv = -1;
+ if (r != NULL) {
+ ss = ap_ctx_get(r->ctx, "ssl::io::suck");
+ if (ss != NULL) {
+ if (ss->active && ss->pendlen > 0) {
+ /* ok, there is pre-sucked data */
+ len = (ss->pendlen > len ? len : ss->pendlen);
+ memcpy(buf, ss->pendptr, len);
+ ss->pendptr += len;
+ ss->pendlen -= len;
+ ssl_log(r->server, SSL_LOG_TRACE,
+ "I/O: injecting %d bytes of pre-sucked data "
+ "into Apache I/O layer", len);
+ rv = len;
+ }
+ }
+ }
+ if (rv == -1)
+ rv = SSL_read(ssl, buf, len);
+ return rv;
+}
+
+/* override SSL_read in the following code... */
+#define SSL_read ssl_io_suck_read
+
+#endif /* !SSL_CONSERVATIVE */
+
+/* _________________________________________________________________
+**
+** I/O Hooks
+** _________________________________________________________________
+*/
+
+#ifndef NO_WRITEV
+#include <sys/types.h>
+#include <sys/uio.h>
+#endif
+
+static int ssl_io_hook_read(BUFF *fb, char *buf, int len);
+static int ssl_io_hook_write(BUFF *fb, char *buf, int len);
+#ifndef NO_WRITEV
+static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt);
+#endif
+#ifdef WIN32
+static int ssl_io_hook_recvwithtimeout(BUFF *fb, char *buf, int len);
+static int ssl_io_hook_sendwithtimeout(BUFF *fb, const char *buf, int len);
+#endif /* WIN32 */
+
+void ssl_io_register(void)
+{
+ ap_hook_register("ap::buff::read", ssl_io_hook_read, AP_HOOK_NOCTX);
+ ap_hook_register("ap::buff::write", ssl_io_hook_write, AP_HOOK_NOCTX);
+#ifndef NO_WRITEV
+ ap_hook_register("ap::buff::writev", ssl_io_hook_writev, AP_HOOK_NOCTX);
+#endif
+#ifdef WIN32
+ ap_hook_register("ap::buff::recvwithtimeout",
+ ssl_io_hook_recvwithtimeout, AP_HOOK_NOCTX);
+ ap_hook_register("ap::buff::sendwithtimeout",
+ ssl_io_hook_sendwithtimeout, AP_HOOK_NOCTX);
+#endif
+ return;
+}
+
+void ssl_io_unregister(void)
+{
+ ap_hook_unregister("ap::buff::read", ssl_io_hook_read);
+ ap_hook_unregister("ap::buff::write", ssl_io_hook_write);
+#ifndef NO_WRITEV
+ ap_hook_unregister("ap::buff::writev", ssl_io_hook_writev);
+#endif
+#ifdef WIN32
+ ap_hook_unregister("ap::buff::recvwithtimeout", ssl_io_hook_recvwithtimeout);
+ ap_hook_unregister("ap::buff::sendwithtimeout", ssl_io_hook_sendwithtimeout);
+#endif
+ return;
+}
+
+static int ssl_io_hook_read(BUFF *fb, char *buf, int len)
+{
+ SSL *ssl;
+ conn_rec *c;
+ int rc;
+
+ if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
+ rc = SSL_read(ssl, buf, len);
+ /*
+ * Simulate an EINTR in case OpenSSL wants to read more.
+ * (This is usually the case when the client forces an SSL
+ * renegotation which is handled implicitly by OpenSSL.)
+ */
+ if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_READ)
+ errno = EINTR;
+ /*
+ * Log SSL errors
+ */
+ if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {
+ c = (conn_rec *)SSL_get_app_data(ssl);
+ ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "SSL error on reading data");
+ }
+ /*
+ * read(2) returns only the generic error number -1
+ */
+ if (rc < 0)
+ rc = -1;
+ }
+ else
+ rc = read(fb->fd_in, buf, len);
+ return rc;
+}
+
+static int ssl_io_hook_write(BUFF *fb, char *buf, int len)
+{
+ SSL *ssl;
+ conn_rec *c;
+ int rc;
+
+ if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
+ rc = SSL_write(ssl, buf, len);
+ /*
+ * Simulate an EINTR in case OpenSSL wants to write more.
+ */
+ if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE)
+ errno = EINTR;
+ /*
+ * Log SSL errors
+ */
+ if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {
+ c = (conn_rec *)SSL_get_app_data(ssl);
+ ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "SSL error on writing data");
+ }
+ /*
+ * write(2) returns only the generic error number -1
+ */
+ if (rc < 0)
+ rc = -1;
+ }
+ else
+ rc = write(fb->fd, buf, len);
+ return rc;
+}
+
+#ifndef NO_WRITEV
+/* the prototype for our own SSL_writev() */
+static int SSL_writev(SSL *, const struct iovec *, int);
+
+static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt)
+{
+ SSL *ssl;
+ conn_rec *c;
+ int rc;
+
+ if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
+ rc = SSL_writev(ssl, iov, iovcnt);
+ /*
+ * Simulate an EINTR in case OpenSSL wants to write more.
+ */
+ if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE)
+ errno = EINTR;
+ /*
+ * Log SSL errors
+ */
+ if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {
+ c = (conn_rec *)SSL_get_app_data(ssl);
+ ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "SSL error on writing data");
+ }
+ /*
+ * writev(2) returns only the generic error number -1
+ */
+ if (rc < 0)
+ rc = -1;
+ }
+ else
+ rc = writev(fb->fd, iov, iovcnt);
+ return rc;
+}
+#endif
+
+#ifdef WIN32
+
+/* these two functions are exported from buff.c under WIN32 */
+API_EXPORT(int) sendwithtimeout(int sock, const char *buf, int len, int flags);
+API_EXPORT(int) recvwithtimeout(int sock, char *buf, int len, int flags);
+
+/* and the prototypes for our SSL_xxx variants */
+static int SSL_sendwithtimeout(BUFF *fb, const char *buf, int len);
+static int SSL_recvwithtimeout(BUFF *fb, char *buf, int len);
+
+static int ssl_io_hook_recvwithtimeout(BUFF *fb, char *buf, int len)
+{
+ SSL *ssl;
+ int rc;
+
+ if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL)
+ rc = SSL_recvwithtimeout(fb, buf, len);
+ else
+ rc = recvwithtimeout(fb->fd, buf, len, 0);
+ return rc;
+}
+
+static int ssl_io_hook_sendwithtimeout(BUFF *fb, const char *buf, int len)
+{
+ SSL *ssl;
+ int rc;
+
+ if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL)
+ rc = SSL_sendwithtimeout(fb, buf, len);
+ else
+ rc = sendwithtimeout(fb->fd, buf, len, 0);
+ return rc;
+}
+
+#endif /* WIN32 */
+
+/* _________________________________________________________________
+**
+** Special Functions for OpenSSL
+** _________________________________________________________________
+*/
+
+#ifdef WIN32
+
+static int SSL_sendwithtimeout(BUFF *fb, const char *buf, int len)
+{
+ int iostate = 1;
+ fd_set fdset;
+ struct timeval tv;
+ int err = WSAEWOULDBLOCK;
+ int rv;
+ int retry;
+ int sock = fb->fd;
+ SSL *ssl;
+
+ ssl = ap_ctx_get(fb->ctx, "ssl");
+
+ if (!(tv.tv_sec = ap_check_alarm()))
+ return (SSL_write(ssl, (char*)buf, len));
+
+ rv = ioctlsocket(sock, FIONBIO, &iostate);
+ iostate = 0;
+ if (rv) {
+ err = WSAGetLastError();
+ ap_assert(0);
+ }
+ rv = SSL_write(ssl, (char*)buf, len);
+ if (rv <= 0) {
+ if (BIO_sock_should_retry(rv)) {
+ do {
+ retry = 0;
+ FD_ZERO(&fdset);
+ FD_SET((unsigned int)sock, &fdset);
+ tv.tv_usec = 0;
+ rv = select(FD_SETSIZE, NULL, &fdset, NULL, &tv);
+ if (rv == SOCKET_ERROR)
+ err = WSAGetLastError();
+ else if (rv == 0) {
+ ioctlsocket(sock, FIONBIO, &iostate);
+ if(ap_check_alarm() < 0) {
+ WSASetLastError(EINTR); /* Simulate an alarm() */
+ return (SOCKET_ERROR);
+ }
+ }
+ else {
+ rv = SSL_write(ssl, (char*)buf, len);
+ if (BIO_sock_should_retry(rv)) {
+ ap_log_error(APLOG_MARK,APLOG_DEBUG, NULL,
+ "select claimed we could write, "
+ "but in fact we couldn't. "
+ "This is a bug in Windows.");
+ retry = 1;
+ Sleep(100);
+ }
+ }
+ } while(retry);
+ }
+ }
+ ioctlsocket(sock, FIONBIO, &iostate);
+ if (rv == SOCKET_ERROR)
+ WSASetLastError(err);
+ return (rv);
+}
+
+static int SSL_recvwithtimeout(BUFF *fb, char *buf, int len)
+{
+ int iostate = 1;
+ fd_set fdset;
+ struct timeval tv;
+ int err = WSAEWOULDBLOCK;
+ int rv;
+ int sock = fb->fd_in;
+ SSL *ssl;
+ int retry;
+
+ ssl = ap_ctx_get(fb->ctx, "ssl");
+
+ if (!(tv.tv_sec = ap_check_alarm()))
+ return (SSL_read(ssl, buf, len));
+
+ rv = ioctlsocket(sock, FIONBIO, &iostate);
+ iostate = 0;
+ ap_assert(!rv);
+ rv = SSL_read(ssl, buf, len);
+ if (rv <= 0) {
+ if (BIO_sock_should_retry(rv)) {
+ do {
+ retry = 0;
+ FD_ZERO(&fdset);
+ FD_SET((unsigned int)sock, &fdset);
+ tv.tv_usec = 0;
+ rv = select(FD_SETSIZE, &fdset, NULL, NULL, &tv);
+ if (rv == SOCKET_ERROR)
+ err = WSAGetLastError();
+ else if (rv == 0) {
+ ioctlsocket(sock, FIONBIO, &iostate);
+ ap_check_alarm();
+ WSASetLastError(WSAEWOULDBLOCK);
+ return (SOCKET_ERROR);
+ }
+ else {
+ rv = SSL_read(ssl, buf, len);
+ if (rv == SOCKET_ERROR) {
+ if (BIO_sock_should_retry(rv)) {
+ ap_log_error(APLOG_MARK,APLOG_DEBUG, NULL,
+ "select claimed we could read, "
+ "but in fact we couldn't. "
+ "This is a bug in Windows.");
+ retry = 1;
+ Sleep(100);
+ }
+ else {
+ err = WSAGetLastError();
+ }
+ }
+ }
+ } while(retry);
+ }
+ }
+ ioctlsocket(sock, FIONBIO, &iostate);
+ if (rv == SOCKET_ERROR)
+ WSASetLastError(err);
+ return (rv);
+}
+
+#endif /*WIN32*/
+
+/*
+ * There is no SSL_writev() provided by OpenSSL. The reason is mainly because
+ * OpenSSL has to fragment the data itself again for the SSL record layer, so a
+ * writev() like interface makes not much sense. What we do is to emulate it
+ * to at least being able to use the write() like interface. But keep in mind
+ * that the network I/O performance is not write() like, of course.
+ */
+#ifndef NO_WRITEV
+static int SSL_writev(SSL *ssl, const struct iovec *iov, int iovcnt)
+{
+ int i;
+ int n;
+ int rc;
+
+ rc = 0;
+ for (i = 0; i < iovcnt; i++) {
+ if ((n = SSL_write(ssl, iov[i].iov_base, iov[i].iov_len)) == -1) {
+ rc = -1;
+ break;
+ }
+ rc += n;
+ }
+ return rc;
+}
+#endif
+
+/* _________________________________________________________________
+**
+** I/O Data Debugging
+** _________________________________________________________________
+*/
+
+#define DUMP_WIDTH 16
+
+static void ssl_io_data_dump(server_rec *srvr, const char *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++;
+ ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
+ "+-------------------------------------------------------------------------+");
+ for(i = 0 ; i< rows; i++) {
+ ap_snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH);
+ ap_cpystrn(buf, tmp, sizeof(buf));
+ for (j = 0; j < DUMP_WIDTH; j++) {
+ if (((i * DUMP_WIDTH) + j) >= len)
+ ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
+ else {
+ ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
+ ap_snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' ');
+ ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
+ }
+ }
+ ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
+ for (j = 0; j < DUMP_WIDTH; j++) {
+ if (((i * DUMP_WIDTH) + j) >= len)
+ ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
+ else {
+ ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
+ ap_snprintf(tmp, sizeof(tmp), "%c", ((ch >= ' ') && (ch <= '~')) ? ch : '.');
+ ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
+ }
+ }
+ ap_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf));
+ ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID, "%s", buf);
+ }
+ if (trunc > 0)
+ ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
+ "| %04x - <SPACES/NULS>", len + trunc);
+ ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
+ "+-------------------------------------------------------------------------+");
+ return;
+}
+
+long ssl_io_data_cb(BIO *bio, int cmd, const char *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->server;
+
+ if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN)
+ || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) {
+ if (rc >= 0) {
+ ssl_log(s, SSL_LOG_DEBUG,
+ "%s: %s %ld/%d bytes %s BIO#%08X [mem: %08lX] %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)" : "(Ops, no memory buffer?)"));
+ if (argp != NULL)
+ ssl_io_data_dump(s, argp, rc);
+ }
+ else {
+ ssl_log(s, SSL_LOG_DEBUG,
+ "%s: I/O error, %d bytes expected to %s on BIO#%08X [mem: %08lX]",
+ SSL_LIBRARY_NAME, argi,
+ (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
+ bio, argp);
+ }
+ }
+ return rc;
+}
+
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
new file mode 100644
index 0000000000..ca1b3f0a55
--- /dev/null
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -0,0 +1,1905 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_kernel.c
+** The SSL engine kernel
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/* ====================================================================
+ * Copyright (c) 1995-1999 Ben Laurie. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by Ben Laurie
+ * for use in the Apache-SSL HTTP server project."
+ *
+ * 4. The name "Apache-SSL Server" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Ben Laurie
+ * for use in the Apache-SSL HTTP server project."
+ *
+ * THIS SOFTWARE IS PROVIDED BY BEN LAURIE ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BEN LAURIE OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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"
+
+
+/* _________________________________________________________________
+**
+** SSL Engine Kernel
+** _________________________________________________________________
+*/
+
+/*
+ * Connect Handler:
+ * Connect SSL to the accepted socket
+ *
+ * Usually we would need an Apache API hook which is triggered right after
+ * the socket is accepted for handling a new request. But Apache 1.3 doesn't
+ * provide such a hook, so we have to patch http_main.c and call this
+ * function directly.
+ */
+void ssl_hook_NewConnection(conn_rec *conn)
+{
+ server_rec *srvr;
+ BUFF *fb;
+ SSLSrvConfigRec *sc;
+ ap_ctx *apctx;
+ SSL *ssl;
+ char *cp;
+ char *cpVHostID;
+ char *cpVHostMD5;
+ X509 *xs;
+ int rc;
+
+ /*
+ * Get context
+ */
+ srvr = conn->server;
+ fb = conn->client;
+ sc = mySrvConfig(srvr);
+
+ /*
+ * Create SSL context
+ */
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+
+ /*
+ * Immediately stop processing if SSL
+ * is disabled for this connection
+ */
+ if (sc == NULL || !sc->bEnabled)
+ return;
+
+ /*
+ * Remember the connection information for
+ * later access inside callback functions
+ */
+ cpVHostID = ssl_util_vhostid(conn->pool, srvr);
+ ssl_log(srvr, SSL_LOG_INFO, "Connection to child %d established "
+ "(server %s, client %s)", conn->child_num, cpVHostID,
+ conn->remote_ip != NULL ? conn->remote_ip : "unknown");
+
+ /*
+ * Seed the Pseudo Random Number Generator (PRNG)
+ */
+ ssl_rand_seed(srvr, conn->pool, SSL_RSCTX_CONNECT, "");
+
+ /*
+ * 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(sc->pSSLCtx)) == NULL) {
+ ssl_log(conn->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Unable to create a new SSL connection from the SSL context");
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ conn->aborted = 1;
+ return;
+ }
+ SSL_clear(ssl);
+ cpVHostMD5 = ap_md5(conn->pool, (unsigned char *)cpVHostID);
+ if (!SSL_set_session_id_context(ssl, (unsigned char *)cpVHostMD5, strlen(cpVHostMD5))) {
+ ssl_log(conn->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Unable to set session id context to `%s'", cpVHostMD5);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ conn->aborted = 1;
+ return;
+ }
+ SSL_set_app_data(ssl, conn);
+ apctx = ap_ctx_new(conn->pool);
+ ap_ctx_set(apctx, "ssl::request_rec", NULL);
+ ap_ctx_set(apctx, "ssl::verify::depth", AP_CTX_NUM2PTR(0));
+ SSL_set_app_data2(ssl, apctx);
+ SSL_set_fd(ssl, fb->fd);
+ ap_ctx_set(fb->ctx, "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);
+ if (sc->nLogLevel >= SSL_LOG_DEBUG) {
+ BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb);
+ BIO_set_callback_arg(SSL_get_rbio(ssl), ssl);
+ }
+
+ /*
+ * Predefine some client verification results
+ */
+ ap_ctx_set(fb->ctx, "ssl::client::dn", NULL);
+ ap_ctx_set(fb->ctx, "ssl::verify::error", NULL);
+ ap_ctx_set(fb->ctx, "ssl::verify::info", NULL);
+ SSL_set_verify_result(ssl, X509_V_OK);
+
+ /*
+ * We have to manage a I/O timeout ourself, because Apache
+ * does it the first time when reading the request, but we're
+ * working some time before this happens.
+ */
+ ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);
+ ap_set_callback_and_alarm(ssl_hook_TimeoutConnection, srvr->timeout);
+
+ /*
+ * Now enter the SSL Handshake Phase
+ */
+ while (!SSL_is_init_finished(ssl)) {
+
+ if ((rc = SSL_accept(ssl)) <= 0) {
+
+ if (SSL_get_error(ssl, rc) == 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.
+ */
+ ssl_log(srvr, SSL_LOG_INFO,
+ "SSL handshake stopped: connection was closed");
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ conn->aborted = 1;
+ return;
+ }
+ else if (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. Hmmmm... At least for this error we can be more friendly
+ * and try to provide him with a HTML error page. We have only one
+ * problem: OpenSSL has already read some bytes from the HTTP
+ * request. So we have to skip the request line manually and
+ * instead provide a faked one in order to continue the internal
+ * Apache processing.
+ *
+ */
+ char ca[2];
+ int rv;
+
+ /* log the situation */
+ ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "SSL handshake failed: HTTP spoken on HTTPS port; "
+ "trying to send HTML error page");
+
+ /* first: skip the remaining bytes of the request line */
+ do {
+ do {
+ rv = read(fb->fd, ca, 1);
+ } while (rv == -1 && errno == EINTR);
+ } while (rv > 0 && ca[0] != '\012' /*LF*/);
+
+ /* second: fake the request line */
+ fb->inbase = ap_palloc(fb->pool, fb->bufsiz);
+ ap_cpystrn((char *)fb->inbase, "GET /mod_ssl:error:HTTP-request HTTP/1.0\r\n",
+ fb->bufsiz);
+ fb->inptr = fb->inbase;
+ fb->incnt = strlen((char *)fb->inptr);
+
+ /* third: kick away the SSL stuff */
+ SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+
+ /* finally: let Apache go on with processing */
+ return;
+ }
+ else if (ap_ctx_get(ap_global_ctx, "ssl::handshake::timeout") == (void *)TRUE) {
+ ssl_log(srvr, SSL_LOG_ERROR,
+ "SSL handshake timed out (client %s, server %s)",
+ conn->remote_ip != NULL ? conn->remote_ip : "unknown", cpVHostID);
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ conn->aborted = 1;
+ return;
+ }
+ else if (SSL_get_error(ssl, rc) == SSL_ERROR_SYSCALL) {
+ if (errno == EINTR)
+ continue;
+ if (errno > 0)
+ ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
+ "SSL handshake interrupted by system "
+ "[Hint: Stop button pressed in browser?!]");
+ else
+ ssl_log(srvr, SSL_LOG_INFO|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
+ "Spurious SSL handshake interrupt"
+ "[Hint: Usually just one of those OpenSSL confusions!?]");
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ conn->aborted = 1;
+ return;
+ }
+ else {
+ /*
+ * Ok, anything else is a fatal error
+ */
+ ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR|SSL_ADD_ERRNO,
+ "SSL handshake failed (server %s, client %s)", cpVHostID,
+ conn->remote_ip != NULL ? conn->remote_ip : "unknown");
+
+ /*
+ * try to gracefully shutdown the connection:
+ * - send an own shutdown message (be gracefully)
+ * - don't wait for peer's shutdown message (deadloop)
+ * - kick away the SSL stuff immediately
+ * - block the socket, so Apache cannot operate any more
+ */
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ conn->aborted = 1;
+ return;
+ }
+ }
+
+ /*
+ * Check for failed client authentication
+ */
+ if ( SSL_get_verify_result(ssl) != X509_V_OK
+ || ap_ctx_get(fb->ctx, "ssl::verify::error") != NULL) {
+ cp = (char *)ap_ctx_get(fb->ctx, "ssl::verify::error");
+ ssl_log(srvr, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "SSL client authentication failed: %s",
+ cp != NULL ? cp : "unknown reason");
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ conn->aborted = 1;
+ return;
+ }
+
+ /*
+ * Remember the peer certificate's DN
+ */
+ if ((xs = SSL_get_peer_certificate(ssl)) != NULL) {
+ cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0);
+ ap_ctx_set(fb->ctx, "ssl::client::dn", ap_pstrdup(conn->pool, cp));
+ free(cp);
+ }
+
+ /*
+ * Make really sure that when a peer certificate
+ * is required we really got one... (be paranoid)
+ */
+ if ( sc->nVerifyClient == SSL_CVERIFY_REQUIRE
+ && ap_ctx_get(fb->ctx, "ssl::client::dn") == NULL) {
+ ssl_log(srvr, SSL_LOG_ERROR,
+ "No acceptable peer certificate available");
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ conn->aborted = 1;
+ return;
+ }
+ }
+
+ /*
+ * Remove the timeout handling
+ */
+ ap_set_callback_and_alarm(NULL, 0);
+ ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)FALSE);
+
+ /*
+ * Improve I/O throughput by using
+ * OpenSSL's read-ahead functionality
+ * (don't used under Win32, because
+ * there we use select())
+ */
+#ifndef WIN32
+ SSL_set_read_ahead(ssl, TRUE);
+#endif
+
+#ifdef SSL_VENDOR
+ /* Allow vendors to do more things on connection time... */
+ ap_hook_use("ap::mod_ssl::vendor::new_connection",
+ AP_HOOK_SIG2(void,ptr), AP_HOOK_ALL, conn);
+#endif
+
+ return;
+}
+
+/*
+ * Signal handler function for the SSL handshake phase
+ */
+void ssl_hook_TimeoutConnection(int sig)
+{
+ /* we just set a flag for the handshake processing loop */
+ ap_ctx_set(ap_global_ctx, "ssl::handshake::timeout", (void *)TRUE);
+ return;
+}
+
+/*
+ * Close the SSL part of the socket connection
+ * (called immediately _before_ the socket is closed)
+ */
+void ssl_hook_CloseConnection(conn_rec *conn)
+{
+ SSL *ssl;
+ char *cpType;
+
+ ssl = ap_ctx_get(conn->client->ctx, "ssl");
+ if (ssl == NULL)
+ return;
+
+ /*
+ * First make sure that no more data is pending in Apache's BUFF,
+ * because when it's (implicitly) flushed later by the ap_bclose()
+ * calls of Apache it would lead to an I/O error in the browser due
+ * to the fact that the SSL layer was already removed by us.
+ */
+ ap_bflush(conn->client);
+
+ /*
+ * 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 (ap_ctx_get(conn->client->ctx, "ssl::flag::unclean-shutdown") == PTRUE) {
+ /* perform no close notify handshake at all
+ (violates the SSL/TLS standard!) */
+ SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
+ cpType = "unclean";
+ }
+ else if (ap_ctx_get(conn->client->ctx, "ssl::flag::accurate-shutdown") == PTRUE) {
+ /* send close notify and wait for clients close notify
+ (standard compliant, but usually causes connection hangs) */
+ SSL_set_shutdown(ssl, 0);
+ cpType = "accurate";
+ }
+ else {
+ /* send close notify, but don't wait for clients close notify
+ (standard compliant and safe, so it's the DEFAULT!) */
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ cpType = "standard";
+ }
+ SSL_smart_shutdown(ssl);
+
+ /* deallocate the SSL connection */
+ SSL_free(ssl);
+ ap_ctx_set(conn->client->ctx, "ssl", NULL);
+
+ /* and finally log the fact that we've closed the connection */
+ ssl_log(conn->server, SSL_LOG_INFO,
+ "Connection to child %d closed with %s shutdown (server %s, client %s)",
+ conn->child_num, cpType, ssl_util_vhostid(conn->pool, conn->server),
+ conn->remote_ip != NULL ? conn->remote_ip : "unknown");
+ return;
+}
+
+/*
+ * Post Read Request Handler
+ */
+int ssl_hook_ReadReq(request_rec *r)
+{
+ SSL *ssl;
+ ap_ctx *apctx;
+
+ /*
+ * Get the SSL connection structure and perform the
+ * delayed interlinking from SSL back to request_rec
+ */
+ ssl = ap_ctx_get(r->connection->client->ctx, "ssl");
+ if (ssl != NULL) {
+ apctx = SSL_get_app_data2(ssl);
+ ap_ctx_set(apctx, "ssl::request_rec", r);
+ }
+
+ /*
+ * Force the mod_ssl content handler when URL indicates this
+ */
+ if (strEQn(r->uri, "/mod_ssl:", 9))
+ r->handler = "mod_ssl:content-handler";
+ if (ssl != NULL) {
+ ap_ctx_set(r->ctx, "ap::http::method", "https");
+ ap_ctx_set(r->ctx, "ap::default::port", "443");
+ }
+ else {
+ ap_ctx_set(r->ctx, "ap::http::method", NULL);
+ ap_ctx_set(r->ctx, "ap::default::port", NULL);
+ }
+ return DECLINED;
+}
+
+/*
+ * URL Translation Handler
+ */
+int ssl_hook_Translate(request_rec *r)
+{
+ if (ap_ctx_get(r->connection->client->ctx, "ssl") == NULL)
+ return DECLINED;
+
+ /*
+ * Log information about incoming HTTPS requests
+ */
+ if (ap_is_initial_req(r))
+ ssl_log(r->server, SSL_LOG_INFO,
+ "%s HTTPS request received for child %d (server %s)",
+ r->connection->keepalives <= 0 ?
+ "Initial (No.1)" :
+ ap_psprintf(r->pool, "Subsequent (No.%d)",
+ r->connection->keepalives+1),
+ r->connection->child_num,
+ ssl_util_vhostid(r->pool, r->server));
+
+ /*
+ * Move SetEnvIf information from request_rec to conn_rec/BUFF
+ * to allow the close connection handler to use them.
+ */
+ if (ap_table_get(r->subprocess_env, "ssl-unclean-shutdown") != NULL)
+ ap_ctx_set(r->connection->client->ctx, "ssl::flag::unclean-shutdown", PTRUE);
+ else
+ ap_ctx_set(r->connection->client->ctx, "ssl::flag::unclean-shutdown", PFALSE);
+ if (ap_table_get(r->subprocess_env, "ssl-accurate-shutdown") != NULL)
+ ap_ctx_set(r->connection->client->ctx, "ssl::flag::accurate-shutdown", PTRUE);
+ else
+ ap_ctx_set(r->connection->client->ctx, "ssl::flag::accurate-shutdown", PFALSE);
+
+ return DECLINED;
+}
+
+/*
+ * Content Handler
+ */
+int ssl_hook_Handler(request_rec *r)
+{
+ int port;
+ char *thisport;
+ char *thisurl;
+
+ if (strNEn(r->uri, "/mod_ssl:", 9))
+ return DECLINED;
+
+ if (strEQ(r->uri, "/mod_ssl:error:HTTP-request")) {
+ thisport = "";
+ port = ap_get_server_port(r);
+ if (!ap_is_default_port(port, r))
+ thisport = ap_psprintf(r->pool, ":%u", port);
+ thisurl = ap_psprintf(r->pool, "https://%s%s/",
+ ap_get_server_name(r), thisport);
+
+ ap_table_setn(r->notes, "error-notes", ap_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));
+ }
+
+ return HTTP_BAD_REQUEST;
+}
+
+/*
+ * Access Handler
+ */
+int ssl_hook_Access(request_rec *r)
+{
+ SSLDirConfigRec *dc;
+ SSLSrvConfigRec *sc;
+ SSL *ssl;
+ SSL_CTX *ctx = NULL;
+ array_header *apRequirement;
+ ssl_require_t *pRequirements;
+ ssl_require_t *pRequirement;
+ char *cp;
+ int ok;
+ int i;
+ BOOL renegotiate;
+ BOOL renegotiate_quick;
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ BOOL reconfigured_locations;
+ STACK_OF(X509_NAME) *skCAList;
+ char *cpCAPath;
+ char *cpCAFile;
+#endif
+ X509 *cert;
+ STACK_OF(X509) *certstack;
+ X509_STORE *certstore;
+ X509_STORE_CTX certstorectx;
+ int depth;
+ STACK_OF(SSL_CIPHER) *skCipherOld;
+ STACK_OF(SSL_CIPHER) *skCipher;
+ SSL_CIPHER *pCipher;
+ ap_ctx *apctx;
+ int nVerifyOld;
+ int nVerify;
+ int n;
+ void *vp;
+ int rc;
+
+ dc = myDirConfig(r);
+ sc = mySrvConfig(r->server);
+ ssl = ap_ctx_get(r->connection->client->ctx, "ssl");
+ if (ssl != NULL)
+ ctx = SSL_get_SSL_CTX(ssl);
+
+ /*
+ * Support for SSLRequireSSL directive
+ */
+ if (dc->bSSLRequired && ssl == NULL) {
+ ap_log_reason("SSL connection required", r->filename, r);
+ /* remember forbidden access for strict require option */
+ ap_table_setn(r->notes, "ssl-access-forbidden", (void *)1);
+ return FORBIDDEN;
+ }
+
+ /*
+ * Check to see if SSL protocol is on
+ */
+ if (!sc->bEnabled)
+ return DECLINED;
+ if (ssl == NULL)
+ 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.
+ */
+ renegotiate = FALSE;
+ renegotiate_quick = FALSE;
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ reconfigured_locations = FALSE;
+#endif
+
+ /*
+ * 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 != NULL) {
+ /* remember old state */
+ pCipher = NULL;
+ skCipherOld = NULL;
+ if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE)
+ pCipher = SSL_get_current_cipher(ssl);
+ else {
+ skCipherOld = SSL_get_ciphers(ssl);
+ if (skCipherOld != NULL)
+ skCipherOld = sk_SSL_CIPHER_dup(skCipherOld);
+ }
+ /* configure new state */
+ if (!SSL_set_cipher_list(ssl, dc->szCipherSuite)) {
+ ssl_log(r->server, SSL_LOG_WARN|SSL_ADD_SSLERR,
+ "Unable to reconfigure (per-directory) permitted SSL ciphers");
+ if (skCipherOld != NULL)
+ sk_SSL_CIPHER_free(skCipherOld);
+ return FORBIDDEN;
+ }
+ /* determine whether a renegotiation has to be forced */
+ skCipher = SSL_get_ciphers(ssl);
+ if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) {
+ /* optimized way */
+ if ((pCipher == NULL && skCipher != NULL) ||
+ (pCipher != NULL && skCipher == NULL) )
+ renegotiate = TRUE;
+ else if (pCipher != NULL && skCipher != NULL
+ && sk_SSL_CIPHER_find(skCipher, pCipher) < 0) {
+ renegotiate = TRUE;
+ }
+ }
+ else {
+ /* paranoid way */
+ if ((skCipherOld == NULL && skCipher != NULL) ||
+ (skCipherOld != NULL && skCipher == NULL) )
+ renegotiate = TRUE;
+ else if (skCipherOld != NULL && skCipher != NULL) {
+ for (n = 0; !renegotiate && n < sk_SSL_CIPHER_num(skCipher); n++) {
+ if (sk_SSL_CIPHER_find(skCipherOld, sk_SSL_CIPHER_value(skCipher, n)) < 0)
+ renegotiate = TRUE;
+ }
+ for (n = 0; !renegotiate && n < sk_SSL_CIPHER_num(skCipherOld); n++) {
+ if (sk_SSL_CIPHER_find(skCipher, sk_SSL_CIPHER_value(skCipherOld, n)) < 0)
+ renegotiate = TRUE;
+ }
+ }
+ }
+ /* cleanup */
+ if (skCipherOld != NULL)
+ sk_SSL_CIPHER_free(skCipherOld);
+ /* tracing */
+ if (renegotiate)
+ ssl_log(r->server, SSL_LOG_TRACE,
+ "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) {
+ apctx = SSL_get_app_data2(ssl);
+ if ((vp = ap_ctx_get(apctx, "ssl::verify::depth")) != NULL)
+ n = (int)AP_CTX_PTR2NUM(vp);
+ else
+ n = sc->nVerifyDepth;
+ ap_ctx_set(apctx, "ssl::verify::depth",
+ AP_CTX_NUM2PTR(dc->nVerifyDepth));
+ /* determine whether a renegotiation has to be forced */
+ if (dc->nVerifyDepth < n) {
+ renegotiate = TRUE;
+ ssl_log(r->server, SSL_LOG_TRACE,
+ "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 */
+ nVerifyOld = SSL_get_verify_mode(ssl);
+ /* configure new state */
+ nVerify = SSL_VERIFY_NONE;
+ if (dc->nVerifyClient == SSL_CVERIFY_REQUIRE)
+ nVerify |= SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ if ( (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL)
+ || (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA) )
+ nVerify |= SSL_VERIFY_PEER;
+ SSL_set_verify(ssl, nVerify, ssl_callback_SSLVerify);
+ SSL_set_verify_result(ssl, X509_V_OK);
+ /* determine whether we've to force a renegotiation */
+ if (nVerify != nVerifyOld) {
+ if ( ( (nVerifyOld == SSL_VERIFY_NONE)
+ && (nVerify != SSL_VERIFY_NONE))
+ || ( !(nVerifyOld & SSL_VERIFY_PEER)
+ && (nVerify & SSL_VERIFY_PEER))
+ || ( !(nVerifyOld & (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+ && (nVerify & (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT)))) {
+ renegotiate = TRUE;
+ /* optimization */
+ if ( dc->nOptions & SSL_OPT_OPTRENEGOTIATE
+ && nVerifyOld == SSL_VERIFY_NONE
+ && SSL_get_peer_certificate(ssl) != NULL)
+ renegotiate_quick = TRUE;
+ ssl_log(r->server, SSL_LOG_TRACE,
+ "Changed client verification type will force %srenegotiation",
+ renegotiate_quick ? "quick " : "");
+ }
+ }
+ }
+
+ /*
+ * override SSLCACertificateFile & SSLCACertificatePath
+ * This is tagged experimental because it has to use an ugly kludge: We
+ * have to change the locations inside the SSL_CTX* (per-server global)
+ * instead inside SSL* (per-connection local) and reconfigure it to the
+ * old values later. That's problematic at least for the threaded process
+ * model of Apache under Win32 or when an error occurs. But unless
+ * OpenSSL provides a SSL_load_verify_locations() function we've no other
+ * chance to provide this functionality...
+ */
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ if ( ( dc->szCACertificateFile != NULL
+ && ( sc->szCACertificateFile == NULL
+ || ( sc->szCACertificateFile != NULL
+ && strNE(dc->szCACertificateFile, sc->szCACertificateFile))))
+ || ( dc->szCACertificatePath != NULL
+ && ( sc->szCACertificatePath == NULL
+ || ( sc->szCACertificatePath != NULL
+ && strNE(dc->szCACertificatePath, sc->szCACertificatePath)))) ) {
+ cpCAFile = dc->szCACertificateFile != NULL ?
+ dc->szCACertificateFile : sc->szCACertificateFile;
+ cpCAPath = dc->szCACertificatePath != NULL ?
+ dc->szCACertificatePath : sc->szCACertificatePath;
+ /*
+ FIXME: This should be...
+ if (!SSL_load_verify_locations(ssl, cpCAFile, cpCAPath)) {
+ ...but OpenSSL still doesn't provide this!
+ */
+ if (!SSL_CTX_load_verify_locations(ctx, cpCAFile, cpCAPath)) {
+ ssl_log(r->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Unable to reconfigure verify locations "
+ "for client authentication");
+ return FORBIDDEN;
+ }
+ if ((skCAList = ssl_init_FindCAList(r->server, r->pool,
+ cpCAFile, cpCAPath)) == NULL) {
+ ssl_log(r->server, SSL_LOG_ERROR,
+ "Unable to determine list of available "
+ "CA certificates for client authentication");
+ return FORBIDDEN;
+ }
+ SSL_set_client_CA_list(ssl, skCAList);
+ renegotiate = TRUE;
+ reconfigured_locations = TRUE;
+ ssl_log(r->server, SSL_LOG_TRACE,
+ "Changed client verification locations will force renegotiation");
+ }
+#endif /* SSL_EXPERIMENTAL_PERDIRCA */
+
+#ifdef SSL_CONSERVATIVE
+ /*
+ * SSL renegotiations in conjunction with HTTP
+ * requests using the POST method are not supported.
+ */
+ if (renegotiate && r->method_number == M_POST) {
+ ssl_log(r->server, SSL_LOG_ERROR,
+ "SSL Re-negotiation in conjunction with POST method not supported!");
+ ssl_log(r->server, SSL_LOG_INFO,
+ "You have to compile without -DSSL_CONSERVATIVE to enabled support for this.");
+ return METHOD_NOT_ALLOWED;
+ }
+#endif /* SSL_CONSERVATIVE */
+
+ /*
+ * 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.
+ */
+ ssl_log(r->server, SSL_LOG_INFO, "Requesting connection re-negotiation");
+ if (renegotiate_quick) {
+ /* perform just a manual re-verification of the peer */
+ ssl_log(r->server, SSL_LOG_TRACE,
+ "Performing quick renegotiation: just re-verifying the peer");
+ certstore = SSL_CTX_get_cert_store(ctx);
+ if (certstore == NULL) {
+ ssl_log(r->server, SSL_LOG_ERROR, "Cannot find certificate storage");
+ return FORBIDDEN;
+ }
+ certstack = SSL_get_peer_cert_chain(ssl);
+ if (certstack == NULL || sk_X509_num(certstack) == 0) {
+ ssl_log(r->server, SSL_LOG_ERROR, "Cannot find peer certificate chain");
+ return FORBIDDEN;
+ }
+ cert = sk_X509_value(certstack, 0);
+ X509_STORE_CTX_init(&certstorectx, certstore, cert, certstack);
+ depth = SSL_get_verify_depth(ssl);
+ if (depth >= 0)
+ X509_STORE_CTX_set_depth(&certstorectx, depth);
+ X509_STORE_CTX_set_ex_data(&certstorectx,
+ SSL_get_ex_data_X509_STORE_CTX_idx(), (char *)ssl);
+ if (!X509_verify_cert(&certstorectx))
+ ssl_log(r->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Re-negotiation verification step failed");
+ SSL_set_verify_result(ssl, certstorectx.error);
+ X509_STORE_CTX_cleanup(&certstorectx);
+ }
+ else {
+ /* do a full renegotiation */
+ ssl_log(r->server, SSL_LOG_TRACE,
+ "Performing full renegotiation: complete handshake protocol");
+ if (r->main != NULL)
+ SSL_set_session_id_context(ssl, (unsigned char *)&(r->main), sizeof(r->main));
+ else
+ SSL_set_session_id_context(ssl, (unsigned char *)&r, sizeof(r));
+#ifndef SSL_CONSERVATIVE
+ ssl_io_suck(r, ssl);
+#endif
+ SSL_renegotiate(ssl);
+ SSL_do_handshake(ssl);
+ if (SSL_get_state(ssl) != SSL_ST_OK) {
+ ssl_log(r->server, SSL_LOG_ERROR, "Re-negotiation request failed");
+ return FORBIDDEN;
+ }
+ ssl_log(r->server, SSL_LOG_INFO, "Awaiting re-negotiation handshake");
+ SSL_set_state(ssl, SSL_ST_ACCEPT);
+ SSL_do_handshake(ssl);
+ if (SSL_get_state(ssl) != SSL_ST_OK) {
+ ssl_log(r->server, SSL_LOG_ERROR,
+ "Re-negotiation handshake failed: Not accepted by client!?");
+ return FORBIDDEN;
+ }
+ }
+
+ /*
+ * Remember the peer certificate's DN
+ */
+ if ((cert = SSL_get_peer_certificate(ssl)) != NULL) {
+ cp = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
+ ap_ctx_set(r->connection->client->ctx, "ssl::client::dn",
+ ap_pstrdup(r->connection->pool, cp));
+ free(cp);
+ }
+
+ /*
+ * Finally check for acceptable renegotiation results
+ */
+ if (dc->nVerifyClient != SSL_CVERIFY_NONE) {
+ if ( dc->nVerifyClient == SSL_CVERIFY_REQUIRE
+ && SSL_get_verify_result(ssl) != X509_V_OK ) {
+ ssl_log(r->server, SSL_LOG_ERROR,
+ "Re-negotiation handshake failed: Client verification failed");
+ return FORBIDDEN;
+ }
+ if ( dc->nVerifyClient == SSL_CVERIFY_REQUIRE
+ && SSL_get_peer_certificate(ssl) == NULL ) {
+ ssl_log(r->server, SSL_LOG_ERROR,
+ "Re-negotiation handshake failed: Client certificate missing");
+ return FORBIDDEN;
+ }
+ }
+ }
+
+ /*
+ * Under old OpenSSL we had to change the X509_STORE inside the
+ * SSL_CTX instead inside the SSL structure, so we have to reconfigure it
+ * to the old values. This should be changed with forthcoming OpenSSL
+ * versions when better functionality is avaiable.
+ */
+#ifdef SSL_EXPERIMENTAL_PERDIRCA
+ if (renegotiate && reconfigured_locations) {
+ if (!SSL_CTX_load_verify_locations(ctx,
+ sc->szCACertificateFile, sc->szCACertificatePath)) {
+ ssl_log(r->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Unable to reconfigure verify locations "
+ "to per-server configuration parameters");
+ return FORBIDDEN;
+ }
+ }
+#endif /* SSL_EXPERIMENTAL_PERDIRCA */
+
+ /*
+ * Check SSLRequire boolean expressions
+ */
+ apRequirement = dc->aRequirement;
+ pRequirements = (ssl_require_t *)apRequirement->elts;
+ for (i = 0; i < apRequirement->nelts; i++) {
+ pRequirement = &pRequirements[i];
+ ok = ssl_expr_exec(r, pRequirement->mpExpr);
+ if (ok < 0) {
+ cp = ap_psprintf(r->pool, "Failed to execute SSL requirement expression: %s",
+ ssl_expr_get_error());
+ ap_log_reason(cp, r->filename, r);
+ /* remember forbidden access for strict require option */
+ ap_table_setn(r->notes, "ssl-access-forbidden", (void *)1);
+ return FORBIDDEN;
+ }
+ if (ok != 1) {
+ ssl_log(r->server, SSL_LOG_INFO,
+ "Access to %s denied for %s (requirement expression not fulfilled)",
+ r->filename, r->connection->remote_ip);
+ ssl_log(r->server, SSL_LOG_INFO,
+ "Failed expression: %s", pRequirement->cpExpr);
+ ap_log_reason("SSL requirement expression not fulfilled "
+ "(see SSL logfile for more details)", r->filename, r);
+ /* remember forbidden access for strict require option */
+ ap_table_setn(r->notes, "ssl-access-forbidden", (void *)1);
+ return 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.
+ */
+ rc = DECLINED;
+#ifdef SSL_VENDOR
+ ap_hook_use("ap::mod_ssl::vendor::access_handler",
+ AP_HOOK_SIG2(int,ptr), AP_HOOK_DECLINE(DECLINED),
+ &rc, r);
+#endif
+ return rc;
+}
+
+/*
+ * Auth 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_Auth(request_rec *r)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(r->server);
+ SSLDirConfigRec *dc = myDirConfig(r);
+ char b1[MAX_STRING_LEN], b2[MAX_STRING_LEN];
+ char *clientdn;
+ const char *cpAL;
+ const char *cpUN;
+ const char *cpPW;
+
+ /*
+ * Additionally forbid access (again)
+ * when strict require option is used.
+ */
+ if ( (dc->nOptions & SSL_OPT_STRICTREQUIRE)
+ && (ap_table_get(r->notes, "ssl-access-forbidden") != NULL))
+ return FORBIDDEN;
+
+ /*
+ * 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 ((cpAL = ap_table_get(r->headers_in, "Authorization")) != NULL) {
+ if (strcEQ(ap_getword(r->pool, &cpAL, ' '), "Basic")) {
+ while (*cpAL == ' ' || *cpAL == '\t')
+ cpAL++;
+ cpAL = ap_pbase64decode(r->pool, cpAL);
+ cpUN = ap_getword_nulls(r->pool, &cpAL, ':');
+ cpPW = cpAL;
+ if (cpUN[0] == '/' && strEQ(cpPW, "password"))
+ return FORBIDDEN;
+ }
+ }
+
+ /*
+ * We decline operation in various situations...
+ */
+ if (!sc->bEnabled)
+ return DECLINED;
+ if (ap_ctx_get(r->connection->client->ctx, "ssl") == NULL)
+ return DECLINED;
+ if (!(dc->nOptions & SSL_OPT_FAKEBASICAUTH))
+ return DECLINED;
+ if (r->connection->user)
+ return DECLINED;
+ if ((clientdn = (char *)ap_ctx_get(r->connection->client->ctx, "ssl::client::dn")) == NULL)
+ return DECLINED;
+
+ /*
+ * 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" ;-)
+ */
+ ap_snprintf(b1, sizeof(b1), "%s:password", clientdn);
+ ssl_util_uuencode(b2, b1, FALSE);
+ ap_snprintf(b1, sizeof(b1), "Basic %s", b2);
+ ap_table_set(r->headers_in, "Authorization", b1);
+ ssl_log(r->server, SSL_LOG_INFO,
+ "Faking HTTP Basic Auth header: \"Authorization: %s\"", b1);
+
+ return DECLINED;
+}
+
+int ssl_hook_UserCheck(request_rec *r)
+{
+ SSLDirConfigRec *dc = myDirConfig(r);
+
+ /*
+ * Additionally forbid access (again)
+ * when strict require option is used.
+ */
+ if ( (dc->nOptions & SSL_OPT_STRICTREQUIRE)
+ && (ap_table_get(r->notes, "ssl-access-forbidden") != NULL))
+ return FORBIDDEN;
+
+ return DECLINED;
+}
+
+/*
+ * Fixup Handler
+ */
+
+static const char *ssl_hook_Fixup_vars[] = {
+ "SSL_VERSION_INTERFACE",
+ "SSL_VERSION_LIBRARY",
+ "SSL_PROTOCOL",
+ "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)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(r->server);
+ SSLDirConfigRec *dc = myDirConfig(r);
+ table *e = r->subprocess_env;
+ char *var;
+ char *val;
+ STACK_OF(X509) *sk;
+ SSL *ssl;
+ int i;
+
+ /*
+ * Check to see if SSL is on
+ */
+ if (!sc->bEnabled)
+ return DECLINED;
+ if ((ssl = ap_ctx_get(r->connection->client->ctx, "ssl")) == NULL)
+ return DECLINED;
+
+ /*
+ * Annotate the SSI/CGI environment with standard SSL information
+ */
+ /* the always present HTTPS (=HTTP over SSL) flag! */
+ ap_table_set(e, "HTTPS", "on");
+ /* standard SSL environment variables */
+ if (dc->nOptions & SSL_OPT_STDENVVARS) {
+ for (i = 0; ssl_hook_Fixup_vars[i] != NULL; i++) {
+ var = (char *)ssl_hook_Fixup_vars[i];
+ val = ssl_var_lookup(r->pool, r->server, r->connection, r, var);
+ if (!strIsEmpty(val))
+ ap_table_set(e, 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");
+ ap_table_set(e, "SSL_SERVER_CERT", val);
+ val = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_CERT");
+ ap_table_set(e, "SSL_CLIENT_CERT", val);
+ if ((sk = SSL_get_peer_cert_chain(ssl)) != NULL) {
+ for (i = 0; i < sk_X509_num(sk); i++) {
+ var = ap_psprintf(r->pool, "SSL_CLIENT_CERT_CHAIN_%d", i);
+ val = ssl_var_lookup(r->pool, r->server, r->connection, r, var);
+ if (val != NULL)
+ ap_table_set(e, var, val);
+ }
+ }
+ }
+
+ /*
+ * On-demand bloat up the SSI/CGI environment with compat variables
+ */
+#ifdef SSL_COMPAT
+ if (dc->nOptions & SSL_OPT_COMPATENVVARS)
+ ssl_compat_variables(r);
+#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.
+ *
+ * So we generated 512 and 1024 bit temporary keys on startup
+ * which we now just handle out on demand....
+ */
+RSA *ssl_callback_TmpRSA(SSL *pSSL, int nExport, int nKeyLen)
+{
+ SSLModConfigRec *mc = myModConfig();
+ RSA *rsa;
+
+ rsa = NULL;
+ if (nExport) {
+ /* It's because an export cipher is used */
+ if (nKeyLen == 512)
+ rsa = (RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA512];
+ else if (nKeyLen == 1024)
+ rsa = (RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA1024];
+ else
+ /* it's too expensive to generate on-the-fly, so keep 1024bit */
+ rsa = (RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA1024];
+ }
+ else {
+ /* It's because a sign-only certificate situation exists */
+ rsa = (RSA *)mc->pTmpKeys[SSL_TKPIDX_RSA1024];
+ }
+ return rsa;
+}
+
+/*
+ * Handle out the already generated DH parameters...
+ */
+DH *ssl_callback_TmpDH(SSL *pSSL, int nExport, int nKeyLen)
+{
+ SSLModConfigRec *mc = myModConfig();
+ DH *dh;
+
+ dh = NULL;
+ if (nExport) {
+ /* It's because an export cipher is used */
+ if (nKeyLen == 512)
+ dh = (DH *)mc->pTmpKeys[SSL_TKPIDX_DH512];
+ else if (nKeyLen == 1024)
+ dh = (DH *)mc->pTmpKeys[SSL_TKPIDX_DH1024];
+ else
+ /* it's too expensive to generate on-the-fly, so keep 1024bit */
+ dh = (DH *)mc->pTmpKeys[SSL_TKPIDX_DH1024];
+ }
+ else {
+ /* It's because a sign-only certificate situation exists */
+ dh = (DH *)mc->pTmpKeys[SSL_TKPIDX_DH1024];
+ }
+ return dh;
+}
+
+/*
+ * 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)
+{
+ SSL *ssl;
+ conn_rec *conn;
+ server_rec *s;
+ request_rec *r;
+ SSLSrvConfigRec *sc;
+ SSLDirConfigRec *dc;
+ ap_ctx *actx;
+ X509 *xs;
+ int errnum;
+ int errdepth;
+ char *cp;
+ char *cp2;
+ int depth;
+ int verify;
+
+ /*
+ * Get Apache context back through OpenSSL context
+ */
+ ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx);
+ conn = (conn_rec *)SSL_get_app_data(ssl);
+ actx = (ap_ctx *)SSL_get_app_data2(ssl);
+ r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec");
+ s = conn->server;
+ sc = mySrvConfig(s);
+ dc = (r != NULL ? myDirConfig(r) : NULL);
+
+ /*
+ * Get verify ingredients
+ */
+ xs = X509_STORE_CTX_get_current_cert(ctx);
+ errnum = X509_STORE_CTX_get_error(ctx);
+ errdepth = X509_STORE_CTX_get_error_depth(ctx);
+
+ /*
+ * Log verification information
+ */
+ cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0);
+ cp2 = X509_NAME_oneline(X509_get_issuer_name(xs), NULL, 0);
+ ssl_log(s, SSL_LOG_TRACE,
+ "Certificate Verification: depth: %d, subject: %s, issuer: %s",
+ errdepth, cp != NULL ? cp : "-unknown-",
+ cp2 != NULL ? cp2 : "-unknown");
+ if (cp)
+ free(cp);
+ if (cp2)
+ free(cp2);
+
+ /*
+ * Check for optionally acceptable non-verifiable issuer situation
+ */
+ if (dc != NULL && dc->nVerifyClient != SSL_CVERIFY_UNSET)
+ verify = dc->nVerifyClient;
+ else
+ verify = sc->nVerifyClient;
+ if ( ( 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
+#if SSL_LIBRARY_VERSION >= 0x00905000
+ || errnum == X509_V_ERR_CERT_UNTRUSTED
+#endif
+ || errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE )
+ && verify == SSL_CVERIFY_OPTIONAL_NO_CA ) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Certificate Verification: Verifiable Issuer is configured as "
+ "optional, therefore we're accepting the certificate");
+ ap_ctx_set(conn->client->ctx, "ssl::verify::info", "GENEROUS");
+ ok = TRUE;
+ }
+
+ /*
+ * Additionally perform CRL-based revocation checks
+ */
+ if (ok) {
+ ok = ssl_callback_SSLVerify_CRL(ok, ctx, s);
+ if (!ok)
+ errnum = X509_STORE_CTX_get_error(ctx);
+ }
+
+ /*
+ * If we already know it's not ok, log the real reason
+ */
+ if (!ok) {
+ ssl_log(s, SSL_LOG_ERROR, "Certificate Verification: Error (%d): %s",
+ errnum, X509_verify_cert_error_string(errnum));
+ ap_ctx_set(conn->client->ctx, "ssl::client::dn", NULL);
+ ap_ctx_set(conn->client->ctx, "ssl::verify::error",
+ (void *)X509_verify_cert_error_string(errnum));
+ }
+
+ /*
+ * Finally check the depth of the certificate verification
+ */
+ if (dc != NULL && dc->nVerifyDepth != UNSET)
+ depth = dc->nVerifyDepth;
+ else
+ depth = sc->nVerifyDepth;
+ if (errdepth > depth) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Certificate Verification: Certificate Chain too long "
+ "(chain has %d certificates, but maximum allowed are only %d)",
+ errdepth, depth);
+ ap_ctx_set(conn->client->ctx, "ssl::verify::error",
+ (void *)X509_verify_cert_error_string(X509_V_ERR_CERT_CHAIN_TOO_LONG));
+ ok = FALSE;
+ }
+
+ /*
+ * And finally signal OpenSSL the (perhaps changed) state
+ */
+ return (ok);
+}
+
+int ssl_callback_SSLVerify_CRL(
+ int ok, X509_STORE_CTX *ctx, server_rec *s)
+{
+ SSLSrvConfigRec *sc;
+ X509_OBJECT obj;
+ X509_NAME *subject;
+ X509_NAME *issuer;
+ X509 *xs;
+ X509_CRL *crl;
+ X509_REVOKED *revoked;
+ long serial;
+ BIO *bio;
+ int i, n, rc;
+ char *cp;
+ char *cp2;
+
+ /*
+ * Unless a revocation store for CRLs was created we
+ * cannot do any CRL-based verification, of course.
+ */
+ sc = mySrvConfig(s);
+ if (sc->pRevocationStore == NULL)
+ return ok;
+
+ /*
+ * Determine certificate ingredients in advance
+ */
+ xs = X509_STORE_CTX_get_current_cert(ctx);
+ subject = X509_get_subject_name(xs);
+ issuer = X509_get_issuer_name(xs);
+
+ /*
+ * 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(sc->pRevocationStore, X509_LU_CRL, subject, &obj);
+ crl = obj.data.crl;
+ if (rc > 0 && crl != NULL) {
+ /*
+ * Log information about CRL
+ * (A little bit complicated because of ASN.1 and BIOs...)
+ */
+ if (ssl_log_applies(s, SSL_LOG_TRACE)) {
+ bio = BIO_new(BIO_s_mem());
+ 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_pending(bio);
+ cp = malloc(n+1);
+ n = BIO_read(bio, cp, n);
+ cp[n] = NUL;
+ BIO_free(bio);
+ cp2 = X509_NAME_oneline(subject, NULL, 0);
+ ssl_log(s, SSL_LOG_TRACE, "CA CRL: Issuer: %s, %s", cp2, cp);
+ free(cp2);
+ free(cp);
+ }
+
+ /*
+ * Verify the signature on this CRL
+ */
+ if (X509_CRL_verify(crl, X509_get_pubkey(xs)) <= 0) {
+ ssl_log(s, SSL_LOG_WARN, "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) {
+ ssl_log(s, SSL_LOG_WARN, "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) {
+ ssl_log(s, SSL_LOG_WARN,
+ "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(sc->pRevocationStore, X509_LU_CRL, issuer, &obj);
+ crl = obj.data.crl;
+ if (rc > 0 && crl != NULL) {
+ /*
+ * Check if the current certificate is revoked by this CRL
+ */
+#if SSL_LIBRARY_VERSION < 0x00904000
+ n = sk_num(X509_CRL_get_REVOKED(crl));
+#else
+ n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
+#endif
+ for (i = 0; i < n; i++) {
+#if SSL_LIBRARY_VERSION < 0x00904000
+ revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i);
+#else
+ revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
+#endif
+ if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(xs)) == 0) {
+
+ serial = ASN1_INTEGER_get(revoked->serialNumber);
+ cp = X509_NAME_oneline(issuer, NULL, 0);
+ ssl_log(s, SSL_LOG_INFO,
+ "Certificate with serial %ld (0x%lX) "
+ "revoked per CRL from issuer %s",
+ serial, serial, cp);
+ 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;
+}
+
+/*
+ * 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 *pNew)
+{
+ conn_rec *conn;
+ server_rec *s;
+ SSLSrvConfigRec *sc;
+ long t;
+ BOOL rc;
+
+ /*
+ * Get Apache context back through OpenSSL context
+ */
+ conn = (conn_rec *)SSL_get_app_data(ssl);
+ s = conn->server;
+ sc = mySrvConfig(s);
+
+ /*
+ * Set the timeout also for the internal OpenSSL cache, because this way
+ * our inter-process cache is consulted only when it's really necessary.
+ */
+ t = sc->nSessionCacheTimeout;
+ SSL_set_timeout(pNew, t);
+
+ /*
+ * Store the SSL_SESSION in the inter-process cache with the
+ * same expire time, so it expires automatically there, too.
+ */
+ t = (SSL_get_time(pNew) + sc->nSessionCacheTimeout);
+ rc = ssl_scache_store(s, pNew->session_id, pNew->session_id_length, t, pNew);
+
+ /*
+ * Log this cache operation
+ */
+ ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache: "
+ "request=SET status=%s id=%s timeout=%ds (session caching)",
+ rc == TRUE ? "OK" : "BAD",
+ SSL_SESSION_id2sz(pNew->session_id, pNew->session_id_length),
+ t-time(NULL));
+
+ /*
+ * return 0 which means to OpenSSL that the pNew 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 *pCopy)
+{
+ conn_rec *conn;
+ server_rec *s;
+ SSL_SESSION *pSession;
+
+ /*
+ * Get Apache context back through OpenSSL context
+ */
+ conn = (conn_rec *)SSL_get_app_data(ssl);
+ s = conn->server;
+
+ /*
+ * Try to retrieve the SSL_SESSION from the inter-process cache
+ */
+ pSession = ssl_scache_retrieve(s, id, idlen);
+
+ /*
+ * Log this cache operation
+ */
+ if (pSession != NULL)
+ ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache: "
+ "request=GET status=FOUND id=%s (session reuse)",
+ SSL_SESSION_id2sz(id, idlen));
+ else
+ ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache: "
+ "request=GET status=MISSED id=%s (session renewal)",
+ SSL_SESSION_id2sz(id, idlen));
+
+ /*
+ * Return NULL or the retrieved SSL_SESSION. But indicate (by
+ * setting pCopy 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.
+ */
+ *pCopy = 0;
+ return pSession;
+}
+
+/*
+ * 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 *pSession)
+{
+ server_rec *s;
+
+ /*
+ * Get Apache context back through OpenSSL context
+ */
+ s = (server_rec *)SSL_CTX_get_app_data(ctx);
+ if (s == NULL) /* on server shutdown Apache is already gone */
+ return;
+
+ /*
+ * Remove the SSL_SESSION from the inter-process cache
+ */
+ ssl_scache_remove(s, pSession->session_id, pSession->session_id_length);
+
+ /*
+ * Log this cache operation
+ */
+ ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache: "
+ "request=REM status=OK id=%s (session dead)",
+ SSL_SESSION_id2sz(pSession->session_id,
+ pSession->session_id_length));
+
+ return;
+}
+
+/*
+ * This callback function is executed while OpenSSL processes the
+ * SSL handshake and does SSL record layer stuff. We use it to
+ * trace OpenSSL's processing in out SSL logfile.
+ */
+void ssl_callback_LogTracingState(SSL *ssl, int where, int rc)
+{
+ conn_rec *c;
+ server_rec *s;
+ SSLSrvConfigRec *sc;
+ char *str;
+
+ /*
+ * find corresponding server
+ */
+ if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL)
+ return;
+ s = c->server;
+ if ((sc = mySrvConfig(s)) == NULL)
+ return;
+
+ /*
+ * create the various trace messages
+ */
+ if (sc->nLogLevel >= SSL_LOG_TRACE) {
+ if (where & SSL_CB_HANDSHAKE_START)
+ ssl_log(s, SSL_LOG_TRACE, "%s: Handshake: start", SSL_LIBRARY_NAME);
+ else if (where & SSL_CB_HANDSHAKE_DONE)
+ ssl_log(s, SSL_LOG_TRACE, "%s: Handshake: done", SSL_LIBRARY_NAME);
+ else if (where & SSL_CB_LOOP)
+ ssl_log(s, SSL_LOG_TRACE, "%s: Loop: %s",
+ SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+ else if (where & SSL_CB_READ)
+ ssl_log(s, SSL_LOG_TRACE, "%s: Read: %s",
+ SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+ else if (where & SSL_CB_WRITE)
+ ssl_log(s, SSL_LOG_TRACE, "%s: Write: %s",
+ SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+ else if (where & SSL_CB_ALERT) {
+ str = (where & SSL_CB_READ) ? "read" : "write";
+ ssl_log(s, SSL_LOG_TRACE, "%s: Alert: %s:%s:%s\n",
+ 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)
+ ssl_log(s, SSL_LOG_TRACE, "%s: Exit: failed in %s",
+ SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+ else if (rc < 0)
+ ssl_log(s, SSL_LOG_TRACE, "%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) {
+ ssl_log(s, SSL_LOG_INFO,
+ "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"));
+ }
+
+ return;
+}
+
diff --git a/modules/ssl/ssl_engine_log.c b/modules/ssl/ssl_engine_log.c
new file mode 100644
index 0000000000..0e1c53a852
--- /dev/null
+++ b/modules/ssl/ssl_engine_log.c
@@ -0,0 +1,326 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_log.c
+** Logging Facility
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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
+** _________________________________________________________________
+*/
+
+/*
+ * Open the SSL logfile
+ */
+void ssl_log_open(server_rec *s_main, server_rec *s, pool *p)
+{
+ char *szLogFile;
+ SSLSrvConfigRec *sc_main = mySrvConfig(s_main);
+ SSLSrvConfigRec *sc = mySrvConfig(s);
+ piped_log *pl;
+
+ /*
+ * Short-circuit for inherited logfiles in order to save
+ * filedescriptors in mass-vhost situation. Be careful, this works
+ * fine because the close happens implicitly by the pool facility.
+ */
+ if ( s != s_main
+ && sc_main->fileLogFile != NULL
+ && ( (sc->szLogFile == NULL)
+ || ( sc->szLogFile != NULL
+ && sc_main->szLogFile != NULL
+ && strEQ(sc->szLogFile, sc_main->szLogFile)))) {
+ sc->fileLogFile = sc_main->fileLogFile;
+ }
+ else if (sc->szLogFile != NULL) {
+ if (strEQ(sc->szLogFile, "/dev/null"))
+ return;
+ else if (sc->szLogFile[0] == '|') {
+ szLogFile = ssl_util_server_root_relative(p, "log", sc->szLogFile+1);
+ if ((pl = ap_open_piped_log(p, szLogFile)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot open reliable pipe to SSL logfile filter %s", szLogFile);
+ ssl_die();
+ }
+ sc->fileLogFile = ap_pfdopen(p, ap_piped_log_write_fd(pl), "a");
+ setbuf(sc->fileLogFile, NULL);
+ }
+ else {
+ szLogFile = ssl_util_server_root_relative(p, "log", sc->szLogFile);
+ if ((sc->fileLogFile = ap_pfopen(p, szLogFile, "a")) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot open SSL logfile %s", szLogFile);
+ ssl_die();
+ }
+ setbuf(sc->fileLogFile, NULL);
+ }
+ }
+ return;
+}
+
+static struct {
+ int nLevel;
+ char *szLevel;
+} ssl_log_level2string[] = {
+ { SSL_LOG_ERROR, "error" },
+ { SSL_LOG_WARN, "warn" },
+ { SSL_LOG_INFO, "info" },
+ { SSL_LOG_TRACE, "trace" },
+ { SSL_LOG_DEBUG, "debug" },
+ { 0, NULL }
+};
+
+static struct {
+ char *cpPattern;
+ 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 char *ssl_log_annotation(char *error)
+{
+ char *errstr;
+ int i;
+
+ errstr = NULL;
+ for (i = 0; ssl_log_annotate[i].cpPattern != NULL; i++) {
+ if (ap_strcmp_match(error, ssl_log_annotate[i].cpPattern) == 0) {
+ errstr = ssl_log_annotate[i].cpAnnotation;
+ break;
+ }
+ }
+ return errstr;
+}
+
+BOOL ssl_log_applies(server_rec *s, int level)
+{
+ SSLSrvConfigRec *sc;
+
+ sc = mySrvConfig(s);
+ if ( sc->fileLogFile == NULL
+ && !(level & SSL_LOG_ERROR))
+ return FALSE;
+ if ( level > sc->nLogLevel
+ && !(level & SSL_LOG_ERROR))
+ return FALSE;
+ return TRUE;
+}
+
+void ssl_log(server_rec *s, int level, const char *msg, ...)
+{
+ char tstr[80];
+ char lstr[20];
+ char vstr[1024];
+ char str[1024];
+ char nstr[2];
+ int timz;
+ struct tm *t;
+ va_list ap;
+ int add;
+ int i;
+ char *astr;
+ int safe_errno;
+ unsigned long e;
+ SSLSrvConfigRec *sc;
+ char *cpE;
+ char *cpA;
+
+ /* initialization */
+ va_start(ap, msg);
+ safe_errno = errno;
+ sc = mySrvConfig(s);
+
+ /* strip out additional flags */
+ add = (level & ~SSL_LOG_MASK);
+ level = (level & SSL_LOG_MASK);
+
+ /* reduce flags when not reasonable in context */
+ if (add & SSL_ADD_ERRNO && errno == 0)
+ add &= ~SSL_ADD_ERRNO;
+ if (add & SSL_ADD_SSLERR && ERR_peek_error() == 0)
+ add &= ~SSL_ADD_SSLERR;
+
+ /* we log only levels below, except for errors */
+ if ( sc->fileLogFile == NULL
+ && !(level & SSL_LOG_ERROR))
+ return;
+ if ( level > sc->nLogLevel
+ && !(level & SSL_LOG_ERROR))
+ return;
+
+ /* determine the time entry string */
+ if (add & SSL_NO_TIMESTAMP)
+ tstr[0] = NUL;
+ else {
+ t = ap_get_gmtoff(&timz);
+ strftime(tstr, 80, "[%d/%b/%Y %H:%M:%S", t);
+ i = strlen(tstr);
+ ap_snprintf(tstr+i, 80-i, " %05d] ", (unsigned int)getpid());
+ }
+
+ /* determine whether newline should be written */
+ if (add & SSL_NO_NEWLINE)
+ nstr[0] = NUL;
+ else {
+ nstr[0] = '\n';
+ nstr[1] = NUL;
+ }
+
+ /* determine level name */
+ lstr[0] = NUL;
+ if (!(add & SSL_NO_LEVELID)) {
+ for (i = 0; ssl_log_level2string[i].nLevel != 0; i++) {
+ if (ssl_log_level2string[i].nLevel == level) {
+ ap_snprintf(lstr, sizeof(lstr), "[%s]", ssl_log_level2string[i].szLevel);
+ break;
+ }
+ }
+ for (i = strlen(lstr); i <= 7; i++)
+ lstr[i] = ' ';
+ lstr[i] = NUL;
+ }
+
+ /* create custom message */
+ ap_vsnprintf(vstr, sizeof(vstr), msg, ap);
+
+ /* write out SSLog message */
+ if ((add & SSL_ADD_ERRNO) && (add & SSL_ADD_SSLERR))
+ astr = " (System and " SSL_LIBRARY_NAME " library errors follow)";
+ else if (add & SSL_ADD_ERRNO)
+ astr = " (System error follows)";
+ else if (add & SSL_ADD_SSLERR)
+ astr = " (" SSL_LIBRARY_NAME " library error follows)";
+ else
+ astr = "";
+ if (level <= sc->nLogLevel && sc->fileLogFile != NULL) {
+ ap_snprintf(str, sizeof(str), "%s%s%s%s%s", tstr, lstr, vstr, astr, nstr);
+ fprintf(sc->fileLogFile, "%s", str);
+ }
+ if (level & SSL_LOG_ERROR)
+ ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s,
+ "mod_ssl: %s%s", vstr, astr);
+
+ /* write out additional attachment messages */
+ if (add & SSL_ADD_ERRNO) {
+ if (level <= sc->nLogLevel && sc->fileLogFile != NULL) {
+ ap_snprintf(str, sizeof(str), "%s%sSystem: %s (errno: %d)%s",
+ tstr, lstr, strerror(safe_errno), safe_errno, nstr);
+ fprintf(sc->fileLogFile, "%s", str);
+ }
+ if (level & SSL_LOG_ERROR)
+ ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s,
+ "System: %s (errno: %d)",
+ strerror(safe_errno), safe_errno);
+ }
+ if (add & SSL_ADD_SSLERR) {
+ while ((e = ERR_get_error())) {
+ cpE = ERR_error_string(e, NULL);
+ cpA = ssl_log_annotation(cpE);
+ if (level <= sc->nLogLevel && sc->fileLogFile != NULL) {
+ ap_snprintf(str, sizeof(str), "%s%s%s: %s%s%s%s%s",
+ tstr, lstr, SSL_LIBRARY_NAME, cpE,
+ cpA != NULL ? " [Hint: " : "",
+ cpA != NULL ? cpA : "", cpA != NULL ? "]" : "",
+ nstr);
+ fprintf(sc->fileLogFile, "%s", str);
+ }
+ if (level & SSL_LOG_ERROR)
+ ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, s,
+ "%s: %s%s%s%s", SSL_LIBRARY_NAME, cpE,
+ cpA != NULL ? " [Hint: " : "",
+ cpA != NULL ? cpA : "", cpA != NULL ? "]" : "");
+ }
+ }
+ /* make sure the next log starts from a clean base */
+ /* ERR_clear_error(); */
+
+ /* cleanup and return */
+ if (sc->fileLogFile != NULL)
+ fflush(sc->fileLogFile);
+ errno = safe_errno;
+ va_end(ap);
+ return;
+}
+
+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);
+}
+
diff --git a/modules/ssl/ssl_engine_mutex.c b/modules/ssl/ssl_engine_mutex.c
new file mode 100644
index 0000000000..146f9ce4d9
--- /dev/null
+++ b/modules/ssl/ssl_engine_mutex.c
@@ -0,0 +1,397 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_mutex.c
+** Semaphore for Mutual Exclusion
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``Real programmers confuse
+ Christmas and Halloween
+ because DEC 25 = OCT 31.''
+ -- Unknown */
+#include "mod_ssl.h"
+
+
+/* _________________________________________________________________
+**
+** Mutex Support (Common)
+** _________________________________________________________________
+*/
+
+void ssl_mutex_init(server_rec *s, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+
+ if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
+ ssl_mutex_file_create(s, p);
+ else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
+ ssl_mutex_sem_create(s, p);
+ return;
+}
+
+void ssl_mutex_reinit(server_rec *s, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+
+ if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
+ ssl_mutex_file_open(s, p);
+ else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
+ ssl_mutex_sem_open(s, p);
+ return;
+}
+
+void ssl_mutex_on(server_rec *s)
+{
+ SSLModConfigRec *mc = myModConfig();
+ BOOL ok = TRUE;
+
+ if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
+ ok = ssl_mutex_file_acquire();
+ else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
+ ok = ssl_mutex_sem_acquire();
+ if (!ok)
+ ssl_log(s, SSL_LOG_WARN, "Failed to acquire global mutex lock");
+ return;
+}
+
+void ssl_mutex_off(server_rec *s)
+{
+ SSLModConfigRec *mc = myModConfig();
+ BOOL ok = TRUE;
+
+ if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
+ ok = ssl_mutex_file_release();
+ else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
+ ok = ssl_mutex_sem_release();
+ if (!ok)
+ ssl_log(s, SSL_LOG_WARN, "Failed to release global mutex lock");
+ return;
+}
+
+void ssl_mutex_kill(server_rec *s)
+{
+ SSLModConfigRec *mc = myModConfig();
+
+ if (mc->nMutexMode == SSL_MUTEXMODE_FILE)
+ ssl_mutex_file_remove(s);
+ else if (mc->nMutexMode == SSL_MUTEXMODE_SEM)
+ ssl_mutex_sem_remove(s);
+ return;
+}
+
+
+/* _________________________________________________________________
+**
+** Mutex Support (Lockfile)
+** _________________________________________________________________
+*/
+
+void ssl_mutex_file_create(server_rec *s, pool *p)
+{
+#ifndef WIN32
+ SSLModConfigRec *mc = myModConfig();
+
+ /* create the lockfile */
+ unlink(mc->szMutexFile);
+ if ((mc->nMutexFD = ap_popenf(p, mc->szMutexFile,
+ O_WRONLY|O_CREAT, SSL_MUTEX_LOCK_MODE)) < 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Parent process could not create SSLMutex lockfile %s",
+ mc->szMutexFile);
+ ssl_die();
+ }
+ ap_pclosef(p, mc->nMutexFD);
+
+ /* make sure the childs have access to this file */
+#ifndef OS2
+ if (geteuid() == 0 /* is superuser */)
+ chown(mc->szMutexFile, ap_user_id, -1 /* no gid change */);
+#endif
+
+ /* open the lockfile for real */
+ if ((mc->nMutexFD = ap_popenf(p, mc->szMutexFile,
+ O_WRONLY, SSL_MUTEX_LOCK_MODE)) < 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Parent could not open SSLMutex lockfile %s",
+ mc->szMutexFile);
+ ssl_die();
+ }
+#endif
+ return;
+}
+
+void ssl_mutex_file_open(server_rec *s, pool *p)
+{
+#ifndef WIN32
+ SSLModConfigRec *mc = myModConfig();
+
+ /* open the lockfile (once per child) to get a unique fd */
+ if ((mc->nMutexFD = ap_popenf(p, mc->szMutexFile,
+ O_WRONLY, SSL_MUTEX_LOCK_MODE)) < 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Child could not open SSLMutex lockfile %s",
+ mc->szMutexFile);
+ ssl_die();
+ }
+#endif
+ return;
+}
+
+void ssl_mutex_file_remove(void *data)
+{
+#ifndef WIN32
+ SSLModConfigRec *mc = myModConfig();
+
+ /* remove the mutex lockfile */
+ unlink(mc->szMutexFile);
+#endif
+ return;
+}
+
+#ifndef WIN32
+#ifdef SSL_USE_FCNTL
+static struct flock lock_it;
+static struct flock unlock_it;
+#endif
+#endif
+
+BOOL ssl_mutex_file_acquire(void)
+{
+ int rc = -1;
+#ifndef WIN32
+ SSLModConfigRec *mc = myModConfig();
+
+#ifdef SSL_USE_FCNTL
+ lock_it.l_whence = SEEK_SET; /* from current point */
+ lock_it.l_start = 0; /* -"- */
+ lock_it.l_len = 0; /* until end of file */
+ lock_it.l_type = F_WRLCK; /* set exclusive/write lock */
+ lock_it.l_pid = 0; /* pid not actually interesting */
+
+ while ( ((rc = fcntl(mc->nMutexFD, F_SETLKW, &lock_it)) < 0)
+ && (errno == EINTR) )
+ ;
+#endif
+#ifdef SSL_USE_FLOCK
+ while ( ((rc = flock(mc->nMutexFD, LOCK_EX)) < 0)
+ && (errno == EINTR) )
+ ;
+#endif
+#endif
+
+ if (rc < 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+BOOL ssl_mutex_file_release(void)
+{
+ int rc = -1;
+#ifndef WIN32
+ SSLModConfigRec *mc = myModConfig();
+
+#ifdef SSL_USE_FCNTL
+ unlock_it.l_whence = SEEK_SET; /* from current point */
+ unlock_it.l_start = 0; /* -"- */
+ unlock_it.l_len = 0; /* until end of file */
+ unlock_it.l_type = F_UNLCK; /* unlock */
+ unlock_it.l_pid = 0; /* pid not actually interesting */
+
+ while ( (rc = fcntl(mc->nMutexFD, F_SETLKW, &unlock_it)) < 0
+ && (errno == EINTR) )
+ ;
+#endif
+#ifdef SSL_USE_FLOCK
+ while ( (rc = flock(mc->nMutexFD, LOCK_UN)) < 0
+ && (errno == EINTR) )
+ ;
+#endif
+#endif
+
+ if (rc < 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+/* _________________________________________________________________
+**
+** Mutex Support (Process Semaphore)
+** _________________________________________________________________
+*/
+
+void ssl_mutex_sem_create(server_rec *s, pool *p)
+{
+#ifdef SSL_CAN_USE_SEM
+ int semid;
+ SSLModConfigRec *mc = myModConfig();
+#ifdef SSL_HAVE_IPCSEM
+ union ssl_ipc_semun semctlarg;
+ struct semid_ds semctlbuf;
+#endif
+
+#ifdef SSL_HAVE_IPCSEM
+ semid = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
+ if (semid == -1 && errno == EEXIST)
+ semid = semget(IPC_PRIVATE, 1, IPC_EXCL|S_IRUSR|S_IWUSR);
+ if (semid == -1) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Parent process could not create private SSLMutex semaphore");
+ ssl_die();
+ }
+ semctlarg.val = 0;
+ if (semctl(semid, 0, SETVAL, semctlarg) < 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Parent process could not initialize SSLMutex semaphore value");
+ ssl_die();
+ }
+ semctlbuf.sem_perm.uid = ap_user_id;
+ semctlbuf.sem_perm.gid = ap_group_id;
+ semctlbuf.sem_perm.mode = 0660;
+ semctlarg.buf = &semctlbuf;
+ if (semctl(semid, 0, IPC_SET, semctlarg) < 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Parent process could not set permissions for SSLMutex semaphore");
+ ssl_die();
+ }
+#endif
+#ifdef SSL_HAVE_W32SEM
+ semid = (int)ap_create_mutex("mod_ssl_mutex");
+#endif
+ mc->nMutexSEMID = semid;
+#endif
+ return;
+}
+
+void ssl_mutex_sem_open(server_rec *s, pool *p)
+{
+#ifdef SSL_CAN_USE_SEM
+#ifdef SSL_HAVE_W32SEM
+ SSLModConfigRec *mc = myModConfig();
+
+ mc->nMutexSEMID = (int)ap_open_mutex("mod_ssl_mutex");
+#endif
+#endif
+ return;
+}
+
+void ssl_mutex_sem_remove(void *data)
+{
+#ifdef SSL_CAN_USE_SEM
+ SSLModConfigRec *mc = myModConfig();
+
+#ifdef SSL_HAVE_IPCSEM
+ semctl(mc->nMutexSEMID, 0, IPC_RMID, 0);
+#endif
+#ifdef SSL_HAVE_W32SEM
+ ap_destroy_mutex((mutex *)mc->nMutexSEMID);
+#endif
+#endif
+ return;
+}
+
+BOOL ssl_mutex_sem_acquire(void)
+{
+ int rc = 0;
+#ifdef SSL_CAN_USE_SEM
+ SSLModConfigRec *mc = myModConfig();
+
+#ifdef SSL_HAVE_IPCSEM
+ struct sembuf sb[] = {
+ { 0, 0, 0 }, /* wait for semaphore */
+ { 0, 1, SEM_UNDO } /* increment semaphore */
+ };
+
+ while ( (rc = semop(mc->nMutexSEMID, sb, 2)) < 0
+ && (errno == EINTR) )
+ ;
+#endif
+#ifdef SSL_HAVE_W32SEM
+ rc = ap_acquire_mutex((mutex *)mc->nMutexSEMID);
+#endif
+#endif
+ if (rc != 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+BOOL ssl_mutex_sem_release(void)
+{
+ int rc = 0;
+#ifdef SSL_CAN_USE_SEM
+ SSLModConfigRec *mc = myModConfig();
+
+#ifdef SSL_HAVE_IPCSEM
+ struct sembuf sb[] = {
+ { 0, -1, SEM_UNDO } /* decrements semaphore */
+ };
+
+ while ( (rc = semop(mc->nMutexSEMID, sb, 1)) < 0
+ && (errno == EINTR) )
+ ;
+#endif
+#ifdef SSL_HAVE_W32SEM
+ rc = ap_release_mutex((mutex *)mc->nMutexSEMID);
+#endif
+#endif
+ if (rc != 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c
new file mode 100644
index 0000000000..2cef4e309e
--- /dev/null
+++ b/modules/ssl/ssl_engine_pphrase.c
@@ -0,0 +1,545 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_pphrase.c
+** Pass Phrase Dialog
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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"
+
+
+/* _________________________________________________________________
+**
+** Pass Phrase and Private Key Handling
+** _________________________________________________________________
+*/
+
+#define STDERR_FILENO_STORE 50
+#define BUILTIN_DIALOG_BACKOFF 2
+#define BUILTIN_DIALOG_RETRIES 5
+
+void ssl_pphrase_Handle(server_rec *s, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+ SSLSrvConfigRec *sc;
+ server_rec *pServ;
+ char *cpVHostID;
+ char szPath[MAX_STRING_LEN];
+ EVP_PKEY *pPrivateKey;
+ ssl_asn1_t *asn1;
+ unsigned char *ucp;
+ X509 *pX509Cert;
+ FILE *fp;
+ BOOL bReadable;
+ ssl_ds_array *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;
+
+ /*
+ * Start with a fresh pass phrase array
+ */
+ aPassPhrase = ssl_ds_array_make(p, sizeof(char *));
+ nPassPhrase = 0;
+ nPassPhraseDialog = 0;
+
+ /*
+ * Walk through all configured servers
+ */
+ for (pServ = s; pServ != NULL; pServ = pServ->next) {
+ sc = mySrvConfig(pServ);
+
+ if (!sc->bEnabled)
+ continue;
+
+ cpVHostID = ssl_util_vhostid(p, pServ);
+ ssl_log(pServ, SSL_LOG_INFO,
+ "Init: Loading certificate & private key of SSL-aware server %s",
+ cpVHostID);
+
+ /*
+ * Read in server certificate(s): This is the easy part
+ * because this file isn't encrypted in any way.
+ */
+ if (sc->szPublicCertFile[0] == NULL) {
+ ssl_log(pServ, SSL_LOG_ERROR,
+ "Init: Server %s should be SSL-aware but has no certificate configured "
+ "[Hint: SSLCertificateFile]", cpVHostID);
+ ssl_die();
+ }
+ algoCert = SSL_ALGO_UNKNOWN;
+ algoKey = SSL_ALGO_UNKNOWN;
+ for (i = 0, j = 0; i < SSL_AIDX_MAX && sc->szPublicCertFile[i] != NULL; i++) {
+
+ ap_cpystrn(szPath, sc->szPublicCertFile[i], sizeof(szPath));
+ if ((fp = ap_pfopen(p, szPath, "r")) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Init: Can't open server certificate file %s", szPath);
+ ssl_die();
+ }
+ if ((pX509Cert = SSL_read_X509(fp, NULL, NULL)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Unable to read server certificate from file %s", szPath);
+ ssl_die();
+ }
+ ap_pfclose(p, fp);
+
+ /*
+ * 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) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Multiple %s server certificates not allowed", an);
+ 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 = ap_psprintf(mc->pPool, "%s:%s", cpVHostID, an);
+ asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tPublicCert, cp);
+ asn1->nData = i2d_X509(pX509Cert, NULL);
+ asn1->cpData = ap_palloc(mc->pPool, asn1->nData);
+ ucp = asn1->cpData; 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->szPrivateKeyFile[j] != NULL)
+ ap_cpystrn(szPath, sc->szPrivateKeyFile[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 ((fp = ap_pfopen(p, szPath, "r")) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Init: Can't open server private key file %s", szPath);
+ ssl_die();
+ }
+ cpPassPhraseCur = NULL;
+ bReadable = ((pPrivateKey = SSL_read_PrivateKey(fp, NULL,
+ ssl_pphrase_Handle_CB)) != NULL ? TRUE : FALSE);
+ ap_pfclose(p, fp);
+
+ /*
+ * 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...
+ */
+ if ( sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN
+ && cpPassPhraseCur != NULL
+ && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) {
+ fprintf(stdout, "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)
+ sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF)*5);
+ continue;
+ }
+
+ /*
+ * Ok, anything else now means a fatal error.
+ */
+ if (cpPassPhraseCur == NULL)
+ ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Private key not found");
+ if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
+ fprintf(stdout, "Apache:mod_ssl:Error: Private key not found.\n");
+ fprintf(stdout, "**Stopped\n");
+ }
+ else {
+ ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Pass phrase incorrect");
+ if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
+ fprintf(stdout, "Apache:mod_ssl:Error: Pass phrase incorrect.\n");
+ fprintf(stdout, "**Stopped\n");
+ }
+ }
+ ssl_die();
+ }
+
+ if (pPrivateKey == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Unable to read server private key from file %s", szPath);
+ 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) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Multiple %s server private keys not allowed", an);
+ ssl_die();
+ }
+ algoKey |= at;
+
+ /*
+ * Log the type of reading
+ */
+ if (nPassPhraseDialogCur == 0)
+ ssl_log(pServ, SSL_LOG_TRACE,
+ "Init: (%s) unencrypted %s private key - pass phrase not required",
+ cpVHostID, an);
+ else {
+ if (cpPassPhraseCur != NULL)
+ ssl_log(pServ, SSL_LOG_TRACE,
+ "Init: (%s) encrypted %s private key - pass phrase requested",
+ cpVHostID, an);
+ else
+ ssl_log(pServ, SSL_LOG_TRACE,
+ "Init: (%s) encrypted %s private key - pass phrase reused",
+ cpVHostID, an);
+ }
+
+ /*
+ * Ok, when we have one more pass phrase store it
+ */
+ if (cpPassPhraseCur != NULL) {
+ cpp = (char **)ssl_ds_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 = ap_psprintf(mc->pPool, "%s:%s", cpVHostID, an);
+ asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tPrivateKey, cp);
+ asn1->nData = i2d_PrivateKey(pPrivateKey, NULL);
+ asn1->cpData = ap_palloc(mc->pPool, asn1->nData);
+ ucp = asn1->cpData; i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */
+
+ /*
+ * Free the private key structure
+ */
+ EVP_PKEY_free(pPrivateKey);
+ }
+ }
+
+ /*
+ * Let the user know when we're successful.
+ */
+ if (nPassPhraseDialog > 0) {
+ sc = mySrvConfig(s);
+ if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
+ fprintf(stdout, "\n");
+ fprintf(stdout, "Ok: Pass Phrase Dialog successful.\n");
+ }
+ }
+
+ /*
+ * Wipe out the used memory from the
+ * pass phrase array and then deallocate it
+ */
+ if (!ssl_ds_array_isempty(aPassPhrase)) {
+ ssl_ds_array_wipeout(aPassPhrase);
+ ssl_ds_array_kill(aPassPhrase);
+ ssl_log(s, SSL_LOG_INFO, "Init: Wiped out the queried pass phrases from memory");
+ }
+
+ return;
+}
+
+int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify)
+{
+ SSLModConfigRec *mc = myModConfig();
+ server_rec *s;
+ pool *p;
+ ssl_ds_array *aPassPhrase;
+ SSLSrvConfigRec *sc;
+ int *pnPassPhraseCur;
+ char **cppPassPhraseCur;
+ char *cpVHostID;
+ char *cpAlgoType;
+ int *pnPassPhraseDialog;
+ int *pnPassPhraseDialogCur;
+ BOOL *pbPassPhraseDialogOnce;
+ int stderr_store;
+ char **cpp;
+ int len = -1;
+
+ /*
+ * Reconnect to the context of ssl_phrase_Handle()
+ */
+ s = myCtxVarGet(mc, 1, server_rec *);
+ p = myCtxVarGet(mc, 2, pool *);
+ aPassPhrase = myCtxVarGet(mc, 3, ssl_ds_array *);
+ 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 = (char **)ssl_ds_array_get(aPassPhrase, *pnPassPhraseCur)) != NULL) {
+ ap_cpystrn(buf, *cpp, bufsize);
+ len = strlen(buf);
+ return len;
+ }
+
+ /*
+ * Builtin dialog
+ */
+ if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
+ char *prompt;
+ int i;
+#ifdef WIN32
+ FILE *con;
+#endif
+
+ ssl_log(s, SSL_LOG_INFO,
+ "Init: Requesting pass phrase via builtin terminal dialog");
+
+ /*
+ * Reconnect STDERR to terminal (here STDOUT) because
+ * at our init stage Apache already connected STDERR
+ * to the general error logfile.
+ */
+#ifdef WIN32
+ stderr_store = STDERR_FILENO_STORE;
+#else
+ if ((stderr_store = open("/dev/null", O_WRONLY)) == -1)
+ stderr_store = STDERR_FILENO_STORE;
+#endif
+ dup2(STDERR_FILENO, stderr_store);
+#ifdef WIN32
+ if ((con = fopen("con", "w")) != NULL)
+ dup2(fileno(con), STDERR_FILENO);
+ else
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+#else
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+#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) {
+ fprintf(stderr, "%s mod_ssl/%s (Pass Phrase Dialog)\n",
+ SERVER_BASEVERSION, MOD_SSL_VERSION);
+ fprintf(stderr, "Some of your private key files are encrypted for security reasons.\n");
+ fprintf(stderr, "In order to read them you have to provide us with the pass phrases.\n");
+ }
+ if (*pbPassPhraseDialogOnce) {
+ *pbPassPhraseDialogOnce = FALSE;
+ fprintf(stderr, "\n");
+ fprintf(stderr, "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 (;;) {
+ if ((i = EVP_read_pw_string(buf, bufsize, prompt, FALSE)) != 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)
+ fprintf(stderr, "Apache:mod_ssl:Error: Pass phrase empty (needs to be at least 1 character).\n");
+ else
+ break;
+ }
+
+ /*
+ * Restore STDERR to Apache error logfile
+ */
+ dup2(stderr_store, STDERR_FILENO);
+ close(stderr_store);
+#ifdef WIN32
+ if (con != NULL)
+ fclose(con);
+#endif
+ }
+
+ /*
+ * Filter program
+ */
+ else if (sc->nPassPhraseDialogType == SSL_PPTYPE_FILTER) {
+ char *cmd;
+ char *result;
+
+ ssl_log(s, SSL_LOG_INFO,
+ "Init: Requesting pass phrase from dialog filter program (%s)",
+ sc->szPassPhraseDialogPath);
+
+ if (strchr(sc->szPassPhraseDialogPath, ' ') != NULL)
+ cmd = ap_psprintf(p, "\"%s\" %s %s", sc->szPassPhraseDialogPath, cpVHostID, cpAlgoType);
+ else
+ cmd = ap_psprintf(p, "%s %s %s", sc->szPassPhraseDialogPath, cpVHostID, cpAlgoType);
+ result = ssl_util_readfilter(s, p, cmd);
+ ap_cpystrn(buf, result, bufsize);
+ len = strlen(buf);
+ }
+
+ /*
+ * Ok, we now have the pass phrase, so give it back
+ */
+ *cppPassPhraseCur = ap_pstrdup(p, buf);
+
+ /*
+ * And return it's length to OpenSSL...
+ */
+ return (len);
+}
+
diff --git a/modules/ssl/ssl_engine_rand.c b/modules/ssl/ssl_engine_rand.c
new file mode 100644
index 0000000000..afb49b4f5c
--- /dev/null
+++ b/modules/ssl/ssl_engine_rand.c
@@ -0,0 +1,215 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_rand.c
+** Random Number Generator Seeding
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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(pool *, FILE *, int);
+
+int ssl_rand_seed(server_rec *s, pool *p, ssl_rsctx_t nCtx, char *prefix)
+{
+ SSLModConfigRec *mc;
+ array_header *apRandSeed;
+ ssl_randseed_t *pRandSeeds;
+ ssl_randseed_t *pRandSeed;
+ unsigned char stackdata[256];
+ int nReq, nDone;
+ FILE *fp;
+ int i, n, l;
+ time_t t;
+ pid_t pid;
+
+ mc = myModConfig();
+ 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 ((fp = ap_pfopen(p, pRandSeed->cpPath, "r")) == NULL)
+ continue;
+ nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes);
+ ap_pfclose(p, fp);
+ }
+ else if (pRandSeed->nSrc == SSL_RSSRC_EXEC) {
+ /*
+ * seed in contents generated by an external program
+ */
+ if ((fp = ssl_util_ppopen(s, p, ap_psprintf(p, "%s %d",
+ pRandSeed->cpPath, pRandSeed->nBytes))) == NULL)
+ continue;
+ nDone += ssl_rand_feedfp(p, fp, pRandSeed->nBytes);
+ ssl_util_ppclose(s, p, fp);
+ }
+#if SSL_LIBRARY_VERSION >= 0x00905100
+ 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) {
+ /*
+ * seed in the current time (usually just 4 bytes)
+ */
+ t = time(NULL);
+ l = sizeof(time_t);
+ RAND_seed((unsigned char *)&t, l);
+ nDone += l;
+
+ /*
+ * seed in the current process id (usually just 4 bytes)
+ */
+ pid = getpid();
+ l = sizeof(pid_t);
+ RAND_seed((unsigned char *)&pid, 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;
+
+ /*
+ * seed in an 1KB extract of the current scoreboard
+ */
+ if (ap_scoreboard_image != NULL) {
+ n = ssl_rand_choosenum(0, SCOREBOARD_SIZE-1024-1);
+ RAND_seed((unsigned char *)ap_scoreboard_image+n, 1024);
+ nDone += 1024;
+ }
+ }
+ }
+ }
+ ssl_log(s, SSL_LOG_INFO, "%sSeeding PRNG with %d bytes of entropy", prefix, nDone);
+
+#if SSL_LIBRARY_VERSION >= 0x00905100
+ if (RAND_status() == 0)
+ ssl_log(s, SSL_LOG_WARN, "%sPRNG still contains not sufficient entropy!", prefix);
+#endif
+ return nDone;
+}
+
+#define BUFSIZE 8192
+
+static int ssl_rand_feedfp(pool *p, FILE *fp, int nReq)
+{
+ int nDone;
+ unsigned char caBuf[BUFSIZE];
+ int nBuf;
+ int nRead;
+ int nTodo;
+
+ nDone = 0;
+ nRead = BUFSIZE;
+ nTodo = nReq;
+ while (1) {
+ if (nReq > 0)
+ nRead = (nTodo < BUFSIZE ? nTodo : BUFSIZE);
+ if ((nBuf = (int)fread(caBuf, 1, nRead, fp)) <= 0)
+ 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];
+
+ srand((unsigned int)time(NULL));
+ ap_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/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c
new file mode 100644
index 0000000000..c0755a5ec8
--- /dev/null
+++ b/modules/ssl/ssl_engine_vars.c
@@ -0,0 +1,615 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_engine_vars.c
+** Variable Lookup Facility
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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(pool *p, request_rec *r, const char *name);
+static char *ssl_var_lookup_ssl(pool *p, conn_rec *c, char *var);
+static char *ssl_var_lookup_ssl_cert(pool *p, X509 *xs, char *var);
+static char *ssl_var_lookup_ssl_cert_dn(pool *p, X509_NAME *xsname, char *var);
+static char *ssl_var_lookup_ssl_cert_valid(pool *p, ASN1_UTCTIME *tm);
+static char *ssl_var_lookup_ssl_cert_serial(pool *p, X509 *xs);
+static char *ssl_var_lookup_ssl_cert_chain(pool *p, STACK_OF(X509) *sk, char *var);
+static char *ssl_var_lookup_ssl_cert_PEM(pool *p, X509 *xs);
+static char *ssl_var_lookup_ssl_cert_verify(pool *p, conn_rec *c);
+static char *ssl_var_lookup_ssl_cipher(pool *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(pool *p, char *var);
+
+void ssl_var_register(void)
+{
+ ap_hook_configure("ap::mod_ssl::var_lookup",
+ AP_HOOK_SIG6(ptr,ptr,ptr,ptr,ptr,ptr), AP_HOOK_DECLINE(NULL));
+ ap_hook_register("ap::mod_ssl::var_lookup",
+ ssl_var_lookup, AP_HOOK_NOCTX);
+ return;
+}
+
+void ssl_var_unregister(void)
+{
+ ap_hook_unregister("ap::mod_ssl::var_lookup", ssl_var_lookup);
+ return;
+}
+
+char *ssl_var_lookup(pool *p, server_rec *s, conn_rec *c, request_rec *r, char *var)
+{
+ SSLModConfigRec *mc = myModConfig();
+ char *result;
+ BOOL resdup;
+ time_t tc;
+ struct tm *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 = 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);
+ 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 = ap_psprintf(p, "%u", ap_get_server_port(r));
+ else if (strcEQ(var, "SERVER_PROTOCOL"))
+ result = r->protocol;
+ }
+
+ /*
+ * Connection stuff
+ */
+ if (result == NULL && c != NULL) {
+ if (strcEQ(var, "REMOTE_ADDR"))
+ result = c->remote_ip;
+ else if (strcEQ(var, "REMOTE_USER"))
+ result = c->user;
+ else if (strcEQ(var, "AUTH_TYPE"))
+ result = c->ap_auth_type;
+ else if (strlen(var) > 4 && strcEQn(var, "SSL_", 4))
+ result = ssl_var_lookup_ssl(p, c, var+4);
+ else if (strcEQ(var, "HTTPS")) {
+ if (ap_ctx_get(c->client->ctx, "ssl") != NULL)
+ 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(p, var+12);
+ else if (strcEQ(var, "SERVER_SOFTWARE"))
+ result = (char *)ap_get_server_version();
+ else if (strcEQ(var, "API_VERSION")) {
+ result = ap_psprintf(p, "%d", MODULE_MAGIC_NUMBER);
+ resdup = FALSE;
+ }
+ else if (strcEQ(var, "TIME_YEAR")) {
+ tc = time(NULL);
+ tm = localtime(&tc);
+ result = ap_psprintf(p, "%02d%02d",
+ (tm->tm_year / 100) + 19, tm->tm_year % 100);
+ resdup = FALSE;
+ }
+#define MKTIMESTR(format, tmfield) \
+ tc = time(NULL); \
+ tm = localtime(&tc); \
+ result = ap_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")) {
+ tc = time(NULL);
+ tm = localtime(&tc);
+ result = ap_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 *)ap_table_get(r->notes, var+4);
+ if (result == NULL)
+ result = (char *)ap_table_get(r->subprocess_env, var+4);
+ if (result == NULL)
+ result = getenv(var+4);
+ }
+ }
+
+ if (result != NULL && resdup)
+ result = ap_pstrdup(p, result);
+ if (result == NULL)
+ result = "";
+ return result;
+}
+
+static char *ssl_var_lookup_header(pool *p, request_rec *r, const char *name)
+{
+ array_header *hdrs_arr;
+ table_entry *hdrs;
+ int i;
+
+ hdrs_arr = ap_table_elts(r->headers_in);
+ hdrs = (table_entry *)hdrs_arr->elts;
+ for (i = 0; i < hdrs_arr->nelts; ++i) {
+ if (hdrs[i].key == NULL)
+ continue;
+ if (strcEQ(hdrs[i].key, name))
+ return ap_pstrdup(p, hdrs[i].val);
+ }
+ return NULL;
+}
+
+static char *ssl_var_lookup_ssl(pool *p, conn_rec *c, char *var)
+{
+ char *result;
+ X509 *xs;
+ STACK_OF(X509) *sk;
+ SSL *ssl;
+
+ result = NULL;
+
+ ssl = ap_ctx_get(c->client->ctx, "ssl");
+ if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) {
+ result = ssl_var_lookup_ssl_version(p, var+8);
+ }
+ else if (ssl != NULL && strcEQ(var, "PROTOCOL")) {
+ result = (char *)SSL_get_version(ssl);
+ }
+ else if (ssl != NULL && strcEQ(var, "SESSION_ID")) {
+ SSL_SESSION *pSession = SSL_get_session(ssl);
+ result = ap_pstrdup(p, SSL_SESSION_id2sz(pSession->session_id,
+ pSession->session_id_length));
+ }
+ 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+17);
+ }
+ 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);
+ }
+ 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);
+ }
+ return result;
+}
+
+static char *ssl_var_lookup_ssl_cert(pool *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 = ap_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 = ap_pstrdup(p, cp);
+ 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 = ap_pstrdup(p, cp);
+ 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(xs->cert_info->signature->algorithm);
+ result = ap_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
+ resdup = FALSE;
+ }
+ else if (strcEQ(var, "A_KEY")) {
+ nid = OBJ_obj2nid(xs->cert_info->key->algor->algorithm);
+ result = ap_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 = ap_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 },
+ { "UID", NID_uniqueIdentifier },
+ { "Email", NID_pkcs9_emailAddress },
+ { NULL, 0 }
+};
+
+static char *ssl_var_lookup_ssl_cert_dn(pool *p, X509_NAME *xsname, char *var)
+{
+ char *result;
+ X509_NAME_ENTRY *xsne;
+ int i, j, n;
+
+ 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(xsname->entries); j++) {
+ xsne = sk_X509_NAME_ENTRY_value(xsname->entries, j);
+ n = OBJ_obj2nid(xsne->object);
+ if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid) {
+ result = ap_palloc(p, xsne->value->length+1);
+ ap_cpystrn(result, (char *)xsne->value->data, xsne->value->length+1);
+#ifdef CHARSET_EBCDIC
+ ascii2ebcdic(result, result, xsne->value->length);
+#endif /* CHARSET_EBCDIC */
+ result[xsne->value->length] = NUL;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+static char *ssl_var_lookup_ssl_cert_valid(pool *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 = ap_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(pool *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 = ap_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(pool *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(pool *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 = ap_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(pool *p, conn_rec *c)
+{
+ char *result;
+ long vrc;
+ char *verr;
+ char *vinfo;
+ SSL *ssl;
+ X509 *xs;
+
+ result = NULL;
+ ssl = ap_ctx_get(c->client->ctx, "ssl");
+ verr = ap_ctx_get(c->client->ctx, "ssl::verify::error");
+ vinfo = ap_ctx_get(c->client->ctx, "ssl::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 = ap_psprintf(p, "FAILED:%s", verr);
+ return result;
+}
+
+static char *ssl_var_lookup_ssl_cipher(pool *p, conn_rec *c, char *var)
+{
+ char *result;
+ BOOL resdup;
+ int usekeysize, algkeysize;
+ SSL *ssl;
+
+ result = NULL;
+ resdup = TRUE;
+
+ ssl = ap_ctx_get(c->client->ctx, "ssl");
+ ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize);
+
+ if (strEQ(var, ""))
+ result = (ssl != NULL ? (char *)SSL_get_cipher_name(ssl) : NULL);
+ else if (strcEQ(var, "_EXPORT"))
+ result = (usekeysize < 56 ? "true" : "false");
+ else if (strcEQ(var, "_USEKEYSIZE")) {
+ result = ap_psprintf(p, "%d", usekeysize);
+ resdup = FALSE;
+ }
+ else if (strcEQ(var, "_ALGKEYSIZE")) {
+ result = ap_psprintf(p, "%d", algkeysize);
+ resdup = FALSE;
+ }
+
+ if (result != NULL && resdup)
+ result = ap_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(pool *p, char *var)
+{
+ char *result;
+ char *cp, *cp2;
+
+ result = NULL;
+
+ if (strEQ(var, "PRODUCT")) {
+#if defined(SSL_PRODUCT_NAME) && defined(SSL_PRODUCT_VERSION)
+ result = ap_psprintf(p, "%s/%s", SSL_PRODUCT_NAME, SSL_PRODUCT_VERSION);
+#else
+ result = NULL;
+#endif
+ }
+ else if (strEQ(var, "INTERFACE")) {
+ result = ap_psprintf(p, "mod_ssl/%s", MOD_SSL_VERSION);
+ }
+ else if (strEQ(var, "LIBRARY")) {
+ result = ap_pstrdup(p, SSL_LIBRARY_TEXT);
+ if ((cp = strchr(result, ' ')) != NULL) {
+ *cp = '/';
+ if ((cp2 = strchr(cp, ' ')) != NULL)
+ *cp2 = NUL;
+ }
+ }
+ return result;
+}
+
diff --git a/modules/ssl/ssl_expr.c b/modules/ssl/ssl_expr.c
new file mode 100644
index 0000000000..49ab873ded
--- /dev/null
+++ b/modules/ssl/ssl_expr.c
@@ -0,0 +1,119 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_expr.c
+** Expression Handling
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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(pool *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 *)ap_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/modules/ssl/ssl_expr.h b/modules/ssl/ssl_expr.h
new file mode 100644
index 0000000000..419bb02192
--- /dev/null
+++ b/modules/ssl/ssl_expr.h
@@ -0,0 +1,139 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_expr.h
+** Expression Handling (Header)
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+ /* ``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;
+} ssl_expr_node;
+
+typedef ssl_expr_node ssl_expr;
+
+typedef struct {
+ pool *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(pool *, 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/modules/ssl/ssl_expr_eval.c b/modules/ssl/ssl_expr_eval.c
new file mode 100644
index 0000000000..d8c5ea5f9e
--- /dev/null
+++ b/modules/ssl/ssl_expr_eval.c
@@ -0,0 +1,282 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_expr_eval.c
+** Expression Evaluation
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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 (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 !(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)
+{
+ FILE *fp;
+ char *buf;
+ int len;
+
+ if ((fp = ap_pfopen(r->pool, filename, "r")) == NULL) {
+ ssl_expr_error = "Cannot open file";
+ return "";
+ }
+ fseek(fp, 0, SEEK_END);
+ len = ftell(fp);
+ if (len == 0) {
+ buf = (char *)ap_palloc(r->pool, sizeof(char) * 1);
+ *buf = NUL;
+ }
+ else {
+ if ((buf = (char *)ap_palloc(r->pool, sizeof(char) * len+1)) == NULL) {
+ ssl_expr_error = "Cannot allocate memory";
+ ap_pfclose(r->pool, fp);
+ return "";
+ }
+ fseek(fp, 0, SEEK_SET);
+ if (fread(buf, len, 1, fp) == 0) {
+ ssl_expr_error = "Cannot read from file";
+ fclose(fp);
+ return ("");
+ }
+ buf[len] = NUL;
+ }
+ ap_pfclose(r->pool, 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/modules/ssl/ssl_expr_parse.c b/modules/ssl/ssl_expr_parse.c
new file mode 100644
index 0000000000..8e35553a4e
--- /dev/null
+++ b/modules/ssl/ssl_expr_parse.c
@@ -0,0 +1,605 @@
+#ifndef lint
+static char const
+ssl_expr_yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.28 2000/01/17 02:04:06 bde Exp $";
+#endif
+#include <stdlib.h>
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define YYLEX ssl_expr_yylex()
+#define YYEMPTY -1
+#define ssl_expr_yyclearin (ssl_expr_yychar=(YYEMPTY))
+#define ssl_expr_yyerrok (ssl_expr_yyerrflag=0)
+#define YYRECOVERING() (ssl_expr_yyerrflag!=0)
+static int ssl_expr_yygrowstack();
+#define YYPREFIX "ssl_expr_yy"
+#line 72 "ssl_expr_parse.y"
+#include "mod_ssl.h"
+#line 75 "ssl_expr_parse.y"
+typedef union {
+ char *cpVal;
+ ssl_expr *exVal;
+} YYSTYPE;
+#line 24 "y.tab.c"
+#define YYERRCODE 256
+#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
+const short ssl_expr_yylhs[] = { -1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 5, 5, 6,
+ 6, 6, 6, 4, 4, 3,
+};
+const short ssl_expr_yylen[] = { 2,
+ 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,
+};
+const short ssl_expr_yydefred[] = { 0,
+ 2, 3, 20, 21, 0, 0, 0, 0, 0, 0,
+ 7, 23, 0, 0, 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,
+ 0, 0, 6, 9, 10, 11, 12, 13, 14, 24,
+ 25, 16, 17, 0, 26, 22, 0, 18, 15, 0,
+ 19,
+};
+const short ssl_expr_yydgoto[] = { 9,
+ 10, 11, 12, 42, 47, 13,
+};
+const short ssl_expr_yysindex[] = { -37,
+ 0, 0, 0, 0, -35, -37, -37, -99, 0, -247,
+ 0, 0, -250, -229, 0, -39, -227, -37, -37, -33,
+ -33, -33, -33, -33, -33, -233, -233, -89, -6, 0,
+ -87, -239, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -33, 0, 0, -38, 0, 0, -33,
+ 0,
+};
+const short ssl_expr_yyrindex[] = { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 39,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+const short ssl_expr_yygindex[] = { 0,
+ 7, 0, 0, 13, 0, -13,
+};
+#define YYTABLESIZE 275
+const short ssl_expr_yytable[] = { 8,
+ 5, 30, 7, 8, 14, 50, 34, 35, 36, 37,
+ 38, 39, 15, 16, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 17, 32, 33, 18, 19, 40, 41,
+ 48, 29, 31, 44, 45, 19, 51, 46, 1, 43,
+ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 49, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 2, 3, 0, 4, 0, 3, 5, 4, 0, 0,
+ 5, 0, 0, 0, 18, 19, 0, 0, 6, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5,
+};
+const short ssl_expr_yycheck[] = { 37,
+ 0, 41, 40, 37, 40, 44, 20, 21, 22, 23,
+ 24, 25, 6, 7, 265, 266, 267, 268, 269, 270,
+ 271, 272, 273, 123, 18, 19, 274, 275, 262, 263,
+ 44, 261, 260, 123, 41, 275, 50, 125, 0, 27,
+ -1, 41, -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, 125, -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, -1, -1, -1, 257,
+ 258, 259, -1, 261, -1, 259, 264, 261, -1, -1,
+ 264, -1, -1, -1, 274, 275, -1, -1, 276, -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, 274,
+};
+#define YYFINAL 9
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 276
+#if YYDEBUG
+const char * const ssl_expr_yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,"'%'",0,0,"'('","')'",0,0,"','",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"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",
+};
+const char * const ssl_expr_yyrule[] = {
+"$accept : root",
+"root : expr",
+"expr : T_TRUE",
+"expr : T_FALSE",
+"expr : T_OP_NOT expr",
+"expr : expr T_OP_OR expr",
+"expr : expr T_OP_AND expr",
+"expr : comparison",
+"expr : '(' expr ')'",
+"comparison : word T_OP_EQ word",
+"comparison : word T_OP_NE word",
+"comparison : word T_OP_LT word",
+"comparison : word T_OP_LE word",
+"comparison : word T_OP_GT word",
+"comparison : word T_OP_GE word",
+"comparison : word T_OP_IN '{' words '}'",
+"comparison : word T_OP_REG regex",
+"comparison : word T_OP_NRE regex",
+"words : word",
+"words : words ',' word",
+"word : T_DIGIT",
+"word : T_STRING",
+"word : '%' '{' T_ID '}'",
+"word : funccall",
+"regex : T_REGEX",
+"regex : T_REGEX_I",
+"funccall : T_FUNC_FILE '(' T_STRING ')'",
+};
+#endif
+#if YYDEBUG
+#include <stdio.h>
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 10000
+#define YYMAXDEPTH 10000
+#endif
+#endif
+#define YYINITSTACKSIZE 200
+int ssl_expr_yydebug;
+int ssl_expr_yynerrs;
+int ssl_expr_yyerrflag;
+int ssl_expr_yychar;
+short *ssl_expr_yyssp;
+YYSTYPE *ssl_expr_yyvsp;
+YYSTYPE ssl_expr_yyval;
+YYSTYPE ssl_expr_yylval;
+short *ssl_expr_yyss;
+short *ssl_expr_yysslim;
+YYSTYPE *ssl_expr_yyvs;
+int ssl_expr_yystacksize;
+#line 180 "ssl_expr_parse.y"
+
+int ssl_expr_yyerror(char *s)
+{
+ ssl_expr_error = s;
+ return 2;
+}
+
+#line 230 "y.tab.c"
+/* allocate initial stack or double stack size, up to YYMAXDEPTH */
+static int ssl_expr_yygrowstack()
+{
+ int newsize, i;
+ short *newss;
+ YYSTYPE *newvs;
+
+ if ((newsize = ssl_expr_yystacksize) == 0)
+ newsize = YYINITSTACKSIZE;
+ else if (newsize >= YYMAXDEPTH)
+ return -1;
+ else if ((newsize *= 2) > YYMAXDEPTH)
+ newsize = YYMAXDEPTH;
+ i = ssl_expr_yyssp - ssl_expr_yyss;
+ newss = ssl_expr_yyss ? (short *)realloc(ssl_expr_yyss, newsize * sizeof *newss) :
+ (short *)malloc(newsize * sizeof *newss);
+ if (newss == NULL)
+ return -1;
+ ssl_expr_yyss = newss;
+ ssl_expr_yyssp = newss + i;
+ newvs = ssl_expr_yyvs ? (YYSTYPE *)realloc(ssl_expr_yyvs, newsize * sizeof *newvs) :
+ (YYSTYPE *)malloc(newsize * sizeof *newvs);
+ if (newvs == NULL)
+ return -1;
+ ssl_expr_yyvs = newvs;
+ ssl_expr_yyvsp = newvs + i;
+ ssl_expr_yystacksize = newsize;
+ ssl_expr_yysslim = ssl_expr_yyss + newsize - 1;
+ return 0;
+}
+
+#define YYABORT goto ssl_expr_yyabort
+#define YYREJECT goto ssl_expr_yyabort
+#define YYACCEPT goto ssl_expr_yyaccept
+#define YYERROR goto ssl_expr_yyerrlab
+
+#ifndef YYPARSE_PARAM
+#if defined(__cplusplus) || __STDC__
+#define YYPARSE_PARAM_ARG void
+#define YYPARSE_PARAM_DECL
+#else /* ! ANSI-C/C++ */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* ANSI-C/C++ */
+#else /* YYPARSE_PARAM */
+#ifndef YYPARSE_PARAM_TYPE
+#define YYPARSE_PARAM_TYPE void *
+#endif
+#if defined(__cplusplus) || __STDC__
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM_TYPE YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* ! ANSI-C/C++ */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL YYPARSE_PARAM_TYPE YYPARSE_PARAM;
+#endif /* ANSI-C/C++ */
+#endif /* ! YYPARSE_PARAM */
+
+int
+ssl_expr_yyparse (YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ register int ssl_expr_yym, ssl_expr_yyn, ssl_expr_yystate;
+#if YYDEBUG
+ register const char *ssl_expr_yys;
+
+ if ((ssl_expr_yys = getenv("YYDEBUG")))
+ {
+ ssl_expr_yyn = *ssl_expr_yys;
+ if (ssl_expr_yyn >= '0' && ssl_expr_yyn <= '9')
+ ssl_expr_yydebug = ssl_expr_yyn - '0';
+ }
+#endif
+
+ ssl_expr_yynerrs = 0;
+ ssl_expr_yyerrflag = 0;
+ ssl_expr_yychar = (-1);
+
+ if (ssl_expr_yyss == NULL && ssl_expr_yygrowstack()) goto ssl_expr_yyoverflow;
+ ssl_expr_yyssp = ssl_expr_yyss;
+ ssl_expr_yyvsp = ssl_expr_yyvs;
+ *ssl_expr_yyssp = ssl_expr_yystate = 0;
+
+ssl_expr_yyloop:
+ if ((ssl_expr_yyn = ssl_expr_yydefred[ssl_expr_yystate])) goto ssl_expr_yyreduce;
+ if (ssl_expr_yychar < 0)
+ {
+ if ((ssl_expr_yychar = ssl_expr_yylex()) < 0) ssl_expr_yychar = 0;
+#if YYDEBUG
+ if (ssl_expr_yydebug)
+ {
+ ssl_expr_yys = 0;
+ if (ssl_expr_yychar <= YYMAXTOKEN) ssl_expr_yys = ssl_expr_yyname[ssl_expr_yychar];
+ if (!ssl_expr_yys) ssl_expr_yys = "illegal-symbol";
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, ssl_expr_yystate, ssl_expr_yychar, ssl_expr_yys);
+ }
+#endif
+ }
+ if ((ssl_expr_yyn = ssl_expr_yysindex[ssl_expr_yystate]) && (ssl_expr_yyn += ssl_expr_yychar) >= 0 &&
+ ssl_expr_yyn <= YYTABLESIZE && ssl_expr_yycheck[ssl_expr_yyn] == ssl_expr_yychar)
+ {
+#if YYDEBUG
+ if (ssl_expr_yydebug)
+ printf("%sdebug: state %d, shifting to state %d\n",
+ YYPREFIX, ssl_expr_yystate, ssl_expr_yytable[ssl_expr_yyn]);
+#endif
+ if (ssl_expr_yyssp >= ssl_expr_yysslim && ssl_expr_yygrowstack())
+ {
+ goto ssl_expr_yyoverflow;
+ }
+ *++ssl_expr_yyssp = ssl_expr_yystate = ssl_expr_yytable[ssl_expr_yyn];
+ *++ssl_expr_yyvsp = ssl_expr_yylval;
+ ssl_expr_yychar = (-1);
+ if (ssl_expr_yyerrflag > 0) --ssl_expr_yyerrflag;
+ goto ssl_expr_yyloop;
+ }
+ if ((ssl_expr_yyn = ssl_expr_yyrindex[ssl_expr_yystate]) && (ssl_expr_yyn += ssl_expr_yychar) >= 0 &&
+ ssl_expr_yyn <= YYTABLESIZE && ssl_expr_yycheck[ssl_expr_yyn] == ssl_expr_yychar)
+ {
+ ssl_expr_yyn = ssl_expr_yytable[ssl_expr_yyn];
+ goto ssl_expr_yyreduce;
+ }
+ if (ssl_expr_yyerrflag) goto ssl_expr_yyinrecovery;
+#if defined(lint) || defined(__GNUC__)
+ goto ssl_expr_yynewerror;
+#endif
+ssl_expr_yynewerror:
+ ssl_expr_yyerror("syntax error");
+#if defined(lint) || defined(__GNUC__)
+ goto ssl_expr_yyerrlab;
+#endif
+ssl_expr_yyerrlab:
+ ++ssl_expr_yynerrs;
+ssl_expr_yyinrecovery:
+ if (ssl_expr_yyerrflag < 3)
+ {
+ ssl_expr_yyerrflag = 3;
+ for (;;)
+ {
+ if ((ssl_expr_yyn = ssl_expr_yysindex[*ssl_expr_yyssp]) && (ssl_expr_yyn += YYERRCODE) >= 0 &&
+ ssl_expr_yyn <= YYTABLESIZE && ssl_expr_yycheck[ssl_expr_yyn] == YYERRCODE)
+ {
+#if YYDEBUG
+ if (ssl_expr_yydebug)
+ printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *ssl_expr_yyssp, ssl_expr_yytable[ssl_expr_yyn]);
+#endif
+ if (ssl_expr_yyssp >= ssl_expr_yysslim && ssl_expr_yygrowstack())
+ {
+ goto ssl_expr_yyoverflow;
+ }
+ *++ssl_expr_yyssp = ssl_expr_yystate = ssl_expr_yytable[ssl_expr_yyn];
+ *++ssl_expr_yyvsp = ssl_expr_yylval;
+ goto ssl_expr_yyloop;
+ }
+ else
+ {
+#if YYDEBUG
+ if (ssl_expr_yydebug)
+ printf("%sdebug: error recovery discarding state %d\n",
+ YYPREFIX, *ssl_expr_yyssp);
+#endif
+ if (ssl_expr_yyssp <= ssl_expr_yyss) goto ssl_expr_yyabort;
+ --ssl_expr_yyssp;
+ --ssl_expr_yyvsp;
+ }
+ }
+ }
+ else
+ {
+ if (ssl_expr_yychar == 0) goto ssl_expr_yyabort;
+#if YYDEBUG
+ if (ssl_expr_yydebug)
+ {
+ ssl_expr_yys = 0;
+ if (ssl_expr_yychar <= YYMAXTOKEN) ssl_expr_yys = ssl_expr_yyname[ssl_expr_yychar];
+ if (!ssl_expr_yys) ssl_expr_yys = "illegal-symbol";
+ printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+ YYPREFIX, ssl_expr_yystate, ssl_expr_yychar, ssl_expr_yys);
+ }
+#endif
+ ssl_expr_yychar = (-1);
+ goto ssl_expr_yyloop;
+ }
+ssl_expr_yyreduce:
+#if YYDEBUG
+ if (ssl_expr_yydebug)
+ printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+ YYPREFIX, ssl_expr_yystate, ssl_expr_yyn, ssl_expr_yyrule[ssl_expr_yyn]);
+#endif
+ ssl_expr_yym = ssl_expr_yylen[ssl_expr_yyn];
+ ssl_expr_yyval = ssl_expr_yyvsp[1-ssl_expr_yym];
+ switch (ssl_expr_yyn)
+ {
+case 1:
+#line 118 "ssl_expr_parse.y"
+{ ssl_expr_info.expr = ssl_expr_yyvsp[0].exVal; }
+break;
+case 2:
+#line 121 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_make(op_True, NULL, NULL); }
+break;
+case 3:
+#line 122 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_make(op_False, NULL, NULL); }
+break;
+case 4:
+#line 123 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_make(op_Not, ssl_expr_yyvsp[0].exVal, NULL); }
+break;
+case 5:
+#line 124 "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 125 "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 126 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_make(op_Comp, ssl_expr_yyvsp[0].exVal, NULL); }
+break;
+case 8:
+#line 127 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_yyvsp[-1].exVal; }
+break;
+case 9:
+#line 130 "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 131 "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 132 "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 133 "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 134 "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 135 "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 136 "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 137 "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 138 "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 141 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_make(op_ListElement, ssl_expr_yyvsp[0].exVal, NULL); }
+break;
+case 19:
+#line 142 "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 145 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_make(op_Digit, ssl_expr_yyvsp[0].cpVal, NULL); }
+break;
+case 21:
+#line 146 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_make(op_String, ssl_expr_yyvsp[0].cpVal, NULL); }
+break;
+case 22:
+#line 147 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_make(op_Var, ssl_expr_yyvsp[-1].cpVal, NULL); }
+break;
+case 23:
+#line 148 "ssl_expr_parse.y"
+{ ssl_expr_yyval.exVal = ssl_expr_yyvsp[0].exVal; }
+break;
+case 24:
+#line 151 "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 161 "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 173 "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;
+#line 550 "y.tab.c"
+ }
+ ssl_expr_yyssp -= ssl_expr_yym;
+ ssl_expr_yystate = *ssl_expr_yyssp;
+ ssl_expr_yyvsp -= ssl_expr_yym;
+ ssl_expr_yym = ssl_expr_yylhs[ssl_expr_yyn];
+ if (ssl_expr_yystate == 0 && ssl_expr_yym == 0)
+ {
+#if YYDEBUG
+ if (ssl_expr_yydebug)
+ printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+ ssl_expr_yystate = YYFINAL;
+ *++ssl_expr_yyssp = YYFINAL;
+ *++ssl_expr_yyvsp = ssl_expr_yyval;
+ if (ssl_expr_yychar < 0)
+ {
+ if ((ssl_expr_yychar = ssl_expr_yylex()) < 0) ssl_expr_yychar = 0;
+#if YYDEBUG
+ if (ssl_expr_yydebug)
+ {
+ ssl_expr_yys = 0;
+ if (ssl_expr_yychar <= YYMAXTOKEN) ssl_expr_yys = ssl_expr_yyname[ssl_expr_yychar];
+ if (!ssl_expr_yys) ssl_expr_yys = "illegal-symbol";
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, YYFINAL, ssl_expr_yychar, ssl_expr_yys);
+ }
+#endif
+ }
+ if (ssl_expr_yychar == 0) goto ssl_expr_yyaccept;
+ goto ssl_expr_yyloop;
+ }
+ if ((ssl_expr_yyn = ssl_expr_yygindex[ssl_expr_yym]) && (ssl_expr_yyn += ssl_expr_yystate) >= 0 &&
+ ssl_expr_yyn <= YYTABLESIZE && ssl_expr_yycheck[ssl_expr_yyn] == ssl_expr_yystate)
+ ssl_expr_yystate = ssl_expr_yytable[ssl_expr_yyn];
+ else
+ ssl_expr_yystate = ssl_expr_yydgoto[ssl_expr_yym];
+#if YYDEBUG
+ if (ssl_expr_yydebug)
+ printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *ssl_expr_yyssp, ssl_expr_yystate);
+#endif
+ if (ssl_expr_yyssp >= ssl_expr_yysslim && ssl_expr_yygrowstack())
+ {
+ goto ssl_expr_yyoverflow;
+ }
+ *++ssl_expr_yyssp = ssl_expr_yystate;
+ *++ssl_expr_yyvsp = ssl_expr_yyval;
+ goto ssl_expr_yyloop;
+ssl_expr_yyoverflow:
+ ssl_expr_yyerror("yacc stack overflow");
+ssl_expr_yyabort:
+ return (1);
+ssl_expr_yyaccept:
+ return (0);
+}
diff --git a/modules/ssl/ssl_expr_parse.h b/modules/ssl/ssl_expr_parse.h
new file mode 100644
index 0000000000..618cacbe3b
--- /dev/null
+++ b/modules/ssl/ssl_expr_parse.h
@@ -0,0 +1,29 @@
+#ifndef YYERRCODE
+#define YYERRCODE 256
+#endif
+
+#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
+typedef union {
+ char *cpVal;
+ ssl_expr *exVal;
+} YYSTYPE;
+extern YYSTYPE ssl_expr_yylval;
diff --git a/modules/ssl/ssl_expr_parse.y b/modules/ssl/ssl_expr_parse.y
new file mode 100644
index 0000000000..1e3ad6e513
--- /dev/null
+++ b/modules/ssl/ssl_expr_parse.y
@@ -0,0 +1,186 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| |
+** | '_ ` _ \ / _ \ / _` | / __/ __| |
+** | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL
+** |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/
+** |_____|
+** ssl_expr_parse.y
+** Expression LR(1) Parser
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+ /* ``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;
+ regex = NULL;
+ }
+ $$ = 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;
+ regex = NULL;
+ }
+ $$ = 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/modules/ssl/ssl_expr_scan.c b/modules/ssl/ssl_expr_scan.c
new file mode 100644
index 0000000000..f3e9f9d1f5
--- /dev/null
+++ b/modules/ssl/ssl_expr_scan.c
@@ -0,0 +1,2002 @@
+#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:
+ */
+
+#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
+/* _ _
+** _ __ ___ ___ __| | ___ ___| |
+** | '_ ` _ \ / _ \ / _` | / __/ __| |
+** | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL
+** |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/
+** |_____|
+** ssl_expr_scan.l
+** Expression Scanner
+*/
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+/* ``Killing for peace is
+like fucking for virginity.''
+-- Unknown */
+/* _________________________________________________________________
+**
+** Expression Scanner
+** _________________________________________________________________
+*/
+#line 73 "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 537 "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 94 "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 700 "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 105 "ssl_expr_scan.l"
+{
+ /* NOP */
+}
+ YY_BREAK
+/*
+ * C-style strings ("...")
+ */
+case 2:
+YY_RULE_SETUP
+#line 112 "ssl_expr_scan.l"
+{
+ cpStr = caStr;
+ BEGIN(str);
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 116 "ssl_expr_scan.l"
+{
+ BEGIN(INITIAL);
+ *cpStr = NUL;
+ yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caStr);
+ return T_STRING;
+}
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 122 "ssl_expr_scan.l"
+{
+ yyerror("Unterminated string");
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 125 "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 134 "ssl_expr_scan.l"
+{
+ yyerror("Bad escape sequence");
+}
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 137 "ssl_expr_scan.l"
+{ *cpStr++ = '\n'; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 138 "ssl_expr_scan.l"
+{ *cpStr++ = '\r'; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 139 "ssl_expr_scan.l"
+{ *cpStr++ = '\t'; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 140 "ssl_expr_scan.l"
+{ *cpStr++ = '\b'; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 141 "ssl_expr_scan.l"
+{ *cpStr++ = '\f'; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 142 "ssl_expr_scan.l"
+{
+ *cpStr++ = yytext[1];
+}
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 145 "ssl_expr_scan.l"
+{
+ char *cp = yytext;
+ while (*cp != NUL)
+ *cpStr++ = *cp++;
+}
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 150 "ssl_expr_scan.l"
+{
+ *cpStr++ = yytext[1];
+}
+ YY_BREAK
+/*
+ * Regular Expression
+ */
+case 15:
+YY_RULE_SETUP
+#line 157 "ssl_expr_scan.l"
+{
+ cRegexDel = yytext[1];
+ cpRegex = caRegex;
+ BEGIN(regex);
+}
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 162 "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 171 "ssl_expr_scan.l"
+{
+ yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex);
+ BEGIN(INITIAL);
+ return T_REGEX_I;
+}
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 176 "ssl_expr_scan.l"
+{
+ yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex);
+ yyless(0);
+ BEGIN(INITIAL);
+ return T_REGEX;
+}
+ YY_BREAK
+case YY_STATE_EOF(regex_flags):
+#line 182 "ssl_expr_scan.l"
+{
+ yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex);
+ BEGIN(INITIAL);
+ return T_REGEX;
+}
+ YY_BREAK
+/*
+ * Operators
+ */
+case 19:
+YY_RULE_SETUP
+#line 191 "ssl_expr_scan.l"
+{ return T_OP_EQ; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 192 "ssl_expr_scan.l"
+{ return T_OP_EQ; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 193 "ssl_expr_scan.l"
+{ return T_OP_NE; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 194 "ssl_expr_scan.l"
+{ return T_OP_NE; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 195 "ssl_expr_scan.l"
+{ return T_OP_LT; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 196 "ssl_expr_scan.l"
+{ return T_OP_LT; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 197 "ssl_expr_scan.l"
+{ return T_OP_LE; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 198 "ssl_expr_scan.l"
+{ return T_OP_LE; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 199 "ssl_expr_scan.l"
+{ return T_OP_GT; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 200 "ssl_expr_scan.l"
+{ return T_OP_GT; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 201 "ssl_expr_scan.l"
+{ return T_OP_GE; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 202 "ssl_expr_scan.l"
+{ return T_OP_GE; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 203 "ssl_expr_scan.l"
+{ return T_OP_REG; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 204 "ssl_expr_scan.l"
+{ return T_OP_NRE; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 205 "ssl_expr_scan.l"
+{ return T_OP_AND; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 206 "ssl_expr_scan.l"
+{ return T_OP_AND; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 207 "ssl_expr_scan.l"
+{ return T_OP_OR; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 208 "ssl_expr_scan.l"
+{ return T_OP_OR; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 209 "ssl_expr_scan.l"
+{ return T_OP_NOT; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 210 "ssl_expr_scan.l"
+{ return T_OP_NOT; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 211 "ssl_expr_scan.l"
+{ return T_OP_IN; }
+ YY_BREAK
+/*
+ * Functions
+ */
+case 40:
+YY_RULE_SETUP
+#line 216 "ssl_expr_scan.l"
+{ return T_FUNC_FILE; }
+ YY_BREAK
+/*
+ * Specials
+ */
+case 41:
+YY_RULE_SETUP
+#line 221 "ssl_expr_scan.l"
+{ return T_TRUE; }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 222 "ssl_expr_scan.l"
+{ return T_FALSE; }
+ YY_BREAK
+/*
+ * Digits
+ */
+case 43:
+YY_RULE_SETUP
+#line 227 "ssl_expr_scan.l"
+{
+ yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, yytext);
+ return T_DIGIT;
+}
+ YY_BREAK
+/*
+ * Identifiers
+ */
+case 44:
+YY_RULE_SETUP
+#line 235 "ssl_expr_scan.l"
+{
+ yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, yytext);
+ return T_ID;
+}
+ YY_BREAK
+/*
+ * Anything else is returned as is...
+ */
+case 45:
+YY_RULE_SETUP
+#line 243 "ssl_expr_scan.l"
+{
+ return yytext[0];
+}
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 247 "ssl_expr_scan.l"
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+#line 1100 "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 247 "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/modules/ssl/ssl_expr_scan.l b/modules/ssl/ssl_expr_scan.l
new file mode 100644
index 0000000000..a0db7cccde
--- /dev/null
+++ b/modules/ssl/ssl_expr_scan.l
@@ -0,0 +1,261 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| |
+** | '_ ` _ \ / _ \ / _` | / __/ __| |
+** | | | | | | (_) | (_| | \__ \__ \ | mod_ssl - Apache Interface to OpenSSL
+** |_| |_| |_|\___/ \__,_|___|___/___/_| http://www.modssl.org/
+** |_____|
+** ssl_expr_scan.l
+** Expression Scanner
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+ /* ``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 = ap_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 = ap_pstrdup(ssl_expr_info.pool, caRegex);
+ BEGIN(INITIAL);
+ return T_REGEX_I;
+}
+<regex_flags>.|\n {
+ yylval.cpVal = ap_pstrdup(ssl_expr_info.pool, caRegex);
+ yyless(0);
+ BEGIN(INITIAL);
+ return T_REGEX;
+}
+<regex_flags><<EOF>> {
+ yylval.cpVal = ap_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 = ap_pstrdup(ssl_expr_info.pool, yytext);
+ return T_DIGIT;
+}
+
+ /*
+ * Identifiers
+ */
+[a-zA-Z][a-zA-Z0-9_:-]* {
+ yylval.cpVal = ap_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/modules/ssl/ssl_scache.c b/modules/ssl/ssl_scache.c
new file mode 100644
index 0000000000..139c7865fe
--- /dev/null
+++ b/modules/ssl/ssl_scache.c
@@ -0,0 +1,204 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_scache.c
+** Session Cache Abstraction
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+
+ if (mc->nSessionCacheMode == SSL_SCMODE_DBM)
+ ssl_scache_dbm_init(s, p);
+ else 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);
+#ifdef SSL_VENDOR
+ else
+ ap_hook_use("ap::mod_ssl::vendor::scache_init",
+ AP_HOOK_SIG3(void,ptr,ptr), AP_HOOK_ALL, s, p);
+#endif
+ return;
+}
+
+void ssl_scache_kill(server_rec *s)
+{
+ SSLModConfigRec *mc = myModConfig();
+
+ 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);
+#ifdef SSL_VENDOR
+ else
+ ap_hook_use("ap::mod_ssl::vendor::scache_kill",
+ AP_HOOK_SIG2(void,ptr), AP_HOOK_ALL, s);
+#endif
+ return;
+}
+
+BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess)
+{
+ SSLModConfigRec *mc = myModConfig();
+ 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);
+#ifdef SSL_VENDOR
+ else
+ ap_hook_use("ap::mod_ssl::vendor::scache_store",
+ AP_HOOK_SIG6(int,ptr,ptr,int,int,ptr), AP_HOOK_ALL,
+ (int *)&rv, s, id, idlen, (int)expiry, sess);
+#endif
+ return rv;
+}
+
+SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen)
+{
+ SSLModConfigRec *mc = myModConfig();
+ 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);
+#ifdef SSL_VENDOR
+ else
+ ap_hook_use("ap::mod_ssl::vendor::scache_retrieve",
+ AP_HOOK_SIG4(ptr,ptr,ptr,int), AP_HOOK_ALL,
+ &sess, s, id, idlen);
+#endif
+ return sess;
+}
+
+void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen)
+{
+ SSLModConfigRec *mc = myModConfig();
+
+ 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);
+#ifdef SSL_VENDOR
+ else
+ ap_hook_use("ap::mod_ssl::vendor::scache_remove",
+ AP_HOOK_SIG4(void,ptr,ptr,int), AP_HOOK_ALL, s, id, idlen);
+#endif
+ return;
+}
+
+void ssl_scache_status(server_rec *s, pool *p, void (*func)(char *, void *), void *arg)
+{
+ SSLModConfigRec *mc = myModConfig();
+
+ 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);
+#ifdef SSL_VENDOR
+ else
+ ap_hook_use("ap::mod_ssl::vendor::scache_status",
+ AP_HOOK_SIG5(void,ptr,ptr,ptr,ptr), AP_HOOK_ALL,
+ s, p, func, arg);
+#endif
+ return;
+}
+
+void ssl_scache_expire(server_rec *s)
+{
+ SSLModConfigRec *mc = myModConfig();
+
+ 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);
+#ifdef SSL_VENDOR
+ else
+ ap_hook_use("ap::mod_ssl::vendor::scache_expire",
+ AP_HOOK_SIG2(void,ptr), AP_HOOK_ALL, s);
+#endif
+ return;
+}
+
diff --git a/modules/ssl/ssl_scache_dbm.c b/modules/ssl/ssl_scache_dbm.c
new file mode 100644
index 0000000000..323c612991
--- /dev/null
+++ b/modules/ssl/ssl_scache_dbm.c
@@ -0,0 +1,440 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_scache_dbm.c
+** Session Cache via DBM
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include "mod_ssl.h"
+
+void ssl_scache_dbm_init(server_rec *s, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+ DBM *dbm;
+
+ /* for the DBM we need the data file */
+ if (mc->szSessionCacheDataFile == NULL) {
+ ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required");
+ ssl_die();
+ }
+
+ /* open it once to create it and to make sure it _can_ be created */
+ ssl_mutex_on(s);
+ if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile,
+ O_RDWR|O_CREAT, SSL_DBM_FILE_MODE)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot create SSLSessionCache DBM file `%s'",
+ mc->szSessionCacheDataFile);
+ ssl_mutex_off(s);
+ return;
+ }
+ ssl_dbm_close(dbm);
+
+#if !defined(OS2) && !defined(WIN32)
+ /*
+ * 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, ap_user_id, -1 /* no gid change */);
+ if (chown(ap_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_DIR, NULL),
+ ap_user_id, -1) == -1) {
+ if (chown(ap_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL),
+ ap_user_id, -1) == -1)
+ chown(ap_pstrcat(p, mc->szSessionCacheDataFile, ".dir", NULL),
+ ap_user_id, -1);
+ }
+ if (chown(ap_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_PAG, NULL),
+ ap_user_id, -1) == -1) {
+ if (chown(ap_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL),
+ ap_user_id, -1) == -1)
+ chown(ap_pstrcat(p, mc->szSessionCacheDataFile, ".pag", NULL),
+ ap_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();
+ pool *p;
+
+ if ((p = ap_make_sub_pool(NULL)) != NULL) {
+ /* the correct way */
+ unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_DIR, NULL));
+ unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, SSL_DBM_FILE_SUFFIX_PAG, NULL));
+ /* the additional ways to be sure */
+ unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, ".dir", NULL));
+ unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, ".pag", NULL));
+ unlink(ap_pstrcat(p, mc->szSessionCacheDataFile, ".db", NULL));
+ unlink(mc->szSessionCacheDataFile);
+ ap_destroy_pool(p);
+ }
+ return;
+}
+
+BOOL ssl_scache_dbm_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess)
+{
+ SSLModConfigRec *mc = myModConfig();
+ DBM *dbm;
+ datum dbmkey;
+ datum dbmval;
+ UCHAR ucaData[SSL_SESSION_MAX_DER];
+ int nData;
+ UCHAR *ucp;
+
+ /* streamline session data */
+ ucp = ucaData;
+ nData = i2d_SSL_SESSION(sess, &ucp);
+
+ /* be careful: do not try to store too much bytes in a DBM file! */
+#ifdef SSL_USE_SDBM
+ if ((idlen + nData) >= PAIRMAX)
+ return FALSE;
+#else
+ if ((idlen + nData) >= 950 /* at least less than approx. 1KB */)
+ 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)
+ 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 ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile,
+ O_RDWR, SSL_DBM_FILE_MODE)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot open SSLSessionCache DBM file `%s' for writing (store)",
+ mc->szSessionCacheDataFile);
+ ssl_mutex_off(s);
+ free(dbmval.dptr);
+ return FALSE;
+ }
+ if (ssl_dbm_store(dbm, dbmkey, dbmval, DBM_INSERT) < 0) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot store SSL session to DBM file `%s'",
+ mc->szSessionCacheDataFile);
+ ssl_dbm_close(dbm);
+ ssl_mutex_off(s);
+ free(dbmval.dptr);
+ return FALSE;
+ }
+ ssl_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();
+ DBM *dbm;
+ datum dbmkey;
+ datum dbmval;
+ SSL_SESSION *sess = NULL;
+ UCHAR *ucpData;
+ int nData;
+ time_t expiry;
+ time_t now;
+
+ /* 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 */
+ ssl_mutex_on(s);
+ if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile,
+ O_RDONLY, SSL_DBM_FILE_MODE)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot open SSLSessionCache DBM file `%s' for reading (fetch)",
+ mc->szSessionCacheDataFile);
+ ssl_mutex_off(s);
+ return NULL;
+ }
+ dbmval = ssl_dbm_fetch(dbm, dbmkey);
+ ssl_dbm_close(dbm);
+ ssl_mutex_off(s);
+
+ /* immediately return if not found */
+ if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(time_t))
+ return NULL;
+
+ /* parse resulting data */
+ nData = dbmval.dsize-sizeof(time_t);
+ ucpData = (UCHAR *)malloc(nData);
+ if (ucpData == NULL)
+ return NULL;
+ memcpy(ucpData, (char *)dbmval.dptr+sizeof(time_t), nData);
+ memcpy(&expiry, dbmval.dptr, sizeof(time_t));
+
+ /* 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();
+ DBM *dbm;
+ datum dbmkey;
+
+ /* create DBM key and values */
+ dbmkey.dptr = (char *)id;
+ dbmkey.dsize = idlen;
+
+ /* and delete it from the DBM file */
+ ssl_mutex_on(s);
+ if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile,
+ O_RDWR, SSL_DBM_FILE_MODE)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot open SSLSessionCache DBM file `%s' for writing (delete)",
+ mc->szSessionCacheDataFile);
+ ssl_mutex_off(s);
+ return;
+ }
+ ssl_dbm_delete(dbm, dbmkey);
+ ssl_dbm_close(dbm);
+ ssl_mutex_off(s);
+
+ return;
+}
+
+void ssl_scache_dbm_expire(server_rec *s)
+{
+ SSLModConfigRec *mc = myModConfig();
+ SSLSrvConfigRec *sc = mySrvConfig(s);
+ static time_t tLast = 0;
+ DBM *dbm;
+ datum dbmkey;
+ datum dbmval;
+ pool *p;
+ time_t tExpiresAt;
+ int nElements = 0;
+ int nDeleted = 0;
+ int bDelete;
+ datum *keylist;
+ int keyidx;
+ int i;
+ 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->nSessionCacheTimeout)
+ 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 */
+ if ((p = ap_make_sub_pool(NULL)) == NULL)
+ break;
+ if ((keylist = ap_palloc(p, sizeof(dbmkey)*KEYMAX)) == NULL) {
+ ap_destroy_pool(p);
+ break;
+ }
+
+ /* pass 1: scan DBM database */
+ keyidx = 0;
+ if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile,
+ O_RDWR, SSL_DBM_FILE_MODE)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot open SSLSessionCache DBM file `%s' for scanning",
+ mc->szSessionCacheDataFile);
+ ap_destroy_pool(p);
+ break;
+ }
+ dbmkey = ssl_dbm_firstkey(dbm);
+ while (dbmkey.dptr != NULL) {
+ nElements++;
+ bDelete = FALSE;
+ dbmval = ssl_dbm_fetch(dbm, dbmkey);
+ 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 = ap_palloc(p, dbmkey.dsize)) != NULL) {
+ memcpy(keylist[keyidx].dptr, dbmkey.dptr, dbmkey.dsize);
+ keylist[keyidx].dsize = dbmkey.dsize;
+ keyidx++;
+ if (keyidx == KEYMAX)
+ break;
+ }
+ }
+ dbmkey = ssl_dbm_nextkey(dbm);
+ }
+ ssl_dbm_close(dbm);
+
+ /* pass 2: delete expired elements */
+ if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile,
+ O_RDWR, SSL_DBM_FILE_MODE)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot re-open SSLSessionCache DBM file `%s' for expiring",
+ mc->szSessionCacheDataFile);
+ ap_destroy_pool(p);
+ break;
+ }
+ for (i = 0; i < keyidx; i++) {
+ ssl_dbm_delete(dbm, keylist[i]);
+ nDeleted++;
+ }
+ ssl_dbm_close(dbm);
+
+ /* destroy temporary pool */
+ ap_destroy_pool(p);
+
+ if (keyidx < KEYMAX)
+ break;
+ }
+ ssl_mutex_off(s);
+
+ ssl_log(s, SSL_LOG_TRACE, "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, pool *p, void (*func)(char *, void *), void *arg)
+{
+ SSLModConfigRec *mc = myModConfig();
+ DBM *dbm;
+ datum dbmkey;
+ datum dbmval;
+ int nElem;
+ int nSize;
+ int nAverage;
+
+ nElem = 0;
+ nSize = 0;
+ ssl_mutex_on(s);
+ if ((dbm = ssl_dbm_open(mc->szSessionCacheDataFile,
+ O_RDONLY, SSL_DBM_FILE_MODE)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Cannot open SSLSessionCache DBM file `%s' for status retrival",
+ mc->szSessionCacheDataFile);
+ ssl_mutex_off(s);
+ return;
+ }
+ dbmkey = ssl_dbm_firstkey(dbm);
+ for ( ; dbmkey.dptr != NULL; dbmkey = ssl_dbm_nextkey(dbm)) {
+ dbmval = ssl_dbm_fetch(dbm, dbmkey);
+ if (dbmval.dptr == NULL)
+ continue;
+ nElem += 1;
+ nSize += dbmval.dsize;
+ }
+ ssl_dbm_close(dbm);
+ ssl_mutex_off(s);
+ if (nSize > 0 && nElem > 0)
+ nAverage = nSize / nElem;
+ else
+ nAverage = 0;
+ func(ap_psprintf(p, "cache type: <b>DBM</b>, maximum size: <b>unlimited</b><br>"), arg);
+ func(ap_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg);
+ func(ap_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg);
+ return;
+}
+
diff --git a/modules/ssl/ssl_scache_shmcb.c b/modules/ssl/ssl_scache_shmcb.c
new file mode 100644
index 0000000000..e588f0a5d1
--- /dev/null
+++ b/modules/ssl/ssl_scache_shmcb.c
@@ -0,0 +1,1343 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_scache_shmcb.c
+** Session Cache via Shared Memory (Cyclic Buffer Variant)
+*/
+
+/* ====================================================================
+ * Copyright (c) 2000-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include "mod_ssl.h"
+
+/*
+ * This shared memory based SSL session cache implementation was
+ * originally written by Geoff Thorpe <geoff@eu.c2.net> for C2Net Europe
+ * and 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 {
+#if 0
+ unsigned char division_mask;
+ unsigned int division_offset;
+ unsigned int division_size;
+ unsigned int queue_size;
+ unsigned char index_num;
+ unsigned char index_offset;
+ unsigned char index_size;
+ unsigned int cache_data_offset;
+ unsigned int cache_data_size;
+ 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;
+#else
+ 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 char index_num;
+ unsigned char index_offset;
+ unsigned char index_size;
+#endif
+} 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(unsigned int *, unsigned int);
+#if 0 /* Unused so far */
+static unsigned long shmcb_get_safe_ulong(unsigned long *);
+static void shmcb_set_safe_ulong(unsigned long *, unsigned long);
+#endif
+static time_t shmcb_get_safe_time(time_t *);
+static void shmcb_set_safe_time(time_t *, time_t);
+
+/* 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 *, int);
+static BOOL shmcb_remove_session_id(server_rec *, SHMCBQueue *, SHMCBCache *, UCHAR *, 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 char *from;
+ unsigned int ret;
+
+ from = (unsigned char *)ptr;
+ memcpy(&ret, from, sizeof(unsigned int));
+ return ret;
+}
+
+static void shmcb_set_safe_uint(unsigned int *ptr, unsigned int val)
+{
+ unsigned char *to, *from;
+
+ to = (unsigned char *)ptr;
+ from = (unsigned char *)(&val);
+ memcpy(to, from, sizeof(unsigned int));
+}
+
+#if 0 /* Unused so far */
+static unsigned long shmcb_get_safe_ulong(unsigned long *ptr)
+{
+ unsigned char *from;
+ unsigned long ret;
+
+ from = (unsigned char *)ptr;
+ memcpy(&ret, from, sizeof(unsigned long));
+ return ret;
+}
+
+static void shmcb_set_safe_ulong(unsigned long *ptr, unsigned long val)
+{
+ unsigned char *to, *from;
+
+ to = (unsigned char *)ptr;
+ from = (unsigned char *)(&val);
+ memcpy(to, from, sizeof(unsigned long));
+}
+#endif
+
+static time_t shmcb_get_safe_time(time_t * ptr)
+{
+ unsigned char *from;
+ time_t ret;
+
+ from = (unsigned char *)ptr;
+ memcpy(&ret, from, sizeof(time_t));
+ return ret;
+}
+
+static void shmcb_set_safe_time(time_t * ptr, time_t val)
+{
+ unsigned char *to, *from;
+
+ to = (unsigned char *)ptr;
+ from = (unsigned char *)(&val);
+ memcpy(to, from, sizeof(time_t));
+}
+
+/*
+**
+** High-Level "handlers" as per ssl_scache.c
+**
+*/
+
+static void *shmcb_malloc(size_t size)
+{
+ SSLModConfigRec *mc = myModConfig();
+ return ap_mm_malloc(mc->pSessionCacheDataMM, size);
+}
+
+void ssl_scache_shmcb_init(server_rec *s, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+ AP_MM *mm;
+ void *shm_segment = NULL;
+ int avail, avail_orig;
+
+ /*
+ * Create shared memory segment
+ */
+ if (mc->szSessionCacheDataFile == NULL) {
+ ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required");
+ ssl_die();
+ }
+ if ((mm = ap_mm_create(mc->nSessionCacheDataSize,
+ mc->szSessionCacheDataFile)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Cannot allocate shared memory: %s", ap_mm_error());
+ ssl_die();
+ }
+ mc->pSessionCacheDataMM = mm;
+
+ /*
+ * Make sure the child processes have access to the underlying files
+ */
+ ap_mm_permission(mm, SSL_MM_FILE_MODE, ap_user_id, -1);
+
+ /*
+ * Create cache inside the shared memory segment
+ */
+ avail = avail_orig = ap_mm_available(mm);
+ ssl_log(s, SSL_LOG_TRACE, "Shared-memory segment has %u available",
+ avail);
+
+ /*
+ * For some reason to do with MM's internal management, I can't
+ * allocate the full amount. Implement a reasonable form of trial
+ * and error and output trace information.
+ */
+ while ((shm_segment == NULL) && ((avail_orig - avail) * 100 < avail_orig)) {
+ shm_segment = shmcb_malloc(avail);
+ if (shm_segment == NULL) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "shmcb_malloc attempt for %u bytes failed", avail);
+ avail -= 2;
+ }
+ }
+ if (shm_segment == NULL) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Cannot allocate memory for the 'shmcb' session cache\n");
+ ssl_die();
+ }
+ ssl_log(s, SSL_LOG_TRACE, "shmcb_init allocated %u bytes of shared "
+ "memory", avail);
+ if (!shmcb_init_memory(s, shm_segment, avail)) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Failure initialising 'shmcb' shared memory");
+ ssl_die();
+ }
+ ssl_log(s, SSL_LOG_INFO, "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();
+
+ if (mc->pSessionCacheDataMM != NULL) {
+ ap_mm_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();
+ 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. */
+ ssl_log(s, SSL_LOG_ERROR, "'shmcb' code was unable to store a "
+ "session in the cache.");
+ else {
+ ssl_log(s, SSL_LOG_TRACE, "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();
+ 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)
+ ssl_log(s, SSL_LOG_TRACE, "shmcb_retrieve had a hit");
+ else {
+ ssl_log(s, SSL_LOG_TRACE, "shmcb_retrieve had a miss");
+ ssl_log(s, SSL_LOG_INFO, "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();
+ void *shm_segment;
+
+ /* We've kludged our pointer into the other cache's member variable. */
+ shm_segment = (void *) mc->tSessionCacheDataTable;
+ shmcb_remove_session(s, shm_segment, id, idlen);
+}
+
+void ssl_scache_shmcb_expire(server_rec *s)
+{
+ /* NOP */
+ return;
+}
+
+void ssl_scache_shmcb_status(server_rec *s, pool *p,
+ void (*func) (char *, void *), void *arg)
+{
+ SSLModConfigRec *mc = myModConfig();
+ 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;
+
+ ssl_log(s, SSL_LOG_TRACE, "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(ap_psprintf(p, "cache type: <b>SHMCB</b>, shared memory: <b>%d</b> "
+ "bytes, current sessions: <b>%d</b><br>",
+ mc->nSessionCacheDataSize, total), arg);
+ func(ap_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(ap_psprintf(p, "time left on oldest entries' SSL sessions: "), arg);
+ if (now < average_expiry)
+ func(ap_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(ap_psprintf(p, "expiry threshold: <b>Calculation Error!</b>"
+ "<br>"), arg);
+
+ }
+ func(ap_psprintf(p, "index usage: <b>%d%%</b>, cache usage: <b>%d%%</b>"
+ "<br>", index_pct, cache_pct), arg);
+ func(ap_psprintf(p, "total sessions stored since starting: <b>%lu</b><br>",
+ header->num_stores), arg);
+ func(ap_psprintf(p, "total sessions expired since starting: <b>%lu</b><br>",
+ header->num_expiries), arg);
+ func(ap_psprintf(p, "total (pre-expiry) sessions scrolled out of the "
+ "cache: <b>%lu</b><br>", header->num_scrolled), arg);
+ func(ap_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(ap_psprintf(p, "total removes since starting: <b>%lu</b> hit, "
+ "<b>%lu</b> miss<br>", header->num_removes_hit,
+ header->num_removes_miss), arg);
+ ssl_log(s, SSL_LOG_TRACE, "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;
+
+ ssl_log(s, SSL_LOG_TRACE, "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)) {
+ ssl_log(s, SSL_LOG_ERROR, "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;
+ ssl_log(s, SSL_LOG_TRACE, "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) {
+ ssl_log(s, SSL_LOG_ERROR, "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 */
+ ssl_log(s, SSL_LOG_TRACE, "shmcb_init_memory choices follow");
+ ssl_log(s, SSL_LOG_TRACE, "division_mask = 0x%02X", header->division_mask);
+ ssl_log(s, SSL_LOG_TRACE, "division_offset = %u", header->division_offset);
+ ssl_log(s, SSL_LOG_TRACE, "division_size = %u", header->division_size);
+ ssl_log(s, SSL_LOG_TRACE, "queue_size = %u", header->queue_size);
+ ssl_log(s, SSL_LOG_TRACE, "index_num = %u", header->index_num);
+ ssl_log(s, SSL_LOG_TRACE, "index_offset = %u", header->index_offset);
+ ssl_log(s, SSL_LOG_TRACE, "index_size = %u", header->index_size);
+ ssl_log(s, SSL_LOG_TRACE, "cache_data_offset = %u", header->cache_data_offset);
+ ssl_log(s, SSL_LOG_TRACE, "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))
+ ssl_log(s, SSL_LOG_ERROR, "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);
+ }
+
+ ssl_log(s, SSL_LOG_TRACE, "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;
+
+ ssl_log(s, SSL_LOG_TRACE, "inside shmcb_store_session");
+
+ /* Get the header structure, which division this session will fall into etc. */
+ shmcb_get_header(shm_segment, &header);
+ masked_index = pSession->session_id[0] & header->division_mask;
+ ssl_log(s, SSL_LOG_TRACE, "session_id[0]=%u, masked index=%u",
+ pSession->session_id[0], masked_index);
+ if (!shmcb_get_division(header, &queue, &cache, (unsigned int)masked_index)) {
+ ssl_log(s, SSL_LOG_ERROR, "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) {
+ ssl_log(s, SSL_LOG_ERROR, "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, pSession->session_id,
+ expiry_time)) {
+ ssl_log(s, SSL_LOG_ERROR, "can't store a session!");
+ return FALSE;
+ }
+ ssl_log(s, SSL_LOG_TRACE, "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;
+
+ ssl_log(s, SSL_LOG_TRACE, "inside shmcb_retrieve_session");
+ if (idlen < 2) {
+ ssl_log(s, SSL_LOG_ERROR, "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;
+ ssl_log(s, SSL_LOG_TRACE, "id[0]=%u, masked index=%u", id[0],
+ masked_index);
+ if (!shmcb_get_division(header, &queue, &cache, (unsigned int) masked_index)) {
+ ssl_log(s, SSL_LOG_ERROR, "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++;
+ ssl_log(s, SSL_LOG_TRACE, "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;
+
+ ssl_log(s, SSL_LOG_TRACE, "inside shmcb_remove_session");
+ if (id == NULL) {
+ ssl_log(s, SSL_LOG_ERROR, "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;
+ ssl_log(s, SSL_LOG_TRACE, "id[0]=%u, masked index=%u",
+ id[0], masked_index);
+ if (!shmcb_get_division(header, &queue, &cache, (unsigned int)masked_index)) {
+ ssl_log(s, SSL_LOG_ERROR, "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++;
+ ssl_log(s, SSL_LOG_TRACE, "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)
+{
+ /* 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)
+{
+ /* 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 > (unsigned int) 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;
+
+ ssl_log(s, SSL_LOG_TRACE, "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) {
+ ssl_log(s, SSL_LOG_TRACE, "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)));
+ }
+ ssl_log(s, SSL_LOG_TRACE, "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;
+
+ ssl_log(s, SSL_LOG_TRACE, "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) {
+ ssl_log(s, SSL_LOG_TRACE, "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);
+ ssl_log(s, SSL_LOG_TRACE, "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) {
+ ssl_log(s, SSL_LOG_ERROR, "shmcb_insert_encoded_session, "
+ "internal error");
+ return FALSE;
+ }
+ if (shmcb_get_safe_uint(queue->pos_count) == header->index_num) {
+ ssl_log(s, SSL_LOG_ERROR, "shmcb_insert_encoded_session, "
+ "internal error");
+ return FALSE;
+ }
+ ssl_log(s, SSL_LOG_TRACE, "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));
+ ssl_log(s, SSL_LOG_TRACE, "storing in index %u, at offset %u", new_pos,
+ new_offset);
+ idx = shmcb_get_index(queue, new_pos);
+ if (idx == NULL) {
+ ssl_log(s, SSL_LOG_ERROR, "shmcb_insert_encoded_session, "
+ "internal error");
+ return FALSE;
+ }
+ memset(idx, 0, 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];
+ ssl_log(s, SSL_LOG_TRACE, "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 ... */
+ ssl_log(s, SSL_LOG_TRACE, "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));
+ ssl_log(s, SSL_LOG_TRACE, "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,
+ int idlen)
+{
+ unsigned char tempasn[SSL_SESSION_MAX_DER];
+ SHMCBIndex *idx;
+ SHMCBHeader *header;
+ SSL_SESSION *pSession = NULL;
+ unsigned int curr_pos, loop, count;
+ unsigned char *ptr;
+ time_t now;
+
+ ssl_log(s, SSL_LOG_TRACE, "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++) {
+ ssl_log(s, SSL_LOG_TRACE, "loop=%u, count=%u, curr_pos=%u",
+ loop, count, curr_pos);
+ idx = shmcb_get_index(queue, curr_pos);
+ ssl_log(s, SSL_LOG_TRACE, "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)) {
+ ssl_log(s, SSL_LOG_TRACE, "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) {
+ ssl_log(s, SSL_LOG_ERROR, "scach2_lookup_"
+ "session_id, internal error");
+ return NULL;
+ }
+ if ((pSession->session_id_length == idlen) &&
+ (memcmp(pSession->session_id, id, idlen) == 0)) {
+ ssl_log(s, SSL_LOG_TRACE, "a match!");
+ return pSession;
+ }
+ ssl_log(s, SSL_LOG_TRACE, "not a match");
+ SSL_SESSION_free(pSession);
+ pSession = NULL;
+ }
+ curr_pos = shmcb_cyclic_increment(header->index_num, curr_pos, 1);
+ }
+ ssl_log(s, SSL_LOG_TRACE, "no matching sessions were found");
+ return NULL;
+}
+
+static BOOL shmcb_remove_session_id(
+ server_rec *s, SHMCBQueue *queue,
+ SHMCBCache *cache, UCHAR *id, int idlen)
+{
+ unsigned char tempasn[SSL_SESSION_MAX_DER];
+ SSL_SESSION *pSession = NULL;
+ SHMCBIndex *idx;
+ SHMCBHeader *header;
+ unsigned int curr_pos, loop, count;
+ unsigned char *ptr;
+ BOOL to_return = FALSE;
+
+ ssl_log(s, SSL_LOG_TRACE, "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++) {
+ ssl_log(s, SSL_LOG_TRACE, "loop=%u, count=%u, curr_pos=%u",
+ loop, count, curr_pos);
+ idx = shmcb_get_index(queue, curr_pos);
+ ssl_log(s, SSL_LOG_TRACE, "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]) {
+ ssl_log(s, SSL_LOG_TRACE, "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) {
+ ssl_log(s, SSL_LOG_ERROR, "shmcb_remove_session_id, "
+ "internal error");
+ goto end;
+ }
+ if ((pSession->session_id_length == idlen)
+ && (memcmp(id, pSession->session_id, idlen) == 0)) {
+ ssl_log(s, SSL_LOG_TRACE, "a match!");
+ /* Scrub out this session "quietly" */
+ idx->removed = (unsigned char) 1;
+ SSL_SESSION_free(pSession);
+ to_return = TRUE;
+ goto end;
+ }
+ ssl_log(s, SSL_LOG_TRACE, "not a match");
+ SSL_SESSION_free(pSession);
+ pSession = NULL;
+ }
+ curr_pos = shmcb_cyclic_increment(header->index_num, curr_pos, 1);
+ }
+ ssl_log(s, SSL_LOG_TRACE, "no matching sessions were found");
+
+ /* If there's entries to expire, ditch them now. */
+ shmcb_expire_division(s, queue, cache);
+end:
+ ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_remove_session_id");
+ return to_return;
+}
+
diff --git a/modules/ssl/ssl_scache_shmht.c b/modules/ssl/ssl_scache_shmht.c
new file mode 100644
index 0000000000..18e688af2c
--- /dev/null
+++ b/modules/ssl/ssl_scache_shmht.c
@@ -0,0 +1,347 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_scache_shmht.c
+** Session Cache via Shared Memory (Hash Table Variant)
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#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(size_t size)
+{
+ SSLModConfigRec *mc = myModConfig();
+ return ap_mm_malloc(mc->pSessionCacheDataMM, size);
+}
+
+static void *ssl_scache_shmht_calloc(size_t number, size_t size)
+{
+ SSLModConfigRec *mc = myModConfig();
+ return ap_mm_calloc(mc->pSessionCacheDataMM, number, size);
+}
+
+static void *ssl_scache_shmht_realloc(void *ptr, size_t size)
+{
+ SSLModConfigRec *mc = myModConfig();
+ return ap_mm_realloc(mc->pSessionCacheDataMM, ptr, size);
+}
+
+static void ssl_scache_shmht_free(void *ptr)
+{
+ SSLModConfigRec *mc = myModConfig();
+ ap_mm_free(mc->pSessionCacheDataMM, ptr);
+ 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, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+ AP_MM *mm;
+ table_t *ta;
+ int ta_errno;
+ int avail;
+ int n;
+
+ /*
+ * Create shared memory segment
+ */
+ if (mc->szSessionCacheDataFile == NULL) {
+ ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required");
+ ssl_die();
+ }
+ if ((mm = ap_mm_create(mc->nSessionCacheDataSize,
+ mc->szSessionCacheDataFile)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Cannot allocate shared memory: %s", ap_mm_error());
+ ssl_die();
+ }
+ mc->pSessionCacheDataMM = mm;
+
+ /*
+ * Make sure the childs have access to the underlaying files
+ */
+ ap_mm_permission(mm, SSL_MM_FILE_MODE, ap_user_id, -1);
+
+ /*
+ * Create hash table in shared memory segment
+ */
+ avail = ap_mm_available(mm);
+ n = (avail/2) / 1024;
+ n = n < 10 ? 10 : n;
+ if ((ta = table_alloc(n, &ta_errno,
+ ssl_scache_shmht_malloc,
+ ssl_scache_shmht_calloc,
+ ssl_scache_shmht_realloc,
+ ssl_scache_shmht_free )) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "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
+ */
+ ssl_log(s, SSL_LOG_INFO,
+ "Init: Created hash-table (%d buckets) "
+ "in shared memory (%d bytes) for SSL session cache", n, avail);
+ return;
+}
+
+void ssl_scache_shmht_kill(server_rec *s)
+{
+ SSLModConfigRec *mc = myModConfig();
+
+ if (mc->pSessionCacheDataMM != NULL) {
+ ap_mm_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();
+ void *vp;
+ UCHAR ucaData[SSL_SESSION_MAX_DER];
+ int nData;
+ UCHAR *ucp;
+
+ /* streamline session data */
+ ucp = ucaData;
+ nData = 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();
+ void *vp;
+ SSL_SESSION *sess = NULL;
+ 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(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();
+
+ /* 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();
+ 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->nSessionCacheTimeout)
+ 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));
+ 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);
+ }
+ ssl_mutex_off(s);
+ ssl_log(s, SSL_LOG_TRACE, "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, pool *p, void (*func)(char *, void *), void *arg)
+{
+ SSLModConfigRec *mc = myModConfig();
+ 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(ap_psprintf(p, "cache type: <b>SHMHT</b>, maximum size: <b>%d</b> bytes<br>", mc->nSessionCacheDataSize), arg);
+ func(ap_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg);
+ func(ap_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg);
+ return;
+}
+
diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c
new file mode 100644
index 0000000000..af4a9672f2
--- /dev/null
+++ b/modules/ssl/ssl_util.c
@@ -0,0 +1,437 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_util.c
+** Utility Functions
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/* ====================================================================
+ * Copyright (c) 1995-1999 Ben Laurie. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by Ben Laurie
+ * for use in the Apache-SSL HTTP server project."
+ *
+ * 4. The name "Apache-SSL Server" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Ben Laurie
+ * for use in the Apache-SSL HTTP server project."
+ *
+ * THIS SOFTWARE IS PROVIDED BY BEN LAURIE ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BEN LAURIE OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+ /* ``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"
+
+
+/* _________________________________________________________________
+**
+** Utility Functions
+** _________________________________________________________________
+*/
+
+char *ssl_util_server_root_relative(pool *p, char *what, char *arg)
+{
+ char *rv = NULL;
+
+#ifdef SSL_VENDOR
+ ap_hook_use("ap::mod_ssl::vendor::ssl_server_root_relative",
+ AP_HOOK_SIG4(ptr,ptr,ptr,ptr), AP_HOOK_ALL, &rv, p, what, arg);
+ if (rv != NULL)
+ return rv;
+#endif
+ rv = ap_server_root_relative(p, arg);
+ return rv;
+}
+
+char *ssl_util_vhostid(pool *p, server_rec *s)
+{
+ char *id;
+ SSLSrvConfigRec *sc;
+ char *host;
+ unsigned int port;
+
+ host = s->server_hostname;
+ if (s->port != 0)
+ port = s->port;
+ else {
+ sc = mySrvConfig(s);
+ if (sc->bEnabled)
+ port = DEFAULT_HTTPS_PORT;
+ else
+ port = DEFAULT_HTTP_PORT;
+ }
+ id = ap_psprintf(p, "%s:%u", host, port);
+ return id;
+}
+
+void ssl_util_strupper(char *s)
+{
+ for (; *s; ++s)
+ *s = 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;
+}
+
+FILE *ssl_util_ppopen(server_rec *s, pool *p, char *cmd)
+{
+ FILE *fpout;
+ int rc;
+
+ fpout = NULL;
+ rc = ap_spawn_child(p, ssl_util_ppopen_child,
+ (void *)cmd, kill_after_timeout,
+ NULL, &fpout, NULL);
+ if (rc == 0 || fpout == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, s,
+ "ssl_util_ppopen: could not run: %s", cmd);
+ return NULL;
+ }
+ return (fpout);
+}
+
+int ssl_util_ppopen_child(void *cmd, child_info *pinfo)
+{
+ int child_pid = 1;
+
+ /*
+ * Prepare for exec
+ */
+ ap_cleanup_for_exec();
+#ifdef SIGHUP
+ signal(SIGHUP, SIG_IGN);
+#endif
+
+ /*
+ * Exec() the child program
+ */
+#if defined(WIN32)
+ /* MS Windows */
+ {
+ char pCommand[MAX_STRING_LEN];
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ ap_snprintf(pCommand, sizeof(pCommand), "%s /C %s", SHELL_PATH, cmd);
+
+ memset(&si, 0, sizeof(si));
+ memset(&pi, 0, sizeof(pi));
+
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
+ si.wShowWindow = SW_HIDE;
+ si.hStdInput = pinfo->hPipeInputRead;
+ si.hStdOutput = pinfo->hPipeOutputWrite;
+ si.hStdError = pinfo->hPipeErrorWrite;
+
+ if (CreateProcess(NULL, pCommand, NULL, NULL, TRUE, 0,
+ environ, NULL, &si, &pi)) {
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ child_pid = pi.dwProcessId;
+ }
+ }
+#elif defined(OS2)
+ /* IBM OS/2 */
+ spawnl(P_NOWAIT, SHELL_PATH, SHELL_PATH, "/c", (char *)cmd, NULL);
+#else
+ /* Standard Unix */
+ execl(SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
+#endif
+ return (child_pid);
+}
+
+void ssl_util_ppclose(server_rec *s, pool *p, FILE *fp)
+{
+ ap_pfclose(p, fp);
+ return;
+}
+
+/*
+ * Run a filter program and read the first line of its stdout output
+ */
+char *ssl_util_readfilter(server_rec *s, pool *p, char *cmd)
+{
+ static char buf[MAX_STRING_LEN];
+ FILE *fp;
+ char c;
+ int k;
+
+ if ((fp = ssl_util_ppopen(s, p, cmd)) == NULL)
+ return NULL;
+ for (k = 0; read(fileno(fp), &c, 1) == 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, char *path)
+{
+ struct stat sb;
+
+ if (path == NULL)
+ return FALSE;
+ if (pcm & SSL_PCM_EXISTS && stat(path, &sb) != 0)
+ return FALSE;
+ if (pcm & SSL_PCM_ISREG && !S_ISREG(sb.st_mode))
+ return FALSE;
+ if (pcm & SSL_PCM_ISDIR && !S_ISDIR(sb.st_mode))
+ return FALSE;
+ if (pcm & SSL_PCM_ISNONZERO && sb.st_mode <= 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_type(pKey->type)) {
+ 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(
+ pool *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 = ap_pcalloc(p, nResult+1);
+ for (cpI = (char *)cpLine, cpO = cpResult, i = 0; cppMatch[i] != NULL; i++) {
+ ap_cpystrn(cpO, cpI, cppMatch[i]-cpI+1);
+ cpO += (cppMatch[i]-cpI);
+ ap_cpystrn(cpO, cpSubst, nSubst+1);
+ cpO += nSubst;
+ cpI = (cppMatch[i]+nMatch);
+ }
+ ap_cpystrn(cpO, cpI, cpResult+nResult-cpO+1);
+
+ return cpResult;
+}
+
+/* _________________________________________________________________
+**
+** Special Functions for Win32/OpenSSL
+** _________________________________________________________________
+*/
+
+#ifdef WIN32
+static HANDLE lock_cs[CRYPTO_NUM_LOCKS];
+
+static void win32_locking_callback(int mode, int type, char* file, int line)
+{
+ if (mode & CRYPTO_LOCK)
+ WaitForSingleObject(lock_cs[type], INFINITE);
+ else
+ ReleaseMutex(lock_cs[type]);
+ return;
+}
+#endif /* WIN32 */
+
+void ssl_util_thread_setup(void)
+{
+#ifdef WIN32
+ int i;
+
+ for (i = 0; i < CRYPTO_NUM_LOCKS; i++)
+ lock_cs[i] = CreateMutex(NULL, FALSE, NULL);
+ CRYPTO_set_locking_callback((void(*)(int, int, const char *, int))
+ win32_locking_callback);
+#endif /* WIN32 */
+ return;
+}
+
diff --git a/modules/ssl/ssl_util_sdbm.c b/modules/ssl/ssl_util_sdbm.c
new file mode 100644
index 0000000000..c728f90c86
--- /dev/null
+++ b/modules/ssl/ssl_util_sdbm.c
@@ -0,0 +1,926 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_util_sdbm.c
+** Built-in Simple DBM
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/*
+ * sdbm - ndbm work-alike hashed database library
+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
+ * author: oz@nexus.yorku.ca
+ * status: public domain.
+ *
+ * core routines
+ */
+
+#include "mod_ssl.h"
+
+#ifdef SSL_USE_SDBM
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef WIN32
+#include <io.h>
+#include <errno.h>
+#else
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#ifdef __STDC__
+#include <stddef.h>
+#endif
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+/*
+ * externals
+ */
+#ifdef sun
+extern int errno;
+#endif
+
+/*
+ * forward
+ */
+static int getdbit proto((DBM *, long));
+static int setdbit proto((DBM *, long));
+static int getpage proto((DBM *, long));
+static datum getnext proto((DBM *));
+static int makroom proto((DBM *, long, int));
+
+/*
+ * useful macros
+ */
+#define bad(x) ((x).dptr == NULL || (x).dsize <= 0)
+#define exhash(item) sdbm_hash((item).dptr, (item).dsize)
+#define ioerr(db) ((db)->flags |= DBM_IOERR)
+
+#define OFF_PAG(off) (long) (off) * PBLKSIZ
+#define OFF_DIR(off) (long) (off) * DBLKSIZ
+
+static long masks[] = {
+ 000000000000, 000000000001, 000000000003, 000000000007,
+ 000000000017, 000000000037, 000000000077, 000000000177,
+ 000000000377, 000000000777, 000000001777, 000000003777,
+ 000000007777, 000000017777, 000000037777, 000000077777,
+ 000000177777, 000000377777, 000000777777, 000001777777,
+ 000003777777, 000007777777, 000017777777, 000037777777,
+ 000077777777, 000177777777, 000377777777, 000777777777,
+ 001777777777, 003777777777, 007777777777, 017777777777
+};
+
+datum nullitem = {NULL, 0};
+
+DBM *
+sdbm_open(file, flags, mode)
+register char *file;
+register int flags;
+register int mode;
+{
+ register DBM *db;
+ register char *dirname;
+ register char *pagname;
+ register int n;
+
+ if (file == NULL || !*file)
+ return errno = EINVAL, (DBM *) NULL;
+/*
+ * need space for two seperate filenames
+ */
+ n = strlen(file) * 2 + strlen(DIRFEXT) + strlen(PAGFEXT) + 2;
+
+ if ((dirname = malloc((unsigned) n)) == NULL)
+ return errno = ENOMEM, (DBM *) NULL;
+/*
+ * build the file names
+ */
+ dirname = strcat(strcpy(dirname, file), DIRFEXT);
+ pagname = strcpy(dirname + strlen(dirname) + 1, file);
+ pagname = strcat(pagname, PAGFEXT);
+
+ db = sdbm_prep(dirname, pagname, flags, mode);
+ free((char *) dirname);
+ return db;
+}
+
+DBM *
+sdbm_prep(dirname, pagname, flags, mode)
+char *dirname;
+char *pagname;
+int flags;
+int mode;
+{
+ register DBM *db;
+ struct stat dstat;
+
+ if ((db = (DBM *) malloc(sizeof(DBM))) == NULL)
+ return errno = ENOMEM, (DBM *) NULL;
+
+ db->flags = 0;
+ db->hmask = 0;
+ db->blkptr = 0;
+ db->keyptr = 0;
+/*
+ * adjust user flags so that WRONLY becomes RDWR,
+ * as required by this package. Also set our internal
+ * flag for RDONLY if needed.
+ */
+ if (flags & O_WRONLY)
+ flags = (flags & ~O_WRONLY) | O_RDWR;
+ else if ((flags & 03) == O_RDONLY)
+ db->flags = DBM_RDONLY;
+#if defined(OS2) || defined(MSDOS) || defined(WIN32)
+ flags |= O_BINARY;
+#endif
+
+/*
+ * open the files in sequence, and stat the dirfile.
+ * If we fail anywhere, undo everything, return NULL.
+ */
+ if ((db->pagf = open(pagname, flags, mode)) > -1) {
+ if ((db->dirf = open(dirname, flags, mode)) > -1) {
+/*
+ * need the dirfile size to establish max bit number.
+ */
+ if (fstat(db->dirf, &dstat) == 0) {
+/*
+ * zero size: either a fresh database, or one with a single,
+ * unsplit data page: dirpage is all zeros.
+ */
+ db->dirbno = (!dstat.st_size) ? 0 : -1;
+ db->pagbno = -1;
+ db->maxbno = dstat.st_size * BYTESIZ;
+
+ (void) memset(db->pagbuf, 0, PBLKSIZ);
+ (void) memset(db->dirbuf, 0, DBLKSIZ);
+ /*
+ * success
+ */
+ return db;
+ }
+ (void) close(db->dirf);
+ }
+ (void) close(db->pagf);
+ }
+ free((char *) db);
+ return (DBM *) NULL;
+}
+
+void
+sdbm_close(db)
+register DBM *db;
+{
+ if (db == NULL)
+ errno = EINVAL;
+ else {
+ (void) close(db->dirf);
+ (void) close(db->pagf);
+ free((char *) db);
+ }
+}
+
+datum
+sdbm_fetch(db, key)
+register DBM *db;
+datum key;
+{
+ if (db == NULL || bad(key))
+ return errno = EINVAL, nullitem;
+
+ if (getpage(db, exhash(key)))
+ return getpair(db->pagbuf, key);
+
+ return ioerr(db), nullitem;
+}
+
+int
+sdbm_delete(db, key)
+register DBM *db;
+datum key;
+{
+ if (db == NULL || bad(key))
+ return errno = EINVAL, -1;
+ if (sdbm_rdonly(db))
+ return errno = EPERM, -1;
+
+ if (getpage(db, exhash(key))) {
+ if (!delpair(db->pagbuf, key))
+ return -1;
+/*
+ * update the page file
+ */
+ if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
+ || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
+ return ioerr(db), -1;
+
+ return 0;
+ }
+
+ return ioerr(db), -1;
+}
+
+int
+sdbm_store(db, key, val, flags)
+register DBM *db;
+datum key;
+datum val;
+int flags;
+{
+ int need;
+ register long hash;
+
+ if (db == NULL || bad(key))
+ return errno = EINVAL, -1;
+ if (sdbm_rdonly(db))
+ return errno = EPERM, -1;
+
+ need = key.dsize + val.dsize;
+/*
+ * is the pair too big (or too small) for this database ??
+ */
+ if (need < 0 || need > PAIRMAX)
+ return errno = EINVAL, -1;
+
+ if (getpage(db, (hash = exhash(key)))) {
+/*
+ * if we need to replace, delete the key/data pair
+ * first. If it is not there, ignore.
+ */
+ if (flags == DBM_REPLACE)
+ (void) delpair(db->pagbuf, key);
+#ifdef SEEDUPS
+ else if (duppair(db->pagbuf, key))
+ return 1;
+#endif
+/*
+ * if we do not have enough room, we have to split.
+ */
+ if (!fitpair(db->pagbuf, need))
+ if (!makroom(db, hash, need))
+ return ioerr(db), -1;
+/*
+ * we have enough room or split is successful. insert the key,
+ * and update the page file.
+ */
+ (void) putpair(db->pagbuf, key, val);
+
+ if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
+ || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
+ return ioerr(db), -1;
+ /*
+ * success
+ */
+ return 0;
+ }
+
+ return ioerr(db), -1;
+}
+
+/*
+ * makroom - make room by splitting the overfull page
+ * this routine will attempt to make room for SPLTMAX times before
+ * giving up.
+ */
+static int
+makroom(db, hash, need)
+register DBM *db;
+long hash;
+int need;
+{
+ long newp;
+ char twin[PBLKSIZ];
+ char *pag = db->pagbuf;
+ char *new = twin;
+ register int smax = SPLTMAX;
+
+ do {
+/*
+ * split the current page
+ */
+ (void) splpage(pag, new, db->hmask + 1);
+/*
+ * address of the new page
+ */
+ newp = (hash & db->hmask) | (db->hmask + 1);
+
+/*
+ * write delay, read avoidence/cache shuffle:
+ * select the page for incoming pair: if key is to go to the new page,
+ * write out the previous one, and copy the new one over, thus making
+ * it the current page. If not, simply write the new page, and we are
+ * still looking at the page of interest. current page is not updated
+ * here, as sdbm_store will do so, after it inserts the incoming pair.
+ */
+ if (hash & (db->hmask + 1)) {
+ if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
+ || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
+ return 0;
+ db->pagbno = newp;
+ (void) memcpy(pag, new, PBLKSIZ);
+ }
+ else if (lseek(db->pagf, OFF_PAG(newp), SEEK_SET) < 0
+ || write(db->pagf, new, PBLKSIZ) < 0)
+ return 0;
+
+ if (!setdbit(db, db->curbit))
+ return 0;
+/*
+ * see if we have enough room now
+ */
+ if (fitpair(pag, need))
+ return 1;
+/*
+ * try again... update curbit and hmask as getpage would have
+ * done. because of our update of the current page, we do not
+ * need to read in anything. BUT we have to write the current
+ * [deferred] page out, as the window of failure is too great.
+ */
+ db->curbit = 2 * db->curbit +
+ ((hash & (db->hmask + 1)) ? 2 : 1);
+ db->hmask |= db->hmask + 1;
+
+ if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
+ || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
+ return 0;
+
+ } while (--smax);
+/*
+ * if we are here, this is real bad news. After SPLTMAX splits,
+ * we still cannot fit the key. say goodnight.
+ */
+#ifdef BADMESS
+ (void) write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44);
+#endif
+ return 0;
+
+}
+
+/*
+ * the following two routines will break if
+ * deletions aren't taken into account. (ndbm bug)
+ */
+datum
+sdbm_firstkey(db)
+register DBM *db;
+{
+ if (db == NULL)
+ return errno = EINVAL, nullitem;
+/*
+ * start at page 0
+ */
+ if (lseek(db->pagf, OFF_PAG(0), SEEK_SET) < 0
+ || read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
+ return ioerr(db), nullitem;
+ db->pagbno = 0;
+ db->blkptr = 0;
+ db->keyptr = 0;
+
+ return getnext(db);
+}
+
+datum
+sdbm_nextkey(db)
+register DBM *db;
+{
+ if (db == NULL)
+ return errno = EINVAL, nullitem;
+ return getnext(db);
+}
+
+/*
+ * all important binary trie traversal
+ */
+static int
+getpage(db, hash)
+register DBM *db;
+register long hash;
+{
+ register int hbit;
+ register long dbit;
+ register long pagb;
+
+ dbit = 0;
+ hbit = 0;
+ while (dbit < db->maxbno && getdbit(db, dbit))
+ dbit = 2 * dbit + ((hash & (1 << hbit++)) ? 2 : 1);
+
+ debug(("dbit: %d...", dbit));
+
+ db->curbit = dbit;
+ db->hmask = masks[hbit];
+
+ pagb = hash & db->hmask;
+/*
+ * see if the block we need is already in memory.
+ * note: this lookaside cache has about 10% hit rate.
+ */
+ if (pagb != db->pagbno) {
+/*
+ * note: here, we assume a "hole" is read as 0s.
+ * if not, must zero pagbuf first.
+ */
+ if (lseek(db->pagf, OFF_PAG(pagb), SEEK_SET) < 0
+ || read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
+ return 0;
+ if (!chkpage(db->pagbuf))
+ return 0;
+ db->pagbno = pagb;
+
+ debug(("pag read: %d\n", pagb));
+ }
+ return 1;
+}
+
+static int
+getdbit(db, dbit)
+register DBM *db;
+register long dbit;
+{
+ register long c;
+ register long dirb;
+
+ c = dbit / BYTESIZ;
+ dirb = c / DBLKSIZ;
+
+ if (dirb != db->dirbno) {
+ if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
+ || read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
+ return 0;
+ db->dirbno = dirb;
+
+ debug(("dir read: %d\n", dirb));
+ }
+
+ return db->dirbuf[c % DBLKSIZ] & (1 << dbit % BYTESIZ);
+}
+
+static int
+setdbit(db, dbit)
+register DBM *db;
+register long dbit;
+{
+ register long c;
+ register long dirb;
+
+ c = dbit / BYTESIZ;
+ dirb = c / DBLKSIZ;
+
+ if (dirb != db->dirbno) {
+ if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
+ || read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
+ return 0;
+ db->dirbno = dirb;
+
+ debug(("dir read: %d\n", dirb));
+ }
+
+ db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ);
+
+ if (dbit >= db->maxbno)
+ db->maxbno += DBLKSIZ * BYTESIZ;
+
+ if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
+ || write(db->dirf, db->dirbuf, DBLKSIZ) < 0)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * getnext - get the next key in the page, and if done with
+ * the page, try the next page in sequence
+ */
+static datum
+getnext(db)
+register DBM *db;
+{
+ datum key;
+
+ for (;;) {
+ db->keyptr++;
+ key = getnkey(db->pagbuf, db->keyptr);
+ if (key.dptr != NULL)
+ return key;
+/*
+ * we either run out, or there is nothing on this page..
+ * try the next one... If we lost our position on the
+ * file, we will have to seek.
+ */
+ db->keyptr = 0;
+ if (db->pagbno != db->blkptr++)
+ if (lseek(db->pagf, OFF_PAG(db->blkptr), SEEK_SET) < 0)
+ break;
+ db->pagbno = db->blkptr;
+ if (read(db->pagf, db->pagbuf, PBLKSIZ) <= 0)
+ break;
+ if (!chkpage(db->pagbuf))
+ break;
+ }
+
+ return ioerr(db), nullitem;
+}
+
+/* ************************* */
+
+/*
+ * sdbm - ndbm work-alike hashed database library
+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
+ * author: oz@nexus.yorku.ca
+ * status: public domain. keep it that way.
+ *
+ * hashing routine
+ */
+
+/*
+ * polynomial conversion ignoring overflows
+ * [this seems to work remarkably well, in fact better
+ * then the ndbm hash function. Replace at your own risk]
+ * use: 65599 nice.
+ * 65587 even better.
+ */
+long
+sdbm_hash(str, len)
+register char *str;
+register int len;
+{
+ register unsigned long n = 0;
+
+#ifdef DUFF
+#define HASHC n = *str++ + 65599 * n
+ if (len > 0) {
+ register int loop = (len + 8 - 1) >> 3;
+
+ switch(len & (8 - 1)) {
+ case 0: do {
+ HASHC; case 7: HASHC;
+ case 6: HASHC; case 5: HASHC;
+ case 4: HASHC; case 3: HASHC;
+ case 2: HASHC; case 1: HASHC;
+ } while (--loop);
+ }
+
+ }
+#else
+ while (len--)
+ n = *str++ + 65599 * n;
+#endif
+ return n;
+}
+
+/* ************************* */
+
+/*
+ * sdbm - ndbm work-alike hashed database library
+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
+ * author: oz@nexus.yorku.ca
+ * status: public domain.
+ *
+ * page-level routines
+ */
+
+#define exhash(item) sdbm_hash((item).dptr, (item).dsize)
+
+/*
+ * forward
+ */
+static int seepair proto((char *, int, char *, int));
+
+/*
+ * page format:
+ * +------------------------------+
+ * ino | n | keyoff | datoff | keyoff |
+ * +------------+--------+--------+
+ * | datoff | - - - ----> |
+ * +--------+---------------------+
+ * | F R E E A R E A |
+ * +--------------+---------------+
+ * | <---- - - - | data |
+ * +--------+-----+----+----------+
+ * | key | data | key |
+ * +--------+----------+----------+
+ *
+ * calculating the offsets for free area: if the number
+ * of entries (ino[0]) is zero, the offset to the END of
+ * the free area is the block size. Otherwise, it is the
+ * nth (ino[ino[0]]) entry's offset.
+ */
+
+int
+fitpair(pag, need)
+char *pag;
+int need;
+{
+ register int n;
+ register int off;
+ register int avail;
+ register short *ino = (short *) pag;
+
+ off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
+ avail = off - (n + 1) * sizeof(short);
+ need += 2 * sizeof(short);
+
+ debug(("free %d need %d\n", avail, need));
+
+ return need <= avail;
+}
+
+void
+putpair(pag, key, val)
+char *pag;
+datum key;
+datum val;
+{
+ register int n;
+ register int off;
+ register short *ino = (short *) pag;
+
+ off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
+/*
+ * enter the key first
+ */
+ off -= key.dsize;
+ (void) memcpy(pag + off, key.dptr, key.dsize);
+ ino[n + 1] = off;
+/*
+ * now the data
+ */
+ off -= val.dsize;
+ (void) memcpy(pag + off, val.dptr, val.dsize);
+ ino[n + 2] = off;
+/*
+ * adjust item count
+ */
+ ino[0] += 2;
+}
+
+datum
+getpair(pag, key)
+char *pag;
+datum key;
+{
+ register int i;
+ register int n;
+ datum val;
+ register short *ino = (short *) pag;
+
+ if ((n = ino[0]) == 0)
+ return nullitem;
+
+ if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
+ return nullitem;
+
+ val.dptr = pag + ino[i + 1];
+ val.dsize = ino[i] - ino[i + 1];
+ return val;
+}
+
+#ifdef SEEDUPS
+int
+duppair(pag, key)
+char *pag;
+datum key;
+{
+ register short *ino = (short *) pag;
+ return ino[0] > 0 && seepair(pag, ino[0], key.dptr, key.dsize) > 0;
+}
+#endif
+
+datum
+getnkey(pag, num)
+char *pag;
+int num;
+{
+ datum key;
+ register int off;
+ register short *ino = (short *) pag;
+
+ num = num * 2 - 1;
+ if (ino[0] == 0 || num > ino[0])
+ return nullitem;
+
+ off = (num > 1) ? ino[num - 1] : PBLKSIZ;
+
+ key.dptr = pag + ino[num];
+ key.dsize = off - ino[num];
+
+ return key;
+}
+
+int
+delpair(pag, key)
+char *pag;
+datum key;
+{
+ register int n;
+ register int i;
+ register short *ino = (short *) pag;
+
+ if ((n = ino[0]) == 0)
+ return 0;
+
+ if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
+ return 0;
+/*
+ * found the key. if it is the last entry
+ * [i.e. i == n - 1] we just adjust the entry count.
+ * hard case: move all data down onto the deleted pair,
+ * shift offsets onto deleted offsets, and adjust them.
+ * [note: 0 < i < n]
+ */
+ if (i < n - 1) {
+ register int m;
+ register char *dst = pag + (i == 1 ? PBLKSIZ : ino[i - 1]);
+ register char *src = pag + ino[i + 1];
+ register int zoo = dst - src;
+
+ debug(("free-up %d ", zoo));
+/*
+ * shift data/keys down
+ */
+ m = ino[i + 1] - ino[n];
+#ifdef DUFF
+#define MOVB *--dst = *--src
+ if (m > 0) {
+ register int loop = (m + 8 - 1) >> 3;
+
+ switch (m & (8 - 1)) {
+ case 0: do {
+ MOVB; case 7: MOVB;
+ case 6: MOVB; case 5: MOVB;
+ case 4: MOVB; case 3: MOVB;
+ case 2: MOVB; case 1: MOVB;
+ } while (--loop);
+ }
+ }
+#else
+ dst -= m;
+ src -= m;
+ memmove(dst, src, m);
+#endif
+/*
+ * adjust offset index up
+ */
+ while (i < n - 1) {
+ ino[i] = ino[i + 2] + zoo;
+ i++;
+ }
+ }
+ ino[0] -= 2;
+ return 1;
+}
+
+/*
+ * search for the key in the page.
+ * return offset index in the range 0 < i < n.
+ * return 0 if not found.
+ */
+static int
+seepair(pag, n, key, siz)
+char *pag;
+register int n;
+register char *key;
+register int siz;
+{
+ register int i;
+ register int off = PBLKSIZ;
+ register short *ino = (short *) pag;
+
+ for (i = 1; i < n; i += 2) {
+ if (siz == off - ino[i] &&
+ memcmp(key, pag + ino[i], siz) == 0)
+ return i;
+ off = ino[i + 1];
+ }
+ return 0;
+}
+
+void
+splpage(pag, new, sbit)
+char *pag;
+char *new;
+long sbit;
+{
+ datum key;
+ datum val;
+
+ register int n;
+ register int off = PBLKSIZ;
+ char cur[PBLKSIZ];
+ register short *ino = (short *) cur;
+
+ (void) memcpy(cur, pag, PBLKSIZ);
+ (void) memset(pag, 0, PBLKSIZ);
+ (void) memset(new, 0, PBLKSIZ);
+
+ n = ino[0];
+ for (ino++; n > 0; ino += 2) {
+ key.dptr = cur + ino[0];
+ key.dsize = off - ino[0];
+ val.dptr = cur + ino[1];
+ val.dsize = ino[0] - ino[1];
+/*
+ * select the page pointer (by looking at sbit) and insert
+ */
+ (void) putpair((exhash(key) & sbit) ? new : pag, key, val);
+
+ off = ino[1];
+ n -= 2;
+ }
+
+ debug(("%d split %d/%d\n", ((short *) cur)[0] / 2,
+ ((short *) new)[0] / 2,
+ ((short *) pag)[0] / 2));
+}
+
+/*
+ * check page sanity:
+ * number of entries should be something
+ * reasonable, and all offsets in the index should be in order.
+ * this could be made more rigorous.
+ */
+int
+chkpage(pag)
+char *pag;
+{
+ register int n;
+ register int off;
+ register short *ino = (short *) pag;
+
+ if ((n = ino[0]) < 0 || n > PBLKSIZ / sizeof(short))
+ return 0;
+
+ if (n > 0) {
+ off = PBLKSIZ;
+ for (ino++; n > 0; ino += 2) {
+ if (ino[0] > off || ino[1] > off ||
+ ino[1] > ino[0])
+ return 0;
+ off = ino[1];
+ n -= 2;
+ }
+ }
+ return 1;
+}
+
+#endif /* SSL_USE_SDBM */
diff --git a/modules/ssl/ssl_util_sdbm.h b/modules/ssl/ssl_util_sdbm.h
new file mode 100644
index 0000000000..723e8095b4
--- /dev/null
+++ b/modules/ssl/ssl_util_sdbm.h
@@ -0,0 +1,191 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_util_sdbm.c
+** Built-in Simple DBM (Header)
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/*
+ * sdbm - ndbm work-alike hashed database library
+ * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
+ * author: oz@nexus.yorku.ca
+ * status: public domain.
+ */
+
+#ifndef SSL_UTIL_SDBM_H
+#define SSL_UTIL_SDBM_H
+
+#define DUFF /* go ahead and use the loop-unrolled version */
+
+#include <stdio.h>
+
+#ifdef MOD_SSL
+#define DBLKSIZ 16384 /* SSL cert chains require more */
+#define PBLKSIZ 8192 /* SSL cert chains require more */
+#define PAIRMAX 8008 /* arbitrary on PBLKSIZ-N */
+#else
+#define DBLKSIZ 4096
+#define PBLKSIZ 1024
+#define PAIRMAX 1008 /* arbitrary on PBLKSIZ-N */
+#endif
+#define SPLTMAX 10 /* maximum allowed splits */
+ /* for a single insertion */
+#define DIRFEXT ".dir"
+#define PAGFEXT ".pag"
+
+typedef struct {
+ int dirf; /* directory file descriptor */
+ int pagf; /* page file descriptor */
+ int flags; /* status/error flags, see below */
+ long maxbno; /* size of dirfile in bits */
+ long curbit; /* current bit number */
+ long hmask; /* current hash mask */
+ long blkptr; /* current block for nextkey */
+ int keyptr; /* current key for nextkey */
+ long blkno; /* current page to read/write */
+ long pagbno; /* current page in pagbuf */
+ char pagbuf[PBLKSIZ]; /* page file block buffer */
+ long dirbno; /* current block in dirbuf */
+ char dirbuf[DBLKSIZ]; /* directory file block buffer */
+} DBM;
+
+#define DBM_RDONLY 0x1 /* data base open read-only */
+#define DBM_IOERR 0x2 /* data base I/O error */
+
+/*
+ * utility macros
+ */
+#define sdbm_rdonly(db) ((db)->flags & DBM_RDONLY)
+#define sdbm_error(db) ((db)->flags & DBM_IOERR)
+
+#define sdbm_clearerr(db) ((db)->flags &= ~DBM_IOERR) /* ouch */
+
+#define sdbm_dirfno(db) ((db)->dirf)
+#define sdbm_pagfno(db) ((db)->pagf)
+
+typedef struct {
+ char *dptr;
+ int dsize;
+} datum;
+
+extern datum nullitem;
+
+#ifdef __STDC__
+#define proto(p) p
+#else
+#define proto(p) ()
+#endif
+
+/*
+ * flags to sdbm_store
+ */
+#define DBM_INSERT 0
+#define DBM_REPLACE 1
+
+/*
+ * ndbm interface
+ */
+extern DBM *sdbm_open proto((char *, int, int));
+extern void sdbm_close proto((DBM *));
+extern datum sdbm_fetch proto((DBM *, datum));
+extern int sdbm_delete proto((DBM *, datum));
+extern int sdbm_store proto((DBM *, datum, datum, int));
+extern datum sdbm_firstkey proto((DBM *));
+extern datum sdbm_nextkey proto((DBM *));
+
+/*
+ * other
+ */
+extern DBM *sdbm_prep proto((char *, char *, int, int));
+extern long sdbm_hash proto((char *, int));
+
+/* pair.h */
+extern int fitpair proto((char *, int));
+extern void putpair proto((char *, datum, datum));
+extern datum getpair proto((char *, datum));
+extern int delpair proto((char *, datum));
+extern int chkpage proto((char *));
+extern datum getnkey proto((char *, int));
+extern void splpage proto((char *, char *, long));
+extern int duppair proto((char *, datum));
+
+/* tune.h */
+/*
+ * sdbm - ndbm work-alike hashed database library
+ * tuning and portability constructs [not nearly enough]
+ * author: oz@nexus.yorku.ca
+ */
+
+#define BYTESIZ 8
+
+/*
+ * important tuning parms (hah)
+ */
+
+#define SEEDUPS /* always detect duplicates */
+#define BADMESS /* generate a message for worst case:
+ cannot make room after SPLTMAX splits */
+/*
+ * misc
+ */
+#ifdef DEBUG
+#define debug(x) printf x
+#else
+#define debug(x)
+#endif
+
+#endif /* SSL_UTIL_SDBM_H */
diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c
new file mode 100644
index 0000000000..19f6bd3629
--- /dev/null
+++ b/modules/ssl/ssl_util_ssl.c
@@ -0,0 +1,544 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_util_ssl.c
+** Additional Utility Functions for OpenSSL
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include "mod_ssl.h"
+
+
+/* _________________________________________________________________
+**
+** Additional High-Level Functions for OpenSSL
+** _________________________________________________________________
+*/
+
+int SSL_get_app_data2_idx(void)
+{
+ static int app_data2_idx = -1;
+
+ if (app_data2_idx < 0) {
+ app_data2_idx = SSL_get_ex_new_index(0,
+ "Second Application Data for SSL", NULL, NULL, NULL);
+ app_data2_idx = SSL_get_ex_new_index(0,
+ "Second Application Data for SSL", NULL, NULL, NULL);
+ }
+ return(app_data2_idx);
+}
+
+void *SSL_get_app_data2(SSL *ssl)
+{
+ return (void *)SSL_get_ex_data(ssl, SSL_get_app_data2_idx());
+}
+
+void SSL_set_app_data2(SSL *ssl, void *arg)
+{
+ SSL_set_ex_data(ssl, SSL_get_app_data2_idx(), (char *)arg);
+ return;
+}
+
+/* _________________________________________________________________
+**
+** High-Level Certificate / Private Key Loading
+** _________________________________________________________________
+*/
+
+X509 *SSL_read_X509(FILE *fp, X509 **x509, int (*cb)())
+{
+ X509 *rc;
+ BIO *bioS;
+ BIO *bioF;
+
+ /* 1. try PEM (= DER+Base64+headers) */
+#if SSL_LIBRARY_VERSION < 0x00904000
+ rc = PEM_read_X509(fp, x509, cb);
+#else
+ rc = PEM_read_X509(fp, x509, cb, NULL);
+#endif
+ if (rc == NULL) {
+ /* 2. try DER+Base64 */
+ fseek(fp, 0L, SEEK_SET);
+ if ((bioS = BIO_new(BIO_s_fd())) == NULL)
+ return NULL;
+ BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE);
+ 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 */
+ fseek(fp, 0L, SEEK_SET);
+ if ((bioS = BIO_new(BIO_s_fd())) == NULL)
+ return NULL;
+ BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE);
+ 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(FILE *fp, EVP_PKEY **key, int (*cb)())
+{
+ EVP_PKEY *rc;
+ BIO *bioS;
+ BIO *bioF;
+
+ /* 1. try PEM (= DER+Base64+headers) */
+#if SSL_LIBRARY_VERSION < 0x00904000
+ rc = PEM_read_PrivateKey(fp, key, cb);
+#else
+ rc = PEM_read_PrivateKey(fp, key, cb, NULL);
+#endif
+ if (rc == NULL) {
+ /* 2. try DER+Base64 */
+ fseek(fp, 0L, SEEK_SET);
+ if ((bioS = BIO_new(BIO_s_fd())) == NULL)
+ return NULL;
+ BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE);
+ 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 */
+ fseek(fp, 0L, SEEK_SET);
+ if ((bioS = BIO_new(BIO_s_fd())) == NULL)
+ return NULL;
+ BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE);
+ 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) {
+ if ((pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_file())) == NULL) {
+ X509_STORE_free(pStore);
+ return NULL;
+ }
+ X509_LOOKUP_load_file(pLookup, cpFile, X509_FILETYPE_PEM);
+ }
+ if (cpPath != NULL) {
+ if ((pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_hash_dir())) == 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(pool *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 = 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(c->name)+2+1;
+ }
+ if (l == 0)
+ return "";
+ cpCipherSuite = (char *)ap_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(c->name);
+ memcpy(cp, c->name, l);
+ cp += l;
+ *cp++ = '/';
+ *cp++ = (c->valid == 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)
+{
+ 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;
+}
+
+/* retrieve basic constraints ingredients */
+BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen)
+{
+ 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;
+}
+
+/* retrieve subject CommonName of certificate */
+BOOL SSL_X509_getCN(pool *p, X509 *xs, char **cppCN)
+{
+ X509_NAME *xsn;
+ X509_NAME_ENTRY *xsne;
+ int i, nid;
+
+ xsn = X509_get_subject_name(xs);
+ for (i = 0; i < sk_X509_NAME_ENTRY_num(xsn->entries); i++) {
+ xsne = sk_X509_NAME_ENTRY_value(xsn->entries, i);
+ nid = OBJ_obj2nid(xsne->object);
+ if (nid == NID_commonName) {
+ *cppCN = ap_palloc(p, xsne->value->length+1);
+ ap_cpystrn(*cppCN, (char *)xsne->value->data, xsne->value->length+1);
+ (*cppCN)[xsne->value->length] = NUL;
+#ifdef CHARSET_EBCDIC
+ ascii2ebcdic(*cppCN, *cppCN, strlen(*cppCN));
+#endif
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* _________________________________________________________________
+**
+** Low-Level CA Certificate Loading
+** _________________________________________________________________
+*/
+
+#ifdef SSL_EXPERIMENTAL_PROXY
+
+BOOL SSL_load_CrtAndKeyInfo_file(pool *p, STACK_OF(X509_INFO) *sk, char *filename)
+{
+ BIO *in;
+
+ if ((in = BIO_new(BIO_s_file())) == NULL)
+ return FALSE;
+ if (BIO_read_filename(in, filename) <= 0) {
+ BIO_free(in);
+ return FALSE;
+ }
+ ERR_clear_error();
+#if SSL_LIBRARY_VERSION < 0x00904000
+ PEM_X509_INFO_read_bio(in, sk, NULL);
+#else
+ PEM_X509_INFO_read_bio(in, sk, NULL, NULL);
+#endif
+ BIO_free(in);
+ return TRUE;
+}
+
+BOOL SSL_load_CrtAndKeyInfo_path(pool *p, STACK_OF(X509_INFO) *sk, char *pathname)
+{
+ struct stat st;
+ DIR *dir;
+ pool *sp;
+ struct dirent *nextent;
+ char *fullname;
+ BOOL ok;
+
+ sp = ap_make_sub_pool(p);
+ if ((dir = ap_popendir(sp, pathname)) == NULL) {
+ ap_destroy_pool(sp);
+ return FALSE;
+ }
+ ok = FALSE;
+ while ((nextent = readdir(dir)) != NULL) {
+ fullname = ap_pstrcat(sp, pathname, "/", nextent->d_name, NULL);
+ if (stat(fullname, &st) != 0)
+ continue;
+ if (!S_ISREG(st.st_mode))
+ continue;
+ if (SSL_load_CrtAndKeyInfo_file(sp, sk, fullname))
+ ok = TRUE;
+ }
+ ap_pclosedir(p, dir);
+ ap_destroy_pool(sp);
+ return ok;
+}
+
+#endif /* SSL_EXPERIMENTAL_PROXY */
+
+/* _________________________________________________________________
+**
+** 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, int (*cb)())
+{
+ BIO *bio;
+ X509 *x509;
+ unsigned long err;
+ int n;
+
+ 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 SSL_LIBRARY_VERSION < 0x00904000
+ if ((x509 = PEM_read_bio_X509(bio, NULL, cb)) == NULL) {
+#else
+ if ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) == NULL) {
+#endif
+ BIO_free(bio);
+ return -1;
+ }
+ X509_free(x509);
+ }
+ /* free a perhaps already configured extra chain */
+ if (ctx->extra_certs != NULL) {
+ sk_X509_pop_free(ctx->extra_certs, X509_free);
+ ctx->extra_certs = NULL;
+ }
+ /* create new extra chain by loading the certs */
+ n = 0;
+#if SSL_LIBRARY_VERSION < 0x00904000
+ while ((x509 = PEM_read_bio_X509(bio, NULL, cb)) != NULL) {
+#else
+ while ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) != NULL) {
+#endif
+ 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)
+{
+ static char str[(SSL_MAX_SSL_SESSION_ID_LENGTH+1)*2];
+ char *cp;
+ int n;
+
+ cp = str;
+ for (n = 0; n < idlen && n < SSL_MAX_SSL_SESSION_ID_LENGTH; n++) {
+ ap_snprintf(cp, sizeof(str)-(cp-str), "%02X", id[n]);
+ cp += 2;
+ }
+ *cp = NUL;
+ return str;
+}
+
diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h
new file mode 100644
index 0000000000..23aaaaa40d
--- /dev/null
+++ b/modules/ssl/ssl_util_ssl.h
@@ -0,0 +1,115 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_util_ssl.h
+** Additional Utility Functions for OpenSSL
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#ifndef SSL_UTIL_SSL_H
+#define SSL_UTIL_SSL_H
+
+/*
+ * Determine SSL library version number
+ */
+#ifdef OPENSSL_VERSION_NUMBER
+#define SSL_LIBRARY_VERSION OPENSSL_VERSION_NUMBER
+#define SSL_LIBRARY_NAME "OpenSSL"
+#define SSL_LIBRARY_TEXT OPENSSL_VERSION_TEXT
+#else
+#define SSL_LIBRARY_VERSION 0x0000
+#define SSL_LIBRARY_NAME "OtherSSL"
+#define SSL_LIBRARY_TEXT "OtherSSL 0.0.0 00 XXX 0000"
+#endif
+
+/*
+ * 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
+
+/*
+ * 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
+
+/*
+ * Additional Functions
+ */
+int SSL_get_app_data2_idx(void);
+void *SSL_get_app_data2(SSL *);
+void SSL_set_app_data2(SSL *, void *);
+X509 *SSL_read_X509(FILE *, X509 **, int (*)());
+EVP_PKEY *SSL_read_PrivateKey(FILE *, EVP_PKEY **, int (*)());
+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(pool *, SSL *);
+BOOL SSL_X509_isSGC(X509 *);
+BOOL SSL_X509_getBC(X509 *, int *, int *);
+BOOL SSL_X509_getCN(pool *, X509 *, char **);
+#ifdef SSL_EXPERIMENTAL_PROXY
+BOOL SSL_load_CrtAndKeyInfo_file(pool *, STACK_OF(X509_INFO) *, char *);
+BOOL SSL_load_CrtAndKeyInfo_path(pool *, STACK_OF(X509_INFO) *, char *);
+#endif /* SSL_EXPERIMENTAL_PROXY */
+int SSL_CTX_use_certificate_chain(SSL_CTX *, char *, int, int (*)());
+char *SSL_SESSION_id2sz(unsigned char *, int);
+
+#endif /* SSL_UTIL_SSL_H */
diff --git a/modules/ssl/ssl_util_table.c b/modules/ssl/ssl_util_table.c
new file mode 100644
index 0000000000..f68c6dd0fe
--- /dev/null
+++ b/modules/ssl/ssl_util_table.c
@@ -0,0 +1,2868 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_util_table.c
+** High Performance Hash Table Functions
+*/
+
+/* ====================================================================
+ * Copyright (c) 1999-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/*
+ * 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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef WIN32
+#include <io.h>
+#include <errno.h>
+#else
+#include <unistd.h>
+#endif
+
+/* 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"
+
+/****************************** 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)(size_t size);
+ void *(*ta_calloc)(size_t number, size_t size);
+ void *(*ta_realloc)(void *ptr, size_t size);
+ void (*ta_free)(void *ptr);
+};
+
+/* 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"
+
+/****************************** 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)(size_t size),
+ void *(*calloc_f)(size_t number, size_t size),
+ void *(*realloc_f)(void *ptr, size_t size),
+ void (*free_f)(void *ptr))
+{
+ table_t *table_p = NULL;
+ unsigned int buck_n;
+
+ /* allocate a table structure */
+ if (malloc_f != NULL)
+ table_p = malloc_f(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(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(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 : malloc;
+ table_p->ta_calloc = calloc_f != NULL ? calloc_f : calloc;
+ table_p->ta_realloc = realloc_f != NULL ? realloc_f : realloc;
+ table_p->ta_free = free_f != NULL ? free_f : free;
+
+ 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(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->ta_buckets);
+ table_p->ta_magic = 0;
+ table_p->ta_free(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;
+ 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(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(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(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(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_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(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(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(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(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->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;
+}
+
+/******************************* file routines *******************************/
+
+/*
+ * int table_read
+ *
+ * DESCRIPTION:
+ *
+ * Read in a table from a file that had been written to disk earlier
+ * via table_write.
+ *
+ * RETURNS:
+ *
+ * Success - Pointer to the new table structure which must be passed
+ * to table_free to be deallocated.
+ *
+ * Failure - NULL
+ *
+ * ARGUMENTS:
+ *
+ * path - Table file to read in.
+ *
+ * error_p - Pointer to an integer which, if not NULL, will contain a
+ * table error code.
+ */
+table_t *table_read(const char *path, int *error_p,
+ void *(*malloc_f)(size_t size),
+ void *(*calloc_f)(size_t number, size_t size),
+ void *(*realloc_f)(void *ptr, size_t size),
+ void (*free_f)(void *ptr))
+{
+ unsigned int size;
+ int fd, ent_size;
+ FILE *infile;
+ table_entry_t entry, **bucket_p, *entry_p = NULL, *last_p;
+ unsigned long pos;
+ table_t *table_p;
+
+ /* open the file */
+ fd = open(path, O_RDONLY, 0);
+ if (fd < 0) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_OPEN;
+ return NULL;
+ }
+
+ /* allocate a table structure */
+ if (malloc_f != NULL)
+ table_p = malloc_f(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;
+ }
+
+ /* now open the fd to get buffered i/o */
+ infile = fdopen(fd, "r");
+ if (infile == NULL) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_OPEN;
+ return NULL;
+ }
+
+ /* read the main table struct */
+ if (fread(table_p, sizeof(table_t), 1, infile) != 1) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_READ;
+ if (free_f != NULL)
+ free_f(table_p);
+ else
+ free(table_p);
+ return NULL;
+ }
+ table_p->ta_file_size = 0;
+
+ table_p->ta_malloc = malloc_f != NULL ? malloc_f : malloc;
+ table_p->ta_calloc = calloc_f != NULL ? calloc_f : calloc;
+ table_p->ta_realloc = realloc_f != NULL ? realloc_f : realloc;
+ table_p->ta_free = free_f != NULL ? free_f : free;
+
+ /* is the file contain bad info or maybe another system type? */
+ if (table_p->ta_magic != TABLE_MAGIC) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_PNT;
+ return NULL;
+ }
+
+ /* allocate the buckets */
+ table_p->ta_buckets = (table_entry_t **)table_p->ta_calloc(table_p->ta_bucket_n, sizeof(table_entry_t *));
+ if (table_p->ta_buckets == NULL) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_ALLOC;
+ table_p->ta_free(table_p);
+ return NULL;
+ }
+
+ if (fread(table_p->ta_buckets, sizeof(table_entry_t *), table_p->ta_bucket_n,
+ infile) != (size_t) table_p->ta_bucket_n) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_READ;
+ table_p->ta_free(table_p->ta_buckets);
+ table_p->ta_free(table_p);
+ return NULL;
+ }
+
+ /* read in the entries */
+ for (bucket_p = table_p->ta_buckets;
+ bucket_p < table_p->ta_buckets + table_p->ta_bucket_n;
+ bucket_p++) {
+
+ /* skip null buckets */
+ if (*bucket_p == NULL)
+ continue;
+ /* run through the entry list */
+ last_p = NULL;
+ for (pos = *(unsigned long *) bucket_p;;
+ pos = (unsigned long) entry_p->te_next_p) {
+
+ /* read in the entry */
+ if (fseek(infile, pos, SEEK_SET) != 0) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_SEEK;
+ table_p->ta_free(table_p->ta_buckets);
+ if (entry_p != NULL)
+ table_p->ta_free(entry_p);
+ table_p->ta_free(table_p);
+ /* the other table elements will not be freed */
+ return NULL;
+ }
+ if (fread(&entry, sizeof(struct table_shell_st), 1, infile) != 1) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_READ;
+ table_p->ta_free(table_p->ta_buckets);
+ if (entry_p != NULL)
+ table_p->ta_free(entry_p);
+ table_p->ta_free(table_p);
+ /* the other table elements will not be freed */
+ return NULL;
+ }
+
+ /* make a new entry */
+ ent_size = entry_size(table_p, entry.te_key_size, entry.te_data_size);
+ entry_p = (table_entry_t *)table_p->ta_malloc(ent_size);
+ if (entry_p == NULL) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_ALLOC;
+ table_p->ta_free(table_p->ta_buckets);
+ table_p->ta_free(table_p);
+ /* the other table elements will not be freed */
+ return NULL;
+ }
+ entry_p->te_key_size = entry.te_key_size;
+ entry_p->te_data_size = entry.te_data_size;
+ entry_p->te_next_p = entry.te_next_p;
+
+ if (last_p == NULL)
+ *bucket_p = entry_p;
+ else
+ last_p->te_next_p = entry_p;
+ /* determine how much more we have to read */
+ size = ent_size - sizeof(struct table_shell_st);
+ if (fread(ENTRY_KEY_BUF(entry_p), sizeof(char), size, infile) != size) {
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_READ;
+ table_p->ta_free(table_p->ta_buckets);
+ table_p->ta_free(entry_p);
+ table_p->ta_free(table_p);
+ /* the other table elements will not be freed */
+ return NULL;
+ }
+
+ /* we are done if the next pointer is null */
+ if (entry_p->te_next_p == (unsigned long) 0)
+ break;
+ last_p = entry_p;
+ }
+ }
+
+ (void) fclose(infile);
+
+ if (error_p != NULL)
+ *error_p = TABLE_ERROR_NONE;
+ return table_p;
+}
+
+/*
+ * int table_write
+ *
+ * DESCRIPTION:
+ *
+ * Write a table from memory to file.
+ *
+ * RETURNS:
+ *
+ * Success - TABLE_ERROR_NONE
+ *
+ * Failure - Table error code.
+ *
+ * ARGUMENTS:
+ *
+ * table_p - Pointer to the table that we are writing to the file.
+ *
+ * path - Table file to write out to.
+ *
+ * mode - Mode of the file. This argument is passed on to open when
+ * the file is created.
+ */
+int table_write(const table_t * table_p, const char *path, const int mode)
+{
+ int fd, rem, ent_size;
+ unsigned int bucket_c;
+ unsigned long size;
+ table_entry_t *entry_p, **buckets, **bucket_p, *next_p;
+ table_t tmain;
+ FILE *outfile;
+
+ if (table_p == NULL)
+ return TABLE_ERROR_ARG_NULL;
+ if (table_p->ta_magic != TABLE_MAGIC)
+ return TABLE_ERROR_PNT;
+ fd = open(path, O_WRONLY | O_CREAT, mode);
+ if (fd < 0)
+ return TABLE_ERROR_OPEN;
+ outfile = fdopen(fd, "w");
+ if (outfile == NULL)
+ return TABLE_ERROR_OPEN;
+ /* allocate a block of sizes for each bucket */
+ buckets = (table_entry_t **) table_p->ta_malloc(sizeof(table_entry_t *) *
+ table_p->ta_bucket_n);
+ if (buckets == NULL)
+ return TABLE_ERROR_ALLOC;
+ /* make a copy of the tmain struct */
+ tmain = *table_p;
+
+ /* start counting the bytes */
+ size = 0;
+ size += sizeof(table_t);
+
+ /* buckets go right after tmain struct */
+ tmain.ta_buckets = (table_entry_t **) size;
+ size += sizeof(table_entry_t *) * table_p->ta_bucket_n;
+
+ /* run through and count the buckets */
+ for (bucket_c = 0; bucket_c < table_p->ta_bucket_n; bucket_c++) {
+ bucket_p = table_p->ta_buckets + bucket_c;
+ if (*bucket_p == NULL) {
+ buckets[bucket_c] = NULL;
+ continue;
+ }
+ buckets[bucket_c] = (table_entry_t *) size;
+ for (entry_p = *bucket_p; entry_p != NULL; entry_p = entry_p->te_next_p) {
+ size += entry_size(table_p, entry_p->te_key_size, entry_p->te_data_size);
+ /*
+ * We now have to round the file to the nearest long so the
+ * mmaping of the longs in the entry structs will work.
+ */
+ rem = size & (sizeof(long) - 1);
+ if (rem > 0)
+ size += sizeof(long) - rem;
+ }
+ }
+ /* add a \0 at the end to fill the last section */
+ size++;
+
+ /* set the tmain fields */
+ tmain.ta_linear.tl_magic = 0;
+ tmain.ta_linear.tl_bucket_c = 0;
+ tmain.ta_linear.tl_entry_c = 0;
+ tmain.ta_file_size = size;
+
+ /*
+ * Now we can start the writing because we got the bucket offsets.
+ */
+
+ /* write the tmain table struct */
+ size = 0;
+ if (fwrite(&tmain, sizeof(table_t), 1, outfile) != 1) {
+ table_p->ta_free(buckets);
+ return TABLE_ERROR_WRITE;
+ }
+ size += sizeof(table_t);
+ if (fwrite(buckets, sizeof(table_entry_t *), table_p->ta_bucket_n,
+ outfile) != (size_t) table_p->ta_bucket_n) {
+ table_p->ta_free(buckets);
+ return TABLE_ERROR_WRITE;
+ }
+ size += sizeof(table_entry_t *) * table_p->ta_bucket_n;
+
+ /* write out the entries */
+ for (bucket_p = table_p->ta_buckets;
+ bucket_p < table_p->ta_buckets + table_p->ta_bucket_n;
+ bucket_p++) {
+ for (entry_p = *bucket_p; entry_p != NULL; entry_p = entry_p->te_next_p) {
+
+ ent_size = entry_size(table_p, entry_p->te_key_size,
+ entry_p->te_data_size);
+ size += ent_size;
+ /* round to nearest long here so we can write copy */
+ rem = size & (sizeof(long) - 1);
+ if (rem > 0)
+ size += sizeof(long) - rem;
+ next_p = entry_p->te_next_p;
+ if (next_p != NULL)
+ entry_p->te_next_p = (table_entry_t *) size;
+ /* now write to disk */
+ if (fwrite(entry_p, ent_size, 1, outfile) != 1) {
+ table_p->ta_free(buckets);
+ return TABLE_ERROR_WRITE;
+ }
+
+ /* restore the next pointer */
+ if (next_p != NULL)
+ entry_p->te_next_p = next_p;
+ /* now write the padding information */
+ if (rem > 0) {
+ rem = sizeof(long) - rem;
+ /*
+ * NOTE: this won't leave fseek'd space at the end but we
+ * don't care there because there is no accessed memory
+ * afterwards. We write 1 \0 at the end to make sure.
+ */
+ if (fseek(outfile, rem, SEEK_CUR) != 0) {
+ table_p->ta_free(buckets);
+ return TABLE_ERROR_SEEK;
+ }
+ }
+ }
+ }
+ /*
+ * Write a \0 at the end of the file to make sure that the last
+ * fseek filled with nulls.
+ */
+ (void) fputc('\0', outfile);
+
+ (void) fclose(outfile);
+ table_p->ta_free(buckets);
+
+ 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->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/modules/ssl/ssl_util_table.h b/modules/ssl/ssl_util_table.h
new file mode 100644
index 0000000000..69c53bd8a0
--- /dev/null
+++ b/modules/ssl/ssl_util_table.h
@@ -0,0 +1,189 @@
+/* _ _
+** _ __ ___ ___ __| | ___ ___| | mod_ssl
+** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
+** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
+** |_____|
+** ssl_util_table.h
+** High Performance Hash Table Header
+*/
+
+/* ====================================================================
+ * Copyright (c) 1999-2001 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * 4. The names "mod_ssl" must not be used to endorse or promote
+ * products derived from this software without prior written
+ * permission. For written permission, please contact
+ * rse@engelschall.com.
+ *
+ * 5. Products derived from this software may not be called "mod_ssl"
+ * nor may "mod_ssl" appear in their names without prior
+ * written permission of Ralf S. Engelschall.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse@engelschall.com> for use in the
+ * mod_ssl project (http://www.modssl.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/*
+ * 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)(size_t size), void *(*calloc_f)(size_t number, size_t size), void *(*realloc_f)(void *ptr, size_t size), void (*free_f)(void *ptr));
+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_t *table_read(const char *path, int *error_p, void *(*malloc_f)(size_t size), void *(*calloc_f)(size_t number, size_t size), void *(*realloc_f)(void *ptr, size_t size), void (*free_f)(void *ptr));
+extern int table_write(const table_t *table_p, const char *path, const int mode);
+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 */