diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 06:33:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 06:33:50 +0000 |
commit | fe39ffb8b90ae4e002ed73fe98617cd590abb467 (patch) | |
tree | b80e5956907d8aeaaffe4e4f0c068c0e6157ce8b /support | |
parent | Initial commit. (diff) | |
download | apache2-fe39ffb8b90ae4e002ed73fe98617cd590abb467.tar.xz apache2-fe39ffb8b90ae4e002ed73fe98617cd590abb467.zip |
Adding upstream version 2.4.56.upstream/2.4.56
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'support')
88 files changed, 21202 insertions, 0 deletions
diff --git a/support/.indent.pro b/support/.indent.pro new file mode 100644 index 0000000..a9fbe9f --- /dev/null +++ b/support/.indent.pro @@ -0,0 +1,54 @@ +-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 +-TBUFF +-TFILE +-TTRANS +-TUINT4 +-T_trans +-Tallow_options_t +-Tapache_sfio +-Tarray_header +-Tbool_int +-Tbuf_area +-Tbuff_struct +-Tbuffy +-Tcmd_how +-Tcmd_parms +-Tcommand_rec +-Tcommand_struct +-Tconn_rec +-Tcore_dir_config +-Tcore_server_config +-Tdir_maker_func +-Tevent +-Tglobals_s +-Thandler_func +-Thandler_rec +-Tjoblist_s +-Tlisten_rec +-Tmerger_func +-Tmode_t +-Tmodule +-Tmodule_struct +-Tmutex +-Tn_long +-Tother_child_rec +-Toverrides_t +-Tparent_score +-Tpid_t +-Tpiped_log +-Tpool +-Trequest_rec +-Trequire_line +-Trlim_t +-Tscoreboard +-Tsemaphore +-Tserver_addr_rec +-Tserver_rec +-Tserver_rec_chain +-Tshort_score +-Ttable +-Ttable_entry +-Tthread +-Tu_wide_int +-Tvtime_t +-Twide_int diff --git a/support/Makefile.in b/support/Makefile.in new file mode 100644 index 0000000..c7d7687 --- /dev/null +++ b/support/Makefile.in @@ -0,0 +1,89 @@ +DISTCLEAN_TARGETS = apxs apachectl dbmmanage log_server_status \ + logresolve.pl phf_abuse_log.cgi split-logfile envvars-std + +CLEAN_TARGETS = suexec + +bin_PROGRAMS = htpasswd htdigest htdbm ab logresolve httxt2dbm +sbin_PROGRAMS = htcacheclean rotatelogs $(NONPORTABLE_SUPPORT) +TARGETS = $(bin_PROGRAMS) $(sbin_PROGRAMS) + +PROGRAM_LDADD = $(UTIL_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(EXTRA_LIBS) $(AP_LIBS) +PROGRAM_DEPENDENCIES = + +include $(top_builddir)/build/rules.mk + +install: + @test -d $(DESTDIR)$(bindir) || $(MKINSTALLDIRS) $(DESTDIR)$(bindir) + @test -d $(DESTDIR)$(sbindir) || $(MKINSTALLDIRS) $(DESTDIR)$(sbindir) + @test -d $(DESTDIR)$(libexecdir) || $(MKINSTALLDIRS) $(DESTDIR)$(libexecdir) + @cp -p $(top_builddir)/server/httpd.exp $(DESTDIR)$(libexecdir) + @for i in apxs dbmmanage; do \ + if test -f "$(builddir)/$$i"; then \ + cp -p $$i $(DESTDIR)$(bindir); \ + chmod 755 $(DESTDIR)$(bindir)/$$i; \ + fi ; \ + done + @for i in apachectl; do \ + if test -f "$(builddir)/$$i"; then \ + cp -p $$i $(DESTDIR)$(sbindir); \ + chmod 755 $(DESTDIR)$(sbindir)/$$i; \ + fi ; \ + done + @if test -f "$(builddir)/envvars-std"; then \ + cp -p envvars-std $(DESTDIR)$(sbindir); \ + if test ! -f $(DESTDIR)$(sbindir)/envvars; then \ + cp -p envvars-std $(DESTDIR)$(sbindir)/envvars ; \ + fi ; \ + fi + +htpasswd.lo: passwd_common.h +passwd_common.lo: passwd_common.h +htpasswd_OBJECTS = htpasswd.lo passwd_common.lo +htpasswd: $(htpasswd_OBJECTS) + $(LINK) $(htpasswd_LTFLAGS) $(htpasswd_OBJECTS) $(PROGRAM_LDADD) $(CRYPT_LIBS) + +htdigest_OBJECTS = htdigest.lo +htdigest: $(htdigest_OBJECTS) + $(LINK) $(htdigest_LTFLAGS) $(htdigest_OBJECTS) $(PROGRAM_LDADD) + +rotatelogs_OBJECTS = rotatelogs.lo +rotatelogs: $(rotatelogs_OBJECTS) + $(LINK) $(rotatelogs_LTFLAGS) $(rotatelogs_OBJECTS) $(PROGRAM_LDADD) + +logresolve_OBJECTS = logresolve.lo +logresolve: $(logresolve_OBJECTS) + $(LINK) $(logresolve_LTFLAGS) $(logresolve_OBJECTS) $(PROGRAM_LDADD) + +htdbm.lo: passwd_common.h +htdbm_OBJECTS = htdbm.lo passwd_common.lo +htdbm: $(htdbm_OBJECTS) + $(LINK) $(htdbm_LTFLAGS) $(htdbm_OBJECTS) $(PROGRAM_LDADD) $(CRYPT_LIBS) + +ab_OBJECTS = ab.lo +ab_LDADD = $(PROGRAM_LDADD) $(MATH_LIBS) $(ab_LIBS) +ab.lo: ab.c + $(LIBTOOL) --mode=compile $(CC) $(ab_CFLAGS) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(ALL_INCLUDES) $(PICFLAGS) $(LTCFLAGS) -c $< && touch $@ +ab: $(ab_OBJECTS) + $(LIBTOOL) --mode=link $(CC) $(ALL_CFLAGS) $(PILDFLAGS) \ + $(LT_LDFLAGS) $(ALL_LDFLAGS) -o $@ $(ab_LTFLAGS) $(ab_OBJECTS) $(ab_LDADD) + +checkgid_OBJECTS = checkgid.lo +checkgid: $(checkgid_OBJECTS) + $(LINK) $(checkgid_LTFLAGS) $(checkgid_OBJECTS) $(PROGRAM_LDADD) + +suexec_OBJECTS = suexec.lo +suexec: $(suexec_OBJECTS) + $(LINK) $(suexec_OBJECTS) + +htcacheclean_OBJECTS = htcacheclean.lo +htcacheclean: $(htcacheclean_OBJECTS) + $(LINK) $(htcacheclean_LTFLAGS) $(htcacheclean_OBJECTS) $(PROGRAM_LDADD) + +httxt2dbm_OBJECTS = httxt2dbm.lo +httxt2dbm: $(httxt2dbm_OBJECTS) + $(LINK) $(httxt2dbm_LTFLAGS) $(httxt2dbm_OBJECTS) $(PROGRAM_LDADD) + +fcgistarter_OBJECTS = fcgistarter.lo +fcgistarter: $(fcgistarter_OBJECTS) + $(LINK) $(fcgistarter_LTFLAGS) $(fcgistarter_OBJECTS) $(PROGRAM_LDADD) diff --git a/support/NWGNUab b/support/NWGNUab new file mode 100644 index 0000000..c22b6c1 --- /dev/null +++ b/support/NWGNUab @@ -0,0 +1,330 @@ +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(AP_WORK)/build/NWGNUhead.inc +endif + +# +# build this level's files +# +# Make sure all needed macro's are defined +# + +ifeq "$(WITH_ABS)" "1" + +ifeq "$(USE_NTLS)" "1" +SSL_INC = $(NTLSSDK)/inc +SSL_LIB = $(NTLSSDK)/imp +SSL_BIN = $(NTLSSDK)/bin +SSL_APP = $(NTLSSDK)/apps +ifneq "$(wildcard $(SSL_INC)/openssl/opensslv.h)" "$(SSL_INC)/openssl/opensslv.h" +$(warning '$(NTLSSDK)' does NOT point to a valid NTLS SDK!) +endif +else +SSL_INC = $(OSSLSDK)/outinc_nw_libc +SSL_LIB = $(OSSLSDK)/out_nw_libc +SSL_BIN = $(OSSLSDK)/out_nw_libc +SSL_APP = $(OSSLSDK)/apps +ifneq "$(wildcard $(SSL_INC)/openssl/opensslv.h)" "$(SSL_INC)/openssl/opensslv.h" +$(warning '$(OSSLSDK)' does NOT point to a valid OpenSSL SDK!) +endif +endif +ifeq "$(wildcard $(SSL_INC)/openssl/opensslv.h)" "$(SSL_INC)/openssl/opensslv.h" +HAVE_OPENSSL = 1 +endif + +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +ifdef HAVE_OPENSSL +XINCDIRS += \ + $(SSL_INC) \ + $(SSL_INC)/openssl \ + $(EOLIST) +endif + +XINCDIRS += \ + $(NWOS) \ + $(AP_WORK)/include \ + $(APR)/include \ + $(APRUTIL)/include \ + $(APR)/misc/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +ifdef HAVE_OPENSSL +XDEFINES += \ + -DHAVE_OPENSSL \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + -l $(SSL_LIB) \ + $(EOLIST) +endif + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +ifdef HAVE_OPENSSL +NLM_NAME = abs +else +NLM_NAME = ab +endif + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) Benchmark Utility for NetWare + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = $(NLM_NAME) + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +#NLM_SCREEN_NAME = Apache Bench +NLM_SCREEN_NAME = DEFAULT + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 65536 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/$(NLM_NAME).nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/ab.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +ifdef HAVE_OPENSSL +ifneq "$(USE_NTLS)" "1" +FILES_nlm_libs += \ + $(SSL_LIB)/crypto.lib \ + $(SSL_LIB)/ssl.lib \ + $(EOLIST) +endif +endif + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +ifdef HAVE_OPENSSL +ifeq "$(USE_NTLS)" "1" +FILES_nlm_modules += ntls \ + $(EOLIST) +endif +endif + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @libc.imp \ + $(EOLIST) + +# Don't link with Winsock if standard sockets are being used +ifneq "$(USE_STDSOCKETS)" "1" +FILES_nlm_Ximports += @ws2nlm.imp \ + $(EOLIST) +endif + +ifdef HAVE_OPENSSL +ifeq "$(USE_NTLS)" "1" +FILES_nlm_Ximports += @ntls.imp \ + $(EOLIST) +else +FILES_nlm_Ximports += \ + GetProcessSwitchCount \ + RunningProcess \ + GetSuperHighResolutionTimer \ + $(EOLIST) +endif +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(AP_WORK)/build/NWGNUtail.inc + diff --git a/support/NWGNUhtcacheclean b/support/NWGNUhtcacheclean new file mode 100644 index 0000000..f813527 --- /dev/null +++ b/support/NWGNUhtcacheclean @@ -0,0 +1,253 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(AP_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(STDMOD)/cache \ + $(APR)/include \ + $(APRUTIL)/include \ + $(AP_WORK)/include \ + $(APR)/misc/netware \ + $(NWOS) \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = htcacheclean + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) HT Disk Cache Cleanup Utility for NetWare + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = htcacheclean + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = DEFAULT + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 8192 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/htcacheclean.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/htcacheclean.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + diff --git a/support/NWGNUhtdbm b/support/NWGNUhtdbm new file mode 100644 index 0000000..5a2f739 --- /dev/null +++ b/support/NWGNUhtdbm @@ -0,0 +1,252 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(AP_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(NWOS) \ + $(APR)/include \ + $(APRUTIL)/include \ + $(APR)/misc/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = htdbm + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) HT Database Management Utility for NetWare + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = htdbm + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = htdbm Password Management + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 8192 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/htdbm.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/htdbm.o \ + $(OBJDIR)/passwd_common.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + diff --git a/support/NWGNUhtdigest b/support/NWGNUhtdigest new file mode 100644 index 0000000..fa5abc1 --- /dev/null +++ b/support/NWGNUhtdigest @@ -0,0 +1,251 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(AP_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(NWOS) \ + $(APR)/include \ + $(APRUTIL)/include \ + $(APR)/misc/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = htdigest + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) HT Digest Utility for NetWare + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = htdigest + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = Digest Password Management + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 8192 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/htdigest.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/htdigest.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + diff --git a/support/NWGNUhtpasswd b/support/NWGNUhtpasswd new file mode 100644 index 0000000..124895b --- /dev/null +++ b/support/NWGNUhtpasswd @@ -0,0 +1,252 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(AP_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(NWOS) \ + $(APR)/include \ + $(APRUTIL)/include \ + $(APR)/misc/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = htpasswd + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) HT Password Utility for NetWare + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = htpasswd + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = htpasswd Password Management + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 8192 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/htpasswd.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/htpasswd.o \ + $(OBJDIR)/passwd_common.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + diff --git a/support/NWGNUhttxt2dbm b/support/NWGNUhttxt2dbm new file mode 100644 index 0000000..c33532d --- /dev/null +++ b/support/NWGNUhttxt2dbm @@ -0,0 +1,251 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(AP_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(NWOS) \ + $(APR)/include \ + $(APRUTIL)/include \ + $(APR)/misc/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = httxt2dbm + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) HT Text to DBM Conversion Utility for NetWare + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = httxt2dbm + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = httxt2dbm Conversion Utility + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 8192 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/httxt2dbm.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/httxt2dbm.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + diff --git a/support/NWGNUlogres b/support/NWGNUlogres new file mode 100644 index 0000000..33ccfe0 --- /dev/null +++ b/support/NWGNUlogres @@ -0,0 +1,258 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(AP_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(NWOS) \ + $(AP_WORK)/include \ + $(APR)/include \ + $(APRUTIL)/include \ + $(APR)/misc/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = logres + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) Logresolve Utility for NetWare + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = logres + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = Log Resolve + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 65536 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/logres.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/logresolve.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @libc.imp \ + $(EOLIST) + +# Don't link with Winsock if standard sockets are being used +ifndef USE_STDSOCKETS +FILES_nlm_Ximports += @ws2nlm.imp \ + $(EOLIST) +endif + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + diff --git a/support/NWGNUmakefile b/support/NWGNUmakefile new file mode 100644 index 0000000..9cb5d1d --- /dev/null +++ b/support/NWGNUmakefile @@ -0,0 +1,51 @@ +# +# Get the 'head' of the build environment. This includes default targets and +# paths to tools +# + +include $(AP_WORK)/build/NWGNUhead.inc + +# +# build this level's files + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/ab.nlm \ + $(OBJDIR)/htpasswd.nlm \ + $(OBJDIR)/htdigest.nlm \ + $(OBJDIR)/htdbm.nlm \ + $(OBJDIR)/htcacheclean.nlm \ + $(OBJDIR)/httxt2dbm.nlm \ + $(OBJDIR)/logres.nlm \ + $(OBJDIR)/rotlogs.nlm \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + $(call COPY,$(OBJDIR)/*.nlm, $(INSTALLBASE)/bin/) + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + + diff --git a/support/NWGNUrotlogs b/support/NWGNUrotlogs new file mode 100644 index 0000000..fb9e3ae --- /dev/null +++ b/support/NWGNUrotlogs @@ -0,0 +1,250 @@ +# +# Make sure all needed macro's are defined +# + +# +# Get the 'head' of the build environment if necessary. This includes default +# targets and paths to tools +# + +ifndef EnvironmentDefined +include $(AP_WORK)/build/NWGNUhead.inc +endif + +# +# These directories will be at the beginning of the include list, followed by +# INCDIRS +# +XINCDIRS += \ + $(NWOS) \ + $(APR)/include \ + $(APR)/misc/netware \ + $(EOLIST) + +# +# These flags will come after CFLAGS +# +XCFLAGS += \ + $(EOLIST) + +# +# These defines will come after DEFINES +# +XDEFINES += \ + $(EOLIST) + +# +# These flags will be added to the link.opt file +# +XLFLAGS += \ + $(EOLIST) + +# +# These values will be appended to the correct variables based on the value of +# RELEASE +# +ifeq "$(RELEASE)" "debug" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "noopt" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +ifeq "$(RELEASE)" "release" +XINCDIRS += \ + $(EOLIST) + +XCFLAGS += \ + $(EOLIST) + +XDEFINES += \ + $(EOLIST) + +XLFLAGS += \ + $(EOLIST) +endif + +# +# These are used by the link target if an NLM is being generated +# This is used by the link 'name' directive to name the nlm. If left blank +# TARGET_nlm (see below) will be used. +# +NLM_NAME = rotlogs + +# +# This is used by the link '-desc ' directive. +# If left blank, NLM_NAME will be used. +# +NLM_DESCRIPTION = Apache $(VERSION_STR) Log Rotation Utility for NetWare + +# +# This is used by the '-threadname' directive. If left blank, +# NLM_NAME Thread will be used. +# +NLM_THREAD_NAME = rotlogs + +# +# This is used by the '-screenname' directive. If left blank, +# 'Apache for NetWare' Thread will be used. +# +NLM_SCREEN_NAME = DEFAULT + +# +# If this is specified, it will override VERSION value in +# $(AP_WORK)/build/NWGNUenvironment.inc +# +NLM_VERSION = + +# +# If this is specified, it will override the default of 64K +# +NLM_STACK_SIZE = 98304 + + +# +# If this is specified it will be used by the link '-entry' directive +# +NLM_ENTRY_SYM = + +# +# If this is specified it will be used by the link '-exit' directive +# +NLM_EXIT_SYM = + +# +# If this is specified it will be used by the link '-check' directive +# +NLM_CHECK_SYM = + +# +# If these are specified it will be used by the link '-flags' directive +# +NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION, MULTIPLE + +# +# If this is specified it will be linked in with the XDCData option in the def +# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled +# by setting APACHE_UNIPROC in the environment +# +XDCDATA = + +# +# If there is an NLM target, put it here +# +TARGET_nlm = \ + $(OBJDIR)/rotlogs.nlm \ + $(EOLIST) + +# +# If there is an LIB target, put it here +# +TARGET_lib = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the NLM target above. +# Paths must all use the '/' character +# +FILES_nlm_objs = \ + $(OBJDIR)/rotatelogs.o \ + $(EOLIST) + +# +# These are the LIB files needed to create the NLM target above. +# These will be added as a library command in the link.opt file. +# +FILES_nlm_libs = \ + $(PRELUDE) \ + $(EOLIST) + +# +# These are the modules that the above NLM target depends on to load. +# These will be added as a module command in the link.opt file. +# +FILES_nlm_modules = \ + aprlib \ + libc \ + $(EOLIST) + +# +# If the nlm has a msg file, put it's path here +# +FILE_nlm_msg = + +# +# If the nlm has a hlp file put it's path here +# +FILE_nlm_hlp = + +# +# If this is specified, it will override $(NWOS)\copyright.txt. +# +FILE_nlm_copyright = + +# +# Any additional imports go here +# +FILES_nlm_Ximports = \ + @aprlib.imp \ + @libc.imp \ + $(EOLIST) + +# +# Any symbols exported to here +# +FILES_nlm_exports = \ + $(EOLIST) + +# +# These are the OBJ files needed to create the LIB target above. +# Paths must all use the '/' character +# +FILES_lib_objs = \ + $(EOLIST) + +# +# implement targets and dependancies (leave this section alone) +# + +libs :: $(OBJDIR) $(TARGET_lib) + +nlms :: libs $(TARGET_nlm) + +# +# Updated this target to create necessary directories and copy files to the +# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples) +# +install :: nlms FORCE + +# +# Any specialized rules here +# + +# +# Include the 'tail' makefile that has targets that depend on variables defined +# in this makefile +# + +include $(APBUILD)/NWGNUtail.inc + diff --git a/support/README b/support/README new file mode 100644 index 0000000..09dadb2 --- /dev/null +++ b/support/README @@ -0,0 +1,65 @@ +Support files: + +ab + ABuse your server with this benchmarker. Rudimentary + command line testing tool. + +apachectl + Apache run-time Control script. To facilitate the + administrator and/or your rc.d scripts to control the + functioning of the Apache httpd daemon. + +apxs + APache eXtenSion tool. Eases building and installing + DSO style modules. + +dbmmanage + Create and update user authentication files in the faster + DBM format used by mod_auth_db. + +htcacheclean + Keep the size of mod_cache_disk store within a certain limit. + +htdigest + Create and update user authentication files used in + DIGEST authentification. See mod_auth_digest. + +htpasswd + Create and update user authentication files used in + BASIC authentification. I.e. the htpasswd files. + See mod_auth. + +httpd.8 + General apache man page. + +log_server_status + This script is designed to be run at a frequent interval by something + like cron. It connects to the server and downloads the status + information. It reformats the information to a single line and logs + it to a file. + +logresolve + resolve hostnames for IP-adresses in Apache logfiles + +phf_abuse_log.cgi + This script can be used to detect people trying to abuse an ancient + and long plugged security hole which existed in a CGI script distributed + with Apache 1.0.3 and earlier versions. + +rotatelogs + rotate Apache logs without having to kill the server. + +split-logfile + This script will take a combined virtual hosts access + log file and break its contents into separate files. + +suexec + Switch User For Exec. Used internally by apache, + see the document `Apache suEXEC Support' + under http://www.apache.org/docs/suexec.html . + +SHA1 + This directory includes some utilities to allow Apache 1.3.6 to + recognize passwords in SHA1 format, as used by Netscape web + servers. It is not installed by default. + diff --git a/support/SHA1/README.sha1 b/support/SHA1/README.sha1 new file mode 100644 index 0000000..3998e1f --- /dev/null +++ b/support/SHA1/README.sha1 @@ -0,0 +1,34 @@ +This directory includes some utilities to allow Apache 1.3.6 to +recognize passwords in SHA1 format, as used by Netscape web servers. + +From Netscape's admin interface, export the password database to an +ldif file and then use convert.pl in this distribution to generate +apache style password files. + +Note: SHA1 support is useful for migration purposes, but is less + secure than Apache's password format, since Apache's (MD5) + password format uses a random eight character salt to generate + one of many possible hashes for the same password. Netscape + uses plain SHA1 without a salt, so the same password + will always generate the same hash, making it easier + to break since the search space is smaller. + +This code was contributed by Clinton Wong <clintdw@netcom.com>. + +README.sha1 + this file + +convert-sha1.pl + takes an ldif dump from Netscape's web server on + standard in, outputs apache htpasswd format on standard out. + + Usage: convert.pl < ldif > passwords + +htpasswd-sha1.pl + perl script to generate entries in apache htpasswd format. + + Usage: htpasswd-sha1.pl some_user some_password + +ldif-sha1.example + sample ldif dump with one sha1 password and one crypt password. + diff --git a/support/SHA1/convert-sha1.pl b/support/SHA1/convert-sha1.pl new file mode 100644 index 0000000..3522802 --- /dev/null +++ b/support/SHA1/convert-sha1.pl @@ -0,0 +1,36 @@ +#!/usr/bin/perl -w +use strict; + +# This is public domain code. Do whatever you want with it. +# It was originally included in Clinton Wong's Apache 1.3.6 SHA1/ldif +# patch distribution as sample code for converting accounts from +# ldif format (as used by Netscape web servers) to Apache password format. + +my $uid=''; +my $passwd=''; + +while (my $line = <>) { + chomp $line; + if ( $line =~ /uid:\s*(.+)/) { $uid = $1 } + if ( $line =~ /userpassword:\s*(\{\w+\}.+)/) { + $passwd = $1; + $passwd =~ s/^\{crypt\}//i; # Apache stores crypt without a magic string + } + + if (length($line)==0) { + + if (length $uid and length $passwd) { + print $uid, ':', $passwd, "\n"; + } # output if we have something to print + + $uid = ''; + $passwd = ''; + + } # if newline +} # while something to read + +# handle last entry if there isn't a newline before EOF + if (length $uid and length $passwd) { + print $uid, ':', $passwd, "\n"; +} + diff --git a/support/SHA1/htpasswd-sha1.pl b/support/SHA1/htpasswd-sha1.pl new file mode 100644 index 0000000..a9dad11 --- /dev/null +++ b/support/SHA1/htpasswd-sha1.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w +use strict; +# +# Utility which takes a username and password +# on the command line and generates a username +# sha1-encrytped password on the stdout. +# +# Typical usage: +# ./htpasswd-sha1.pl dirkx MySecret >> sha1-passwd +# +# This is public domain code. Do whatever you want with it. +# It was originally included in Clinton Wong's Apache 1.3.6 SHA1/ldif +# patch distribution as sample code for generating entries for +# Apache password files using SHA1. + +use MIME::Base64; # http://www.cpan.org/modules/by-module/MIME/ +use Digest::SHA1; # http://www.cpan.org/modules/by-module/MD5/ + +if ($#ARGV!=1) { die "Usage $0: user password\n" } + +print $ARGV[0], ':{SHA}', encode_base64( Digest::SHA1::sha1($ARGV[1]) ); + diff --git a/support/SHA1/ldif-sha1.example b/support/SHA1/ldif-sha1.example new file mode 100644 index 0000000..b8fe917 --- /dev/null +++ b/support/SHA1/ldif-sha1.example @@ -0,0 +1,19 @@ +dn: cn=someuser +cn: someuser +sn: someuser +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: someuser +userpassword: {SHA}GvF+c3IdvgxAARuC7Uuxp9vjzik= + +dn: cn=anotheruser +cn: anotheruser +sn: anotheruser +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: anotheruser +userpassword: {crypt}eFnp.4sz5XnH6 diff --git a/support/ab.c b/support/ab.c new file mode 100644 index 0000000..3aa2660 --- /dev/null +++ b/support/ab.c @@ -0,0 +1,2719 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + ** This program is based on ZeusBench V1.0 written by Adam Twiss + ** which is Copyright (c) 1996 by Zeus Technology Ltd. http://www.zeustech.net/ + ** + ** This software is provided "as is" and any express or implied warranties, + ** including but not limited to, the implied warranties of merchantability and + ** fitness for a particular purpose are disclaimed. In no event shall + ** Zeus Technology Ltd. be liable for any direct, indirect, incidental, special, + ** exemplary, or consequential damaged (including, but not limited to, + ** procurement of substitute good or services; loss of use, data, or profits; + ** or business interruption) however caused and on 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. + ** + */ + +/* + ** HISTORY: + ** - Originally written by Adam Twiss <adam@zeus.co.uk>, March 1996 + ** with input from Mike Belshe <mbelshe@netscape.com> and + ** Michael Campanella <campanella@stevms.enet.dec.com> + ** - Enhanced by Dean Gaudet <dgaudet@apache.org>, November 1997 + ** - Cleaned up by Ralf S. Engelschall <rse@apache.org>, March 1998 + ** - POST and verbosity by Kurt Sussman <kls@merlot.com>, August 1998 + ** - HTML table output added by David N. Welton <davidw@prosa.it>, January 1999 + ** - Added Cookie, Arbitrary header and auth support. <dirkx@webweaving.org>, April 1999 + ** Version 1.3d + ** - Increased version number - as some of the socket/error handling has + ** fundamentally changed - and will give fundamentally different results + ** in situations where a server is dropping requests. Therefore you can + ** no longer compare results of AB as easily. Hence the inc of the version. + ** They should be closer to the truth though. Sander & <dirkx@covalent.net>, End 2000. + ** - Fixed proxy functionality, added median/mean statistics, added gnuplot + ** output option, added _experimental/rudimentary_ SSL support. Added + ** confidence guestimators and warnings. Sander & <dirkx@covalent.net>, End 2000 + ** - Fixed serious int overflow issues which would cause realistic (longer + ** than a few minutes) run's to have wrong (but believable) results. Added + ** trapping of connection errors which influenced measurements. + ** Contributed by Sander Temme, Early 2001 + ** Version 1.3e + ** - Changed timeout behavior during write to work whilst the sockets + ** are filling up and apr_write() does writes a few - but not all. + ** This will potentially change results. <dirkx@webweaving.org>, April 2001 + ** Version 2.0.36-dev + ** Improvements to concurrent processing: + ** - Enabled non-blocking connect()s. + ** - Prevent blocking calls to apr_socket_recv() (thereby allowing AB to + ** manage its entire set of socket descriptors). + ** - Any error returned from apr_socket_recv() that is not EAGAIN or EOF + ** is now treated as fatal. + ** Contributed by Aaron Bannert, April 24, 2002 + ** + ** Version 2.0.36-2 + ** Internalized the version string - this string is part + ** of the Agent: header and the result output. + ** + ** Version 2.0.37-dev + ** Adopted SSL code by Madhu Mathihalli <madhusudan_mathihalli@hp.com> + ** [PATCH] ab with SSL support Posted Wed, 15 Aug 2001 20:55:06 GMT + ** Introduces four 'if (int == value)' tests per non-ssl request. + ** + ** Version 2.0.40-dev + ** Switched to the new abstract pollset API, allowing ab to + ** take advantage of future apr_pollset_t scalability improvements. + ** Contributed by Brian Pane, August 31, 2002 + ** + ** Version 2.3 + ** SIGINT now triggers output_results(). + ** Contributed by colm, March 30, 2006 + **/ + +/* Note: this version string should start with \d+[\d\.]* and be a valid + * string for an HTTP Agent: header when prefixed with 'ApacheBench/'. + * It should reflect the version of AB - and not that of the apache server + * it happens to accompany. And it should be updated or changed whenever + * the results are no longer fundamentally comparable to the results of + * a previous version of ab. Either due to a change in the logic of + * ab - or to due to a change in the distribution it is compiled with + * (such as an APR change in for example blocking). + */ +#define AP_AB_BASEREVISION "2.3" + +/* + * BUGS: + * + * - uses strcpy/etc. + * - has various other poor buffer attacks related to the lazy parsing of + * response headers from the server + * - doesn't implement much of HTTP/1.x, only accepts certain forms of + * responses + * - (performance problem) heavy use of strstr shows up top in profile + * only an issue for loopback usage + */ + +/* -------------------------------------------------------------------- */ + +#if 'A' != 0x41 +/* Hmmm... This source code isn't being compiled in ASCII. + * In order for data that flows over the network to make + * sense, we need to translate to/from ASCII. + */ +#define NOT_ASCII +#endif + +/* affects include files on Solaris */ +#define BSD_COMP + +#include "apr.h" +#include "apr_signal.h" +#include "apr_strings.h" +#include "apr_network_io.h" +#include "apr_file_io.h" +#include "apr_time.h" +#include "apr_getopt.h" +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_portable.h" +#include "ap_release.h" +#include "apr_poll.h" + +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#include "apr_base64.h" +#ifdef NOT_ASCII +#include "apr_xlate.h" +#endif +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* for getpid() */ +#endif + +#if !defined(WIN32) && !defined(NETWARE) +#include "ap_config_auto.h" +#endif + +#include <math.h> +#if APR_HAVE_CTYPE_H +#include <ctype.h> +#endif +#if APR_HAVE_LIMITS_H +#include <limits.h> +#endif + +#if defined(HAVE_OPENSSL) + +#include <openssl/rsa.h> +#include <openssl/crypto.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/ssl.h> +#include <openssl/rand.h> +#define USE_SSL + +#define SK_NUM(x) sk_X509_num(x) +#define SK_VALUE(x,y) sk_X509_value(x,y) +typedef STACK_OF(X509) X509_STACK_TYPE; + +#if defined(_MSC_VER) && !defined(LIBRESSL_VERSION_NUMBER) +/* The following logic ensures we correctly glue FILE* within one CRT used + * by the OpenSSL library build to another CRT used by the ab.exe build. + * This became especially problematic with Visual Studio 2015. + */ +#include <openssl/applink.c> +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x00909000) +#define AB_SSL_METHOD_CONST const +#else +#define AB_SSL_METHOD_CONST +#endif +#if (OPENSSL_VERSION_NUMBER >= 0x0090707f) +#define AB_SSL_CIPHER_CONST const +#else +#define AB_SSL_CIPHER_CONST +#endif +#ifdef SSL_OP_NO_TLSv1_2 +#define HAVE_TLSV1_X +#endif +#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_set_tlsext_host_name) +#define HAVE_TLSEXT +#endif + +#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2060000f +#define SSL_CTRL_SET_MIN_PROTO_VERSION 123 +#define SSL_CTRL_SET_MAX_PROTO_VERSION 124 +#define SSL_CTX_set_min_proto_version(ctx, version) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, version, NULL) +#define SSL_CTX_set_max_proto_version(ctx, version) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, NULL) +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#ifdef TLS1_3_VERSION +#define MAX_SSL_PROTO TLS1_3_VERSION +#else +#define MAX_SSL_PROTO TLS1_2_VERSION +#endif +#ifndef OPENSSL_NO_SSL3 +#define MIN_SSL_PROTO SSL3_VERSION +#else +#define MIN_SSL_PROTO TLS1_VERSION +#endif +#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ + +#endif /* HAVE_OPENSSL */ + +/* ------------------- DEFINITIONS -------------------------- */ + +#ifndef LLONG_MAX +#define AB_MAX APR_INT64_C(0x7fffffffffffffff) +#else +#define AB_MAX LLONG_MAX +#endif + +/* maximum number of requests on a time limited test */ +#define MAX_REQUESTS (INT_MAX > 50000 ? 50000 : INT_MAX) + +/* connection state + * don't add enums or rearrange or otherwise change values without + * visiting set_conn_state() + */ +typedef enum { + STATE_UNCONNECTED = 0, + STATE_CONNECTING, /* TCP connect initiated, but we don't + * know if it worked yet + */ + STATE_CONNECTED, /* we know TCP connect completed */ + STATE_READ +} connect_state_e; + +#define CBUFFSIZE (8192) + +struct connection { + apr_pool_t *ctx; + apr_socket_t *aprsock; + apr_pollfd_t pollfd; + int state; + apr_size_t read; /* amount of bytes read */ + apr_size_t bread; /* amount of body read */ + apr_size_t rwrite, rwrote; /* keep pointers in what we write - across + * EAGAINs */ + apr_size_t length; /* Content-Length value used for keep-alive */ + char cbuff[CBUFFSIZE]; /* a buffer to store server response header */ + int cbx; /* offset in cbuffer */ + int keepalive; /* non-zero if a keep-alive request */ + int gotheader; /* non-zero if we have the entire header in + * cbuff */ + apr_time_t start, /* Start of connection */ + connect, /* Connected, start writing */ + endwrite, /* Request written */ + beginread, /* First byte of input */ + done; /* Connection closed */ + + int socknum; +#ifdef USE_SSL + SSL *ssl; +#endif +}; + +struct data { + apr_time_t starttime; /* start time of connection */ + apr_interval_time_t waittime; /* between request and reading response */ + apr_interval_time_t ctime; /* time to connect */ + apr_interval_time_t time; /* time for connection */ +}; + +#define ap_min(a,b) (((a)<(b))?(a):(b)) +#define ap_max(a,b) (((a)>(b))?(a):(b)) +#define ap_round_ms(a) ((apr_time_t)((a) + 500)/1000) +#define ap_double_ms(a) ((double)(a)/1000.0) +#define MAX_CONCURRENCY 20000 + +/* --------------------- GLOBALS ---------------------------- */ + +int verbosity = 0; /* no verbosity by default */ +int recverrok = 0; /* ok to proceed after socket receive errors */ +enum {NO_METH = 0, GET, HEAD, PUT, POST, CUSTOM_METHOD} method = NO_METH; +const char *method_str[] = {"bug", "GET", "HEAD", "PUT", "POST", ""}; +int send_body = 0; /* non-zero if sending body with request */ +int requests = 1; /* Number of requests to make */ +int heartbeatres = 100; /* How often do we say we're alive */ +int concurrency = 1; /* Number of multiple requests to make */ +int percentile = 1; /* Show percentile served */ +int nolength = 0; /* Accept variable document length */ +int confidence = 1; /* Show confidence estimator and warnings */ +int tlimit = 0; /* time limit in secs */ +int keepalive = 0; /* try and do keepalive connections */ +int windowsize = 0; /* we use the OS default window size */ +char servername[1024]; /* name that server reports */ +char *hostname; /* host name from URL */ +const char *host_field; /* value of "Host:" header field */ +const char *path; /* path name */ +char *postdata; /* *buffer containing data from postfile */ +apr_size_t postlen = 0; /* length of data to be POSTed */ +char *content_type = NULL; /* content type to put in POST header */ +const char *cookie, /* optional cookie line */ + *auth, /* optional (basic/uuencoded) auhentication */ + *hdrs; /* optional arbitrary headers */ +apr_port_t port; /* port number */ +char *proxyhost = NULL; /* proxy host name */ +int proxyport = 0; /* proxy port */ +const char *connecthost; +const char *myhost; +apr_port_t connectport; +const char *gnuplot; /* GNUplot file */ +const char *csvperc; /* CSV Percentile file */ +const char *fullurl; +const char *colonhost; +int isproxy = 0; +apr_interval_time_t aprtimeout = apr_time_from_sec(30); /* timeout value */ + +/* overrides for ab-generated common headers */ +const char *opt_host; /* which optional "Host:" header specified, if any */ +int opt_useragent = 0; /* was an optional "User-Agent:" header specified? */ +int opt_accept = 0; /* was an optional "Accept:" header specified? */ + /* + * XXX - this is now a per read/write transact type of value + */ + +int use_html = 0; /* use html in the report */ +const char *tablestring; +const char *trstring; +const char *tdstring; + +apr_size_t doclen = 0; /* the length the document should be */ +apr_int64_t totalread = 0; /* total number of bytes read */ +apr_int64_t totalbread = 0; /* totoal amount of entity body read */ +apr_int64_t totalposted = 0; /* total number of bytes posted, inc. headers */ +int started = 0; /* number of requests started, so no excess */ +int done = 0; /* number of requests we have done */ +int doneka = 0; /* number of keep alive connections done */ +int good = 0, bad = 0; /* number of good and bad requests */ +int epipe = 0; /* number of broken pipe writes */ +int err_length = 0; /* requests failed due to response length */ +int err_conn = 0; /* requests failed due to connection drop */ +int err_recv = 0; /* requests failed due to broken read */ +int err_except = 0; /* requests failed due to exception */ +int err_response = 0; /* requests with invalid or non-200 response */ + +#ifdef USE_SSL +int is_ssl; +SSL_CTX *ssl_ctx; +char *ssl_cipher = NULL; +char *ssl_info = NULL; +char *ssl_cert = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +char *ssl_tmp_key = NULL; +#endif +BIO *bio_out,*bio_err; +#ifdef HAVE_TLSEXT +int tls_use_sni = 1; /* used by default, -I disables it */ +const char *tls_sni = NULL; /* 'opt_host' if any, 'hostname' otherwise */ +#endif +#endif + +apr_time_t start, lasttime, stoptime; + +/* global request (and its length) */ +char _request[8192]; +char *request = _request; +apr_size_t reqlen; +int requests_initialized = 0; + +/* one global throw-away buffer to read stuff into */ +char buffer[8192]; + +/* interesting percentiles */ +int percs[] = {50, 66, 75, 80, 90, 95, 98, 99, 100}; + +struct connection *con; /* connection array */ +struct data *stats; /* data for each request */ +apr_pool_t *cntxt; + +apr_pollset_t *readbits; + +apr_sockaddr_t *mysa; +apr_sockaddr_t *destsa; + +#ifdef NOT_ASCII +apr_xlate_t *from_ascii, *to_ascii; +#endif + +static void write_request(struct connection * c); +static void close_connection(struct connection * c); + +/* --------------------------------------------------------- */ + +/* simple little function to write an error string and exit */ + +static void err(const char *s) +{ + fprintf(stderr, "%s\n", s); + if (done) + printf("Total of %d requests completed\n" , done); + exit(1); +} + +/* simple little function to write an APR error string and exit */ + +static void apr_err(const char *s, apr_status_t rv) +{ + char buf[120]; + + fprintf(stderr, + "%s: %s (%d)\n", + s, apr_strerror(rv, buf, sizeof buf), rv); + if (done) + printf("Total of %d requests completed\n" , done); + exit(rv); +} + +static void *xmalloc(size_t size) +{ + void *ret = malloc(size); + if (ret == NULL) { + fprintf(stderr, "Could not allocate memory (%" + APR_SIZE_T_FMT" bytes)\n", size); + exit(1); + } + return ret; +} + +static void *xcalloc(size_t num, size_t size) +{ + void *ret = calloc(num, size); + if (ret == NULL) { + fprintf(stderr, "Could not allocate memory (%" + APR_SIZE_T_FMT" bytes)\n", size*num); + exit(1); + } + return ret; +} + +static char *xstrdup(const char *s) +{ + char *ret = strdup(s); + if (ret == NULL) { + fprintf(stderr, "Could not allocate memory (%" + APR_SIZE_T_FMT " bytes)\n", strlen(s)); + exit(1); + } + return ret; +} + +/* + * Similar to standard strstr() but we ignore case in this version. + * Copied from ap_strcasestr(). + */ +static char *xstrcasestr(const char *s1, const char *s2) +{ + char *p1, *p2; + if (*s2 == '\0') { + /* an empty s2 */ + return((char *)s1); + } + while(1) { + for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++); + if (*s1 == '\0') { + return(NULL); + } + /* found first character of s2, see if the rest matches */ + p1 = (char *)s1; + p2 = (char *)s2; + for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) { + if (*p1 == '\0') { + /* both strings ended together */ + return((char *)s1); + } + } + if (*p2 == '\0') { + /* second string ended, a match */ + break; + } + /* didn't find a match here, try starting at next character in s1 */ + s1++; + } + return((char *)s1); +} + +/* pool abort function */ +static int abort_on_oom(int retcode) +{ + fprintf(stderr, "Could not allocate memory\n"); + exit(1); + /* not reached */ + return retcode; +} + +static void set_polled_events(struct connection *c, apr_int16_t new_reqevents) +{ + apr_status_t rv; + + if (c->pollfd.reqevents != new_reqevents) { + if (c->pollfd.reqevents != 0) { + rv = apr_pollset_remove(readbits, &c->pollfd); + if (rv != APR_SUCCESS) { + apr_err("apr_pollset_remove()", rv); + } + } + + if (new_reqevents != 0) { + c->pollfd.reqevents = new_reqevents; + rv = apr_pollset_add(readbits, &c->pollfd); + if (rv != APR_SUCCESS) { + apr_err("apr_pollset_add()", rv); + } + } + } +} + +static void set_conn_state(struct connection *c, connect_state_e new_state) +{ + apr_int16_t events_by_state[] = { + 0, /* for STATE_UNCONNECTED */ + APR_POLLOUT, /* for STATE_CONNECTING */ + APR_POLLIN, /* for STATE_CONNECTED; we don't poll in this state, + * so prepare for polling in the following state -- + * STATE_READ + */ + APR_POLLIN /* for STATE_READ */ + }; + + c->state = new_state; + + set_polled_events(c, events_by_state[new_state]); +} + +/* --------------------------------------------------------- */ +/* write out request to a connection - assumes we can write + * (small) request out in one go into our new socket buffer + * + */ +#ifdef USE_SSL +static long ssl_print_cb(BIO *bio,int cmd,const char *argp,int argi,long argl,long ret) +{ + BIO *out; + + out=(BIO *)BIO_get_callback_arg(bio); + if (out == NULL) return(ret); + + if (cmd == (BIO_CB_READ|BIO_CB_RETURN)) { + BIO_printf(out,"read from %p [%p] (%d bytes => %ld (0x%lX))\n", + bio, argp, argi, ret, ret); + BIO_dump(out,(char *)argp,(int)ret); + return(ret); + } + else if (cmd == (BIO_CB_WRITE|BIO_CB_RETURN)) { + BIO_printf(out,"write to %p [%p] (%d bytes => %ld (0x%lX))\n", + bio, argp, argi, ret, ret); + BIO_dump(out,(char *)argp,(int)ret); + } + return ret; +} + +static void ssl_state_cb(const SSL *s, int w, int r) +{ + if (w & SSL_CB_ALERT) { + BIO_printf(bio_err, "SSL/TLS Alert [%s] %s:%s\n", + (w & SSL_CB_READ ? "read" : "write"), + SSL_alert_type_string_long(r), + SSL_alert_desc_string_long(r)); + } else if (w & SSL_CB_LOOP) { + BIO_printf(bio_err, "SSL/TLS State [%s] %s\n", + (SSL_in_connect_init((SSL*)s) ? "connect" : "-"), + SSL_state_string_long(s)); + } else if (w & (SSL_CB_HANDSHAKE_START|SSL_CB_HANDSHAKE_DONE)) { + BIO_printf(bio_err, "SSL/TLS Handshake [%s] %s\n", + (w & SSL_CB_HANDSHAKE_START ? "Start" : "Done"), + SSL_state_string_long(s)); + } +} + +#ifndef RAND_MAX +#define RAND_MAX INT_MAX +#endif + +static int ssl_rand_choosenum(int l, int h) +{ + int i; + char buf[50]; + + srand((unsigned int)time(NULL)); + apr_snprintf(buf, sizeof(buf), "%.0f", + (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l))); + i = atoi(buf)+1; + if (i < l) i = l; + if (i > h) i = h; + return i; +} + +static void ssl_rand_seed(void) +{ + int n, l; + time_t t; + pid_t pid; + unsigned char stackdata[256]; + + /* + * seed in the current time (usually just 4 bytes) + */ + t = time(NULL); + l = sizeof(time_t); + RAND_seed((unsigned char *)&t, l); + + /* + * seed in the current process id (usually just 4 bytes) + */ + pid = getpid(); + l = sizeof(pid_t); + RAND_seed((unsigned char *)&pid, 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); +} + +static int ssl_print_connection_info(BIO *bio, SSL *ssl) +{ + AB_SSL_CIPHER_CONST SSL_CIPHER *c; + int alg_bits,bits; + + BIO_printf(bio,"Transport Protocol :%s\n", SSL_get_version(ssl)); + + c = SSL_get_current_cipher(ssl); + BIO_printf(bio,"Cipher Suite Protocol :%s\n", SSL_CIPHER_get_version(c)); + BIO_printf(bio,"Cipher Suite Name :%s\n",SSL_CIPHER_get_name(c)); + + bits = SSL_CIPHER_get_bits(c,&alg_bits); + BIO_printf(bio,"Cipher Suite Cipher Bits:%d (%d)\n",bits,alg_bits); + + return(1); +} + +static void ssl_print_cert_info(BIO *bio, X509 *cert) +{ + X509_NAME *dn; + EVP_PKEY *pk; + char buf[1024]; + + BIO_printf(bio, "Certificate version: %ld\n", X509_get_version(cert)+1); + BIO_printf(bio,"Valid from: "); + ASN1_UTCTIME_print(bio, X509_get_notBefore(cert)); + BIO_printf(bio,"\n"); + + BIO_printf(bio,"Valid to : "); + ASN1_UTCTIME_print(bio, X509_get_notAfter(cert)); + BIO_printf(bio,"\n"); + + pk = X509_get_pubkey(cert); + BIO_printf(bio,"Public key is %d bits\n", + EVP_PKEY_bits(pk)); + EVP_PKEY_free(pk); + + dn = X509_get_issuer_name(cert); + X509_NAME_oneline(dn, buf, sizeof(buf)); + BIO_printf(bio,"The issuer name is %s\n", buf); + + dn=X509_get_subject_name(cert); + X509_NAME_oneline(dn, buf, sizeof(buf)); + BIO_printf(bio,"The subject name is %s\n", buf); + + /* dump the extension list too */ + BIO_printf(bio, "Extension Count: %d\n", X509_get_ext_count(cert)); +} + +static void ssl_print_info(struct connection *c) +{ + X509_STACK_TYPE *sk; + X509 *cert; + int count; + + BIO_printf(bio_err, "\n"); + sk = SSL_get_peer_cert_chain(c->ssl); + if ((count = SK_NUM(sk)) > 0) { + int i; + for (i=1; i<count; i++) { + cert = (X509 *)SK_VALUE(sk, i); + ssl_print_cert_info(bio_out, cert); + } + } + cert = SSL_get_peer_certificate(c->ssl); + if (cert == NULL) { + BIO_printf(bio_out, "Anon DH\n"); + } else { + BIO_printf(bio_out, "Peer certificate\n"); + ssl_print_cert_info(bio_out, cert); + X509_free(cert); + } + ssl_print_connection_info(bio_err,c->ssl); + SSL_SESSION_print(bio_err, SSL_get_session(c->ssl)); + } + +static void ssl_proceed_handshake(struct connection *c) +{ + int do_next = 1; + + while (do_next) { + int ret, ecode; + + ret = SSL_do_handshake(c->ssl); + ecode = SSL_get_error(c->ssl, ret); + + switch (ecode) { + case SSL_ERROR_NONE: + if (verbosity >= 2) + ssl_print_info(c); + if (ssl_info == NULL) { + AB_SSL_CIPHER_CONST SSL_CIPHER *ci; + X509 *cert; + int sk_bits, pk_bits, swork; + + ci = SSL_get_current_cipher(c->ssl); + sk_bits = SSL_CIPHER_get_bits(ci, &swork); + cert = SSL_get_peer_certificate(c->ssl); + if (cert) + pk_bits = EVP_PKEY_bits(X509_get_pubkey(cert)); + else + pk_bits = 0; /* Anon DH */ + + ssl_info = xmalloc(128); + apr_snprintf(ssl_info, 128, "%s,%s,%d,%d", + SSL_get_version(c->ssl), + SSL_CIPHER_get_name(ci), + pk_bits, sk_bits); + } +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (ssl_tmp_key == NULL) { + EVP_PKEY *key; + if (SSL_get_server_tmp_key(c->ssl, &key)) { + ssl_tmp_key = xmalloc(128); + switch (EVP_PKEY_id(key)) { + case EVP_PKEY_RSA: + apr_snprintf(ssl_tmp_key, 128, "RSA %d bits", + EVP_PKEY_bits(key)); + break; + case EVP_PKEY_DH: + apr_snprintf(ssl_tmp_key, 128, "DH %d bits", + EVP_PKEY_bits(key)); + break; +#ifndef OPENSSL_NO_EC + case EVP_PKEY_EC: { + const char *cname = NULL; + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); + int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); + EC_KEY_free(ec); + cname = EC_curve_nid2nist(nid); + if (!cname) + cname = OBJ_nid2sn(nid); + + apr_snprintf(ssl_tmp_key, 128, "ECDH %s %d bits", + cname, + EVP_PKEY_bits(key)); + break; + } +#endif + default: + apr_snprintf(ssl_tmp_key, 128, "%s %d bits", + OBJ_nid2sn(EVP_PKEY_id(key)), + EVP_PKEY_bits(key)); + break; + } + EVP_PKEY_free(key); + } + } +#endif + write_request(c); + do_next = 0; + break; + case SSL_ERROR_WANT_READ: + set_polled_events(c, APR_POLLIN); + do_next = 0; + break; + case SSL_ERROR_WANT_WRITE: + set_polled_events(c, APR_POLLOUT); + do_next = 0; + break; + case SSL_ERROR_WANT_CONNECT: + case SSL_ERROR_SSL: + case SSL_ERROR_SYSCALL: + /* Unexpected result */ + BIO_printf(bio_err, "SSL handshake failed (%d).\n", ecode); + ERR_print_errors(bio_err); + close_connection(c); + do_next = 0; + break; + } + } +} + +#endif /* USE_SSL */ + +static void write_request(struct connection * c) +{ + if (started >= requests) { + return; + } + + do { + apr_time_t tnow; + apr_size_t l = c->rwrite; + apr_status_t e = APR_SUCCESS; /* prevent gcc warning */ + + tnow = lasttime = apr_time_now(); + + /* + * First time round ? + */ + if (c->rwrite == 0) { + apr_socket_timeout_set(c->aprsock, 0); + c->connect = tnow; + c->rwrote = 0; + c->rwrite = reqlen; + if (send_body) + c->rwrite += postlen; + l = c->rwrite; + } + else if (tnow > c->connect + aprtimeout) { + printf("Send request timed out!\n"); + close_connection(c); + return; + } + +#ifdef USE_SSL + if (c->ssl) { + e = SSL_write(c->ssl, request + c->rwrote, l); + if (e <= 0) { + switch (SSL_get_error(c->ssl, e)) { + case SSL_ERROR_WANT_READ: + set_polled_events(c, APR_POLLIN); + break; + case SSL_ERROR_WANT_WRITE: + set_polled_events(c, APR_POLLOUT); + break; + default: + BIO_printf(bio_err, "SSL write failed - closing connection\n"); + ERR_print_errors(bio_err); + close_connection (c); + break; + } + return; + } + l = e; + } + else +#endif + { + e = apr_socket_send(c->aprsock, request + c->rwrote, &l); + if (e != APR_SUCCESS && !l) { + if (!APR_STATUS_IS_EAGAIN(e)) { + epipe++; + printf("Send request failed!\n"); + close_connection(c); + } + else { + set_polled_events(c, APR_POLLOUT); + } + return; + } + } + totalposted += l; + c->rwrote += l; + c->rwrite -= l; + } while (c->rwrite); + + c->endwrite = lasttime = apr_time_now(); + started++; + set_conn_state(c, STATE_READ); +} + +/* --------------------------------------------------------- */ + +/* calculate and output results */ + +static int compradre(struct data * a, struct data * b) +{ + if ((a->ctime) < (b->ctime)) + return -1; + if ((a->ctime) > (b->ctime)) + return +1; + return 0; +} + +static int comprando(struct data * a, struct data * b) +{ + if ((a->time) < (b->time)) + return -1; + if ((a->time) > (b->time)) + return +1; + return 0; +} + +static int compri(struct data * a, struct data * b) +{ + apr_interval_time_t p = a->time - a->ctime; + apr_interval_time_t q = b->time - b->ctime; + if (p < q) + return -1; + if (p > q) + return +1; + return 0; +} + +static int compwait(struct data * a, struct data * b) +{ + if ((a->waittime) < (b->waittime)) + return -1; + if ((a->waittime) > (b->waittime)) + return 1; + return 0; +} + +static void output_results(int sig) +{ + double timetaken; + + if (sig) { + lasttime = apr_time_now(); /* record final time if interrupted */ + } + timetaken = (double) (lasttime - start) / APR_USEC_PER_SEC; + + printf("\n\n"); + printf("Server Software: %s\n", servername); + printf("Server Hostname: %s\n", hostname); + printf("Server Port: %hu\n", port); +#ifdef USE_SSL + if (is_ssl && ssl_info) { + printf("SSL/TLS Protocol: %s\n", ssl_info); + } +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (is_ssl && ssl_tmp_key) { + printf("Server Temp Key: %s\n", ssl_tmp_key); + } +#endif +#ifdef HAVE_TLSEXT + if (is_ssl && tls_sni) { + printf("TLS Server Name: %s\n", tls_sni); + } +#endif +#endif + printf("\n"); + printf("Document Path: %s\n", path); + if (nolength) + printf("Document Length: Variable\n"); + else + printf("Document Length: %" APR_SIZE_T_FMT " bytes\n", doclen); + printf("\n"); + printf("Concurrency Level: %d\n", concurrency); + printf("Time taken for tests: %.3f seconds\n", timetaken); + printf("Complete requests: %d\n", done); + printf("Failed requests: %d\n", bad); + if (bad) + printf(" (Connect: %d, Receive: %d, Length: %d, Exceptions: %d)\n", + err_conn, err_recv, err_length, err_except); + if (epipe) + printf("Write errors: %d\n", epipe); + if (err_response) + printf("Non-2xx responses: %d\n", err_response); + if (keepalive) + printf("Keep-Alive requests: %d\n", doneka); + printf("Total transferred: %" APR_INT64_T_FMT " bytes\n", totalread); + if (send_body) + printf("Total body sent: %" APR_INT64_T_FMT "\n", + totalposted); + printf("HTML transferred: %" APR_INT64_T_FMT " bytes\n", totalbread); + + /* avoid divide by zero */ + if (timetaken && done) { + printf("Requests per second: %.2f [#/sec] (mean)\n", + (double) done / timetaken); + printf("Time per request: %.3f [ms] (mean)\n", + (double) concurrency * timetaken * 1000 / done); + printf("Time per request: %.3f [ms] (mean, across all concurrent requests)\n", + (double) timetaken * 1000 / done); + printf("Transfer rate: %.2f [Kbytes/sec] received\n", + (double) totalread / 1024 / timetaken); + if (send_body) { + printf(" %.2f kb/s sent\n", + (double) totalposted / 1024 / timetaken); + printf(" %.2f kb/s total\n", + (double) (totalread + totalposted) / 1024 / timetaken); + } + } + + if (done > 0) { + /* work out connection times */ + int i; + apr_time_t totalcon = 0, total = 0, totald = 0, totalwait = 0; + apr_time_t meancon, meantot, meand, meanwait; + apr_interval_time_t mincon = AB_MAX, mintot = AB_MAX, mind = AB_MAX, + minwait = AB_MAX; + apr_interval_time_t maxcon = 0, maxtot = 0, maxd = 0, maxwait = 0; + apr_interval_time_t mediancon = 0, mediantot = 0, mediand = 0, medianwait = 0; + double sdtot = 0, sdcon = 0, sdd = 0, sdwait = 0; + + for (i = 0; i < done; i++) { + struct data *s = &stats[i]; + mincon = ap_min(mincon, s->ctime); + mintot = ap_min(mintot, s->time); + mind = ap_min(mind, s->time - s->ctime); + minwait = ap_min(minwait, s->waittime); + + maxcon = ap_max(maxcon, s->ctime); + maxtot = ap_max(maxtot, s->time); + maxd = ap_max(maxd, s->time - s->ctime); + maxwait = ap_max(maxwait, s->waittime); + + totalcon += s->ctime; + total += s->time; + totald += s->time - s->ctime; + totalwait += s->waittime; + } + meancon = totalcon / done; + meantot = total / done; + meand = totald / done; + meanwait = totalwait / done; + + /* calculating the sample variance: the sum of the squared deviations, divided by n-1 */ + for (i = 0; i < done; i++) { + struct data *s = &stats[i]; + double a; + a = ((double)s->time - meantot); + sdtot += a * a; + a = ((double)s->ctime - meancon); + sdcon += a * a; + a = ((double)s->time - (double)s->ctime - meand); + sdd += a * a; + a = ((double)s->waittime - meanwait); + sdwait += a * a; + } + + sdtot = (done > 1) ? sqrt(sdtot / (done - 1)) : 0; + sdcon = (done > 1) ? sqrt(sdcon / (done - 1)) : 0; + sdd = (done > 1) ? sqrt(sdd / (done - 1)) : 0; + sdwait = (done > 1) ? sqrt(sdwait / (done - 1)) : 0; + + /* + * XXX: what is better; this hideous cast of the compradre function; or + * the four warnings during compile ? dirkx just does not know and + * hates both/ + */ + qsort(stats, done, sizeof(struct data), + (int (*) (const void *, const void *)) compradre); + if ((done > 1) && (done % 2)) + mediancon = (stats[done / 2].ctime + stats[done / 2 + 1].ctime) / 2; + else + mediancon = stats[done / 2].ctime; + + qsort(stats, done, sizeof(struct data), + (int (*) (const void *, const void *)) compri); + if ((done > 1) && (done % 2)) + mediand = (stats[done / 2].time + stats[done / 2 + 1].time \ + -stats[done / 2].ctime - stats[done / 2 + 1].ctime) / 2; + else + mediand = stats[done / 2].time - stats[done / 2].ctime; + + qsort(stats, done, sizeof(struct data), + (int (*) (const void *, const void *)) compwait); + if ((done > 1) && (done % 2)) + medianwait = (stats[done / 2].waittime + stats[done / 2 + 1].waittime) / 2; + else + medianwait = stats[done / 2].waittime; + + qsort(stats, done, sizeof(struct data), + (int (*) (const void *, const void *)) comprando); + if ((done > 1) && (done % 2)) + mediantot = (stats[done / 2].time + stats[done / 2 + 1].time) / 2; + else + mediantot = stats[done / 2].time; + + printf("\nConnection Times (ms)\n"); + /* + * Reduce stats from apr time to milliseconds + */ + mincon = ap_round_ms(mincon); + mind = ap_round_ms(mind); + minwait = ap_round_ms(minwait); + mintot = ap_round_ms(mintot); + meancon = ap_round_ms(meancon); + meand = ap_round_ms(meand); + meanwait = ap_round_ms(meanwait); + meantot = ap_round_ms(meantot); + mediancon = ap_round_ms(mediancon); + mediand = ap_round_ms(mediand); + medianwait = ap_round_ms(medianwait); + mediantot = ap_round_ms(mediantot); + maxcon = ap_round_ms(maxcon); + maxd = ap_round_ms(maxd); + maxwait = ap_round_ms(maxwait); + maxtot = ap_round_ms(maxtot); + sdcon = ap_double_ms(sdcon); + sdd = ap_double_ms(sdd); + sdwait = ap_double_ms(sdwait); + sdtot = ap_double_ms(sdtot); + + if (confidence) { +#define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %4" APR_TIME_T_FMT " %5.1f %6" APR_TIME_T_FMT " %7" APR_TIME_T_FMT "\n" + printf(" min mean[+/-sd] median max\n"); + printf("Connect: " CONF_FMT_STRING, + mincon, meancon, sdcon, mediancon, maxcon); + printf("Processing: " CONF_FMT_STRING, + mind, meand, sdd, mediand, maxd); + printf("Waiting: " CONF_FMT_STRING, + minwait, meanwait, sdwait, medianwait, maxwait); + printf("Total: " CONF_FMT_STRING, + mintot, meantot, sdtot, mediantot, maxtot); +#undef CONF_FMT_STRING + +#define SANE(what,mean,median,sd) \ + { \ + double d = (double)mean - median; \ + if (d < 0) d = -d; \ + if (d > 2 * sd ) \ + printf("ERROR: The median and mean for " what " are more than twice the standard\n" \ + " deviation apart. These results are NOT reliable.\n"); \ + else if (d > sd ) \ + printf("WARNING: The median and mean for " what " are not within a normal deviation\n" \ + " These results are probably not that reliable.\n"); \ + } + SANE("the initial connection time", meancon, mediancon, sdcon); + SANE("the processing time", meand, mediand, sdd); + SANE("the waiting time", meanwait, medianwait, sdwait); + SANE("the total time", meantot, mediantot, sdtot); + } + else { + printf(" min avg max\n"); +#define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %5" APR_TIME_T_FMT "%5" APR_TIME_T_FMT "\n" + printf("Connect: " CONF_FMT_STRING, mincon, meancon, maxcon); + printf("Processing: " CONF_FMT_STRING, mind, meand, maxd); + printf("Waiting: " CONF_FMT_STRING, minwait, meanwait, maxwait); + printf("Total: " CONF_FMT_STRING, mintot, meantot, maxtot); +#undef CONF_FMT_STRING + } + + + /* Sorted on total connect times */ + if (percentile && (done > 1)) { + printf("\nPercentage of the requests served within a certain time (ms)\n"); + for (i = 0; i < sizeof(percs) / sizeof(int); i++) { + if (percs[i] <= 0) + printf(" 0%% <0> (never)\n"); + else if (percs[i] >= 100) + printf(" 100%% %5" APR_TIME_T_FMT " (longest request)\n", + ap_round_ms(stats[done - 1].time)); + else + printf(" %d%% %5" APR_TIME_T_FMT "\n", percs[i], + ap_round_ms(stats[(unsigned long)done * percs[i] / 100].time)); + } + } + if (csvperc) { + FILE *out = fopen(csvperc, "w"); + if (!out) { + perror("Cannot open CSV output file"); + exit(1); + } + fprintf(out, "" "Percentage served" "," "Time in ms" "\n"); + for (i = 0; i <= 100; i++) { + double t; + if (i == 0) + t = ap_double_ms(stats[0].time); + else if (i == 100) + t = ap_double_ms(stats[done - 1].time); + else + t = ap_double_ms(stats[(unsigned long) (0.5 + (double)done * i / 100.0)].time); + fprintf(out, "%d,%.3f\n", i, t); + } + fclose(out); + } + if (gnuplot) { + FILE *out = fopen(gnuplot, "w"); + char tmstring[APR_CTIME_LEN]; + if (!out) { + perror("Cannot open gnuplot output file"); + exit(1); + } + fprintf(out, "starttime\tseconds\tctime\tdtime\tttime\twait\n"); + for (i = 0; i < done; i++) { + (void) apr_ctime(tmstring, stats[i].starttime); + fprintf(out, "%s\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT + "\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT + "\t%" APR_TIME_T_FMT "\n", tmstring, + apr_time_sec(stats[i].starttime), + ap_round_ms(stats[i].ctime), + ap_round_ms(stats[i].time - stats[i].ctime), + ap_round_ms(stats[i].time), + ap_round_ms(stats[i].waittime)); + } + fclose(out); + } + } + + if (sig) { + exit(1); + } +} + +/* --------------------------------------------------------- */ + +/* calculate and output results in HTML */ + +static void output_html_results(void) +{ + double timetaken = (double) (lasttime - start) / APR_USEC_PER_SEC; + + printf("\n\n<table %s>\n", tablestring); + printf("<tr %s><th colspan=2 %s>Server Software:</th>" + "<td colspan=2 %s>%s</td></tr>\n", + trstring, tdstring, tdstring, servername); + printf("<tr %s><th colspan=2 %s>Server Hostname:</th>" + "<td colspan=2 %s>%s</td></tr>\n", + trstring, tdstring, tdstring, hostname); + printf("<tr %s><th colspan=2 %s>Server Port:</th>" + "<td colspan=2 %s>%hu</td></tr>\n", + trstring, tdstring, tdstring, port); + printf("<tr %s><th colspan=2 %s>Document Path:</th>" + "<td colspan=2 %s>%s</td></tr>\n", + trstring, tdstring, tdstring, path); + if (nolength) + printf("<tr %s><th colspan=2 %s>Document Length:</th>" + "<td colspan=2 %s>Variable</td></tr>\n", + trstring, tdstring, tdstring); + else + printf("<tr %s><th colspan=2 %s>Document Length:</th>" + "<td colspan=2 %s>%" APR_SIZE_T_FMT " bytes</td></tr>\n", + trstring, tdstring, tdstring, doclen); + printf("<tr %s><th colspan=2 %s>Concurrency Level:</th>" + "<td colspan=2 %s>%d</td></tr>\n", + trstring, tdstring, tdstring, concurrency); + printf("<tr %s><th colspan=2 %s>Time taken for tests:</th>" + "<td colspan=2 %s>%.3f seconds</td></tr>\n", + trstring, tdstring, tdstring, timetaken); + printf("<tr %s><th colspan=2 %s>Complete requests:</th>" + "<td colspan=2 %s>%d</td></tr>\n", + trstring, tdstring, tdstring, done); + printf("<tr %s><th colspan=2 %s>Failed requests:</th>" + "<td colspan=2 %s>%d</td></tr>\n", + trstring, tdstring, tdstring, bad); + if (bad) + printf("<tr %s><td colspan=4 %s > (Connect: %d, Length: %d, Exceptions: %d)</td></tr>\n", + trstring, tdstring, err_conn, err_length, err_except); + if (err_response) + printf("<tr %s><th colspan=2 %s>Non-2xx responses:</th>" + "<td colspan=2 %s>%d</td></tr>\n", + trstring, tdstring, tdstring, err_response); + if (keepalive) + printf("<tr %s><th colspan=2 %s>Keep-Alive requests:</th>" + "<td colspan=2 %s>%d</td></tr>\n", + trstring, tdstring, tdstring, doneka); + printf("<tr %s><th colspan=2 %s>Total transferred:</th>" + "<td colspan=2 %s>%" APR_INT64_T_FMT " bytes</td></tr>\n", + trstring, tdstring, tdstring, totalread); + if (send_body) + printf("<tr %s><th colspan=2 %s>Total body sent:</th>" + "<td colspan=2 %s>%" APR_INT64_T_FMT "</td></tr>\n", + trstring, tdstring, + tdstring, totalposted); + printf("<tr %s><th colspan=2 %s>HTML transferred:</th>" + "<td colspan=2 %s>%" APR_INT64_T_FMT " bytes</td></tr>\n", + trstring, tdstring, tdstring, totalbread); + + /* avoid divide by zero */ + if (timetaken) { + printf("<tr %s><th colspan=2 %s>Requests per second:</th>" + "<td colspan=2 %s>%.2f</td></tr>\n", + trstring, tdstring, tdstring, (double) done / timetaken); + printf("<tr %s><th colspan=2 %s>Transfer rate:</th>" + "<td colspan=2 %s>%.2f kb/s received</td></tr>\n", + trstring, tdstring, tdstring, (double) totalread / 1024 / timetaken); + if (send_body) { + printf("<tr %s><td colspan=2 %s> </td>" + "<td colspan=2 %s>%.2f kb/s sent</td></tr>\n", + trstring, tdstring, tdstring, + (double) totalposted / 1024 / timetaken); + printf("<tr %s><td colspan=2 %s> </td>" + "<td colspan=2 %s>%.2f kb/s total</td></tr>\n", + trstring, tdstring, tdstring, + (double) (totalread + totalposted) / 1024 / timetaken); + } + } + { + /* work out connection times */ + int i; + apr_interval_time_t totalcon = 0, total = 0; + apr_interval_time_t mincon = AB_MAX, mintot = AB_MAX; + apr_interval_time_t maxcon = 0, maxtot = 0; + + for (i = 0; i < done; i++) { + struct data *s = &stats[i]; + mincon = ap_min(mincon, s->ctime); + mintot = ap_min(mintot, s->time); + maxcon = ap_max(maxcon, s->ctime); + maxtot = ap_max(maxtot, s->time); + totalcon += s->ctime; + total += s->time; + } + /* + * Reduce stats from apr time to milliseconds + */ + mincon = ap_round_ms(mincon); + mintot = ap_round_ms(mintot); + maxcon = ap_round_ms(maxcon); + maxtot = ap_round_ms(maxtot); + totalcon = ap_round_ms(totalcon); + total = ap_round_ms(total); + + if (done > 0) { /* avoid division by zero (if 0 done) */ + printf("<tr %s><th %s colspan=4>Connection Times (ms)</th></tr>\n", + trstring, tdstring); + printf("<tr %s><th %s> </th> <th %s>min</th> <th %s>avg</th> <th %s>max</th></tr>\n", + trstring, tdstring, tdstring, tdstring, tdstring); + printf("<tr %s><th %s>Connect:</th>" + "<td %s>%5" APR_TIME_T_FMT "</td>" + "<td %s>%5" APR_TIME_T_FMT "</td>" + "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n", + trstring, tdstring, tdstring, mincon, tdstring, totalcon / done, tdstring, maxcon); + printf("<tr %s><th %s>Processing:</th>" + "<td %s>%5" APR_TIME_T_FMT "</td>" + "<td %s>%5" APR_TIME_T_FMT "</td>" + "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n", + trstring, tdstring, tdstring, mintot - mincon, tdstring, + (total / done) - (totalcon / done), tdstring, maxtot - maxcon); + printf("<tr %s><th %s>Total:</th>" + "<td %s>%5" APR_TIME_T_FMT "</td>" + "<td %s>%5" APR_TIME_T_FMT "</td>" + "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n", + trstring, tdstring, tdstring, mintot, tdstring, total / done, tdstring, maxtot); + } + printf("</table>\n"); + } +} + +/* --------------------------------------------------------- */ + +/* start asnchronous non-blocking connection */ + +static void start_connect(struct connection * c) +{ + apr_status_t rv; + + if (!(started < requests)) + return; + + c->read = 0; + c->bread = 0; + c->keepalive = 0; + c->cbx = 0; + c->gotheader = 0; + c->rwrite = 0; + if (c->ctx) + apr_pool_clear(c->ctx); + else + apr_pool_create(&c->ctx, cntxt); + + if ((rv = apr_socket_create(&c->aprsock, destsa->family, + SOCK_STREAM, 0, c->ctx)) != APR_SUCCESS) { + apr_err("socket", rv); + } + + if (myhost) { + if ((rv = apr_socket_bind(c->aprsock, mysa)) != APR_SUCCESS) { + apr_err("bind", rv); + } + } + + c->pollfd.desc_type = APR_POLL_SOCKET; + c->pollfd.desc.s = c->aprsock; + c->pollfd.reqevents = 0; + c->pollfd.client_data = c; + + if ((rv = apr_socket_opt_set(c->aprsock, APR_SO_NONBLOCK, 1)) + != APR_SUCCESS) { + apr_err("socket nonblock", rv); + } + + if (windowsize != 0) { + rv = apr_socket_opt_set(c->aprsock, APR_SO_SNDBUF, + windowsize); + if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { + apr_err("socket send buffer", rv); + } + rv = apr_socket_opt_set(c->aprsock, APR_SO_RCVBUF, + windowsize); + if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { + apr_err("socket receive buffer", rv); + } + } + + c->start = lasttime = apr_time_now(); +#ifdef USE_SSL + if (is_ssl) { + BIO *bio; + apr_os_sock_t fd; + + if ((c->ssl = SSL_new(ssl_ctx)) == NULL) { + BIO_printf(bio_err, "SSL_new failed.\n"); + ERR_print_errors(bio_err); + exit(1); + } + ssl_rand_seed(); + apr_os_sock_get(&fd, c->aprsock); + bio = BIO_new_socket(fd, BIO_NOCLOSE); + BIO_set_nbio(bio, 1); + SSL_set_bio(c->ssl, bio, bio); + SSL_set_connect_state(c->ssl); + if (verbosity >= 4) { + BIO_set_callback(bio, ssl_print_cb); + BIO_set_callback_arg(bio, (void *)bio_err); + } +#ifdef HAVE_TLSEXT + if (tls_sni) { + SSL_set_tlsext_host_name(c->ssl, tls_sni); + } +#endif + } else { + c->ssl = NULL; + } +#endif + if ((rv = apr_socket_connect(c->aprsock, destsa)) != APR_SUCCESS) { + if (APR_STATUS_IS_EINPROGRESS(rv)) { + set_conn_state(c, STATE_CONNECTING); + c->rwrite = 0; + return; + } + else { + set_conn_state(c, STATE_UNCONNECTED); + apr_socket_close(c->aprsock); + if (good == 0 && destsa->next) { + destsa = destsa->next; + err_conn = 0; + } + else if (bad++ > 10) { + fprintf(stderr, + "\nTest aborted after 10 failures\n\n"); + apr_err("apr_socket_connect()", rv); + } + else { + err_conn++; + } + + start_connect(c); + return; + } + } + + /* connected first time */ + set_conn_state(c, STATE_CONNECTED); +#ifdef USE_SSL + if (c->ssl) { + ssl_proceed_handshake(c); + } else +#endif + { + write_request(c); + } +} + +/* --------------------------------------------------------- */ + +/* close down connection and save stats */ + +static void close_connection(struct connection * c) +{ + if (c->read == 0 && c->keepalive) { + /* + * server has legitimately shut down an idle keep alive request + */ + if (good) + good--; /* connection never happened */ + } + else { + if (good == 1) { + /* first time here */ + doclen = c->bread; + } + else if ((c->bread != doclen) && !nolength) { + bad++; + err_length++; + } + /* save out time */ + if (done < requests) { + struct data *s = &stats[done++]; + c->done = lasttime = apr_time_now(); + s->starttime = c->start; + s->ctime = ap_max(0, c->connect - c->start); + s->time = ap_max(0, c->done - c->start); + s->waittime = ap_max(0, c->beginread - c->endwrite); + if (heartbeatres && !(done % heartbeatres)) { + fprintf(stderr, "Completed %d requests\n", done); + fflush(stderr); + } + } + } + + set_conn_state(c, STATE_UNCONNECTED); +#ifdef USE_SSL + if (c->ssl) { + SSL_shutdown(c->ssl); + SSL_free(c->ssl); + c->ssl = NULL; + } +#endif + apr_socket_close(c->aprsock); + + /* connect again */ + start_connect(c); + return; +} + +/* --------------------------------------------------------- */ + +/* read data from connection */ + +static void read_connection(struct connection * c) +{ + apr_size_t r; + apr_status_t status; + char *part; + char respcode[4]; /* 3 digits and null */ + int i; + + r = sizeof(buffer); +read_more: +#ifdef USE_SSL + if (c->ssl) { + status = SSL_read(c->ssl, buffer, r); + if (status <= 0) { + int scode = SSL_get_error(c->ssl, status); + + if (scode == SSL_ERROR_ZERO_RETURN) { + /* connection closed cleanly: */ + good++; + close_connection(c); + } + else if (scode == SSL_ERROR_SYSCALL + && status == 0 + && c->read != 0) { + /* connection closed, but in violation of the protocol, after + * some data has already been read; this commonly happens, so + * let the length check catch any response errors + */ + good++; + close_connection(c); + } + else if (scode == SSL_ERROR_SYSCALL + && c->read == 0 + && destsa->next + && c->state == STATE_CONNECTING + && good == 0) { + return; + } + else if (scode == SSL_ERROR_WANT_READ) { + set_polled_events(c, APR_POLLIN); + } + else if (scode == SSL_ERROR_WANT_WRITE) { + set_polled_events(c, APR_POLLOUT); + } + else { + /* some fatal error: */ + c->read = 0; + BIO_printf(bio_err, "SSL read failed (%d) - closing connection\n", scode); + ERR_print_errors(bio_err); + close_connection(c); + } + return; + } + r = status; + } + else +#endif + { + status = apr_socket_recv(c->aprsock, buffer, &r); + if (APR_STATUS_IS_EAGAIN(status)) + return; + else if (r == 0 && APR_STATUS_IS_EOF(status)) { + good++; + close_connection(c); + return; + } + /* catch legitimate fatal apr_socket_recv errors */ + else if (status != APR_SUCCESS) { + if (recverrok) { + err_recv++; + bad++; + close_connection(c); + if (verbosity >= 1) { + char buf[120]; + fprintf(stderr,"%s: %s (%d)\n", "apr_socket_recv", apr_strerror(status, buf, sizeof buf), status); + } + return; + } else if (destsa->next && c->state == STATE_CONNECTING + && c->read == 0 && good == 0) { + return; + } + else { + err_recv++; + apr_err("apr_socket_recv", status); + } + } + } + + totalread += r; + if (c->read == 0) { + c->beginread = apr_time_now(); + } + c->read += r; + + + if (!c->gotheader) { + char *s; + int l = 4; + apr_size_t space = CBUFFSIZE - c->cbx - 1; /* -1 allows for \0 term */ + int tocopy = (space < r) ? space : r; +#ifdef NOT_ASCII + apr_size_t inbytes_left = space, outbytes_left = space; + + status = apr_xlate_conv_buffer(from_ascii, buffer, &inbytes_left, + c->cbuff + c->cbx, &outbytes_left); + if (status || inbytes_left || outbytes_left) { + fprintf(stderr, "only simple translation is supported (%d/%" APR_SIZE_T_FMT + "/%" APR_SIZE_T_FMT ")\n", status, inbytes_left, outbytes_left); + exit(1); + } +#else + memcpy(c->cbuff + c->cbx, buffer, space); +#endif /* NOT_ASCII */ + c->cbx += tocopy; + space -= tocopy; + c->cbuff[c->cbx] = 0; /* terminate for benefit of strstr */ + if (verbosity >= 2) { + printf("LOG: header received:\n%s\n", c->cbuff); + } + s = strstr(c->cbuff, "\r\n\r\n"); + /* + * this next line is so that we talk to NCSA 1.5 which blatantly + * breaks the http specifaction + */ + if (!s) { + s = strstr(c->cbuff, "\n\n"); + l = 2; + } + + if (!s) { + /* read rest next time */ + if (space) { + return; + } + else { + /* header is in invalid or too big - close connection */ + set_conn_state(c, STATE_UNCONNECTED); + apr_socket_close(c->aprsock); + err_response++; + if (bad++ > 10) { + err("\nTest aborted after 10 failures\n\n"); + } + start_connect(c); + } + } + else { + /* have full header */ + if (!good) { + /* + * this is first time, extract some interesting info + */ + char *p, *q; + size_t len = 0; + p = xstrcasestr(c->cbuff, "Server:"); + q = servername; + if (p) { + p += 8; + /* -1 to not overwrite last '\0' byte */ + while (*p > 32 && len++ < sizeof(servername) - 1) + *q++ = *p++; + } + *q = 0; + } + /* + * XXX: this parsing isn't even remotely HTTP compliant... but in + * the interest of speed it doesn't totally have to be, it just + * needs to be extended to handle whatever servers folks want to + * test against. -djg + */ + + /* check response code */ + part = strstr(c->cbuff, "HTTP"); /* really HTTP/1.x_ */ + if (part && strlen(part) > strlen("HTTP/1.x_")) { + strncpy(respcode, (part + strlen("HTTP/1.x_")), 3); + respcode[3] = '\0'; + } + else { + strcpy(respcode, "500"); + } + + if (respcode[0] != '2') { + err_response++; + if (verbosity >= 2) + printf("WARNING: Response code not 2xx (%s)\n", respcode); + } + else if (verbosity >= 3) { + printf("LOG: Response code = %s\n", respcode); + } + c->gotheader = 1; + *s = 0; /* terminate at end of header */ + if (keepalive && xstrcasestr(c->cbuff, "Keep-Alive")) { + char *cl; + c->keepalive = 1; + cl = xstrcasestr(c->cbuff, "Content-Length:"); + if (cl && method != HEAD) { + /* response to HEAD doesn't have entity body */ + c->length = atoi(cl + 16); + } + else { + c->length = 0; + } + } + c->bread += c->cbx - (s + l - c->cbuff) + r - tocopy; + totalbread += c->bread; + + /* We have received the header, so we know this destination socket + * address is working, so initialize all remaining requests. */ + if (!requests_initialized) { + for (i = 1; i < concurrency; i++) { + con[i].socknum = i; + start_connect(&con[i]); + } + requests_initialized = 1; + } + } + } + else { + /* outside header, everything we have read is entity body */ + c->bread += r; + totalbread += r; + } + if (r == sizeof(buffer) && c->bread < c->length) { + /* read was full, try more immediately (nonblocking already) */ + goto read_more; + } + + if (c->keepalive && (c->bread >= c->length)) { + /* finished a keep-alive connection */ + good++; + /* save out time */ + if (good == 1) { + /* first time here */ + doclen = c->bread; + } + else if ((c->bread != doclen) && !nolength) { + bad++; + err_length++; + } + if (done < requests) { + struct data *s = &stats[done++]; + doneka++; + c->done = apr_time_now(); + s->starttime = c->start; + s->ctime = ap_max(0, c->connect - c->start); + s->time = ap_max(0, c->done - c->start); + s->waittime = ap_max(0, c->beginread - c->endwrite); + if (heartbeatres && !(done % heartbeatres)) { + fprintf(stderr, "Completed %d requests\n", done); + fflush(stderr); + } + } + c->keepalive = 0; + c->length = 0; + c->gotheader = 0; + c->cbx = 0; + c->read = c->bread = 0; + /* zero connect time with keep-alive */ + c->start = c->connect = lasttime = apr_time_now(); + set_conn_state(c, STATE_CONNECTED); + write_request(c); + } +} + +/* --------------------------------------------------------- */ + +/* run the tests */ + +static void test(void) +{ + apr_time_t stoptime; + apr_int16_t rtnev; + apr_status_t rv; + int i; + apr_status_t status; + int snprintf_res = 0; +#ifdef NOT_ASCII + apr_size_t inbytes_left, outbytes_left; +#endif + + if (isproxy) { + connecthost = apr_pstrdup(cntxt, proxyhost); + connectport = proxyport; + } + else { + connecthost = apr_pstrdup(cntxt, hostname); + connectport = port; + } + + if (!use_html) { + printf("Benchmarking %s ", hostname); + if (isproxy) + printf("[through %s:%d] ", proxyhost, proxyport); + printf("(be patient)%s", + (heartbeatres ? "\n" : "...")); + fflush(stdout); + } + + con = xcalloc(concurrency, sizeof(struct connection)); + + /* + * XXX: a way to calculate the stats without requiring O(requests) memory + * XXX: would be nice. + */ + stats = xcalloc(requests, sizeof(struct data)); + + if ((status = apr_pollset_create(&readbits, concurrency, cntxt, + APR_POLLSET_NOCOPY)) != APR_SUCCESS) { + apr_err("apr_pollset_create failed", status); + } + + /* add default headers if necessary */ + if (!opt_host) { + /* Host: header not overridden, add default value to hdrs */ + hdrs = apr_pstrcat(cntxt, hdrs, "Host: ", host_field, colonhost, "\r\n", NULL); + } + else { + /* Header overridden, no need to add, as it is already in hdrs */ + } + +#ifdef HAVE_TLSEXT + if (is_ssl && tls_use_sni) { + apr_ipsubnet_t *ip; + if (((tls_sni = opt_host) || (tls_sni = hostname)) && + (!*tls_sni || apr_ipsubnet_create(&ip, tls_sni, NULL, + cntxt) == APR_SUCCESS)) { + /* IP not allowed in TLS SNI extension */ + tls_sni = NULL; + } + } +#endif + + if (!opt_useragent) { + /* User-Agent: header not overridden, add default value to hdrs */ + hdrs = apr_pstrcat(cntxt, hdrs, "User-Agent: ApacheBench/", AP_AB_BASEREVISION, "\r\n", NULL); + } + else { + /* Header overridden, no need to add, as it is already in hdrs */ + } + + if (!opt_accept) { + /* Accept: header not overridden, add default value to hdrs */ + hdrs = apr_pstrcat(cntxt, hdrs, "Accept: */*\r\n", NULL); + } + else { + /* Header overridden, no need to add, as it is already in hdrs */ + } + + /* setup request */ + if (!send_body) { + snprintf_res = apr_snprintf(request, sizeof(_request), + "%s %s HTTP/1.0\r\n" + "%s" "%s" "%s" + "%s" "\r\n", + method_str[method], + (isproxy) ? fullurl : path, + keepalive ? "Connection: Keep-Alive\r\n" : "", + cookie, auth, hdrs); + } + else { + snprintf_res = apr_snprintf(request, sizeof(_request), + "%s %s HTTP/1.0\r\n" + "%s" "%s" "%s" + "Content-length: %" APR_SIZE_T_FMT "\r\n" + "Content-type: %s\r\n" + "%s" + "\r\n", + method_str[method], + (isproxy) ? fullurl : path, + keepalive ? "Connection: Keep-Alive\r\n" : "", + cookie, auth, + postlen, + (content_type != NULL) ? content_type : "text/plain", hdrs); + } + if (snprintf_res >= sizeof(_request)) { + err("Request too long\n"); + } + + if (verbosity >= 2) + printf("INFO: %s header == \n---\n%s\n---\n", + method_str[method], request); + + reqlen = strlen(request); + + /* + * Combine headers and (optional) post file into one continuous buffer + */ + if (send_body) { + char *buff = xmalloc(postlen + reqlen + 1); + strcpy(buff, request); + memcpy(buff + reqlen, postdata, postlen); + request = buff; + } + +#ifdef NOT_ASCII + inbytes_left = outbytes_left = reqlen; + status = apr_xlate_conv_buffer(to_ascii, request, &inbytes_left, + request, &outbytes_left); + if (status || inbytes_left || outbytes_left) { + fprintf(stderr, "only simple translation is supported (%d/%" + APR_SIZE_T_FMT "/%" APR_SIZE_T_FMT ")\n", + status, inbytes_left, outbytes_left); + exit(1); + } +#endif /* NOT_ASCII */ + + if (myhost) { + /* This only needs to be done once */ + if ((rv = apr_sockaddr_info_get(&mysa, myhost, APR_UNSPEC, 0, 0, cntxt)) != APR_SUCCESS) { + char buf[120]; + apr_snprintf(buf, sizeof(buf), + "apr_sockaddr_info_get() for %s", myhost); + apr_err(buf, rv); + } + } + + /* This too */ + if ((rv = apr_sockaddr_info_get(&destsa, connecthost, + myhost ? mysa->family : APR_UNSPEC, + connectport, 0, cntxt)) + != APR_SUCCESS) { + char buf[120]; + apr_snprintf(buf, sizeof(buf), + "apr_sockaddr_info_get() for %s", connecthost); + apr_err(buf, rv); + } + + /* ok - lets start */ + start = lasttime = apr_time_now(); + stoptime = tlimit ? (start + apr_time_from_sec(tlimit)) : AB_MAX; + +#ifdef SIGINT + /* Output the results if the user terminates the run early. */ + apr_signal(SIGINT, output_results); +#endif + + /* initialise first connection to determine destination socket address + * which should be used for next connections. */ + con[0].socknum = 0; + start_connect(&con[0]); + + do { + apr_int32_t n; + const apr_pollfd_t *pollresults, *pollfd; + + n = concurrency; + do { + status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults); + } while (APR_STATUS_IS_EINTR(status)); + if (status != APR_SUCCESS) + apr_err("apr_pollset_poll", status); + + for (i = 0, pollfd = pollresults; i < n; i++, pollfd++) { + struct connection *c; + + c = pollfd->client_data; + + /* + * If the connection isn't connected how can we check it? + */ + if (c->state == STATE_UNCONNECTED) + continue; + + rtnev = pollfd->rtnevents; + +#ifdef USE_SSL + if (c->state == STATE_CONNECTED && c->ssl && SSL_in_init(c->ssl)) { + ssl_proceed_handshake(c); + continue; + } +#endif + + /* + * Notes: APR_POLLHUP is set after FIN is received on some + * systems, so treat that like APR_POLLIN so that we try to read + * again. + * + * Some systems return APR_POLLERR with APR_POLLHUP. We need to + * call read_connection() for APR_POLLHUP, so check for + * APR_POLLHUP first so that a closed connection isn't treated + * like an I/O error. If it is, we never figure out that the + * connection is done and we loop here endlessly calling + * apr_poll(). + */ + if ((rtnev & APR_POLLIN) || (rtnev & APR_POLLPRI) || (rtnev & APR_POLLHUP)) + read_connection(c); + if ((rtnev & APR_POLLERR) || (rtnev & APR_POLLNVAL)) { + if (destsa->next && c->state == STATE_CONNECTING && good == 0) { + destsa = destsa->next; + start_connect(c); + } + else { + bad++; + err_except++; + /* avoid apr_poll/EINPROGRESS loop on HP-UX, let recv discover ECONNREFUSED */ + if (c->state == STATE_CONNECTING) { + read_connection(c); + } + else { + start_connect(c); + } + } + continue; + } + if (rtnev & APR_POLLOUT) { + if (c->state == STATE_CONNECTING) { + /* call connect() again to detect errors */ + rv = apr_socket_connect(c->aprsock, destsa); + if (rv != APR_SUCCESS) { + set_conn_state(c, STATE_UNCONNECTED); + apr_socket_close(c->aprsock); + err_conn++; + if (bad++ > 10) { + fprintf(stderr, + "\nTest aborted after 10 failures\n\n"); + apr_err("apr_socket_connect()", rv); + } + start_connect(c); + continue; + } + else { + set_conn_state(c, STATE_CONNECTED); +#ifdef USE_SSL + if (c->ssl) + ssl_proceed_handshake(c); + else +#endif + write_request(c); + } + } + else { + /* POLLOUT is one shot */ + set_polled_events(c, APR_POLLIN); + if (c->state == STATE_READ) { + read_connection(c); + } + else { + write_request(c); + } + } + } + } + } while (lasttime < stoptime && done < requests); + + if (heartbeatres) + fprintf(stderr, "Finished %d requests\n", done); + else + printf("..done\n"); + + if (use_html) + output_html_results(); + else + output_results(0); +} + +/* ------------------------------------------------------- */ + +/* display copyright information */ +static void copyright(void) +{ + if (!use_html) { + printf("This is ApacheBench, Version %s\n", AP_AB_BASEREVISION " <$Revision: 1903618 $>"); + printf("Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/\n"); + printf("Licensed to The Apache Software Foundation, http://www.apache.org/\n"); + printf("\n"); + } + else { + printf("<p>\n"); + printf(" This is ApacheBench, Version %s <i><%s></i><br>\n", AP_AB_BASEREVISION, "$Revision: 1903618 $"); + printf(" Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/<br>\n"); + printf(" Licensed to The Apache Software Foundation, http://www.apache.org/<br>\n"); + printf("</p>\n<p>\n"); + } +} + +/* display usage information */ +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s [options] [http" +#ifdef USE_SSL + "[s]" +#endif + "://]hostname[:port]/path\n", progname); +/* 80 column ruler: ******************************************************************************** + */ + fprintf(stderr, "Options are:\n"); + fprintf(stderr, " -n requests Number of requests to perform\n"); + fprintf(stderr, " -c concurrency Number of multiple requests to make at a time\n"); + fprintf(stderr, " -t timelimit Seconds to max. to spend on benchmarking\n"); + fprintf(stderr, " This implies -n 50000\n"); + fprintf(stderr, " -s timeout Seconds to max. wait for each response\n"); + fprintf(stderr, " Default is 30 seconds\n"); + fprintf(stderr, " -b windowsize Size of TCP send/receive buffer, in bytes\n"); + fprintf(stderr, " -B address Address to bind to when making outgoing connections\n"); + fprintf(stderr, " -p postfile File containing data to POST. Remember also to set -T\n"); + fprintf(stderr, " -u putfile File containing data to PUT. Remember also to set -T\n"); + fprintf(stderr, " -T content-type Content-type header to use for POST/PUT data, eg.\n"); + fprintf(stderr, " 'application/x-www-form-urlencoded'\n"); + fprintf(stderr, " Default is 'text/plain'\n"); + fprintf(stderr, " -v verbosity How much troubleshooting info to print\n"); + fprintf(stderr, " -w Print out results in HTML tables\n"); + fprintf(stderr, " -i Use HEAD instead of GET\n"); + fprintf(stderr, " -x attributes String to insert as table attributes\n"); + fprintf(stderr, " -y attributes String to insert as tr attributes\n"); + fprintf(stderr, " -z attributes String to insert as td or th attributes\n"); + fprintf(stderr, " -C attribute Add cookie, eg. 'Apache=1234'. (repeatable)\n"); + fprintf(stderr, " -H attribute Add Arbitrary header line, eg. 'Accept-Encoding: gzip'\n"); + fprintf(stderr, " Inserted after all normal header lines. (repeatable)\n"); + fprintf(stderr, " -A attribute Add Basic WWW Authentication, the attributes\n"); + fprintf(stderr, " are a colon separated username and password.\n"); + fprintf(stderr, " -P attribute Add Basic Proxy Authentication, the attributes\n"); + fprintf(stderr, " are a colon separated username and password.\n"); + fprintf(stderr, " -X proxy:port Proxyserver and port number to use\n"); + fprintf(stderr, " -V Print version number and exit\n"); + fprintf(stderr, " -k Use HTTP KeepAlive feature\n"); + fprintf(stderr, " -d Do not show percentiles served table.\n"); + fprintf(stderr, " -S Do not show confidence estimators and warnings.\n"); + fprintf(stderr, " -q Do not show progress when doing more than 150 requests\n"); + fprintf(stderr, " -l Accept variable document length (use this for dynamic pages)\n"); + fprintf(stderr, " -g filename Output collected data to gnuplot format file.\n"); + fprintf(stderr, " -e filename Output CSV file with percentages served\n"); + fprintf(stderr, " -r Don't exit on socket receive errors.\n"); + fprintf(stderr, " -m method Method name\n"); + fprintf(stderr, " -h Display usage information (this message)\n"); +#ifdef USE_SSL + +#ifndef OPENSSL_NO_SSL2 +#define SSL2_HELP_MSG "SSL2, " +#else +#define SSL2_HELP_MSG "" +#endif + +#ifndef OPENSSL_NO_SSL3 +#define SSL3_HELP_MSG "SSL3, " +#else +#define SSL3_HELP_MSG "" +#endif + +#ifdef HAVE_TLSV1_X + +#ifdef TLS1_3_VERSION +#define TLS1_X_HELP_MSG ", TLS1.1, TLS1.2, TLS1.3" +#else +#define TLS1_X_HELP_MSG ", TLS1.1, TLS1.2" +#endif + +#else +#define TLS1_X_HELP_MSG "" +#endif + +#ifdef HAVE_TLSEXT + fprintf(stderr, " -I Disable TLS Server Name Indication (SNI) extension\n"); +#endif + fprintf(stderr, " -Z ciphersuite Specify SSL/TLS cipher suite (See openssl ciphers)\n"); + fprintf(stderr, " -f protocol Specify SSL/TLS protocol\n"); + fprintf(stderr, " (" SSL2_HELP_MSG SSL3_HELP_MSG "TLS1" TLS1_X_HELP_MSG " or ALL)\n"); + fprintf(stderr, " -E certfile Specify optional client certificate chain and private key\n"); +#endif + exit(EINVAL); +} + +/* ------------------------------------------------------- */ + +/* split URL into parts */ + +static int parse_url(const char *url) +{ + char *cp; + char *h; + char *scope_id; + apr_status_t rv; + + /* Save a copy for the proxy */ + fullurl = apr_pstrdup(cntxt, url); + + if (strlen(url) > 7 && strncmp(url, "http://", 7) == 0) { + url += 7; +#ifdef USE_SSL + is_ssl = 0; +#endif + } + else +#ifdef USE_SSL + if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) { + url += 8; + is_ssl = 1; + } +#else + if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) { + fprintf(stderr, "SSL not compiled in; no https support\n"); + exit(1); + } +#endif + + if ((cp = strchr(url, '/')) == NULL) + return 1; + h = apr_pstrmemdup(cntxt, url, cp - url); + rv = apr_parse_addr_port(&hostname, &scope_id, &port, h, cntxt); + if (rv != APR_SUCCESS || !hostname || scope_id) { + return 1; + } + path = apr_pstrdup(cntxt, cp); + *cp = '\0'; + if (*url == '[') { /* IPv6 numeric address string */ + host_field = apr_psprintf(cntxt, "[%s]", hostname); + } + else { + host_field = hostname; + } + + if (port == 0) { /* no port specified */ +#ifdef USE_SSL + if (is_ssl) + port = 443; + else +#endif + port = 80; + } + + if (( +#ifdef USE_SSL + is_ssl && (port != 443)) || (!is_ssl && +#endif + (port != 80))) + { + colonhost = apr_psprintf(cntxt,":%d",port); + } else + colonhost = ""; + return 0; +} + +/* ------------------------------------------------------- */ + +/* read data to POST/PUT from file, save contents and length */ + +static apr_status_t open_postfile(const char *pfile) +{ + apr_file_t *postfd; + apr_finfo_t finfo; + apr_status_t rv; + char errmsg[120]; + + rv = apr_file_open(&postfd, pfile, APR_READ, APR_OS_DEFAULT, cntxt); + if (rv != APR_SUCCESS) { + fprintf(stderr, "ab: Could not open POST data file (%s): %s\n", pfile, + apr_strerror(rv, errmsg, sizeof errmsg)); + return rv; + } + + rv = apr_file_info_get(&finfo, APR_FINFO_NORM, postfd); + if (rv != APR_SUCCESS) { + fprintf(stderr, "ab: Could not stat POST data file (%s): %s\n", pfile, + apr_strerror(rv, errmsg, sizeof errmsg)); + return rv; + } + postlen = (apr_size_t)finfo.size; + postdata = xmalloc(postlen); + rv = apr_file_read_full(postfd, postdata, postlen, NULL); + if (rv != APR_SUCCESS) { + fprintf(stderr, "ab: Could not read POST data file: %s\n", + apr_strerror(rv, errmsg, sizeof errmsg)); + return rv; + } + apr_file_close(postfd); + return APR_SUCCESS; +} + +/* ------------------------------------------------------- */ + +/* sort out command-line args and call test */ +int main(int argc, const char * const argv[]) +{ + char tmp[1024]; + apr_status_t status; + apr_getopt_t *opt; + const char *opt_arg; + char c; +#ifdef USE_SSL +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + int max_prot = MAX_SSL_PROTO; + int min_prot = MIN_SSL_PROTO; +#endif /* #if OPENSSL_VERSION_NUMBER >= 0x10100000L */ + AB_SSL_METHOD_CONST SSL_METHOD *meth = SSLv23_client_method(); +#endif /* USE_SSL */ + + /* table defaults */ + tablestring = ""; + trstring = ""; + tdstring = "bgcolor=white"; + cookie = ""; + auth = ""; + proxyhost = ""; + hdrs = ""; + + apr_app_initialize(&argc, &argv, NULL); + atexit(apr_terminate); + apr_pool_create(&cntxt, NULL); + apr_pool_abort_set(abort_on_oom, cntxt); + +#ifdef NOT_ASCII + status = apr_xlate_open(&to_ascii, "ISO-8859-1", APR_DEFAULT_CHARSET, cntxt); + if (status) { + fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", status); + exit(1); + } + status = apr_xlate_open(&from_ascii, APR_DEFAULT_CHARSET, "ISO-8859-1", cntxt); + if (status) { + fprintf(stderr, "apr_xlate_open(from ASCII)->%d\n", status); + exit(1); + } + status = apr_base64init_ebcdic(to_ascii, from_ascii); + if (status) { + fprintf(stderr, "apr_base64init_ebcdic()->%d\n", status); + exit(1); + } +#endif + + myhost = NULL; /* 0.0.0.0 or :: */ + + apr_getopt_init(&opt, cntxt, argc, argv); + while ((status = apr_getopt(opt, "n:c:t:s:b:T:p:u:v:lrkVhwiIx:y:z:C:H:P:A:g:X:de:SqB:m:" +#ifdef USE_SSL + "Z:f:E:" +#endif + ,&c, &opt_arg)) == APR_SUCCESS) { + switch (c) { + case 'n': + requests = atoi(opt_arg); + if (requests <= 0) { + err("Invalid number of requests\n"); + } + break; + case 'k': + keepalive = 1; + break; + case 'q': + heartbeatres = 0; + break; + case 'c': + concurrency = atoi(opt_arg); + break; + case 'b': + windowsize = atoi(opt_arg); + break; + case 'i': + if (method != NO_METH) + err("Cannot mix HEAD with other methods\n"); + method = HEAD; + break; + case 'g': + gnuplot = xstrdup(opt_arg); + break; + case 'd': + percentile = 0; + break; + case 'e': + csvperc = xstrdup(opt_arg); + break; + case 'S': + confidence = 0; + break; + case 's': + aprtimeout = apr_time_from_sec(atoi(opt_arg)); /* timeout value */ + break; + case 'p': + if (method != NO_METH) + err("Cannot mix POST with other methods\n"); + if (open_postfile(opt_arg) != APR_SUCCESS) { + exit(1); + } + method = POST; + send_body = 1; + break; + case 'u': + if (method != NO_METH) + err("Cannot mix PUT with other methods\n"); + if (open_postfile(opt_arg) != APR_SUCCESS) { + exit(1); + } + method = PUT; + send_body = 1; + break; + case 'l': + nolength = 1; + break; + case 'r': + recverrok = 1; + break; + case 'v': + verbosity = atoi(opt_arg); + break; + case 't': + tlimit = atoi(opt_arg); + requests = MAX_REQUESTS; /* need to size data array on + * something */ + break; + case 'T': + content_type = apr_pstrdup(cntxt, opt_arg); + break; + case 'C': + cookie = apr_pstrcat(cntxt, "Cookie: ", opt_arg, "\r\n", NULL); + break; + case 'A': + /* + * assume username passwd already to be in colon separated form. + * Ready to be uu-encoded. + */ + while (apr_isspace(*opt_arg)) + opt_arg++; + if (apr_base64_encode_len(strlen(opt_arg)) > sizeof(tmp)) { + err("Authentication credentials too long\n"); + } + apr_base64_encode(tmp, opt_arg, strlen(opt_arg)); + + auth = apr_pstrcat(cntxt, auth, "Authorization: Basic ", tmp, + "\r\n", NULL); + break; + case 'P': + /* + * assume username passwd already to be in colon separated form. + */ + while (apr_isspace(*opt_arg)) + opt_arg++; + if (apr_base64_encode_len(strlen(opt_arg)) > sizeof(tmp)) { + err("Proxy credentials too long\n"); + } + apr_base64_encode(tmp, opt_arg, strlen(opt_arg)); + + auth = apr_pstrcat(cntxt, auth, "Proxy-Authorization: Basic ", + tmp, "\r\n", NULL); + break; + case 'H': + hdrs = apr_pstrcat(cntxt, hdrs, opt_arg, "\r\n", NULL); + /* + * allow override of some of the common headers that ab adds + */ + if (strncasecmp(opt_arg, "Host:", 5) == 0) { + char *host; + apr_size_t len; + opt_arg += 5; + while (apr_isspace(*opt_arg)) + opt_arg++; + len = strlen(opt_arg); + host = strdup(opt_arg); + while (len && apr_isspace(host[len-1])) + host[--len] = '\0'; + opt_host = host; + } else if (strncasecmp(opt_arg, "Accept:", 7) == 0) { + opt_accept = 1; + } else if (strncasecmp(opt_arg, "User-Agent:", 11) == 0) { + opt_useragent = 1; + } + break; + case 'w': + use_html = 1; + break; + /* + * if any of the following three are used, turn on html output + * automatically + */ + case 'x': + use_html = 1; + tablestring = opt_arg; + break; + case 'X': + { + char *p; + /* + * assume proxy-name[:port] + */ + if ((p = strchr(opt_arg, ':'))) { + *p = '\0'; + p++; + proxyport = atoi(p); + } + proxyhost = apr_pstrdup(cntxt, opt_arg); + isproxy = 1; + } + break; + case 'y': + use_html = 1; + trstring = opt_arg; + break; + case 'z': + use_html = 1; + tdstring = opt_arg; + break; + case 'h': + usage(argv[0]); + break; + case 'V': + copyright(); + return 0; + case 'B': + myhost = apr_pstrdup(cntxt, opt_arg); + break; + case 'm': + method = CUSTOM_METHOD; + method_str[CUSTOM_METHOD] = strdup(opt_arg); + break; +#ifdef USE_SSL + case 'Z': + ssl_cipher = strdup(opt_arg); + break; + case 'E': + ssl_cert = strdup(opt_arg); + break; + case 'f': +#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (strncasecmp(opt_arg, "ALL", 3) == 0) { + meth = SSLv23_client_method(); +#ifndef OPENSSL_NO_SSL2 + } else if (strncasecmp(opt_arg, "SSL2", 4) == 0) { + meth = SSLv2_client_method(); +#ifdef HAVE_TLSEXT + tls_use_sni = 0; +#endif +#endif +#ifndef OPENSSL_NO_SSL3 + } else if (strncasecmp(opt_arg, "SSL3", 4) == 0) { + meth = SSLv3_client_method(); +#ifdef HAVE_TLSEXT + tls_use_sni = 0; +#endif +#endif +#ifdef HAVE_TLSV1_X + } else if (strncasecmp(opt_arg, "TLS1.1", 6) == 0) { + meth = TLSv1_1_client_method(); + } else if (strncasecmp(opt_arg, "TLS1.2", 6) == 0) { + meth = TLSv1_2_client_method(); +#endif + } else if (strncasecmp(opt_arg, "TLS1", 4) == 0) { + meth = TLSv1_client_method(); + } +#else /* #if OPENSSL_VERSION_NUMBER < 0x10100000L */ + meth = TLS_client_method(); + if (strncasecmp(opt_arg, "ALL", 3) == 0) { + max_prot = MAX_SSL_PROTO; + min_prot = MIN_SSL_PROTO; +#ifndef OPENSSL_NO_SSL3 + } else if (strncasecmp(opt_arg, "SSL3", 4) == 0) { + max_prot = SSL3_VERSION; + min_prot = SSL3_VERSION; +#endif + } else if (strncasecmp(opt_arg, "TLS1.1", 6) == 0) { + max_prot = TLS1_1_VERSION; + min_prot = TLS1_1_VERSION; + } else if (strncasecmp(opt_arg, "TLS1.2", 6) == 0) { + max_prot = TLS1_2_VERSION; + min_prot = TLS1_2_VERSION; +#ifdef TLS1_3_VERSION + } else if (strncasecmp(opt_arg, "TLS1.3", 6) == 0) { + max_prot = TLS1_3_VERSION; + min_prot = TLS1_3_VERSION; +#endif + } else if (strncasecmp(opt_arg, "TLS1", 4) == 0) { + max_prot = TLS1_VERSION; + min_prot = TLS1_VERSION; + } +#endif /* #if OPENSSL_VERSION_NUMBER < 0x10100000L */ + break; +#ifdef HAVE_TLSEXT + case 'I': + tls_use_sni = 0; + break; +#endif +#endif /* USE_SSL */ + } + } + + if (opt->ind != argc - 1) { + fprintf(stderr, "%s: wrong number of arguments\n", argv[0]); + usage(argv[0]); + } + + if (method == NO_METH) { + method = GET; + } + + if (parse_url(apr_pstrdup(cntxt, opt->argv[opt->ind++]))) { + fprintf(stderr, "%s: invalid URL\n", argv[0]); + usage(argv[0]); + } + + if ((concurrency < 0) || (concurrency > MAX_CONCURRENCY)) { + fprintf(stderr, "%s: Invalid Concurrency [Range 0..%d]\n", + argv[0], MAX_CONCURRENCY); + usage(argv[0]); + } + + if (concurrency > requests) { + fprintf(stderr, "%s: Cannot use concurrency level greater than " + "total number of requests\n", argv[0]); + usage(argv[0]); + } + + if ((heartbeatres) && (requests > 150)) { + heartbeatres = requests / 10; /* Print line every 10% of requests */ + if (heartbeatres < 100) + heartbeatres = 100; /* but never more often than once every 100 + * connections. */ + } + else + heartbeatres = 0; + +#ifdef USE_SSL +#ifdef RSAREF + R_malloc_init(); +#else +#if OPENSSL_VERSION_NUMBER < 0x10100000L + CRYPTO_malloc_init(); +#endif +#endif + SSL_load_error_strings(); + SSL_library_init(); + bio_out=BIO_new_fp(stdout,BIO_NOCLOSE); + bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); + + if (!(ssl_ctx = SSL_CTX_new(meth))) { + BIO_printf(bio_err, "Could not initialize SSL Context.\n"); + ERR_print_errors(bio_err); + exit(1); + } + SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + SSL_CTX_set_max_proto_version(ssl_ctx, max_prot); + SSL_CTX_set_min_proto_version(ssl_ctx, min_prot); +#endif +#ifdef SSL_MODE_RELEASE_BUFFERS + /* Keep memory usage as low as possible */ + SSL_CTX_set_mode (ssl_ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + + if (ssl_cipher != NULL) { + int ok; +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && defined(TLS1_3_VERSION) + if (min_prot >= TLS1_3_VERSION) + ok = SSL_CTX_set_ciphersuites(ssl_ctx, ssl_cipher); + else +#endif + ok = SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher); + if (!ok) { + BIO_printf(bio_err, "error setting ciphersuite list [%s]\n", + ssl_cipher); + ERR_print_errors(bio_err); + exit(1); + } + } + + if (verbosity >= 3) { + SSL_CTX_set_info_callback(ssl_ctx, ssl_state_cb); + } + if (ssl_cert != NULL) { + if (SSL_CTX_use_certificate_chain_file(ssl_ctx, ssl_cert) <= 0) { + BIO_printf(bio_err, "unable to get certificate from '%s'\n", + ssl_cert); + ERR_print_errors(bio_err); + exit(1); + } + if (SSL_CTX_use_PrivateKey_file(ssl_ctx, ssl_cert, SSL_FILETYPE_PEM) <= 0) { + BIO_printf(bio_err, "unable to get private key from '%s'\n", + ssl_cert); + ERR_print_errors(bio_err); + exit(1); + } + if (!SSL_CTX_check_private_key(ssl_ctx)) { + BIO_printf(bio_err, + "private key does not match the certificate public key in %s\n", ssl_cert); + exit(1); + } + } + +#endif +#ifdef SIGPIPE + apr_signal(SIGPIPE, SIG_IGN); /* Ignore writes to connections that + * have been closed at the other end. */ +#endif + copyright(); + test(); + apr_pool_destroy(cntxt); + + return 0; +} diff --git a/support/ab.dep b/support/ab.dep new file mode 100644 index 0000000..36eab1d --- /dev/null +++ b/support/ab.dep @@ -0,0 +1,37 @@ +# Microsoft Developer Studio Generated Dependency File, included by ab.mak + +.\ab.c : \ + "..\include\ap_release.h"\ + "..\srclib\apr-util\include\apr_base64.h"\ + "..\srclib\apr-util\include\apr_xlate.h"\ + "..\srclib\apr-util\include\apu.h"\ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_dso.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_getopt.h"\ + "..\srclib\apr\include\apr_global_mutex.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_network_io.h"\ + "..\srclib\apr\include\apr_poll.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_portable.h"\ + "..\srclib\apr\include\apr_proc_mutex.h"\ + "..\srclib\apr\include\apr_shm.h"\ + "..\srclib\apr\include\apr_signal.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_thread_proc.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_want.h"\ + + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + diff --git a/support/ab.dsp b/support/ab.dsp new file mode 100644 index 0000000..7de1c86 --- /dev/null +++ b/support/ab.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="ab" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ab - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ab.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ab.mak" CFG="ab - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ab - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ab - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ab - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/ab_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/ab.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\ab.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "ab - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/ab_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/ab.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\ab.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "ab - Win32 Release" +# Name "ab - Win32 Debug" +# Begin Source File + +SOURCE=.\ab.c +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/ab.mak b/support/ab.mak new file mode 100644 index 0000000..669ac79 --- /dev/null +++ b/support/ab.mak @@ -0,0 +1,317 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on ab.dsp +!IF "$(CFG)" == "" +CFG=ab - Win32 Debug +!MESSAGE No configuration specified. Defaulting to ab - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "ab - Win32 Release" && "$(CFG)" != "ab - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ab.mak" CFG="ab - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ab - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ab - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "ab - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\ab.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\ab.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\ab.obj" + -@erase "$(INTDIR)\ab.res" + -@erase "$(INTDIR)\ab_src.idb" + -@erase "$(INTDIR)\ab_src.pdb" + -@erase "$(OUTDIR)\ab.exe" + -@erase "$(OUTDIR)\ab.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\ab_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\ab.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\ab.pdb" /debug /out:"$(OUTDIR)\ab.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\ab.obj" \ + "$(INTDIR)\ab.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\ab.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\ab.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\ab.exe" + if exist .\Release\ab.exe.manifest mt.exe -manifest .\Release\ab.exe.manifest -outputresource:.\Release\ab.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "ab - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\ab.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\ab.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\ab.obj" + -@erase "$(INTDIR)\ab.res" + -@erase "$(INTDIR)\ab_src.idb" + -@erase "$(INTDIR)\ab_src.pdb" + -@erase "$(OUTDIR)\ab.exe" + -@erase "$(OUTDIR)\ab.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\ab_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\ab.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\ab.pdb" /debug /out:"$(OUTDIR)\ab.exe" +LINK32_OBJS= \ + "$(INTDIR)\ab.obj" \ + "$(INTDIR)\ab.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\ab.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\ab.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\ab.exe" + if exist .\Debug\ab.exe.manifest mt.exe -manifest .\Debug\ab.exe.manifest -outputresource:.\Debug\ab.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("ab.dep") +!INCLUDE "ab.dep" +!ELSE +!MESSAGE Warning: cannot find "ab.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "ab - Win32 Release" || "$(CFG)" == "ab - Win32 Debug" + +!IF "$(CFG)" == "ab - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "ab - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "ab - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "ab - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=.\ab.c + +"$(INTDIR)\ab.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "ab - Win32 Release" + + +"$(INTDIR)\ab.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility" $(SOURCE) + + +!ELSEIF "$(CFG)" == "ab - Win32 Debug" + + +"$(INTDIR)\ab.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench command line utility" $(SOURCE) + + +!ENDIF + + +!ENDIF + diff --git a/support/abs.dep b/support/abs.dep new file mode 100644 index 0000000..4b6f12f --- /dev/null +++ b/support/abs.dep @@ -0,0 +1,37 @@ +# Microsoft Developer Studio Generated Dependency File, included by abs.mak + +.\ab.c : \ + "..\include\ap_release.h"\ + "..\srclib\apr-util\include\apr_base64.h"\ + "..\srclib\apr-util\include\apr_xlate.h"\ + "..\srclib\apr-util\include\apu.h"\ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_dso.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_getopt.h"\ + "..\srclib\apr\include\apr_global_mutex.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_network_io.h"\ + "..\srclib\apr\include\apr_poll.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_portable.h"\ + "..\srclib\apr\include\apr_proc_mutex.h"\ + "..\srclib\apr\include\apr_shm.h"\ + "..\srclib\apr\include\apr_signal.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_thread_proc.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_want.h"\ + + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + diff --git a/support/abs.dsp b/support/abs.dsp new file mode 100644 index 0000000..bb407eb --- /dev/null +++ b/support/abs.dsp @@ -0,0 +1,144 @@ +# Microsoft Developer Studio Project File - Name="abs" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=abs - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "abs.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "abs.mak" CFG="abs - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "abs - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "abs - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "abs - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "SSL" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /I "../srclib/openssl/inc32" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fd"Release/abs_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/ab.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /libpath:"../srclib/openssl/out32dll" +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /debug /libpath:"../srclib/openssl/out32dll" /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\abs.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "abs - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "SSL" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /I "../srclib/openssl/inc32" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fd"Debug/abs_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/ab.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /incremental:no /debug /libpath:"../srclib/openssl/out32dll" +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib ssleay32.lib libeay32.lib /nologo /subsystem:console /incremental:no /debug /libpath:"../srclib/openssl/out32dll" +# Begin Special Build Tool +TargetPath=.\Debug\abs.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "abs - Win32 Release" +# Name "abs - Win32 Debug" +# Begin Source File + +SOURCE=.\ab.c + +!IF "$(CFG)" == "abs - Win32 Release" + +# ADD CPP /Fo"Release/abs.obj" + +!ELSEIF "$(CFG)" == "abs - Win32 Debug" + +# ADD CPP /Fo"Debug/abs.obj" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=../include\ap_release.h + +!IF "$(CFG)" == "abs - Win32 Release" + +# Begin Custom Build - Create applink.c from ms/applink.c +InputPath=../include\ap_release.h + +"..\srclib\openssl\include\openssl\applink.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + IF EXIST ..\srclib\openssl\ms\applink.c type ..\srclib\openssl\ms\applink.c > ..\srclib\openssl\include\openssl\applink.c + +# End Custom Build + +!ELSEIF "$(CFG)" == "abs - Win32 Debug" + +# Begin Custom Build - Create applink.c from ms/applink.c +InputPath=../include\ap_release.h + +"..\srclib\openssl\include\openssl\applink.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + IF EXIST ..\srclib\openssl\ms\applink.c type ..\srclib\openssl\ms\applink.c > ..\srclib\openssl\include\openssl\applink.c + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/abs.mak b/support/abs.mak new file mode 100644 index 0000000..81da635 --- /dev/null +++ b/support/abs.mak @@ -0,0 +1,374 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on abs.dsp +!IF "$(CFG)" == "" +CFG=abs - Win32 Debug +!MESSAGE No configuration specified. Defaulting to abs - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "abs - Win32 Release" && "$(CFG)" != "abs - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "abs.mak" CFG="abs - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "abs - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "abs - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(_HAVE_OSSL110)" == "1" +SSLCRP=libcrypto +SSLLIB=libssl +SSLINC=/I ../srclib/openssl/include +SSLBIN=/libpath:../srclib/openssl +!ELSE +SSLCRP=libeay32 +SSLLIB=ssleay32 +SSLINC=/I ../srclib/openssl/inc32 +SSLBIN=/libpath:../srclib/openssl/out32dll +!ENDIF + +!IF "$(CFG)" == "abs - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "..\srclib\openssl\include\openssl\applink.c" "$(OUTDIR)\abs.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "..\srclib\openssl\include\openssl\applink.c" "$(OUTDIR)\abs.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\ab.res" + -@erase "$(INTDIR)\abs.obj" + -@erase "$(INTDIR)\abs_src.idb" + -@erase "$(INTDIR)\abs_src.pdb" + -@erase "$(OUTDIR)\abs.exe" + -@erase "$(OUTDIR)\abs.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" $(SSLINC) /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\abs_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\abs.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib $(SSLCRP).lib $(SSLLIB).lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\abs.pdb" /debug /out:"$(OUTDIR)\abs.exe" $(SSLBIN) /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\abs.obj" \ + "$(INTDIR)\ab.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\abs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\abs.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\abs.exe" + if exist .\Release\abs.exe.manifest mt.exe -manifest .\Release\abs.exe.manifest -outputresource:.\Release\abs.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "abs - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "..\srclib\openssl\include\openssl\applink.c" "$(OUTDIR)\abs.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "..\srclib\openssl\include\openssl\applink.c" "$(OUTDIR)\abs.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\ab.res" + -@erase "$(INTDIR)\abs.obj" + -@erase "$(INTDIR)\abs_src.idb" + -@erase "$(INTDIR)\abs_src.pdb" + -@erase "$(OUTDIR)\abs.exe" + -@erase "$(OUTDIR)\abs.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" $(SSLINC) /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\abs_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\abs.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib $(SSLCRP).lib $(SSLLIB).lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\abs.pdb" /debug /out:"$(OUTDIR)\abs.exe" $(SSLBIN) +LINK32_OBJS= \ + "$(INTDIR)\abs.obj" \ + "$(INTDIR)\ab.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\abs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\abs.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\abs.exe" + if exist .\Debug\abs.exe.manifest mt.exe -manifest .\Debug\abs.exe.manifest -outputresource:.\Debug\abs.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("abs.dep") +!INCLUDE "abs.dep" +!ELSE +!MESSAGE Warning: cannot find "abs.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "abs - Win32 Release" || "$(CFG)" == "abs - Win32 Debug" + +!IF "$(CFG)" == "abs - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "abs - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "abs - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "abs - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=.\ab.c + +!IF "$(CFG)" == "abs - Win32 Release" + +CPP_SWITCHES=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" $(SSLINC) /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fo"$(INTDIR)\abs.obj" /Fd"$(INTDIR)\abs_src" /FD /c + +"$(INTDIR)\abs.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) @<< + $(CPP_SWITCHES) $(SOURCE) +<< + + +!ELSEIF "$(CFG)" == "abs - Win32 Debug" + +CPP_SWITCHES=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" $(SSLINC) /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /D "HAVE_OPENSSL" /D "WIN32_LEAN_AND_MEAN" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /Fo"$(INTDIR)\abs.obj" /Fd"$(INTDIR)\abs_src" /FD /EHsc /c + +"$(INTDIR)\abs.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) @<< + $(CPP_SWITCHES) $(SOURCE) +<< + + +!ENDIF + +SOURCE=../include\ap_release.h + +!IF "$(CFG)" == "abs - Win32 Release" + +InputPath=../include\ap_release.h + +"..\srclib\openssl\include\openssl\applink.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + <<tempfile.bat + @echo off + IF EXIST ..\srclib\openssl\ms\applink.c type ..\srclib\openssl\ms\applink.c > ..\srclib\openssl\include\openssl\applink.c +<< + + +!ELSEIF "$(CFG)" == "abs - Win32 Debug" + +InputPath=../include\ap_release.h + +"..\srclib\openssl\include\openssl\applink.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + <<tempfile.bat + @echo off + IF EXIST ..\srclib\openssl\ms\applink.c type ..\srclib\openssl\ms\applink.c > ..\srclib\openssl\include\openssl\applink.c +<< + + +!ENDIF + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "abs - Win32 Release" + + +"$(INTDIR)\ab.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility" $(SOURCE) + + +!ELSEIF "$(CFG)" == "abs - Win32 Debug" + + +"$(INTDIR)\ab.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\ab.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="ab.exe" /d LONG_NAME="ApacheBench/SSL command line utility" $(SOURCE) + + +!ENDIF + + +!ENDIF + diff --git a/support/apachectl.in b/support/apachectl.in new file mode 100644 index 0000000..3281c2e --- /dev/null +++ b/support/apachectl.in @@ -0,0 +1,106 @@ +#!/bin/sh +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# Apache control script designed to allow an easy command line interface +# to controlling Apache. Written by Marc Slemko, 1997/08/23 +# +# The exit codes returned are: +# XXX this doc is no longer correct now that the interesting +# XXX functions are handled by httpd +# 0 - operation completed successfully +# 1 - +# 2 - usage error +# 3 - httpd could not be started +# 4 - httpd could not be stopped +# 5 - httpd could not be started during a restart +# 6 - httpd could not be restarted during a restart +# 7 - httpd could not be restarted during a graceful restart +# 8 - configuration syntax error +# +# When multiple arguments are given, only the error from the _last_ +# one is reported. Run "apachectl help" for usage info +# +ACMD="$1" +ARGV="$@" +# +# |||||||||||||||||||| START CONFIGURATION SECTION |||||||||||||||||||| +# -------------------- -------------------- +# +# the path to your httpd binary, including options if necessary +HTTPD='@exp_sbindir@/@progname@' +# +# pick up any necessary environment variables +if test -f @exp_sbindir@/envvars; then + . @exp_sbindir@/envvars +fi +# +# a command that outputs a formatted text version of the HTML at the +# url given on the command line. Designed for lynx, however other +# programs may work. +LYNX="@LYNX_PATH@ -dump" +# +# the URL to your server's mod_status status page. If you do not +# have one, then status and fullstatus will not work. +STATUSURL="http://localhost:@PORT@/server-status" +# +# Set this variable to a command that increases the maximum +# number of file descriptors allowed per child process. This is +# critical for configurations that use many file descriptors, +# such as mass vhosting, or a multithreaded server. +ULIMIT_MAX_FILES="@APACHECTL_ULIMIT@" +# -------------------- -------------------- +# |||||||||||||||||||| END CONFIGURATION SECTION |||||||||||||||||||| + +# Set the maximum number of file descriptors allowed per child process. +if [ "x$ULIMIT_MAX_FILES" != "x" ] ; then + $ULIMIT_MAX_FILES +fi + +ERROR=0 +if [ "x$ARGV" = "x" ] ; then + ARGV="-h" +fi + +case $ACMD in +start|stop|restart|graceful|graceful-stop) + $HTTPD -k $ARGV + ERROR=$? + ;; +startssl|sslstart|start-SSL) + echo The startssl option is no longer supported. + echo Please edit httpd.conf to include the SSL configuration settings + echo and then use "apachectl start". + ERROR=2 + ;; +configtest) + $HTTPD -t + ERROR=$? + ;; +status) + $LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } ' + ;; +fullstatus) + $LYNX $STATUSURL + ;; +*) + $HTTPD "$@" + ERROR=$? +esac + +exit $ERROR + diff --git a/support/apxs.in b/support/apxs.in new file mode 100644 index 0000000..b2705fa --- /dev/null +++ b/support/apxs.in @@ -0,0 +1,801 @@ +#!@perlbin@ -w +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 5.004; +use strict; +package apxs; + +## +## Configuration +## + +# are we building in a cross compile environment? If so, destdir contains +# the base directory of the cross compiled environment, otherwise destdir +# is the empty string. + +my $destdir = ""; +my $ddi = rindex($0, "@exp_bindir@"); +if ($ddi >= 0) { + $destdir = substr($0, 0, $ddi); +} + +my %config_vars = (); + +my $installbuilddir = "@exp_installbuilddir@"; +get_config_vars($destdir . "$installbuilddir/config_vars.mk",\%config_vars); + +# read the configuration variables once + +my $prefix = get_vars("prefix"); +my $CFG_PREFIX = $prefix; +my $exec_prefix = get_vars("exec_prefix"); +my $datadir = get_vars("datadir"); +my $localstatedir = get_vars("localstatedir"); +my $CFG_TARGET = get_vars("progname"); +my $CFG_SYSCONFDIR = get_vars("sysconfdir"); +my $CFG_CFLAGS = join ' ', map { get_vars($_) } + qw(SHLTCFLAGS CFLAGS NOTEST_CPPFLAGS EXTRA_CPPFLAGS EXTRA_CFLAGS); +my $CFG_LDFLAGS = join ' ', map { get_vars($_) } + qw(LDFLAGS NOTEST_LDFLAGS SH_LDFLAGS); +my $includedir = $destdir . get_vars("includedir"); +my $CFG_INCLUDEDIR = eval qq("$includedir"); +my $CFG_CC = get_vars("CC"); +my $libexecdir = $destdir . get_vars("libexecdir"); +my $CFG_LIBEXECDIR = eval qq("$libexecdir"); +my $sbindir = get_vars("sbindir"); +my $CFG_SBINDIR = eval qq("$sbindir"); +my $ltflags = $ENV{'LTFLAGS'}; +$ltflags or $ltflags = "--silent"; + +my %internal_vars = map {$_ => 1} + qw(TARGET CC CFLAGS CFLAGS_SHLIB LD_SHLIB LDFLAGS_SHLIB LIBS_SHLIB + PREFIX SBINDIR INCLUDEDIR LIBEXECDIR SYSCONFDIR); + +## +## parse argument line +## + +# defaults for parameters +my $opt_n = ''; +my $opt_g = ''; +my $opt_c = 0; +my $opt_o = ''; +my @opt_D = (); +my @opt_I = (); +my @opt_L = (); +my @opt_l = (); +my @opt_W = (); +my @opt_S = (); +my $opt_e = 0; +my $opt_i = 0; +my $opt_a = 0; +my $opt_A = 0; +my $opt_q = 0; +my $opt_h = 0; +my $opt_p = 0; +my $opt_v = 0; + +# this subroutine is derived from Perl's getopts.pl with the enhancement of +# the "+" metacharacter at the format string to allow a list to be built by +# subsequent occurrences of the same option. +sub Getopts { + my ($argumentative, @ARGV) = @_; + my $errs = 0; + local $_; + + my @args = split / */, $argumentative; + while (@ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) { + my ($first, $rest) = ($1,$2); + if ($_ =~ m|^--$|) { + shift @ARGV; + last; + } + my $pos = index($argumentative,$first); + if ($pos >= 0) { + if ($pos < $#args && $args[$pos+1] eq ':') { + shift @ARGV; + if ($rest eq '') { + unless (@ARGV) { + error("Incomplete option: $first (needs an argument)"); + $errs++; + } + $rest = shift(@ARGV); + } + eval "\$opt_$first = \$rest;"; + } + elsif ($pos < $#args && $args[$pos+1] eq '+') { + shift @ARGV; + if ($rest eq '') { + unless (@ARGV) { + error("Incomplete option: $first (needs an argument)"); + $errs++; + } + $rest = shift(@ARGV); + } + eval "push(\@opt_$first, \$rest);"; + } + else { + eval "\$opt_$first = 1"; + if ($rest eq '') { + shift(@ARGV); + } + else { + $ARGV[0] = "-$rest"; + } + } + } + else { + error("Unknown option: $first"); + $errs++; + if ($rest ne '') { + $ARGV[0] = "-$rest"; + } + else { + shift(@ARGV); + } + } + } + return ($errs == 0, @ARGV); +} + +sub usage { + print STDERR "Usage: apxs -g [-S <var>=<val>] -n <modname>\n"; + print STDERR " apxs -q [-v] [-S <var>=<val>] [<query> ...]\n"; + print STDERR " apxs -c [-S <var>=<val>] [-o <dsofile>] [-D <name>[=<value>]]\n"; + print STDERR " [-I <incdir>] [-L <libdir>] [-l <libname>] [-Wc,<flags>]\n"; + print STDERR " [-Wl,<flags>] [-p] <files> ...\n"; + print STDERR " apxs -i [-S <var>=<val>] [-a] [-A] [-n <modname>] <dsofile> ...\n"; + print STDERR " apxs -e [-S <var>=<val>] [-a] [-A] [-n <modname>] <dsofile> ...\n"; + exit(1); +} + +# option handling +my $rc; +($rc, @ARGV) = &Getopts("qn:gco:I+D+L+l+W+S+eiaApv", @ARGV); +&usage if ($rc == 0); +&usage if ($#ARGV == -1 and not $opt_g and not $opt_q); +&usage if (not $opt_q and not ($opt_g and $opt_n) and not $opt_i and not $opt_c and not $opt_e); + +# argument handling +my @args = @ARGV; +my $name = 'unknown'; +$name = $opt_n if ($opt_n ne ''); + +if (@opt_S) { + my ($opt_S); + foreach $opt_S (@opt_S) { + if ($opt_S =~ m/^([^=]+)=(.*)$/) { + my ($var) = $1; + my ($val) = $2; + my $oldval = eval "\$CFG_$var"; + + unless ($var and $oldval) { + print STDERR "apxs:Error: no config variable $var\n"; + &usage; + } + + eval "\$CFG_${var}=\"${val}\""; + } else { + print STDERR "apxs:Error: malformatted -S option\n"; + &usage; + } + } +} + +## +## Initial shared object support check +## +unless ("@MOD_SO_ENABLED@" eq "yes") { + error("Sorry, no shared object support for Apache"); + error("available under your platform. Make sure"); + error("the Apache module mod_so is compiled into"); + error("the server binary."); + exit 1; +} + +sub get_config_vars{ + my ($file, $rh_config) = @_; + + open IN, $file or die "cannot open $file: $!"; + while (<IN>){ + if (/^\s*(.*?)\s*=\s*(.*)$/){ + $rh_config->{$1} = $2; + } + } + close IN; +} + +sub get_vars { + my $result = ''; + my $ok = 0; + my $arg; + foreach $arg (@_) { + if (exists $config_vars{$arg} or exists $config_vars{lc $arg}) { + my $val = exists $config_vars{$arg} + ? $config_vars{$arg} + : $config_vars{lc $arg}; + $val =~ s/[()]//g; + $result .= eval "qq($val)" if defined $val; + $result .= ";;"; + $ok = 1; + } + if (not $ok) { + if (exists $internal_vars{$arg} or exists $internal_vars{lc $arg}) { + my $val = exists $internal_vars{$arg} ? $arg : lc $arg; + $val = eval "\$CFG_$val"; + $result .= eval "qq($val)" if defined $val; + $result .= ";;"; + $ok = 1; + } + if (not $ok) { + error("Invalid query string `$arg'"); + exit(1); + } + } + } + $result =~ s|;;$||; + return $result; +} + +## +## Operation +## + +# helper function for executing a list of +# system command with return code checks +sub execute_cmds { + my (@cmds) = @_; + my ($cmd, $rc); + + foreach $cmd (@cmds) { + notice($cmd); + $rc = system $cmd; + if ($rc) { + error(sprintf "Command failed with rc=%d\n", $rc << 8); + exit 1 ; + } + } +} + +if ($opt_g) { + ## + ## SAMPLE MODULE SOURCE GENERATION + ## + + if (-d $name) { + error("Directory `$name' already exists. Remove first"); + exit(1); + } + + my $data = join('', <DATA>); + $data =~ s|%NAME%|$name|sg; + $data =~ s|%TARGET%|$CFG_TARGET|sg; + $data =~ s|%PREFIX%|$prefix|sg; + $data =~ s|%INSTALLBUILDDIR%|$installbuilddir|sg; + + my ($mkf, $mods, $src) = ($data =~ m|^(.+)-=#=-\n(.+)-=#=-\n(.+)|s); + + notice("Creating [DIR] $name"); + system("mkdir $name"); + notice("Creating [FILE] $name/Makefile"); + open(FP, ">${name}/Makefile") || die; + print FP $mkf; + close(FP); + notice("Creating [FILE] $name/modules.mk"); + open(FP, ">${name}/modules.mk") || die; + print FP $mods; + close(FP); + notice("Creating [FILE] $name/mod_$name.c"); + open(FP, ">${name}/mod_${name}.c") || die; + print FP $src; + close(FP); + notice("Creating [FILE] $name/.deps"); + system("touch ${name}/.deps"); + + exit(0); +} + + +if ($opt_q) { + ## + ## QUERY INFORMATION + ## + my $result; + if ($#args >= 0) { + $result = get_vars(@args); + print "$result\n"; + } else { + # -q without var name prints all variables and their values + + # Additional -v pretty-prints output + if ($opt_v) { + # Variable names in alphabetic order + my @vars = sort {uc($a) cmp uc($b)} keys %config_vars; + + # Make the left column as wide as the longest variable name + my $width = 0; + foreach (@vars) { + my $l = length $_; + $width = $l unless ($l <= $width); + } + + foreach (@vars) { + printf "%-${width}s = %s\n", $_, $config_vars{$_}; + } + } else { + # Unprettified name=value list + foreach (keys %config_vars) { + print "$_=$config_vars{$_}\n"; + } + } + } +} + +my $apr_config = $destdir . get_vars("APR_CONFIG"); + +if (! -x "$apr_config") { + error("$apr_config not found!"); + exit(1); +} + +my $apr_major_version = (split /\./, `$apr_config --version`)[0]; + +my $apu_config = ""; +if ($apr_major_version < 2) { + $apu_config = $destdir . get_vars("APU_CONFIG"); + + if (! -x "$apu_config") { + error("$apu_config not found!"); + exit(1); + } +} + +my $libtool = `$apr_config --apr-libtool`; +chomp($libtool); + +my $apr_includedir = `$apr_config --includes`; +chomp($apr_includedir); +my $apu_includedir = ""; +if ($apr_major_version < 2) { + $apu_includedir = `$apu_config --includes`; + chomp($apu_includedir); +} + +if ($opt_c) { + ## + ## SHARED OBJECT COMPILATION + ## + + # split files into sources and objects + my @srcs = (); + my @objs = (); + my $f; + foreach $f (@args) { + if ($f =~ m|\.c$|) { + push(@srcs, $f); + } + else { + push(@objs, $f); + } + } + + # determine output file + my $dso_file; + if ($opt_o eq '') { + if ($#srcs > -1) { + $dso_file = $srcs[0]; + $dso_file =~ s|\.[^.]+$|.la|; + } + elsif ($#objs > -1) { + $dso_file = $objs[0]; + $dso_file =~ s|\.[^.]+$|.la|; + } + else { + $dso_file = "mod_unknown.la"; + } + } + else { + $dso_file = $opt_o; + $dso_file =~ s|\.[^.]+$|.la|; + } + + # create compilation commands + my @cmds = (); + my $opt = ''; + my ($opt_Wc, $opt_I, $opt_D); + foreach $opt_Wc (@opt_W) { + $opt .= "$1 " if ($opt_Wc =~ m|^\s*c,(.*)$|); + } + foreach $opt_I (@opt_I) { + $opt .= "-I$opt_I "; + } + foreach $opt_D (@opt_D) { + $opt .= "-D$opt_D "; + } + my $cflags = "$CFG_CFLAGS"; + my $s; + my $mod; + foreach $s (@srcs) { + my $slo = $s; + $slo =~ s|\.c$|.slo|; + my $lo = $s; + $lo =~ s|\.c$|.lo|; + my $la = $s; + $la =~ s|\.c$|.la|; + my $o = $s; + $o =~ s|\.c$|.o|; + push(@cmds, "$libtool $ltflags --mode=compile $CFG_CC $cflags -I$CFG_INCLUDEDIR $apr_includedir $apu_includedir $opt -c -o $lo $s && touch $slo"); + unshift(@objs, $lo); + } + + # create link command + my $o; + my $lo; + foreach $o (@objs) { + $lo .= " $o"; + } + my ($opt_Wl, $opt_L, $opt_l); + $opt = ''; + foreach $opt_Wl (@opt_W) { + $opt .= "$1 " if ($opt_Wl =~ m|^\s*l,(.*)$|); + } + foreach $opt_L (@opt_L) { + $opt .= " -L$opt_L"; + } + foreach $opt_l (@opt_l) { + $opt .= " -l$opt_l"; + } + + my $ldflags = "$CFG_LDFLAGS"; + if ($opt_p == 1) { + + my $apr_libs=`$apr_config --cflags --ldflags --link-libtool --libs`; + chomp($apr_libs); + my $apu_libs=""; + if ($apr_major_version < 2) { + $apu_libs=`$apu_config --ldflags --link-libtool --libs`; + chomp($apu_libs); + } + + $opt .= " ".$apu_libs." ".$apr_libs; + } + else { + my $apr_ldflags=`$apr_config --ldflags`; + chomp($apr_ldflags); + $opt .= " -rpath $CFG_LIBEXECDIR -module -avoid-version $apr_ldflags"; + } + + push(@cmds, "$libtool $ltflags --mode=link $CFG_CC $ldflags -o $dso_file $opt $lo"); + + # execute the commands + &execute_cmds(@cmds); + + # allow one-step compilation and installation + if ($opt_i or $opt_e) { + @args = ( $dso_file ); + } +} + +if ($opt_i or $opt_e) { + ## + ## SHARED OBJECT INSTALLATION + ## + + # determine installation commands + # and corresponding LoadModule directive + my @lmd = (); + my @cmds = (); + my $f; + foreach $f (@args) { + # ack all potential gcc, hp/ux, win32+os2+aix and os/x extensions + if ($f !~ m#(\.so$|\.la$|\.sl$|\.dll$|\.dylib$|)#) { + error("file $f is not a shared object"); + exit(1); + } + my $t = $f; + $t =~ s|^.+/([^/]+)$|$1|; + # use .so unambigiously for installed shared library modules + $t =~ s|\.[^./\\]+$|\.so|; + if ($opt_i) { + push(@cmds, $destdir . "$installbuilddir/instdso.sh SH_LIBTOOL='" . + "$libtool' $f $CFG_LIBEXECDIR"); + push(@cmds, "chmod 755 $CFG_LIBEXECDIR/$t"); + } + + # determine module symbolname and filename + my $filename = ''; + if ($name eq 'unknown') { + $name = ''; + my $base = $f; + $base =~ s|\.[^.]+$||; + if (-f "$base.c") { + open(FP, "<$base.c"); + my $content = join('', <FP>); + close(FP); + if ($content =~ m|.*AP_DECLARE_MODULE\s*\(\s*([a-zA-Z0-9_]+)\s*\)\s*=.*|s || $content =~ m|.*module\s+(?:AP_MODULE_DECLARE_DATA\s+)?([a-zA-Z0-9_]+)_module\s*=\s*.*|s) { + $name = "$1"; + $filename = "$base.c"; + $filename =~ s|^[^/]+/||; + } + } + if ($name eq '') { + if ($base =~ m|.*mod_([a-zA-Z0-9_]+)\..+|) { + $name = "$1"; + $filename = $base; + $filename =~ s|^[^/]+/||; + } + } + if ($name eq '') { + error("Sorry, cannot determine bootstrap symbol name"); + error("Please specify one with option `-n'"); + exit(1); + } + } + if ($filename eq '') { + $filename = "mod_${name}.c"; + } + my $dir = $CFG_LIBEXECDIR; + $dir =~ s|^$CFG_PREFIX/?||; + $dir =~ s|(.)$|$1/|; + $t =~ s|\.la$|.so|; + push(@lmd, sprintf("LoadModule %-18s %s", "${name}_module", "$dir$t")); + } + + # execute the commands + &execute_cmds(@cmds); + + # activate module via LoadModule/AddModule directive + if ($opt_a or $opt_A) { + if (not -f "$CFG_SYSCONFDIR/$CFG_TARGET.conf") { + error("Config file $CFG_SYSCONFDIR/$CFG_TARGET.conf not found"); + exit(1); + } + + open(FP, "<$CFG_SYSCONFDIR/$CFG_TARGET.conf") || die; + my $content = join('', <FP>); + close(FP); + + if ($content !~ m|\n#?\s*LoadModule\s+|) { + error("Activation failed for custom $CFG_SYSCONFDIR/$CFG_TARGET.conf file."); + error("At least one `LoadModule' directive already has to exist."); + exit(1); + } + + my $lmd; + my $c = ''; + $c = '#' if ($opt_A); + foreach $lmd (@lmd) { + my $what = $opt_A ? "preparing" : "activating"; + my $lmd_re = $lmd; + $lmd_re =~ s/\s+/\\s+/g; + + if ($content !~ m|\n#?\s*$lmd_re|) { + # check for open <containers>, so that the new LoadModule + # directive always appears *outside* of an <container>. + + my $before = ($content =~ m|^(.*\n)#?\s*LoadModule\s+[^\n]+\n|s)[0]; + + # the '()=' trick forces list context and the scalar + # assignment counts the number of list members (aka number + # of matches) then + my $cntopen = () = ($before =~ m|^\s*<[^/].*$|mg); + my $cntclose = () = ($before =~ m|^\s*</.*$|mg); + + if ($cntopen == $cntclose) { + # fine. Last LoadModule is contextless. + $content =~ s|^(.*\n#?\s*LoadModule\s+[^\n]+\n)|$1$c$lmd\n|s; + } + elsif ($cntopen < $cntclose) { + error('Configuration file is not valid. There are sections' + . ' closed before opened.'); + exit(1); + } + else { + # put our cmd after the section containing the last + # LoadModule. + my $found = + $content =~ s!\A ( # string and capture start + (?:(?: + ^\s* # start of conf line with a + (?:[^<]|<[^/]) # directive which does not + # start with '</' + + .*(?:$)\n # rest of the line. + # the '$' is in parentheses + # to avoid misinterpreting + # the string "$\" as + # perl variable. + + )* # catch as much as possible + # of such lines. (including + # zero) + + ^\s*</.*(?:$)\n? # after the above, we + # expect a config line with + # a closing container (</) + + ) {$cntopen} # the whole pattern (bunch + # of lines that end up with + # a closing directive) must + # be repeated $cntopen + # times. That's it. + # Simple, eh? ;-) + + ) # capture end + !$1$c$lmd\n!mx; + + unless ($found) { + error('Configuration file is not valid. There are ' + . 'sections opened and not closed.'); + exit(1); + } + } + } else { + # replace already existing LoadModule line + $content =~ s|^(.*\n)#?\s*$lmd_re[^\n]*\n|$1$c$lmd\n|s; + } + $lmd =~ m|LoadModule\s+(.+?)_module.*|; + notice("[$what module `$1' in $CFG_SYSCONFDIR/$CFG_TARGET.conf]"); + } + if (@lmd) { + if (open(FP, ">$CFG_SYSCONFDIR/$CFG_TARGET.conf.new")) { + print FP $content; + close(FP); + system("cp $CFG_SYSCONFDIR/$CFG_TARGET.conf $CFG_SYSCONFDIR/$CFG_TARGET.conf.bak && " . + "cp $CFG_SYSCONFDIR/$CFG_TARGET.conf.new $CFG_SYSCONFDIR/$CFG_TARGET.conf && " . + "rm $CFG_SYSCONFDIR/$CFG_TARGET.conf.new"); + } else { + notice("unable to open configuration file"); + } + } + } +} + +sub error{ + print STDERR "apxs:Error: $_[0].\n"; +} + +sub notice{ + print STDERR "$_[0]\n"; +} + +##EOF## +__DATA__ +## +## Makefile -- Build procedure for sample %NAME% Apache module +## Autogenerated via ``apxs -n %NAME% -g''. +## + +builddir=. +top_srcdir=%PREFIX% +top_builddir=%PREFIX% +include %INSTALLBUILDDIR%/special.mk + +# the used tools +APACHECTL=apachectl + +# additional defines, includes and libraries +#DEFS=-Dmy_define=my_value +#INCLUDES=-Imy/include/dir +#LIBS=-Lmy/lib/dir -lmylib + +# the default target +all: local-shared-build + +# install the shared object file into Apache +install: install-modules-yes + +# cleanup +clean: + -rm -f mod_%NAME%.o mod_%NAME%.lo mod_%NAME%.slo mod_%NAME%.la + +# simple test +test: reload + lynx -mime_header http://localhost/%NAME% + +# install and activate shared object by reloading Apache to +# force a reload of the shared object file +reload: install restart + +# the general Apache start/restart/stop +# procedures +start: + $(APACHECTL) start +restart: + $(APACHECTL) restart +stop: + $(APACHECTL) stop + +-=#=- +mod_%NAME%.la: mod_%NAME%.slo + $(SH_LINK) -rpath $(libexecdir) -module -avoid-version mod_%NAME%.lo +DISTCLEAN_TARGETS = modules.mk +shared = mod_%NAME%.la +-=#=- +/* +** mod_%NAME%.c -- Apache sample %NAME% module +** [Autogenerated via ``apxs -n %NAME% -g''] +** +** To play with this sample module first compile it into a +** DSO file and install it into Apache's modules directory +** by running: +** +** $ apxs -c -i mod_%NAME%.c +** +** Then activate it in Apache's %TARGET%.conf file for instance +** for the URL /%NAME% in as follows: +** +** # %TARGET%.conf +** LoadModule %NAME%_module modules/mod_%NAME%.so +** <Location /%NAME%> +** SetHandler %NAME% +** </Location> +** +** Then after restarting Apache via +** +** $ apachectl restart +** +** you immediately can request the URL /%NAME% and watch for the +** output of this module. This can be achieved for instance via: +** +** $ lynx -mime_header http://localhost/%NAME% +** +** The output should be similar to the following one: +** +** HTTP/1.1 200 OK +** Date: Tue, 31 Mar 1998 14:42:22 GMT +** Server: Apache/1.3.4 (Unix) +** Connection: close +** Content-Type: text/html +** +** The sample page from mod_%NAME%.c +*/ + +#include "httpd.h" +#include "http_config.h" +#include "http_protocol.h" +#include "ap_config.h" + +/* The sample content handler */ +static int %NAME%_handler(request_rec *r) +{ + if (strcmp(r->handler, "%NAME%")) { + return DECLINED; + } + r->content_type = "text/html"; + + if (!r->header_only) + ap_rputs("The sample page from mod_%NAME%.c\n", r); + return OK; +} + +static void %NAME%_register_hooks(apr_pool_t *p) +{ + ap_hook_handler(%NAME%_handler, NULL, NULL, APR_HOOK_MIDDLE); +} + +/* Dispatch list for API hooks */ +module AP_MODULE_DECLARE_DATA %NAME%_module = { + STANDARD20_MODULE_STUFF, + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + NULL, /* table of config file commands */ + %NAME%_register_hooks /* register hooks */ +}; + diff --git a/support/check_forensic b/support/check_forensic new file mode 100755 index 0000000..d7a3f78 --- /dev/null +++ b/support/check_forensic @@ -0,0 +1,51 @@ +#!/bin/sh + +# check_forensic <forensic log file> + +# check the forensic log for requests that did not complete +# output the request log for each one + +F=$1 + +temp_create_method=file +if test -f `which mktemp`; then + temp_create_method=mktemp +elif test -f `which tempfile`; then + temp_create_method=tempfile +fi + +create_temp() +{ + prefix=$1 + case "$temp_create_method" in + file) + name="/tmp/$1.$$" + ;; + mktemp) + name=`mktemp -t $1.XXXXXX` + ;; + tempfile) + name=`tempfile --prefix=$1` + ;; + *) + echo "$0: Cannot create temporary file" + exit 1 + ;; + esac +} + +create_temp fcall +all=$name +create_temp fcin +in=$name +create_temp fcout +out=$name +trap "rm -f -- \"$all\" \"$in\" \"$out\";" 0 1 2 3 13 15 + +cut -f 1 -d '|' $F > $all +grep ^+ < $all | cut -c2- | sort > $in +grep -- ^- < $all | cut -c2- | sort > $out + +# use -i instead of -I for GNU xargs +join -v 1 $in $out | xargs -I xx egrep "^\\+xx" $F +exit 0 diff --git a/support/checkgid.c b/support/checkgid.c new file mode 100644 index 0000000..29de650 --- /dev/null +++ b/support/checkgid.c @@ -0,0 +1,110 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Given one or more group identifiers on the command line (e.g., + * "httpd" or "#-1"), figure out whether they'll be valid for + * the server to use at run-time. + * + * If a groupname isn't found, or we can't setgid() to it, return + * -1. If all groups are valid, return 0. + * + * This may need to be run as the superuser for the setgid() to + * succeed; running it as any other user may result in a false + * negative. + */ + +#include "ap_config.h" +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_GRP_H +#include <grp.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +int main(int argc, char *argv[]) +{ + int i; + int result; + gid_t gid; + struct group *grent; + struct group fake_grent; + + /* + * Assume success. :-) + */ + result = 0; + for (i = 1; i < argc; ++i) { + char *arg; + arg = argv[i]; + + /* + * If it's from a 'Group #-1' statement, get the numeric value + * and skip the group lookup stuff. + */ + if (*arg == '#') { + gid = atoi(&arg[1]); + fake_grent.gr_gid = gid; + grent = &fake_grent; + } + else { + grent = getgrnam(arg); + } + + /* + * A NULL return means no such group was found, so we're done + * with this one. + */ + if (grent == NULL) { + fprintf(stderr, "%s: group '%s' not found\n", argv[0], arg); + result = -1; + } + else { + int check; + + /* + * See if we can switch to the numeric GID we have. If so, + * all well and good; if not, well.. + */ + gid = grent->gr_gid; + check = setgid(gid); + if (check != 0) { + fprintf(stderr, "%s: invalid group '%s'\n", argv[0], arg); + perror(argv[0]); + result = -1; + } + } + } + /* + * Worst-case return value. + */ + return result; +} +/* + * Local Variables: + * mode: C + * c-file-style: "bsd" + * End: + */ diff --git a/support/config.m4 b/support/config.m4 new file mode 100644 index 0000000..4865e38 --- /dev/null +++ b/support/config.m4 @@ -0,0 +1,151 @@ +htpasswd_LTFLAGS="" +htdigest_LTFLAGS="" +rotatelogs_LTFLAGS="" +logresolve_LTFLAGS="" +htdbm_LTFLAGS="" +ab_LTFLAGS="" +checkgid_LTFLAGS="" +htcacheclean_LTFLAGS="" +httxt2dbm_LTFLAGS="" +fcgistarter_LTFLAGS="" + +AC_ARG_ENABLE(static-support,APACHE_HELP_STRING(--enable-static-support,Build a statically linked version of the support binaries),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(htpasswd_LTFLAGS, [-static]) + APR_ADDTO(htdigest_LTFLAGS, [-static]) + APR_ADDTO(rotatelogs_LTFLAGS, [-static]) + APR_ADDTO(logresolve_LTFLAGS, [-static]) + APR_ADDTO(htdbm_LTFLAGS, [-static]) + APR_ADDTO(ab_LTFLAGS, [-static]) + APR_ADDTO(checkgid_LTFLAGS, [-static]) + APR_ADDTO(htcacheclean_LTFLAGS, [-static]) + APR_ADDTO(httxt2dbm_LTFLAGS, [-static]) + APR_ADDTO(fcgistarter_LTFLAGS, [-static]) +fi +]) + +AC_ARG_ENABLE(static-htpasswd,APACHE_HELP_STRING(--enable-static-htpasswd,Build a statically linked version of htpasswd),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(htpasswd_LTFLAGS, [-static]) +else + APR_REMOVEFROM(htpasswd_LTFLAGS, [-static]) +fi +]) +APACHE_SUBST(htpasswd_LTFLAGS) + +AC_ARG_ENABLE(static-htdigest,APACHE_HELP_STRING(--enable-static-htdigest,Build a statically linked version of htdigest),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(htdigest_LTFLAGS, [-static]) +else + APR_REMOVEFROM(htdigest_LTFLAGS, [-static]) +fi +]) +APACHE_SUBST(htdigest_LTFLAGS) + +AC_ARG_ENABLE(static-rotatelogs,APACHE_HELP_STRING(--enable-static-rotatelogs,Build a statically linked version of rotatelogs),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(rotatelogs_LTFLAGS, [-static]) +else + APR_REMOVEFROM(rotatelogs_LTFLAGS, [-static]) +fi +]) +APACHE_SUBST(rotatelogs_LTFLAGS) + +AC_ARG_ENABLE(static-logresolve,APACHE_HELP_STRING(--enable-static-logresolve,Build a statically linked version of logresolve),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(logresolve_LTFLAGS, [-static]) +else + APR_REMOVEFROM(logresolve_LTFLAGS, [-static]) +fi +]) +APACHE_SUBST(logresolve_LTFLAGS) + +AC_ARG_ENABLE(static-htdbm,APACHE_HELP_STRING(--enable-static-htdbm,Build a statically linked version of htdbm),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(htdbm_LTFLAGS, [-static]) +else + APR_REMOVEFROM(htdbm_LTFLAGS, [-static]) +fi +]) +APACHE_SUBST(htdbm_LTFLAGS) + +AC_ARG_ENABLE(static-ab,APACHE_HELP_STRING(--enable-static-ab,Build a statically linked version of ab),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(ab_LTFLAGS, [-static]) +else + APR_REMOVEFROM(ab_LTFLAGS, [-static]) +fi +]) +APACHE_SUBST(ab_LTFLAGS) + +AC_ARG_ENABLE(static-checkgid,APACHE_HELP_STRING(--enable-static-checkgid,Build a statically linked version of checkgid),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(checkgid_LTFLAGS, [-static]) +else + APR_REMOVEFROM(checkgid_LTFLAGS, [-static]) +fi +]) +APACHE_SUBST(checkgid_LTFLAGS) + +AC_ARG_ENABLE(static-htcacheclean,APACHE_HELP_STRING(--enable-static-htcacheclean,Build a statically linked version of htcacheclean),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(htcacheclean_LTFLAGS, [-static]) +else + APR_REMOVEFROM(htcacheclean_LTFLAGS, [-static]) +fi +]) +APACHE_SUBST(htcacheclean_LTFLAGS) + +AC_ARG_ENABLE(static-httxt2dbm,APACHE_HELP_STRING(--enable-static-httxt2dbm,Build a statically linked version of httxt2dbm),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(httxt2dbm_LTFLAGS, [-static]) +else + APR_REMOVEFROM(httxt2dbm, [-static]) +fi +]) +APACHE_SUBST(httxt2dbm_LTFLAGS) + +AC_ARG_ENABLE(static-fcgistarter,APACHE_HELP_STRING(--enable-static-fcgistarter,Build a statically linked version of fcgistarter),[ +if test "$enableval" = "yes" ; then + APR_ADDTO(fcgistarter_LTFLAGS, [-static]) +else + APR_REMOVEFROM(fcgistarter, [-static]) +fi +]) +APACHE_SUBST(fcgistarter_LTFLAGS) + +# Configure or check which of the non-portable support programs can be enabled. + +NONPORTABLE_SUPPORT="" +case $host in + *mingw*) + ;; + *) + NONPORTABLE_SUPPORT="checkgid fcgistarter" + ;; +esac +APACHE_SUBST(NONPORTABLE_SUPPORT) + +# Configure the ulimit -n command used by apachectl. + +case $host in + *aix*) + # this works in any locale, unlike the default command below, which + # fails in a non-English locale if the hard limit is unlimited + # since the display of the limit will translate "unlimited", but + # ulimit only accepts English "unlimited" on input + APACHECTL_ULIMIT="ulimit -S -n unlimited" + ;; + *alpha*-dec-osf*) + # Tru64: -H is for setting, not retrieving + APACHECTL_ULIMIT="ulimit -S -n \`ulimit -h -n\`" + ;; + *) + if TMP_ULIMIT=`ulimit -H -n` && ulimit -S -n $TMP_ULIMIT >/dev/null 2>&1; then + APACHECTL_ULIMIT="ulimit -S -n \`ulimit -H -n\`" + else + APACHECTL_ULIMIT="" + fi + ;; +esac +APACHE_SUBST(APACHECTL_ULIMIT) diff --git a/support/dbmmanage.in b/support/dbmmanage.in new file mode 100644 index 0000000..2dd8c86 --- /dev/null +++ b/support/dbmmanage.in @@ -0,0 +1,312 @@ +#!@perlbin@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#for more functionality see the HTTPD::UserAdmin module: +# http://www.perl.com/CPAN/modules/by-module/HTTPD/HTTPD-Tools-x.xx.tar.gz +# +# usage: dbmmanage <DBMfile> <command> <user> <password> <groups> <comment> + +package dbmmanage; +# -ldb -lndbm -lgdbm -lsdbm +BEGIN { @AnyDBM_File::ISA = qw(DB_File NDBM_File GDBM_File SDBM_File) } +use strict; +use Fcntl; +use AnyDBM_File (); + +sub usage { + my $cmds = join "|", sort keys %dbmc::; + die <<SYNTAX; +Usage: dbmmanage [enc] dbname command [username [pw [group[,group] [comment]]]] + + where enc is -d for crypt encryption (default except on Win32, Netware) + -m for MD5 encryption (default on Win32, Netware) + -s for SHA1 encryption + -p for plaintext + + command is one of: $cmds + + pw of . for update command retains the old password + pw of - (or blank) for update command prompts for the password + + groups or comment of . (or blank) for update command retains old values + groups or comment of - for update command clears the existing value + groups or comment of - for add and adduser commands is the empty value +SYNTAX +} + +sub need_sha1_crypt { + if (!eval ('require "Digest/SHA1.pm";')) { + print STDERR <<SHAERR; +dbmmanage SHA1 passwords require the interface or the module Digest::SHA1 +available from CPAN: + + http://www.cpan.org/modules/by-module/Digest/Digest-MD5-2.12.tar.gz + +Please install Digest::SHA1 and try again, or use a different crypt option: + +SHAERR + usage(); + } +} + +sub need_md5_crypt { + if (!eval ('require "Crypt/PasswdMD5.pm";')) { + print STDERR <<MD5ERR; +dbmmanage MD5 passwords require the module Crypt::PasswdMD5 available from CPAN + + http://www.cpan.org/modules/by-module/Crypt/Crypt-PasswdMD5-1.1.tar.gz + +Please install Crypt::PasswdMD5 and try again, or use a different crypt option: + +MD5ERR + usage(); + } +} + +# if your osname is in $newstyle_salt, then use new style salt (starts with '_' and contains +# four bytes of iteration count and four bytes of salt). Otherwise, just use +# the traditional two-byte salt. +# see the man page on your system to decide if you have a newer crypt() lib. +# I believe that 4.4BSD derived systems do (at least BSD/OS 2.0 does). +# The new style crypt() allows up to 20 characters of the password to be +# significant rather than only 8. +# +my $newstyle_salt_platforms = join '|', qw{bsdos}; #others? +my $newstyle_salt = $^O =~ /(?:$newstyle_salt_platforms)/; + +# Some platforms just can't crypt() for Apache +# +my $crypt_not_supported_platforms = join '|', qw{MSWin32 NetWare}; #others? +my $crypt_not_supported = $^O =~ /(?:$crypt_not_supported_platforms)/; + +my $crypt_method = "crypt"; + +if ($crypt_not_supported) { + $crypt_method = "md5"; +} + +# Some platforms won't jump through our favorite hoops +# +my $not_unix_platforms = join '|', qw{MSWin32 NetWare}; #others? +my $not_unix = $^O =~ /(?:$not_unix_platforms)/; + +if ($crypt_not_supported) { + $crypt_method = "md5"; +} + +if (@ARGV[0] eq "-d") { + shift @ARGV; + if ($crypt_not_supported) { + print STDERR + "Warning: Apache/$^O does not support crypt()ed passwords!\n\n"; + } + $crypt_method = "crypt"; +} + +if (@ARGV[0] eq "-m") { + shift @ARGV; + $crypt_method = "md5"; +} + +if (@ARGV[0] eq "-p") { + shift @ARGV; + if (!$crypt_not_supported) { + print STDERR + "Warning: Apache/$^O does not support plaintext passwords!\n\n"; + } + $crypt_method = "plain"; +} + +if (@ARGV[0] eq "-s") { + shift @ARGV; + need_sha1_crypt(); + $crypt_method = "sha1"; +} + +if ($crypt_method eq "md5") { + need_md5_crypt(); +} + +my($file,$command,$key,$crypted_pwd,$groups,$comment) = @ARGV; + +usage() unless $file and $command and defined &{$dbmc::{$command}}; + +# remove extension if any +my $chop = join '|', qw{db.? pag dir}; +$file =~ s/\.($chop)$//; + +my $is_update = $command eq "update"; +my %DB = (); +my @range = (); +my($mode, $flags) = $command =~ + /^(?:view|check)$/ ? (0644, O_RDONLY) : (0644, O_RDWR|O_CREAT); + +tie (%DB, "AnyDBM_File", $file, $flags, $mode) || die "Can't tie $file: $!"; +dbmc->$command(); +untie %DB; + + +my $x; +sub genseed { + my $psf; + if ($not_unix) { + srand (time ^ $$ or time ^ ($$ + ($$ << 15))); + } + else { + for (qw(-xlwwa -le)) { + `ps $_ 2>/dev/null`; + $psf = $_, last unless $?; + } + srand (time ^ $$ ^ unpack("%L*", `ps $psf | gzip -f`)); + } + @range = (qw(. /), '0'..'9','a'..'z','A'..'Z'); + $x = int scalar @range; +} + +sub randchar { + join '', map $range[rand $x], 1..shift||1; +} + +sub saltpw_crypt { + genseed() unless @range; + return $newstyle_salt ? + join '', "_", randchar, "a..", randchar(4) : + randchar(2); +} + +sub cryptpw_crypt { + my ($pw, $salt) = @_; + $salt = saltpw_crypt unless $salt; + crypt $pw, $salt; +} + +sub saltpw_md5 { + genseed() unless @range; + randchar(8); +} + +sub cryptpw_md5 { + my($pw, $salt) = @_; + $salt = saltpw_md5 unless $salt; + Crypt::PasswdMD5::apache_md5_crypt($pw, $salt); +} + +sub cryptpw_sha1 { + my($pw, $salt) = @_; + '{SHA}' . Digest::SHA1::sha1_base64($pw) . "="; +} + +sub cryptpw { + if ($crypt_method eq "md5") { + return cryptpw_md5(@_); + } elsif ($crypt_method eq "sha1") { + return cryptpw_sha1(@_); + } elsif ($crypt_method eq "crypt") { + return cryptpw_crypt(@_); + } + @_[0]; # otherwise return plaintext +} + +sub getpass { + my $prompt = shift || "Enter password:"; + + unless($not_unix) { + open STDIN, "/dev/tty" or warn "couldn't open /dev/tty $!\n"; + system "stty -echo;"; + } + + my($c,$pwd); + print STDERR $prompt; + while (($c = getc(STDIN)) ne '' and $c ne "\n" and $c ne "\r") { + $pwd .= $c; + } + + system "stty echo" unless $not_unix; + print STDERR "\n"; + die "Can't use empty password!\n" unless length $pwd; + return $pwd; +} + +sub dbmc::update { + die "Sorry, user `$key' doesn't exist!\n" unless $DB{$key}; + $crypted_pwd = (split /:/, $DB{$key}, 3)[0] if $crypted_pwd eq '.'; + $groups = (split /:/, $DB{$key}, 3)[1] if !$groups || $groups eq '.'; + $comment = (split /:/, $DB{$key}, 3)[2] if !$comment || $comment eq '.'; + if (!$crypted_pwd || $crypted_pwd eq '-') { + dbmc->adduser; + } + else { + dbmc->add; + } +} + +sub dbmc::add { + die "Can't use empty password!\n" unless $crypted_pwd; + unless($is_update) { + die "Sorry, user `$key' already exists!\n" if $DB{$key}; + } + $groups = '' if $groups eq '-'; + $comment = '' if $comment eq '-'; + $groups .= ":" . $comment if $comment; + $crypted_pwd .= ":" . $groups if $groups; + $DB{$key} = $crypted_pwd; + my $action = $is_update ? "updated" : "added"; + print "User $key $action with password encrypted to $DB{$key} using $crypt_method\n"; +} + +sub dbmc::adduser { + my $value = getpass "New password:"; + die "They don't match, sorry.\n" unless getpass("Re-type new password:") eq $value; + $crypted_pwd = cryptpw $value; + dbmc->add; +} + +sub dbmc::delete { + die "Sorry, user `$key' doesn't exist!\n" unless $DB{$key}; + delete $DB{$key}, print "`$key' deleted\n"; +} + +sub dbmc::view { + print $key ? "$key:$DB{$key}\n" : map { "$_:$DB{$_}\n" if $DB{$_} } keys %DB; +} + +sub dbmc::check { + die "Sorry, user `$key' doesn't exist!\n" unless $DB{$key}; + my $chkpass = (split /:/, $DB{$key}, 3)[0]; + my $testpass = getpass(); + if (substr($chkpass, 0, 6) eq '$apr1$') { + need_md5_crypt; + $crypt_method = "md5"; + } elsif (substr($chkpass, 0, 5) eq '{SHA}') { + need_sha1_crypt; + $crypt_method = "sha1"; + } elsif (length($chkpass) == 13 && $chkpass ne $testpass) { + $crypt_method = "crypt"; + } else { + $crypt_method = "plain"; + } + print $crypt_method . (cryptpw($testpass, $chkpass) eq $chkpass + ? " password ok\n" : " password mismatch\n"); +} + +sub dbmc::import { + while(defined($_ = <STDIN>) and chomp) { + ($key,$crypted_pwd,$groups,$comment) = split /:/, $_, 4; + dbmc->add; + } +} + diff --git a/support/envvars-std.in b/support/envvars-std.in new file mode 100644 index 0000000..9493bc7 --- /dev/null +++ b/support/envvars-std.in @@ -0,0 +1,28 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# envvars-std - default environment variables for apachectl +# +# This file is generated from envvars-std.in +# +if test "x$@SHLIBPATH_VAR@" != "x" ; then + @SHLIBPATH_VAR@="@exp_libdir@:$@SHLIBPATH_VAR@" +else + @SHLIBPATH_VAR@="@exp_libdir@" +fi +export @SHLIBPATH_VAR@ +# +@OS_SPECIFIC_VARS@ diff --git a/support/fcgistarter.c b/support/fcgistarter.c new file mode 100644 index 0000000..9cfda51 --- /dev/null +++ b/support/fcgistarter.c @@ -0,0 +1,220 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <apr.h> +#include <apr_pools.h> +#include <apr_network_io.h> +#include <apr_thread_proc.h> +#include <apr_getopt.h> +#include <apr_portable.h> + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* For EXIT_SUCCESS, EXIT_FAILURE */ +#endif + +#if APR_HAVE_UNISTD_H +#include <unistd.h> /* For execl */ +#endif + +static const char *usage_message = + "usage: fcgistarter -c <command> -p <port> [-i <interface> -N <num>]\n" + "\n" + "If an interface is not specified, any available will be used.\n"; + +static void usage(void) +{ + fprintf(stderr, "%s", usage_message); + + exit(EXIT_FAILURE); +} + +static void exit_error(apr_status_t rv, const char *func) +{ + char buffer[1024]; + + fprintf(stderr, + "%s: %s\n", + func, + apr_strerror(rv, buffer, sizeof(buffer))); + + exit(EXIT_FAILURE); +} + +int main(int argc, const char * const argv[]) +{ + apr_file_t *infd, *skwrapper; + apr_sockaddr_t *skaddr; + apr_getopt_t *gopt; + apr_socket_t *skt; + apr_pool_t *pool; + apr_status_t rv; + apr_proc_t proc; + + + /* Command line arguments */ + int num_to_start = 1, port = 0; + const char *interface = NULL; + const char *command = NULL; + + apr_app_initialize(&argc, &argv, NULL); + + atexit(apr_terminate); + + apr_pool_create(&pool, NULL); + + rv = apr_getopt_init(&gopt, pool, argc, argv); + if (rv) { + return EXIT_FAILURE; + } + + for (;;) { + const char *arg; + char opt; + + rv = apr_getopt(gopt, "c:p:i:N:", &opt, &arg); + if (APR_STATUS_IS_EOF(rv)) { + break; + } else if (rv) { + usage(); + } else { + switch (opt) { + case 'c': + command = arg; + break; + + case 'p': + port = atoi(arg); + if (! port) { + usage(); + } + break; + + case 'i': + interface = arg; + break; + + case 'N': + num_to_start = atoi(arg); + if (! num_to_start) { + usage(); + } + break; + + default: + break; + } + } + } + + if (! command || ! port) { + usage(); + } + + rv = apr_sockaddr_info_get(&skaddr, interface, APR_UNSPEC, port, 0, pool); + if (rv) { + exit_error(rv, "apr_sockaddr_info_get"); + } + + rv = apr_socket_create(&skt, skaddr->family, SOCK_STREAM, APR_PROTO_TCP, pool); + if (rv) { + exit_error(rv, "apr_socket_create"); + } + + rv = apr_socket_opt_set(skt, APR_SO_REUSEADDR, 1); + if (rv) { + exit_error(rv, "apr_socket_opt_set(APR_SO_REUSEADDR)"); + } + + rv = apr_socket_bind(skt, skaddr); + if (rv) { + exit_error(rv, "apr_socket_bind"); + } + + rv = apr_socket_listen(skt, 1024); + if (rv) { + exit_error(rv, "apr_socket_listen"); + } + + rv = apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); + if (rv) { + exit_error(rv, "apr_proc_detach"); + } + +#if defined(WIN32) || defined(OS2) || defined(NETWARE) + +#error "Please implement me." + +#else + + while (--num_to_start >= 0) { + rv = apr_proc_fork(&proc, pool); + if (rv == APR_INCHILD) { + apr_os_file_t oft = 0; + apr_os_sock_t oskt; + + /* Ok, so we need a file that has file descriptor 0 (which + * FastCGI wants), but points to our socket. This isn't really + * possible in APR, so we cheat a bit. I have no idea how to + * do this on a non-unix platform, so for now this is platform + * specific. Ick. + * + * Note that this has to happen post-detach, otherwise fd 0 + * gets closed during apr_proc_detach and it's all for nothing. + * + * Unfortunately, doing this post detach means we have no way + * to let anyone know if there's a problem at this point :( */ + + rv = apr_os_file_put(&infd, &oft, APR_READ | APR_WRITE, pool); + if (rv) { + exit(EXIT_FAILURE); + } + + rv = apr_os_sock_get(&oskt, skt); + if (rv) { + exit(EXIT_FAILURE); + } + + rv = apr_os_file_put(&skwrapper, &oskt, APR_READ | APR_WRITE, + pool); + if (rv) { + exit(EXIT_FAILURE); + } + + rv = apr_file_dup2(infd, skwrapper, pool); + if (rv) { + exit(EXIT_FAILURE); + } + + /* XXX Can't use apr_proc_create because there's no way to get + * infd into the procattr without going through another dup2, + * which means by the time it gets to the fastcgi process it + * is no longer fd 0, so it doesn't work. Sigh. */ + + execl(command, command, NULL); + + } else if (rv == APR_INPARENT) { + if (num_to_start == 0) { + apr_socket_close(skt); + } + } else { + exit_error(rv, "apr_proc_fork"); + } + } + +#endif + + return EXIT_SUCCESS; +} diff --git a/support/fcgistarter.dep b/support/fcgistarter.dep new file mode 100644 index 0000000..d27b8d2 --- /dev/null +++ b/support/fcgistarter.dep @@ -0,0 +1,29 @@ +# Microsoft Developer Studio Generated Dependency File, included by fcgistarter.mak + +.\fcgistarter.c : \ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_dso.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_getopt.h"\ + "..\srclib\apr\include\apr_global_mutex.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_network_io.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_portable.h"\ + "..\srclib\apr\include\apr_proc_mutex.h"\ + "..\srclib\apr\include\apr_shm.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_thread_proc.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_want.h"\ + + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + diff --git a/support/fcgistarter.dsp b/support/fcgistarter.dsp new file mode 100644 index 0000000..9cd5780 --- /dev/null +++ b/support/fcgistarter.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="fcgistarter" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=fcgistarter - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "fcgistarter.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "fcgistarter.mak" CFG="fcgistarter - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "fcgistarter - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "fcgistarter - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "fcgistarter - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/fcgistarter_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/fcgistarter.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\fcgistarter.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/fcgistarter_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/fcgistarter.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\fcgistarter.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "fcgistarter - Win32 Release" +# Name "fcgistarter - Win32 Debug" +# Begin Source File + +SOURCE=.\fcgistarter.c +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/fcgistarter.mak b/support/fcgistarter.mak new file mode 100644 index 0000000..b47d185 --- /dev/null +++ b/support/fcgistarter.mak @@ -0,0 +1,317 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on fcgistarter.dsp +!IF "$(CFG)" == "" +CFG=fcgistarter - Win32 Debug +!MESSAGE No configuration specified. Defaulting to fcgistarter - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "fcgistarter - Win32 Release" && "$(CFG)" != "fcgistarter - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "fcgistarter.mak" CFG="fcgistarter - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "fcgistarter - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "fcgistarter - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "fcgistarter - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\fcgistarter.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\fcgistarter.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\fcgistarter.obj" + -@erase "$(INTDIR)\fcgistarter.res" + -@erase "$(INTDIR)\fcgistarter_src.idb" + -@erase "$(INTDIR)\fcgistarter_src.pdb" + -@erase "$(OUTDIR)\fcgistarter.exe" + -@erase "$(OUTDIR)\fcgistarter.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\fcgistarter_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\fcgistarter.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\fcgistarter.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\fcgistarter.pdb" /debug /out:"$(OUTDIR)\fcgistarter.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\fcgistarter.obj" \ + "$(INTDIR)\fcgistarter.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\fcgistarter.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\fcgistarter.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\fcgistarter.exe" + if exist .\Release\fcgistarter.exe.manifest mt.exe -manifest .\Release\fcgistarter.exe.manifest -outputresource:.\Release\fcgistarter.exe;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\fcgistarter.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\fcgistarter.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\fcgistarter.obj" + -@erase "$(INTDIR)\fcgistarter.res" + -@erase "$(INTDIR)\fcgistarter_src.idb" + -@erase "$(INTDIR)\fcgistarter_src.pdb" + -@erase "$(OUTDIR)\fcgistarter.exe" + -@erase "$(OUTDIR)\fcgistarter.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /I "../include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\fcgistarter_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\fcgistarter.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\fcgistarter.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\fcgistarter.pdb" /debug /out:"$(OUTDIR)\fcgistarter.exe" +LINK32_OBJS= \ + "$(INTDIR)\fcgistarter.obj" \ + "$(INTDIR)\fcgistarter.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\fcgistarter.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\fcgistarter.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\fcgistarter.exe" + if exist .\Debug\fcgistarter.exe.manifest mt.exe -manifest .\Debug\fcgistarter.exe.manifest -outputresource:.\Debug\fcgistarter.exe;2 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("fcgistarter.dep") +!INCLUDE "fcgistarter.dep" +!ELSE +!MESSAGE Warning: cannot find "fcgistarter.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "fcgistarter - Win32 Release" || "$(CFG)" == "fcgistarter - Win32 Debug" + +!IF "$(CFG)" == "fcgistarter - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "fcgistarter - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=.\fcgistarter.c + +"$(INTDIR)\fcgistarter.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "fcgistarter - Win32 Release" + + +"$(INTDIR)\fcgistarter.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\fcgistarter.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility" $(SOURCE) + + +!ELSEIF "$(CFG)" == "fcgistarter - Win32 Debug" + + +"$(INTDIR)\fcgistarter.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\fcgistarter.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="fcgistarter.exe" /d LONG_NAME="Apache fcgi command line utility" $(SOURCE) + + +!ENDIF + + +!ENDIF + diff --git a/support/htcacheclean.c b/support/htcacheclean.c new file mode 100644 index 0000000..b4eabbf --- /dev/null +++ b/support/htcacheclean.c @@ -0,0 +1,1842 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * htcacheclean.c: simple program for cleaning of + * the disk cache of the Apache HTTP server + * + * Contributed by Andreas Steinmetz <ast domdv.de> + * 8 Oct 2004 + */ + +#include "apr.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_pools.h" +#include "apr_hash.h" +#include "apr_thread_proc.h" +#include "apr_signal.h" +#include "apr_getopt.h" +#include "apr_md5.h" +#include "apr_ring.h" +#include "apr_date.h" +#include "apr_buckets.h" + +#include "../modules/cache/cache_common.h" +#include "../modules/cache/cache_disk_common.h" + +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +/* define the following for debugging */ +#undef DEBUG + +/* + * Note: on Linux delays <= 2ms are busy waits without + * scheduling, so never use a delay <= 2ms below + */ + +#define NICE_DELAY 10000 /* usecs */ +#define DELETE_NICE 10 /* be nice after this amount of delete ops */ +#define STAT_ATTEMPTS 10 /* maximum stat attempts for a file */ +#define STAT_DELAY 5000 /* usecs */ +#define HEADER 1 /* headers file */ +#define DATA 2 /* body file */ +#define TEMP 4 /* temporary file */ +#define HEADERDATA (HEADER|DATA) +#define MAXDEVIATION 3600 /* secs */ +#define SECS_PER_MIN 60 +#define KBYTE 1024 +#define MBYTE 1048576 +#define GBYTE 1073741824 + +#define DIRINFO (APR_FINFO_MTIME|APR_FINFO_SIZE|APR_FINFO_TYPE|APR_FINFO_LINK) + +typedef struct _direntry { + APR_RING_ENTRY(_direntry) link; + int type; /* type of file/fileset: TEMP, HEADER, DATA, HEADERDATA */ + apr_time_t htime; /* headers file modification time */ + apr_time_t dtime; /* body file modification time */ + apr_off_t hsize; /* headers file size */ + apr_off_t dsize; /* body or temporary file size */ + char *basename; /* file/fileset base name */ +} DIRENTRY; + +typedef struct _entry { + APR_RING_ENTRY(_entry) link; + apr_time_t expire; /* cache entry exiration time */ + apr_time_t response_time; /* cache entry time of last response to client */ + apr_time_t htime; /* headers file modification time */ + apr_time_t dtime; /* body file modification time */ + apr_off_t hsize; /* headers file size */ + apr_off_t dsize; /* body or temporary file size */ + char *basename; /* fileset base name */ +} ENTRY; + + +static int delcount; /* file deletion count for nice mode */ +static int interrupted; /* flag: true if SIGINT or SIGTERM occurred */ +static int realclean; /* flag: true means user said apache is not running */ +static int verbose; /* flag: true means print statistics */ +static int benice; /* flag: true means nice mode is activated */ +static int dryrun; /* flag: true means dry run, don't actually delete + anything */ +static int deldirs; /* flag: true means directories should be deleted */ +static int listurls; /* flag: true means list cached urls */ +static int listextended;/* flag: true means list cached urls */ +static int baselen; /* string length of the path to the proxy directory */ +static apr_time_t now; /* start time of this processing run */ + +static apr_file_t *errfile; /* stderr file handle */ +static apr_file_t *outfile; /* stdout file handle */ +static apr_off_t unsolicited; /* file size summary for deleted unsolicited + files */ +static ENTRY root; /* ENTRY ring anchor */ + +/* short program name as called */ +static const char *shortname = "htcacheclean"; + +/* what did we clean? */ +struct stats { + apr_off_t total; + apr_off_t sum; + apr_off_t max; + apr_off_t ntotal; + apr_off_t nodes; + apr_off_t inodes; + apr_off_t etotal; + apr_off_t entries; + apr_off_t dfuture; + apr_off_t dexpired; + apr_off_t dfresh; +}; + + +#ifdef DEBUG +/* + * fake delete for debug purposes + */ +#define apr_file_remove fake_file_remove +static void fake_file_remove(char *pathname, apr_pool_t *p) +{ + apr_finfo_t info; + + /* stat and printing to simulate some deletion system load and to + display what would actually have happened */ + apr_stat(&info, pathname, DIRINFO, p); + apr_file_printf(errfile, "would delete %s" APR_EOL_STR, pathname); +} +#endif + +/* + * called on SIGINT or SIGTERM + */ +static void setterm(int unused) +{ +#ifdef DEBUG + apr_file_printf(errfile, "interrupt" APR_EOL_STR); +#endif + interrupted = 1; +} + +/* + * called in out of memory condition + */ +static int oom(int unused) +{ + static int called = 0; + + /* be careful to call exit() only once */ + if (!called) { + called = 1; + exit(1); + } + return APR_ENOMEM; +} + +/* + * print purge statistics + */ +static void printstats(char *path, struct stats *s) +{ + char ttype, stype, mtype, utype; + apr_off_t tfrag, sfrag, ufrag; + + if (!verbose) { + return; + } + + ttype = 'K'; + tfrag = ((s->total * 10) / KBYTE) % 10; + s->total /= KBYTE; + if (s->total >= KBYTE) { + ttype = 'M'; + tfrag = ((s->total * 10) / KBYTE) % 10; + s->total /= KBYTE; + } + + stype = 'K'; + sfrag = ((s->sum * 10) / KBYTE) % 10; + s->sum /= KBYTE; + if (s->sum >= KBYTE) { + stype = 'M'; + sfrag = ((s->sum * 10) / KBYTE) % 10; + s->sum /= KBYTE; + } + + mtype = 'K'; + s->max /= KBYTE; + if (s->max >= KBYTE) { + mtype = 'M'; + s->max /= KBYTE; + } + + apr_file_printf(errfile, "Cleaned %s. Statistics:" APR_EOL_STR, path); + if (unsolicited) { + utype = 'K'; + ufrag = ((unsolicited * 10) / KBYTE) % 10; + unsolicited /= KBYTE; + if (unsolicited >= KBYTE) { + utype = 'M'; + ufrag = ((unsolicited * 10) / KBYTE) % 10; + unsolicited /= KBYTE; + } + if (!unsolicited && !ufrag) { + ufrag = 1; + } + apr_file_printf(errfile, "unsolicited size %d.%d%c" APR_EOL_STR, + (int)(unsolicited), (int)(ufrag), utype); + } + apr_file_printf(errfile, "size limit %" APR_OFF_T_FMT ".0%c" APR_EOL_STR, + s->max, mtype); + apr_file_printf(errfile, "inodes limit %" APR_OFF_T_FMT APR_EOL_STR, + s->inodes); + apr_file_printf( + errfile, + "total size was %" APR_OFF_T_FMT ".%" APR_OFF_T_FMT "%c, total size now " + "%" APR_OFF_T_FMT ".%" APR_OFF_T_FMT "%c" APR_EOL_STR, s->total, + tfrag, ttype, s->sum, sfrag, stype); + apr_file_printf(errfile, "total inodes was %" APR_OFF_T_FMT + ", total %sinodes now " + "%" APR_OFF_T_FMT APR_EOL_STR, s->ntotal, dryrun && deldirs ? "estimated " + : "", s->nodes); + apr_file_printf( + errfile, + "total entries was %" APR_OFF_T_FMT ", total entries now %" APR_OFF_T_FMT + APR_EOL_STR, s->etotal, s->entries); + apr_file_printf( + errfile, + "%" APR_OFF_T_FMT " entries deleted (%" APR_OFF_T_FMT " from future, %" + APR_OFF_T_FMT " expired, %" APR_OFF_T_FMT " fresh)" APR_EOL_STR, + (s->etotal - s->entries), s->dfuture, s->dexpired, s->dfresh); +} + +/** + * Round the value up to the given threshold. + */ +static apr_size_t round_up(apr_size_t val, apr_off_t round) +{ + if (round > 1) { + return (apr_size_t)(((val + round - 1) / round) * round); + } + return val; +} + +/* + * delete parent directories + */ +static void delete_parent(const char *path, const char *basename, + apr_off_t *nodes, apr_pool_t *pool) +{ + char *nextpath, *name; + apr_pool_t *p; + + /* temp pool, otherwise lots of memory could be allocated */ + apr_pool_create(&p, pool); + name = apr_pstrdup(p, basename); + + /* If asked to delete dirs, do so now. We don't care if it fails. + * If it fails, it likely means there was something else there. + */ + if (deldirs && !dryrun) { + const char *vary; + char *end = strrchr(name, '/'); + while (end) { + *end = 0; + + /* remove the directory */ + nextpath = apr_pstrcat(p, path, "/", name, NULL); + if (!apr_dir_remove(nextpath, p)) { + (*nodes)--; + + /* vary directory found? */ + vary = strstr(name, CACHE_VDIR_SUFFIX); + if (vary && !vary[sizeof(CACHE_VDIR_SUFFIX) - 1]) { + nextpath = apr_pstrcat(p, path, "/", apr_pstrndup(p, name, vary + - name), NULL); + if (!apr_file_remove(nextpath, p)) { + (*nodes)--; + } + } + + } + else { + break; + } + end = strrchr(name, '/'); + } + } + + apr_pool_destroy(p); + + if (benice) { + if (++delcount >= DELETE_NICE) { + apr_sleep(NICE_DELAY); + delcount = 0; + } + } + +} + +/* + * delete a single file + */ +static void delete_file(char *path, char *basename, apr_off_t *nodes, + apr_pool_t *pool) +{ + char *nextpath; + apr_pool_t *p; + + /* temp pool, otherwise lots of memory could be allocated */ + apr_pool_create(&p, pool); + nextpath = apr_pstrcat(p, path, "/", basename, NULL); + + if (dryrun) { + apr_finfo_t finfo; + if (!apr_stat(&finfo, nextpath, APR_FINFO_NLINK, p)) { + (*nodes)--; + } + } + else if (!apr_file_remove(nextpath, p)) { + (*nodes)--; + } + + apr_pool_destroy(p); + + if (benice) { + if (++delcount >= DELETE_NICE) { + apr_sleep(NICE_DELAY); + delcount = 0; + } + } + + delete_parent(path, basename, nodes, pool); + +} + +/* + * delete cache file set + */ +static void delete_entry(char *path, char *basename, apr_off_t *nodes, + apr_pool_t *pool) +{ + char *nextpath; + apr_pool_t *p; + + /* temp pool, otherwise lots of memory could be allocated */ + apr_pool_create(&p, pool); + + nextpath = apr_pstrcat(p, path, "/", basename, CACHE_HEADER_SUFFIX, NULL); + if (dryrun) { + apr_finfo_t finfo; + if (!apr_stat(&finfo, nextpath, APR_FINFO_NLINK, p)) { + (*nodes)--; + } + } + else if (!apr_file_remove(nextpath, p)) { + (*nodes)--; + } + + nextpath = apr_pstrcat(p, path, "/", basename, CACHE_DATA_SUFFIX, NULL); + if (dryrun) { + apr_finfo_t finfo; + if (!apr_stat(&finfo, nextpath, APR_FINFO_NLINK, p)) { + (*nodes)--; + } + } + else if (!apr_file_remove(nextpath, p)) { + (*nodes)--; + } + + apr_pool_destroy(p); + + if (benice) { + delcount += 2; + if (delcount >= DELETE_NICE) { + apr_sleep(NICE_DELAY); + delcount = 0; + } + } + + delete_parent(path, basename, nodes, pool); + +} + +/* + * list the cache directory tree + */ +static int list_urls(char *path, apr_pool_t *pool, apr_off_t round) +{ + apr_dir_t *dir; + apr_finfo_t info; + apr_size_t len; + apr_pool_t *p; + apr_file_t *fd; + const char *ext, *nextpath; + char *url; + apr_uint32_t format; + disk_cache_info_t disk_info; + + apr_pool_create(&p, pool); + + if (apr_dir_open(&dir, path, p) != APR_SUCCESS) { + return 1; + } + + while (apr_dir_read(&info, APR_FINFO_TYPE, dir) == APR_SUCCESS && !interrupted) { + + if (info.filetype == APR_DIR) { + if (!strcmp(info.name, ".") || !strcmp(info.name, "..")) { + continue; + } + + if (list_urls(apr_pstrcat(p, path, "/", info.name, NULL), pool, round)) { + return 1; + } + } + + else if (info.filetype == APR_REG) { + + ext = strchr(info.name, '.'); + + if (ext && !strcasecmp(ext, CACHE_HEADER_SUFFIX)) { + + nextpath = apr_pstrcat(p, path, "/", info.name, NULL); + + if (apr_file_open(&fd, nextpath, APR_FOPEN_READ + | APR_FOPEN_BINARY, APR_OS_DEFAULT, p) == APR_SUCCESS) { + len = sizeof(format); + if (apr_file_read_full(fd, &format, len, &len) + == APR_SUCCESS) { + if (format == DISK_FORMAT_VERSION) { + apr_off_t offset = 0; + + apr_file_seek(fd, APR_SET, &offset); + + len = sizeof(disk_cache_info_t); + + if (apr_file_read_full(fd, &disk_info, len, &len) + == APR_SUCCESS) { + len = disk_info.name_len; + url = apr_palloc(p, len + 1); + url[len] = 0; + + if (apr_file_read_full(fd, url, len, &len) + == APR_SUCCESS) { + + if (listextended) { + apr_finfo_t hinfo, dinfo; + + /* stat the header file */ + if (APR_SUCCESS != apr_file_info_get( + &hinfo, APR_FINFO_SIZE, fd)) { + /* ignore the file */ + } + else if (disk_info.has_body && APR_SUCCESS + != apr_stat( + &dinfo, + apr_pstrcat( + p, + path, + "/", + apr_pstrndup( + p, + info.name, + ext + - info.name), + CACHE_DATA_SUFFIX, + NULL), + APR_FINFO_SIZE + | APR_FINFO_IDENT, + p)) { + /* ignore the file */ + } + else if (disk_info.has_body && (dinfo.device + != disk_info.device + || dinfo.inode + != disk_info.inode)) { + /* ignore the file */ + } + else { + + apr_file_printf( + outfile, + "%s %" APR_SIZE_T_FMT + " %" APR_SIZE_T_FMT + " %d %" APR_SIZE_T_FMT + " %" APR_TIME_T_FMT + " %" APR_TIME_T_FMT + " %" APR_TIME_T_FMT + " %" APR_TIME_T_FMT + " %d %d\n", + url, + round_up((apr_size_t)hinfo.size, round), + round_up( + disk_info.has_body ? (apr_size_t)dinfo.size + : 0, round), + disk_info.status, + disk_info.entity_version, + disk_info.date, + disk_info.expire, + disk_info.request_time, + disk_info.response_time, + disk_info.has_body, + disk_info.header_only); + } + } + else { + apr_finfo_t dinfo; + + /* stat the data file */ + if (disk_info.has_body && APR_SUCCESS + != apr_stat( + &dinfo, + apr_pstrcat( + p, + path, + "/", + apr_pstrndup( + p, + info.name, + ext + - info.name), + CACHE_DATA_SUFFIX, + NULL), + APR_FINFO_SIZE + | APR_FINFO_IDENT, + p)) { + /* ignore the file */ + } + else if (disk_info.has_body && (dinfo.device + != disk_info.device + || dinfo.inode + != disk_info.inode)) { + /* ignore the file */ + } + else { + apr_file_printf(outfile, "%s\n", + url); + } + } + } + + break; + } + } + } + apr_file_close(fd); + + } + } + } + + } + + apr_dir_close(dir); + + if (interrupted) { + return 1; + } + + apr_pool_destroy(p); + + if (benice) { + apr_sleep(NICE_DELAY); + } + + if (interrupted) { + return 1; + } + + return 0; +} + +/* + * walk the cache directory tree + */ +static int process_dir(char *path, apr_pool_t *pool, apr_off_t *nodes) +{ + apr_dir_t *dir; + apr_pool_t *p; + apr_hash_t *h; + apr_hash_index_t *i; + apr_file_t *fd; + apr_status_t status; + apr_finfo_t info; + apr_size_t len; + apr_time_t current, deviation; + char *nextpath, *base, *ext; + DIRENTRY *d, *t, *n, anchor; + ENTRY *e; + int skip, retries; + disk_cache_info_t disk_info; + + APR_RING_INIT(&anchor.link, _direntry, link); + apr_pool_create(&p, pool); + h = apr_hash_make(p); + fd = NULL; + deviation = MAXDEVIATION * APR_USEC_PER_SEC; + + if (apr_dir_open(&dir, path, p) != APR_SUCCESS) { + return 1; + } + + while (apr_dir_read(&info, 0, dir) == APR_SUCCESS && !interrupted) { + if (!strcmp(info.name, ".") || !strcmp(info.name, "..")) { + continue; + } + d = apr_pcalloc(p, sizeof(DIRENTRY)); + d->basename = apr_pstrcat(p, path, "/", info.name, NULL); + APR_RING_INSERT_TAIL(&anchor.link, d, _direntry, link); + (*nodes)++; + } + + apr_dir_close(dir); + + if (interrupted) { + return 1; + } + + skip = baselen + 1; + + for (d = APR_RING_FIRST(&anchor.link); + !interrupted && d != APR_RING_SENTINEL(&anchor.link, _direntry, link); + d=n) { + n = APR_RING_NEXT(d, link); + base = strrchr(d->basename, '/'); + if (!base++) { + base = d->basename; + } + ext = strchr(base, '.'); + + /* there may be temporary files which may be gone before + * processing, always skip these if not in realclean mode + */ + if (!ext && !realclean) { + if (!strncasecmp(base, AP_TEMPFILE_BASE, AP_TEMPFILE_BASELEN) + && strlen(base) == AP_TEMPFILE_NAMELEN) { + continue; + } + } + + /* this may look strange but apr_stat() may return an error which + * is system dependent and there may be transient failures, + * so just blindly retry for a short while + */ + retries = STAT_ATTEMPTS; + status = APR_SUCCESS; + do { + if (status != APR_SUCCESS) { + apr_sleep(STAT_DELAY); + } + status = apr_stat(&info, d->basename, DIRINFO, p); + } while (status != APR_SUCCESS && !interrupted && --retries); + + /* what may happen here is that apache did create a file which + * we did detect but then does delete the file before we can + * get file information, so if we don't get any file information + * we will ignore the file in this case + */ + if (status != APR_SUCCESS) { + if (!realclean && !interrupted) { + continue; + } + return 1; + } + + if (info.filetype == APR_DIR) { + char *dirpath = apr_pstrdup(p, d->basename); + + if (process_dir(d->basename, pool, nodes)) { + return 1; + } + /* When given the -t option htcacheclean does not + * delete directories that are already empty, so we'll do that here + * since process_dir checks all the directories. + * If it fails, it likely means there was something else there. + */ + if (deldirs && !dryrun) { + apr_dir_remove(dirpath, p); + } + continue; + } + + if (info.filetype != APR_REG) { + continue; + } + + if (!ext) { + if (!strncasecmp(base, AP_TEMPFILE_BASE, AP_TEMPFILE_BASELEN) + && strlen(base) == AP_TEMPFILE_NAMELEN) { + d->basename += skip; + d->type = TEMP; + d->dsize = info.size; + apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d); + } + continue; + } + + if (!strcasecmp(ext, CACHE_HEADER_SUFFIX)) { + *ext = '\0'; + d->basename += skip; + /* if a user manually creates a '.header' file */ + if (d->basename[0] == '\0') { + continue; + } + t = apr_hash_get(h, d->basename, APR_HASH_KEY_STRING); + if (t) { + d = t; + } + d->type |= HEADER; + d->htime = info.mtime; + d->hsize = info.size; + apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d); + continue; + } + + if (!strcasecmp(ext, CACHE_DATA_SUFFIX)) { + *ext = '\0'; + d->basename += skip; + /* if a user manually creates a '.data' file */ + if (d->basename[0] == '\0') { + continue; + } + t = apr_hash_get(h, d->basename, APR_HASH_KEY_STRING); + if (t) { + d = t; + } + d->type |= DATA; + d->dtime = info.mtime; + d->dsize = info.size; + apr_hash_set(h, d->basename, APR_HASH_KEY_STRING, d); + } + } + + if (interrupted) { + return 1; + } + + path[baselen] = '\0'; + + for (i = apr_hash_first(p, h); i && !interrupted; i = apr_hash_next(i)) { + void *hvalue; + apr_uint32_t format; + + apr_hash_this(i, NULL, NULL, &hvalue); + d = hvalue; + + switch(d->type) { + case HEADERDATA: + nextpath = apr_pstrcat(p, path, "/", d->basename, + CACHE_HEADER_SUFFIX, NULL); + if (apr_file_open(&fd, nextpath, APR_FOPEN_READ | APR_FOPEN_BINARY, + APR_OS_DEFAULT, p) == APR_SUCCESS) { + len = sizeof(format); + if (apr_file_read_full(fd, &format, len, + &len) == APR_SUCCESS) { + if (format == DISK_FORMAT_VERSION) { + apr_off_t offset = 0; + + apr_file_seek(fd, APR_SET, &offset); + + len = sizeof(disk_cache_info_t); + + if (apr_file_read_full(fd, &disk_info, len, + &len) == APR_SUCCESS) { + apr_file_close(fd); + e = apr_palloc(pool, sizeof(ENTRY)); + APR_RING_INSERT_TAIL(&root.link, e, _entry, link); + e->expire = disk_info.expire; + e->response_time = disk_info.response_time; + e->htime = d->htime; + e->dtime = d->dtime; + e->hsize = d->hsize; + e->dsize = d->dsize; + e->basename = apr_pstrdup(pool, d->basename); + if (!disk_info.has_body) { + delete_file(path, apr_pstrcat(p, path, "/", + d->basename, CACHE_DATA_SUFFIX, NULL), + nodes, p); + } + break; + } + else { + apr_file_close(fd); + } + } + else if (format == VARY_FORMAT_VERSION) { + apr_finfo_t finfo; + + /* This must be a URL that added Vary headers later, + * so kill the orphaned .data file + */ + apr_file_close(fd); + + if (apr_stat(&finfo, apr_pstrcat(p, nextpath, + CACHE_VDIR_SUFFIX, NULL), APR_FINFO_TYPE, p) + || finfo.filetype != APR_DIR) { + delete_entry(path, d->basename, nodes, p); + } + else { + delete_file(path, apr_pstrcat(p, path, "/", + d->basename, CACHE_DATA_SUFFIX, NULL), + nodes, p); + } + break; + } + else { + /* We didn't recognise the format, kill the files */ + apr_file_close(fd); + delete_entry(path, d->basename, nodes, p); + break; + } + } + else { + apr_file_close(fd); + } + + } + /* we have a somehow unreadable headers file which is associated + * with a data file. this may be caused by apache currently + * rewriting the headers file. thus we may delete the file set + * either in realclean mode or if the headers file modification + * timestamp is not within a specified positive or negative offset + * to the current time. + */ + current = apr_time_now(); + if (realclean || d->htime < current - deviation + || d->htime > current + deviation) { + delete_entry(path, d->basename, nodes, p); + unsolicited += d->hsize; + unsolicited += d->dsize; + } + break; + + /* single data and header files may be deleted either in realclean + * mode or if their modification timestamp is not within a + * specified positive or negative offset to the current time. + * this handling is necessary due to possible race conditions + * between apache and this process + */ + case HEADER: + current = apr_time_now(); + nextpath = apr_pstrcat(p, path, "/", d->basename, + CACHE_HEADER_SUFFIX, NULL); + if (apr_file_open(&fd, nextpath, APR_FOPEN_READ | APR_FOPEN_BINARY, + APR_OS_DEFAULT, p) == APR_SUCCESS) { + len = sizeof(format); + if (apr_file_read_full(fd, &format, len, + &len) == APR_SUCCESS) { + if (format == VARY_FORMAT_VERSION) { + apr_time_t expires; + + len = sizeof(expires); + + if (apr_file_read_full(fd, &expires, len, + &len) == APR_SUCCESS) { + apr_finfo_t finfo; + + apr_file_close(fd); + + if (apr_stat(&finfo, apr_pstrcat(p, nextpath, + CACHE_VDIR_SUFFIX, NULL), APR_FINFO_TYPE, p) + || finfo.filetype != APR_DIR) { + delete_entry(path, d->basename, nodes, p); + } + else if (expires < current) { + delete_entry(path, d->basename, nodes, p); + } + + break; + } + } + else if (format == DISK_FORMAT_VERSION) { + apr_off_t offset = 0; + + apr_file_seek(fd, APR_SET, &offset); + + len = sizeof(disk_cache_info_t); + + if (apr_file_read_full(fd, &disk_info, len, + &len) == APR_SUCCESS) { + apr_file_close(fd); + e = apr_palloc(pool, sizeof(ENTRY)); + APR_RING_INSERT_TAIL(&root.link, e, _entry, link); + e->expire = disk_info.expire; + e->response_time = disk_info.response_time; + e->htime = d->htime; + e->dtime = d->dtime; + e->hsize = d->hsize; + e->dsize = d->dsize; + e->basename = apr_pstrdup(pool, d->basename); + break; + } + else { + apr_file_close(fd); + } + } + else { + apr_file_close(fd); + delete_entry(path, d->basename, nodes, p); + break; + } + } + else { + apr_file_close(fd); + } + } + + if (realclean || d->htime < current - deviation + || d->htime > current + deviation) { + delete_entry(path, d->basename, nodes, p); + unsolicited += d->hsize; + } + break; + + case DATA: + current = apr_time_now(); + if (realclean || d->dtime < current - deviation + || d->dtime > current + deviation) { + delete_entry(path, d->basename, nodes, p); + unsolicited += d->dsize; + } + break; + + /* temp files may only be deleted in realclean mode which + * is asserted above if a tempfile is in the hash array + */ + case TEMP: + delete_file(path, d->basename, nodes, p); + unsolicited += d->dsize; + break; + } + } + + if (interrupted) { + return 1; + } + + apr_pool_destroy(p); + + if (benice) { + apr_sleep(NICE_DELAY); + } + + if (interrupted) { + return 1; + } + + return 0; +} + +/* + * purge cache entries + */ +static void purge(char *path, apr_pool_t *pool, apr_off_t max, + apr_off_t inodes, apr_off_t nodes, apr_off_t round) +{ + ENTRY *e, *n, *oldest; + + struct stats s; + s.sum = 0; + s.entries = 0; + s.dfuture = 0; + s.dexpired = 0; + s.dfresh = 0; + s.max = max; + s.nodes = nodes; + s.inodes = inodes; + s.ntotal = nodes; + + for (e = APR_RING_FIRST(&root.link); + e != APR_RING_SENTINEL(&root.link, _entry, link); + e = APR_RING_NEXT(e, link)) { + s.sum += round_up((apr_size_t)e->hsize, round); + s.sum += round_up((apr_size_t)e->dsize, round); + s.entries++; + } + + s.total = s.sum; + s.etotal = s.entries; + + if ((!s.max || s.sum <= s.max) && (!s.inodes || s.nodes <= s.inodes)) { + printstats(path, &s); + return; + } + + /* process all entries with a timestamp in the future, this may + * happen if a wrong system time is corrected + */ + + for (e = APR_RING_FIRST(&root.link); + e != APR_RING_SENTINEL(&root.link, _entry, link) && !interrupted;) { + n = APR_RING_NEXT(e, link); + if (e->response_time > now || e->htime > now || e->dtime > now) { + delete_entry(path, e->basename, &s.nodes, pool); + s.sum -= round_up((apr_size_t)e->hsize, round); + s.sum -= round_up((apr_size_t)e->dsize, round); + s.entries--; + s.dfuture++; + APR_RING_REMOVE(e, link); + if ((!s.max || s.sum <= s.max) && (!s.inodes || s.nodes <= s.inodes)) { + if (!interrupted) { + printstats(path, &s); + } + return; + } + } + e = n; + } + + if (interrupted) { + return; + } + + /* process all entries which are expired */ + for (e = APR_RING_FIRST(&root.link); + e != APR_RING_SENTINEL(&root.link, _entry, link) && !interrupted;) { + n = APR_RING_NEXT(e, link); + if (e->expire != APR_DATE_BAD && e->expire < now) { + delete_entry(path, e->basename, &s.nodes, pool); + s.sum -= round_up((apr_size_t)e->hsize, round); + s.sum -= round_up((apr_size_t)e->dsize, round); + s.entries--; + s.dexpired++; + APR_RING_REMOVE(e, link); + if ((!s.max || s.sum <= s.max) && (!s.inodes || s.nodes <= s.inodes)) { + if (!interrupted) { + printstats(path, &s); + } + return; + } + } + e = n; + } + + if (interrupted) { + return; + } + + /* process remaining entries oldest to newest, the check for an empty + * ring actually isn't necessary except when the compiler does + * corrupt 64bit arithmetics which happened to me once, so better safe + * than sorry + */ + while (!((!s.max || s.sum <= s.max) && (!s.inodes || s.nodes <= s.inodes)) + && !interrupted && !APR_RING_EMPTY(&root.link, _entry, link)) { + oldest = APR_RING_FIRST(&root.link); + + for (e = APR_RING_NEXT(oldest, link); + e != APR_RING_SENTINEL(&root.link, _entry, link); + e = APR_RING_NEXT(e, link)) { + if (e->dtime < oldest->dtime) { + oldest = e; + } + } + + delete_entry(path, oldest->basename, &s.nodes, pool); + s.sum -= round_up((apr_size_t)oldest->hsize, round); + s.sum -= round_up((apr_size_t)oldest->dsize, round); + s.entries--; + s.dfresh++; + APR_RING_REMOVE(oldest, link); + } + + if (!interrupted) { + printstats(path, &s); + } +} + +static apr_status_t remove_directory(apr_pool_t *pool, const char *dir) +{ + apr_status_t rv; + apr_dir_t *dirp; + apr_finfo_t dirent; + + rv = apr_dir_open(&dirp, dir, pool); + if (APR_STATUS_IS_ENOENT(rv)) { + return rv; + } + if (rv != APR_SUCCESS) { + apr_file_printf(errfile, "Could not open directory %s: %pm" APR_EOL_STR, + dir, &rv); + return rv; + } + + while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) + == APR_SUCCESS) { + if (dirent.filetype == APR_DIR) { + if (strcmp(dirent.name, ".") && strcmp(dirent.name, "..")) { + rv = remove_directory(pool, apr_pstrcat(pool, dir, "/", + dirent.name, NULL)); + /* tolerate the directory not being empty, the cache may have + * attempted to recreate the directory in the mean time. + */ + if (APR_SUCCESS != rv && APR_ENOTEMPTY != rv) { + break; + } + } + } else { + const char *file = apr_pstrcat(pool, dir, "/", dirent.name, NULL); + rv = apr_file_remove(file, pool); + if (APR_SUCCESS != rv) { + apr_file_printf(errfile, + "Could not remove file '%s': %pm" APR_EOL_STR, file, + &rv); + break; + } + } + } + + apr_dir_close(dirp); + + if (rv == APR_SUCCESS) { + rv = apr_dir_remove(dir, pool); + if (APR_ENOTEMPTY == rv) { + rv = APR_SUCCESS; + } + if (rv != APR_SUCCESS) { + apr_file_printf(errfile, "Could not remove directory %s: %pm" APR_EOL_STR, + dir, &rv); + } + } + + return rv; +} + +static apr_status_t find_directory(apr_pool_t *pool, const char *base, + const char *rest) +{ + apr_status_t rv; + apr_dir_t *dirp; + apr_finfo_t dirent; + int found = 0, files = 0; + const char *header = apr_pstrcat(pool, rest, CACHE_HEADER_SUFFIX, NULL); + const char *data = apr_pstrcat(pool, rest, CACHE_DATA_SUFFIX, NULL); + const char *vdir = apr_pstrcat(pool, rest, CACHE_HEADER_SUFFIX, + CACHE_VDIR_SUFFIX, NULL); + const char *dirname = NULL; + + rv = apr_dir_open(&dirp, base, pool); + if (rv != APR_SUCCESS) { + apr_file_printf(errfile, "Could not open directory %s: %pm" APR_EOL_STR, + base, &rv); + return rv; + } + + rv = APR_ENOENT; + + while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) + == APR_SUCCESS) { + int len = strlen(dirent.name); + int restlen = strlen(rest); + if (dirent.filetype == APR_DIR && !strncmp(rest, dirent.name, len)) { + dirname = apr_pstrcat(pool, base, "/", dirent.name, NULL); + rv = find_directory(pool, dirname, rest + (len < restlen ? len + : restlen)); + if (APR_SUCCESS == rv) { + found = 1; + } + } + if (dirent.filetype == APR_DIR) { + if (!strcmp(dirent.name, vdir)) { + files = 1; + } + } + if (dirent.filetype == APR_REG) { + if (!strcmp(dirent.name, header) || !strcmp(dirent.name, data)) { + files = 1; + } + } + } + + apr_dir_close(dirp); + + if (files) { + rv = APR_SUCCESS; + if (!dryrun) { + const char *remove; + apr_status_t status; + + remove = apr_pstrcat(pool, base, "/", header, NULL); + status = apr_file_remove(remove, pool); + if (status != APR_SUCCESS && !APR_STATUS_IS_ENOENT(status)) { + apr_file_printf(errfile, "Could not remove file %s: %pm" APR_EOL_STR, + remove, &status); + rv = status; + } + + remove = apr_pstrcat(pool, base, "/", data, NULL); + status = apr_file_remove(remove, pool); + if (status != APR_SUCCESS && !APR_STATUS_IS_ENOENT(status)) { + apr_file_printf(errfile, "Could not remove file %s: %pm" APR_EOL_STR, + remove, &status); + rv = status; + } + + status = remove_directory(pool, apr_pstrcat(pool, base, "/", vdir, NULL)); + if (status != APR_SUCCESS && !APR_STATUS_IS_ENOENT(status)) { + rv = status; + } + } + } + + /* If asked to delete dirs, do so now. We don't care if it fails. + * If it fails, it likely means there was something else there. + */ + if (dirname && deldirs && !dryrun) { + apr_dir_remove(dirname, pool); + } + + if (found) { + return APR_SUCCESS; + } + + return rv; +} + +/** + * Delete a specific URL from the cache. + */ +static apr_status_t delete_url(apr_pool_t *pool, const char *proxypath, const char *url) +{ + apr_md5_ctx_t context; + unsigned char digest[16]; + char tmp[23]; + int i, k; + unsigned int x; + static const char enc_table[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@"; + + apr_md5_init(&context); + apr_md5_update(&context, (const unsigned char *) url, strlen(url)); + apr_md5_final(digest, &context); + + /* encode 128 bits as 22 characters, using a modified uuencoding + * the encoding is 3 bytes -> 4 characters* i.e. 128 bits is + * 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters + */ + for (i = 0, k = 0; i < 15; i += 3) { + x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2]; + tmp[k++] = enc_table[x >> 18]; + tmp[k++] = enc_table[(x >> 12) & 0x3f]; + tmp[k++] = enc_table[(x >> 6) & 0x3f]; + tmp[k++] = enc_table[x & 0x3f]; + } + + /* one byte left */ + x = digest[15]; + tmp[k++] = enc_table[x >> 2]; /* use up 6 bits */ + tmp[k++] = enc_table[(x << 4) & 0x3f]; + tmp[k] = 0; + + /* automatically find the directory levels */ + return find_directory(pool, proxypath, tmp); +} + +/* + * usage info + */ +#define NL APR_EOL_STR +static void usage(const char *error) +{ + if (error) { + apr_file_printf(errfile, "%s error: %s\n", shortname, error); + } + apr_file_printf(errfile, + "%s -- program for cleaning the disk cache." NL + "Usage: %s [-Dvtrn] -pPATH [-lLIMIT] [-LLIMIT] [-PPIDFILE]" NL + " %s [-nti] -dINTERVAL -pPATH [-lLIMIT] [-LLIMIT] [-PPIDFILE]" NL + " %s [-Dvt] -pPATH URL ..." NL + NL + "Options:" NL + " -d Daemonize and repeat cache cleaning every INTERVAL minutes." NL + " This option is mutually exclusive with the -D, -v and -r" NL + " options." NL + NL + " -D Do a dry run and don't delete anything. This option is mutually" NL + " exclusive with the -d option. When doing a dry run and deleting" NL + " directories with -t, the inodes reported deleted in the stats" NL + " cannot take into account the directories deleted, and will be" NL + " marked as an estimate." NL + NL + " -v Be verbose and print statistics. This option is mutually" NL + " exclusive with the -d option." NL + NL + " -r Clean thoroughly. This assumes that the Apache web server is " NL + " not running. This option is mutually exclusive with the -d" NL + " option and implies -t." NL + NL + " -n Be nice. This causes slower processing in favour of other" NL + " processes." NL + NL + " -t Delete all empty directories. By default only cache files are" NL + " removed, however with some configurations the large number of" NL + " directories created may require attention." NL + NL + " -p Specify PATH as the root directory of the disk cache." NL + NL + " -P Specify PIDFILE as the file to write the pid to." NL + NL + " -R Specify amount to round sizes up to." NL + NL + " -l Specify LIMIT as the total disk cache size limit. Attach 'K'," NL + " 'M' or 'G' to the number for specifying KBytes, MBytes or" NL + " GBytes." NL + NL + " -L Specify LIMIT as the total disk cache inode limit. 'K', 'M' or" NL + " 'G' suffix can also be used." NL + NL + " -i Be intelligent and run only when there was a modification of" NL + " the disk cache. This option is only possible together with the" NL + " -d option." NL + NL + " -a List the URLs currently stored in the cache. Variants of the" NL + " same URL will be listed once for each variant." NL + NL + " -A List the URLs currently stored in the cache, along with their" NL + " attributes in the following order: url, header size, body size," NL + " status, entity version, date, expiry, request time," NL + " response time, body present, head request." NL + NL + "Should an URL be provided on the command line, the URL will be" NL + "deleted from the cache. A reverse proxied URL is made up as follows:" NL + "http://<hostname>:<port><path>?[query]. So, for the path \"/\" on the" NL + "host \"localhost\" and port 80, the URL to delete becomes" NL + "\"http://localhost:80/?\". Note the '?' in the URL must always be" NL + "specified explicitly, whether a query string is present or not." NL, + shortname, + shortname, + shortname, + shortname + ); + + exit(1); +} +#undef NL + +static void usage_repeated_arg(apr_pool_t *pool, char option) +{ + usage(apr_psprintf(pool, + "The option '%c' cannot be specified more than once", + option)); +} + +static void log_pid(apr_pool_t *pool, const char *pidfilename, apr_file_t **pidfile) +{ + apr_status_t status; + pid_t mypid = getpid(); + + if (APR_SUCCESS == (status = apr_file_open(pidfile, pidfilename, + APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | + APR_FOPEN_DELONCLOSE, APR_FPROT_UREAD | APR_FPROT_UWRITE | + APR_FPROT_GREAD | APR_FPROT_WREAD, pool))) { + apr_file_printf(*pidfile, "%" APR_PID_T_FMT APR_EOL_STR, mypid); + } + else { + if (errfile) { + apr_file_printf(errfile, + "Could not write the pid file '%s': %pm" APR_EOL_STR, + pidfilename, &status); + } + exit(1); + } +} + +/* + * main + */ +int main(int argc, const char * const argv[]) +{ + apr_off_t max, inodes, round; + apr_time_t current, repeat, delay, previous; + apr_status_t status; + apr_pool_t *pool, *instance; + apr_getopt_t *o; + apr_finfo_t info; + apr_file_t *pidfile; + int retries, isdaemon, limit_found, inodes_found, intelligent, dowork; + char opt; + const char *arg; + char *proxypath, *path, *pidfilename; + + interrupted = 0; + repeat = 0; + isdaemon = 0; + dryrun = 0; + limit_found = 0; + inodes_found = 0; + max = 0; + inodes = 0; + round = 0; + verbose = 0; + realclean = 0; + benice = 0; + deldirs = 0; + intelligent = 0; + previous = 0; /* avoid compiler warning */ + proxypath = NULL; + pidfilename = NULL; + + if (apr_app_initialize(&argc, &argv, NULL) != APR_SUCCESS) { + return 1; + } + atexit(apr_terminate); + + if (argc) { + shortname = apr_filepath_name_get(argv[0]); + } + + if (apr_pool_create(&pool, NULL) != APR_SUCCESS) { + return 1; + } + apr_pool_abort_set(oom, pool); + apr_file_open_stderr(&errfile, pool); + apr_file_open_stdout(&outfile, pool); + apr_signal(SIGINT, setterm); + apr_signal(SIGTERM, setterm); + + apr_getopt_init(&o, pool, argc, argv); + + while (1) { + status = apr_getopt(o, "iDnvrtd:l:L:p:P:R:aA", &opt, &arg); + if (status == APR_EOF) { + break; + } + else if (status != APR_SUCCESS) { + usage(NULL); + } + else { + char *end; + apr_status_t rv; + switch (opt) { + case 'i': + if (intelligent) { + usage_repeated_arg(pool, opt); + } + intelligent = 1; + break; + + case 'D': + if (dryrun) { + usage_repeated_arg(pool, opt); + } + dryrun = 1; + break; + + case 'n': + if (benice) { + usage_repeated_arg(pool, opt); + } + benice = 1; + break; + + case 't': + if (deldirs) { + usage_repeated_arg(pool, opt); + } + deldirs = 1; + break; + + case 'v': + if (verbose) { + usage_repeated_arg(pool, opt); + } + verbose = 1; + break; + + case 'r': + if (realclean) { + usage_repeated_arg(pool, opt); + } + realclean = 1; + deldirs = 1; + break; + + case 'd': + if (isdaemon) { + usage_repeated_arg(pool, opt); + } + isdaemon = 1; + repeat = apr_atoi64(arg); + repeat *= SECS_PER_MIN; + repeat *= APR_USEC_PER_SEC; + break; + + case 'l': + if (limit_found) { + usage_repeated_arg(pool, opt); + } + limit_found = 1; + + do { + rv = apr_strtoff(&max, arg, &end, 10); + if (rv == APR_SUCCESS) { + if ((*end == 'K' || *end == 'k') && !end[1]) { + max *= KBYTE; + } + else if ((*end == 'M' || *end == 'm') && !end[1]) { + max *= MBYTE; + } + else if ((*end == 'G' || *end == 'g') && !end[1]) { + max *= GBYTE; + } + else if (*end && /* neither empty nor [Bb] */ + ((*end != 'B' && *end != 'b') || end[1])) { + rv = APR_EGENERAL; + } + } + if (rv != APR_SUCCESS) { + usage(apr_psprintf(pool, "Invalid limit: %s" + APR_EOL_STR APR_EOL_STR, arg)); + } + } while (0); + break; + + case 'L': + if (inodes_found) { + usage_repeated_arg(pool, opt); + } + inodes_found = 1; + + do { + rv = apr_strtoff(&inodes, arg, &end, 10); + if (rv == APR_SUCCESS) { + if ((*end == 'K' || *end == 'k') && !end[1]) { + inodes *= KBYTE; + } + else if ((*end == 'M' || *end == 'm') && !end[1]) { + inodes *= MBYTE; + } + else if ((*end == 'G' || *end == 'g') && !end[1]) { + inodes *= GBYTE; + } + else if (*end && /* neither empty nor [Bb] */ + ((*end != 'B' && *end != 'b') || end[1])) { + rv = APR_EGENERAL; + } + } + if (rv != APR_SUCCESS) { + usage(apr_psprintf(pool, "Invalid limit: %s" + APR_EOL_STR APR_EOL_STR, arg)); + } + } while (0); + break; + + case 'a': + if (listurls) { + usage_repeated_arg(pool, opt); + } + listurls = 1; + break; + + case 'A': + if (listurls) { + usage_repeated_arg(pool, opt); + } + listurls = 1; + listextended = 1; + break; + + case 'p': + if (proxypath) { + usage_repeated_arg(pool, opt); + } + proxypath = apr_pstrdup(pool, arg); + if ((status = apr_filepath_set(proxypath, pool)) != APR_SUCCESS) { + usage(apr_psprintf(pool, "Could not set filepath to '%s': %pm", + proxypath, &status)); + } + break; + + case 'P': + if (pidfilename) { + usage_repeated_arg(pool, opt); + } + pidfilename = apr_pstrdup(pool, arg); + break; + + case 'R': + if (round) { + usage_repeated_arg(pool, opt); + } + rv = apr_strtoff(&round, arg, &end, 10); + if (rv == APR_SUCCESS) { + if (*end) { + usage(apr_psprintf(pool, "Invalid round value: %s" + APR_EOL_STR APR_EOL_STR, arg)); + } + else if (round < 0) { + usage(apr_psprintf(pool, "Round value must be positive: %s" + APR_EOL_STR APR_EOL_STR, arg)); + } + } + if (rv != APR_SUCCESS) { + usage(apr_psprintf(pool, "Invalid round value: %s" + APR_EOL_STR APR_EOL_STR, arg)); + } + break; + + } /* switch */ + } /* else */ + } /* while */ + + if (argc <= 1) { + usage(NULL); + } + + if (!proxypath) { + usage("Option -p must be specified"); + } + + if (o->ind < argc) { + int deleted = 0; + int error = 0; + if (isdaemon) { + usage("Option -d cannot be used with URL arguments, aborting"); + } + if (intelligent) { + usage("Option -i cannot be used with URL arguments, aborting"); + } + if (limit_found) { + usage("Option -l and -L cannot be used with URL arguments, aborting"); + } + while (o->ind < argc) { + status = delete_url(pool, proxypath, argv[o->ind]); + if (APR_SUCCESS == status) { + if (verbose) { + apr_file_printf(errfile, "Removed: %s" APR_EOL_STR, + argv[o->ind]); + } + deleted = 1; + } + else if (APR_ENOENT == status) { + if (verbose) { + apr_file_printf(errfile, "Not cached: %s" APR_EOL_STR, + argv[o->ind]); + } + } + else { + if (verbose) { + apr_file_printf(errfile, "Error while removed: %s" APR_EOL_STR, + argv[o->ind]); + } + error = 1; + } + o->ind++; + } + return error ? 1 : deleted ? 0 : 2; + } + + if (isdaemon && repeat <= 0) { + usage("Option -d must be greater than zero"); + } + + if (isdaemon && (verbose || realclean || dryrun || listurls)) { + usage("Option -d cannot be used with -v, -r, -L or -D"); + } + + if (!isdaemon && intelligent) { + usage("Option -i cannot be used without -d"); + } + + if (!listurls && max <= 0 && inodes <= 0) { + usage("At least one of option -l or -L must be greater than zero"); + } + + if (apr_filepath_get(&path, 0, pool) != APR_SUCCESS) { + usage(apr_psprintf(pool, "Could not get the filepath: %pm", &status)); + } + baselen = strlen(path); + + if (pidfilename) { + log_pid(pool, pidfilename, &pidfile); /* before daemonizing, so we + * can report errors + */ + } + + if (listurls) { + list_urls(path, pool, round); + return (interrupted != 0); + } + +#ifndef DEBUG + if (isdaemon) { + apr_file_close(errfile); + errfile = NULL; + if (pidfilename) { + apr_file_close(pidfile); /* delete original pidfile only in parent */ + } + apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); + if (pidfilename) { + log_pid(pool, pidfilename, &pidfile); + } + } +#endif + + do { + apr_pool_create(&instance, pool); + + now = apr_time_now(); + APR_RING_INIT(&root.link, _entry, link); + delcount = 0; + unsolicited = 0; + dowork = 0; + + switch (intelligent) { + case 0: + dowork = 1; + break; + + case 1: + retries = STAT_ATTEMPTS; + status = APR_SUCCESS; + + do { + if (status != APR_SUCCESS) { + apr_sleep(STAT_DELAY); + } + status = apr_stat(&info, path, APR_FINFO_MTIME, instance); + } while (status != APR_SUCCESS && !interrupted && --retries); + + if (status == APR_SUCCESS) { + previous = info.mtime; + intelligent = 2; + } + dowork = 1; + break; + + case 2: + retries = STAT_ATTEMPTS; + status = APR_SUCCESS; + + do { + if (status != APR_SUCCESS) { + apr_sleep(STAT_DELAY); + } + status = apr_stat(&info, path, APR_FINFO_MTIME, instance); + } while (status != APR_SUCCESS && !interrupted && --retries); + + if (status == APR_SUCCESS) { + if (previous != info.mtime) { + dowork = 1; + } + previous = info.mtime; + break; + } + intelligent = 1; + dowork = 1; + break; + } + + if (dowork && !interrupted) { + apr_off_t nodes = 0; + if (!process_dir(path, instance, &nodes) && !interrupted) { + purge(path, instance, max, inodes, nodes, round); + } + else if (!isdaemon && !interrupted) { + apr_file_printf(errfile, "An error occurred, cache cleaning " + "aborted." APR_EOL_STR); + return 1; + } + + if (intelligent && !interrupted) { + retries = STAT_ATTEMPTS; + status = APR_SUCCESS; + do { + if (status != APR_SUCCESS) { + apr_sleep(STAT_DELAY); + } + status = apr_stat(&info, path, APR_FINFO_MTIME, instance); + } while (status != APR_SUCCESS && !interrupted && --retries); + + if (status == APR_SUCCESS) { + previous = info.mtime; + intelligent = 2; + } + else { + intelligent = 1; + } + } + } + + apr_pool_destroy(instance); + + current = apr_time_now(); + if (current < now) { + delay = repeat; + } + else if (current - now >= repeat) { + delay = repeat; + } + else { + delay = now + repeat - current; + } + + /* we can't sleep the whole delay time here apiece as this is racy + * with respect to interrupt delivery - think about what happens + * if we have tested for an interrupt, then get scheduled + * before the apr_sleep() call and while waiting for the cpu + * we do get an interrupt + */ + if (isdaemon) { + while (delay && !interrupted) { + if (delay > APR_USEC_PER_SEC) { + apr_sleep(APR_USEC_PER_SEC); + delay -= APR_USEC_PER_SEC; + } + else { + apr_sleep(delay); + delay = 0; + } + } + } + } while (isdaemon && !interrupted); + + if (!isdaemon && interrupted) { + apr_file_printf(errfile, "Cache cleaning aborted due to user " + "request." APR_EOL_STR); + return 1; + } + + return 0; +} diff --git a/support/htcacheclean.dep b/support/htcacheclean.dep new file mode 100644 index 0000000..0d5d0f8 --- /dev/null +++ b/support/htcacheclean.dep @@ -0,0 +1,37 @@ +# Microsoft Developer Studio Generated Dependency File, included by htcacheclean.mak + +.\htcacheclean.c : \ + "..\modules\cache\cache_common.h"\ + "..\modules\cache\cache_disk_common.h"\ + "..\srclib\apr-util\include\apr_buckets.h"\ + "..\srclib\apr-util\include\apr_date.h"\ + "..\srclib\apr-util\include\apr_md5.h"\ + "..\srclib\apr-util\include\apr_xlate.h"\ + "..\srclib\apr-util\include\apu.h"\ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_getopt.h"\ + "..\srclib\apr\include\apr_hash.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_mmap.h"\ + "..\srclib\apr\include\apr_network_io.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_ring.h"\ + "..\srclib\apr\include\apr_signal.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_thread_proc.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_want.h"\ + + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + diff --git a/support/htcacheclean.dsp b/support/htcacheclean.dsp new file mode 100644 index 0000000..b1422e0 --- /dev/null +++ b/support/htcacheclean.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="htcacheclean" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=htcacheclean - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "htcacheclean.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "htcacheclean.mak" CFG="htcacheclean - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "htcacheclean - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "htcacheclean - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "htcacheclean - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/htcacheclean_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/htcacheclean.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\htcacheclean.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/htcacheclean_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/htcacheclean.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\htcacheclean.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "htcacheclean - Win32 Release" +# Name "htcacheclean - Win32 Debug" +# Begin Source File + +SOURCE=.\htcacheclean.c +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/htcacheclean.mak b/support/htcacheclean.mak new file mode 100644 index 0000000..a6fc784 --- /dev/null +++ b/support/htcacheclean.mak @@ -0,0 +1,317 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on htcacheclean.dsp +!IF "$(CFG)" == "" +CFG=htcacheclean - Win32 Debug +!MESSAGE No configuration specified. Defaulting to htcacheclean - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "htcacheclean - Win32 Release" && "$(CFG)" != "htcacheclean - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "htcacheclean.mak" CFG="htcacheclean - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "htcacheclean - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "htcacheclean - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "htcacheclean - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\htcacheclean.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\htcacheclean.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\htcacheclean.obj" + -@erase "$(INTDIR)\htcacheclean.res" + -@erase "$(INTDIR)\htcacheclean_src.idb" + -@erase "$(INTDIR)\htcacheclean_src.pdb" + -@erase "$(OUTDIR)\htcacheclean.exe" + -@erase "$(OUTDIR)\htcacheclean.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htcacheclean_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htcacheclean.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\htcacheclean.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htcacheclean.pdb" /debug /out:"$(OUTDIR)\htcacheclean.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\htcacheclean.obj" \ + "$(INTDIR)\htcacheclean.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\htcacheclean.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\htcacheclean.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htcacheclean.exe" + if exist .\Release\htcacheclean.exe.manifest mt.exe -manifest .\Release\htcacheclean.exe.manifest -outputresource:.\Release\htcacheclean.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\htcacheclean.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\htcacheclean.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\htcacheclean.obj" + -@erase "$(INTDIR)\htcacheclean.res" + -@erase "$(INTDIR)\htcacheclean_src.idb" + -@erase "$(INTDIR)\htcacheclean_src.pdb" + -@erase "$(OUTDIR)\htcacheclean.exe" + -@erase "$(OUTDIR)\htcacheclean.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htcacheclean_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htcacheclean.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\htcacheclean.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htcacheclean.pdb" /debug /out:"$(OUTDIR)\htcacheclean.exe" +LINK32_OBJS= \ + "$(INTDIR)\htcacheclean.obj" \ + "$(INTDIR)\htcacheclean.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\htcacheclean.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\htcacheclean.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htcacheclean.exe" + if exist .\Debug\htcacheclean.exe.manifest mt.exe -manifest .\Debug\htcacheclean.exe.manifest -outputresource:.\Debug\htcacheclean.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("htcacheclean.dep") +!INCLUDE "htcacheclean.dep" +!ELSE +!MESSAGE Warning: cannot find "htcacheclean.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "htcacheclean - Win32 Release" || "$(CFG)" == "htcacheclean - Win32 Debug" + +!IF "$(CFG)" == "htcacheclean - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "htcacheclean - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=.\htcacheclean.c + +"$(INTDIR)\htcacheclean.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "htcacheclean - Win32 Release" + + +"$(INTDIR)\htcacheclean.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\htcacheclean.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility" $(SOURCE) + + +!ELSEIF "$(CFG)" == "htcacheclean - Win32 Debug" + + +"$(INTDIR)\htcacheclean.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\htcacheclean.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htcacheclean.exe" /d LONG_NAME="Apache htcacheclean command line utility" $(SOURCE) + + +!ENDIF + + +!ENDIF + diff --git a/support/htdbm.c b/support/htdbm.c new file mode 100644 index 0000000..40a3d23 --- /dev/null +++ b/support/htdbm.c @@ -0,0 +1,472 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * htdbm.c: simple program for manipulating DBM + * password databases for the Apache HTTP server + * + * Contributed by Mladen Turk <mturk mappingsoft.com> + * 12 Oct 2001 + */ + +#include "passwd_common.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_pools.h" +#include "apr_signal.h" +#include "apr_md5.h" +#include "apr_sha1.h" +#include "apr_dbm.h" +#include "apr_getopt.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_STRINGS_H +#include <strings.h> +#endif +#include <time.h> + +#if APR_CHARSET_EBCDIC +#include "apr_xlate.h" +#endif /*APR_CHARSET_EBCDIC*/ + +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_CRYPT_H +#include <crypt.h> +#endif + + +typedef struct htdbm_t htdbm_t; + +struct htdbm_t { + apr_dbm_t *dbm; + struct passwd_ctx ctx; +#if APR_CHARSET_EBCDIC + apr_xlate_t *to_ascii; +#endif + char *filename; + char *username; + char *comment; + char *type; + int create; + int rdonly; +}; + + +#define HTDBM_MAKE 0 +#define HTDBM_DELETE 1 +#define HTDBM_VERIFY 2 +#define HTDBM_LIST 3 +#define HTDBM_NOFILE 4 + +static void terminate(void) +{ + apr_terminate(); +#ifdef NETWARE + pressanykey(); +#endif +} + +static void htdbm_terminate(htdbm_t *htdbm) +{ + if (htdbm->dbm) + apr_dbm_close(htdbm->dbm); + htdbm->dbm = NULL; +} + +static htdbm_t *h; + +static void htdbm_interrupted(void) +{ + htdbm_terminate(h); + fprintf(stderr, "htdbm Interrupted !\n"); + exit(ERR_INTERRUPTED); +} + +static apr_status_t htdbm_init(apr_pool_t **pool, htdbm_t **hdbm) +{ + +#if APR_CHARSET_EBCDIC + apr_status_t rv; +#endif + + apr_pool_create( pool, NULL); + apr_pool_abort_set(abort_on_oom, *pool); + apr_file_open_stderr(&errfile, *pool); + apr_signal(SIGINT, (void (*)(int)) htdbm_interrupted); + + (*hdbm) = (htdbm_t *)apr_pcalloc(*pool, sizeof(htdbm_t)); + (*hdbm)->ctx.pool = *pool; + +#if APR_CHARSET_EBCDIC + rv = apr_xlate_open(&((*hdbm)->to_ascii), "ISO-8859-1", APR_DEFAULT_CHARSET, (*hdbm)->ctx.pool); + if (rv) { + fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", rv); + return APR_EGENERAL; + } + rv = apr_SHA1InitEBCDIC((*hdbm)->to_ascii); + if (rv) { + fprintf(stderr, "apr_SHA1InitEBCDIC()->%d\n", rv); + return APR_EGENERAL; + } + rv = apr_MD5InitEBCDIC((*hdbm)->to_ascii); + if (rv) { + fprintf(stderr, "apr_MD5InitEBCDIC()->%d\n", rv); + return APR_EGENERAL; + } +#endif /*APR_CHARSET_EBCDIC*/ + + /* Set MD5 as default */ + (*hdbm)->ctx.alg = ALG_APMD5; + (*hdbm)->type = "default"; + return APR_SUCCESS; +} + +static apr_status_t htdbm_open(htdbm_t *htdbm) +{ + if (htdbm->create) + return apr_dbm_open_ex(&htdbm->dbm, htdbm->type, htdbm->filename, APR_DBM_RWCREATE, + APR_OS_DEFAULT, htdbm->ctx.pool); + else + return apr_dbm_open_ex(&htdbm->dbm, htdbm->type, htdbm->filename, + htdbm->rdonly ? APR_DBM_READONLY : APR_DBM_READWRITE, + APR_OS_DEFAULT, htdbm->ctx.pool); +} + +static apr_status_t htdbm_save(htdbm_t *htdbm, int *changed) +{ + apr_datum_t key, val; + + if (!htdbm->username) + return APR_SUCCESS; + + key.dptr = htdbm->username; + key.dsize = strlen(htdbm->username); + if (apr_dbm_exists(htdbm->dbm, key)) + *changed = 1; + + val.dsize = strlen(htdbm->ctx.passwd); + if (!htdbm->comment) + val.dptr = htdbm->ctx.passwd; + else { + val.dptr = apr_pstrcat(htdbm->ctx.pool, htdbm->ctx.passwd, ":", + htdbm->comment, NULL); + val.dsize += (strlen(htdbm->comment) + 1); + } + return apr_dbm_store(htdbm->dbm, key, val); +} + +static apr_status_t htdbm_del(htdbm_t *htdbm) +{ + apr_datum_t key; + + key.dptr = htdbm->username; + key.dsize = strlen(htdbm->username); + if (!apr_dbm_exists(htdbm->dbm, key)) + return APR_ENOENT; + + return apr_dbm_delete(htdbm->dbm, key); +} + +static apr_status_t htdbm_verify(htdbm_t *htdbm) +{ + apr_datum_t key, val; + char *pwd; + char *rec, *cmnt; + + key.dptr = htdbm->username; + key.dsize = strlen(htdbm->username); + if (!apr_dbm_exists(htdbm->dbm, key)) + return APR_ENOENT; + if (apr_dbm_fetch(htdbm->dbm, key, &val) != APR_SUCCESS) + return APR_ENOENT; + rec = apr_pstrndup(htdbm->ctx.pool, val.dptr, val.dsize); + cmnt = strchr(rec, ':'); + if (cmnt) + pwd = apr_pstrndup(htdbm->ctx.pool, rec, cmnt - rec); + else + pwd = apr_pstrdup(htdbm->ctx.pool, rec); + return apr_password_validate(htdbm->ctx.passwd, pwd); +} + +static apr_status_t htdbm_list(htdbm_t *htdbm) +{ + apr_status_t rv; + apr_datum_t key, val; + char *cmnt; + int i = 0; + + rv = apr_dbm_firstkey(htdbm->dbm, &key); + if (rv != APR_SUCCESS) { + fprintf(stderr, "Empty database -- %s\n", htdbm->filename); + return APR_ENOENT; + } + fprintf(stderr, "Dumping records from database -- %s\n", htdbm->filename); + fprintf(stderr, " %-32s Comment\n", "Username"); + while (key.dptr != NULL) { + rv = apr_dbm_fetch(htdbm->dbm, key, &val); + if (rv != APR_SUCCESS) { + fprintf(stderr, "Failed getting data from %s\n", htdbm->filename); + return APR_EGENERAL; + } + /* Note: we don't store \0-terminators on our dbm data */ + fprintf(stderr, " %-32.*s", (int)key.dsize, key.dptr); + cmnt = memchr(val.dptr, ':', val.dsize); + if (cmnt) + fprintf(stderr, " %.*s", (int)(val.dptr+val.dsize - (cmnt+1)), cmnt + 1); + fprintf(stderr, "\n"); + rv = apr_dbm_nextkey(htdbm->dbm, &key); + if (rv != APR_SUCCESS) + fprintf(stderr, "Failed getting NextKey\n"); + ++i; + } + + fprintf(stderr, "Total #records : %d\n", i); + return APR_SUCCESS; +} + +static int htdbm_make(htdbm_t *htdbm) +{ + char cpw[MAX_STRING_LEN]; + int ret; + + htdbm->ctx.out = cpw; + htdbm->ctx.out_len = sizeof(cpw); + ret = mkhash(&htdbm->ctx); + if (ret != 0) { + fprintf(stderr, "Error: %s\n", htdbm->ctx.errstr); + return ret; + } + htdbm->ctx.passwd = apr_pstrdup(htdbm->ctx.pool, cpw); + return 0; +} + +static apr_status_t htdbm_valid_username(htdbm_t *htdbm) +{ + if (!htdbm->username || (strlen(htdbm->username) > 64) || (strlen(htdbm->username) < 1)) { + fprintf(stderr, "Invalid username length\n"); + return APR_EINVAL; + } + if (strchr(htdbm->username, ':')) { + fprintf(stderr, "Username contains invalid characters\n"); + return APR_EINVAL; + } + return APR_SUCCESS; +} + +static void htdbm_usage(void) +{ + fprintf(stderr, + "htdbm -- program for manipulating DBM password databases.\n\n" + "Usage: htdbm [-cimBdpstvx] [-C cost] [-TDBTYPE] database username\n" + " -b[cmBdptsv] [-C cost] [-TDBTYPE] database username password\n" + " -n[imBdpst] [-C cost] username\n" + " -nb[mBdpst] [-C cost] username password\n" + " -v[imBdps] [-C cost] [-TDBTYPE] database username\n" + " -vb[mBdps] [-C cost] [-TDBTYPE] database username password\n" + " -x [-TDBTYPE] database username\n" + " -l [-TDBTYPE] database\n" + "Options:\n" + " -c Create a new database.\n" + " -n Don't update database; display results on stdout.\n" + " -b Use the password from the command line rather than prompting for it.\n" + " -i Read password from stdin without verification (for script usage).\n" + " -m Force MD5 encryption of the password (default).\n" + " -B Force BCRYPT encryption of the password (very secure).\n" + " -C Set the computing time used for the bcrypt algorithm\n" + " (higher is more secure but slower, default: %d, valid: 4 to 31).\n" + " -d Force CRYPT encryption of the password (8 chars max, insecure).\n" + " -s Force SHA encryption of the password (insecure).\n" + " -p Do not encrypt the password (plaintext, insecure).\n" + " -T DBM Type (SDBM|GDBM|DB|default).\n" + " -l Display usernames from database on stdout.\n" + " -v Verify the username/password.\n" + " -x Remove the username record from database.\n" + " -t The last param is username comment.\n" + "The SHA algorithm does not use a salt and is less secure than the " + "MD5 algorithm.\n", + BCRYPT_DEFAULT_COST); + exit(ERR_SYNTAX); +} + +int main(int argc, const char * const argv[]) +{ + apr_pool_t *pool; + apr_status_t rv; + char errbuf[MAX_STRING_LEN]; + int need_file = 1; + int need_user = 1; + int need_pwd = 1; + int need_cmnt = 0; + int changed = 0; + int cmd = HTDBM_MAKE; + int i, ret, args_left = 2; + apr_getopt_t *state; + char opt; + const char *opt_arg; + + apr_app_initialize(&argc, &argv, NULL); + atexit(terminate); + + if ((rv = htdbm_init(&pool, &h)) != APR_SUCCESS) { + fprintf(stderr, "Unable to initialize htdbm terminating!\n"); + apr_strerror(rv, errbuf, sizeof(errbuf)); + exit(1); + } + + rv = apr_getopt_init(&state, pool, argc, argv); + if (rv != APR_SUCCESS) + exit(ERR_SYNTAX); + + while ((rv = apr_getopt(state, "cnmspdBbtivxlC:T:", &opt, &opt_arg)) == APR_SUCCESS) { + switch (opt) { + case 'c': + h->create = 1; + break; + case 'n': + need_file = 0; + cmd = HTDBM_NOFILE; + args_left--; + break; + case 'l': + need_pwd = 0; + need_user = 0; + cmd = HTDBM_LIST; + h->rdonly = 1; + args_left--; + break; + case 't': + need_cmnt = 1; + args_left++; + break; + case 'T': + h->type = apr_pstrdup(h->ctx.pool, opt_arg); + break; + case 'v': + h->rdonly = 1; + cmd = HTDBM_VERIFY; + break; + case 'x': + need_pwd = 0; + cmd = HTDBM_DELETE; + break; + default: + ret = parse_common_options(&h->ctx, opt, opt_arg); + if (ret) { + fprintf(stderr, "Error: %s\n", h->ctx.errstr); + exit(ret); + } + } + } + if (h->ctx.passwd_src == PW_ARG) { + need_pwd = 0; + args_left++; + } + /* + * Make sure we still have exactly the right number of arguments left + * (the filename, the username, and possibly the password if -b was + * specified). + */ + i = state->ind; + if (rv != APR_EOF || argc - i != args_left) + htdbm_usage(); + + if (need_file) { + h->filename = apr_pstrdup(h->ctx.pool, argv[i++]); + if ((rv = htdbm_open(h)) != APR_SUCCESS) { + fprintf(stderr, "Error opening database %s\n", h->filename); + apr_strerror(rv, errbuf, sizeof(errbuf)); + fprintf(stderr,"%s\n",errbuf); + exit(ERR_FILEPERM); + } + } + if (need_user) { + h->username = apr_pstrdup(pool, argv[i++]); + if (htdbm_valid_username(h) != APR_SUCCESS) + exit(ERR_BADUSER); + } + if (h->ctx.passwd_src == PW_ARG) + h->ctx.passwd = apr_pstrdup(pool, argv[i++]); + + if (need_pwd) { + ret = get_password(&h->ctx); + if (ret) { + fprintf(stderr, "Error: %s\n", h->ctx.errstr); + exit(ret); + } + } + if (need_cmnt) + h->comment = apr_pstrdup(pool, argv[i++]); + + switch (cmd) { + case HTDBM_VERIFY: + if ((rv = htdbm_verify(h)) != APR_SUCCESS) { + if (APR_STATUS_IS_ENOENT(rv)) { + fprintf(stderr, "The user '%s' could not be found in database\n", h->username); + exit(ERR_BADUSER); + } + else { + fprintf(stderr, "Password mismatch for user '%s'\n", h->username); + exit(ERR_PWMISMATCH); + } + } + else + fprintf(stderr, "Password validated for user '%s'\n", h->username); + break; + case HTDBM_DELETE: + if (htdbm_del(h) != APR_SUCCESS) { + fprintf(stderr, "Cannot find user '%s' in database\n", h->username); + exit(ERR_BADUSER); + } + h->username = NULL; + changed = 1; + break; + case HTDBM_LIST: + htdbm_list(h); + break; + default: + ret = htdbm_make(h); + if (ret) + exit(ret); + break; + } + if (need_file && !h->rdonly) { + if ((rv = htdbm_save(h, &changed)) != APR_SUCCESS) { + apr_strerror(rv, errbuf, sizeof(errbuf)); + exit(ERR_FILEPERM); + } + fprintf(stdout, "Database %s %s.\n", h->filename, + h->create ? "created" : (changed ? "modified" : "updated")); + } + if (cmd == HTDBM_NOFILE) { + if (!need_cmnt) { + fprintf(stderr, "%s:%s\n", h->username, h->ctx.passwd); + } + else { + fprintf(stderr, "%s:%s:%s\n", h->username, h->ctx.passwd, + h->comment); + } + } + htdbm_terminate(h); + + return 0; /* Suppress compiler warning. */ +} diff --git a/support/htdbm.dep b/support/htdbm.dep new file mode 100644 index 0000000..c6b60d8 --- /dev/null +++ b/support/htdbm.dep @@ -0,0 +1,58 @@ +# Microsoft Developer Studio Generated Dependency File, included by htdbm.mak + +.\htdbm.c : \ + "..\srclib\apr-util\include\apr_dbm.h"\ + "..\srclib\apr-util\include\apr_md5.h"\ + "..\srclib\apr-util\include\apr_sha1.h"\ + "..\srclib\apr-util\include\apr_xlate.h"\ + "..\srclib\apr-util\include\apu.h"\ + "..\srclib\apr-util\include\apu_version.h"\ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_getopt.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_signal.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_version.h"\ + "..\srclib\apr\include\apr_want.h"\ + ".\passwd_common.h"\ + + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + + +.\passwd_common.c : \ + "..\srclib\apr-util\include\apr_md5.h"\ + "..\srclib\apr-util\include\apr_sha1.h"\ + "..\srclib\apr-util\include\apr_xlate.h"\ + "..\srclib\apr-util\include\apu.h"\ + "..\srclib\apr-util\include\apu_version.h"\ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_version.h"\ + "..\srclib\apr\include\apr_want.h"\ + ".\passwd_common.h"\ + diff --git a/support/htdbm.dsp b/support/htdbm.dsp new file mode 100644 index 0000000..c1d5494 --- /dev/null +++ b/support/htdbm.dsp @@ -0,0 +1,110 @@ +# Microsoft Developer Studio Project File - Name="htdbm" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=htdbm - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "htdbm.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "htdbm.mak" CFG="htdbm - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "htdbm - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "htdbm - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "htdbm - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/htdbm_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/htdbm.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib rpcrt4.lib ws2_32.lib shell32.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\htdbm.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "htdbm - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/htdbm_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/htdbm.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\htdbm.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "htdbm - Win32 Release" +# Name "htdbm - Win32 Debug" +# Begin Source File + +SOURCE=.\htdbm.c +# End Source File +# Begin Source File + +SOURCE=.\passwd_common.c +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/htdbm.mak b/support/htdbm.mak new file mode 100644 index 0000000..f4379f7 --- /dev/null +++ b/support/htdbm.mak @@ -0,0 +1,326 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on htdbm.dsp +!IF "$(CFG)" == "" +CFG=htdbm - Win32 Debug +!MESSAGE No configuration specified. Defaulting to htdbm - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "htdbm - Win32 Release" && "$(CFG)" != "htdbm - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "htdbm.mak" CFG="htdbm - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "htdbm - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "htdbm - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "htdbm - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\htdbm.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\htdbm.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\htdbm.obj" + -@erase "$(INTDIR)\htdbm.res" + -@erase "$(INTDIR)\htdbm_src.idb" + -@erase "$(INTDIR)\htdbm_src.pdb" + -@erase "$(INTDIR)\passwd_common.obj" + -@erase "$(OUTDIR)\htdbm.exe" + -@erase "$(OUTDIR)\htdbm.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htdbm_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htdbm.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdbm.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htdbm.pdb" /debug /out:"$(OUTDIR)\htdbm.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\htdbm.obj" \ + "$(INTDIR)\passwd_common.obj" \ + "$(INTDIR)\htdbm.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\htdbm.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\htdbm.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htdbm.exe" + if exist .\Release\htdbm.exe.manifest mt.exe -manifest .\Release\htdbm.exe.manifest -outputresource:.\Release\htdbm.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "htdbm - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\htdbm.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\htdbm.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\htdbm.obj" + -@erase "$(INTDIR)\htdbm.res" + -@erase "$(INTDIR)\htdbm_src.idb" + -@erase "$(INTDIR)\htdbm_src.pdb" + -@erase "$(INTDIR)\passwd_common.obj" + -@erase "$(OUTDIR)\htdbm.exe" + -@erase "$(OUTDIR)\htdbm.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htdbm_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htdbm.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdbm.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htdbm.pdb" /debug /out:"$(OUTDIR)\htdbm.exe" +LINK32_OBJS= \ + "$(INTDIR)\htdbm.obj" \ + "$(INTDIR)\passwd_common.obj" \ + "$(INTDIR)\htdbm.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\htdbm.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\htdbm.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htdbm.exe" + if exist .\Debug\htdbm.exe.manifest mt.exe -manifest .\Debug\htdbm.exe.manifest -outputresource:.\Debug\htdbm.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("htdbm.dep") +!INCLUDE "htdbm.dep" +!ELSE +!MESSAGE Warning: cannot find "htdbm.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "htdbm - Win32 Release" || "$(CFG)" == "htdbm - Win32 Debug" + +!IF "$(CFG)" == "htdbm - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "htdbm - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "htdbm - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "htdbm - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=.\htdbm.c + +"$(INTDIR)\htdbm.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "htdbm - Win32 Release" + + +"$(INTDIR)\htdbm.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\htdbm.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility" $(SOURCE) + + +!ELSEIF "$(CFG)" == "htdbm - Win32 Debug" + + +"$(INTDIR)\htdbm.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\htdbm.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdbm.exe" /d LONG_NAME="Apache htdbm command line utility" $(SOURCE) + + +!ENDIF + +SOURCE=.\passwd_common.c + +"$(INTDIR)\passwd_common.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/support/htdigest.c b/support/htdigest.c new file mode 100644 index 0000000..43f7054 --- /dev/null +++ b/support/htdigest.c @@ -0,0 +1,303 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + ****************************************************************************** + * NOTE! This program is not safe as a setuid executable! Do not make it + * setuid! + ****************************************************************************** + *****************************************************************************/ +/* + * htdigest.c: simple program for manipulating digest passwd file for Apache + * + * by Alexei Kosut, based on htpasswd.c, by Rob McCool + */ + +#include "apr.h" +#include "apr_file_io.h" +#include "apr_md5.h" +#include "apr_lib.h" /* for apr_getpass() */ +#include "apr_general.h" +#include "apr_signal.h" +#include "apr_strings.h" /* for apr_pstrdup() */ + +#define APR_WANT_STDIO +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#if APR_HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef WIN32 +#include <conio.h> +#endif + + +#if APR_CHARSET_EBCDIC +#define LF '\n' +#define CR '\r' +#else +#define LF 10 +#define CR 13 +#endif /* APR_CHARSET_EBCDIC */ + +#define MAX_STRING_LEN 256 +#define MAX_LINE_LEN 768 + +apr_file_t *tfp = NULL; +apr_file_t *errfile; +apr_pool_t *cntxt; +#if APR_CHARSET_EBCDIC +apr_xlate_t *to_ascii; +#endif + +static void cleanup_tempfile_and_exit(int rc) +{ + if (tfp) { + apr_file_close(tfp); + } + exit(rc); +} + +static int getword(char *word, char *line, char stop) +{ + int x = 0, y; + + for (x = 0; ((line[x]) && (line[x] != stop)); x++) { + if (x == (MAX_STRING_LEN - 1)) { + return 1; + } + word[x] = line[x]; + } + + word[x] = '\0'; + if (line[x]) + ++x; + y = 0; + + while ((line[y++] = line[x++])); + + return 0; +} + +static int get_line(char *s, int n, apr_file_t *f) +{ + int i = 0; + char ch; + apr_status_t rv = APR_EINVAL; + + /* we need 2 remaining bytes in buffer */ + while (i < (n - 2) && + ((rv = apr_file_getc(&ch, f)) == APR_SUCCESS) && (ch != '\n')) { + s[i++] = ch; + } + /* First remaining byte potentially used here */ + if (ch == '\n') + s[i++] = ch; + /* Second remaining byte used here */ + s[i] = '\0'; + + if (rv != APR_SUCCESS) + return 1; + + return 0; +} + +static void putline(apr_file_t *f, char *l) +{ + int x; + + for (x = 0; l[x]; x++) + apr_file_putc(l[x], f); +} + + +static void add_password(const char *user, const char *realm, apr_file_t *f) +{ + char *pw; + apr_md5_ctx_t context; + unsigned char digest[16]; + char string[MAX_LINE_LEN]; /* this includes room for 2 * ':' + '\0' */ + char pwin[MAX_STRING_LEN]; + char pwv[MAX_STRING_LEN]; + unsigned int i; + apr_size_t len = sizeof(pwin); + + if (apr_password_get("New password: ", pwin, &len) != APR_SUCCESS) { + apr_file_printf(errfile, "password too long"); + cleanup_tempfile_and_exit(5); + } + len = sizeof(pwin); + apr_password_get("Re-type new password: ", pwv, &len); + if (strcmp(pwin, pwv) != 0) { + apr_file_printf(errfile, "They don't match, sorry.\n"); + cleanup_tempfile_and_exit(1); + } + pw = pwin; + apr_file_printf(f, "%s:%s:", user, realm); + + /* Do MD5 stuff */ + apr_snprintf(string, sizeof(string), "%s:%s:%s", user, realm, pw); + + apr_md5_init(&context); +#if APR_CHARSET_EBCDIC + apr_md5_set_xlate(&context, to_ascii); +#endif + apr_md5_update(&context, (unsigned char *) string, strlen(string)); + apr_md5_final(digest, &context); + + for (i = 0; i < 16; i++) + apr_file_printf(f, "%02x", digest[i]); + + apr_file_printf(f, "\n"); +} + +static void usage(void) +{ + apr_file_printf(errfile, "Usage: htdigest [-c] passwordfile realm username\n"); + apr_file_printf(errfile, "The -c flag creates a new file.\n"); + exit(1); +} + +static void interrupted(void) +{ + apr_file_printf(errfile, "Interrupted.\n"); + cleanup_tempfile_and_exit(1); +} + +static void terminate(void) +{ + apr_terminate(); +#ifdef NETWARE + pressanykey(); +#endif +} + +int main(int argc, const char * const argv[]) +{ + apr_file_t *f; + apr_status_t rv; + char tn[] = "htdigest.tmp.XXXXXX"; + char *dirname; + char user[MAX_STRING_LEN]; + char realm[MAX_STRING_LEN]; + char line[MAX_LINE_LEN]; + char l[MAX_LINE_LEN]; + char w[MAX_STRING_LEN]; + char x[MAX_STRING_LEN]; + int found; + + apr_app_initialize(&argc, &argv, NULL); + atexit(terminate); + apr_pool_create(&cntxt, NULL); + apr_file_open_stderr(&errfile, cntxt); + +#if APR_CHARSET_EBCDIC + rv = apr_xlate_open(&to_ascii, "ISO-8859-1", APR_DEFAULT_CHARSET, cntxt); + if (rv) { + apr_file_printf(errfile, "apr_xlate_open(): %pm (%d)\n", + &rv, rv); + exit(1); + } +#endif + + apr_signal(SIGINT, (void (*)(int)) interrupted); + if (argc == 5) { + if (strcmp(argv[1], "-c")) + usage(); + rv = apr_file_open(&f, argv[2], APR_WRITE | APR_CREATE, + APR_OS_DEFAULT, cntxt); + if (rv != APR_SUCCESS) { + apr_file_printf(errfile, "Could not open passwd file %s for writing: %pm\n", + argv[2], &rv); + exit(1); + } + apr_cpystrn(user, argv[4], sizeof(user)); + apr_cpystrn(realm, argv[3], sizeof(realm)); + apr_file_printf(errfile, "Adding password for %s in realm %s.\n", + user, realm); + add_password(user, realm, f); + apr_file_close(f); + exit(0); + } + else if (argc != 4) + usage(); + + if (apr_temp_dir_get((const char**)&dirname, cntxt) != APR_SUCCESS) { + apr_file_printf(errfile, "%s: could not determine temp dir\n", + argv[0]); + exit(1); + } + dirname = apr_psprintf(cntxt, "%s/%s", dirname, tn); + + if (apr_file_mktemp(&tfp, dirname, 0, cntxt) != APR_SUCCESS) { + apr_file_printf(errfile, "Could not open temp file %s.\n", dirname); + exit(1); + } + + if (apr_file_open(&f, argv[1], APR_READ, APR_OS_DEFAULT, cntxt) != APR_SUCCESS) { + apr_file_printf(errfile, + "Could not open passwd file %s for reading.\n", argv[1]); + apr_file_printf(errfile, "Use -c option to create new one.\n"); + cleanup_tempfile_and_exit(1); + } + apr_cpystrn(user, argv[3], sizeof(user)); + apr_cpystrn(realm, argv[2], sizeof(realm)); + + found = 0; + while (!(get_line(line, sizeof(line), f))) { + if (found || (line[0] == '#') || (!line[0])) { + putline(tfp, line); + continue; + } + strcpy(l, line); + if (getword(w, l, ':') || getword(x, l, ':')) { + apr_file_printf(errfile, "The following line contains a string longer than the " + "allowed maximum size (%i): %s\n", MAX_STRING_LEN - 1, line); + cleanup_tempfile_and_exit(1); + } + if (strcmp(user, w) || strcmp(realm, x)) { + putline(tfp, line); + continue; + } + else { + apr_file_printf(errfile, "Changing password for user %s in realm %s\n", + user, realm); + add_password(user, realm, tfp); + found = 1; + } + } + if (!found) { + apr_file_printf(errfile, "Adding user %s in realm %s\n", user, realm); + add_password(user, realm, tfp); + } + apr_file_close(f); + + /* The temporary file has all the data, just copy it to the new location. + */ + if (apr_file_copy(dirname, argv[1], APR_OS_DEFAULT, cntxt) != + APR_SUCCESS) { + apr_file_printf(errfile, "%s: unable to update file %s\n", + argv[0], argv[1]); + } + apr_file_close(tfp); + + return 0; +} diff --git a/support/htdigest.dep b/support/htdigest.dep new file mode 100644 index 0000000..2bde4ac --- /dev/null +++ b/support/htdigest.dep @@ -0,0 +1,27 @@ +# Microsoft Developer Studio Generated Dependency File, included by htdigest.mak + +.\htdigest.c : \ + "..\srclib\apr-util\include\apr_md5.h"\ + "..\srclib\apr-util\include\apr_xlate.h"\ + "..\srclib\apr-util\include\apu.h"\ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_signal.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_want.h"\ + + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + diff --git a/support/htdigest.dsp b/support/htdigest.dsp new file mode 100644 index 0000000..bc3cffe --- /dev/null +++ b/support/htdigest.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="htdigest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=htdigest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "htdigest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "htdigest.mak" CFG="htdigest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "htdigest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "htdigest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "htdigest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/htdigest_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/htdigest.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\htdigest.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "htdigest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/htdigest_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/htdigest.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\htdigest.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "htdigest - Win32 Release" +# Name "htdigest - Win32 Debug" +# Begin Source File + +SOURCE=.\htdigest.c +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/htdigest.mak b/support/htdigest.mak new file mode 100644 index 0000000..acccd23 --- /dev/null +++ b/support/htdigest.mak @@ -0,0 +1,317 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on htdigest.dsp +!IF "$(CFG)" == "" +CFG=htdigest - Win32 Debug +!MESSAGE No configuration specified. Defaulting to htdigest - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "htdigest - Win32 Release" && "$(CFG)" != "htdigest - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "htdigest.mak" CFG="htdigest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "htdigest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "htdigest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "htdigest - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\htdigest.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\htdigest.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\htdigest.obj" + -@erase "$(INTDIR)\htdigest.res" + -@erase "$(INTDIR)\htdigest_src.idb" + -@erase "$(INTDIR)\htdigest_src.pdb" + -@erase "$(OUTDIR)\htdigest.exe" + -@erase "$(OUTDIR)\htdigest.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htdigest_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htdigest.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdigest.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htdigest.pdb" /debug /out:"$(OUTDIR)\htdigest.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\htdigest.obj" \ + "$(INTDIR)\htdigest.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\htdigest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\htdigest.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htdigest.exe" + if exist .\Release\htdigest.exe.manifest mt.exe -manifest .\Release\htdigest.exe.manifest -outputresource:.\Release\htdigest.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "htdigest - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\htdigest.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\htdigest.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\htdigest.obj" + -@erase "$(INTDIR)\htdigest.res" + -@erase "$(INTDIR)\htdigest_src.idb" + -@erase "$(INTDIR)\htdigest_src.pdb" + -@erase "$(OUTDIR)\htdigest.exe" + -@erase "$(OUTDIR)\htdigest.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htdigest_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htdigest.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\htdigest.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htdigest.pdb" /debug /out:"$(OUTDIR)\htdigest.exe" +LINK32_OBJS= \ + "$(INTDIR)\htdigest.obj" \ + "$(INTDIR)\htdigest.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\htdigest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\htdigest.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htdigest.exe" + if exist .\Debug\htdigest.exe.manifest mt.exe -manifest .\Debug\htdigest.exe.manifest -outputresource:.\Debug\htdigest.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("htdigest.dep") +!INCLUDE "htdigest.dep" +!ELSE +!MESSAGE Warning: cannot find "htdigest.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "htdigest - Win32 Release" || "$(CFG)" == "htdigest - Win32 Debug" + +!IF "$(CFG)" == "htdigest - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "htdigest - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "htdigest - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "htdigest - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=.\htdigest.c + +"$(INTDIR)\htdigest.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "htdigest - Win32 Release" + + +"$(INTDIR)\htdigest.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\htdigest.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility" $(SOURCE) + + +!ELSEIF "$(CFG)" == "htdigest - Win32 Debug" + + +"$(INTDIR)\htdigest.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\htdigest.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htdigest.exe" /d LONG_NAME="Apache htdigest command line utility" $(SOURCE) + + +!ENDIF + + +!ENDIF + diff --git a/support/htpasswd.c b/support/htpasswd.c new file mode 100644 index 0000000..7dd5af9 --- /dev/null +++ b/support/htpasswd.c @@ -0,0 +1,524 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + ****************************************************************************** + * NOTE! This program is not safe as a setuid executable! Do not make it + * setuid! + ****************************************************************************** + *****************************************************************************/ +/* + * htpasswd.c: simple program for manipulating password file for + * the Apache HTTP server + * + * Originally by Rob McCool + * + * Exit values: + * 0: Success + * 1: Failure; file access/permission problem + * 2: Failure; command line syntax problem (usage message issued) + * 3: Failure; password verification failure + * 4: Failure; operation interrupted (such as with CTRL/C) + * 5: Failure; buffer would overflow (username, filename, or computed + * record too long) + * 6: Failure; username contains illegal or reserved characters + * 7: Failure; file is not a valid htpasswd file + */ + +#include "passwd_common.h" +#include "apr_signal.h" +#include "apr_getopt.h" + +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif + +#include "apr_md5.h" +#include "apr_sha1.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef WIN32 +#include <conio.h> +#define unlink _unlink +#endif + +#define APHTP_NEWFILE 1 +#define APHTP_NOFILE 2 +#define APHTP_DELUSER 4 +#define APHTP_VERIFY 8 + +apr_file_t *ftemp = NULL; + +static int mkrecord(struct passwd_ctx *ctx, char *user) +{ + char hash_str[MAX_STRING_LEN]; + int ret; + + ctx->out = hash_str; + ctx->out_len = sizeof(hash_str); + + ret = mkhash(ctx); + if (ret) { + ctx->out = NULL; + ctx->out_len = 0; + return ret; + } + + ctx->out = apr_pstrcat(ctx->pool, user, ":", hash_str, NL, NULL); + ctx->out_len = strlen(ctx->out); + if (ctx->out_len >= MAX_STRING_LEN) { + ctx->errstr = "resultant record too long"; + return ERR_OVERFLOW; + } + return 0; +} + +static void usage(void) +{ + apr_file_printf(errfile, "Usage:" NL + "\thtpasswd [-cimBdpsDv] [-C cost] passwordfile username" NL + "\thtpasswd -b[cmBdpsDv] [-C cost] passwordfile username password" NL + NL + "\thtpasswd -n[imBdps] [-C cost] username" NL + "\thtpasswd -nb[mBdps] [-C cost] username password" NL + " -c Create a new file." NL + " -n Don't update file; display results on stdout." NL + " -b Use the password from the command line rather than prompting " + "for it." NL + " -i Read password from stdin without verification (for script usage)." NL + " -m Force MD5 encryption of the password (default)." NL + " -B Force bcrypt encryption of the password (very secure)." NL + " -C Set the computing time used for the bcrypt algorithm" NL + " (higher is more secure but slower, default: %d, valid: 4 to 17)." NL + " -d Force CRYPT encryption of the password (8 chars max, insecure)." NL + " -s Force SHA encryption of the password (insecure)." NL + " -p Do not encrypt the password (plaintext, insecure)." NL + " -D Delete the specified user." NL + " -v Verify password for the specified user." NL + "On other systems than Windows and NetWare the '-p' flag will " + "probably not work." NL + "The SHA algorithm does not use a salt and is less secure than the " + "MD5 algorithm." NL, + BCRYPT_DEFAULT_COST + ); + exit(ERR_SYNTAX); +} + +/* + * Check to see if the specified file can be opened for the given + * access. + */ +static int accessible(apr_pool_t *pool, char *fname, int mode) +{ + apr_file_t *f = NULL; + + if (apr_file_open(&f, fname, mode, APR_OS_DEFAULT, pool) != APR_SUCCESS) { + return 0; + } + apr_file_close(f); + return 1; +} + +/* + * Return true if the named file exists, regardless of permissions. + */ +static int exists(char *fname, apr_pool_t *pool) +{ + apr_finfo_t sbuf; + apr_status_t check; + + check = apr_stat(&sbuf, fname, APR_FINFO_TYPE, pool); + return ((check || sbuf.filetype != APR_REG) ? 0 : 1); +} + +static void terminate(void) +{ + apr_terminate(); +#ifdef NETWARE + pressanykey(); +#endif +} + +static void check_args(int argc, const char *const argv[], + struct passwd_ctx *ctx, unsigned *mask, char **user, + char **pwfilename) +{ + const char *arg; + int args_left = 2; + int i, ret; + apr_getopt_t *state; + apr_status_t rv; + char opt; + const char *opt_arg; + apr_pool_t *pool = ctx->pool; + + rv = apr_getopt_init(&state, pool, argc, argv); + if (rv != APR_SUCCESS) + exit(ERR_SYNTAX); + + while ((rv = apr_getopt(state, "cnmspdBbDiC:v", &opt, &opt_arg)) == APR_SUCCESS) { + switch (opt) { + case 'c': + *mask |= APHTP_NEWFILE; + break; + case 'n': + args_left--; + *mask |= APHTP_NOFILE; + break; + case 'D': + *mask |= APHTP_DELUSER; + break; + case 'v': + *mask |= APHTP_VERIFY; + break; + default: + ret = parse_common_options(ctx, opt, opt_arg); + if (ret) { + apr_file_printf(errfile, "%s: %s" NL, argv[0], ctx->errstr); + exit(ret); + } + } + } + if (ctx->passwd_src == PW_ARG) + args_left++; + if (rv != APR_EOF) + usage(); + + if ((*mask) & (*mask - 1)) { + /* not a power of two, i.e. more than one flag specified */ + apr_file_printf(errfile, "%s: only one of -c -n -v -D may be specified" NL, + argv[0]); + exit(ERR_SYNTAX); + } + if ((*mask & APHTP_VERIFY) && ctx->passwd_src == PW_PROMPT) + ctx->passwd_src = PW_PROMPT_VERIFY; + + /* + * Make sure we still have exactly the right number of arguments left + * (the filename, the username, and possibly the password if -b was + * specified). + */ + i = state->ind; + if ((argc - i) != args_left) { + usage(); + } + + if (!(*mask & APHTP_NOFILE)) { + if (strlen(argv[i]) > (APR_PATH_MAX - 1)) { + apr_file_printf(errfile, "%s: filename too long" NL, argv[0]); + exit(ERR_OVERFLOW); + } + *pwfilename = apr_pstrdup(pool, argv[i++]); + } + if (strlen(argv[i]) > (MAX_STRING_LEN - 1)) { + apr_file_printf(errfile, "%s: username too long (> %d)" NL, + argv[0], MAX_STRING_LEN - 1); + exit(ERR_OVERFLOW); + } + *user = apr_pstrdup(pool, argv[i++]); + if ((arg = strchr(*user, ':')) != NULL) { + apr_file_printf(errfile, "%s: username contains illegal " + "character '%c'" NL, argv[0], *arg); + exit(ERR_BADUSER); + } + if (ctx->passwd_src == PW_ARG) { + if (strlen(argv[i]) > (MAX_STRING_LEN - 1)) { + apr_file_printf(errfile, "%s: password too long (> %d)" NL, + argv[0], MAX_STRING_LEN); + exit(ERR_OVERFLOW); + } + ctx->passwd = apr_pstrdup(pool, argv[i]); + } +} + +static int verify(struct passwd_ctx *ctx, const char *hash) +{ + apr_status_t rv; + int ret; + + if (ctx->passwd == NULL && (ret = get_password(ctx)) != 0) + return ret; + rv = apr_password_validate(ctx->passwd, hash); + if (rv == APR_SUCCESS) + return 0; + if (APR_STATUS_IS_EMISMATCH(rv)) { + ctx->errstr = "password verification failed"; + return ERR_PWMISMATCH; + } + ctx->errstr = apr_psprintf(ctx->pool, "Could not verify password: %pm", + &rv); + return ERR_GENERAL; +} + +/* + * Let's do it. We end up doing a lot of file opening and closing, + * but what do we care? This application isn't run constantly. + */ +int main(int argc, const char * const argv[]) +{ + apr_file_t *fpw = NULL; + char line[MAX_STRING_LEN]; + char *pwfilename = NULL; + char *user = NULL; + char tn[] = "htpasswd.tmp.XXXXXX"; + char *dirname; + char *scratch, cp[MAX_STRING_LEN]; + int found = 0; + int i; + unsigned mask = 0; + apr_pool_t *pool; + int existing_file = 0; + struct passwd_ctx ctx = { 0 }; +#if APR_CHARSET_EBCDIC + apr_status_t rv; + apr_xlate_t *to_ascii; +#endif + + apr_app_initialize(&argc, &argv, NULL); + atexit(terminate); + apr_pool_create(&pool, NULL); + apr_pool_abort_set(abort_on_oom, pool); + apr_file_open_stderr(&errfile, pool); + ctx.pool = pool; + ctx.alg = ALG_APMD5; + +#if APR_CHARSET_EBCDIC + rv = apr_xlate_open(&to_ascii, "ISO-8859-1", APR_DEFAULT_CHARSET, pool); + if (rv) { + apr_file_printf(errfile, "apr_xlate_open(to ASCII)->%d" NL, rv); + exit(1); + } + rv = apr_SHA1InitEBCDIC(to_ascii); + if (rv) { + apr_file_printf(errfile, "apr_SHA1InitEBCDIC()->%d" NL, rv); + exit(1); + } + rv = apr_MD5InitEBCDIC(to_ascii); + if (rv) { + apr_file_printf(errfile, "apr_MD5InitEBCDIC()->%d" NL, rv); + exit(1); + } +#endif /*APR_CHARSET_EBCDIC*/ + + check_args(argc, argv, &ctx, &mask, &user, &pwfilename); + + /* + * Only do the file checks if we're supposed to frob it. + */ + if (!(mask & APHTP_NOFILE)) { + existing_file = exists(pwfilename, pool); + if (existing_file && (mask & APHTP_VERIFY) == 0) { + /* + * Check that this existing file is readable and writable. + */ + if (!accessible(pool, pwfilename, APR_FOPEN_READ|APR_FOPEN_WRITE)) { + apr_file_printf(errfile, "%s: cannot open file %s for " + "read/write access" NL, argv[0], pwfilename); + exit(ERR_FILEPERM); + } + } + else if (existing_file && (mask & APHTP_VERIFY) != 0) { + /* + * Check that this existing file is readable. + */ + if (!accessible(pool, pwfilename, APR_FOPEN_READ)) { + apr_file_printf(errfile, "%s: cannot open file %s for " + "read access" NL, argv[0], pwfilename); + exit(ERR_FILEPERM); + } + } + else { + /* + * Error out if -c was omitted for this non-existent file. + */ + if (!(mask & APHTP_NEWFILE)) { + apr_file_printf(errfile, + "%s: cannot modify file %s; use '-c' to create it" NL, + argv[0], pwfilename); + exit(ERR_FILEPERM); + } + /* + * As it doesn't exist yet, verify that we can create it. + */ + if (!accessible(pool, pwfilename, APR_FOPEN_WRITE|APR_FOPEN_CREATE)) { + apr_file_printf(errfile, "%s: cannot create file %s" NL, + argv[0], pwfilename); + exit(ERR_FILEPERM); + } + } + } + + /* + * All the file access checks (if any) have been made. Time to go to work; + * try to create the record for the username in question. If that + * fails, there's no need to waste any time on file manipulations. + * Any error message text is returned in the record buffer, since + * the mkrecord() routine doesn't have access to argv[]. + */ + if ((mask & (APHTP_DELUSER|APHTP_VERIFY)) == 0) { + i = mkrecord(&ctx, user); + if (i != 0) { + apr_file_printf(errfile, "%s: %s" NL, argv[0], ctx.errstr); + exit(i); + } + if (mask & APHTP_NOFILE) { + printf("%s" NL, ctx.out); + exit(0); + } + } + + if ((mask & APHTP_VERIFY) == 0) { + /* + * We can access the files the right way, and we have a record + * to add or update. Let's do it.. + */ + if (apr_temp_dir_get((const char**)&dirname, pool) != APR_SUCCESS) { + apr_file_printf(errfile, "%s: could not determine temp dir" NL, + argv[0]); + exit(ERR_FILEPERM); + } + dirname = apr_psprintf(pool, "%s/%s", dirname, tn); + + if (apr_file_mktemp(&ftemp, dirname, 0, pool) != APR_SUCCESS) { + apr_file_printf(errfile, "%s: unable to create temporary file %s" NL, + argv[0], dirname); + exit(ERR_FILEPERM); + } + } + + /* + * If we're not creating a new file, copy records from the existing + * one to the temporary file until we find the specified user. + */ + if (existing_file && !(mask & APHTP_NEWFILE)) { + if (apr_file_open(&fpw, pwfilename, APR_READ | APR_BUFFERED, + APR_OS_DEFAULT, pool) != APR_SUCCESS) { + apr_file_printf(errfile, "%s: unable to read file %s" NL, + argv[0], pwfilename); + exit(ERR_FILEPERM); + } + while (apr_file_gets(line, sizeof(line), fpw) == APR_SUCCESS) { + char *colon; + + strcpy(cp, line); + scratch = cp; + while (apr_isspace(*scratch)) { + ++scratch; + } + + if (!*scratch || (*scratch == '#')) { + putline(ftemp, line); + continue; + } + /* + * See if this is our user. + */ + colon = strchr(scratch, ':'); + if (colon != NULL) { + *colon = '\0'; + } + else { + /* + * If we've not got a colon on the line, this could well + * not be a valid htpasswd file. + * We should bail at this point. + */ + apr_file_printf(errfile, "%s: The file %s does not appear " + "to be a valid htpasswd file." NL, + argv[0], pwfilename); + apr_file_close(fpw); + exit(ERR_INVALID); + } + if (strcmp(user, scratch) != 0) { + putline(ftemp, line); + continue; + } + else { + /* We found the user we were looking for */ + found++; + if ((mask & APHTP_DELUSER)) { + /* Delete entry from the file */ + apr_file_printf(errfile, "Deleting "); + } + else if ((mask & APHTP_VERIFY)) { + /* Verify */ + char *hash = colon + 1; + size_t len; + + len = strcspn(hash, "\r\n"); + if (len == 0) { + apr_file_printf(errfile, "Empty hash for user %s" NL, + user); + exit(ERR_INVALID); + } + hash[len] = '\0'; + + i = verify(&ctx, hash); + if (i != 0) { + apr_file_printf(errfile, "%s" NL, ctx.errstr); + exit(i); + } + } + else { + /* Update entry */ + apr_file_printf(errfile, "Updating "); + putline(ftemp, ctx.out); + } + } + } + apr_file_close(fpw); + } + if (!found) { + if (mask & APHTP_DELUSER) { + apr_file_printf(errfile, "User %s not found" NL, user); + exit(0); + } + else if (mask & APHTP_VERIFY) { + apr_file_printf(errfile, "User %s not found" NL, user); + exit(ERR_BADUSER); + } + else { + apr_file_printf(errfile, "Adding "); + putline(ftemp, ctx.out); + } + } + if (mask & APHTP_VERIFY) { + apr_file_printf(errfile, "Password for user %s correct." NL, user); + exit(0); + } + + apr_file_printf(errfile, "password for user %s" NL, user); + + /* The temporary file has all the data, just copy it to the new location. + */ + if (apr_file_copy(dirname, pwfilename, APR_OS_DEFAULT, pool) != + APR_SUCCESS) { + apr_file_printf(errfile, "%s: unable to update file %s" NL, + argv[0], pwfilename); + exit(ERR_FILEPERM); + } + apr_file_close(ftemp); + return 0; +} diff --git a/support/htpasswd.dep b/support/htpasswd.dep new file mode 100644 index 0000000..6e3e4fa --- /dev/null +++ b/support/htpasswd.dep @@ -0,0 +1,57 @@ +# Microsoft Developer Studio Generated Dependency File, included by htpasswd.mak + +.\htpasswd.c : \ + "..\srclib\apr-util\include\apr_md5.h"\ + "..\srclib\apr-util\include\apr_sha1.h"\ + "..\srclib\apr-util\include\apr_xlate.h"\ + "..\srclib\apr-util\include\apu.h"\ + "..\srclib\apr-util\include\apu_version.h"\ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_getopt.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_signal.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_version.h"\ + "..\srclib\apr\include\apr_want.h"\ + ".\passwd_common.h"\ + + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + + +.\passwd_common.c : \ + "..\srclib\apr-util\include\apr_md5.h"\ + "..\srclib\apr-util\include\apr_sha1.h"\ + "..\srclib\apr-util\include\apr_xlate.h"\ + "..\srclib\apr-util\include\apu.h"\ + "..\srclib\apr-util\include\apu_version.h"\ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_version.h"\ + "..\srclib\apr\include\apr_want.h"\ + ".\passwd_common.h"\ + diff --git a/support/htpasswd.dsp b/support/htpasswd.dsp new file mode 100644 index 0000000..b605669 --- /dev/null +++ b/support/htpasswd.dsp @@ -0,0 +1,110 @@ +# Microsoft Developer Studio Project File - Name="htpasswd" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=htpasswd - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "htpasswd.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "htpasswd.mak" CFG="htpasswd - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "htpasswd - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "htpasswd - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "htpasswd - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/htpasswd_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/htpasswd.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\htpasswd.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/htpasswd_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/htpasswd.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\htpasswd.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "htpasswd - Win32 Release" +# Name "htpasswd - Win32 Debug" +# Begin Source File + +SOURCE=.\htpasswd.c +# End Source File +# Begin Source File + +SOURCE=.\passwd_common.c +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/htpasswd.mak b/support/htpasswd.mak new file mode 100644 index 0000000..a492324 --- /dev/null +++ b/support/htpasswd.mak @@ -0,0 +1,326 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on htpasswd.dsp +!IF "$(CFG)" == "" +CFG=htpasswd - Win32 Debug +!MESSAGE No configuration specified. Defaulting to htpasswd - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "htpasswd - Win32 Release" && "$(CFG)" != "htpasswd - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "htpasswd.mak" CFG="htpasswd - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "htpasswd - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "htpasswd - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "htpasswd - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\htpasswd.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\htpasswd.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\htpasswd.obj" + -@erase "$(INTDIR)\htpasswd.res" + -@erase "$(INTDIR)\htpasswd_src.idb" + -@erase "$(INTDIR)\htpasswd_src.pdb" + -@erase "$(INTDIR)\passwd_common.obj" + -@erase "$(OUTDIR)\htpasswd.exe" + -@erase "$(OUTDIR)\htpasswd.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htpasswd_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htpasswd.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\htpasswd.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htpasswd.pdb" /debug /out:"$(OUTDIR)\htpasswd.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\htpasswd.obj" \ + "$(INTDIR)\passwd_common.obj" \ + "$(INTDIR)\htpasswd.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\htpasswd.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\htpasswd.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htpasswd.exe" + if exist .\Release\htpasswd.exe.manifest mt.exe -manifest .\Release\htpasswd.exe.manifest -outputresource:.\Release\htpasswd.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\htpasswd.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\htpasswd.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\htpasswd.obj" + -@erase "$(INTDIR)\htpasswd.res" + -@erase "$(INTDIR)\htpasswd_src.idb" + -@erase "$(INTDIR)\htpasswd_src.pdb" + -@erase "$(INTDIR)\passwd_common.obj" + -@erase "$(OUTDIR)\htpasswd.exe" + -@erase "$(OUTDIR)\htpasswd.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\htpasswd_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\htpasswd.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\htpasswd.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib shell32.lib rpcrt4.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\htpasswd.pdb" /debug /out:"$(OUTDIR)\htpasswd.exe" +LINK32_OBJS= \ + "$(INTDIR)\htpasswd.obj" \ + "$(INTDIR)\passwd_common.obj" \ + "$(INTDIR)\htpasswd.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\htpasswd.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\htpasswd.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\htpasswd.exe" + if exist .\Debug\htpasswd.exe.manifest mt.exe -manifest .\Debug\htpasswd.exe.manifest -outputresource:.\Debug\htpasswd.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("htpasswd.dep") +!INCLUDE "htpasswd.dep" +!ELSE +!MESSAGE Warning: cannot find "htpasswd.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "htpasswd - Win32 Release" || "$(CFG)" == "htpasswd - Win32 Debug" + +!IF "$(CFG)" == "htpasswd - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "htpasswd - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=.\htpasswd.c + +"$(INTDIR)\htpasswd.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "htpasswd - Win32 Release" + + +"$(INTDIR)\htpasswd.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\htpasswd.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility" $(SOURCE) + + +!ELSEIF "$(CFG)" == "htpasswd - Win32 Debug" + + +"$(INTDIR)\htpasswd.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\htpasswd.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="htpasswd.exe" /d LONG_NAME="Apache htpasswd command line utility" $(SOURCE) + + +!ENDIF + +SOURCE=.\passwd_common.c + +"$(INTDIR)\passwd_common.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/support/httxt2dbm.c b/support/httxt2dbm.c new file mode 100644 index 0000000..387418b --- /dev/null +++ b/support/httxt2dbm.c @@ -0,0 +1,335 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * httxt2dbm.c: simple program for converting RewriteMap text files to DBM + * Rewrite databases for the Apache HTTP server + * + */ + +#include "apr.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_pools.h" +#include "apr_getopt.h" +#include "apu.h" +#include "apr_dbm.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> /* for atexit() */ +#endif + +static const char *input; +static const char *output; +static const char *format; +static const char *shortname; +static apr_file_t *errfile; +static int verbose; + +/* From mod_rewrite.c */ +#ifndef REWRITE_MAX_TXT_MAP_LINE +#define REWRITE_MAX_TXT_MAP_LINE 1024 +#endif + +#define NL APR_EOL_STR + +#define AVAIL "available" +#define UNAVAIL "unavailable" + +static void usage(void) +{ + const char *have_sdbm; + const char *have_gdbm; + const char *have_ndbm; + const char *have_db; + +#if APU_HAVE_SDBM + have_sdbm = AVAIL; +#else + have_sdbm = UNAVAIL; +#endif +#if APU_HAVE_GDBM + have_gdbm = AVAIL; +#else + have_gdbm = UNAVAIL; +#endif +#if APU_HAVE_NDBM + have_ndbm = AVAIL; +#else + have_ndbm = UNAVAIL; +#endif +#if APU_HAVE_DB + have_db = AVAIL; +#else + have_db = UNAVAIL; +#endif + + apr_file_printf(errfile, + "%s -- Program to Create DBM Files for use by RewriteMap" NL + "Usage: %s [-v] [-f format] -i SOURCE_TXT -o OUTPUT_DBM" NL + NL + "Options: " NL + " -v More verbose output" NL + NL + " -i Source Text File. If '-', use stdin." NL + NL + " -o Output DBM." NL + NL + " -f DBM Format. If not specified, will use the APR Default." NL + " GDBM for GDBM files (%s)" NL + " SDBM for SDBM files (%s)" NL + " DB for berkeley DB files (%s)" NL + " NDBM for NDBM files (%s)" NL + " default for the default DBM type" NL + NL, + shortname, + shortname, + have_gdbm, + have_sdbm, + have_db, + have_ndbm); +} + + +static apr_status_t to_dbm(apr_dbm_t *dbm, apr_file_t *fp, apr_pool_t *pool) +{ + apr_status_t rv = APR_SUCCESS; + char line[REWRITE_MAX_TXT_MAP_LINE + 1]; /* +1 for \0 */ + apr_datum_t dbmkey; + apr_datum_t dbmval; + apr_pool_t* p; + + apr_pool_create(&p, pool); + + while (apr_file_gets(line, sizeof(line), fp) == APR_SUCCESS) { + char *c, *value; + + if (*line == '#' || apr_isspace(*line)) { + continue; + } + + c = line; + + while (*c && !apr_isspace(*c)) { + ++c; + } + + if (!*c) { + /* no value. solid line of data. */ + continue; + } + + dbmkey.dptr = apr_pstrmemdup(p, line, c - line); + dbmkey.dsize = (c - line); + + while (apr_isspace(*c)) { + ++c; + } + + if (!*c) { + apr_pool_clear(p); + continue; + } + + value = c; + + while (*c && !apr_isspace(*c)) { + ++c; + } + + dbmval.dptr = apr_pstrmemdup(p, value, c - value); + dbmval.dsize = (c - value); + + if (verbose) { + apr_file_printf(errfile, " '%s' -> '%s'" NL, + dbmkey.dptr, dbmval.dptr); + } + + rv = apr_dbm_store(dbm, dbmkey, dbmval); + + apr_pool_clear(p); + + if (rv != APR_SUCCESS) { + break; + } + } + + return rv; +} + +int main(int argc, const char *const argv[]) +{ + apr_pool_t *pool; + apr_status_t rv = APR_SUCCESS; + apr_getopt_t *opt; + const char *opt_arg; + char ch; + apr_file_t *infile; + apr_dbm_t *outdbm; + + apr_app_initialize(&argc, &argv, NULL); + atexit(apr_terminate); + + verbose = 0; + format = NULL; + input = NULL; + output = NULL; + + apr_pool_create(&pool, NULL); + + if (argc) { + shortname = apr_filepath_name_get(argv[0]); + } + else { + shortname = "httxt2dbm"; + } + + apr_file_open_stderr(&errfile, pool); + rv = apr_getopt_init(&opt, pool, argc, argv); + + if (rv != APR_SUCCESS) { + apr_file_printf(errfile, "Error: apr_getopt_init failed." NL NL); + return 1; + } + + if (argc <= 1) { + usage(); + return 1; + } + + while ((rv = apr_getopt(opt, "vf::i::o::", &ch, &opt_arg)) == APR_SUCCESS) { + switch (ch) { + case 'v': + if (verbose) { + apr_file_printf(errfile, "Error: -v can only be passed once" NL NL); + usage(); + return 1; + } + verbose = 1; + break; + case 'f': + if (format) { + apr_file_printf(errfile, "Error: -f can only be passed once" NL NL); + usage(); + return 1; + } + format = apr_pstrdup(pool, opt_arg); + break; + case 'i': + if (input) { + apr_file_printf(errfile, "Error: -i can only be passed once" NL NL); + usage(); + return 1; + } + input = apr_pstrdup(pool, opt_arg); + break; + case 'o': + if (output) { + apr_file_printf(errfile, "Error: -o can only be passed once" NL NL); + usage(); + return 1; + } + output = apr_pstrdup(pool, opt_arg); + break; + } + } + + if (rv != APR_EOF) { + apr_file_printf(errfile, "Error: Parsing Arguments Failed" NL NL); + usage(); + return 1; + } + + if (!input) { + apr_file_printf(errfile, "Error: No input file specified." NL NL); + usage(); + return 1; + } + + if (!output) { + apr_file_printf(errfile, "Error: No output DBM specified." NL NL); + usage(); + return 1; + } + + if (!format) { + format = "default"; + } + + if (verbose) { + apr_file_printf(errfile, "DBM Format: %s" NL, format); + } + + if (!strcmp(input, "-")) { + rv = apr_file_open_stdin(&infile, pool); + } + else { + rv = apr_file_open(&infile, input, APR_READ|APR_BUFFERED, + APR_OS_DEFAULT, pool); + } + + if (rv != APR_SUCCESS) { + apr_file_printf(errfile, + "Error: Cannot open input file '%s': (%d) %pm" NL NL, + input, rv, &rv); + return 1; + } + + if (verbose) { + apr_file_printf(errfile, "Input File: %s" NL, input); + } + + rv = apr_dbm_open_ex(&outdbm, format, output, APR_DBM_RWCREATE, + APR_OS_DEFAULT, pool); + + if (APR_STATUS_IS_ENOTIMPL(rv)) { + apr_file_printf(errfile, + "Error: The requested DBM Format '%s' is not available." NL NL, + format); + return 1; + } + + if (rv != APR_SUCCESS) { + apr_file_printf(errfile, + "Error: Cannot open output DBM '%s': (%d) %pm" NL NL, + output, rv, &rv); + return 1; + } + + if (verbose) { + apr_file_printf(errfile, "DBM File: %s" NL, output); + } + + rv = to_dbm(outdbm, infile, pool); + + if (rv != APR_SUCCESS) { + apr_file_printf(errfile, + "Error: Converting to DBM: (%d) %pm" NL NL, + rv, &rv); + return 1; + } + + apr_dbm_close(outdbm); + + if (verbose) { + apr_file_printf(errfile, "Conversion Complete." NL); + } + + return 0; +} + diff --git a/support/httxt2dbm.dep b/support/httxt2dbm.dep new file mode 100644 index 0000000..b546ab4 --- /dev/null +++ b/support/httxt2dbm.dep @@ -0,0 +1,26 @@ +# Microsoft Developer Studio Generated Dependency File, included by httxt2dbm.mak + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + + +.\httxt2dbm.c : \ + "..\srclib\apr-util\include\apr_dbm.h"\ + "..\srclib\apr-util\include\apu.h"\ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_getopt.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_want.h"\ + diff --git a/support/httxt2dbm.dsp b/support/httxt2dbm.dsp new file mode 100644 index 0000000..94ed525 --- /dev/null +++ b/support/httxt2dbm.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="httxt2dbm" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=httxt2dbm - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "httxt2dbm.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "httxt2dbm.mak" CFG="httxt2dbm - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "httxt2dbm - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "httxt2dbm - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "httxt2dbm - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/httxt2dbm_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\httxt2dbm.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/httxt2dbm_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\httxt2dbm.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "httxt2dbm - Win32 Release" +# Name "httxt2dbm - Win32 Debug" +# Begin Source File + +SOURCE=.\httxt2dbm.c +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/httxt2dbm.mak b/support/httxt2dbm.mak new file mode 100644 index 0000000..615f0e9 --- /dev/null +++ b/support/httxt2dbm.mak @@ -0,0 +1,317 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on httxt2dbm.dsp +!IF "$(CFG)" == "" +CFG=httxt2dbm - Win32 Debug +!MESSAGE No configuration specified. Defaulting to httxt2dbm - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "httxt2dbm - Win32 Release" && "$(CFG)" != "httxt2dbm - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "httxt2dbm.mak" CFG="httxt2dbm - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "httxt2dbm - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "httxt2dbm - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "httxt2dbm - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\httxt2dbm.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\httxt2dbm.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\httxt2dbm.obj" + -@erase "$(INTDIR)\httxt2dbm.res" + -@erase "$(INTDIR)\httxt2dbm_src.idb" + -@erase "$(INTDIR)\httxt2dbm_src.pdb" + -@erase "$(OUTDIR)\httxt2dbm.exe" + -@erase "$(OUTDIR)\httxt2dbm.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\httxt2dbm_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\httxt2dbm.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\httxt2dbm.pdb" /debug /out:"$(OUTDIR)\httxt2dbm.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\httxt2dbm.obj" \ + "$(INTDIR)\httxt2dbm.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\httxt2dbm.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\httxt2dbm.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\httxt2dbm.exe" + if exist .\Release\httxt2dbm.exe.manifest mt.exe -manifest .\Release\httxt2dbm.exe.manifest -outputresource:.\Release\httxt2dbm.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\httxt2dbm.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\httxt2dbm.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\httxt2dbm.obj" + -@erase "$(INTDIR)\httxt2dbm.res" + -@erase "$(INTDIR)\httxt2dbm_src.idb" + -@erase "$(INTDIR)\httxt2dbm_src.pdb" + -@erase "$(OUTDIR)\httxt2dbm.exe" + -@erase "$(OUTDIR)\httxt2dbm.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\httxt2dbm_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\httxt2dbm.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\httxt2dbm.pdb" /debug /out:"$(OUTDIR)\httxt2dbm.exe" +LINK32_OBJS= \ + "$(INTDIR)\httxt2dbm.obj" \ + "$(INTDIR)\httxt2dbm.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\httxt2dbm.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\httxt2dbm.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\httxt2dbm.exe" + if exist .\Debug\httxt2dbm.exe.manifest mt.exe -manifest .\Debug\httxt2dbm.exe.manifest -outputresource:.\Debug\httxt2dbm.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("httxt2dbm.dep") +!INCLUDE "httxt2dbm.dep" +!ELSE +!MESSAGE Warning: cannot find "httxt2dbm.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "httxt2dbm - Win32 Release" || "$(CFG)" == "httxt2dbm - Win32 Debug" + +!IF "$(CFG)" == "httxt2dbm - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "httxt2dbm - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "httxt2dbm - Win32 Release" + + +"$(INTDIR)\httxt2dbm.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility" $(SOURCE) + + +!ELSEIF "$(CFG)" == "httxt2dbm - Win32 Debug" + + +"$(INTDIR)\httxt2dbm.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\httxt2dbm.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="httxt2dbm.exe" /d LONG_NAME="Apache httxt2dbm command line utility" $(SOURCE) + + +!ENDIF + +SOURCE=.\httxt2dbm.c + +"$(INTDIR)\httxt2dbm.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/support/list_hooks.pl b/support/list_hooks.pl new file mode 100755 index 0000000..7a6c933 --- /dev/null +++ b/support/list_hooks.pl @@ -0,0 +1,101 @@ +#!/usr/bin/perl -w +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +use strict; + +use Carp; + +my $path=shift || '.'; + +findInDir($path); + +foreach my $hook (sort keys %::Hooks) { + my $h=$::Hooks{$hook}; + for my $x (qw(declared implemented type args)) { + print "$hook datum '$x' missing\n" if !exists $h->{$x}; + } + print "$hook\n"; + print " declared in $h->{declared}\n" if defined $h->{declared}; + print " implemented in $h->{implemented}\n" if defined $h->{implemented}; + print " type is $h->{type}\n" if defined $h->{type}; + print " $h->{ret} $hook($h->{args})\n" if defined $h->{args}; + print "\n"; +} + +sub findInDir { + my $path=shift; + + local(*D); + opendir(D,$path) || croak "Can't open $path: $!"; + while(my $f=readdir D) { + next if $f=~/^\./; + my $file="$path/$f"; + + if(-d $file) { + findInDir($file); + next; + } + next if $file !~ /\.[ch]$/; + + scanFile($file); + } + closedir D; +} + +sub scanFile { + my $file=shift; + +# print "scanning $file\n"; + + open(F,$file) || croak "Can't open $file: $!"; + while(<F>) { + next if /\#define/; + next if /\@deffunc/; + if(/AP_DECLARE_HOOK\s*\(/) { + my($ret,$name,$args); + while(!(($ret,$name,$args)= + /AP_DECLARE_HOOK\s*\(\s*([^,]+)\s*,\s*([^,\s]+)\s*,\s*\((.*?)\)\)/s)) { + chomp; + # swallow subsequent lines if needed to get all the required info + my $l=<F>; + return unless defined $l; + $l=~s/^\s*/ /; + $_.=$l; + } + $ret=~s/\s*$//; + $args=~s/^\s*//; $args=~s/\s*$//; +# print "found $ret $name($args) in $file\n"; + + croak "$name declared twice! ($_)" + if exists $::Hooks{$name}->{declared}; + $::Hooks{$name}->{declared}=$file; + $::Hooks{$name}->{ret}=$ret; + $::Hooks{$name}->{args}=$args; + } + if(/AP_IMPLEMENT_HOOK_()(VOID)\(([^,\s]+)/ + || /AP_IMPLEMENT(_OPTIONAL|)_HOOK_(.*?)\([^,]+?\s*,\s*([^,\s]+)/) { + my($type,$name)=($1 ? "OPTIONAL $2" : $2,$3); + +# print "found $name $type in $file\n"; + + croak "$name implemented twice ($::Hooks{$name}->{implemented} and $file) ($_)" + if exists $::Hooks{$name}->{implemented}; + $::Hooks{$name}->{implemented}=$file; + $::Hooks{$name}->{type}=$type; + } + } +} diff --git a/support/log_server_status.in b/support/log_server_status.in new file mode 100644 index 0000000..ba08d7e --- /dev/null +++ b/support/log_server_status.in @@ -0,0 +1,76 @@ +#!@perlbin@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# Log Server Status +# Mark J Cox, UK Web Ltd 1996, mark ukweb.com +# +# This script is designed to be run at a frequent interval by something +# like cron. It connects to the server and downloads the status +# information. It reformats the information to a single line and logs +# it to a file. Make sure the directory $wherelog is writable by the +# user who runs this script. +# +use IO::Socket; +use strict; +use warnings; + +my $wherelog = "@exp_logfiledir@/"; # Logs will be like "@exp_logfiledir@/19960312" +my $server = "localhost"; # Name of server, could be "www.foo.com" +my $port = "@PORT@"; # Port on server +my $request = "/server-status/?auto"; # Request to send + +my @ltime = localtime(time); + +my $day = + $ltime[5] + 1900 + . sprintf( "%02d", $ltime[4] + 1 ) + . sprintf( "%02d", $ltime[3] ); + +my $time = + sprintf( "%02d", $ltime[2] ) + . sprintf( "%02d", $ltime[1] ) + . sprintf( "%02d", $ltime[0] ); + +open(OUT,">>$wherelog$day"); + +my $socket = new IO::Socket::INET( + PeerAddr => $server, + PeerPort => $port, + Proto => "tcp", + Type => SOCK_STREAM + ) + or do { + print OUT "$time:-1:-1:-1:-1:$@\n"; + close OUT; + die "Couldn't connect to $server:$port : $@\n"; + }; +$| = 1; + +print $socket + "GET $request HTTP/1.1\r\nHost: $server\r\nConnection: close\r\n\r\n\r\n"; + +my ( $requests, $idle, $number, $cpu ); +while (<$socket>) { + $requests = $1 if (m|^BusyWorkers:\ (\S+)|); + $idle = $1 if (m|^IdleWorkers:\ (\S+)|); + $number = $1 if (m|sses:\ (\S+)|); + $cpu = $1 if (m|^CPULoad:\ (\S+)|); +} +print OUT "$time:$requests:$idle:$number:$cpu\n"; +close OUT; + diff --git a/support/logresolve.c b/support/logresolve.c new file mode 100644 index 0000000..1cab753 --- /dev/null +++ b/support/logresolve.c @@ -0,0 +1,329 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * logresolve 2.0 + * + * Tom Rathborne - tomr uunet.ca - http://www.uunet.ca/~tomr/ + * UUNET Canada, April 16, 1995 + * + * Rewritten by David Robinson. (drtr ast.cam.ac.uk) + * Rewritten again, and ported to APR by Colm MacCarthaigh + * + * Usage: logresolve [-s filename] [-c] < access_log > new_log + * + * Arguments: + * -s filename name of a file to record statistics + * -c check the DNS for a matching A record for the host. + * + * Notes: (For historical interest) + * + * To generate meaningful statistics from an HTTPD log file, it's good + * to have the domain name of each machine that accessed your site, but + * doing this on the fly can slow HTTPD down. + * + * Compiling NCSA HTTPD with the -DMINIMAL_DNS flag turns IP#->hostname + * resolution off. Before running your stats program, just run your log + * file through this program (logresolve) and all of your IP numbers will + * be resolved into hostnames (where possible). + * + * logresolve takes an HTTPD access log (in the COMMON log file format, + * or any other format that has the IP number/domain name as the first + * field for that matter), and outputs the same file with all of the + * domain names looked up. Where no domain name can be found, the IP + * number is left in. + * + * To minimize impact on your nameserver, logresolve has its very own + * internal hash-table cache. This means that each IP number will only + * be looked up the first time it is found in the log file. + * + * The -c option causes logresolve to apply the same check as httpd + * compiled with -DMAXIMUM_DNS; after finding the hostname from the IP + * address, it looks up the IP addresses for the hostname and checks + * that one of these matches the original address. + */ + +#include "apr.h" +#include "apr_lib.h" +#include "apr_hash.h" +#include "apr_getopt.h" +#include "apr_strings.h" +#include "apr_file_io.h" +#include "apr_network_io.h" + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#define READ_BUF_SIZE 128*1024 +#define WRITE_BUF_SIZE 128*1024 +#define LINE_BUF_SIZE 128*1024 + +static apr_file_t *errfile; +static const char *shortname = "logresolve"; +static apr_hash_t *cache; + +/* Statistics */ +static int cachehits = 0; +static int cachesize = 0; +static int entries = 0; +static int resolves = 0; +static int withname = 0; +static int doublefailed = 0; +static int noreverse = 0; + +/* + * prints various statistics to output + */ +#define NL APR_EOL_STR +static void print_statistics (apr_file_t *output) +{ + apr_file_printf(output, "logresolve Statistics:" NL); + apr_file_printf(output, "Entries: %d" NL, entries); + apr_file_printf(output, " With name : %d" NL, withname); + apr_file_printf(output, " Resolves : %d" NL, resolves); + + if (noreverse) { + apr_file_printf(output, " - No reverse : %d" NL, + noreverse); + } + + if (doublefailed) { + apr_file_printf(output, " - Double lookup failed : %d" NL, + doublefailed); + } + + apr_file_printf(output, "Cache hits : %d" NL, cachehits); + apr_file_printf(output, "Cache size : %d" NL, cachesize); +} + +/* + * usage info + */ +static void usage(void) +{ + apr_file_printf(errfile, + "%s -- Resolve IP-addresses to hostnames in Apache log files." NL + "Usage: %s [-s STATFILE] [-c]" NL + NL + "Options:" NL + " -s Record statistics to STATFILE when finished." NL + NL + " -c Perform double lookups when resolving IP addresses." NL, + shortname, shortname); + exit(1); +} +#undef NL + +int main(int argc, const char * const argv[]) +{ + apr_file_t * outfile; + apr_file_t * infile; + apr_getopt_t * o; + apr_pool_t * pool; + apr_pool_t *pline; + apr_status_t status; + const char * arg; + char * stats = NULL; + char * inbuffer; + char * outbuffer; + char * line; + int doublelookups = 0; + + if (apr_app_initialize(&argc, &argv, NULL) != APR_SUCCESS) { + return 1; + } + atexit(apr_terminate); + + if (argc) { + shortname = apr_filepath_name_get(argv[0]); + } + + if (apr_pool_create(&pool, NULL) != APR_SUCCESS) { + return 1; + } + apr_file_open_stderr(&errfile, pool); + apr_getopt_init(&o, pool, argc, argv); + + while (1) { + char opt; + status = apr_getopt(o, "s:c", &opt, &arg); + if (status == APR_EOF) { + break; + } + else if (status != APR_SUCCESS) { + usage(); + } + else { + switch (opt) { + case 'c': + if (doublelookups) { + usage(); + } + doublelookups = 1; + break; + case 's': + if (stats) { + usage(); + } + stats = apr_pstrdup(pool, arg); + break; + } /* switch */ + } /* else */ + } /* while */ + + apr_file_open_stdout(&outfile, pool); + apr_file_open_stdin(&infile, pool); + + /* Allocate two new 10k file buffers */ + if ( (outbuffer = apr_palloc(pool, WRITE_BUF_SIZE)) == NULL + || (inbuffer = apr_palloc(pool, READ_BUF_SIZE)) == NULL + || (line = apr_palloc(pool, LINE_BUF_SIZE)) == NULL) { + return 1; + } + + /* Set the buffers */ + apr_file_buffer_set(infile, inbuffer, READ_BUF_SIZE); + apr_file_buffer_set(outfile, outbuffer, WRITE_BUF_SIZE); + + cache = apr_hash_make(pool); + if (apr_pool_create(&pline, pool) != APR_SUCCESS) { + return 1; + } + + while (apr_file_gets(line, LINE_BUF_SIZE, infile) == APR_SUCCESS) { + char *hostname; + char *space; + apr_sockaddr_t *ip; + apr_sockaddr_t *ipdouble; + char dummy[] = " " APR_EOL_STR; + + if (line[0] == '\0') { + continue; + } + + /* Count our log entries */ + entries++; + + /* Check if this could even be an IP address */ + if (!apr_isxdigit(line[0]) && line[0] != ':') { + withname++; + apr_file_puts(line, outfile); + continue; + } + + /* Terminate the line at the next space */ + if ((space = strchr(line, ' ')) != NULL) { + *space = '\0'; + } + else { + space = dummy; + } + + /* See if we have it in our cache */ + hostname = (char *) apr_hash_get(cache, line, APR_HASH_KEY_STRING); + if (hostname) { + apr_file_printf(outfile, "%s %s", hostname, space + 1); + cachehits++; + continue; + } + + /* Parse the IP address */ + status = apr_sockaddr_info_get(&ip, line, APR_UNSPEC, 0, 0, pline); + if (status != APR_SUCCESS) { + /* Not an IP address */ + withname++; + *space = ' '; + apr_file_puts(line, outfile); + continue; + } + + /* This does not make much sense, but historically "resolves" means + * "parsed as an IP address". It does not mean we actually resolved + * the IP address into a hostname. + */ + resolves++; + + /* From here on our we cache each result, even if it was not + * successful + */ + cachesize++; + + /* Try and perform a reverse lookup */ + status = apr_getnameinfo(&hostname, ip, 0) != APR_SUCCESS; + if (status || hostname == NULL) { + /* Could not perform a reverse lookup */ + *space = ' '; + apr_file_puts(line, outfile); + noreverse++; + + /* Add to cache */ + *space = '\0'; + apr_hash_set(cache, line, APR_HASH_KEY_STRING, + apr_pstrdup(apr_hash_pool_get(cache), line)); + continue; + } + + /* Perform a double lookup */ + if (doublelookups) { + /* Do a forward lookup on our hostname, and see if that matches our + * original IP address. + */ + status = apr_sockaddr_info_get(&ipdouble, hostname, ip->family, 0, + 0, pline); + if (status != APR_SUCCESS || + memcmp(ipdouble->ipaddr_ptr, ip->ipaddr_ptr, ip->ipaddr_len)) { + /* Double-lookup failed */ + *space = ' '; + apr_file_puts(line, outfile); + doublefailed++; + + /* Add to cache */ + *space = '\0'; + apr_hash_set(cache, line, APR_HASH_KEY_STRING, + apr_pstrdup(apr_hash_pool_get(cache), line)); + continue; + } + } + + /* Output the resolved name */ + apr_file_printf(outfile, "%s %s", hostname, space + 1); + + /* Store it in the cache */ + apr_hash_set(cache, line, APR_HASH_KEY_STRING, + apr_pstrdup(apr_hash_pool_get(cache), hostname)); + + apr_pool_clear(pline); + } + + /* Flush any remaining output */ + apr_file_flush(outfile); + + if (stats) { + apr_file_t *statsfile; + if (apr_file_open(&statsfile, stats, + APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE, + APR_OS_DEFAULT, pool) != APR_SUCCESS) { + apr_file_printf(errfile, "%s: Could not open %s for writing.", + shortname, stats); + return 1; + } + print_statistics(statsfile); + apr_file_close(statsfile); + } + + return 0; +} diff --git a/support/logresolve.dep b/support/logresolve.dep new file mode 100644 index 0000000..7b6c07f --- /dev/null +++ b/support/logresolve.dep @@ -0,0 +1,26 @@ +# Microsoft Developer Studio Generated Dependency File, included by logresolve.mak + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + + +.\logresolve.c : \ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_getopt.h"\ + "..\srclib\apr\include\apr_hash.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_network_io.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_want.h"\ + diff --git a/support/logresolve.dsp b/support/logresolve.dsp new file mode 100644 index 0000000..648daac --- /dev/null +++ b/support/logresolve.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="logresolve" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=logresolve - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "logresolve.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "logresolve.mak" CFG="logresolve - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "logresolve - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "logresolve - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "logresolve - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/logresolve_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/logresolve.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\logresolve.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "logresolve - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/logresolve_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/logresolve.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\logresolve.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "logresolve - Win32 Release" +# Name "logresolve - Win32 Debug" +# Begin Source File + +SOURCE=.\logresolve.c +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/logresolve.mak b/support/logresolve.mak new file mode 100644 index 0000000..6e54624 --- /dev/null +++ b/support/logresolve.mak @@ -0,0 +1,317 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on logresolve.dsp +!IF "$(CFG)" == "" +CFG=logresolve - Win32 Debug +!MESSAGE No configuration specified. Defaulting to logresolve - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "logresolve - Win32 Release" && "$(CFG)" != "logresolve - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "logresolve.mak" CFG="logresolve - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "logresolve - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "logresolve - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "logresolve - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\logresolve.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\logresolve.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\logresolve.obj" + -@erase "$(INTDIR)\logresolve.res" + -@erase "$(INTDIR)\logresolve_src.idb" + -@erase "$(INTDIR)\logresolve_src.pdb" + -@erase "$(OUTDIR)\logresolve.exe" + -@erase "$(OUTDIR)\logresolve.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\logresolve_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\logresolve.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\logresolve.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\logresolve.pdb" /debug /out:"$(OUTDIR)\logresolve.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\logresolve.obj" \ + "$(INTDIR)\logresolve.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\logresolve.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\logresolve.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\logresolve.exe" + if exist .\Release\logresolve.exe.manifest mt.exe -manifest .\Release\logresolve.exe.manifest -outputresource:.\Release\logresolve.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "logresolve - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\logresolve.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\logresolve.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\logresolve.obj" + -@erase "$(INTDIR)\logresolve.res" + -@erase "$(INTDIR)\logresolve_src.idb" + -@erase "$(INTDIR)\logresolve_src.pdb" + -@erase "$(OUTDIR)\logresolve.exe" + -@erase "$(OUTDIR)\logresolve.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\logresolve_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\logresolve.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\logresolve.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\logresolve.pdb" /debug /out:"$(OUTDIR)\logresolve.exe" +LINK32_OBJS= \ + "$(INTDIR)\logresolve.obj" \ + "$(INTDIR)\logresolve.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\logresolve.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\logresolve.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\logresolve.exe" + if exist .\Debug\logresolve.exe.manifest mt.exe -manifest .\Debug\logresolve.exe.manifest -outputresource:.\Debug\logresolve.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("logresolve.dep") +!INCLUDE "logresolve.dep" +!ELSE +!MESSAGE Warning: cannot find "logresolve.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "logresolve - Win32 Release" || "$(CFG)" == "logresolve - Win32 Debug" + +!IF "$(CFG)" == "logresolve - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "logresolve - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "logresolve - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "logresolve - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "logresolve - Win32 Release" + + +"$(INTDIR)\logresolve.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\logresolve.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe" $(SOURCE) + + +!ELSEIF "$(CFG)" == "logresolve - Win32 Debug" + + +"$(INTDIR)\logresolve.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\logresolve.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="logresolve.exe" /d LONG_NAME="Apache logresolve command line pipe" $(SOURCE) + + +!ENDIF + +SOURCE=.\logresolve.c + +"$(INTDIR)\logresolve.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/support/logresolve.pl.in b/support/logresolve.pl.in new file mode 100644 index 0000000..2cd212d --- /dev/null +++ b/support/logresolve.pl.in @@ -0,0 +1,225 @@ +#!@perlbin@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# logresolve.pl +# +# v 1.2 by robh imdb.com +# +# usage: logresolve.pl <infile >outfile +# +# input = Apache/NCSA/.. logfile with IP numbers at start of lines +# output = same logfile with IP addresses resolved to hostnames where +# name lookups succeeded. +# +# this differs from the C based 'logresolve' in that this script +# spawns a number ($CHILDREN) of subprocesses to resolve addresses +# concurrently and sets a short timeout ($TIMEOUT) for each lookup in +# order to keep things moving quickly. +# +# the parent process handles caching of IP->hostnames using a Perl hash +# it also avoids sending the same IP to multiple child processes to be +# resolved multiple times concurrently. +# +# Depending on the settings of $CHILDREN and $TIMEOUT you should see +# significant reductions in the overall time taken to resolve your +# logfiles. With $CHILDREN=40 and $TIMEOUT=5 I've seen 200,000 - 300,000 +# logfile lines processed per hour compared to ~45,000 per hour +# with 'logresolve'. +# +# I haven't yet seen any noticeable reduction in the percentage of IPs +# that fail to get resolved. Your mileage will no doubt vary. 5s is long +# enough to wait IMO. +# +# Known to work with FreeBSD 2.2 +# Known to have problems with Solaris +# +# 980417 - use 'sockaddr_un' for bind/connect to make the script work +# with linux. Fix from Luuk de Boer <luuk_de_boer pi.net> + +require 5.004; + +$|=1; + +use FileHandle; +use Socket; + +use strict; +no strict 'refs'; + +use vars qw($PROTOCOL); +$PROTOCOL = 0; + +my $CHILDREN = 40; +my $TIMEOUT = 5; + +my $filename; +my %hash = (); +my $parent = $$; + +my @children = (); +for (my $child = 1; $child <=$CHILDREN; $child++) { + my $f = fork(); + if (!$f) { + $filename = "./.socket.$parent.$child"; + if (-e $filename) { unlink($filename) || warn "$filename .. $!\n";} + &child($child); + exit(0); + } + push(@children, $f); +} + +&parent; +&cleanup; + +## remove all temporary files before shutting down +sub cleanup { + # die kiddies, die + kill(15, @children); + for (my $child = 1; $child <=$CHILDREN; $child++) { + if (-e "./.socket.$parent.$child") { + unlink("./.socket.$parent.$child") + || warn ".socket.$parent.$child $!"; + } + } +} + +sub parent { + # Trap some possible signals to trigger temp file cleanup + $SIG{'KILL'} = $SIG{'INT'} = $SIG{'PIPE'} = \&cleanup; + + my %CHILDSOCK; + my $filename; + + ## fork child processes. Each child will create a socket connection + ## to this parent and use an unique temp filename to do so. + for (my $child = 1; $child <=$CHILDREN; $child++) { + $CHILDSOCK{$child}= FileHandle->new; + + if (!socket($CHILDSOCK{$child}, AF_UNIX, SOCK_STREAM, $PROTOCOL)) { + warn "parent socket to child failed $!"; + } + $filename = "./.socket.$parent.$child"; + my $response; + do { + $response = connect($CHILDSOCK{$child}, sockaddr_un($filename)); + if ($response != 1) { + sleep(1); + } + } while ($response != 1); + $CHILDSOCK{$child}->autoflush; + } + ## All child processes should now be ready or at worst warming up + + my (@buffer, $child, $ip, $rest, $hostname, $response); + ## read the logfile lines from STDIN + while(<STDIN>) { + @buffer = (); # empty the logfile line buffer array. + $child = 1; # children are numbered 1..N, start with #1 + + # while we have a child to talk to and data to give it.. + do { + push(@buffer, $_); # buffer the line + ($ip, $rest) = split(/ /, $_, 2); # separate IP form rest + + unless ($hash{$ip}) { # resolve if unseen IP + $CHILDSOCK{$child}->print("$ip\n"); # pass IP to next child + $hash{$ip} = $ip; # don't look it up again. + $child++; + } + } while (($child < ($CHILDREN-1)) and ($_ = <STDIN>)); + + ## now poll each child for a response + while (--$child > 0) { + $response = $CHILDSOCK{$child}->getline; + chomp($response); + # child sends us back both the IP and HOSTNAME, no need for us + # to remember what child received any given IP, and no worries + # what order we talk to the children + ($ip, $hostname) = split(/\|/, $response, 2); + $hash{$ip} = $hostname; + } + + # resolve all the logfiles lines held in the log buffer array.. + for (my $line = 0; $line <=$#buffer; $line++) { + # get next buffered line + ($ip, $rest) = split(/ /, $buffer[$line], 2); + # separate IP from rest and replace with cached hostname + printf STDOUT ("%s %s", $hash{$ip}, $rest); + } + } +} + +######################################## + +sub child { + # arg = numeric ID - how the parent refers to me + my $me = shift; + + # add trap for alarm signals. + $SIG{'ALRM'} = sub { die "alarmed"; }; + + # create a socket to communicate with parent + socket(INBOUND, AF_UNIX, SOCK_STREAM, $PROTOCOL) + || die "Error with Socket: !$\n"; + $filename = "./.socket.$parent.$me"; + bind(INBOUND, sockaddr_un($filename)) + || die "Error Binding $filename: $!\n"; + listen(INBOUND, 5) || die "Error Listening: $!\n"; + + my ($ip, $send_back); + my $talk = FileHandle->new; + + # accept a connection from the parent process. We only ever have + # have one connection where we exchange 1 line of info with the + # parent.. 1 line in (IP address), 1 line out (IP + hostname). + accept($talk, INBOUND) || die "Error Accepting: $!\n"; + # disable I/O buffering just in case + $talk->autoflush; + # while the parent keeps sending data, we keep responding.. + while(($ip = $talk->getline)) { + chomp($ip); + # resolve the IP if time permits and send back what we found.. + $send_back = sprintf("%s|%s", $ip, &nslookup($ip)); + $talk->print($send_back."\n"); + } +} + +# perform a time restricted hostname lookup. +sub nslookup { + # get the IP as an arg + my $ip = shift; + my $hostname = undef; + + # do the hostname lookup inside an eval. The eval will use the + # already configured SIGnal handler and drop out of the {} block + # regardless of whether the alarm occurred or not. + eval { + alarm($TIMEOUT); + $hostname = gethostbyaddr(gethostbyname($ip), AF_INET); + alarm(0); + }; + if ($@ =~ /alarm/) { + # useful for debugging perhaps.. + # print "alarming, isn't it? ($ip)"; + } + + # return the hostname or the IP address itself if there is no hostname + $hostname ne "" ? $hostname : $ip; +} + + diff --git a/support/passwd_common.c b/support/passwd_common.c new file mode 100644 index 0000000..664e509 --- /dev/null +++ b/support/passwd_common.c @@ -0,0 +1,344 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "passwd_common.h" +#include "apr_strings.h" +#include "apr_errno.h" + +#if APR_HAVE_STDIO_H +#include <stdio.h> +#endif + +#include "apr_md5.h" +#include "apr_sha1.h" + +#if APR_HAVE_TIME_H +#include <time.h> +#endif +#if APR_HAVE_CRYPT_H +#include <crypt.h> +#endif +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if APR_HAVE_STRING_H +#include <string.h> +#endif +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif +#if APR_HAVE_IO_H +#include <io.h> +#endif + +#ifdef _MSC_VER +#define write _write +#endif + +apr_file_t *errfile; + +int abort_on_oom(int rc) +{ + const char *buf = "Error: out of memory\n"; + int written, count = strlen(buf); + do { + written = write(STDERR_FILENO, buf, count); + if (written == count) + break; + if (written > 0) { + buf += written; + count -= written; + } + } while (written >= 0 || errno == EINTR); + abort(); + /* NOTREACHED */ + return 0; +} + +static int generate_salt(char *s, size_t size, const char **errstr, + apr_pool_t *pool) +{ + unsigned char rnd[32]; + static const char itoa64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + apr_size_t n; + unsigned int val = 0, bits = 0; + apr_status_t rv; + + n = (size * 6 + 7)/8; + if (n > sizeof(rnd)) { + apr_file_printf(errfile, "generate_salt(): BUG: Buffer too small"); + abort(); + } + rv = apr_generate_random_bytes(rnd, n); + if (rv) { + *errstr = apr_psprintf(pool, "Unable to generate random bytes: %pm", + &rv); + return ERR_RANDOM; + } + n = 0; + while (size > 0) { + if (bits < 6) { + val |= (rnd[n++] << bits); + bits += 8; + } + *s++ = itoa64[val & 0x3f]; + size--; + val >>= 6; + bits -= 6; + } + *s = '\0'; + return 0; +} + +void putline(apr_file_t *f, const char *l) +{ + apr_status_t rv; + if (f == NULL) + return; + rv = apr_file_puts(l, f); + if (rv != APR_SUCCESS) { + apr_file_printf(errfile, "Error writing temp file: %pm", &rv); + apr_file_close(f); + exit(ERR_FILEPERM); + } +} + +int get_password(struct passwd_ctx *ctx) +{ + char buf[MAX_STRING_LEN + 1]; + if (ctx->passwd_src == PW_STDIN) { + apr_file_t *file_stdin; + apr_size_t nread; + if (apr_file_open_stdin(&file_stdin, ctx->pool) != APR_SUCCESS) { + ctx->errstr = "Unable to read from stdin."; + return ERR_GENERAL; + } + if (apr_file_read_full(file_stdin, buf, sizeof(buf) - 1, + &nread) != APR_EOF + || nread == sizeof(buf) - 1) { + goto err_too_long; + } + buf[nread] = '\0'; + if (nread >= 1 && buf[nread-1] == '\n') { + buf[nread-1] = '\0'; + if (nread >= 2 && buf[nread-2] == '\r') + buf[nread-2] = '\0'; + } + apr_file_close(file_stdin); + ctx->passwd = apr_pstrdup(ctx->pool, buf); + } + else if (ctx->passwd_src == PW_PROMPT_VERIFY) { + apr_size_t bufsize = sizeof(buf); + if (apr_password_get("Enter password: ", buf, &bufsize) != 0) + goto err_too_long; + ctx->passwd = apr_pstrdup(ctx->pool, buf); + } + else { + apr_size_t bufsize = sizeof(buf); + if (apr_password_get("New password: ", buf, &bufsize) != 0) + goto err_too_long; + ctx->passwd = apr_pstrdup(ctx->pool, buf); + bufsize = sizeof(buf); + buf[0] = '\0'; + apr_password_get("Re-type new password: ", buf, &bufsize); + if (strcmp(ctx->passwd, buf) != 0) { + ctx->errstr = "password verification error"; + memset(ctx->passwd, '\0', strlen(ctx->passwd)); + memset(buf, '\0', sizeof(buf)); + return ERR_PWMISMATCH; + } + } + memset(buf, '\0', sizeof(buf)); + return 0; + +err_too_long: + ctx->errstr = apr_psprintf(ctx->pool, + "password too long (>%" APR_SIZE_T_FMT ")", + sizeof(buf) - 1); + return ERR_OVERFLOW; +} + +/* + * Make a password record from the given information. A zero return + * indicates success; on failure, ctx->errstr points to the error message. + */ +int mkhash(struct passwd_ctx *ctx) +{ + char *pw; + char salt[16]; + apr_status_t rv; + int ret = 0; +#if CRYPT_ALGO_SUPPORTED + char *cbuf; +#endif + + if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) { + apr_file_printf(errfile, + "Warning: Ignoring -C argument for this algorithm." NL); + } + + if (ctx->passwd == NULL) { + if ((ret = get_password(ctx)) != 0) + return ret; + } + pw = ctx->passwd; + + switch (ctx->alg) { + case ALG_APSHA: + /* XXX out >= 28 + strlen(sha1) chars - fixed len SHA */ + apr_sha1_base64(pw, strlen(pw), ctx->out); + break; + + case ALG_APMD5: + ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool); + if (ret != 0) + break; + rv = apr_md5_encode(pw, salt, ctx->out, ctx->out_len); + if (rv != APR_SUCCESS) { + ctx->errstr = apr_psprintf(ctx->pool, + "could not encode password: %pm", &rv); + ret = ERR_GENERAL; + } + break; + + case ALG_PLAIN: + /* XXX this len limitation is not in sync with any HTTPd len. */ + apr_cpystrn(ctx->out, pw, ctx->out_len); + break; + +#if CRYPT_ALGO_SUPPORTED + case ALG_CRYPT: + ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool); + if (ret != 0) + break; + cbuf = crypt(pw, salt); + if (cbuf == NULL) { + rv = APR_FROM_OS_ERROR(errno); + ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv); + ret = ERR_PWMISMATCH; + break; + } + + apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1); + if (strlen(pw) > 8) { + char *truncpw = apr_pstrdup(ctx->pool, pw); + truncpw[8] = '\0'; + if (!strcmp(ctx->out, crypt(truncpw, salt))) { + apr_file_printf(errfile, "Warning: Password truncated to 8 " + "characters by CRYPT algorithm." NL); + } + memset(truncpw, '\0', strlen(pw)); + } + break; +#endif /* CRYPT_ALGO_SUPPORTED */ + +#if BCRYPT_ALGO_SUPPORTED + case ALG_BCRYPT: + rv = apr_generate_random_bytes((unsigned char*)salt, 16); + if (rv != APR_SUCCESS) { + ctx->errstr = apr_psprintf(ctx->pool, "Unable to generate random " + "bytes: %pm", &rv); + ret = ERR_RANDOM; + break; + } + + if (ctx->cost == 0) + ctx->cost = BCRYPT_DEFAULT_COST; + rv = apr_bcrypt_encode(pw, ctx->cost, (unsigned char*)salt, 16, + ctx->out, ctx->out_len); + if (rv != APR_SUCCESS) { + ctx->errstr = apr_psprintf(ctx->pool, "Unable to encode with " + "bcrypt: %pm", &rv); + ret = ERR_PWMISMATCH; + break; + } + break; +#endif /* BCRYPT_ALGO_SUPPORTED */ + + default: + apr_file_printf(errfile, "mkhash(): BUG: invalid algorithm %d", + ctx->alg); + abort(); + } + memset(pw, '\0', strlen(pw)); + return ret; +} + +int parse_common_options(struct passwd_ctx *ctx, char opt, + const char *opt_arg) +{ + switch (opt) { + case 'b': + ctx->passwd_src = PW_ARG; + break; + case 'i': + ctx->passwd_src = PW_STDIN; + break; + case 'm': + ctx->alg = ALG_APMD5; + break; + case 's': + ctx->alg = ALG_APSHA; + break; + case 'p': + ctx->alg = ALG_PLAIN; +#if !PLAIN_ALGO_SUPPORTED + /* Backward compatible behavior: Just print a warning */ + apr_file_printf(errfile, + "Warning: storing passwords as plain text might just " + "not work on this platform." NL); +#endif + break; + case 'd': +#if CRYPT_ALGO_SUPPORTED + ctx->alg = ALG_CRYPT; +#else + /* Backward compatible behavior: Use MD5. OK since MD5 is more secure */ + apr_file_printf(errfile, + "Warning: CRYPT algorithm not supported on this " + "platform." NL + "Automatically using MD5 format." NL); + ctx->alg = ALG_APMD5; +#endif + break; + case 'B': +#if BCRYPT_ALGO_SUPPORTED + ctx->alg = ALG_BCRYPT; +#else + /* Don't fall back to something less secure */ + ctx->errstr = "BCRYPT algorithm not supported on this platform"; + return ERR_ALG_NOT_SUPP; +#endif + break; + case 'C': { + char *endptr; + long num = strtol(opt_arg, &endptr, 10); + if (*endptr != '\0' || num <= 0) { + ctx->errstr = "argument to -C must be a positive integer"; + return ERR_SYNTAX; + } + ctx->cost = num; + break; + } + default: + apr_file_printf(errfile, + "parse_common_options(): BUG: invalid option %c", + opt); + abort(); + } + return 0; +} diff --git a/support/passwd_common.h b/support/passwd_common.h new file mode 100644 index 0000000..660081e --- /dev/null +++ b/support/passwd_common.h @@ -0,0 +1,128 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _PASSWD_COMMON_H +#define _PASSWD_COMMON_H + +#include "apr.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_errno.h" +#include "apr_file_io.h" +#include "apr_general.h" +#include "apr_version.h" +#if !APR_VERSION_AT_LEAST(2,0,0) +#include "apu_version.h" +#endif + +#define MAX_STRING_LEN 256 + +#define ALG_PLAIN 0 +#define ALG_CRYPT 1 +#define ALG_APMD5 2 +#define ALG_APSHA 3 +#define ALG_BCRYPT 4 + +#define BCRYPT_DEFAULT_COST 5 + +#define ERR_FILEPERM 1 +#define ERR_SYNTAX 2 +#define ERR_PWMISMATCH 3 +#define ERR_INTERRUPTED 4 +#define ERR_OVERFLOW 5 +#define ERR_BADUSER 6 +#define ERR_INVALID 7 +#define ERR_RANDOM 8 +#define ERR_GENERAL 9 +#define ERR_ALG_NOT_SUPP 10 + +#define NL APR_EOL_STR + +#if defined(WIN32) || defined(NETWARE) +#define CRYPT_ALGO_SUPPORTED 0 +#define PLAIN_ALGO_SUPPORTED 1 +#else +#define CRYPT_ALGO_SUPPORTED 1 +#define PLAIN_ALGO_SUPPORTED 0 +#endif + +#if APR_VERSION_AT_LEAST(2,0,0) || \ + (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 5) +#define BCRYPT_ALGO_SUPPORTED 1 +#else +#define BCRYPT_ALGO_SUPPORTED 0 +#endif + +#if APR_CHARSET_EBCDIC +#undef BCRYPT_ALGO_SUPPORTED +#define BCRYPT_ALGO_SUPPORTED 0 +#endif + +/* + * Must be initialized with apr_file_open_stderr() before using any of the + * below functions. + */ +extern apr_file_t *errfile; + +struct passwd_ctx { + apr_pool_t *pool; + const char *errstr; + char *out; + apr_size_t out_len; + char *passwd; + int alg; + int cost; + enum { + PW_PROMPT = 0, + PW_ARG, + PW_STDIN, + PW_PROMPT_VERIFY, + } passwd_src; +}; + + +/* + * To be used as apr_pool_abort_fn + */ +int abort_on_oom(int rc); + +/* + * Write a line to the file. On error, print a message and exit + */ +void putline(apr_file_t *f, const char *l); + +/* + * The following functions return zero on success; otherwise, one of + * the ERR_* codes is returned and an error message is stored in ctx->errstr. + */ + +/* + * Parse the algorithm specific options. + */ +int parse_common_options(struct passwd_ctx *ctx, char opt, const char *opt_arg); + +/* + * Ask for password with verification. + */ +int get_password(struct passwd_ctx *ctx); + +/* + * Make a password record from the given information. + */ +int mkhash(struct passwd_ctx *ctx); + +#endif /* _PASSWD_COMMON_H */ + diff --git a/support/phf_abuse_log.cgi.in b/support/phf_abuse_log.cgi.in new file mode 100644 index 0000000..39900bf --- /dev/null +++ b/support/phf_abuse_log.cgi.in @@ -0,0 +1,38 @@ +#!@perlbin@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# This script is used to detect people trying to abuse the security hole which +# existed in A CGI script direstributed with Apache 1.0.3 and earlier versions. +# You can redirect them to here using the "<Location /cgi-bin/phf*>" suggestion +# in httpd.conf. +# +# The format logged to is +# "[date] remote_addr remote_host [date] referrer user_agent". + +$LOG = "/var/log/phf_log"; + +require "ctime.pl"; +$when = &ctime(time); +$when =~ s/\n//go; +$ENV{HTTP_USER_AGENT} .= " via $ENV{HTTP_VIA}" if($ENV{HTTP_VIA}); + +open(LOG, ">>$LOG") || die "boo hoo, phf_log $!"; +print LOG "[$when] $ENV{REMOTE_ADDR} $ENV{REMOTE_HOST} $ENV{$HTTP_REFERER} $ENV{HTTP_USER_AGENT}\n"; +close(LOG); + +print "Content-type: text/html\r\n\r\n<BLINK>Smile, you're on Candid Camera.</BLINK>\n"; diff --git a/support/rotatelogs.c b/support/rotatelogs.c new file mode 100644 index 0000000..e0819da --- /dev/null +++ b/support/rotatelogs.c @@ -0,0 +1,810 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr.h" +#include "apr_lib.h" +#include "apr_strings.h" +#include "apr_errno.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_general.h" +#include "apr_time.h" +#include "apr_getopt.h" +#include "apr_thread_proc.h" +#include "apr_signal.h" +#if APR_FILES_AS_SOCKETS +#include "apr_poll.h" +#endif + +#if APR_HAVE_STDLIB_H +#include <stdlib.h> +#endif +#define APR_WANT_STRFUNC +#include "apr_want.h" + +#define BUFSIZE 65536 + +#define ROTATE_NONE 0 +#define ROTATE_NEW 1 +#define ROTATE_TIME 2 +#define ROTATE_SIZE 3 +#define ROTATE_FORCE 4 + +static const char *const ROTATE_REASONS[] = { + "None", + "Open a new file", + "Time interval expired", + "Maximum size reached", + "Forced rotation", + NULL +}; + +typedef struct rotate_config rotate_config_t; + +struct rotate_config { + unsigned int sRotation; + int tRotation; + int utc_offset; + int use_localtime; + int use_strftime; + int force_open; + int verbose; + int echo; + char *szLogRoot; + int truncate; + int truncate_rotated_only; + const char *linkfile; + const char *postrotate_prog; +#if APR_FILES_AS_SOCKETS + int create_empty; +#endif + int num_files; + int create_path; +}; + +typedef struct rotate_status rotate_status_t; + +/* "adjusted_time_t" is used to store Unix time (seconds since epoch) + * which has been adjusted for some timezone fudge factor. It should + * be used for storing the return values from get_now(). A typedef is + * used since this type is similar to time_t, but different. */ +typedef long adjusted_time_t; + +/* Structure to contain relevant logfile state: fd, pool and + * filename. */ +struct logfile { + apr_pool_t *pool; + apr_file_t *fd; + char name[APR_PATH_MAX]; +}; + +struct rotate_status { + struct logfile current; /* current logfile. */ + apr_pool_t *pool; /* top-level pool */ + int rotateReason; + adjusted_time_t tLogEnd; + int nMessCount; + int fileNum; +}; + +static rotate_config_t config; +static rotate_status_t status; + +static void usage(const char *argv0, const char *reason) +{ + if (reason) { + fprintf(stderr, "%s\n", reason); + } + fprintf(stderr, +#if APR_FILES_AS_SOCKETS + "Usage: %s [-vlfDtTec] [-L linkname] [-p prog] [-n number] <logfile> " +#else + "Usage: %s [-vlfDtTe] [-L linkname] [-p prog] [-n number] <logfile> " +#endif + "{<rotation time in seconds>|<rotation size>(B|K|M|G)} " + "[offset minutes from UTC]\n\n", + argv0); +#ifdef OS2 + fprintf(stderr, + "Add this:\n\nTransferLog \"|%s.exe /some/where 86400\"\n\n", + argv0); +#else + fprintf(stderr, + "Add this:\n\nTransferLog \"|%s /some/where 86400\"\n\n", + argv0); + fprintf(stderr, + "or \n\nTransferLog \"|%s /some/where 5M\"\n\n", argv0); +#endif + fprintf(stderr, + "to httpd.conf. By default, the generated name will be\n" + "<logfile>.nnnn where nnnn is the system time at which the log\n" + "nominally starts (N.B. if using a rotation time, the time will\n" + "always be a multiple of the rotation time, so you can synchronize\n" + "cron scripts with it). If <logfile> contains strftime conversion\n" + "specifications, those will be used instead. At the end of each\n" + "rotation time or when the file size is reached a new log is\n" + "started.\n" + "\n" + "Options:\n" + " -v Verbose operation. Messages are written to stderr.\n" + " -l Base rotation on local time instead of UTC.\n" + " -L path Create hard link from current log to specified path.\n" + " -p prog Run specified program after opening a new log file. See below.\n" + " -f Force opening of log on program start.\n" + " -D Create parent directories of log file.\n" + " -t Truncate logfile instead of rotating, tail friendly.\n" + " -T Truncate logfiles opened for rotation, but not the initial logfile.\n" + " -e Echo log to stdout for further processing.\n" +#if APR_FILES_AS_SOCKETS + " -c Create log even if it is empty.\n" +#endif + " -n num Rotate file by adding suffixes '.1', '.2', ..., '.num'.\n" + "\n" + "The program for '-p' is invoked as \"[prog] <curfile> [<prevfile>]\"\n" + "where <curfile> is the filename of the newly opened logfile, and\n" + "<prevfile>, if given, is the filename of the previously used logfile.\n" + "\n"); + exit(1); +} + +/* This function returns the current Unix time (time_t) adjusted for + * any configured or derived local time offset. The offset applied is + * returned via *offset. */ +static adjusted_time_t get_now(rotate_config_t *config, apr_int32_t *offset) +{ + apr_time_t tNow = apr_time_now(); + apr_int32_t utc_offset; + + if (config->use_localtime) { + /* Check for our UTC offset before using it, since it might + * change if there's a switch between standard and daylight + * savings time. + */ + apr_time_exp_t lt; + apr_time_exp_lt(<, tNow); + utc_offset = lt.tm_gmtoff; + } + else { + utc_offset = config->utc_offset; + } + + if (offset) + *offset = utc_offset; + + return apr_time_sec(tNow) + utc_offset; +} + +/* + * Close a file and destroy the associated pool. + */ +static void close_logfile(rotate_config_t *config, struct logfile *logfile) +{ + if (config->verbose) { + fprintf(stderr, "Closing file %s\n", logfile->name); + } + apr_file_close(logfile->fd); + apr_pool_destroy(logfile->pool); +} + +/* + * Dump the configuration parsing result to STDERR. + */ +static void dumpConfig (rotate_config_t *config) +{ + fprintf(stderr, "Rotation time interval: %12d\n", config->tRotation); + fprintf(stderr, "Rotation size interval: %12d\n", config->sRotation); + fprintf(stderr, "Rotation time UTC offset: %12d\n", config->utc_offset); + fprintf(stderr, "Rotation based on localtime: %12s\n", config->use_localtime ? "yes" : "no"); + fprintf(stderr, "Rotation file date pattern: %12s\n", config->use_strftime ? "yes" : "no"); + fprintf(stderr, "Rotation file forced open: %12s\n", config->force_open ? "yes" : "no"); + fprintf(stderr, "Create parent directories: %12s\n", config->create_path ? "yes" : "no"); + fprintf(stderr, "Rotation verbose: %12s\n", config->verbose ? "yes" : "no"); +#if APR_FILES_AS_SOCKETS + fprintf(stderr, "Rotation create empty logs: %12s\n", config->create_empty ? "yes" : "no"); +#endif + fprintf(stderr, "Rotation file name: %21s\n", config->szLogRoot); + fprintf(stderr, "Post-rotation prog: %21s\n", config->postrotate_prog ? config->postrotate_prog : "not used"); +} + +/* + * Check whether we need to rotate. + * Possible reasons are: + * - No log file open (ROTATE_NEW) + * - User forces us to rotate (ROTATE_FORCE) + * - Our log file size is already bigger than the + * allowed maximum (ROTATE_SIZE) + * - The next log time interval expired (ROTATE_TIME) + * + * When size and time constraints are both given, + * it suffices that one of them is fulfilled. + */ +static void checkRotate(rotate_config_t *config, rotate_status_t *status) +{ + if (status->current.fd == NULL) { + status->rotateReason = ROTATE_NEW; + } + else if (config->sRotation) { + apr_finfo_t finfo; + apr_off_t current_size = -1; + + if (apr_file_info_get(&finfo, APR_FINFO_SIZE, status->current.fd) == APR_SUCCESS) { + current_size = finfo.size; + } + + if (current_size > config->sRotation) { + status->rotateReason = ROTATE_SIZE; + } + else if (config->tRotation) { + if (get_now(config, NULL) >= status->tLogEnd) { + status->rotateReason = ROTATE_TIME; + } + } + } + else if (config->tRotation) { + if (get_now(config, NULL) >= status->tLogEnd) { + status->rotateReason = ROTATE_TIME; + } + } + else { + fprintf(stderr, "No rotation time or size specified\n"); + exit(2); + } + + if (status->rotateReason != ROTATE_NONE && config->verbose) { + fprintf(stderr, "File rotation needed, reason: %s\n", ROTATE_REASONS[status->rotateReason]); + } +} + +/* + * Handle post-rotate processing. + */ +static void post_rotate(apr_pool_t *pool, struct logfile *newlog, + rotate_config_t *config, rotate_status_t *status) +{ + apr_status_t rv; + char error[120]; + apr_procattr_t *pattr; + const char *argv[4]; + apr_proc_t proc; + + /* Handle link file, if configured. */ + if (config->linkfile) { + apr_file_remove(config->linkfile, newlog->pool); + if (config->verbose) { + fprintf(stderr, "Linking %s to %s\n", newlog->name, config->linkfile); + } + rv = apr_file_link(newlog->name, config->linkfile); + if (rv != APR_SUCCESS) { + apr_strerror(rv, error, sizeof error); + fprintf(stderr, "Error linking file %s to %s (%s)\n", + newlog->name, config->linkfile, error); + exit(2); + } + } + + if (!config->postrotate_prog) { + /* Nothing more to do. */ + return; + } + + /* Collect any zombies from a previous run, but don't wait. */ + while (apr_proc_wait_all_procs(&proc, NULL, NULL, APR_NOWAIT, pool) == APR_CHILD_DONE) + /* noop */; + + if ((rv = apr_procattr_create(&pattr, pool)) != APR_SUCCESS) { + fprintf(stderr, + "post_rotate: apr_procattr_create failed for '%s': %s\n", + config->postrotate_prog, + apr_strerror(rv, error, sizeof(error))); + return; + } + + rv = apr_procattr_error_check_set(pattr, 1); + if (rv == APR_SUCCESS) + rv = apr_procattr_cmdtype_set(pattr, APR_PROGRAM_ENV); + + if (rv != APR_SUCCESS) { + fprintf(stderr, + "post_rotate: could not set up process attributes for '%s': %s\n", + config->postrotate_prog, + apr_strerror(rv, error, sizeof(error))); + return; + } + + argv[0] = config->postrotate_prog; + argv[1] = newlog->name; + if (status->current.fd) { + argv[2] = status->current.name; + argv[3] = NULL; + } + else { + argv[2] = NULL; + } + + if (config->verbose) + fprintf(stderr, "Calling post-rotate program: %s\n", argv[0]); + + rv = apr_proc_create(&proc, argv[0], argv, NULL, pattr, pool); + if (rv != APR_SUCCESS) { + fprintf(stderr, "Could not spawn post-rotate process '%s': %s\n", + config->postrotate_prog, + apr_strerror(rv, error, sizeof(error))); + return; + } +} + +/* After a error, truncate the current file and write out an error + * message, which must be contained in message. The process is + * terminated on failure. */ +static void truncate_and_write_error(rotate_status_t *status, const char *message) +{ + apr_size_t buflen = strlen(message); + + if (apr_file_trunc(status->current.fd, 0) != APR_SUCCESS) { + fprintf(stderr, "Error truncating the file %s\n", status->current.name); + exit(2); + } + if (apr_file_write_full(status->current.fd, message, buflen, NULL) != APR_SUCCESS) { + fprintf(stderr, "Error writing error (%s) to the file %s\n", + message, status->current.name); + exit(2); + } +} + +/* + * Open a new log file, and if successful + * also close the old one. + * + * The timestamp for the calculation of the file + * name of the new log file will be the actual millisecond + * timestamp, except when a regular rotation based on a time + * interval is configured and the previous interval + * is over. Then the timestamp is the starting time + * of the actual interval. + */ +static void doRotate(rotate_config_t *config, rotate_status_t *status) +{ + apr_int32_t offset; + adjusted_time_t now, tLogStart; + apr_status_t rv; + struct logfile newlog; + int thisLogNum = -1; + int oldreason = status->rotateReason; + int truncate = config->truncate; + + /* Retrieve local-time-adjusted-Unix-time. */ + now = get_now(config, &offset); + + status->rotateReason = ROTATE_NONE; + + if (config->tRotation) { + adjusted_time_t tLogEnd; + + tLogStart = (now / config->tRotation) * config->tRotation; + tLogEnd = tLogStart + config->tRotation; + /* + * Check if rotation was forced and the last rotation + * interval is not yet over. Use the value of now instead + * of the time interval boundary for the file name then. + */ + if (tLogStart < status->tLogEnd) { + tLogStart = now; + } + status->tLogEnd = tLogEnd; + } + else { + tLogStart = now; + } + + if (config->use_strftime) { + apr_time_t tNow = apr_time_from_sec(tLogStart); + apr_time_exp_t e; + apr_size_t rs; + + /* Explode the local-time-adjusted-Unix-time into a struct tm, + * first *reversing* local-time-adjustment applied by + * get_now() if we are using localtime. */ + if (config->use_localtime) + apr_time_exp_lt(&e, tNow - apr_time_from_sec(offset)); + else + apr_time_exp_gmt(&e, tNow); + apr_strftime(newlog.name, &rs, sizeof(newlog.name), config->szLogRoot, &e); + } + else { + if (config->truncate) { + apr_snprintf(newlog.name, sizeof(newlog.name), "%s", config->szLogRoot); + } + else if (config->num_files > 0) { + if (status->fileNum == -1 || status->fileNum == (config->num_files - 1)) { + thisLogNum = 0; + apr_snprintf(newlog.name, sizeof(newlog.name), "%s", config->szLogRoot); + } + else { + thisLogNum = status->fileNum + 1; + apr_snprintf(newlog.name, sizeof(newlog.name), "%s.%d", config->szLogRoot, thisLogNum); + } + } + else { + apr_snprintf(newlog.name, sizeof(newlog.name), "%s.%010ld", config->szLogRoot, + tLogStart); + } + } + apr_pool_create(&newlog.pool, status->pool); + if (config->create_path) { + char *ptr = strrchr(newlog.name, '/'); + if (ptr && ptr > newlog.name) { + char *path = apr_pstrmemdup(newlog.pool, newlog.name, ptr - newlog.name); + if (config->verbose) { + fprintf(stderr, "Creating directory tree %s\n", path); + } + rv = apr_dir_make_recursive(path, APR_FPROT_OS_DEFAULT, newlog.pool); + if (rv != APR_SUCCESS) { + char error[120]; + + apr_strerror(rv, error, sizeof error); + fprintf(stderr, "Could not create directory '%s' (%s)\n", path, error); + exit(2); + } + } + } + if (config->verbose) { + fprintf(stderr, "Opening file %s\n", newlog.name); + } + + if (!truncate) { + /* -n and -T truncate subsequent files only. */ + if (status->current.fd && + (config->num_files > 0 || config->truncate_rotated_only)) { + truncate = 1; + } + } + rv = apr_file_open(&newlog.fd, newlog.name, + APR_WRITE | APR_CREATE | APR_APPEND + | (truncate ? APR_TRUNCATE : 0), + APR_OS_DEFAULT, newlog.pool); + if (rv == APR_SUCCESS) { + /* Handle post-rotate processing. */ + post_rotate(newlog.pool, &newlog, config, status); + + status->fileNum = thisLogNum; + /* Close out old (previously 'current') logfile, if any. */ + if (status->current.fd) { + close_logfile(config, &status->current); + } + + /* New log file is now 'current'. */ + status->current = newlog; + + /* The first write to the initial file hasn't checked for size. + * In the normalized timestamp case and the custom strftime case with + * any reasonable accuracy, it's futile as the rotation will pick the + * same filename again. + * For -n, when not truncating, check and rotate. + */ + if (config->num_files > 0 && oldreason == ROTATE_NEW && !config->truncate) { + checkRotate(config, status); + if (status->rotateReason != ROTATE_NONE) { + doRotate(config, status); + } + } + } + else { + char *error = apr_psprintf(newlog.pool, "%pm", &rv); + char *message; + + /* Uh-oh. Failed to open the new log file. Try to clear + * the previous log file, note the lost log entries, + * and keep on truckin'. */ + if (status->current.fd == NULL) { + fprintf(stderr, "Could not open log file '%s' (%s)\n", newlog.name, error); + exit(2); + } + + /* Try to keep this error message constant length + * in case it occurs several times. */ + message = apr_psprintf(newlog.pool, + "Resetting log file due to error opening " + "new log file, %10d messages lost: %-25.25s\n", + status->nMessCount, error); + + truncate_and_write_error(status, message); + + /* Throw away new state; it isn't going to be used. */ + apr_pool_destroy(newlog.pool); + } + + status->nMessCount = 0; +} + +/* + * Get a size or time param from a string. + * Parameter 'last' indicates, whether the + * argument is the last commandline argument. + * UTC offset is only allowed as a last argument + * in order to make is distinguishable from the + * rotation interval time. + */ +static const char *get_time_or_size(rotate_config_t *config, + const char *arg, int last) { + char *ptr = NULL; + /* Byte multiplier */ + unsigned int mult = 1; + if ((ptr = strchr(arg, 'B')) != NULL) { /* Found KB size */ + mult = 1; + } + else if ((ptr = strchr(arg, 'K')) != NULL) { /* Found KB size */ + mult = 1024; + } + else if ((ptr = strchr(arg, 'M')) != NULL) { /* Found MB size */ + mult = 1024 * 1024; + } + else if ((ptr = strchr(arg, 'G')) != NULL) { /* Found GB size */ + mult = 1024 * 1024 * 1024; + } + if (ptr) { /* rotation based on file size */ + if (config->sRotation > 0) { + return "Rotation size parameter allowed only once"; + } + if (*(ptr+1) == '\0') { + config->sRotation = atoi(arg) * mult; + } + if (config->sRotation == 0) { + return "Invalid rotation size parameter"; + } + } + else if ((config->sRotation > 0 || config->tRotation > 0) && last) { + /* rotation based on elapsed time */ + if (config->use_localtime) { + return "UTC offset parameter is not valid with -l"; + } + config->utc_offset = atoi(arg) * 60; + } + else { /* rotation based on elapsed time */ + if (config->tRotation > 0) { + return "Rotation time parameter allowed only once"; + } + config->tRotation = atoi(arg); + if (config->tRotation <= 0) { + return "Invalid rotation time parameter"; + } + } + return NULL; +} + +int main (int argc, const char * const argv[]) +{ + char buf[BUFSIZE]; + apr_size_t nRead, nWrite; + apr_file_t *f_stdin; + apr_file_t *f_stdout; + apr_getopt_t *opt; + apr_status_t rv; + char c; + const char *opt_arg; + const char *err = NULL; +#if APR_FILES_AS_SOCKETS + apr_pollfd_t pollfd = { 0 }; + apr_status_t pollret = APR_SUCCESS; + long polltimeout; +#endif + + apr_app_initialize(&argc, &argv, NULL); + atexit(apr_terminate); + + memset(&config, 0, sizeof config); + memset(&status, 0, sizeof status); + status.rotateReason = ROTATE_NONE; + + apr_pool_create(&status.pool, NULL); + apr_getopt_init(&opt, status.pool, argc, argv); +#if APR_FILES_AS_SOCKETS + while ((rv = apr_getopt(opt, "lL:p:fDtTvecn:", &c, &opt_arg)) == APR_SUCCESS) { +#else + while ((rv = apr_getopt(opt, "lL:p:fDtTven:", &c, &opt_arg)) == APR_SUCCESS) { +#endif + switch (c) { + case 'l': + config.use_localtime = 1; + break; + case 'L': + config.linkfile = opt_arg; + break; + case 'p': + config.postrotate_prog = opt_arg; +#ifdef SIGCHLD + /* Prevent creation of zombies (on modern Unix systems). */ + apr_signal(SIGCHLD, SIG_IGN); +#endif + break; + case 'f': + config.force_open = 1; + break; + case 'D': + config.create_path = 1; + break; + case 't': + config.truncate = 1; + break; + case 'T': + config.truncate_rotated_only = 1; + break; + case 'v': + config.verbose = 1; + break; + case 'e': + config.echo = 1; + break; +#if APR_FILES_AS_SOCKETS + case 'c': + config.create_empty = 1; + break; +#endif + case 'n': + config.num_files = atoi(opt_arg); + status.fileNum = -1; + break; + } + } + + if (rv != APR_EOF) { + usage(argv[0], NULL /* specific error message already issued */ ); + } + + /* + * After the initial flags we need 2 to 4 arguments, + * the file name, either the rotation interval time or size + * or both of them, and optionally the UTC offset. + */ + if ((argc - opt->ind < 2) || (argc - opt->ind > 4) ) { + usage(argv[0], "Incorrect number of arguments"); + } + + rv = apr_filepath_merge(&config.szLogRoot, "", argv[opt->ind++], + APR_FILEPATH_TRUENAME, status.pool); + if (rv != APR_SUCCESS && rv != APR_EPATHWILD) { + usage(argv[0], "Invalid filename given"); + } + + /* Read in the remaining flags, namely time, size and UTC offset. */ + for(; opt->ind < argc; opt->ind++) { + if ((err = get_time_or_size(&config, argv[opt->ind], + opt->ind < argc - 1 ? 0 : 1)) != NULL) { + usage(argv[0], err); + } + } + + config.use_strftime = (strchr(config.szLogRoot, '%') != NULL); + + if (config.use_strftime && config.num_files > 0) { + fprintf(stderr, "Cannot use -n with %% in filename\n"); + exit(1); + } + + if (status.fileNum == -1 && config.num_files < 1) { + fprintf(stderr, "Invalid -n argument\n"); + exit(1); + } + + if (apr_file_open_stdin(&f_stdin, status.pool) != APR_SUCCESS) { + fprintf(stderr, "Unable to open stdin\n"); + exit(1); + } + + if (apr_file_open_stdout(&f_stdout, status.pool) != APR_SUCCESS) { + fprintf(stderr, "Unable to open stdout\n"); + exit(1); + } + + /* + * Write out result of config parsing if verbose is set. + */ + if (config.verbose) { + dumpConfig(&config); + } + +#if APR_FILES_AS_SOCKETS + if (config.create_empty && config.tRotation) { + pollfd.p = status.pool; + pollfd.desc_type = APR_POLL_FILE; + pollfd.reqevents = APR_POLLIN; + pollfd.desc.f = f_stdin; + } +#endif + + /* + * Immediately open the logfile as we start, if we were forced + * to do so via '-f'. + */ + if (config.force_open) { + doRotate(&config, &status); + } + + for (;;) { + nRead = sizeof(buf); +#if APR_FILES_AS_SOCKETS + if (config.create_empty && config.tRotation) { + polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config, NULL) : config.tRotation; + if (polltimeout <= 0) { + pollret = APR_TIMEUP; + } + else { + pollret = apr_poll(&pollfd, 1, &pollret, apr_time_from_sec(polltimeout)); + } + } + if (pollret == APR_SUCCESS) { + rv = apr_file_read(f_stdin, buf, &nRead); + if (APR_STATUS_IS_EOF(rv)) { + break; + } + else if (rv != APR_SUCCESS) { + exit(3); + } + } + else if (pollret == APR_TIMEUP) { + *buf = 0; + nRead = 0; + } + else { + fprintf(stderr, "Unable to poll stdin\n"); + exit(5); + } +#else /* APR_FILES_AS_SOCKETS */ + rv = apr_file_read(f_stdin, buf, &nRead); + if (APR_STATUS_IS_EOF(rv)) { + break; + } + else if (rv != APR_SUCCESS) { + exit(3); + } +#endif /* APR_FILES_AS_SOCKETS */ + checkRotate(&config, &status); + if (status.rotateReason != ROTATE_NONE) { + doRotate(&config, &status); + } + + nWrite = nRead; + rv = apr_file_write_full(status.current.fd, buf, nWrite, &nWrite); + if (nWrite != nRead) { + apr_off_t cur_offset; + apr_pool_t *pool; + char *error; + + cur_offset = 0; + if (apr_file_seek(status.current.fd, APR_CUR, &cur_offset) != APR_SUCCESS) { + cur_offset = -1; + } + status.nMessCount++; + apr_pool_create(&pool, status.pool); + error = apr_psprintf(pool, "Error %d writing to log file at offset %" + APR_OFF_T_FMT ". %10d messages lost (%pm)\n", + rv, cur_offset, status.nMessCount, &rv); + + truncate_and_write_error(&status, error); + apr_pool_destroy(pool); + } + else { + status.nMessCount++; + } + if (config.echo) { + if (apr_file_write_full(f_stdout, buf, nRead, &nWrite)) { + fprintf(stderr, "Unable to write to stdout\n"); + exit(4); + } + } + } + + return 0; /* reached only at stdin EOF. */ +} diff --git a/support/rotatelogs.dep b/support/rotatelogs.dep new file mode 100644 index 0000000..5b27972 --- /dev/null +++ b/support/rotatelogs.dep @@ -0,0 +1,28 @@ +# Microsoft Developer Studio Generated Dependency File, included by rotatelogs.mak + +..\build\win32\httpd.rc : \ + "..\include\ap_release.h"\ + + +.\rotatelogs.c : \ + "..\srclib\apr\include\apr.h"\ + "..\srclib\apr\include\apr_allocator.h"\ + "..\srclib\apr\include\apr_errno.h"\ + "..\srclib\apr\include\apr_file_info.h"\ + "..\srclib\apr\include\apr_file_io.h"\ + "..\srclib\apr\include\apr_general.h"\ + "..\srclib\apr\include\apr_getopt.h"\ + "..\srclib\apr\include\apr_inherit.h"\ + "..\srclib\apr\include\apr_lib.h"\ + "..\srclib\apr\include\apr_network_io.h"\ + "..\srclib\apr\include\apr_poll.h"\ + "..\srclib\apr\include\apr_pools.h"\ + "..\srclib\apr\include\apr_signal.h"\ + "..\srclib\apr\include\apr_strings.h"\ + "..\srclib\apr\include\apr_tables.h"\ + "..\srclib\apr\include\apr_thread_mutex.h"\ + "..\srclib\apr\include\apr_thread_proc.h"\ + "..\srclib\apr\include\apr_time.h"\ + "..\srclib\apr\include\apr_user.h"\ + "..\srclib\apr\include\apr_want.h"\ + diff --git a/support/rotatelogs.dsp b/support/rotatelogs.dsp new file mode 100644 index 0000000..abfa9c1 --- /dev/null +++ b/support/rotatelogs.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="rotatelogs" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=rotatelogs - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "rotatelogs.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "rotatelogs.mak" CFG="rotatelogs - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "rotatelogs - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "rotatelogs - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "rotatelogs - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/rotatelogs_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/rotatelogs.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\rotatelogs.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/rotatelogs_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/rotatelogs.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\rotatelogs.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "rotatelogs - Win32 Release" +# Name "rotatelogs - Win32 Debug" +# Begin Source File + +SOURCE=.\rotatelogs.c +# End Source File +# Begin Source File + +SOURCE=..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/rotatelogs.mak b/support/rotatelogs.mak new file mode 100644 index 0000000..f7a6fd4 --- /dev/null +++ b/support/rotatelogs.mak @@ -0,0 +1,317 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on rotatelogs.dsp +!IF "$(CFG)" == "" +CFG=rotatelogs - Win32 Debug +!MESSAGE No configuration specified. Defaulting to rotatelogs - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "rotatelogs - Win32 Release" && "$(CFG)" != "rotatelogs - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "rotatelogs.mak" CFG="rotatelogs - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "rotatelogs - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "rotatelogs - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "rotatelogs - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\rotatelogs.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\rotatelogs.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\rotatelogs.obj" + -@erase "$(INTDIR)\rotatelogs.res" + -@erase "$(INTDIR)\rotatelogs_src.idb" + -@erase "$(INTDIR)\rotatelogs_src.pdb" + -@erase "$(OUTDIR)\rotatelogs.exe" + -@erase "$(OUTDIR)\rotatelogs.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\rotatelogs_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\rotatelogs.res" /i "../include" /i "../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\rotatelogs.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\rotatelogs.pdb" /debug /out:"$(OUTDIR)\rotatelogs.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\rotatelogs.obj" \ + "$(INTDIR)\rotatelogs.res" \ + "..\srclib\apr\LibR\apr-1.lib" \ + "..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\rotatelogs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\rotatelogs.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\rotatelogs.exe" + if exist .\Release\rotatelogs.exe.manifest mt.exe -manifest .\Release\rotatelogs.exe.manifest -outputresource:.\Release\rotatelogs.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\rotatelogs.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\rotatelogs.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\rotatelogs.obj" + -@erase "$(INTDIR)\rotatelogs.res" + -@erase "$(INTDIR)\rotatelogs_src.idb" + -@erase "$(INTDIR)\rotatelogs_src.pdb" + -@erase "$(OUTDIR)\rotatelogs.exe" + -@erase "$(OUTDIR)\rotatelogs.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\rotatelogs_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\rotatelogs.res" /i "../include" /i "../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\rotatelogs.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib advapi32.lib wsock32.lib ws2_32.lib rpcrt4.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\rotatelogs.pdb" /debug /out:"$(OUTDIR)\rotatelogs.exe" +LINK32_OBJS= \ + "$(INTDIR)\rotatelogs.obj" \ + "$(INTDIR)\rotatelogs.res" \ + "..\srclib\apr\LibD\apr-1.lib" \ + "..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\rotatelogs.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\rotatelogs.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\rotatelogs.exe" + if exist .\Debug\rotatelogs.exe.manifest mt.exe -manifest .\Debug\rotatelogs.exe.manifest -outputresource:.\Debug\rotatelogs.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("rotatelogs.dep") +!INCLUDE "rotatelogs.dep" +!ELSE +!MESSAGE Warning: cannot find "rotatelogs.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "rotatelogs - Win32 Release" || "$(CFG)" == "rotatelogs - Win32 Debug" + +!IF "$(CFG)" == "rotatelogs - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support" + +"apr - Win32 DebugCLEAN" : + cd ".\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +!IF "$(CFG)" == "rotatelogs - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support" + +!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support" + +!ENDIF + +SOURCE=..\build\win32\httpd.rc + +!IF "$(CFG)" == "rotatelogs - Win32 Release" + + +"$(INTDIR)\rotatelogs.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\rotatelogs.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe" $(SOURCE) + + +!ELSEIF "$(CFG)" == "rotatelogs - Win32 Debug" + + +"$(INTDIR)\rotatelogs.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\rotatelogs.res" /i "../include" /i "../srclib/apr/include" /i "../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="rotatelogs.exe" /d LONG_NAME="Apache rotatelogs command line pipe" $(SOURCE) + + +!ENDIF + +SOURCE=.\rotatelogs.c + +"$(INTDIR)\rotatelogs.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + diff --git a/support/split-logfile.in b/support/split-logfile.in new file mode 100644 index 0000000..e5abfc7 --- /dev/null +++ b/support/split-logfile.in @@ -0,0 +1,69 @@ +#!@perlbin@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# This script will take a combined Web server access +# log file and break its contents into separate files. +# It assumes that the first field of each line is the +# virtual host identity (put there by "%v"), and that +# the logfiles should be named that+".log" in the current +# directory. +# +# The combined log file is read from stdin. Records read +# will be appended to any existing log files. +# +use strict; +use warnings; + +my %log_file = (); + +while (my $log_line = <STDIN>) { + # + # Get the first token from the log record; it's the + # identity of the virtual host to which the record + # applies. + # + my ($vhost) = split (/\s/, $log_line); + # + # Normalize the virtual host name to all lowercase. + # If it's blank, the request was handled by the default + # server, so supply a default name. This shouldn't + # happen, but caution rocks. + # + $vhost = lc ($vhost) || "access"; + # + # if the vhost contains a "/" or "\", it is illegal so just use + # the default log to avoid any security issues due if it is interprted + # as a directory separator. + if ($vhost =~ m#[/\\]#) { $vhost = "access" } + # + # If the log file for this virtual host isn't opened + # yet, do it now. + # + if (! $log_file{$vhost}) { + open $log_file{$vhost}, ">>${vhost}.log" + or die ("Can't open ${vhost}.log"); + } + # + # Strip off the first token (which may be null in the + # case of the default server), and write the edited + # record to the current log file. + # + $log_line =~ s/^\S*\s+//; + print {$log_file{$vhost}} $log_line; +} +exit 0; diff --git a/support/suexec.c b/support/suexec.c new file mode 100644 index 0000000..c2eb0b6 --- /dev/null +++ b/support/suexec.c @@ -0,0 +1,685 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * suexec.c -- "Wrapper" support program for suEXEC behaviour for Apache + * + *********************************************************************** + * + * NOTE! : DO NOT edit this code!!! Unless you know what you are doing, + * editing this code might open up your system in unexpected + * ways to would-be crackers. Every precaution has been taken + * to make this code as safe as possible; alter it at your own + * risk. + * + *********************************************************************** + * + * + */ + +#include "apr.h" +#include "ap_config.h" +#include "suexec.h" + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <string.h> +#include <time.h> +#if APR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#if APR_HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif + +#ifdef HAVE_GRP_H +#include <grp.h> +#endif + +#ifdef AP_LOG_SYSLOG +#include <syslog.h> +#endif + +#if defined(PATH_MAX) +#define AP_MAXPATH PATH_MAX +#elif defined(MAXPATHLEN) +#define AP_MAXPATH MAXPATHLEN +#else +#define AP_MAXPATH 8192 +#endif + +#define AP_ENVBUF 256 + +extern char **environ; + +#ifdef AP_LOG_SYSLOG +/* Syslog support. */ +#if !defined(AP_LOG_FACILITY) && defined(LOG_AUTHPRIV) +#define AP_LOG_FACILITY LOG_AUTHPRIV +#elif !defined(AP_LOG_FACILITY) +#define AP_LOG_FACILITY LOG_AUTH +#endif + +static int log_open; +#else +/* Non-syslog support. */ +static FILE *log = NULL; +#endif + +static const char *const safe_env_lst[] = +{ + /* variable name starts with */ + "HTTP_", + "SSL_", + + /* variable name is */ + "AUTH_TYPE=", + "CONTENT_LENGTH=", + "CONTENT_TYPE=", + "CONTEXT_DOCUMENT_ROOT=", + "CONTEXT_PREFIX=", + "DATE_GMT=", + "DATE_LOCAL=", + "DOCUMENT_ARGS=", + "DOCUMENT_NAME=", + "DOCUMENT_PATH_INFO=", + "DOCUMENT_ROOT=", + "DOCUMENT_URI=", + "GATEWAY_INTERFACE=", + "HTTPS=", + "LAST_MODIFIED=", + "PATH_INFO=", + "PATH_TRANSLATED=", + "QUERY_STRING=", + "QUERY_STRING_UNESCAPED=", + "REMOTE_ADDR=", + "REMOTE_HOST=", + "REMOTE_IDENT=", + "REMOTE_PORT=", + "REMOTE_USER=", + "REDIRECT_ERROR_NOTES=", + "REDIRECT_HANDLER=", + "REDIRECT_QUERY_STRING=", + "REDIRECT_REMOTE_USER=", + "REDIRECT_SCRIPT_FILENAME=", + "REDIRECT_STATUS=", + "REDIRECT_URL=", + "REQUEST_METHOD=", + "REQUEST_SCHEME=", + "REQUEST_URI=", + "SCRIPT_FILENAME=", + "SCRIPT_NAME=", + "SCRIPT_URI=", + "SCRIPT_URL=", + "SERVER_ADDR=", + "SERVER_ADMIN=", + "SERVER_NAME=", + "SERVER_PORT=", + "SERVER_PROTOCOL=", + "SERVER_SIGNATURE=", + "SERVER_SOFTWARE=", + "UNIQUE_ID=", + "USER_NAME=", + "TZ=", + NULL +}; + +static void log_err(const char *fmt,...) + __attribute__((format(printf,1,2))); +static void log_no_err(const char *fmt,...) + __attribute__((format(printf,1,2))); +static void err_output(int is_error, const char *fmt, va_list ap) + __attribute__((format(printf,2,0))); + +static void err_output(int is_error, const char *fmt, va_list ap) +{ +#if defined(AP_LOG_SYSLOG) + if (!log_open) { + openlog("suexec", LOG_PID, AP_LOG_FACILITY); + log_open = 1; + } + + vsyslog(is_error ? LOG_ERR : LOG_INFO, fmt, ap); +#elif defined(AP_LOG_EXEC) + time_t timevar; + struct tm *lt; + + if (!log) { +#if defined(_LARGEFILE64_SOURCE) && HAVE_FOPEN64 + if ((log = fopen64(AP_LOG_EXEC, "a")) == NULL) { +#else + if ((log = fopen(AP_LOG_EXEC, "a")) == NULL) { +#endif + fprintf(stderr, "suexec failure: could not open log file\n"); + perror("fopen"); + exit(1); + } + } + + if (is_error) { + fprintf(stderr, "suexec policy violation: see suexec log for more " + "details\n"); + } + + time(&timevar); + lt = localtime(&timevar); + + fprintf(log, "[%d-%.2d-%.2d %.2d:%.2d:%.2d]: ", + lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, + lt->tm_hour, lt->tm_min, lt->tm_sec); + + vfprintf(log, fmt, ap); + + fflush(log); +#endif /* AP_LOG_EXEC */ + return; +} + +static void log_err(const char *fmt,...) +{ +#ifdef AP_LOG_EXEC + va_list ap; + + va_start(ap, fmt); + err_output(1, fmt, ap); /* 1 == is_error */ + va_end(ap); +#endif /* AP_LOG_EXEC */ + return; +} + +static void log_no_err(const char *fmt,...) +{ +#ifdef AP_LOG_EXEC + va_list ap; + + va_start(ap, fmt); + err_output(0, fmt, ap); /* 0 == !is_error */ + va_end(ap); +#endif /* AP_LOG_EXEC */ + return; +} + +static void clean_env(void) +{ + char **cleanenv; + char **ep; + int cidx = 0; + int idx; + + /* While cleaning the environment, the environment should be clean. + * (e.g. malloc() may get the name of a file for writing debugging info. + * Bad news if MALLOC_DEBUG_FILE is set to /etc/passwd. Sprintf() may be + * susceptible to bad locale settings....) + * (from PR 2790) + */ + char **envp = environ; + char *empty_ptr = NULL; + + environ = &empty_ptr; /* VERY safe environment */ + + if ((cleanenv = (char **) calloc(AP_ENVBUF, sizeof(char *))) == NULL) { + log_err("failed to malloc memory for environment\n"); + exit(123); + } + + cleanenv[cidx] = strdup("PATH=" AP_SAFE_PATH); + if (cleanenv[cidx] == NULL) { + log_err("failed to malloc memory for environment\n"); + exit(124); + } + cidx++; + + for (ep = envp; *ep && cidx < AP_ENVBUF-1; ep++) { + for (idx = 0; safe_env_lst[idx]; idx++) { + if (!strncmp(*ep, safe_env_lst[idx], + strlen(safe_env_lst[idx]))) { + cleanenv[cidx] = *ep; + cidx++; + break; + } + } + } + + cleanenv[cidx] = NULL; + + environ = cleanenv; +} + +int main(int argc, char *argv[]) +{ + int userdir = 0; /* ~userdir flag */ + uid_t uid; /* user information */ + gid_t gid; /* target group placeholder */ + char *target_uname; /* target user name */ + char *target_gname; /* target group name */ + char *target_homedir; /* target home directory */ + char *actual_uname; /* actual user name */ + char *actual_gname; /* actual group name */ + char *cmd; /* command to be executed */ + char cwd[AP_MAXPATH]; /* current working directory */ + char dwd[AP_MAXPATH]; /* docroot working directory */ + struct passwd *pw; /* password entry holder */ + struct group *gr; /* group entry holder */ + struct stat dir_info; /* directory info holder */ + struct stat prg_info; /* program info holder */ + + /* + * Start with a "clean" environment + */ + clean_env(); + + /* + * Check existence/validity of the UID of the user + * running this program. Error out if invalid. + */ + uid = getuid(); + if ((pw = getpwuid(uid)) == NULL) { + log_err("crit: invalid uid: (%lu)\n", (unsigned long)uid); + exit(102); + } + /* + * See if this is a 'how were you compiled' request, and + * comply if so. + */ + if ((argc > 1) + && (! strcmp(argv[1], "-V")) + && ((uid == 0) +#ifdef _OSD_POSIX + /* User name comparisons are case insensitive on BS2000/OSD */ + || (! strcasecmp(AP_HTTPD_USER, pw->pw_name))) +#else /* _OSD_POSIX */ + || (! strcmp(AP_HTTPD_USER, pw->pw_name))) +#endif /* _OSD_POSIX */ + ) { +#ifdef AP_DOC_ROOT + fprintf(stderr, " -D AP_DOC_ROOT=\"%s\"\n", AP_DOC_ROOT); +#endif +#ifdef AP_GID_MIN + fprintf(stderr, " -D AP_GID_MIN=%d\n", AP_GID_MIN); +#endif +#ifdef AP_HTTPD_USER + fprintf(stderr, " -D AP_HTTPD_USER=\"%s\"\n", AP_HTTPD_USER); +#endif +#if defined(AP_LOG_SYSLOG) + fprintf(stderr, " -D AP_LOG_SYSLOG\n"); +#elif defined(AP_LOG_EXEC) + fprintf(stderr, " -D AP_LOG_EXEC=\"%s\"\n", AP_LOG_EXEC); +#endif +#ifdef AP_SAFE_PATH + fprintf(stderr, " -D AP_SAFE_PATH=\"%s\"\n", AP_SAFE_PATH); +#endif +#ifdef AP_SUEXEC_UMASK + fprintf(stderr, " -D AP_SUEXEC_UMASK=%03o\n", AP_SUEXEC_UMASK); +#endif +#ifdef AP_UID_MIN + fprintf(stderr, " -D AP_UID_MIN=%d\n", AP_UID_MIN); +#endif +#ifdef AP_USERDIR_SUFFIX + fprintf(stderr, " -D AP_USERDIR_SUFFIX=\"%s\"\n", AP_USERDIR_SUFFIX); +#endif + exit(0); + } + /* + * If there are a proper number of arguments, set + * all of them to variables. Otherwise, error out. + */ + if (argc < 4) { + log_err("too few arguments\n"); + exit(101); + } + target_uname = argv[1]; + target_gname = argv[2]; + cmd = argv[3]; + + /* + * Check to see if the user running this program + * is the user allowed to do so as defined in + * suexec.h. If not the allowed user, error out. + */ +#ifdef _OSD_POSIX + /* User name comparisons are case insensitive on BS2000/OSD */ + if (strcasecmp(AP_HTTPD_USER, pw->pw_name)) { + log_err("user mismatch (%s instead of %s)\n", pw->pw_name, AP_HTTPD_USER); + exit(103); + } +#else /*_OSD_POSIX*/ + if (strcmp(AP_HTTPD_USER, pw->pw_name)) { + log_err("user mismatch (%s instead of %s)\n", pw->pw_name, AP_HTTPD_USER); + exit(103); + } +#endif /*_OSD_POSIX*/ + + /* + * Check for a leading '/' (absolute path) in the command to be executed, + * or attempts to back up out of the current directory, + * to protect against attacks. If any are + * found, error out. Naughty naughty crackers. + */ + if ((cmd[0] == '/') || (!strncmp(cmd, "../", 3)) + || (strstr(cmd, "/../") != NULL)) { + log_err("invalid command (%s)\n", cmd); + exit(104); + } + + /* + * Check to see if this is a ~userdir request. If + * so, set the flag, and remove the '~' from the + * target username. + */ + if (!strncmp("~", target_uname, 1)) { + target_uname++; + userdir = 1; + } + + /* + * Error out if the target username is invalid. + */ + if (strspn(target_uname, "1234567890") != strlen(target_uname)) { + if ((pw = getpwnam(target_uname)) == NULL) { + log_err("invalid target user name: (%s)\n", target_uname); + exit(105); + } + } + else { + if ((pw = getpwuid(atoi(target_uname))) == NULL) { + log_err("invalid target user id: (%s)\n", target_uname); + exit(121); + } + } + + /* + * Error out if the target group name is invalid. + */ + if (strspn(target_gname, "1234567890") != strlen(target_gname)) { + if ((gr = getgrnam(target_gname)) == NULL) { + log_err("invalid target group name: (%s)\n", target_gname); + exit(106); + } + } + else { + if ((gr = getgrgid(atoi(target_gname))) == NULL) { + log_err("invalid target group id: (%s)\n", target_gname); + exit(106); + } + } + gid = gr->gr_gid; + if ((actual_gname = strdup(gr->gr_name)) == NULL) { + log_err("failed to alloc memory\n"); + exit(125); + } + +#ifdef _OSD_POSIX + /* + * Initialize BS2000 user environment + */ + { + pid_t pid; + int status; + + switch (pid = ufork(target_uname)) { + case -1: /* Error */ + log_err("failed to setup bs2000 environment for user %s: %s\n", + target_uname, strerror(errno)); + exit(150); + case 0: /* Child */ + break; + default: /* Father */ + while (pid != waitpid(pid, &status, 0)) + ; + /* @@@ FIXME: should we deal with STOP signals as well? */ + if (WIFSIGNALED(status)) { + kill (getpid(), WTERMSIG(status)); + } + exit(WEXITSTATUS(status)); + } + } +#endif /*_OSD_POSIX*/ + + /* + * Save these for later since initgroups will hose the struct + */ + uid = pw->pw_uid; + actual_uname = strdup(pw->pw_name); + target_homedir = strdup(pw->pw_dir); + if (actual_uname == NULL || target_homedir == NULL) { + log_err("failed to alloc memory\n"); + exit(126); + } + + /* + * Log the transaction here to be sure we have an open log + * before we setuid(). + */ + log_no_err("uid: (%s/%s) gid: (%s/%s) cmd: %s\n", + target_uname, actual_uname, + target_gname, actual_gname, + cmd); + + /* + * Error out if attempt is made to execute as root or as + * a UID less than AP_UID_MIN. Tsk tsk. + */ + if ((uid == 0) || (uid < AP_UID_MIN)) { + log_err("cannot run as forbidden uid (%lu/%s)\n", (unsigned long)uid, cmd); + exit(107); + } + + /* + * Error out if attempt is made to execute as root group + * or as a GID less than AP_GID_MIN. Tsk tsk. + */ + if ((gid == 0) || (gid < AP_GID_MIN)) { + log_err("cannot run as forbidden gid (%lu/%s)\n", (unsigned long)gid, cmd); + exit(108); + } + + /* + * Change UID/GID here so that the following tests work over NFS. + * + * Initialize the group access list for the target user, + * and setgid() to the target group. If unsuccessful, error out. + */ + if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 0)) { + log_err("failed to setgid/initgroups (%lu: %s): %s\n", + (unsigned long)gid, cmd, strerror(errno)); + exit(109); + } + + /* + * setuid() to the target user. Error out on fail. + */ + if ((setuid(uid)) != 0) { + log_err("failed to setuid (%lu: %s): %s\n", + (unsigned long)uid, cmd, strerror(errno)); + exit(110); + } + + /* + * Get the current working directory, as well as the proper + * document root (dependent upon whether or not it is a + * ~userdir request). Error out if we cannot get either one, + * or if the current working directory is not in the docroot. + * Use chdir()s and getcwd()s to avoid problems with symlinked + * directories. Yuck. + */ + if (getcwd(cwd, AP_MAXPATH) == NULL) { + log_err("cannot get current working directory\n"); + exit(111); + } + + if (userdir) { + if (((chdir(target_homedir)) != 0) || + ((chdir(AP_USERDIR_SUFFIX)) != 0) || + ((getcwd(dwd, AP_MAXPATH)) == NULL) || + ((chdir(cwd)) != 0)) { + log_err("cannot get docroot information (%s)\n", target_homedir); + exit(112); + } + } + else { + if (((chdir(AP_DOC_ROOT)) != 0) || + ((getcwd(dwd, AP_MAXPATH)) == NULL) || + ((chdir(cwd)) != 0)) { + log_err("cannot get docroot information (%s)\n", AP_DOC_ROOT); + exit(113); + } + } + + if ((strncmp(cwd, dwd, strlen(dwd))) != 0) { + log_err("command not in docroot (%s/%s)\n", cwd, cmd); + exit(114); + } + + /* + * Stat the cwd and verify it is a directory, or error out. + */ + if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) { + log_err("cannot stat directory: (%s)\n", cwd); + exit(115); + } + + /* + * Error out if cwd is writable by others. + */ + if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) { + log_err("directory is writable by others: (%s)\n", cwd); + exit(116); + } + + /* + * Error out if we cannot stat the program. + */ + if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) { + log_err("cannot stat program: (%s)\n", cmd); + exit(117); + } + + /* + * Error out if the program is writable by others. + */ + if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) { + log_err("file is writable by others: (%s/%s)\n", cwd, cmd); + exit(118); + } + + /* + * Error out if the file is setuid or setgid. + */ + if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & S_ISGID)) { + log_err("file is either setuid or setgid: (%s/%s)\n", cwd, cmd); + exit(119); + } + + /* + * Error out if the target name/group is different from + * the name/group of the cwd or the program. + */ + if ((uid != dir_info.st_uid) || + (gid != dir_info.st_gid) || + (uid != prg_info.st_uid) || + (gid != prg_info.st_gid)) { + log_err("target uid/gid (%lu/%lu) mismatch " + "with directory (%lu/%lu) or program (%lu/%lu)\n", + (unsigned long)uid, (unsigned long)gid, + (unsigned long)dir_info.st_uid, (unsigned long)dir_info.st_gid, + (unsigned long)prg_info.st_uid, (unsigned long)prg_info.st_gid); + exit(120); + } + /* + * Error out if the program is not executable for the user. + * Otherwise, she won't find any error in the logs except for + * "[error] Premature end of script headers: ..." + */ + if (!(prg_info.st_mode & S_IXUSR)) { + log_err("file has no execute permission: (%s/%s)\n", cwd, cmd); + exit(121); + } + +#ifdef AP_SUEXEC_UMASK + /* + * umask() uses inverse logic; bits are CLEAR for allowed access. + */ + if ((~AP_SUEXEC_UMASK) & 0022) { + log_err("notice: AP_SUEXEC_UMASK of %03o allows " + "write permission to group and/or other\n", AP_SUEXEC_UMASK); + } + umask(AP_SUEXEC_UMASK); +#endif /* AP_SUEXEC_UMASK */ + + /* Be sure to close the log file so the CGI can't mess with it. */ +#ifdef AP_LOG_SYSLOG + if (log_open) { + closelog(); + log_open = 0; + } +#else + if (log != NULL) { +#if APR_HAVE_FCNTL_H + /* + * ask fcntl(2) to set the FD_CLOEXEC flag on the log file, + * so it'll be automagically closed if the exec() call succeeds. + */ + fflush(log); + setbuf(log, NULL); + if ((fcntl(fileno(log), F_SETFD, FD_CLOEXEC) == -1)) { + log_err("error: can't set close-on-exec flag"); + exit(122); + } +#else + /* + * In this case, exec() errors won't be logged because we have already + * dropped privileges and won't be able to reopen the log file. + */ + fclose(log); + log = NULL; +#endif + } +#endif + + /* + * Execute the command, replacing our image with its own. + */ +#ifdef NEED_HASHBANG_EMUL + /* We need the #! emulation when we want to execute scripts */ + { + extern char **environ; + + ap_execve(cmd, &argv[3], environ); + } +#else /*NEED_HASHBANG_EMUL*/ + execv(cmd, &argv[3]); +#endif /*NEED_HASHBANG_EMUL*/ + + /* + * (I can't help myself...sorry.) + * + * Uh oh. Still here. Where's the kaboom? There was supposed to be an + * EARTH-shattering kaboom! + * + * Oh well, log the failure and error out. + */ + log_err("(%d)%s: exec failed (%s)\n", errno, strerror(errno), cmd); + exit(255); +} diff --git a/support/suexec.h b/support/suexec.h new file mode 100644 index 0000000..07bb7bb --- /dev/null +++ b/support/suexec.h @@ -0,0 +1,109 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file suexec.h + * @brief user-definable variables for the suexec wrapper code. + * (See README.configure on how to customize these variables.) + */ + + +#ifndef _SUEXEC_H +#define _SUEXEC_H + +/* + * Include ap_config_layout so we can work out where the default htdocsdir + * and logsdir are. + */ +#include "ap_config_layout.h" + +/* + * HTTPD_USER -- Define as the username under which Apache normally + * runs. This is the only user allowed to execute + * this program. + */ +#ifndef AP_HTTPD_USER +#define AP_HTTPD_USER "www" +#endif + +/* + * UID_MIN -- Define this as the lowest UID allowed to be a target user + * for suEXEC. For most systems, 500 or 100 is common. + */ +#ifndef AP_UID_MIN +#define AP_UID_MIN 100 +#endif + +/* + * GID_MIN -- Define this as the lowest GID allowed to be a target group + * for suEXEC. For most systems, 100 is common. + */ +#ifndef AP_GID_MIN +#define AP_GID_MIN 100 +#endif + +/* + * USERDIR_SUFFIX -- Define to be the subdirectory under users' + * home directories where suEXEC access should + * be allowed. All executables under this directory + * will be executable by suEXEC as the user so + * they should be "safe" programs. If you are + * using a "simple" UserDir directive (ie. one + * without a "*" in it) this should be set to + * the same value. suEXEC will not work properly + * in cases where the UserDir directive points to + * a location that is not the same as the user's + * home directory as referenced in the passwd file. + * + * If you have VirtualHosts with a different + * UserDir for each, you will need to define them to + * all reside in one parent directory; then name that + * parent directory here. IF THIS IS NOT DEFINED + * PROPERLY, ~USERDIR CGI REQUESTS WILL NOT WORK! + * See the suEXEC documentation for more detailed + * information. + */ +#ifndef AP_USERDIR_SUFFIX +#define AP_USERDIR_SUFFIX "public_html" +#endif + +/* + * LOG_EXEC -- Define this as a filename if you want all suEXEC + * transactions and errors logged for auditing and + * debugging purposes. + */ +#ifndef AP_LOG_EXEC +#define AP_LOG_EXEC DEFAULT_EXP_LOGFILEDIR "/suexec_log" /* Need me? */ +#endif + +/* + * DOC_ROOT -- Define as the DocumentRoot set for Apache. This + * will be the only hierarchy (aside from UserDirs) + * that can be used for suEXEC behavior. + */ +#ifndef AP_DOC_ROOT +#define AP_DOC_ROOT DEFAULT_EXP_HTDOCSDIR +#endif + +/* + * SAFE_PATH -- Define a safe PATH environment to pass to CGI executables. + * + */ +#ifndef AP_SAFE_PATH +#define AP_SAFE_PATH "/usr/local/bin:/usr/bin:/bin" +#endif + +#endif /* _SUEXEC_H */ diff --git a/support/win32/ApacheMonitor.c b/support/win32/ApacheMonitor.c new file mode 100644 index 0000000..841b4ab --- /dev/null +++ b/support/win32/ApacheMonitor.c @@ -0,0 +1,1671 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* ==================================================================== + * ApacheMonitor.c Simple program to manage and monitor Apache services. + * + * Contributed by Mladen Turk <mturk mappingsoft.com> + * + * 05 Aug 2001 + * ==================================================================== + */ + +#define _WIN32_WINNT 0x0500 +#ifndef STRICT +#define STRICT +#endif +#ifndef OEMRESOURCE +#define OEMRESOURCE +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#include <windows.h> +#include <windowsx.h> +#include <commctrl.h> +#include <objbase.h> +#include <shlobj.h> +#include <stdlib.h> +#include <stdio.h> +#include <WtsApi32.h> +#include <tchar.h> +#include "ApacheMonitor.h" + +#ifndef AM_STRINGIFY +/** Properly quote a value as a string in the C preprocessor */ +#define AM_STRINGIFY(n) AM_STRINGIFY_HELPER(n) +/** Helper macro for AM_STRINGIFY */ +#define AM_STRINGIFY_HELPER(n) #n +#endif + +#define OS_VERSION_WINNT 2 +#define OS_VERSION_WIN2K 3 + +/* Should be enough */ +#define MAX_APACHE_SERVICES 128 +#define MAX_APACHE_COMPUTERS 32 + +#define WM_TRAYMESSAGE (WM_APP+1) +#define WM_UPDATEMESSAGE (WM_USER+1) +#define WM_MANAGEMESSAGE (WM_USER+2) +#define WM_TIMER_REFRESH 10 +#define WM_TIMER_RESCAN 11 +#define SERVICE_APACHE_RESTART 128 +#define XBITMAP 16 +#define YBITMAP 16 +#define MAX_LOADSTRING 100 +#define REFRESH_TIME 2000 /* service refresh time (ms) */ +#define RESCAN_TIME 20000 /* registry rescan time (ms) */ + +typedef struct _st_APACHE_SERVICE +{ + LPTSTR szServiceName; + LPTSTR szDisplayName; + LPTSTR szDescription; + LPTSTR szImagePath; + LPTSTR szComputerName; + DWORD dwPid; +} ST_APACHE_SERVICE; + +typedef struct _st_MONITORED_COMPUTERS +{ + LPTSTR szComputerName; + HKEY hRegistry; +} ST_MONITORED_COMP; + +/* Global variables */ +HINSTANCE g_hInstance = NULL; +TCHAR *g_szTitle; /* The title bar text */ +TCHAR *g_szWindowClass; /* Window Class Name */ +HICON g_icoStop; +HICON g_icoRun; +UINT g_bUiTaskbarCreated; +DWORD g_dwOSVersion; +BOOL g_bDlgServiceOn = FALSE; +BOOL g_bConsoleRun = FALSE; +ST_APACHE_SERVICE g_stServices[MAX_APACHE_SERVICES]; +ST_MONITORED_COMP g_stComputers[MAX_APACHE_COMPUTERS]; + +HBITMAP g_hBmpStart, g_hBmpStop; +HBITMAP g_hBmpPicture, g_hBmpOld; +BOOL g_bRescanServices; +HWND g_hwndServiceDlg; +HWND g_hwndMain; +HWND g_hwndStdoutList; +HWND g_hwndConnectDlg; +HCURSOR g_hCursorHourglass; +HCURSOR g_hCursorArrow; + +LANGID g_LangID; +CRITICAL_SECTION g_stcSection; +LPTSTR g_szLocalHost; + +/* locale language support */ +static TCHAR *g_lpMsg[IDS_MSG_LAST - IDS_MSG_FIRST + 1]; + + +void am_ClearServicesSt() +{ + int i; + for (i = 0; i < MAX_APACHE_SERVICES; i++) + { + if (g_stServices[i].szServiceName) { + free(g_stServices[i].szServiceName); + } + if (g_stServices[i].szDisplayName) { + free(g_stServices[i].szDisplayName); + } + if (g_stServices[i].szDescription) { + free(g_stServices[i].szDescription); + } + if (g_stServices[i].szImagePath) { + free(g_stServices[i].szImagePath); + } + if (g_stServices[i].szComputerName) { + free(g_stServices[i].szComputerName); + } + + } + memset(g_stServices, 0, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES); + +} + + +void am_ClearComputersSt() +{ + int i; + for (i = 0; i < MAX_APACHE_COMPUTERS; i++) { + if (g_stComputers[i].szComputerName) { + free(g_stComputers[i].szComputerName); + RegCloseKey(g_stComputers[i].hRegistry); + } + } + memset(g_stComputers, 0, sizeof(ST_MONITORED_COMP) * MAX_APACHE_COMPUTERS); + +} + + +BOOL am_IsComputerConnected(LPTSTR szComputerName) +{ + int i = 0; + while (g_stComputers[i].szComputerName != NULL) { + if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) { + return TRUE; + } + ++i; + } + return FALSE; +} + + +void am_DisconnectComputer(LPTSTR szComputerName) +{ + int i = 0, j; + while (g_stComputers[i].szComputerName != NULL) { + if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) { + break; + } + ++i; + } + if (g_stComputers[i].szComputerName != NULL) { + free(g_stComputers[i].szComputerName); + RegCloseKey(g_stComputers[i].hRegistry); + for (j = i; j < MAX_APACHE_COMPUTERS - 1; j++) { + g_stComputers[j].szComputerName= g_stComputers[j+1].szComputerName; + g_stComputers[j].hRegistry = g_stComputers[j+1].hRegistry; + } + g_stComputers[j].szComputerName = NULL; + g_stComputers[j].hRegistry = NULL; + } +} + + +void ErrorMessage(LPCTSTR szError, BOOL bFatal) +{ + LPVOID lpMsgBuf = NULL; + if (szError) { + MessageBox(NULL, szError, g_lpMsg[IDS_MSG_ERROR - IDS_MSG_FIRST], + MB_OK | (bFatal ? MB_ICONERROR : MB_ICONEXCLAMATION)); + } + else { + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), g_LangID, + (LPTSTR) &lpMsgBuf, 0, NULL); + MessageBox(NULL, (LPCTSTR)lpMsgBuf, + g_lpMsg[IDS_MSG_ERROR - IDS_MSG_FIRST], + MB_OK | (bFatal ? MB_ICONERROR : MB_ICONEXCLAMATION)); + LocalFree(lpMsgBuf); + } + if (bFatal) { + PostQuitMessage(0); + } +} + + +int am_RespawnAsUserAdmin(HWND hwnd, DWORD op, LPCTSTR szService, + LPCTSTR szComputerName) +{ + TCHAR args[MAX_PATH + MAX_COMPUTERNAME_LENGTH + 12]; + + if (g_dwOSVersion < OS_VERSION_WIN2K) { + ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST], FALSE); + return 0; + } + + _sntprintf(args, sizeof(args) / sizeof(TCHAR), + _T("%d \"%s\" \"%s\""), op, szService, + szComputerName ? szComputerName : _T("")); + if (!ShellExecute(hwnd, _T("runas"), __targv[0], args, NULL, SW_NORMAL)) { + ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST], + FALSE); + return 0; + } + + return 1; +} + + +BOOL am_ConnectComputer(LPTSTR szComputerName) +{ + int i = 0; + HKEY hKeyRemote; + TCHAR szTmp[MAX_PATH]; + + while (g_stComputers[i].szComputerName != NULL) { + if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) { + return FALSE; + } + ++i; + } + if (i > MAX_APACHE_COMPUTERS - 1) { + return FALSE; + } + if (RegConnectRegistry(szComputerName, HKEY_LOCAL_MACHINE, &hKeyRemote) + != ERROR_SUCCESS) { + _sntprintf(szTmp, sizeof(szTmp) / sizeof(TCHAR), + g_lpMsg[IDS_MSG_ECONNECT - IDS_MSG_FIRST], + szComputerName); + ErrorMessage(szTmp, FALSE); + return FALSE; + } + else { + g_stComputers[i].szComputerName = _tcsdup(szComputerName); + g_stComputers[i].hRegistry = hKeyRemote; + return TRUE; + } +} + + +LPTSTR GetStringRes(int id) +{ + static TCHAR buffer[MAX_PATH]; + + buffer[0] = 0; + LoadString(GetModuleHandle(NULL), id, buffer, MAX_PATH); + return buffer; +} + + +BOOL GetSystemOSVersion(LPDWORD dwVersion) +{ + OSVERSIONINFO osvi; + /* + Try calling GetVersionEx using the OSVERSIONINFOEX structure. + If that fails, try using the OSVERSIONINFO structure. + */ + memset(&osvi, 0, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + if (!GetVersionEx(&osvi)) { + return FALSE; + } + + switch (osvi.dwPlatformId) + { + case VER_PLATFORM_WIN32_NT: + if (osvi.dwMajorVersion >= 5) + *dwVersion = OS_VERSION_WIN2K; + else + *dwVersion = OS_VERSION_WINNT; + break; + + case VER_PLATFORM_WIN32_WINDOWS: + case VER_PLATFORM_WIN32s: + default: + *dwVersion = 0; + return FALSE; + } + return TRUE; +} + + +static VOID ShowNotifyIcon(HWND hWnd, DWORD dwMessage) +{ + NOTIFYICONDATA nid; + int i = 0, n = 0; + + memset(&nid, 0, sizeof(nid)); + nid.cbSize = sizeof(NOTIFYICONDATA); + nid.hWnd = hWnd; + nid.uID = 0xFF; + nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + nid.uCallbackMessage = WM_TRAYMESSAGE; + + while (g_stServices[i].szServiceName != NULL) + { + if (g_stServices[i].dwPid != 0) { + ++n; + } + ++i; + } + if (dwMessage != NIM_DELETE) + { + if (n) { + nid.hIcon = g_icoRun; + } + else { + nid.hIcon = g_icoStop; + } + } + else { + nid.hIcon = NULL; + } + if (n == i && n > 0) { + _tcscpy(nid.szTip, g_lpMsg[IDS_MSG_RUNNINGALL - IDS_MSG_FIRST]); + } + else if (n) { + _sntprintf(nid.szTip, sizeof(nid.szTip) / sizeof(TCHAR), + g_lpMsg[IDS_MSG_RUNNING - IDS_MSG_FIRST], n, i); + } + else if (i) { + _sntprintf(nid.szTip, sizeof(nid.szTip) / sizeof(TCHAR), + g_lpMsg[IDS_MSG_RUNNINGNONE - IDS_MSG_FIRST], i); + } + else { + _tcscpy(nid.szTip, g_lpMsg[IDS_MSG_NOSERVICES - IDS_MSG_FIRST]); + } + Shell_NotifyIcon(dwMessage, &nid); +} + + +void appendMenuItem(HMENU hMenu, UINT uMenuId, LPTSTR szName, + BOOL fDefault, BOOL fEnabled) +{ + MENUITEMINFO mii; + + memset(&mii, 0, sizeof(MENUITEMINFO)); + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; + if (_tcslen(szName)) + { + mii.fType = MFT_STRING; + mii.wID = uMenuId; + if (fDefault) { + mii.fState = MFS_DEFAULT; + } + if (!fEnabled) { + mii.fState |= MFS_DISABLED; + } + mii.dwTypeData = szName; + } + else { + mii.fType = MFT_SEPARATOR; + } + InsertMenuItem(hMenu, uMenuId, FALSE, &mii); +} + + +void appendServiceMenu(HMENU hMenu, UINT uMenuId, + LPTSTR szServiceName, BOOL fRunning) +{ + MENUITEMINFO mii; + HMENU smh; + + smh = CreatePopupMenu(); + + appendMenuItem(smh, IDM_SM_START + uMenuId, + g_lpMsg[IDS_MSG_SSTART - IDS_MSG_FIRST], FALSE, !fRunning); + appendMenuItem(smh, IDM_SM_STOP + uMenuId, + g_lpMsg[IDS_MSG_SSTOP - IDS_MSG_FIRST], FALSE, fRunning); + appendMenuItem(smh, IDM_SM_RESTART + uMenuId, + g_lpMsg[IDS_MSG_SRESTART - IDS_MSG_FIRST], FALSE, fRunning); + + memset(&mii, 0, sizeof(MENUITEMINFO)); + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU + | MIIM_CHECKMARKS; + mii.fType = MFT_STRING; + mii.wID = uMenuId; + mii.hbmpChecked = g_hBmpStart; + mii.hbmpUnchecked = g_hBmpStop; + mii.dwTypeData = szServiceName; + mii.hSubMenu = smh; + mii.fState = fRunning ? MFS_CHECKED : MFS_UNCHECKED; + InsertMenuItem(hMenu, IDM_SM_SERVICE + uMenuId, FALSE, &mii); +} + + +void ShowTryPopupMenu(HWND hWnd) +{ + /* create popup menu */ + HMENU hMenu = CreatePopupMenu(); + POINT pt; + + if (hMenu) + { + appendMenuItem(hMenu, IDM_RESTORE, + g_lpMsg[IDS_MSG_MNUSHOW - IDS_MSG_FIRST], + TRUE, TRUE); + appendMenuItem(hMenu, IDC_SMANAGER, + g_lpMsg[IDS_MSG_MNUSERVICES - IDS_MSG_FIRST], + FALSE, TRUE); + appendMenuItem(hMenu, 0, _T(""), FALSE, TRUE); + appendMenuItem(hMenu, IDM_EXIT, + g_lpMsg[IDS_MSG_MNUEXIT - IDS_MSG_FIRST], + FALSE, TRUE); + + if (!SetForegroundWindow(hWnd)) { + SetForegroundWindow(NULL); + } + GetCursorPos(&pt); + TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON, + pt.x, pt.y, 0, hWnd, NULL); + DestroyMenu(hMenu); + } +} + + +void ShowTryServicesMenu(HWND hWnd) +{ + /* create services list popup menu and submenus */ + HMENU hMenu = CreatePopupMenu(); + POINT pt; + int i = 0; + + if (hMenu) + { + while (g_stServices[i].szServiceName != NULL) + { + appendServiceMenu(hMenu, i, g_stServices[i].szDisplayName, + g_stServices[i].dwPid != 0); + ++i; + } + if (i) + { + if (!SetForegroundWindow(hWnd)) { + SetForegroundWindow(NULL); + } + GetCursorPos(&pt); + TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON, + pt.x, pt.y, 0, hWnd, NULL); + DestroyMenu(hMenu); + } + } +} + + +BOOL CenterWindow(HWND hwndChild) +{ + RECT rChild, rWorkArea; + int wChild, hChild; + int xNew, yNew; + BOOL bResult; + + /* Get the Height and Width of the child window */ + GetWindowRect(hwndChild, &rChild); + wChild = rChild.right - rChild.left; + hChild = rChild.bottom - rChild.top; + + /* Get the limits of the 'workarea' */ + bResult = SystemParametersInfo(SPI_GETWORKAREA, sizeof(RECT), + &rWorkArea, 0); + if (!bResult) { + rWorkArea.left = rWorkArea.top = 0; + rWorkArea.right = GetSystemMetrics(SM_CXSCREEN); + rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN); + } + + /* Calculate new X and Y position*/ + xNew = (rWorkArea.right - wChild) / 2; + yNew = (rWorkArea.bottom - hChild) / 2; + return SetWindowPos(hwndChild, HWND_TOP, xNew, yNew, 0, 0, + SWP_NOSIZE | SWP_SHOWWINDOW); +} + + +static void addListBoxItem(HWND hDlg, LPTSTR lpStr, HBITMAP hBmp) +{ + LRESULT nItem; + + nItem = SendMessage(hDlg, LB_ADDSTRING, 0, (LPARAM)lpStr); + SendMessage(hDlg, LB_SETITEMDATA, nItem, (LPARAM)hBmp); +} + + +static void addListBoxString(HWND hListBox, LPTSTR lpStr) +{ + static int nItems = 0; + if (!g_bDlgServiceOn) { + return; + } + ++nItems; + if (nItems > MAX_LOADSTRING) + { + SendMessage(hListBox, LB_RESETCONTENT, 0, 0); + nItems = 1; + } + ListBox_SetCurSel(hListBox, + ListBox_AddString(hListBox, lpStr)); + +} + + +BOOL ApacheManageService(LPCTSTR szServiceName, LPCTSTR szImagePath, + LPTSTR szComputerName, DWORD dwCommand) +{ + TCHAR szMsg[MAX_PATH]; + BOOL retValue; + SC_HANDLE schService; + SC_HANDLE schSCManager; + SERVICE_STATUS schSStatus; + int ticks; + + schSCManager = OpenSCManager(szComputerName, NULL, + SC_MANAGER_CONNECT); + if (!schSCManager) { + ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST], + FALSE); + return FALSE; + } + + schService = OpenService(schSCManager, szServiceName, + SERVICE_QUERY_STATUS | SERVICE_START | + SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL); + if (schService == NULL) + { + /* Avoid recursion of ImagePath NULL (from this Respawn) */ + if (szImagePath) { + am_RespawnAsUserAdmin(g_hwndMain, dwCommand, + szServiceName, szComputerName); + } + else { + ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST], + FALSE); + } + CloseServiceHandle(schSCManager); + return FALSE; + } + else + { + retValue = FALSE; + g_bConsoleRun = TRUE; + SetCursor(g_hCursorHourglass); + switch (dwCommand) + { + case SERVICE_CONTROL_STOP: + _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), + g_lpMsg[IDS_MSG_SRVSTOP - IDS_MSG_FIRST], + szServiceName); + addListBoxString(g_hwndStdoutList, szMsg); + if (ControlService(schService, SERVICE_CONTROL_STOP, + &schSStatus)) { + Sleep(1000); + while (QueryServiceStatus(schService, &schSStatus)) + { + if (schSStatus.dwCurrentState == SERVICE_STOP_PENDING) + { + Sleep(1000); + } + else { + break; + } + } + } + if (QueryServiceStatus(schService, &schSStatus)) + { + if (schSStatus.dwCurrentState == SERVICE_STOPPED) + { + retValue = TRUE; + _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), + g_lpMsg[IDS_MSG_SRVSTOPPED - IDS_MSG_FIRST], + szServiceName); + addListBoxString(g_hwndStdoutList, szMsg); + } + } + break; + + case SERVICE_CONTROL_CONTINUE: + _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), + g_lpMsg[IDS_MSG_SRVSTART - IDS_MSG_FIRST], + szServiceName); + addListBoxString(g_hwndStdoutList, szMsg); + + if (StartService(schService, 0, NULL)) + { + Sleep(1000); + while (QueryServiceStatus(schService, &schSStatus)) + { + if (schSStatus.dwCurrentState == SERVICE_START_PENDING) + { + Sleep(1000); + } + else { + break; + } + } + } + if (QueryServiceStatus(schService, &schSStatus)) + { + if (schSStatus.dwCurrentState == SERVICE_RUNNING) + { + retValue = TRUE; + _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), + g_lpMsg[IDS_MSG_SRVSTARTED - IDS_MSG_FIRST], + szServiceName); + addListBoxString(g_hwndStdoutList, szMsg); + } + } + break; + + case SERVICE_APACHE_RESTART: + _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), + g_lpMsg[IDS_MSG_SRVRESTART - IDS_MSG_FIRST], + szServiceName); + addListBoxString(g_hwndStdoutList, szMsg); + if (ControlService(schService, SERVICE_APACHE_RESTART, + &schSStatus)) + { + ticks = 60; + while (schSStatus.dwCurrentState == SERVICE_START_PENDING) + { + Sleep(1000); + if (!QueryServiceStatus(schService, &schSStatus)) + { + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + g_bConsoleRun = FALSE; + SetCursor(g_hCursorArrow); + return FALSE; + } + if (!--ticks) { + break; + } + } + } + if (schSStatus.dwCurrentState == SERVICE_RUNNING) + { + retValue = TRUE; + _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), + g_lpMsg[IDS_MSG_SRVRESTARTED - IDS_MSG_FIRST], + szServiceName); + addListBoxString(g_hwndStdoutList, szMsg); + } + break; + } + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + if (!retValue) { + ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST], + FALSE); + } + g_bConsoleRun = FALSE; + SetCursor(g_hCursorArrow); + return retValue; + } + return FALSE; +} + + +BOOL IsServiceRunning(LPCTSTR szServiceName, LPCTSTR szComputerName, + LPDWORD lpdwPid) +{ + DWORD dwPid; + SC_HANDLE schService; + SC_HANDLE schSCManager; + SERVICE_STATUS schSStatus; + + dwPid = 0; + schSCManager = OpenSCManager(szComputerName, NULL, + SC_MANAGER_CONNECT); + if (!schSCManager) { + return FALSE; + } + + schService = OpenService(schSCManager, szServiceName, + SERVICE_QUERY_STATUS); + if (schService != NULL) + { + if (QueryServiceStatus(schService, &schSStatus)) + { + dwPid = schSStatus.dwCurrentState; + if (lpdwPid) { + *lpdwPid = 1; + } + } + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return dwPid == SERVICE_RUNNING ? TRUE : FALSE; + } + else { + g_bRescanServices = TRUE; + } + CloseServiceHandle(schSCManager); + return FALSE; +} + + +BOOL FindRunningServices(void) +{ + int i = 0; + DWORD dwPid; + BOOL rv = FALSE; + while (g_stServices[i].szServiceName != NULL) + { + if (!IsServiceRunning(g_stServices[i].szServiceName, + g_stServices[i].szComputerName, &dwPid)) { + dwPid = 0; + } + if (g_stServices[i].dwPid != dwPid) { + rv = TRUE; + } + g_stServices[i].dwPid = dwPid; + ++i; + } + return rv; +} + + +BOOL GetApacheServicesStatus() +{ + TCHAR szKey[MAX_PATH]; + TCHAR achKey[MAX_PATH]; + TCHAR szImagePath[MAX_PATH]; + TCHAR szBuf[MAX_PATH]; + TCHAR szTmp[MAX_PATH]; + HKEY hKey, hSubKey, hKeyRemote; + DWORD retCode, rv, dwKeyType; + DWORD dwBufLen = MAX_PATH; + int i, stPos = 0; + int computers = 0; + + g_bRescanServices = FALSE; + + am_ClearServicesSt(); + while (g_stComputers[computers].szComputerName != NULL) { + hKeyRemote = g_stComputers[computers].hRegistry; + retCode = RegOpenKeyEx(hKeyRemote, + _T("System\\CurrentControlSet\\Services\\"), + 0, KEY_READ, &hKey); + if (retCode != ERROR_SUCCESS) + { + ErrorMessage(NULL, FALSE); + return FALSE; + } + for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++) + { + retCode = RegEnumKey(hKey, i, achKey, MAX_PATH); + if (retCode == ERROR_SUCCESS) + { + _tcscpy(szKey, _T("System\\CurrentControlSet\\Services\\")); + _tcscat(szKey, achKey); + + if (RegOpenKeyEx(hKeyRemote, szKey, 0, + KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) + { + dwBufLen = MAX_PATH; + rv = RegQueryValueEx(hSubKey, _T("ImagePath"), NULL, + &dwKeyType, (LPBYTE)szImagePath, &dwBufLen); + + if (rv == ERROR_SUCCESS + && (dwKeyType == REG_SZ + || dwKeyType == REG_EXPAND_SZ) + && dwBufLen) + { + _tcscpy(szBuf, szImagePath); + CharLower(szBuf); + /* the service name could be httpd*.exe or Apache*.exe */ + if (((_tcsstr(szBuf, _T("\\apache")) != NULL) + || (_tcsstr(szBuf, _T("\\httpd")) != NULL)) + && _tcsstr(szBuf, _T(".exe")) + && (_tcsstr(szBuf, _T("--ntservice")) != NULL + || _tcsstr(szBuf, _T("-k ")) != NULL)) + { + g_stServices[stPos].szServiceName = _tcsdup(achKey); + g_stServices[stPos].szImagePath = _tcsdup(szImagePath); + g_stServices[stPos].szComputerName = + _tcsdup(g_stComputers[computers].szComputerName); + dwBufLen = MAX_PATH; + if (RegQueryValueEx(hSubKey, _T("Description"), NULL, + &dwKeyType, (LPBYTE)szBuf, &dwBufLen) + == ERROR_SUCCESS) { + g_stServices[stPos].szDescription = _tcsdup(szBuf); + } + dwBufLen = MAX_PATH; + if (RegQueryValueEx(hSubKey, _T("DisplayName"), NULL, + &dwKeyType, (LPBYTE)szBuf, &dwBufLen) + == ERROR_SUCCESS) + { + if (_tcscmp(g_stComputers[computers] + .szComputerName, g_szLocalHost) != 0) + { + _tcscpy(szTmp, g_stComputers[computers] + .szComputerName + 2); + _tcscat(szTmp, _T("@")); + _tcscat(szTmp, szBuf); + } + else { + _tcscpy(szTmp, szBuf); + } + g_stServices[stPos].szDisplayName = _tcsdup(szTmp); + + } + ++stPos; + if (stPos >= MAX_APACHE_SERVICES) { + retCode = !ERROR_SUCCESS; + } + } + } + RegCloseKey(hSubKey); + } + } + } + ++computers; + RegCloseKey(hKey); + } + FindRunningServices(); + return TRUE; +} + + +LRESULT CALLBACK ConnectDlgProc(HWND hDlg, UINT message, + WPARAM wParam, LPARAM lParam) +{ + TCHAR szCmp[MAX_COMPUTERNAME_LENGTH+4]; + switch (message) + { + case WM_INITDIALOG: + ShowWindow(hDlg, SW_HIDE); + g_hwndConnectDlg = hDlg; + CenterWindow(hDlg); + ShowWindow(hDlg, SW_SHOW); + SetFocus(GetDlgItem(hDlg, IDC_COMPUTER)); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + memset(szCmp, 0, sizeof(szCmp)); + _tcscpy(szCmp, _T("\\\\")); + SendMessage(GetDlgItem(hDlg, IDC_COMPUTER), WM_GETTEXT, + (WPARAM) MAX_COMPUTERNAME_LENGTH, + (LPARAM) szCmp+2); + + _tcsupr(szCmp); + if (_tcslen(szCmp) < 3) { + EndDialog(hDlg, TRUE); + return TRUE; + } + am_ConnectComputer(szCmp); + SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0); + + case IDCANCEL: + EndDialog(hDlg, TRUE); + return TRUE; + + case IDC_LBROWSE: + { + BROWSEINFO bi; + ITEMIDLIST *il; + LPMALLOC pMalloc; + memset(&bi, 0, sizeof(BROWSEINFO)); + SHGetSpecialFolderLocation(hDlg, CSIDL_NETWORK, &il); + + bi.lpszTitle = _T("ApacheMonitor :\nSelect Network Computer!"); + bi.pszDisplayName = szCmp; + bi.hwndOwner = hDlg; + bi.ulFlags = BIF_BROWSEFORCOMPUTER; + bi.lpfn = NULL; + bi.lParam = 0; + bi.iImage = 0; + bi.pidlRoot = il; + + if (SHBrowseForFolder(&bi) != NULL) { + SendMessage(GetDlgItem(hDlg, IDC_COMPUTER), + WM_SETTEXT, + (WPARAM) NULL, (LPARAM) szCmp); + } + if (SUCCEEDED(SHGetMalloc(&pMalloc))) { + pMalloc->lpVtbl->Free(pMalloc, il); + pMalloc->lpVtbl->Release(pMalloc); + } + return TRUE; + } + } + break; + + case WM_QUIT: + case WM_CLOSE: + EndDialog(hDlg, TRUE); + return TRUE; + + default: + return FALSE; + } + return FALSE; + +} + + +LRESULT CALLBACK ServiceDlgProc(HWND hDlg, UINT message, + WPARAM wParam, LPARAM lParam) +{ + TCHAR szBuf[MAX_PATH]; + HWND hListBox; + static HWND hStatusBar; + TEXTMETRIC tm; + int i, y; + HDC hdcMem; + RECT rcBitmap; + LRESULT nItem; + LPMEASUREITEMSTRUCT lpmis; + LPDRAWITEMSTRUCT lpdis; + + memset(szBuf, 0, sizeof(szBuf)); + switch (message) + { + case WM_INITDIALOG: + ShowWindow(hDlg, SW_HIDE); + g_hwndServiceDlg = hDlg; + SetWindowText(hDlg, g_szTitle); + Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE); + SetWindowText(GetDlgItem(hDlg, IDC_SSTART), + g_lpMsg[IDS_MSG_SSTART - IDS_MSG_FIRST]); + SetWindowText(GetDlgItem(hDlg, IDC_SSTOP), + g_lpMsg[IDS_MSG_SSTOP - IDS_MSG_FIRST]); + SetWindowText(GetDlgItem(hDlg, IDC_SRESTART), + g_lpMsg[IDS_MSG_SRESTART - IDS_MSG_FIRST]); + SetWindowText(GetDlgItem(hDlg, IDC_SMANAGER), + g_lpMsg[IDS_MSG_SERVICES - IDS_MSG_FIRST]); + SetWindowText(GetDlgItem(hDlg, IDC_SCONNECT), + g_lpMsg[IDS_MSG_CONNECT - IDS_MSG_FIRST]); + SetWindowText(GetDlgItem(hDlg, IDCANCEL), + g_lpMsg[IDS_MSG_OK - IDS_MSG_FIRST]); + hListBox = GetDlgItem(hDlg, IDL_SERVICES); + g_hwndStdoutList = GetDlgItem(hDlg, IDL_STDOUT); + hStatusBar = CreateStatusWindow(0x0800 /* SBT_TOOLTIPS */ + | WS_CHILD | WS_VISIBLE, + _T(""), hDlg, IDC_STATBAR); + if (GetApacheServicesStatus()) + { + i = 0; + while (g_stServices[i].szServiceName != NULL) + { + addListBoxItem(hListBox, g_stServices[i].szDisplayName, + g_stServices[i].dwPid == 0 ? g_hBmpStop + : g_hBmpStart); + ++i; + } + } + CenterWindow(hDlg); + ShowWindow(hDlg, SW_SHOW); + SetFocus(hListBox); + SendMessage(hListBox, LB_SETCURSEL, 0, 0); + return TRUE; + break; + + case WM_MANAGEMESSAGE: + ApacheManageService(g_stServices[LOWORD(wParam)].szServiceName, + g_stServices[LOWORD(wParam)].szImagePath, + g_stServices[LOWORD(wParam)].szComputerName, + LOWORD(lParam)); + + return TRUE; + break; + + case WM_UPDATEMESSAGE: + hListBox = GetDlgItem(hDlg, IDL_SERVICES); + SendMessage(hListBox, LB_RESETCONTENT, 0, 0); + SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)_T("")); + Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE); + i = 0; + while (g_stServices[i].szServiceName != NULL) + { + addListBoxItem(hListBox, g_stServices[i].szDisplayName, + g_stServices[i].dwPid == 0 ? g_hBmpStop : g_hBmpStart); + ++i; + } + SendMessage(hListBox, LB_SETCURSEL, 0, 0); + /* Dirty hack to bring the window to the foreground */ + SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW); + SetWindowPos(hDlg, HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW); + SetFocus(hListBox); + return TRUE; + break; + + case WM_MEASUREITEM: + lpmis = (LPMEASUREITEMSTRUCT) lParam; + lpmis->itemHeight = YBITMAP; + return TRUE; + + case WM_SETCURSOR: + if (g_bConsoleRun) { + SetCursor(g_hCursorHourglass); + } + else { + SetCursor(g_hCursorArrow); + } + return TRUE; + + case WM_DRAWITEM: + lpdis = (LPDRAWITEMSTRUCT) lParam; + if (lpdis->itemID == -1) { + break; + } + switch (lpdis->itemAction) + { + case ODA_FOCUS: + case ODA_SELECT: + case ODA_DRAWENTIRE: + g_hBmpPicture = (HBITMAP)SendMessage(lpdis->hwndItem, + LB_GETITEMDATA, + lpdis->itemID, (LPARAM) 0); + + hdcMem = CreateCompatibleDC(lpdis->hDC); + g_hBmpOld = SelectObject(hdcMem, g_hBmpPicture); + + BitBlt(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, + lpdis->rcItem.right - lpdis->rcItem.left, + lpdis->rcItem.bottom - lpdis->rcItem.top, + hdcMem, 0, 0, SRCCOPY); + SendMessage(lpdis->hwndItem, LB_GETTEXT, + lpdis->itemID, (LPARAM) szBuf); + + GetTextMetrics(lpdis->hDC, &tm); + y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2; + + SelectObject(hdcMem, g_hBmpOld); + DeleteDC(hdcMem); + + rcBitmap.left = lpdis->rcItem.left + XBITMAP + 2; + rcBitmap.top = lpdis->rcItem.top; + rcBitmap.right = lpdis->rcItem.right; + rcBitmap.bottom = lpdis->rcItem.top + YBITMAP; + + if (lpdis->itemState & ODS_SELECTED) + { + if (g_hBmpPicture == g_hBmpStop) + { + Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE); + Button_SetStyle(GetDlgItem(hDlg, IDC_SSTART), BS_DEFPUSHBUTTON, TRUE); + Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE); + } + else if (g_hBmpPicture == g_hBmpStart) + { + Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE); + Button_SetStyle(GetDlgItem(hDlg, IDC_SSTOP), BS_DEFPUSHBUTTON, TRUE); + Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE); + } + else { + Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE); + } + if (_tcscmp(g_stServices[lpdis->itemID].szComputerName, + g_szLocalHost) == 0) { + Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE); + } + else { + Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), TRUE); + } + + if (g_stServices[lpdis->itemID].szDescription) { + SendMessage(hStatusBar, SB_SETTEXT, 0, + (LPARAM)g_stServices[lpdis->itemID].szDescription); + } + else { + SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)_T("")); + } + if (lpdis->itemState & ODS_FOCUS) { + SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT)); + FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_HIGHLIGHT+1)); + } + else { + SetTextColor(lpdis->hDC, GetSysColor(COLOR_INACTIVECAPTIONTEXT)); + SetBkColor(lpdis->hDC, GetSysColor(COLOR_INACTIVECAPTION)); + FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_INACTIVECAPTION+1)); + } + } + else + { + SetTextColor(lpdis->hDC, GetSysColor(COLOR_MENUTEXT)); + SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW)); + FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_WINDOW+1)); + } + TextOut(lpdis->hDC, XBITMAP + 6, y, szBuf, (int)_tcslen(szBuf)); + break; + } + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDL_SERVICES: + switch (HIWORD(wParam)) + { + case LBN_DBLCLK: + /* if started then stop, if stopped then start */ + hListBox = GetDlgItem(hDlg, IDL_SERVICES); + nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); + if (nItem != LB_ERR) + { + g_hBmpPicture = (HBITMAP)SendMessage(hListBox, + LB_GETITEMDATA, + nItem, (LPARAM) 0); + if (g_hBmpPicture == g_hBmpStop) { + SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, + SERVICE_CONTROL_CONTINUE); + } + else { + SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, + SERVICE_CONTROL_STOP); + } + + } + return TRUE; + } + break; + + case IDCANCEL: + EndDialog(hDlg, TRUE); + return TRUE; + + case IDC_SSTART: + Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE); + hListBox = GetDlgItem(hDlg, IDL_SERVICES); + nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); + if (nItem != LB_ERR) { + SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, + SERVICE_CONTROL_CONTINUE); + } + Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE); + return TRUE; + + case IDC_SSTOP: + Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE); + hListBox = GetDlgItem(hDlg, IDL_SERVICES); + nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); + if (nItem != LB_ERR) { + SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, + SERVICE_CONTROL_STOP); + } + Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE); + return TRUE; + + case IDC_SRESTART: + Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE); + hListBox = GetDlgItem(hDlg, IDL_SERVICES); + nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); + if (nItem != LB_ERR) { + SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, + SERVICE_APACHE_RESTART); + } + Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE); + return TRUE; + + case IDC_SMANAGER: + if (g_dwOSVersion >= OS_VERSION_WIN2K) { + ShellExecute(hDlg, _T("open"), _T("services.msc"), _T("/s"), + NULL, SW_NORMAL); + } + else { + WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL); + } + return TRUE; + + case IDC_SCONNECT: + DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGCONNECT), + hDlg, (DLGPROC)ConnectDlgProc); + return TRUE; + + case IDC_SDISCONN: + hListBox = GetDlgItem(hDlg, IDL_SERVICES); + nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); + if (nItem != LB_ERR) { + am_DisconnectComputer(g_stServices[nItem].szComputerName); + SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0); + } + return TRUE; + } + break; + + case WM_SIZE: + switch (LOWORD(wParam)) + { + case SIZE_MINIMIZED: + EndDialog(hDlg, TRUE); + return TRUE; + break; + } + break; + + case WM_QUIT: + case WM_CLOSE: + EndDialog(hDlg, TRUE); + return TRUE; + + default: + return FALSE; + } + return FALSE; +} + + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + if (message == g_bUiTaskbarCreated) + { + /* restore the tray icon on shell restart */ + ShowNotifyIcon(hWnd, NIM_ADD); + return DefWindowProc(hWnd, message, wParam, lParam); + } + switch (message) + { + case WM_CREATE: + GetApacheServicesStatus(); + ShowNotifyIcon(hWnd, NIM_ADD); + SetTimer(hWnd, WM_TIMER_REFRESH, REFRESH_TIME, NULL); + SetTimer(hWnd, WM_TIMER_RESCAN, RESCAN_TIME, NULL); + break; + + case WM_TIMER: + switch (wParam) + { + case WM_TIMER_RESCAN: + { + int nPrev = 0, nNew = 0; + EnterCriticalSection(&g_stcSection); + if (FindRunningServices() || g_bRescanServices) + { + ShowNotifyIcon(hWnd, NIM_MODIFY); + if (g_hwndServiceDlg) + PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0); + } + /* check if services list changed */ + while (g_stServices[nPrev].szServiceName != NULL) + ++nPrev; + GetApacheServicesStatus(); + while (g_stServices[nNew].szServiceName != NULL) + ++nNew; + if (nPrev != nNew) + { + ShowNotifyIcon(hWnd, NIM_MODIFY); + if (g_hwndServiceDlg) { + PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0); + } + } + LeaveCriticalSection(&g_stcSection); + break; + } + + case WM_TIMER_REFRESH: + { + EnterCriticalSection(&g_stcSection); + if (g_bRescanServices) + { + GetApacheServicesStatus(); + ShowNotifyIcon(hWnd, NIM_MODIFY); + if (g_hwndServiceDlg) { + PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0); + } + } + else if (FindRunningServices()) + { + ShowNotifyIcon(hWnd, NIM_MODIFY); + if (g_hwndServiceDlg) { + PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0); + } + } + LeaveCriticalSection(&g_stcSection); + break; + } + } + break; + + case WM_QUIT: + ShowNotifyIcon(hWnd, NIM_DELETE); + break; + + case WM_TRAYMESSAGE: + switch (lParam) + { + case WM_LBUTTONDBLCLK: + if (!g_bDlgServiceOn) + { + g_bDlgServiceOn = TRUE; + DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES), + hWnd, (DLGPROC)ServiceDlgProc); + g_bDlgServiceOn = FALSE; + g_hwndServiceDlg = NULL; + } + else if (IsWindow(g_hwndServiceDlg)) + { + /* Dirty hack to bring the window to the foreground */ + SetWindowPos(g_hwndServiceDlg, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW); + SetWindowPos(g_hwndServiceDlg, HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW); + SetFocus(g_hwndServiceDlg); + } + break; + + case WM_LBUTTONUP: + ShowTryServicesMenu(hWnd); + break; + + case WM_RBUTTONUP: + ShowTryPopupMenu(hWnd); + break; + } + break; + + case WM_COMMAND: + if ((LOWORD(wParam) & IDM_SM_START) == IDM_SM_START) + { + ApacheManageService(g_stServices[LOWORD(wParam) + - IDM_SM_START].szServiceName, + g_stServices[LOWORD(wParam) + - IDM_SM_START].szImagePath, + g_stServices[LOWORD(wParam) + - IDM_SM_START].szComputerName, + SERVICE_CONTROL_CONTINUE); + return TRUE; + } + else if ((LOWORD(wParam) & IDM_SM_STOP) == IDM_SM_STOP) + { + ApacheManageService(g_stServices[LOWORD(wParam) + - IDM_SM_STOP].szServiceName, + g_stServices[LOWORD(wParam) + - IDM_SM_STOP].szImagePath, + g_stServices[LOWORD(wParam) + - IDM_SM_STOP].szComputerName, + SERVICE_CONTROL_STOP); + return TRUE; + } + else if ((LOWORD(wParam) & IDM_SM_RESTART) == IDM_SM_RESTART) + { + ApacheManageService(g_stServices[LOWORD(wParam) + - IDM_SM_RESTART].szServiceName, + g_stServices[LOWORD(wParam) + - IDM_SM_RESTART].szImagePath, + g_stServices[LOWORD(wParam) + - IDM_SM_RESTART].szComputerName, + SERVICE_APACHE_RESTART); + return TRUE; + } + switch (LOWORD(wParam)) + { + case IDM_RESTORE: + if (!g_bDlgServiceOn) + { + g_bDlgServiceOn = TRUE; + DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES), + hWnd, (DLGPROC)ServiceDlgProc); + g_bDlgServiceOn = FALSE; + g_hwndServiceDlg = NULL; + } + else if (IsWindow(g_hwndServiceDlg)) { + SetFocus(g_hwndServiceDlg); + } + break; + + case IDC_SMANAGER: + if (g_dwOSVersion >= OS_VERSION_WIN2K) { + ShellExecute(NULL, _T("open"), _T("services.msc"), _T("/s"), + NULL, SW_NORMAL); + } + else { + WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL); + } + return TRUE; + + case IDM_EXIT: + ShowNotifyIcon(hWnd, NIM_DELETE); + PostQuitMessage(0); + return TRUE; + } + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + + return FALSE; +} + + +static int KillAWindow(HWND appwindow) +{ + HANDLE appproc; + DWORD procid; + BOOL postres; + + SetLastError(0); + GetWindowThreadProcessId(appwindow, &procid); + if (GetLastError()) + return(2); + + appproc = OpenProcess(SYNCHRONIZE, 0, procid); + postres = PostMessage(appwindow, WM_COMMAND, IDM_EXIT, 0); + if (appproc && postres) { + if (WaitForSingleObject(appproc, 10 /* seconds */ * 1000) + == WAIT_OBJECT_0) { + CloseHandle(appproc); + return (0); + } + } + if (appproc) + CloseHandle(appproc); + + if ((appproc = OpenProcess(PROCESS_TERMINATE, 0, procid)) != NULL) { + if (TerminateProcess(appproc, 0)) { + CloseHandle(appproc); + return (0); + } + CloseHandle(appproc); + } + + /* Perhaps we were short of permissions? */ + return (2); +} + + +static int KillAllMonitors(void) +{ + HWND appwindow; + int exitcode = 0; + PWTS_PROCESS_INFO tsProcs; + DWORD tsProcCount, i; + DWORD thisProcId; + + /* This is graceful, close our own Window, clearing the icon */ + if ((appwindow = FindWindow(g_szWindowClass, g_szTitle)) != NULL) + exitcode = KillAWindow(appwindow); + + if (g_dwOSVersion < OS_VERSION_WIN2K) + return exitcode; + + thisProcId = GetCurrentProcessId(); + + if (!WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, + &tsProcs, &tsProcCount)) + return exitcode; + + /* This is ungraceful; close other Windows, with a lingering icon. + * Since on terminal server it's not possible to post the message + * to exit across sessions, we have to suffer this side effect + * of a taskbar 'icon' which will evaporate the next time that + * the user hovers over it or when the taskbar area is updated. + */ + for (i = 0; i < tsProcCount; ++i) { + if (_tcscmp(tsProcs[i].pProcessName, _T(AM_STRINGIFY(BIN_NAME))) == 0 + && tsProcs[i].ProcessId != thisProcId) + WTSTerminateProcess(WTS_CURRENT_SERVER_HANDLE, + tsProcs[i].ProcessId, 1); + } + WTSFreeMemory(tsProcs); + return exitcode; +} + + +/* Create main invisible window */ +HWND CreateMainWindow(HINSTANCE hInstance) +{ + HWND hWnd = NULL; + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON), + IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); + wcex.hCursor = g_hCursorArrow; + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = 0; + wcex.lpszClassName = g_szWindowClass; + wcex.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON), + IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + + if (RegisterClassEx(&wcex)) { + hWnd = CreateWindow(g_szWindowClass, g_szTitle, + 0, 0, 0, 0, 0, + NULL, NULL, hInstance, NULL); + } + return hWnd; +} + + +#ifndef UNICODE +/* Borrowed from CRT internal.h for _MBCS argc/argv parsing in this GUI app */ +int __cdecl _setargv(void); +#endif + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nCmdShow) +{ + TCHAR szTmp[MAX_LOADSTRING]; + TCHAR szCmp[MAX_COMPUTERNAME_LENGTH+4]; + MSG msg; + /* existing window */ + HWND appwindow; + DWORD dwControl; + int i; + DWORD d; + + if (!GetSystemOSVersion(&g_dwOSVersion)) + { + ErrorMessage(NULL, TRUE); + return 1; + } + + g_LangID = GetUserDefaultLangID(); + if ((g_LangID & 0xFF) != LANG_ENGLISH) { + g_LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); + } + for (i = IDS_MSG_FIRST; i <= IDS_MSG_LAST; ++i) { + LoadString(hInstance, i, szTmp, MAX_LOADSTRING); + g_lpMsg[i - IDS_MSG_FIRST] = _tcsdup(szTmp); + } + LoadString(hInstance, IDS_APMONITORTITLE, szTmp, MAX_LOADSTRING); + d = MAX_COMPUTERNAME_LENGTH+1; + _tcscpy(szCmp, _T("\\\\")); + GetComputerName(szCmp + 2, &d); + _tcsupr(szCmp); + g_szLocalHost = _tcsdup(szCmp); + + memset(g_stComputers, 0, sizeof(ST_MONITORED_COMP) * MAX_APACHE_COMPUTERS); + g_stComputers[0].szComputerName = _tcsdup(szCmp); + g_stComputers[0].hRegistry = HKEY_LOCAL_MACHINE; + g_szTitle = _tcsdup(szTmp); + LoadString(hInstance, IDS_APMONITORCLASS, szTmp, MAX_LOADSTRING); + g_szWindowClass = _tcsdup(szTmp); + + appwindow = FindWindow(g_szWindowClass, g_szTitle); + +#ifdef UNICODE + __wargv = CommandLineToArgvW(GetCommandLineW(), &__argc); +#else +#if defined(_MSC_VER) && _MSC_VER < 1800 + _setargv(); +#endif +#endif + + if ((__argc == 2) && (_tcscmp(__targv[1], _T("--kill")) == 0)) + { + /* Off to chase and close up every ApacheMonitor taskbar window */ + return KillAllMonitors(); + } + else if ((__argc == 4) && (g_dwOSVersion >= OS_VERSION_WIN2K)) + { + dwControl = _ttoi(__targv[1]); + if ((dwControl != SERVICE_CONTROL_CONTINUE) && + (dwControl != SERVICE_APACHE_RESTART) && + (dwControl != SERVICE_CONTROL_STOP)) + { + return 1; + } + + /* Chase down and close up our session's previous window */ + if ((appwindow) != NULL) + KillAWindow(appwindow); + } + else if (__argc != 1) { + return 1; + } + else if (appwindow) + { + ErrorMessage(g_lpMsg[IDS_MSG_APPRUNNING - IDS_MSG_FIRST], FALSE); + return 0; + } + + g_icoStop = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICOSTOP), + IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + g_icoRun = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICORUN), + IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + g_hCursorHourglass = LoadImage(NULL, MAKEINTRESOURCE(OCR_WAIT), + IMAGE_CURSOR, LR_DEFAULTSIZE, + LR_DEFAULTSIZE, LR_SHARED); + g_hCursorArrow = LoadImage(NULL, MAKEINTRESOURCE(OCR_NORMAL), + IMAGE_CURSOR, LR_DEFAULTSIZE, + LR_DEFAULTSIZE, LR_SHARED); + g_hBmpStart = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPRUN), + IMAGE_BITMAP, XBITMAP, YBITMAP, + LR_DEFAULTCOLOR); + g_hBmpStop = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPSTOP), + IMAGE_BITMAP, XBITMAP, YBITMAP, + LR_DEFAULTCOLOR); + + memset(g_stServices, 0, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES); + CoInitialize(NULL); + InitCommonControls(); + g_hInstance = hInstance; + g_hwndMain = CreateMainWindow(hInstance); + g_bUiTaskbarCreated = RegisterWindowMessage(_T("TaskbarCreated")); + InitializeCriticalSection(&g_stcSection); + g_hwndServiceDlg = NULL; + if (g_hwndMain != NULL) + { + /* To avoid recursion, pass ImagePath NULL (a noop on NT and later) */ + if ((__argc == 4) && (g_dwOSVersion >= OS_VERSION_WIN2K)) + ApacheManageService(__targv[2], NULL, __targv[3], dwControl); + + while (GetMessage(&msg, NULL, 0, 0) == TRUE) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + am_ClearServicesSt(); + } + am_ClearComputersSt(); + DeleteCriticalSection(&g_stcSection); + DestroyIcon(g_icoStop); + DestroyIcon(g_icoRun); + DestroyCursor(g_hCursorHourglass); + DestroyCursor(g_hCursorArrow); + DeleteObject(g_hBmpStart); + DeleteObject(g_hBmpStop); + CoUninitialize(); + return 0; +} + diff --git a/support/win32/ApacheMonitor.dep b/support/win32/ApacheMonitor.dep new file mode 100644 index 0000000..d0eac54 --- /dev/null +++ b/support/win32/ApacheMonitor.dep @@ -0,0 +1,18 @@ +# Microsoft Developer Studio Generated Dependency File, included by ApacheMonitor.mak + +.\ApacheMonitor.c : \ + ".\ApacheMonitor.h"\ + + +.\ApacheMonitor.rc : \ + "..\..\build\win32\httpd.rc"\ + "..\..\include\ap_release.h"\ + ".\apache_header.bmp"\ + ".\ApacheMonitor.h"\ + ".\ApacheMonitor.ico"\ + ".\ApacheMonitor.manifest"\ + ".\aprun.ico"\ + ".\apstop.ico"\ + ".\srun.bmp"\ + ".\sstop.bmp"\ + diff --git a/support/win32/ApacheMonitor.dsp b/support/win32/ApacheMonitor.dsp new file mode 100644 index 0000000..3465ecd --- /dev/null +++ b/support/win32/ApacheMonitor.dsp @@ -0,0 +1,143 @@ +# Microsoft Developer Studio Project File - Name="ApacheMonitor" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ApacheMonitor - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ApacheMonitor.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ApacheMonitor.mak" CFG="ApacheMonitor - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ApacheMonitor - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ApacheMonitor - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ApacheMonitor - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /EHsc /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# ADD CPP /nologo /MD /W3 /EHsc /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "STRICT" /Fd"Release/ApacheMonitor_src" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /i "../../include" /I "../../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\ApacheMonitor.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# ADD CPP /nologo /MDd /W3 /Gm /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "STRICT" /Fd"Debug/ApacheMonitor_src" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /i "../../include" /I "../../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /debug +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\ApacheMonitor.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "ApacheMonitor - Win32 Release" +# Name "ApacheMonitor - Win32 Debug" +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\apache_header.bmp +# End Source File +# Begin Source File + +SOURCE=.\ApacheMonitor.ico +# End Source File +# Begin Source File + +SOURCE=.\aprun.ico +# End Source File +# Begin Source File + +SOURCE=.\apstop.ico +# End Source File +# Begin Source File + +SOURCE=.\srun.bmp +# End Source File +# Begin Source File + +SOURCE=.\sstop.bmp +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ApacheMonitor.c +# End Source File +# Begin Source File + +SOURCE=.\ApacheMonitor.h +# End Source File +# Begin Source File + +SOURCE=.\ApacheMonitor.rc +# End Source File +# End Target +# End Project diff --git a/support/win32/ApacheMonitor.h b/support/win32/ApacheMonitor.h new file mode 100644 index 0000000..87109aa --- /dev/null +++ b/support/win32/ApacheMonitor.h @@ -0,0 +1,78 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ApacheMonitor.h + * @brief Resource definitions for ApacheMonitor.rc and ApacheMonitor.c + */ +#define BIN_NAME ApacheMonitor.exe + +#define IDD_DLGSERVICES 101 +#define IDS_APMONITORTITLE 102 +#define IDS_APMONITORCLASS 103 +#define IDM_RESTORE 104 +#define IDM_EXIT 105 +#define IDI_APSRVMON 106 +#define IDI_ICOSTOP 107 +#define IDI_ICORUN 108 +#define IDC_STATBAR 109 +#define IDC_SSTATUS 110 +#define IDB_BMPSTOP 111 +#define IDB_BMPRUN 112 +#define IDB_BMPHEADER 114 +#define IDL_SERVICES 115 +#define IDL_STDOUT 116 +#define IDC_SSTART 117 +#define IDC_SSTOP 118 +#define IDC_SRESTART 119 +#define IDC_SMANAGER 121 +#define IDD_DLGCONNECT 122 +#define IDC_LREMOTE 123 +#define IDC_LBROWSE 124 +#define IDC_COMPUTER 125 +#define IDC_SCONNECT 126 +#define IDC_SDISCONN 127 +#define IDS_MSG_FIRST 256 +#define IDS_MSG_APPRUNNING 256 +#define IDS_MSG_ERROR 257 +#define IDS_MSG_RUNNINGALL 258 +#define IDS_MSG_RUNNING 259 +#define IDS_MSG_RUNNINGNONE 260 +#define IDS_MSG_NOSERVICES 261 +#define IDS_MSG_MNUSERVICES 262 +#define IDS_MSG_MNUSHOW 263 +#define IDS_MSG_MNUEXIT 264 +#define IDS_MSG_SRVSTART 265 +#define IDS_MSG_SRVSTARTED 266 +#define IDS_MSG_SRVSTOP 267 +#define IDS_MSG_SRVSTOPPED 268 +#define IDS_MSG_SRVRESTART 269 +#define IDS_MSG_SRVRESTARTED 270 +#define IDS_MSG_SRVFAILED 271 +#define IDS_MSG_SSTART 272 +#define IDS_MSG_SSTOP 273 +#define IDS_MSG_SRESTART 274 +#define IDS_MSG_SERVICES 275 +#define IDS_MSG_CONNECT 276 +#define IDS_MSG_ECONNECT 277 +#define IDS_MSG_OK 278 +#define IDS_MSG_LAST 278 +#define IDM_SM_SERVICE 0x1100 +#define IDM_SM_START 0x1200 +#define IDM_SM_STOP 0x1400 +#define IDM_SM_RESTART 0x1800 +#define IDC_STATIC -1 + diff --git a/support/win32/ApacheMonitor.ico b/support/win32/ApacheMonitor.ico Binary files differnew file mode 100644 index 0000000..cd28dc5 --- /dev/null +++ b/support/win32/ApacheMonitor.ico diff --git a/support/win32/ApacheMonitor.mak b/support/win32/ApacheMonitor.mak new file mode 100644 index 0000000..5143155 --- /dev/null +++ b/support/win32/ApacheMonitor.mak @@ -0,0 +1,309 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on ApacheMonitor.dsp +!IF "$(CFG)" == "" +CFG=ApacheMonitor - Win32 Debug +!MESSAGE No configuration specified. Defaulting to ApacheMonitor - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "ApacheMonitor - Win32 Release" && "$(CFG)" != "ApacheMonitor - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ApacheMonitor.mak" CFG="ApacheMonitor - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ApacheMonitor - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ApacheMonitor - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "ApacheMonitor - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\ApacheMonitor.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\ApacheMonitor.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\ApacheMonitor.obj" + -@erase "$(INTDIR)\ApacheMonitor.res" + -@erase "$(INTDIR)\ApacheMonitor_src.idb" + -@erase "$(INTDIR)\ApacheMonitor_src.pdb" + -@erase "$(OUTDIR)\ApacheMonitor.exe" + -@erase "$(OUTDIR)\ApacheMonitor.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "STRICT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\ApacheMonitor_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ApacheMonitor.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\ApacheMonitor.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\ApacheMonitor.pdb" /debug /out:"$(OUTDIR)\ApacheMonitor.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\ApacheMonitor.obj" \ + "$(INTDIR)\ApacheMonitor.res" \ + "..\..\srclib\apr\LibR\apr-1.lib" \ + "..\..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\ApacheMonitor.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\ApacheMonitor.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\ApacheMonitor.exe" + if exist .\Release\ApacheMonitor.exe.manifest mt.exe -manifest .\Release\ApacheMonitor.exe.manifest -outputresource:.\Release\ApacheMonitor.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\ApacheMonitor.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\ApacheMonitor.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\ApacheMonitor.obj" + -@erase "$(INTDIR)\ApacheMonitor.res" + -@erase "$(INTDIR)\ApacheMonitor_src.idb" + -@erase "$(INTDIR)\ApacheMonitor_src.pdb" + -@erase "$(OUTDIR)\ApacheMonitor.exe" + -@erase "$(OUTDIR)\ApacheMonitor.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Gm /Zi /Od /I "../../include" /I "../../srclib/apr/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "STRICT" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\ApacheMonitor_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\ApacheMonitor.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\ApacheMonitor.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib wtsapi32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\ApacheMonitor.pdb" /debug /out:"$(OUTDIR)\ApacheMonitor.exe" +LINK32_OBJS= \ + "$(INTDIR)\ApacheMonitor.obj" \ + "$(INTDIR)\ApacheMonitor.res" \ + "..\..\srclib\apr\LibD\apr-1.lib" \ + "..\..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\ApacheMonitor.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\ApacheMonitor.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\ApacheMonitor.exe" + if exist .\Debug\ApacheMonitor.exe.manifest mt.exe -manifest .\Debug\ApacheMonitor.exe.manifest -outputresource:.\Debug\ApacheMonitor.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("ApacheMonitor.dep") +!INCLUDE "ApacheMonitor.dep" +!ELSE +!MESSAGE Warning: cannot find "ApacheMonitor.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "ApacheMonitor - Win32 Release" || "$(CFG)" == "ApacheMonitor - Win32 Debug" + +!IF "$(CFG)" == "ApacheMonitor - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support\win32" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support\win32" + +!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support\win32" + +"apr - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support\win32" + +!ENDIF + +!IF "$(CFG)" == "ApacheMonitor - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support\win32" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support\win32" + +!ELSEIF "$(CFG)" == "ApacheMonitor - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support\win32" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support\win32" + +!ENDIF + +SOURCE=.\ApacheMonitor.c + +"$(INTDIR)\ApacheMonitor.obj" : $(SOURCE) "$(INTDIR)" + + +SOURCE=.\ApacheMonitor.rc + +"$(INTDIR)\ApacheMonitor.res" : $(SOURCE) "$(INTDIR)" + $(RSC) $(RSC_PROJ) $(SOURCE) + + + +!ENDIF + diff --git a/support/win32/ApacheMonitor.manifest b/support/win32/ApacheMonitor.manifest new file mode 100644 index 0000000..94860b0 --- /dev/null +++ b/support/win32/ApacheMonitor.manifest @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity version="3.1.0.0" processorArchitecture="*" name="Apache.ApacheMonitor" type="win32" /> +<description>Apache Service Monitor</description> +<dependency> +<dependentAssembly> +<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" /> +</dependentAssembly> +</dependency> +</assembly> diff --git a/support/win32/ApacheMonitor.rc b/support/win32/ApacheMonitor.rc new file mode 100644 index 0000000..d4203bf --- /dev/null +++ b/support/win32/ApacheMonitor.rc @@ -0,0 +1,103 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <windows.h> + +#include "ApacheMonitor.h" + +#define LONG_NAME Apache HTTP Server Monitor + +#include "../../build/win32/httpd.rc" + + +IDI_APSRVMON ICON DISCARDABLE "ApacheMonitor.ico" +IDI_ICOSTOP ICON DISCARDABLE "apstop.ico" +IDI_ICORUN ICON DISCARDABLE "aprun.ico" +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "ApacheMonitor.manifest" + +IDD_DLGSERVICES DIALOGEX 0, 0, 350, 192 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | WS_MINIMIZEBOX | WS_VISIBLE | + WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Apache Service Monitor" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "OK",IDCANCEL,298,161,50,14 + CONTROL IDB_BMPHEADER,IDC_STATIC,"Static",SS_BITMAP,0,0,349,38 + LTEXT "Service St&atus :",IDC_SSTATUS,3,40,272,8 + LISTBOX IDL_SERVICES,2,49,285,73,LBS_OWNERDRAWFIXED | + LBS_HASSTRINGS | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | + LBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP + LISTBOX IDL_STDOUT,2,124,285,51,LBS_NOINTEGRALHEIGHT | + LBS_DISABLENOSCROLL | LBS_NOSEL | WS_VSCROLL + PUSHBUTTON "&Start",IDC_SSTART,298,49,50,14 + PUSHBUTTON "S&top",IDC_SSTOP,298,65,50,14 + PUSHBUTTON "&Restart",IDC_SRESTART,298,81,50,14 + PUSHBUTTON "Ser&vices",IDC_SMANAGER,298,97,50,14 + PUSHBUTTON "&Connect",IDC_SCONNECT,298,113,50,14 + PUSHBUTTON "&Disconnect",IDC_SDISCONN,298,129,50,14 +END + +IDD_DLGCONNECT DIALOGEX 0, 0, 240, 54 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | WS_VISIBLE | WS_CLIPCHILDREN | + WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Connect To A Remote Computer" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Computer &Name:",IDC_LREMOTE,7,4,155,8 + EDITTEXT IDC_COMPUTER,7,14,169,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "&OK",IDOK,183,14,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,183,34,50,14 + PUSHBUTTON "&Browse",IDC_LBROWSE,7,34,50,14 +END + +IDB_BMPSTOP BITMAP DISCARDABLE "sstop.bmp" +IDB_BMPRUN BITMAP DISCARDABLE "srun.bmp" +IDB_BMPHEADER BITMAP DISCARDABLE "apache_header.bmp" + +STRINGTABLE DISCARDABLE +BEGIN + IDS_APMONITORTITLE "Apache Service Monitor" + IDS_APMONITORCLASS "ApacheServiceMonitorClass" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MSG_APPRUNNING "Apache monitor is already started" + IDS_MSG_ERROR "Error" + IDS_MSG_RUNNINGALL "Running all Apache services" + IDS_MSG_RUNNING "Running %d of %d Apache services" + IDS_MSG_RUNNINGNONE "Running none of %d Apache services" + IDS_MSG_NOSERVICES "No services installed" + IDS_MSG_MNUSERVICES "Open &Services" + IDS_MSG_MNUSHOW "&Open Apache Monitor" + IDS_MSG_MNUEXIT "E&xit" + IDS_MSG_OK "OK" + IDS_MSG_SRVSTART "The %s service is starting." + IDS_MSG_SRVSTARTED "The %s service has started." + IDS_MSG_SRVSTOP "The %s service is stopping." + IDS_MSG_SRVSTOPPED "The %s service has stopped." + IDS_MSG_SRVRESTART "The %s service is restarting." + IDS_MSG_SRVRESTARTED "The %s service has restarted." + IDS_MSG_SRVFAILED "The requested operation has failed!" + IDS_MSG_SSTART "&Start" + IDS_MSG_SSTOP "S&top" + IDS_MSG_SRESTART "&Restart" + IDS_MSG_SERVICES "Ser&vices" + IDS_MSG_CONNECT "&Connect" + IDS_MSG_ECONNECT "Unable to connect to the remote registry on %s" +END diff --git a/support/win32/apache_header.bmp b/support/win32/apache_header.bmp Binary files differnew file mode 100644 index 0000000..7340fac --- /dev/null +++ b/support/win32/apache_header.bmp diff --git a/support/win32/aprun.ico b/support/win32/aprun.ico Binary files differnew file mode 100644 index 0000000..dbd5832 --- /dev/null +++ b/support/win32/aprun.ico diff --git a/support/win32/apstop.ico b/support/win32/apstop.ico Binary files differnew file mode 100644 index 0000000..fba49ad --- /dev/null +++ b/support/win32/apstop.ico diff --git a/support/win32/srun.bmp b/support/win32/srun.bmp Binary files differnew file mode 100644 index 0000000..90ecd46 --- /dev/null +++ b/support/win32/srun.bmp diff --git a/support/win32/sstop.bmp b/support/win32/sstop.bmp Binary files differnew file mode 100644 index 0000000..ba73d87 --- /dev/null +++ b/support/win32/sstop.bmp diff --git a/support/win32/wintty.c b/support/win32/wintty.c new file mode 100644 index 0000000..684ce5b --- /dev/null +++ b/support/win32/wintty.c @@ -0,0 +1,374 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* -------------------------------------------------------------------- + * + * wintty : a Apache/WinNT support utility for monitoring and + * reflecting user feedback from the Apache process via + * stdin/stdout, even as running within the service context. + * + * Originally contributed by William Rowe <wrowe covalent.net> + * + * Note: this implementation is _very_ experimental, and error handling + * is far from complete. Using it as a cgi or pipe process allows the + * programmer to discover if facilities such as reliable piped logs + * are working as expected, or answer operator prompts that would + * otherwise be discarded by the service process. + * + * Also note the isservice detection semantics, which far exceed any + * mechanism we have discovered thus far. + * + * -------------------------------------------------------------------- + */ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <stdlib.h> +#include <stdio.h> + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +#define _CRT_SECURE_NO_DEPRECATE +#pragma warning(disable: 4996) +#endif + +const char *options = +"\nwintty: a utility for echoing the stdin stream to a new console window,\n" +"\teven when invoked from within a service (such as the Apache server.)\n" +"\tAlso reflects the console input back to the stdout stream, allowing\n" +"\tthe operator to respond to prompts from the context of a service.\n\n" +"Syntax: %s [opts] [-t \"Window Title\"]\n\n" +" opts: -c{haracter} or -l{ine} input\n" +"\t-q{uiet} or -e{cho} input\n" +"\t-u{nprocessed} or -p{rocessed} input\n" +"\t-n{owrap} or -w{rap} output lines\n" +"\t-f{ormatted} or -r{aw} output lines\n" +"\t-O{output} [number of seconds]\n" +"\t-v{erbose} error reporting (for debugging)\n" +"\t-? for this message\n\n"; + +BOOL verbose = FALSE; + +void printerr(char *fmt, ...) +{ + char str[1024]; + va_list args; + if (!verbose) + return; + va_start(args, fmt); + wvsprintf(str, fmt, args); + OutputDebugString(str); +} + +DWORD WINAPI feedback(LPVOID args); + +typedef struct feedback_args_t { + HANDLE in; + HANDLE out; +} feedback_args_t; + +int main(int argc, char** argv) +{ + char str[1024], *contitle = NULL; + HANDLE hproc, thread; + HANDLE hwinsta = NULL, hsavewinsta; + HANDLE hdesk = NULL, hsavedesk = NULL; + HANDLE conin, conout; + HANDLE hstdin, hstdout, hstderr, hdup; + feedback_args_t feed; + DWORD conmode; + DWORD newinmode = 0, notinmode = 0; + DWORD newoutmode = 0, notoutmode = 0; + DWORD tid; + DWORD len; + DWORD timeout = INFINITE; + BOOL isservice = FALSE; + char *arg0 = argv[0]; + + while (--argc) { + ++argv; + if (**argv == '/' || **argv == '-') { + switch (tolower((*argv)[1])) { + case 'c': + notinmode |= ENABLE_LINE_INPUT; break; + case 'l': + newinmode |= ENABLE_LINE_INPUT; break; + case 'q': + notinmode |= ENABLE_ECHO_INPUT; break; + case 'e': + newinmode |= ENABLE_ECHO_INPUT; break; + case 'u': + notinmode |= ENABLE_PROCESSED_INPUT; break; + case 'p': + newinmode |= ENABLE_PROCESSED_INPUT; break; + case 'n': + notoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break; + case 'w': + newoutmode |= ENABLE_WRAP_AT_EOL_OUTPUT; break; + case 'r': + notoutmode |= ENABLE_PROCESSED_OUTPUT; break; + case 'f': + newoutmode |= ENABLE_PROCESSED_OUTPUT; break; + case 'o': + if (*(argv + 1) && *(argv + 1)[0] != '-') { + *(++argv); + timeout = atoi(*argv) / 1000; + --argc; + } + else { + timeout = 0; + } + break; + case 'v': + verbose = TRUE; + break; + case 't': + contitle = *(++argv); + --argc; + break; + case '?': + printf(options, arg0); + exit(1); + default: + printf("wintty option %s not recognized, use -? for help.\n\n", *argv); + exit(1); + } + } + else { + printf("wintty argument %s not understood, use -? for help.\n\n", *argv); + exit(1); + } + } + + hproc = GetCurrentProcess(); + hsavewinsta = GetProcessWindowStation(); + if (!hsavewinsta || hsavewinsta == INVALID_HANDLE_VALUE) { + printerr("GetProcessWindowStation() failed (%d)\n", GetLastError()); + } + else if (!GetUserObjectInformation(hsavewinsta, UOI_NAME, str, sizeof(str), &len)) { + printerr("GetUserObjectInfoformation(hWinSta) failed (%d)\n", GetLastError()); + } + else if (strnicmp(str, "Service-", 8) == 0) { + printerr("WindowStation Name %s is a service\n", str); + isservice = TRUE; + } + SetLastError(0); + + hstdin = GetStdHandle(STD_INPUT_HANDLE); + if (!hstdin || hstdin == INVALID_HANDLE_VALUE) { + printerr("GetStdHandle(STD_INPUT_HANDLE) failed (%d)\n", + GetLastError()); + } + else if (DuplicateHandle(hproc, hstdin, hproc, &hdup, 0, + isservice, DUPLICATE_SAME_ACCESS)) { + CloseHandle(hstdin); + hstdin = hdup; + } + else { + printerr("DupHandle(stdin [%x]) failed (%d)\n", + hstdin, GetLastError()); + } + + hstdout = GetStdHandle(STD_OUTPUT_HANDLE); + if (!hstdout || hstdout == INVALID_HANDLE_VALUE) { + printerr("GetStdHandle(STD_OUTPUT_HANDLE) failed (%d)\n", + GetLastError()); + } + else if (DuplicateHandle(hproc, hstdout, hproc, &hdup, 0, + isservice, DUPLICATE_SAME_ACCESS)) { + CloseHandle(hstdout); + hstdout = hdup; + } + else { + printerr("DupHandle(stdout [%x]) failed (%d)\n", + hstdout, GetLastError()); + } + + hstderr = GetStdHandle(STD_ERROR_HANDLE); + if (!hstderr || hstderr == INVALID_HANDLE_VALUE) { + printerr("GetStdHandle(STD_ERROR_HANDLE) failed (%d)\n", + GetLastError()); + } + else if (DuplicateHandle(hproc, hstderr, hproc, &hdup, 0, + isservice, DUPLICATE_SAME_ACCESS)) { + CloseHandle(hstderr); + hstderr = hdup; + } + else { + printerr("DupHandle(stderr [%x]) failed (%d)\n", + hstderr, GetLastError()); + } + + /* You can't close the console till all the handles above were + * rescued by DuplicateHandle() + */ + if (!FreeConsole()) + printerr("FreeConsole() failed (%d)\n", GetLastError()); + + if (isservice) { +#ifdef WE_EVER_FIGURE_OUT_WHY_THIS_DOESNT_WORK + hsavedesk = GetThreadDesktop(GetCurrentThreadId()); + if (!hsavedesk || hsavedesk == INVALID_HANDLE_VALUE) { + printerr("GetThreadDesktop(GetTID()) failed (%d)\n", GetLastError()); + } + CloseWindowStation(hwinsta); + hwinsta = OpenWindowStation("WinSta0", TRUE, MAXIMUM_ALLOWED); + if (!hwinsta || hwinsta == INVALID_HANDLE_VALUE) { + printerr("OpenWinSta(WinSta0) failed (%d)\n", GetLastError()); + } + else if (!SetProcessWindowStation(hwinsta)) { + printerr("SetProcWinSta(WinSta0) failed (%d)\n", GetLastError()); + } + hdesk = OpenDesktop("Default", 0, TRUE, MAXIMUM_ALLOWED); + if (!hdesk || hdesk == INVALID_HANDLE_VALUE) { + printerr("OpenDesktop(Default) failed (%d)\n", GetLastError()); + } + else if (!SetThreadDesktop(hdesk)) { + printerr("SetThreadDesktop(Default) failed (%d)\n", GetLastError()); + } +#else + PROCESS_INFORMATION pi; + STARTUPINFO si; + DWORD exitcode = 1; + char appbuff[MAX_PATH]; + char *appname = NULL; + char *cmdline = GetCommandLine(); + + if (!GetModuleFileName(NULL, appbuff, sizeof(appbuff))) { + appname = appbuff; + } + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW + | STARTF_USESTDHANDLES; + si.lpDesktop = "WinSta0\\Default"; + si.wShowWindow = 1; /* SW_SHOWNORMAL */ + si.hStdInput = hstdin; + si.hStdOutput = hstdout; + si.hStdError = hstderr; + + /* Instantly, upon creating the new process, we will close our + * copies of the handles so our parent isn't confused when the + * child closes their copy of the handle. Without this action, + * we would hold a copy of the handle, and the parent would not + * receive their EOF notification. + */ + if (CreateProcess(appname, cmdline, NULL, NULL, TRUE, + CREATE_SUSPENDED | CREATE_NEW_CONSOLE, + NULL, NULL, &si, &pi)) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + ResumeThread(pi.hThread); + CloseHandle(pi.hThread); + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &exitcode); + CloseHandle(pi.hProcess); + return exitcode; + } + return 1; +#endif + } + + if (!AllocConsole()) { + printerr("AllocConsole(Default) failed (%d)\n", GetLastError()); + } + + if (contitle && !SetConsoleTitle(contitle)) { + printerr("SetConsoleTitle() failed (%d)\n", GetLastError()); + } + + conout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FALSE, OPEN_EXISTING, 0, NULL); + if (!conout || conout == INVALID_HANDLE_VALUE) { + printerr("CreateFile(CONOUT$) failed (%d)\n", GetLastError()); + } + else if (!GetConsoleMode(conout, &conmode)) { + printerr("GetConsoleMode(CONOUT) failed (%d)\n", GetLastError()); + } + else if (!SetConsoleMode(conout, conmode = ((conmode | newoutmode) + & ~notoutmode))) { + printerr("SetConsoleMode(CONOUT, 0x%x) failed (%d)\n", + conmode, GetLastError()); + } + + conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FALSE, OPEN_EXISTING, 0, NULL); + if (!conin || conin == INVALID_HANDLE_VALUE) { + printerr("CreateFile(CONIN$) failed (%d)\n", GetLastError()); + } + else if (!GetConsoleMode(conin, &conmode)) { + printerr("GetConsoleMode(CONIN) failed (%d)\n", GetLastError()); + } + else if (!SetConsoleMode(conin, conmode = ((conmode | newinmode) + & ~notinmode))) { + printerr("SetConsoleMode(CONIN, 0x%x) failed (%d)\n", + conmode, GetLastError()); + } + + feed.in = conin; + feed.out = hstdout; + thread = CreateThread(NULL, 0, feedback, (LPVOID)&feed, 0, &tid); + + while (ReadFile(hstdin, str, sizeof(str), &len, NULL)) + if (!len || !WriteFile(conout, str, len, &len, NULL)) + break; + + printerr("[EOF] from stdin (%d)\n", GetLastError()); + + CloseHandle(stdout); + if (!GetConsoleTitle(str, sizeof(str))) { + printerr("SetConsoleTitle() failed (%d)\n", GetLastError()); + } + else { + strcat(str, " - [Finished]"); + if (!SetConsoleTitle(str)) { + printerr("SetConsoleTitle() failed (%d)\n", GetLastError()); + } + } + + WaitForSingleObject(thread, timeout); + FreeConsole(); + if (isservice) { + if (!SetProcessWindowStation(hsavewinsta)) { + len = GetLastError(); + } + if (!SetThreadDesktop(hsavedesk)) { + len = GetLastError(); + } + CloseDesktop(hdesk); + CloseWindowStation(hwinsta); + } + return 0; +} + + +DWORD WINAPI feedback(LPVOID arg) +{ + feedback_args_t *feed = (feedback_args_t*)arg; + char *str[1024]; + DWORD len; + + while (ReadFile(feed->in, str, sizeof(str), &len, NULL)) + if (!len || !WriteFile(feed->out, str, len, &len, NULL)) + break; + + printerr("[EOF] from Console (%d)\n", GetLastError()); + + return 0; +} diff --git a/support/win32/wintty.dep b/support/win32/wintty.dep new file mode 100644 index 0000000..8f57409 --- /dev/null +++ b/support/win32/wintty.dep @@ -0,0 +1,5 @@ +# Microsoft Developer Studio Generated Dependency File, included by wintty.mak + +..\..\build\win32\httpd.rc : \ + "..\..\include\ap_release.h"\ + diff --git a/support/win32/wintty.dsp b/support/win32/wintty.dsp new file mode 100644 index 0000000..337ba17 --- /dev/null +++ b/support/win32/wintty.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="wintty" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=wintty - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "wintty.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wintty.mak" CFG="wintty - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wintty - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "wintty - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wintty - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Release/wintty_src" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /fo"Release/wintty.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console +# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /debug /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\wintty.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "wintty - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fd"Debug/wintty_src" /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /fo"Debug/wintty.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /incremental:no /debug +# Begin Special Build Tool +TargetPath=.\Debug\wintty.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);1 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "wintty - Win32 Release" +# Name "wintty - Win32 Debug" +# Begin Source File + +SOURCE=.\wintty.c +# End Source File +# Begin Source File + +SOURCE=..\..\build\win32\httpd.rc +# End Source File +# End Target +# End Project diff --git a/support/win32/wintty.mak b/support/win32/wintty.mak new file mode 100644 index 0000000..d2c3d6c --- /dev/null +++ b/support/win32/wintty.mak @@ -0,0 +1,317 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on wintty.dsp +!IF "$(CFG)" == "" +CFG=wintty - Win32 Debug +!MESSAGE No configuration specified. Defaulting to wintty - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "wintty - Win32 Release" && "$(CFG)" != "wintty - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wintty.mak" CFG="wintty - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wintty - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "wintty - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "wintty - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\wintty.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Release" "apr - Win32 Release" "$(OUTDIR)\wintty.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\wintty.obj" + -@erase "$(INTDIR)\wintty.res" + -@erase "$(INTDIR)\wintty_src.idb" + -@erase "$(INTDIR)\wintty_src.pdb" + -@erase "$(OUTDIR)\wintty.exe" + -@erase "$(OUTDIR)\wintty.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\wintty_src" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\wintty.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\wintty.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\wintty.pdb" /debug /out:"$(OUTDIR)\wintty.exe" /opt:ref +LINK32_OBJS= \ + "$(INTDIR)\wintty.obj" \ + "$(INTDIR)\wintty.res" \ + "..\..\srclib\apr\LibR\apr-1.lib" \ + "..\..\srclib\apr-util\LibR\aprutil-1.lib" + +"$(OUTDIR)\wintty.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Release\wintty.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Release +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\wintty.exe" + if exist .\Release\wintty.exe.manifest mt.exe -manifest .\Release\wintty.exe.manifest -outputresource:.\Release\wintty.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ELSEIF "$(CFG)" == "wintty - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +!IF "$(RECURSE)" == "0" + +ALL : "$(OUTDIR)\wintty.exe" "$(DS_POSTBUILD_DEP)" + +!ELSE + +ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\wintty.exe" "$(DS_POSTBUILD_DEP)" + +!ENDIF + +!IF "$(RECURSE)" == "1" +CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" +!ELSE +CLEAN : +!ENDIF + -@erase "$(INTDIR)\wintty.obj" + -@erase "$(INTDIR)\wintty.res" + -@erase "$(INTDIR)\wintty_src.idb" + -@erase "$(INTDIR)\wintty_src.pdb" + -@erase "$(OUTDIR)\wintty.exe" + -@erase "$(OUTDIR)\wintty.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../srclib/apr/include" /I "../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "APR_DECLARE_STATIC" /D "APU_DECLARE_STATIC" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\wintty_src" /FD /EHsc /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +RSC_PROJ=/l 0x409 /fo"$(INTDIR)\wintty.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe" +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\wintty.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\wintty.pdb" /debug /out:"$(OUTDIR)\wintty.exe" +LINK32_OBJS= \ + "$(INTDIR)\wintty.obj" \ + "$(INTDIR)\wintty.res" \ + "..\..\srclib\apr\LibD\apr-1.lib" \ + "..\..\srclib\apr-util\LibD\aprutil-1.lib" + +"$(OUTDIR)\wintty.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +TargetPath=.\Debug\wintty.exe +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep + +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\wintty.exe" + if exist .\Debug\wintty.exe.manifest mt.exe -manifest .\Debug\wintty.exe.manifest -outputresource:.\Debug\wintty.exe;1 + echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("wintty.dep") +!INCLUDE "wintty.dep" +!ELSE +!MESSAGE Warning: cannot find "wintty.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "wintty - Win32 Release" || "$(CFG)" == "wintty - Win32 Debug" + +!IF "$(CFG)" == "wintty - Win32 Release" + +"apr - Win32 Release" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" + cd "..\..\support\win32" + +"apr - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support\win32" + +!ELSEIF "$(CFG)" == "wintty - Win32 Debug" + +"apr - Win32 Debug" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" + cd "..\..\support\win32" + +"apr - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr" + $(MAKE) /$(MAKEFLAGS) /F ".\apr.mak" CFG="apr - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support\win32" + +!ENDIF + +!IF "$(CFG)" == "wintty - Win32 Release" + +"aprutil - Win32 Release" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" + cd "..\..\support\win32" + +"aprutil - Win32 ReleaseCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" RECURSE=1 CLEAN + cd "..\..\support\win32" + +!ELSEIF "$(CFG)" == "wintty - Win32 Debug" + +"aprutil - Win32 Debug" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" + cd "..\..\support\win32" + +"aprutil - Win32 DebugCLEAN" : + cd ".\..\..\srclib\apr-util" + $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" RECURSE=1 CLEAN + cd "..\..\support\win32" + +!ENDIF + +SOURCE=..\..\build\win32\httpd.rc + +!IF "$(CFG)" == "wintty - Win32 Release" + + +"$(INTDIR)\wintty.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\wintty.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe" $(SOURCE) + + +!ELSEIF "$(CFG)" == "wintty - Win32 Debug" + + +"$(INTDIR)\wintty.res" : $(SOURCE) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)\wintty.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d "APP_FILE" /d BIN_NAME="wintty.exe" /d LONG_NAME="Apache wintty console pipe" $(SOURCE) + + +!ENDIF + +SOURCE=.\wintty.c + +"$(INTDIR)\wintty.obj" : $(SOURCE) "$(INTDIR)" + + + +!ENDIF + |